676 lines
17 KiB
Swift
676 lines
17 KiB
Swift
// p4rse, Copyright 2026, Will Hawkins
|
|
//
|
|
// This file is part of p4rse.
|
|
//
|
|
// This file is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
import Common
|
|
|
|
extension P4Value: CST.AnExpression {}
|
|
|
|
public struct CST {
|
|
|
|
public protocol AnExpression {}
|
|
public protocol Statement {}
|
|
public protocol AnState {}
|
|
|
|
struct Expression {}
|
|
|
|
public struct Statements {
|
|
public let statements: [Statement]
|
|
|
|
public init(_ s: [Statement]) {
|
|
self.statements = s
|
|
}
|
|
}
|
|
|
|
public struct VariableDeclarationStatement: Statement {
|
|
public var initializer: AnExpression?
|
|
public var identifier: CST.Identifier
|
|
public var tipe: CST.Tipe
|
|
|
|
public init(
|
|
identifier: Identifier, withType tipe: CST.Tipe, withInitializer initializer: AnExpression?
|
|
) {
|
|
self.identifier = identifier
|
|
self.initializer = initializer
|
|
self.tipe = tipe
|
|
}
|
|
}
|
|
|
|
public struct ConditionalStatement: Statement {
|
|
public var condition: AnExpression
|
|
public var thenn: Statement
|
|
public var elss: Statement?
|
|
|
|
public init(condition: AnExpression, withThen thenn: Statement) {
|
|
self.condition = condition
|
|
self.thenn = thenn
|
|
self.elss = .none
|
|
}
|
|
|
|
public init(
|
|
condition: AnExpression, withThen thenn: Statement,
|
|
andElse elss: Statement
|
|
) {
|
|
self.condition = condition
|
|
self.thenn = thenn
|
|
self.elss = elss
|
|
}
|
|
}
|
|
|
|
public struct BlockStatement: Statement {
|
|
public var statements: Statements
|
|
|
|
public init(_ statements: Statements) {
|
|
self.statements = statements
|
|
}
|
|
|
|
}
|
|
|
|
public struct ReturnStatement: Statement {
|
|
public let value: AnExpression
|
|
|
|
public init(_ value: AnExpression) {
|
|
self.value = value
|
|
}
|
|
}
|
|
|
|
public struct ApplyStatement: Statement {
|
|
public let body: CST.BlockStatement?
|
|
|
|
public init() { self.body = .none }
|
|
public init(_ body: CST.BlockStatement) {
|
|
self.body = body
|
|
}
|
|
}
|
|
|
|
public struct Action: CustomStringConvertible {
|
|
public var description: String {
|
|
return "Action: "
|
|
+ "\(self.name) with parameters \(self.params) and body \(String(describing: self.body))"
|
|
}
|
|
|
|
public var body: CST.BlockStatement?
|
|
public var params: CST.ParameterList
|
|
public var name: CST.Identifier
|
|
|
|
public init(
|
|
named name: CST.Identifier = CST.Identifier(Common.Identifier(name: "")),
|
|
withParameters parameters: ParameterList = ParameterList([]),
|
|
withBody body: CST.BlockStatement? = .none
|
|
) {
|
|
self.name = name
|
|
self.params = parameters
|
|
self.body = body
|
|
}
|
|
|
|
}
|
|
|
|
public struct Actions: CustomStringConvertible {
|
|
public let actions: [CST.Action]
|
|
public init(withActions actions: [CST.Action]) {
|
|
self.actions = actions
|
|
}
|
|
|
|
public var description: String {
|
|
return "Actions: "
|
|
+ actions.map { action in
|
|
return "\(action)"
|
|
}.joined(separator: ";")
|
|
}
|
|
}
|
|
|
|
public enum TableKeyMatchType {
|
|
case Exact
|
|
}
|
|
|
|
public struct TableKeyEntry: CustomStringConvertible {
|
|
public let key: CST.KeysetExpression
|
|
public let match_type: CST.TableKeyMatchType
|
|
|
|
public init(_ key: CST.KeysetExpression, _ match: CST.TableKeyMatchType) {
|
|
self.key = key
|
|
self.match_type = match
|
|
}
|
|
|
|
public var description: String {
|
|
return "Table Key Entry: " + "\(self.key): \(self.match_type)"
|
|
}
|
|
}
|
|
|
|
public struct TableKeys: CustomStringConvertible {
|
|
public let keys: [CST.TableKeyEntry]
|
|
|
|
public init(withEntries entries: [CST.TableKeyEntry]) {
|
|
self.keys = entries
|
|
}
|
|
public init() {
|
|
self.keys = []
|
|
}
|
|
|
|
public var description: String {
|
|
return "Table Keys: "
|
|
+ self.keys.map { key in
|
|
return "\(key)"
|
|
}.joined(separator: ";")
|
|
}
|
|
}
|
|
|
|
public struct TableActionsProperty: CustomStringConvertible {
|
|
public let actions: [CST.Identifier]
|
|
public init(_ actions: [CST.Identifier] = []) {
|
|
self.actions = actions
|
|
}
|
|
|
|
public var description: String {
|
|
return "Table Actions: "
|
|
+ self.actions.map { action in
|
|
return "\(action)"
|
|
}.joined(separator: ";")
|
|
}
|
|
}
|
|
|
|
public struct TablePropertyList: CustomStringConvertible {
|
|
public let actions: CST.TableActionsProperty
|
|
public let keys: CST.TableKeys
|
|
public init(withActions actions: CST.TableActionsProperty, withKeys keys: CST.TableKeys) {
|
|
self.actions = actions
|
|
self.keys = keys
|
|
}
|
|
|
|
public var description: String {
|
|
return "Table Property List: \(self.actions) \(self.keys)"
|
|
}
|
|
}
|
|
|
|
public struct Table: CustomStringConvertible {
|
|
public let properties: CST.TablePropertyList
|
|
let name: CST.Identifier
|
|
public let entries: [(P4Value, CST.Identifier)]
|
|
|
|
public init(
|
|
withName name: CST.Identifier, withPropertyList property_list: CST.TablePropertyList,
|
|
withEntries entries: [(P4Value, CST.Identifier)] = []
|
|
) {
|
|
self.name = name
|
|
self.properties = property_list
|
|
self.entries = entries
|
|
}
|
|
|
|
public var description: String {
|
|
return "Table named: \(self.name) \(self.properties)"
|
|
}
|
|
|
|
/// When the control is evaluated, the value of the x in the table is
|
|
/// compared to the entries and the match is assocated with an action
|
|
/// that is invoked when the match occurs!
|
|
|
|
public func update(addEntry entry: (P4Value, CST.Identifier)) -> Table {
|
|
return Table(
|
|
withName: self.name, withPropertyList: self.properties, withEntries: self.entries + [entry])
|
|
}
|
|
}
|
|
|
|
public protocol AnDeclaration: Statement {}
|
|
|
|
public struct Declaration {}
|
|
|
|
public struct Control: CustomStringConvertible, AnDeclaration {
|
|
public var description: String {
|
|
return "Control named \(self._name) \(self.parameters) \(self.actions) \(self.table)"
|
|
}
|
|
|
|
public let actions: CST.Actions
|
|
public let table: CST.Table
|
|
let _parameters: CST.ParameterList
|
|
let _name: CST.Identifier
|
|
let apply: CST.ApplyStatement
|
|
|
|
public var parameters: CST.ParameterList {
|
|
_parameters
|
|
}
|
|
|
|
public var name: CST.Identifier {
|
|
_name
|
|
}
|
|
|
|
public init(
|
|
named: CST.Identifier, withParameters parameters: CST.ParameterList,
|
|
withTable table: CST.Table,
|
|
withActions actions: CST.Actions, withApply apply: CST.ApplyStatement
|
|
) {
|
|
self._name = named
|
|
self._parameters = parameters
|
|
self.actions = actions
|
|
self.table = table
|
|
self.apply = apply
|
|
}
|
|
|
|
public func updateTable(addEntry entry: (P4Value, CST.Identifier)) -> Control {
|
|
let table = self.table.update(addEntry: entry)
|
|
|
|
return Control(
|
|
named: self.name, withParameters: self.parameters, withTable: table,
|
|
withActions: self.actions, withApply: self.apply)
|
|
}
|
|
|
|
public func def() -> P4DataValue? {
|
|
return .none
|
|
}
|
|
|
|
}
|
|
|
|
public struct ExternDeclaration: AnDeclaration {
|
|
public let declaration: CST.AnDeclaration
|
|
|
|
public init(_ declaration: CST.AnDeclaration) {
|
|
self.declaration = declaration
|
|
}
|
|
}
|
|
|
|
public struct FunctionDeclaration: AnDeclaration {
|
|
public var description: String {
|
|
return "Function named \(self.name) that returns \(self.tipe) with parameters \(self.params)"
|
|
}
|
|
|
|
public var body: CST.BlockStatement?
|
|
public var params: CST.ParameterList
|
|
public var name: CST.Identifier
|
|
public var tipe: CST.Tipe
|
|
|
|
public init(
|
|
named name: CST.Identifier, ofType type: CST.Tipe,
|
|
withParameters parameters: CST.ParameterList,
|
|
withBody body: CST.BlockStatement?
|
|
) {
|
|
self.name = name
|
|
self.tipe = type
|
|
self.params = parameters
|
|
self.body = body
|
|
}
|
|
}
|
|
|
|
public struct StructDeclaration: AnDeclaration {
|
|
public let fields: [CST.VariableDeclarationStatement]
|
|
public let identifier: CST.Identifier
|
|
public init(_ id: CST.Identifier, _ fields: [CST.VariableDeclarationStatement]) {
|
|
self.identifier = id
|
|
self.fields = fields
|
|
}
|
|
}
|
|
|
|
public struct Instantiation: Statement {
|
|
public let name: CST.Identifier
|
|
public var tipe: CST.Identifier
|
|
public let arguments: CST.ArgumentList
|
|
|
|
public init(
|
|
named name: CST.Identifier, withType tipe: CST.Identifier,
|
|
withArguments arguments: CST.ArgumentList
|
|
) {
|
|
self.name = name
|
|
self.arguments = arguments
|
|
self.tipe = tipe
|
|
}
|
|
}
|
|
|
|
public struct ExpressionStatement: Statement {
|
|
public let expression: AnExpression
|
|
|
|
public init(_ expr: AnExpression) {
|
|
self.expression = expr
|
|
}
|
|
}
|
|
|
|
public struct Identifier: AnExpression {
|
|
public let id: Common.Identifier
|
|
public init(_ id: Common.Identifier) {
|
|
self.id = id
|
|
}
|
|
}
|
|
|
|
public struct Literal: AnExpression {
|
|
public let literal: P4Value
|
|
public init(_ literal: P4Value) {
|
|
self.literal = literal
|
|
}
|
|
}
|
|
|
|
public enum KeysetExpression: AnExpression {
|
|
case Default
|
|
case Value(AnExpression)
|
|
}
|
|
|
|
public struct SelectCaseExpression: AnExpression {
|
|
public let key: CST.KeysetExpression
|
|
public let next_state_identifier: CST.Identifier
|
|
|
|
public init(withKey key: CST.KeysetExpression, withNextState next_state_id: CST.Identifier) {
|
|
self.key = key
|
|
self.next_state_identifier = next_state_id
|
|
}
|
|
}
|
|
|
|
public struct SelectExpression: AnExpression {
|
|
public let selector: AnExpression
|
|
public let case_expressions: [CST.SelectCaseExpression]
|
|
|
|
public init(
|
|
withSelector selector: AnExpression,
|
|
withSelectCaseExpressions sces: [CST.SelectCaseExpression]
|
|
) {
|
|
self.selector = selector
|
|
self.case_expressions = sces
|
|
}
|
|
|
|
public func append_checked_sce(sce: CST.SelectCaseExpression) -> CST.SelectExpression {
|
|
var new_cses = self.case_expressions
|
|
new_cses.append(sce)
|
|
return SelectExpression(
|
|
withSelector: self.selector, withSelectCaseExpressions: new_cses)
|
|
}
|
|
}
|
|
|
|
public enum BinaryOperatorExpressionType {
|
|
case Add
|
|
case Subtract
|
|
case Multiply
|
|
case Divide
|
|
case Lt
|
|
case Lte
|
|
case Gt
|
|
case Gte
|
|
case Eq
|
|
case And
|
|
case Or
|
|
}
|
|
|
|
public struct BinaryOperatorExpression: AnExpression {
|
|
public let left: AnExpression
|
|
public let right: AnExpression
|
|
public let type: BinaryOperatorExpressionType
|
|
|
|
public init(
|
|
withType tipe: BinaryOperatorExpressionType,
|
|
withLhs lhs: AnExpression,
|
|
withRhs rhs: AnExpression
|
|
) {
|
|
self.type = tipe
|
|
self.left = lhs
|
|
self.right = rhs
|
|
}
|
|
}
|
|
|
|
public struct ArrayAccessExpression: AnExpression {
|
|
public let indexor: AnExpression
|
|
public let name: AnExpression
|
|
|
|
public init(
|
|
withName name: AnExpression,
|
|
withIndexor indexor: AnExpression
|
|
) {
|
|
self.name = name
|
|
self.indexor = indexor
|
|
}
|
|
}
|
|
|
|
public struct FieldAccessExpression: AnExpression {
|
|
public let field: Identifier
|
|
public let strct: AnExpression
|
|
|
|
public init(withStruct strct: AnExpression, withField field: Identifier) {
|
|
self.strct = strct
|
|
self.field = field
|
|
}
|
|
}
|
|
|
|
public struct FunctionCall: AnExpression {
|
|
public let callee: Identifier
|
|
public let arguments: ArgumentList
|
|
|
|
public init(_ callee: Identifier, withArguments arguments: ArgumentList) {
|
|
self.callee = callee
|
|
self.arguments = arguments
|
|
}
|
|
}
|
|
|
|
public struct LocalElements {}
|
|
|
|
public struct LocalElement {}
|
|
|
|
public struct ParserAssignmentStatement: Statement {
|
|
public let lvalue: AnExpression
|
|
public let value: AnExpression
|
|
|
|
public init(
|
|
withLValue lvalue: AnExpression, withValue value: AnExpression
|
|
) {
|
|
self.lvalue = lvalue
|
|
self.value = value
|
|
}
|
|
}
|
|
|
|
/// A P4 Parser State
|
|
public class ParserState {
|
|
let name: Identifier
|
|
public let statements: CST.Statements?
|
|
|
|
public var description: String {
|
|
return "Parser State named \(self.name)"
|
|
}
|
|
|
|
public func getName() -> Identifier {
|
|
return self.name
|
|
}
|
|
|
|
public func getStatements() -> CST.Statements? {
|
|
return self.statements
|
|
}
|
|
|
|
/// Construct a ParserState
|
|
public init(_ name: Identifier, _ statements: CST.Statements? = .none) {
|
|
self.name = name
|
|
self.statements = statements
|
|
}
|
|
}
|
|
|
|
/// TransitionStatement
|
|
///
|
|
/// Only defined to define Compilable extension.
|
|
public struct TransitionStatement {}
|
|
|
|
public class ParserStateDirectTransition: ParserState, AnState {
|
|
public let next_state_identifier: Identifier?
|
|
|
|
public init(
|
|
name: Identifier, withNextStateIdentifier next_state_id: Identifier,
|
|
withStatements stmts: CST.Statements? = .none
|
|
) {
|
|
self.next_state_identifier = next_state_id
|
|
super.init(name, stmts)
|
|
}
|
|
}
|
|
|
|
public class ParserStateNoTransition: ParserState, AnState {
|
|
/// Construct a ParserState
|
|
public init(
|
|
name: Identifier, withStatements stmts: CST.Statements? = .none
|
|
) {
|
|
super.init(name, stmts)
|
|
}
|
|
}
|
|
|
|
public class ParserStateSelectTransition: ParserState, AnState {
|
|
|
|
public let te: SelectExpression
|
|
|
|
public init(
|
|
name: Identifier, withTransitionExpression te: SelectExpression,
|
|
withStatements stmts: CST.Statements? = .none
|
|
) {
|
|
self.te = te
|
|
super.init(name, stmts)
|
|
}
|
|
}
|
|
|
|
public struct ParserStates {
|
|
public var states: [AnState] = Array()
|
|
|
|
public func count() -> Int {
|
|
return states.count
|
|
}
|
|
|
|
public init(_ states: [AnState] = Array()) {
|
|
self.states = states
|
|
}
|
|
|
|
public func append(state: AnState) -> ParserStates {
|
|
var new_states = self.states
|
|
new_states.append(state)
|
|
return ParserStates(new_states)
|
|
}
|
|
}
|
|
|
|
/// A P4 Parser
|
|
///
|
|
/// Note: A Parser is a type
|
|
public struct Parser: AnDeclaration {
|
|
public var states: ParserStates
|
|
|
|
public var name: Identifier
|
|
public var parameters: ParameterList
|
|
|
|
public init(withName name: Identifier) {
|
|
self.states = ParserStates()
|
|
self.parameters = ParameterList()
|
|
self.name = name
|
|
}
|
|
|
|
public init(withName name: Identifier, withParameters parameters: ParameterList) {
|
|
self.states = ParserStates()
|
|
self.parameters = parameters
|
|
self.name = name
|
|
}
|
|
|
|
public var description: String {
|
|
return "Parser \(self.name) with parameters: \(parameters) and states: \(self.states)"
|
|
}
|
|
}
|
|
|
|
public struct Types {}
|
|
|
|
public struct Tipe {
|
|
public let tipe: P4QualifiedType
|
|
public init(_ tipe: P4QualifiedType) {
|
|
self.tipe = tipe
|
|
}
|
|
}
|
|
|
|
public struct Parameter: CustomStringConvertible {
|
|
public var name: CST.Identifier
|
|
public var type: CST.Tipe
|
|
|
|
public init(
|
|
identifier: Identifier, withType type: CST.Tipe
|
|
) {
|
|
self.name = identifier
|
|
self.type = type
|
|
}
|
|
|
|
public var description: String {
|
|
return "Parameter: \(self.name) with type \(self.type)"
|
|
}
|
|
|
|
}
|
|
|
|
public struct ParameterList: CustomStringConvertible {
|
|
public var parameters: [CST.Parameter]
|
|
|
|
public init() {
|
|
self.parameters = Array()
|
|
}
|
|
|
|
public init(_ parameters: [CST.Parameter]) {
|
|
self.parameters = parameters
|
|
}
|
|
|
|
public func addParameter(_ parameter: CST.Parameter) -> CST.ParameterList {
|
|
return CST.ParameterList(self.parameters + [parameter])
|
|
}
|
|
|
|
public var description: String {
|
|
let parameters = self.parameters.map { parameter in
|
|
parameter.description
|
|
}.joined(separator: ";")
|
|
return "Parameter list: \(parameters)"
|
|
}
|
|
}
|
|
|
|
public struct ArgumentList {
|
|
public let arguments: [CST.Argument]
|
|
|
|
public init(_ arguments: [CST.Argument] = []) {
|
|
self.arguments = arguments
|
|
}
|
|
|
|
public func addArgument(_ argument: CST.Argument) -> CST.ArgumentList {
|
|
return ArgumentList(self.arguments + [argument])
|
|
}
|
|
}
|
|
|
|
public struct Argument {
|
|
public let index: Int
|
|
public let argument: CST.AnExpression
|
|
|
|
public init(_ argument: CST.AnExpression, atIndex index: Int) {
|
|
self.argument = argument
|
|
self.index = index
|
|
}
|
|
}
|
|
|
|
public struct Program {
|
|
public var statements: Statements
|
|
public init(_ stmts: Statements = Statements([])) {
|
|
self.statements = stmts
|
|
}
|
|
}
|
|
}
|
|
|
|
public struct CSTCompilerContext {
|
|
public let lexical_context_name: CST.Identifier?
|
|
public let lexical_context_statements: CST.Statements?
|
|
public let extern_context: Bool
|
|
|
|
public init(
|
|
_ name: CST.Identifier? = .none, _ stmts: CST.Statements? = .none, _ extern: Bool = false
|
|
) {
|
|
self.lexical_context_name = name
|
|
self.lexical_context_statements = stmts
|
|
self.extern_context = extern
|
|
}
|
|
|
|
public func update(withContextName cn: CST.Identifier?) -> CSTCompilerContext {
|
|
return CSTCompilerContext(cn, self.lexical_context_statements, self.extern_context)
|
|
}
|
|
|
|
public func update(withContextStatements stmts: CST.Statements?) -> CSTCompilerContext {
|
|
return CSTCompilerContext(self.lexical_context_name, stmts, self.extern_context)
|
|
}
|
|
|
|
public func update(withExtern extern: Bool) -> CSTCompilerContext {
|
|
return CSTCompilerContext(self.lexical_context_name, self.lexical_context_statements, extern)
|
|
}
|
|
}
|