Files
Will Hawkins ef6b07b54a
Continuous Integration / Grammar Tests (push) Successful in 3m52s
Continuous Integration / Library Format Tests (push) Successful in 4m52s
Continuous Integration / Library Tests (push) Successful in 7m32s
Make Formatter Happy
Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
2026-06-15 23:37:48 -04:00

681 lines
18 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.Categories.Expression {}
public struct CST {
public struct Categories {
public protocol LanguageElement {}
public protocol Expression: Categories.LanguageElement {}
public protocol Statement: Categories.LanguageElement {}
public protocol State: Categories.LanguageElement {}
public protocol Declaration: Categories.Statement {}
}
struct Expression {}
public struct Statements: Categories.Statement {
public let statements: [Categories.Statement]
public init(_ s: [Categories.Statement]) {
self.statements = s
}
}
public struct VariableDeclarationStatement: Categories.Statement {
public var initializer: Categories.Expression?
public var identifier: CST.Identifier
public var tipe: CST.Tipe
public init(
identifier: Identifier, withType tipe: CST.Tipe,
withInitializer initializer: Categories.Expression?
) {
self.identifier = identifier
self.initializer = initializer
self.tipe = tipe
}
}
public struct ConditionalStatement: Categories.Statement {
public var condition: Categories.Expression
public var thenn: Categories.Statement
public var elss: Categories.Statement?
public init(condition: Categories.Expression, withThen thenn: Categories.Statement) {
self.condition = condition
self.thenn = thenn
self.elss = .none
}
public init(
condition: Categories.Expression, withThen thenn: Categories.Statement,
andElse elss: Categories.Statement
) {
self.condition = condition
self.thenn = thenn
self.elss = elss
}
}
public struct BlockStatement: Categories.Statement {
public var statements: Statements
public init(_ statements: Statements) {
self.statements = statements
}
}
public struct ReturnStatement: Categories.Statement {
public let value: Categories.Expression
public init(_ value: Categories.Expression) {
self.value = value
}
}
public struct ApplyStatement: Categories.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 struct Declaration {}
public struct Control: CustomStringConvertible, Categories.Declaration {
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: Categories.Declaration {
public let declaration: CST.Categories.Declaration
public init(_ declaration: CST.Categories.Declaration) {
self.declaration = declaration
}
}
public struct FunctionDeclaration: Categories.Declaration {
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: Categories.Declaration {
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: Categories.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: Categories.Statement {
public let expression: Categories.Expression
public init(_ expr: Categories.Expression) {
self.expression = expr
}
}
public struct Identifier: Categories.Expression {
public let id: Common.Identifier
public init(_ id: Common.Identifier) {
self.id = id
}
}
public struct Literal: Categories.Expression {
public let literal: P4Value
public init(_ literal: P4Value) {
self.literal = literal
}
}
public enum KeysetExpression: Categories.Expression {
case Default
case Value(Categories.Expression)
}
public struct SelectCaseExpression: Categories.Expression {
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: Categories.Expression {
public let selector: Categories.Expression
public let case_expressions: [CST.SelectCaseExpression]
public init(
withSelector selector: Categories.Expression,
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: Categories.Expression {
public let left: Categories.Expression
public let right: Categories.Expression
public let type: BinaryOperatorExpressionType
public init(
withType tipe: BinaryOperatorExpressionType,
withLhs lhs: Categories.Expression,
withRhs rhs: Categories.Expression
) {
self.type = tipe
self.left = lhs
self.right = rhs
}
}
public struct ArrayAccessExpression: Categories.Expression {
public let indexor: Categories.Expression
public let name: Categories.Expression
public init(
withName name: Categories.Expression,
withIndexor indexor: Categories.Expression
) {
self.name = name
self.indexor = indexor
}
}
public struct FieldAccessExpression: Categories.Expression {
public let field: Identifier
public let strct: Categories.Expression
public init(withStruct strct: Categories.Expression, withField field: Identifier) {
self.strct = strct
self.field = field
}
}
public struct FunctionCall: Categories.Expression {
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: Categories.Statement {
public let lvalue: Categories.Expression
public let value: Categories.Expression
public init(
withLValue lvalue: Categories.Expression, withValue value: Categories.Expression
) {
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, Categories.State {
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, Categories.State {
/// Construct a ParserState
public init(
name: Identifier, withStatements stmts: CST.Statements? = .none
) {
super.init(name, stmts)
}
}
public class ParserStateSelectTransition: ParserState, Categories.State {
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: [Categories.State] = Array()
public func count() -> Int {
return states.count
}
public init(_ states: [Categories.State] = Array()) {
self.states = states
}
public func append(state: Categories.State) -> 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: Categories.Declaration {
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: Categories.Expression
public init(_ argument: Categories.Expression, 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 Statement {}
}
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)
}
}