@@ -0,0 +1,665 @@
|
||||
// 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: AST.AnExpression {}
|
||||
|
||||
public struct AST {
|
||||
|
||||
public protocol AnExpression {}
|
||||
public protocol AnStatement {}
|
||||
public protocol AnState {}
|
||||
|
||||
public struct Statement {}
|
||||
struct Expression {}
|
||||
|
||||
public struct VariableDeclarationStatement: AnStatement {
|
||||
public var initializer: AnExpression?
|
||||
public var identifier: AST.Identifier
|
||||
public var tipe: AST.Tipe
|
||||
|
||||
public init(
|
||||
identifier: Identifier, withType tipe: AST.Tipe, withInitializer initializer: AnExpression?
|
||||
) {
|
||||
self.identifier = identifier
|
||||
self.initializer = initializer
|
||||
self.tipe = tipe
|
||||
}
|
||||
}
|
||||
|
||||
public struct ConditionalStatement: AnStatement {
|
||||
public var condition: AnExpression
|
||||
public var thenn: AnStatement
|
||||
public var elss: AnStatement?
|
||||
|
||||
public init(condition: AnExpression, withThen thenn: AnStatement) {
|
||||
self.condition = condition
|
||||
self.thenn = thenn
|
||||
self.elss = .none
|
||||
}
|
||||
|
||||
public init(
|
||||
condition: AnExpression, withThen thenn: AnStatement,
|
||||
andElse elss: AnStatement
|
||||
) {
|
||||
self.condition = condition
|
||||
self.thenn = thenn
|
||||
self.elss = elss
|
||||
}
|
||||
}
|
||||
|
||||
public struct BlockStatement: AnStatement {
|
||||
public var statements: [AnStatement]
|
||||
|
||||
public init(_ statements: [AnStatement]) {
|
||||
self.statements = statements
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct ReturnStatement: AnStatement {
|
||||
public let value: AnExpression
|
||||
|
||||
public init(_ value: AnExpression) {
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
public struct ApplyStatement: AnStatement {
|
||||
public let body: AST.BlockStatement?
|
||||
|
||||
public init() { self.body = .none }
|
||||
public init(_ body: AST.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: AST.BlockStatement?
|
||||
public var params: AST.ParameterList
|
||||
public var name: AST.Identifier
|
||||
|
||||
public init(
|
||||
named name: AST.Identifier = AST.Identifier(Common.Identifier(name: "")),
|
||||
withParameters parameters: ParameterList = ParameterList([]),
|
||||
withBody body: AST.BlockStatement? = .none
|
||||
) {
|
||||
self.name = name
|
||||
self.params = parameters
|
||||
self.body = body
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct Actions: CustomStringConvertible {
|
||||
public let actions: [AST.Action]
|
||||
public init(withActions actions: [AST.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: AST.KeysetExpression
|
||||
public let match_type: AST.TableKeyMatchType
|
||||
|
||||
public init(_ key: AST.KeysetExpression, _ match: AST.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: [AST.TableKeyEntry]
|
||||
|
||||
public init(withEntries entries: [AST.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: [AST.Identifier]
|
||||
public init(_ actions: [AST.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: AST.TableActionsProperty
|
||||
public let keys: AST.TableKeys
|
||||
public init(withActions actions: AST.TableActionsProperty, withKeys keys: AST.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: AST.TablePropertyList
|
||||
let name: AST.Identifier
|
||||
public let entries: [(P4Value, AST.Identifier)]
|
||||
|
||||
public init(
|
||||
withName name: AST.Identifier, withPropertyList property_list: AST.TablePropertyList,
|
||||
withEntries entries: [(P4Value, AST.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, AST.Identifier)) -> Table {
|
||||
return Table(
|
||||
withName: self.name, withPropertyList: self.properties, withEntries: self.entries + [entry])
|
||||
}
|
||||
}
|
||||
|
||||
public protocol AnDeclaration: AnStatement {}
|
||||
|
||||
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: AST.Actions
|
||||
public let table: AST.Table
|
||||
let _parameters: AST.ParameterList
|
||||
let _name: AST.Identifier
|
||||
let apply: AST.ApplyStatement
|
||||
|
||||
public var parameters: AST.ParameterList {
|
||||
_parameters
|
||||
}
|
||||
|
||||
public var name: AST.Identifier {
|
||||
_name
|
||||
}
|
||||
|
||||
public init(
|
||||
named: AST.Identifier, withParameters parameters: AST.ParameterList,
|
||||
withTable table: AST.Table,
|
||||
withActions actions: AST.Actions, withApply apply: AST.ApplyStatement
|
||||
) {
|
||||
self._name = named
|
||||
self._parameters = parameters
|
||||
self.actions = actions
|
||||
self.table = table
|
||||
self.apply = apply
|
||||
}
|
||||
|
||||
public func updateTable(addEntry entry: (P4Value, AST.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: AST.AnDeclaration
|
||||
|
||||
public init(_ declaration: AST.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: AST.BlockStatement?
|
||||
public var params: AST.ParameterList
|
||||
public var name: AST.Identifier
|
||||
public var tipe: AST.Tipe
|
||||
|
||||
public init(
|
||||
named name: AST.Identifier, ofType type: AST.Tipe,
|
||||
withParameters parameters: AST.ParameterList,
|
||||
withBody body: AST.BlockStatement?
|
||||
) {
|
||||
self.name = name
|
||||
self.tipe = type
|
||||
self.params = parameters
|
||||
self.body = body
|
||||
}
|
||||
}
|
||||
|
||||
public struct StructDeclaration: AnDeclaration {
|
||||
public let fields: [AST.VariableDeclarationStatement]
|
||||
public let identifier: AST.Identifier
|
||||
public init(_ id: AST.Identifier, _ fields: [AST.VariableDeclarationStatement]) {
|
||||
self.identifier = id
|
||||
self.fields = fields
|
||||
}
|
||||
}
|
||||
|
||||
public struct Instantiation: AnStatement {
|
||||
public let name: AST.Identifier
|
||||
public var tipe: AST.Identifier
|
||||
public let arguments: AST.ArgumentList
|
||||
|
||||
public init(named name: AST.Identifier, withType tipe: AST.Identifier, withArguments arguments: AST.ArgumentList) {
|
||||
self.name = name
|
||||
self.arguments = arguments
|
||||
self.tipe = tipe
|
||||
}
|
||||
}
|
||||
|
||||
public struct ExpressionStatement: AnStatement {
|
||||
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: AST.KeysetExpression
|
||||
public let next_state_identifier: AST.Identifier
|
||||
|
||||
public init(withKey key: AST.KeysetExpression, withNextState next_state_id: AST.Identifier) {
|
||||
self.key = key
|
||||
self.next_state_identifier = next_state_id
|
||||
}
|
||||
}
|
||||
|
||||
public struct SelectExpression: AnExpression {
|
||||
public let selector: AnExpression
|
||||
public let case_expressions: [AST.SelectCaseExpression]
|
||||
|
||||
public init(
|
||||
withSelector selector: AnExpression,
|
||||
withSelectCaseExpressions sces: [AST.SelectCaseExpression]
|
||||
) {
|
||||
self.selector = selector
|
||||
self.case_expressions = sces
|
||||
}
|
||||
|
||||
public func append_checked_sce(sce: AST.SelectCaseExpression) -> AST.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: AnStatement {
|
||||
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: [AnStatement]
|
||||
|
||||
public var description: String {
|
||||
return "Parser State named \(self.name)"
|
||||
}
|
||||
|
||||
public func getName() -> Identifier {
|
||||
return self.name
|
||||
}
|
||||
|
||||
public func getStatements() -> [AnStatement] {
|
||||
return self.statements
|
||||
}
|
||||
|
||||
/// Construct a ParserState
|
||||
public init(_ name: Identifier, _ statements: [AnStatement] = Array()) {
|
||||
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: [AnStatement] = Array(),
|
||||
) {
|
||||
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: [AnStatement] = Array(),
|
||||
) {
|
||||
super.init(name, stmts)
|
||||
}
|
||||
}
|
||||
|
||||
public class ParserStateSelectTransition: ParserState, AnState {
|
||||
|
||||
public let te: SelectExpression
|
||||
|
||||
public init(
|
||||
name: Identifier, withTransitionExpression te: SelectExpression,
|
||||
withStatements stmts: [AnStatement] = Array()
|
||||
) {
|
||||
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: AST.Identifier
|
||||
public var type: AST.Tipe
|
||||
|
||||
public init(
|
||||
identifier: Identifier, withType type: AST.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: [AST.Parameter]
|
||||
|
||||
public init() {
|
||||
self.parameters = Array()
|
||||
}
|
||||
|
||||
public init(_ parameters: [AST.Parameter]) {
|
||||
self.parameters = parameters
|
||||
}
|
||||
|
||||
public func addParameter(_ parameter: AST.Parameter) -> AST.ParameterList {
|
||||
return AST.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: [AST.Argument]
|
||||
|
||||
public init(_ arguments: [AST.Argument] = []) {
|
||||
self.arguments = arguments
|
||||
}
|
||||
|
||||
public func addArgument(_ argument: AST.Argument) -> AST.ArgumentList {
|
||||
return ArgumentList(self.arguments + [argument])
|
||||
}
|
||||
}
|
||||
|
||||
public struct Argument {
|
||||
public let index: Int
|
||||
public let argument: AST.AnExpression
|
||||
|
||||
public init(_ argument: AST.AnExpression, atIndex index: Int) {
|
||||
self.argument = argument
|
||||
self.index = index
|
||||
}
|
||||
}
|
||||
|
||||
public struct Program {
|
||||
public var statements: [AnStatement]
|
||||
public init(_ stmts: [AnStatement] = Array()) {
|
||||
self.statements = stmts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct ASTCompilerContext {
|
||||
public let lexical_context_name: AST.Identifier?
|
||||
public let lexical_context_statements: [AST.AnStatement]?
|
||||
public let extern_context: Bool
|
||||
|
||||
public init(_ name: AST.Identifier? = .none, _ stmts: [AST.AnStatement]? = .none, _ extern: Bool = false) {
|
||||
self.lexical_context_name = name
|
||||
self.lexical_context_statements = stmts
|
||||
self.extern_context = extern
|
||||
}
|
||||
|
||||
public func update(withContextName cn: AST.Identifier?) -> ASTCompilerContext {
|
||||
return ASTCompilerContext(cn, self.lexical_context_statements, self.extern_context)
|
||||
}
|
||||
|
||||
public func update(withContextStatements stmts: [AST.AnStatement]?) -> ASTCompilerContext {
|
||||
return ASTCompilerContext(self.lexical_context_name, stmts, self.extern_context)
|
||||
}
|
||||
|
||||
public func update(withExtern extern: Bool) -> ASTCompilerContext {
|
||||
return ASTCompilerContext(self.lexical_context_name, self.lexical_context_statements, extern)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,369 +16,10 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import Common
|
||||
import P4Lang
|
||||
import P4Runtime
|
||||
import SwiftTreeSitter
|
||||
import TreeSitterExtensions
|
||||
import TreeSitterP4
|
||||
|
||||
func parameter_list_compiler(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<ParameterList> {
|
||||
|
||||
var walker = Walker(node: node)
|
||||
var current_node: Node? = .none
|
||||
|
||||
if node.text == ")" {
|
||||
// There are no parameters!
|
||||
return Result.Ok(ParameterList([]))
|
||||
}
|
||||
|
||||
#RequireNodeType<Node, ParameterList>(
|
||||
node: node, type: "parameter_list", nice_type_name: "Parameter List")
|
||||
|
||||
var parameters: ParameterList = ParameterList([])
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ParameterList>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
|
||||
|
||||
if current_node?.nodeType == "parameter_list" {
|
||||
switch parameter_list_compiler(node: current_node!, withContext: context) {
|
||||
case .Ok(let ps):
|
||||
parameters = ps
|
||||
case .Error(let e): return Result.Error(e)
|
||||
}
|
||||
walker.next()
|
||||
}
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ParameterList>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
|
||||
|
||||
// If this is a ')', we are done.
|
||||
if current_node?.text == ")" {
|
||||
return Result.Ok(parameters)
|
||||
}
|
||||
|
||||
// If this is a comma, we skip it!
|
||||
if current_node?.text == "," {
|
||||
walker.next()
|
||||
}
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ParameterList>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
|
||||
|
||||
// Otherwise, there should be one parameter left!
|
||||
switch Parameter.Compile(node: current_node!, withContext: context) {
|
||||
case .Ok(let parsed_parameter):
|
||||
return Result.Ok(parameters.addParameter(parsed_parameter))
|
||||
case .Error(let e): return Result.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
extension ParameterList: Compilable {
|
||||
public typealias C = ParameterList
|
||||
public static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<ParameterList> {
|
||||
|
||||
let parameter_node = node
|
||||
#RequireNodeType<Node, ParameterList>(
|
||||
node: parameter_node, type: "parameters", nice_type_name: "Parameters")
|
||||
|
||||
var walker = Walker(node: parameter_node)
|
||||
|
||||
var current_node: Node? = .none
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ParameterList>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing '(' in parameter list component")))
|
||||
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ParameterList>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
|
||||
|
||||
return parameter_list_compiler(node: current_node!, withContext: context)
|
||||
}
|
||||
}
|
||||
|
||||
extension Direction: Compilable {
|
||||
public typealias C = Direction
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<Direction> {
|
||||
let direction_node = node
|
||||
#RequireNodeType<Node, Direction>(
|
||||
node: direction_node, type: "direction", nice_type_name: "direction")
|
||||
let directions = [
|
||||
"in": Direction.In,
|
||||
"out": Direction.Out,
|
||||
"inout": Direction.InOut,
|
||||
]
|
||||
|
||||
guard let parsed_direction = directions[direction_node.text!] else {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: direction_node.toSourceLocation(),
|
||||
withError: "\(direction_node.text!) is not a valid direction"))
|
||||
}
|
||||
|
||||
return .Ok(parsed_direction)
|
||||
}
|
||||
}
|
||||
|
||||
extension Parameter: Compilable {
|
||||
public typealias C = Parameter
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<Parameter> {
|
||||
|
||||
#RequireNodeType<Node, P4Statement>(
|
||||
node: node, type: "parameter", nice_type_name: "parameter")
|
||||
|
||||
var walker = Walker(node: node)
|
||||
var current_node: Node? = .none
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<Parameter>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing parameter declaration component")))
|
||||
|
||||
// Annotation?
|
||||
if current_node!.nodeType == "annotations" {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: current_node!.toSourceLocation(),
|
||||
withError: "Annotations in parameter declarations are not yet handled"))
|
||||
// Will increment indexes here.
|
||||
}
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<Parameter>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing parameter declaration component")))
|
||||
|
||||
var direction: Direction? = .none
|
||||
// Direction?
|
||||
if current_node!.nodeType == "direction" {
|
||||
|
||||
let maybe_parsed_direction = Direction.Compile(node: current_node!, withContext: context)
|
||||
guard case .Ok(let parsed_direction) = maybe_parsed_direction else {
|
||||
return .Error(maybe_parsed_direction.error()!)
|
||||
}
|
||||
direction = parsed_direction
|
||||
|
||||
walker.next()
|
||||
}
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<Parameter>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing parameter declaration component")))
|
||||
|
||||
if current_node!.nodeType != "typeRef" {
|
||||
return Result.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Did not find type name for parameter declaration"))
|
||||
}
|
||||
|
||||
guard
|
||||
case .Ok(let parameter_type) = Types.CompileType(type: current_node!, withContext: context)
|
||||
else {
|
||||
return Result.Error(
|
||||
Error(withMessage: "Could not parse a P4 type from \(current_node!.text!)"))
|
||||
}
|
||||
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<Parameter>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing parameter declaration component")))
|
||||
|
||||
if current_node!.nodeType != "identifier" {
|
||||
return Result.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Did not find identifier for parameter statement"))
|
||||
}
|
||||
|
||||
guard
|
||||
case .Ok(let parameter_name) = Identifier.Compile(node: current_node!, withContext: context)
|
||||
else {
|
||||
return Result.Error(
|
||||
Error(withMessage: "Could not parse a parameter name from \(current_node!.text!)"))
|
||||
}
|
||||
|
||||
return Result.Ok(
|
||||
Parameter(
|
||||
identifier: parameter_name,
|
||||
withType: direction != nil
|
||||
? parameter_type.update(addAttribute: P4TypeQualifier.Direction(direction!))
|
||||
: parameter_type),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func argument_list_compiler(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<ArgumentList> {
|
||||
|
||||
var walker = Walker(node: node)
|
||||
var current_node: Node? = .none
|
||||
|
||||
if node.text == ")" {
|
||||
// There are no arguments!
|
||||
return Result.Ok(ArgumentList([]))
|
||||
}
|
||||
|
||||
#RequireNodeType<Node, ArgumentList>(
|
||||
node: node, type: "argument_list", nice_type_name: "argument List")
|
||||
|
||||
var arguments: ArgumentList = ArgumentList([])
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ArgumentList>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
|
||||
|
||||
if current_node?.nodeType == "argument_list" {
|
||||
switch argument_list_compiler(node: current_node!, withContext: context) {
|
||||
case .Ok(let ps):
|
||||
arguments = ps
|
||||
case .Error(let e): return Result.Error(e)
|
||||
}
|
||||
|
||||
walker.next()
|
||||
}
|
||||
|
||||
// We may have moved nodes, check/reset current_node.
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ArgumentList>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
|
||||
|
||||
// If this is a ')', we are done.
|
||||
if current_node?.text == ")" {
|
||||
return Result.Ok(arguments)
|
||||
}
|
||||
|
||||
// If this is a comma, we skip it!
|
||||
if current_node?.text == "," {
|
||||
walker.next()
|
||||
}
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ArgumentList>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
|
||||
|
||||
// Otherwise, there should be one argument left!
|
||||
switch Argument.Compile(node: current_node!, withContext: context) {
|
||||
case .Ok(let ce):
|
||||
return Result.Ok(
|
||||
arguments.addArgument(Argument(ce, atIndex: arguments.count() + 1)))
|
||||
case .Error(let e): return Result.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
extension ArgumentList: Compilable {
|
||||
public typealias C = ArgumentList
|
||||
public static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<ArgumentList> {
|
||||
|
||||
let argument_node = node
|
||||
#RequireNodeType<Node, ArgumentList>(
|
||||
node: argument_node, type: "arguments", nice_type_name: "arguments")
|
||||
|
||||
var walker = Walker(node: argument_node)
|
||||
var current_node: Node? = .none
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ArgumentList>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing '(' in argument list component")))
|
||||
|
||||
walker.next()
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ArgumentList>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
|
||||
|
||||
return argument_list_compiler(node: current_node!, withContext: context)
|
||||
}
|
||||
}
|
||||
|
||||
extension Argument: Compilable {
|
||||
public typealias C = P4Expression
|
||||
public static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<P4Expression> {
|
||||
let argument_node = node
|
||||
#RequireNodeType<Node, P4Expression>(
|
||||
node: argument_node, type: "argument", nice_type_name: "argument")
|
||||
|
||||
let expression_node = node.child(at: 0)!
|
||||
|
||||
return switch Expression.Compile(node: expression_node, withContext: context) {
|
||||
case .Ok(let compiled_expression): .Ok(compiled_expression)
|
||||
case .Error(let e): .Error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ContainsInvalidStatements(
|
||||
statement: P4Statement, invalids: [P4Statement.Type]
|
||||
) -> Bool {
|
||||
for es in invalids {
|
||||
if type(of: statement) == es {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ContainsInvalidStatements(block: BlockStatement, invalids: [P4Statement.Type]) -> Bool {
|
||||
return block.statements.contains { statement in
|
||||
for es in invalids {
|
||||
if type(of: statement) == es {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
extension Node {
|
||||
public func toSourceLocation() -> SourceLocation {
|
||||
return SourceLocation(self.range.location, self.range.length)
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import Common
|
||||
import P4Runtime
|
||||
import SwiftTreeSitter
|
||||
import TreeSitterExtensions
|
||||
import TreeSitterP4
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+199
-463
@@ -16,66 +16,34 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import Common
|
||||
import P4Lang
|
||||
import P4Runtime
|
||||
import SwiftTreeSitter
|
||||
import TreeSitterP4
|
||||
|
||||
extension TypedIdentifier: CompilableExpression {
|
||||
public static func compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression?> {
|
||||
extension AST.Identifier: CompilableExpression {
|
||||
public static func CompileExpression(
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
|
||||
let node = node.child(at: 0)!
|
||||
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
|
||||
node: node, type: "identifier")
|
||||
|
||||
guard
|
||||
case Result.Ok(let type) = context.instances.lookup(
|
||||
identifier: Common.Identifier(name: node.text!))
|
||||
else {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Cannot find \(node.text!) in scope"))
|
||||
}
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: node, type: "identifier", nice_type_name: "Identifier")
|
||||
|
||||
/// TODO: If there is a value here, then we can make this a compile-time constant!
|
||||
return .Ok(TypedIdentifier(name: node.text!, withType: type.0))
|
||||
}
|
||||
}
|
||||
|
||||
extension TypedIdentifier: CompilableLValueExpression {
|
||||
public static func compile_as_lvalue(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4LValueExpression?> {
|
||||
|
||||
let expression = node.child(at: 0)!
|
||||
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
|
||||
node: expression, type: "identifier")
|
||||
|
||||
let maybe_parsed_expression = TypedIdentifier.compile(node: node, withContext: context)
|
||||
guard case .Ok(let maybe_typed_identifier) = maybe_parsed_expression else {
|
||||
return .Error(maybe_parsed_expression.error()!)
|
||||
}
|
||||
|
||||
let typed_identifier_expression = maybe_typed_identifier as! TypedIdentifier
|
||||
|
||||
return Result.Ok(typed_identifier_expression)
|
||||
return .Ok(AST.Identifier(Common.Identifier(name: node.text!)))
|
||||
}
|
||||
}
|
||||
|
||||
extension P4BooleanValue: CompilableExpression {
|
||||
public static func compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression?> {
|
||||
public static func CompileExpression(
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
let node = node.child(at: 0)!
|
||||
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
|
||||
node: node, type: "booleanLiteralExpression")
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: node, type: "booleanLiteralExpression", nice_type_name: "Boolean Literal Expression")
|
||||
|
||||
if node.text == "false" {
|
||||
return .Ok(P4Value(P4BooleanValue(withValue: false)))
|
||||
return .Ok(AST.Literal(P4Value(P4BooleanValue(withValue: false))))
|
||||
} else if node.text == "true" {
|
||||
return .Ok(P4Value(P4BooleanValue(withValue: true)))
|
||||
return .Ok(AST.Literal(P4Value(P4BooleanValue(withValue: true))))
|
||||
}
|
||||
|
||||
return .Error(
|
||||
@@ -86,13 +54,14 @@ extension P4BooleanValue: CompilableExpression {
|
||||
}
|
||||
|
||||
extension P4IntValue: CompilableExpression {
|
||||
public static func compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression?> {
|
||||
public static func CompileExpression(
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
let node = node.child(at: 0)!
|
||||
|
||||
#SkipUnlessNodesTypes<SwiftTreeSitter.Node>(
|
||||
node: node, types: ["integer", "integer_elaborated"])
|
||||
#RequireNodesType<Node, AST.AnExpression>(
|
||||
nodes: node, type: ["integer", "integer_elaborated"],
|
||||
nice_type_names: ["Integer", "Elaborated Integer"])
|
||||
|
||||
var bit_width: BitWidth = BitWidth.Infinite
|
||||
let value_source: String
|
||||
@@ -124,7 +93,7 @@ extension P4IntValue: CompilableExpression {
|
||||
}
|
||||
|
||||
if let parsed_int = Int(value_source) {
|
||||
return .Ok(P4Value(P4IntValue(withValue: parsed_int, andWidth: bit_width)))
|
||||
return .Ok(AST.Literal(P4Value(P4IntValue(withValue: parsed_int, andWidth: bit_width))))
|
||||
} else {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
@@ -135,131 +104,83 @@ extension P4IntValue: CompilableExpression {
|
||||
}
|
||||
|
||||
extension P4StringValue: CompilableExpression {
|
||||
public static func compile(
|
||||
node: SwiftTreeSitter.Node, withContext scopes: CompilerContext
|
||||
) -> Result<P4Expression?> {
|
||||
public static func CompileExpression(
|
||||
node: SwiftTreeSitter.Node, withContext scopes: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
let node = node.child(at: 0)!
|
||||
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
|
||||
node: node, type: "string_literal")
|
||||
return .Ok(P4Value(P4StringValue(withValue: node.text!)))
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: node, type: "string_literal", nice_type_name: "String Literal")
|
||||
return .Ok(AST.Literal(P4Value(P4StringValue(withValue: node.text!))))
|
||||
}
|
||||
}
|
||||
|
||||
extension KeysetExpression: CompilableExpression {
|
||||
public static func compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression?> {
|
||||
extension AST.Expression: Compilable {
|
||||
public static func Compile(
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: node, type: "expression", nice_type_name: "expression")
|
||||
|
||||
let expression_node = node.child(at: 0)!
|
||||
#RequireNodesType<Node, AST.AnExpression>(
|
||||
nodes: expression_node, type: ["grouped_expression", "simple_expression"],
|
||||
nice_type_names: ["grouped expression", "simple expression"])
|
||||
|
||||
// If this is a grouped expression, recurse!
|
||||
if expression_node.nodeType == "grouped_expression" {
|
||||
return AST.Expression.Compile(node: expression_node.child(at: 1)!, withContext: context)
|
||||
}
|
||||
|
||||
let expression_parsers: [CompilableExpression.Type] = [
|
||||
P4BooleanValue.self, P4StringValue.self, P4IntValue.self, AST.Identifier.self,
|
||||
AST.BinaryOperatorExpression.self, AST.ArrayAccessExpression.self, AST.FieldAccessExpression.self,
|
||||
AST.FunctionCall.self,
|
||||
]
|
||||
|
||||
for candidate_expression_parser in expression_parsers {
|
||||
switch candidate_expression_parser.CompileExpression(
|
||||
node: expression_node, withContext: context)
|
||||
{
|
||||
case .Ok(let parsed): return .Ok(parsed)
|
||||
case .Error(let e): return .Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Error(Error(withMessage: "\(node.range): Could not parse into expression"))
|
||||
}
|
||||
}
|
||||
|
||||
extension AST.KeysetExpression: CompilableExpression {
|
||||
public static func CompileExpression(
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
let keyset_expression_node = node.child(at: 0)!
|
||||
|
||||
#RequireNodesType<Node, P4Expression>(
|
||||
#RequireNodesType<Node, AST.AnExpression>(
|
||||
nodes: keyset_expression_node, type: ["expression", "default_keyset"],
|
||||
nice_type_names: ["expression", "default keyset"])
|
||||
|
||||
// If there is a default keyset, that's easy!
|
||||
if keyset_expression_node.nodeType == "default_keyset" {
|
||||
return .Ok(KeysetExpression(P4Value(P4SetDefaultValue(withType: context.expected_type!))))
|
||||
return .Ok(AST.KeysetExpression.Default)
|
||||
}
|
||||
|
||||
// Compile the expression:
|
||||
let maybe_compiled_set_expression = Expression.Compile(
|
||||
let maybe_compiled_set_expression = AST.Expression.Compile(
|
||||
node: keyset_expression_node, withContext: context)
|
||||
guard case .Ok(let compiled_expression) = maybe_compiled_set_expression else {
|
||||
return .Error(maybe_compiled_set_expression.error()!)
|
||||
}
|
||||
|
||||
return .Ok(KeysetExpression(compiled_expression))
|
||||
return .Ok(AST.KeysetExpression.Value(compiled_expression))
|
||||
}
|
||||
}
|
||||
|
||||
struct Expression {
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression> {
|
||||
#RequireNodeType<Node, P4Expression>(
|
||||
node: node, type: "expression", nice_type_name: "expression")
|
||||
|
||||
let expression_node = node.child(at: 0)!
|
||||
#RequireNodesType<Node, P4Expression>(
|
||||
nodes: expression_node, type: ["grouped_expression", "simple_expression"],
|
||||
nice_type_names: ["grouped expression", "simple expression"])
|
||||
|
||||
// If this is a grouped expression, recurse!
|
||||
if expression_node.nodeType == "grouped_expression" {
|
||||
return Expression.Compile(node: expression_node.child(at: 1)!, withContext: context)
|
||||
}
|
||||
|
||||
let expression_parsers: [CompilableExpression.Type] = [
|
||||
P4BooleanValue.self, P4StringValue.self, P4IntValue.self, TypedIdentifier.self,
|
||||
BinaryOperatorExpression.self, ArrayAccessExpression.self, FieldAccessExpression.self,
|
||||
FunctionCall.self,
|
||||
]
|
||||
|
||||
for candidate_expression_parser in expression_parsers {
|
||||
switch candidate_expression_parser.compile(
|
||||
node: expression_node, withContext: context)
|
||||
{
|
||||
case .Ok(.some(let parsed)): return .Ok(parsed)
|
||||
case .Error(let e): return .Error(e)
|
||||
default: continue
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Error(Error(withMessage: "\(node.range): Could not parse into expression"))
|
||||
}
|
||||
}
|
||||
|
||||
struct LValue {
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<P4LValueExpression> {
|
||||
#RequireNodeType<Node, P4Expression>(
|
||||
node: node, type: "expression", nice_type_name: "expression")
|
||||
|
||||
let expression_node = node.child(at: 0)!
|
||||
#RequireNodesType<Node, P4Expression>(
|
||||
nodes: expression_node, type: ["grouped_expression", "simple_expression"],
|
||||
nice_type_names: ["grouped expression", "simple expression"])
|
||||
|
||||
// If this is a grouped expression, recurse!
|
||||
if expression_node.nodeType == "grouped_expression" {
|
||||
return LValue.Compile(node: expression_node.child(at: 1)!, withContext: context)
|
||||
}
|
||||
|
||||
let lvalue_parsers: [CompilableLValueExpression.Type] = [
|
||||
TypedIdentifier.self, FieldAccessExpression.self, ArrayAccessExpression.self,
|
||||
]
|
||||
|
||||
for candidate_lvalue_parser in lvalue_parsers {
|
||||
switch candidate_lvalue_parser.compile_as_lvalue(
|
||||
node: expression_node, withContext: context)
|
||||
{
|
||||
case .Ok(.some(let parsed)): return .Ok(parsed)
|
||||
case .Error(let e): return .Error(e)
|
||||
default: continue
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Error(Error(withMessage: "\(node.range): Could not parse into expression"))
|
||||
}
|
||||
}
|
||||
|
||||
struct Identifier {
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<Common.Identifier> {
|
||||
return if let node_text_value = node.text {
|
||||
.Ok(Common.Identifier(name: node_text_value))
|
||||
} else {
|
||||
.Error(Error(withMessage: "Could not parse an identifier from \(node)"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SelectExpression: CompilableExpression {
|
||||
public static func compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression?> {
|
||||
#RequireNodeType<Node, (SelectExpression, CompilerContext)>(
|
||||
extension AST.SelectExpression: CompilableExpression {
|
||||
public static func CompileExpression(
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
#RequireNodeType<Node, (AST.SelectExpression, ASTCompilerContext)>(
|
||||
node: node, type: "selectExpression", nice_type_name: "parser select expression")
|
||||
|
||||
guard let selector_node = node.child(at: 2),
|
||||
@@ -279,7 +200,7 @@ extension SelectExpression: CompilableExpression {
|
||||
withError: "Could not find select expression body"))
|
||||
}
|
||||
|
||||
let maybe_selector = Expression.Compile(node: selector_node, withContext: context)
|
||||
let maybe_selector = AST.Expression.Compile(node: selector_node, withContext: context)
|
||||
guard case .Ok(let selector) = maybe_selector else {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
@@ -289,14 +210,14 @@ extension SelectExpression: CompilableExpression {
|
||||
))
|
||||
}
|
||||
|
||||
var sces: [SelectCaseExpression] = Array()
|
||||
var sces: [AST.SelectCaseExpression] = Array()
|
||||
var sces_errors: (any Errorable)? = .none
|
||||
|
||||
select_body_node.enumerateNamedChildren { current_node in
|
||||
let maybe_parsed_cse = SelectCaseExpression.compile(
|
||||
node: current_node, withContext: context.update(newExpectation: selector.type()))
|
||||
let maybe_parsed_cse = AST.SelectCaseExpression.CompileExpression(
|
||||
node: current_node, withContext: context)
|
||||
switch maybe_parsed_cse {
|
||||
case .Ok(let parsed_cse): sces.append(parsed_cse as! SelectCaseExpression)
|
||||
case .Ok(let parsed_cse): sces.append(parsed_cse as! AST.SelectCaseExpression)
|
||||
case .Error(let e):
|
||||
sces_errors =
|
||||
if let sces_errors = sces_errors {
|
||||
@@ -312,18 +233,18 @@ extension SelectExpression: CompilableExpression {
|
||||
}
|
||||
|
||||
return .Ok(
|
||||
SelectExpression(withSelector: selector, withSelectCaseExpressions: sces),
|
||||
AST.SelectExpression(withSelector: selector, withSelectCaseExpressions: sces),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension SelectCaseExpression: CompilableExpression {
|
||||
public static func compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression?> {
|
||||
if node.nodeType != "selectCase" {
|
||||
return Result.Error(Error(withMessage: "Expected select case not found"))
|
||||
}
|
||||
extension AST.SelectCaseExpression: CompilableExpression {
|
||||
public static func CompileExpression(
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: node, type: "selectCase", nice_type_name: "Select Case")
|
||||
|
||||
guard let keysetexpression_node = node.child(at: 0),
|
||||
keysetexpression_node.nodeType == "keysetExpression"
|
||||
@@ -337,94 +258,56 @@ extension SelectCaseExpression: CompilableExpression {
|
||||
return Result.Error(Error(withMessage: "Missing target state in select case"))
|
||||
}
|
||||
|
||||
let maybe_parsed_keysetexpression = KeysetExpression.compile(
|
||||
let maybe_parsed_keysetexpression = AST.KeysetExpression.CompileExpression(
|
||||
node: keysetexpression_node, withContext: context)
|
||||
guard case Result.Ok(let maybe_keysetexpression) = maybe_parsed_keysetexpression else {
|
||||
return Result.Error(maybe_parsed_keysetexpression.error()!)
|
||||
}
|
||||
|
||||
guard let maybe_keysetexpression = maybe_keysetexpression else {
|
||||
return Result.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: keysetexpression_node.toSourceLocation(),
|
||||
withError: "Missing expected keyset expression"))
|
||||
}
|
||||
let keysetexpression = maybe_keysetexpression as! AST.KeysetExpression
|
||||
|
||||
let keysetexpression = maybe_keysetexpression as! KeysetExpression
|
||||
|
||||
if case .Error(let e) = keysetexpression.compatible(type: context.expected_type!) {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: keysetexpression_node.toSourceLocation(), withError: e.msg()))
|
||||
}
|
||||
|
||||
let maybe_parsed_targetstate = Identifier.Compile(
|
||||
let maybe_parsed_targetstate = AST.Identifier.CompileExpression(
|
||||
node: targetstate_node, withContext: context)
|
||||
guard case .Ok(let targetstate) = maybe_parsed_targetstate else {
|
||||
return Result.Error(maybe_parsed_targetstate.error()!)
|
||||
}
|
||||
|
||||
return .Ok(
|
||||
SelectCaseExpression(
|
||||
withKey: keysetexpression, withNextState: targetstate)
|
||||
AST.SelectCaseExpression(
|
||||
withKey: keysetexpression, withNextState: targetstate as! AST.Identifier)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// swift-format-ignore
|
||||
public typealias BinaryOperatorChecker = (P4Expression, P4Expression) -> Result<()>
|
||||
|
||||
public func binary_and_or_operator_checker(
|
||||
left: P4Expression, right: P4Expression
|
||||
) -> Result<()> {
|
||||
// Check that both are Boolean-typed things!
|
||||
if !(left.type().baseType().eq(rhs: P4Boolean()) && right.type().baseType().eq(rhs: P4Boolean()))
|
||||
{
|
||||
return .Error(Error(withMessage: "And/Or on operands with non-bool type is not allowed"))
|
||||
}
|
||||
return .Ok(())
|
||||
}
|
||||
|
||||
public func binary_int_math_operator_checker(
|
||||
left: P4Expression, right: P4Expression
|
||||
) -> Result<()> {
|
||||
// Check that both are int-typed things!
|
||||
if !(left.type().baseType().eq(rhs: P4Int()) && right.type().baseType().eq(rhs: P4Int())) {
|
||||
return .Error(
|
||||
Error(withMessage: "Mathematical operation on operands with non-int type is not allowed"))
|
||||
}
|
||||
return .Ok(())
|
||||
}
|
||||
|
||||
extension BinaryOperatorExpression: CompilableExpression {
|
||||
public static func compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<(P4Expression)?> {
|
||||
extension AST.BinaryOperatorExpression: CompilableExpression {
|
||||
public static func CompileExpression(
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
let expression = node.child(at: 0)!
|
||||
|
||||
#SkipUnlessNodeType<Node>(
|
||||
node: expression, type: "binaryOperatorExpression")
|
||||
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: expression, type: "binaryOperatorExpression",
|
||||
nice_type_name: "Binary Operator Expression")
|
||||
let binary_operator_expression_node = expression.child(at: 0)!
|
||||
var walker = Walker(node: binary_operator_expression_node)
|
||||
|
||||
var current_node: Node? = .none
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Malformed binary operator expression"
|
||||
)))
|
||||
|
||||
/// TODO: This macro cannot handle new lines in the arrays
|
||||
// swift-format-ignore
|
||||
#RequireNodesType<Node, P4Expression?>(
|
||||
#RequireNodesType<Node, AST.AnExpression>(
|
||||
nodes: binary_operator_expression_node,
|
||||
type: ["binaryEqualOperatorExpression", "binaryLessThanOperatorExpression", "binaryLessThanEqualOperatorExpression", "binaryGreaterThanOperatorExpression", "binaryGreaterThanEqualOperatorExpression", "binaryAndOperatorExpression", "binaryOrOperatorExpression", "binaryAddOperatorExpression", "binarySubtractOperatorExpression", "binaryMultiplyOperatorExpression", "binaryDivideOperatorExpression"],
|
||||
nice_type_names: [ "binary equal operator", "binary less than operator", "binary less than or equal to operator", "binary greater than operator", "binary greater than or equal to operator", "binary and operator", "binary or operator", "binary add operator", "binary subtract operator", "binary multiply operator", "binary divide operator"])
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing LHS for binary operator expression")))
|
||||
@@ -434,7 +317,7 @@ extension BinaryOperatorExpression: CompilableExpression {
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing binary operator for binary operator expression")))
|
||||
@@ -442,105 +325,92 @@ extension BinaryOperatorExpression: CompilableExpression {
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing RHS for binary operator expression")))
|
||||
|
||||
let right_hand_side_raw = current_node!
|
||||
|
||||
let maybe_left_hand_side = Expression.Compile(node: left_hand_side_raw, withContext: context)
|
||||
let maybe_left_hand_side = AST.Expression.Compile(
|
||||
node: left_hand_side_raw, withContext: context)
|
||||
guard case Result.Ok(let left_hand_side) = maybe_left_hand_side else {
|
||||
return Result.Error(maybe_left_hand_side.error()!)
|
||||
}
|
||||
|
||||
let maybe_right_hand_side = Expression.Compile(node: right_hand_side_raw, withContext: context)
|
||||
let maybe_right_hand_side = AST.Expression.Compile(
|
||||
node: right_hand_side_raw, withContext: context)
|
||||
guard case Result.Ok(let right_hand_side) = maybe_right_hand_side else {
|
||||
return Result.Error(maybe_right_hand_side.error()!)
|
||||
}
|
||||
|
||||
let evaluators:
|
||||
[String: (String, P4QualifiedType, BinaryOperatorChecker?, BinaryOperatorEvaluator)] = [
|
||||
"binaryEqualOperatorExpression": (
|
||||
"Binary Equal", P4QualifiedType(P4Boolean()), Optional<BinaryOperatorChecker>.none,
|
||||
binary_equal_operator_evaluator
|
||||
),
|
||||
"binaryLessThanOperatorExpression": (
|
||||
"Binary Less Than", P4QualifiedType(P4Boolean()), Optional<BinaryOperatorChecker>.none,
|
||||
binary_lt_operator_evaluator
|
||||
),
|
||||
"binaryLessThanEqualOperatorExpression": (
|
||||
"Binary Less Than Or Equal", P4QualifiedType(P4Boolean()),
|
||||
Optional<BinaryOperatorChecker>.none,
|
||||
binary_lte_operator_evaluator
|
||||
),
|
||||
"binaryGreaterThanOperatorExpression": (
|
||||
"Binary Greater Than", P4QualifiedType(P4Boolean()), Optional<BinaryOperatorChecker>.none,
|
||||
binary_gt_operator_evaluator
|
||||
),
|
||||
"binaryGreaterThanEqualOperatorExpression": (
|
||||
"Binary Greater Than Or Equal", P4QualifiedType(P4Boolean()),
|
||||
Optional<BinaryOperatorChecker>.none,
|
||||
binary_gte_operator_evaluator
|
||||
),
|
||||
"binaryAndOperatorExpression": (
|
||||
"Binary Or", P4QualifiedType(P4Boolean()), binary_and_or_operator_checker,
|
||||
binary_and_operator_evaluator
|
||||
),
|
||||
"binaryOrOperatorExpression": (
|
||||
"Binary And", P4QualifiedType(P4Boolean()), binary_and_or_operator_checker,
|
||||
binary_or_operator_evaluator
|
||||
),
|
||||
"binaryAddOperatorExpression": (
|
||||
"Binary Add", P4QualifiedType(P4Int()), binary_int_math_operator_checker,
|
||||
binary_add_operator_evaluator
|
||||
),
|
||||
"binarySubtractOperatorExpression": (
|
||||
"Binary Subtract", P4QualifiedType(P4Int()), binary_int_math_operator_checker,
|
||||
binary_subtract_operator_evaluator
|
||||
),
|
||||
"binaryMultiplyOperatorExpression": (
|
||||
"Binary Multiply", P4QualifiedType(P4Int()), binary_int_math_operator_checker,
|
||||
binary_multiply_operator_evaluator
|
||||
),
|
||||
"binaryDivideOperatorExpression": (
|
||||
"Binary Divide", P4QualifiedType(P4Int()), binary_int_math_operator_checker,
|
||||
binary_divide_operator_evaluator
|
||||
),
|
||||
]
|
||||
|
||||
if !left_hand_side.type().eq(right_hand_side.type()) {
|
||||
return Result.Error(
|
||||
Error(withMessage: "Types of values used with binary expression are not the same"))
|
||||
}
|
||||
let evaluators: [String: (String, P4QualifiedType, AST.BinaryOperatorExpressionType)] = [
|
||||
"binaryEqualOperatorExpression": (
|
||||
"Binary Equal", P4QualifiedType(P4Boolean()),
|
||||
AST.BinaryOperatorExpressionType.Eq
|
||||
),
|
||||
"binaryLessThanOperatorExpression": (
|
||||
"Binary Less Than", P4QualifiedType(P4Boolean()),
|
||||
AST.BinaryOperatorExpressionType.Lt
|
||||
),
|
||||
"binaryLessThanEqualOperatorExpression": (
|
||||
"Binary Less Than Or Equal", P4QualifiedType(P4Boolean()),
|
||||
AST.BinaryOperatorExpressionType.Lte
|
||||
),
|
||||
"binaryGreaterThanOperatorExpression": (
|
||||
"Binary Greater Than", P4QualifiedType(P4Boolean()),
|
||||
AST.BinaryOperatorExpressionType.Gt
|
||||
),
|
||||
"binaryGreaterThanEqualOperatorExpression": (
|
||||
"Binary Greater Than Or Equal", P4QualifiedType(P4Boolean()),
|
||||
AST.BinaryOperatorExpressionType.Gte
|
||||
),
|
||||
"binaryAndOperatorExpression": (
|
||||
"Binary Or", P4QualifiedType(P4Boolean()),
|
||||
AST.BinaryOperatorExpressionType.And
|
||||
),
|
||||
"binaryOrOperatorExpression": (
|
||||
"Binary And", P4QualifiedType(P4Boolean()),
|
||||
AST.BinaryOperatorExpressionType.Or
|
||||
),
|
||||
"binaryAddOperatorExpression": (
|
||||
"Binary Add", P4QualifiedType(P4Int()),
|
||||
AST.BinaryOperatorExpressionType.Add
|
||||
),
|
||||
"binarySubtractOperatorExpression": (
|
||||
"Binary Subtract", P4QualifiedType(P4Int()),
|
||||
AST.BinaryOperatorExpressionType.Subtract
|
||||
),
|
||||
"binaryMultiplyOperatorExpression": (
|
||||
"Binary Multiply", P4QualifiedType(P4Int()),
|
||||
AST.BinaryOperatorExpressionType.Multiply
|
||||
),
|
||||
"binaryDivideOperatorExpression": (
|
||||
"Binary Divide", P4QualifiedType(P4Int()),
|
||||
AST.BinaryOperatorExpressionType.Divide
|
||||
),
|
||||
]
|
||||
|
||||
guard let selected_evaluator = evaluators[binary_operator_expression_node.nodeType!] else {
|
||||
return Result.Error(
|
||||
Error(withMessage: "No evaluator for \(binary_operator_expression_node.nodeType!)"))
|
||||
}
|
||||
|
||||
if let checker = selected_evaluator.2,
|
||||
case .Error(let e) = checker(left_hand_side, right_hand_side)
|
||||
{
|
||||
return Result.Error(e)
|
||||
}
|
||||
|
||||
return .Ok(
|
||||
BinaryOperatorExpression(
|
||||
withEvaluator: (selected_evaluator.0, selected_evaluator.1, selected_evaluator.3),
|
||||
AST.BinaryOperatorExpression(
|
||||
withType: selected_evaluator.2,
|
||||
withLhs: left_hand_side, withRhs: right_hand_side))
|
||||
}
|
||||
}
|
||||
|
||||
extension ArrayAccessExpression: CompilableExpression {
|
||||
public static func compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression?> {
|
||||
extension AST.ArrayAccessExpression: CompilableExpression {
|
||||
public static func CompileExpression(
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
let expression = node.child(at: 0)!
|
||||
|
||||
#SkipUnlessNodeType<Node>(
|
||||
node: expression, type: "arrayAccessExpression")
|
||||
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: expression, type: "arrayAccessExpression", nice_type_name: "Array Access Expression")
|
||||
let array_access_expression_node = expression
|
||||
|
||||
var walker = Walker(node: array_access_expression_node)
|
||||
@@ -548,11 +418,11 @@ extension ArrayAccessExpression: CompilableExpression {
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Malformed array access expression")))
|
||||
|
||||
#RequireNodeType<Node, P4Expression?>(
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: current_node!, type: "expression",
|
||||
nice_type_name: "array identifier expression")
|
||||
let array_access_identifier_node = current_node!
|
||||
@@ -560,7 +430,7 @@ extension ArrayAccessExpression: CompilableExpression {
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing [ for array access expression")))
|
||||
@@ -569,52 +439,43 @@ extension ArrayAccessExpression: CompilableExpression {
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing indexor expression for array access expression")))
|
||||
|
||||
#RequireNodeType<Node, P4Expression?>(
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: current_node!, type: "expression",
|
||||
nice_type_name: "array indexor expression")
|
||||
|
||||
let array_access_indexor_node = current_node!
|
||||
|
||||
let maybe_array_identifier = Expression.Compile(
|
||||
let maybe_array_identifier = AST.Expression.Compile(
|
||||
node: array_access_identifier_node, withContext: context)
|
||||
guard case Result.Ok(let array_identifier) = maybe_array_identifier else {
|
||||
return Result.Error(maybe_array_identifier.error()!)
|
||||
}
|
||||
|
||||
let maybe_array_type = array_identifier.type()
|
||||
guard let array_type = maybe_array_type.baseType() as? P4Array else {
|
||||
return Result.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: array_access_identifier_node.toSourceLocation(),
|
||||
withError: "\(array_identifier) does not name an array type")
|
||||
)
|
||||
}
|
||||
|
||||
let maybe_array_indexor = Expression.Compile(
|
||||
let maybe_array_indexor = AST.Expression.Compile(
|
||||
node: array_access_indexor_node, withContext: context)
|
||||
guard case Result.Ok(let array_indexor) = maybe_array_indexor else {
|
||||
return Result.Error(maybe_array_indexor.error()!)
|
||||
}
|
||||
|
||||
return .Ok(
|
||||
ArrayAccessExpression(
|
||||
withName: array_identifier, withType: array_type, withIndexor: array_indexor))
|
||||
AST.ArrayAccessExpression(
|
||||
withName: array_identifier, withIndexor: array_indexor))
|
||||
}
|
||||
}
|
||||
|
||||
extension FieldAccessExpression: CompilableExpression {
|
||||
public static func compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression?> {
|
||||
extension AST.FieldAccessExpression: CompilableExpression {
|
||||
public static func CompileExpression(
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
let expression = node.child(at: 0)!
|
||||
|
||||
#SkipUnlessNodeType<Node>(
|
||||
node: expression, type: "fieldAccessExpression")
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: expression, type: "fieldAccessExpression", nice_type_name: "Array Access Expression")
|
||||
|
||||
let field_access_expression_node = expression
|
||||
|
||||
@@ -623,11 +484,11 @@ extension FieldAccessExpression: CompilableExpression {
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Malformed field access expression")))
|
||||
|
||||
#RequireNodeType<Node, P4Expression?>(
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: current_node!, type: "expression",
|
||||
nice_type_name: "struct identifier expression")
|
||||
let struct_identifier_node = current_node!
|
||||
@@ -635,7 +496,7 @@ extension FieldAccessExpression: CompilableExpression {
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing . for field access expression")))
|
||||
@@ -643,198 +504,73 @@ extension FieldAccessExpression: CompilableExpression {
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing field name for field access expression")))
|
||||
|
||||
#RequireNodeType<Node, P4Expression?>(
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: current_node!, type: "identifier",
|
||||
nice_type_name: "field name")
|
||||
|
||||
let field_name_node = current_node!
|
||||
|
||||
// Make sure that the identifier really identifies a struct.
|
||||
let maybe_struct_identifier = Expression.Compile(
|
||||
let maybe_struct_identifier = AST.Expression.Compile(
|
||||
node: struct_identifier_node, withContext: context)
|
||||
guard case Result.Ok(let struct_identifier) = maybe_struct_identifier else {
|
||||
return Result.Error(maybe_struct_identifier.error()!)
|
||||
}
|
||||
guard let struct_type = struct_identifier.type().baseType() as? P4Struct else {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: struct_identifier_node.toSourceLocation(),
|
||||
withError: "\(struct_identifier_node.text!) does not have struct type"))
|
||||
}
|
||||
|
||||
let maybe_field_name = Identifier.Compile(
|
||||
let maybe_field_name = AST.Identifier.CompileExpression(
|
||||
node: field_name_node, withContext: context)
|
||||
guard case Result.Ok(let field_name) = maybe_field_name else {
|
||||
return Result.Error(maybe_field_name.error()!)
|
||||
}
|
||||
|
||||
// Make sure that the field is valid for the struct type.
|
||||
let maybe_field_type = struct_type.fields.get_field_type(field_name)
|
||||
guard let field_type = maybe_field_type else {
|
||||
return .Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: field_name_node.toSourceLocation(),
|
||||
withError: "\(field_name) is not a valid field for struct with type \(struct_type)"))
|
||||
}
|
||||
|
||||
return .Ok(
|
||||
FieldAccessExpression(
|
||||
AST.FieldAccessExpression(
|
||||
withStruct: struct_identifier,
|
||||
withField: P4StructFieldIdentifier(id: field_name, withType: field_type)))
|
||||
withField: field_name as! AST.Identifier))
|
||||
}
|
||||
}
|
||||
|
||||
extension FieldAccessExpression: CompilableLValueExpression {
|
||||
public static func compile_as_lvalue(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4LValueExpression?> {
|
||||
let expression = node.child(at: 0)!
|
||||
#SkipUnlessNodeType<Node>(
|
||||
node: expression, type: "fieldAccessExpression")
|
||||
|
||||
let maybe_parsed_expression = FieldAccessExpression.compile(node: node, withContext: context)
|
||||
guard case .Ok(let maybe_field_access_expression) = maybe_parsed_expression else {
|
||||
return .Error(maybe_parsed_expression.error()!)
|
||||
}
|
||||
|
||||
let field_access_expression = maybe_field_access_expression as! FieldAccessExpression
|
||||
|
||||
return Result.Ok(field_access_expression)
|
||||
}
|
||||
}
|
||||
|
||||
extension ArrayAccessExpression: CompilableLValueExpression {
|
||||
public static func compile_as_lvalue(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4LValueExpression?> {
|
||||
let expression = node.child(at: 0)!
|
||||
#SkipUnlessNodeType<Node>(
|
||||
node: expression, type: "arrayAccessExpression")
|
||||
|
||||
let maybe_parsed_expression = ArrayAccessExpression.compile(node: node, withContext: context)
|
||||
guard case .Ok(let maybe_array_access_expression) = maybe_parsed_expression else {
|
||||
return .Error(maybe_parsed_expression.error()!)
|
||||
}
|
||||
|
||||
let array_access_expression = maybe_array_access_expression as! ArrayAccessExpression
|
||||
|
||||
return Result.Ok(array_access_expression)
|
||||
}
|
||||
}
|
||||
|
||||
extension FunctionCall: CompilableExpression {
|
||||
public static func compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression?> {
|
||||
extension AST.FunctionCall: CompilableExpression {
|
||||
public static func CompileExpression(
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression> {
|
||||
|
||||
let expression = node.child(at: 0)!
|
||||
#SkipUnlessNodeType<Node>(
|
||||
node: expression, type: "function_call")
|
||||
#RequireNodeType<Node, AST.AnExpression>(
|
||||
node: expression, type: "function_call", nice_type_name: "Function Call")
|
||||
|
||||
var walker = Walker(node: expression)
|
||||
var current_node: Node? = .none
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
|
||||
|
||||
let maybe_callee_name = Identifier.Compile(
|
||||
let maybe_callee_name = AST.Identifier.CompileExpression(
|
||||
node: current_node!, withContext: context)
|
||||
guard case .Ok(let callee_name) = maybe_callee_name else {
|
||||
return Result.Error(maybe_callee_name.error()!)
|
||||
}
|
||||
|
||||
var maybe_callee: Result<(FunctionDeclaration?, Declaration?)> =
|
||||
switch context.types.lookup(identifier: callee_name) {
|
||||
case .Ok(let looked_up):
|
||||
switch looked_up {
|
||||
case let callee as FunctionDeclaration:
|
||||
Result<(FunctionDeclaration?, Declaration?)>.Ok((callee, .none)) // What we found is actually a function declaration
|
||||
default:
|
||||
Result<(FunctionDeclaration?, Declaration?)>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: current_node!.toSourceLocation(),
|
||||
withError: "\(callee_name) is not a function"))
|
||||
}
|
||||
case .Error(let e): Result<(FunctionDeclaration?, Declaration?)>.Error(e)
|
||||
}
|
||||
|
||||
maybe_callee =
|
||||
if case .Error(let e) = maybe_callee {
|
||||
switch context.externs.lookup(identifier: callee_name) {
|
||||
case .Ok(let callee as Declaration):
|
||||
// Now, make sure that it is a function declaration!
|
||||
switch callee.identifier.type.baseType() {
|
||||
case is FunctionDeclaration: Result.Ok((.none, callee))
|
||||
default:
|
||||
.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: current_node!.toSourceLocation(),
|
||||
withError: "\(callee_name) is not a function"))
|
||||
}
|
||||
default: .Error(e)
|
||||
}
|
||||
} else {
|
||||
maybe_callee
|
||||
}
|
||||
|
||||
guard case .Ok(let callee) = maybe_callee else {
|
||||
return .Error(maybe_callee.error()!)
|
||||
}
|
||||
|
||||
walker.next()
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<P4Expression?>.Error(
|
||||
or: Result<AST.AnExpression>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
|
||||
|
||||
let maybe_argument_list = ArgumentList.Compile(node: current_node!, withContext: context)
|
||||
let maybe_argument_list = AST.ArgumentList.Compile(node: current_node!, withContext: context)
|
||||
|
||||
guard case .Ok(let arguments) = maybe_argument_list else {
|
||||
return .Error(maybe_argument_list.error()!)
|
||||
}
|
||||
|
||||
// Now, compare the arguments with the parameters:
|
||||
|
||||
let params =
|
||||
switch callee {
|
||||
case (.some(let callee), .none): Optional<ParameterList>.some(callee.params)
|
||||
case (.none, .some(let callee)):
|
||||
Optional<ParameterList>.some((callee.ffi!.type().baseType() as! FunctionDeclaration).params)
|
||||
default: Optional<ParameterList>.none
|
||||
}
|
||||
|
||||
guard case .some(let params) = params else {
|
||||
return Result.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Could not lookup the parameters for the called function (\(callee_name))"))
|
||||
}
|
||||
|
||||
if case .Error(let e) = arguments.compatible(params) {
|
||||
return .Error(e)
|
||||
}
|
||||
|
||||
// All good!
|
||||
|
||||
return switch callee {
|
||||
case (.some(let callee), .none): .Ok(FunctionCall(callee, withArguments: arguments))
|
||||
case (.none, .some(let callee)): .Ok(FunctionCall(callee.ffi!, withArguments: arguments))
|
||||
default:
|
||||
Result.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Unexpected error occurred calling function named (\(callee_name))"
|
||||
))
|
||||
}
|
||||
return .Ok(AST.FunctionCall(callee_name as! AST.Identifier, withArguments: arguments))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,17 +16,15 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import Common
|
||||
import P4Lang
|
||||
import P4Runtime
|
||||
import SwiftTreeSitter
|
||||
import TreeSitterExtensions
|
||||
import TreeSitterP4
|
||||
|
||||
extension Statement: Compilable {
|
||||
public typealias C = P4Statement
|
||||
extension AST.Statement: Compilable {
|
||||
public typealias C = AST.AnStatement
|
||||
public static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4Statement> {
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnStatement> {
|
||||
|
||||
if node.nodeType != "parserStatement" && node.nodeType != "statement" {
|
||||
return Result.Error(
|
||||
@@ -38,11 +36,11 @@ extension Statement: Compilable {
|
||||
let statement = node.child(at: 0)!
|
||||
|
||||
let statementParsers: [String: CompilableStatement.Type] = [
|
||||
"assignmentStatement": ParserAssignmentStatement.self,
|
||||
"expressionStatement": ExpressionStatement.self,
|
||||
"variableDeclaration": VariableDeclarationStatement.self,
|
||||
"conditionalStatement": ConditionalStatement.self, "blockStatement": BlockStatement.self,
|
||||
"return_statement": ReturnStatement.self,
|
||||
"assignmentStatement": AST.ParserAssignmentStatement.self,
|
||||
"expressionStatement": AST.ExpressionStatement.self,
|
||||
"variableDeclaration": AST.VariableDeclarationStatement.self,
|
||||
"conditionalStatement": AST.ConditionalStatement.self, "blockStatement": AST.BlockStatement.self,
|
||||
"return_statement": AST.ReturnStatement.self,
|
||||
]
|
||||
guard let parser = statementParsers[statement.nodeType ?? ""] else {
|
||||
return Result.Error(
|
||||
@@ -63,13 +61,13 @@ extension Statement: Compilable {
|
||||
}
|
||||
}
|
||||
|
||||
extension LocalElements: Compilable {
|
||||
public typealias C = P4Statement
|
||||
extension AST.LocalElements: Compilable {
|
||||
public typealias C = AST.AnStatement
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<P4Statement> {
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnStatement> {
|
||||
let localElementsParsers: [String: CompilableStatement.Type] = [
|
||||
"variableDeclaration": VariableDeclarationStatement.self
|
||||
"variableDeclaration": AST.VariableDeclarationStatement.self
|
||||
]
|
||||
|
||||
guard let parser = localElementsParsers[node.nodeType ?? ""] else {
|
||||
@@ -88,11 +86,11 @@ extension LocalElements: Compilable {
|
||||
}
|
||||
}
|
||||
|
||||
extension ParserState: Compilable {
|
||||
public typealias C = ParserState
|
||||
extension AST.ParserState: Compilable {
|
||||
public typealias C = AST.AnState
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<ParserState> {
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnState> {
|
||||
var walker = Walker(node: node)
|
||||
|
||||
var current_node: Node? = .none
|
||||
@@ -108,7 +106,7 @@ extension ParserState: Compilable {
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ParserState>.Error(
|
||||
or: Result<AST.AnState>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing elements in parser state declaration")))
|
||||
@@ -126,12 +124,12 @@ extension ParserState: Compilable {
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ParserState>.Error(
|
||||
or: Result<AST.AnState>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing elements in parser state declaration")))
|
||||
|
||||
let maybe_state_identifier = Identifier.Compile(
|
||||
let maybe_state_identifier = AST.Identifier.CompileExpression(
|
||||
node: current_node!, withContext: context)
|
||||
guard case Result.Ok(let state_identifier) = maybe_state_identifier else {
|
||||
return Result.Error(maybe_state_identifier.error()!)
|
||||
@@ -142,13 +140,13 @@ extension ParserState: Compilable {
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ParserState>.Error(
|
||||
or: Result<AST.AnState>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing body of state declaration")
|
||||
))
|
||||
|
||||
var errors: (any Errorable)? = .none
|
||||
var parsed_s: [P4Statement] = Array()
|
||||
var parsed_s: [AST.AnStatement] = Array()
|
||||
|
||||
if current_node!.nodeType == "parserStatements" {
|
||||
switch SpecialCompilers.Statements.Compile(
|
||||
@@ -173,14 +171,13 @@ extension ParserState: Compilable {
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<ParserState>.Error(
|
||||
or: Result<AST.AnState>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing transition statement of state declaration")))
|
||||
|
||||
let updated_context = SpecialCompilers.Statements.effect(statements: parsed_s, context: context)
|
||||
.update(newLexicalContextName: state_identifier).update(newLexicalContextStatements: parsed_s)
|
||||
let updated_context = context.update(withContextName: (state_identifier as! AST.Identifier)).update(withContextStatements: parsed_s)
|
||||
|
||||
return TransitionStatement.Compile(node: current_node!, withContext: updated_context)
|
||||
return AST.TransitionStatement.Compile(node: current_node!, withContext: updated_context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,6 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import Common
|
||||
import P4Lang
|
||||
import P4Runtime
|
||||
import SwiftTreeSitter
|
||||
import TreeSitterExtensions
|
||||
import TreeSitterP4
|
||||
@@ -26,33 +24,44 @@ public protocol CompilableValue {
|
||||
static func CompileValue(withValue value: String) -> Result<P4DataValue>
|
||||
}
|
||||
|
||||
public protocol MaybeCompilableType {
|
||||
static func MaybeCompileType(
|
||||
type: SwiftTreeSitter.Node, withContext: ASTCompilerContext
|
||||
) -> Result<AST.Tipe?>
|
||||
}
|
||||
|
||||
public protocol CompilableType {
|
||||
static func CompileType(
|
||||
type: SwiftTreeSitter.Node, withContext: CompilerContext
|
||||
) -> Result<P4Type?>
|
||||
type: SwiftTreeSitter.Node, withContext: ASTCompilerContext
|
||||
) -> Result<AST.Tipe>
|
||||
}
|
||||
|
||||
public protocol CompilableExpression {
|
||||
static func compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<P4Expression?>
|
||||
}
|
||||
|
||||
public protocol CompilableLValueExpression {
|
||||
static func compile_as_lvalue(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<P4LValueExpression?>
|
||||
static func CompileExpression(
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnExpression>
|
||||
}
|
||||
|
||||
public protocol Compilable<C> {
|
||||
associatedtype C
|
||||
static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<C>
|
||||
}
|
||||
|
||||
public protocol CompilableStatement {
|
||||
static func CompileStatement(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<P4Statement>
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnStatement>
|
||||
}
|
||||
|
||||
public protocol ASTVisitor<T> {
|
||||
associatedtype T
|
||||
func visit(node: AST.BinaryOperatorExpression, driver: ASTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: AST.Literal, driver: ASTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: AST.Identifier, driver: ASTVisitorDriver, context: T) -> Result<T>
|
||||
|
||||
func visit(node: AST.Parser, driver: ASTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: AST.ParserStateDirectTransition, driver: ASTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: AST.ParserStateNoTransition, driver: ASTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: AST.ParserStateSelectTransition, driver: ASTVisitorDriver, context: T) -> Result<T>
|
||||
}
|
||||
@@ -16,22 +16,14 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import Common
|
||||
import P4Lang
|
||||
import P4Runtime
|
||||
import SwiftTreeSitter
|
||||
import TreeSitterExtensions
|
||||
import TreeSitterP4
|
||||
|
||||
protocol AnyCompilable {
|
||||
static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<(Any, CompilerContext)>
|
||||
}
|
||||
|
||||
extension TransitionStatement: Compilable {
|
||||
extension AST.TransitionStatement: Compilable {
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<ParserState> {
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnState> {
|
||||
|
||||
guard let state_identifier = context.lexical_context_name else {
|
||||
return .Error(
|
||||
@@ -71,51 +63,27 @@ extension TransitionStatement: Compilable {
|
||||
|
||||
// If the next node is an identifier, we have the simple form ...
|
||||
if next_node.nodeType == "identifier" {
|
||||
let maybe_parsed_next_state_id = Identifier.Compile(
|
||||
let maybe_parsed_next_state_id = AST.Identifier.CompileExpression(
|
||||
node: next_node, withContext: context)
|
||||
if case .Ok(let next_state_id) = maybe_parsed_next_state_id {
|
||||
if case .Ok(let next_state) = context.instances.lookup(identifier: next_state_id) {
|
||||
switch next_state {
|
||||
case (_, .some(let instance)):
|
||||
return .Ok(
|
||||
ParserStateDirectTransition(
|
||||
name: state_identifier,
|
||||
withNextState: instance.dataValue() as! InstantiatedParserState,
|
||||
withStatements: stmts,
|
||||
)
|
||||
)
|
||||
case (_, .none):
|
||||
return .Ok(
|
||||
ParserStateDirectTransition(
|
||||
name: state_identifier,
|
||||
withNextStateIdentifier: next_state_id, withStatements: stmts)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
||||
return .Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"\(next_state_id) does not name a parser state in scope"
|
||||
))
|
||||
}
|
||||
} else {
|
||||
return .Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"Could not parse the next state in a transition statement: \(maybe_parsed_next_state_id.error()!)"
|
||||
))
|
||||
switch maybe_parsed_next_state_id {
|
||||
case .Ok(let next_state_id):
|
||||
return .Ok(
|
||||
AST.ParserStateDirectTransition(
|
||||
name: (state_identifier),
|
||||
withNextStateIdentifier: next_state_id as! AST.Identifier, withStatements: stmts))
|
||||
case .Error(let e):
|
||||
return .Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
// We know that the next node is a select expression.
|
||||
return
|
||||
switch SelectExpression.compile(node: next_node, withContext: context)
|
||||
switch AST.SelectExpression.CompileExpression(node: next_node, withContext: context)
|
||||
{
|
||||
case .Ok(let tse):
|
||||
.Ok(
|
||||
ParserStateSelectTransition(
|
||||
name: state_identifier, withTransitionExpression: tse as! SelectExpression,
|
||||
AST.ParserStateSelectTransition(
|
||||
name: state_identifier, withTransitionExpression: tse as! AST.SelectExpression,
|
||||
withStatements: stmts,
|
||||
)
|
||||
)
|
||||
@@ -127,8 +95,8 @@ extension TransitionStatement: Compilable {
|
||||
public struct SpecialCompilers {
|
||||
public struct Statements {
|
||||
static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<[P4Statement]> {
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<[AST.AnStatement]> {
|
||||
if node.nodeType != "statements" && node.nodeType != "parserStatements" {
|
||||
return Result.Error(
|
||||
ErrorWithLocation(
|
||||
@@ -136,16 +104,14 @@ public struct SpecialCompilers {
|
||||
}
|
||||
|
||||
var errors: (any Errorable)? = .none
|
||||
var current_context = context
|
||||
var parsed_s: [P4Statement] = Array()
|
||||
var parsed_s: [AST.AnStatement] = Array()
|
||||
|
||||
node.enumerateNamedChildren { node in
|
||||
switch Statement.Compile(
|
||||
node: node, withContext: current_context)
|
||||
switch AST.Statement.Compile(
|
||||
node: node, withContext: context)
|
||||
{
|
||||
case .Ok(let parsed_statement):
|
||||
parsed_s.append(parsed_statement)
|
||||
current_context = parsed_statement.effect(context: current_context)
|
||||
case .Error(let e):
|
||||
errors =
|
||||
if let errors = errors {
|
||||
@@ -162,28 +128,18 @@ public struct SpecialCompilers {
|
||||
|
||||
return Result.Ok(parsed_s)
|
||||
}
|
||||
|
||||
static func effect(statements: [P4Statement], context: CompilerContext) -> CompilerContext {
|
||||
var current = context
|
||||
for s in statements {
|
||||
current = s.effect(context: current)
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static func CompileParserBody(
|
||||
withName name: Common.Identifier, withParameters parameters: ParameterList, node: Node,
|
||||
withContext context: CompilerContext
|
||||
) -> Result<P4Lang.Parser> {
|
||||
withName name: AST.Identifier, withParameters parameters: AST.ParameterList, node: Node,
|
||||
withContext context: ASTCompilerContext
|
||||
) -> Result<AST.Parser> {
|
||||
|
||||
var parser = P4Lang.Parser(withName: name, withParameters: parameters)
|
||||
var parser = AST.Parser(withName: name, withParameters: parameters)
|
||||
|
||||
// Build a state from each one listed.
|
||||
var error: (any Errorable)? = .none
|
||||
var errors: (any Errorable)? = .none
|
||||
|
||||
var current_context = context
|
||||
/// TODO: Assert that there is only one.
|
||||
node.enumerateNamedChildren { parser_state in
|
||||
if parser_state.nodeType != "parserState" {
|
||||
@@ -191,53 +147,32 @@ public struct SpecialCompilers {
|
||||
}
|
||||
|
||||
// Parse a state in a nested scope.
|
||||
switch ParserState.Compile(
|
||||
switch AST.ParserState.Compile(
|
||||
node: parser_state,
|
||||
withContext: context.update(newInstances: current_context.instances.enter()))
|
||||
withContext: context)
|
||||
{
|
||||
case Result.Ok(let state):
|
||||
let statement = state as P4Statement
|
||||
current_context = statement.effect(context: current_context)
|
||||
// All states are instances inside the parser.
|
||||
parser.states = parser.states.append(state: state)
|
||||
case Result.Error(let e): error = e
|
||||
case Result.Error(let e):
|
||||
errors =
|
||||
if let errors = errors {
|
||||
errors.append(error: e)
|
||||
} else {
|
||||
e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let error = error {
|
||||
return .Error(error)
|
||||
if let errors = errors {
|
||||
return .Error(errors)
|
||||
}
|
||||
|
||||
return Result.Ok(parser)
|
||||
return .Ok(parser)
|
||||
}
|
||||
|
||||
public struct ProgramCompiler {
|
||||
public static func Compile(_ source: String) -> Result<P4Lang.Program> {
|
||||
|
||||
// Certain names are always in scope during compilation.
|
||||
var globals = StaticVarValueScopes().enter()
|
||||
globals = globals.declare(
|
||||
identifier: accept.state().getName(),
|
||||
withValue: (P4QualifiedType(accept.type()), P4Value(accept))
|
||||
)
|
||||
.declare(
|
||||
identifier: reject.state.getName(),
|
||||
withValue: (P4QualifiedType(reject.type()), P4Value(reject)))
|
||||
|
||||
return ProgramCompiler.Compile(
|
||||
source, withGlobalInstances: globals, withGlobalTypes: .none, withFFIs: [])
|
||||
}
|
||||
|
||||
public static func Compile(
|
||||
_ source: String, withGlobalInstances globalInstances: StaticVarValueScopes
|
||||
) -> Result<P4Lang.Program> {
|
||||
return ProgramCompiler.Compile(
|
||||
source, withGlobalInstances: globalInstances, withGlobalTypes: .none, withFFIs: [])
|
||||
}
|
||||
|
||||
public static func Compile(
|
||||
_ source: String, withGlobalInstances globalInstances: StaticVarValueScopes?,
|
||||
withGlobalTypes globalTypes: TypeTypeScopes?, withFFIs ffis: [P4FFI] = Array()
|
||||
) -> Result<P4Lang.Program> {
|
||||
public static func Compile(_ source: String) -> Result<AST.Program> {
|
||||
|
||||
let maybe_parser = ConfigureP4Parser()
|
||||
guard case .Ok(let p) = maybe_parser else {
|
||||
@@ -252,38 +187,25 @@ public struct SpecialCompilers {
|
||||
return Result.Error(Error(withMessage: "Could not compile the P4 program"))
|
||||
}
|
||||
|
||||
var program = P4Lang.Program()
|
||||
var program = AST.Program()
|
||||
|
||||
// Set up a context for parsing.
|
||||
var compilation_context = CompilerContext()
|
||||
|
||||
// Add our FFIs
|
||||
compilation_context = compilation_context.update(newFFIs: ffis)
|
||||
let compilation_context = ASTCompilerContext()
|
||||
|
||||
var errors: (any Errorable)? = .none
|
||||
|
||||
// If the caller gave any global instances, add them here.
|
||||
if let globalInstances = globalInstances {
|
||||
compilation_context = compilation_context.update(newInstances: globalInstances)
|
||||
}
|
||||
|
||||
// If the caller gave any global types, add them here.
|
||||
if let globalTypes = globalTypes {
|
||||
compilation_context = compilation_context.update(newTypes: globalTypes)
|
||||
}
|
||||
|
||||
// Try to parse all top-level declarations.
|
||||
result?.rootNode?.enumerateNamedChildren { (declaration_node: Node) in
|
||||
let declaration_parsers: [String: CompilableStatement.Type] = [
|
||||
"declaration": Declaration.self,
|
||||
"instantiation": Instantiation.self,
|
||||
"declaration": AST.Declaration.self,
|
||||
"instantiation": AST.Instantiation.self,
|
||||
]
|
||||
|
||||
if let parser = declaration_parsers[declaration_node.nodeType!] {
|
||||
let r = parser.CompileStatement(node: declaration_node, withContext: compilation_context)
|
||||
switch r {
|
||||
case .Ok(let compiled):
|
||||
compilation_context = compiled.effect(context: compilation_context)
|
||||
program.statements = program.statements + [compiled]
|
||||
case .Error(let e):
|
||||
errors =
|
||||
if let errors = errors {
|
||||
@@ -310,28 +232,8 @@ public struct SpecialCompilers {
|
||||
if let errors = errors {
|
||||
return .Error(errors)
|
||||
}
|
||||
|
||||
// Any of the instances that are in the top-level scope should go into the program!
|
||||
program.instances = Array(
|
||||
compilation_context.instances.filter { (_, v) in
|
||||
v.1 != nil
|
||||
}.map { (_, v) in
|
||||
v.1!
|
||||
})
|
||||
|
||||
// Any of the types that are in the top-level scope should go into the program!
|
||||
program.types = Array(
|
||||
compilation_context.types.map { (_, v) in
|
||||
v
|
||||
})
|
||||
|
||||
// Any of the extern types that are in the top-level scope should go into the program!
|
||||
program.externs = Array(
|
||||
compilation_context.externs.map { (_, v) in
|
||||
v
|
||||
})
|
||||
|
||||
return Result.Ok(program)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,18 +16,17 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import Common
|
||||
import P4Lang
|
||||
import P4Runtime
|
||||
import SwiftTreeSitter
|
||||
import TreeSitterExtensions
|
||||
import TreeSitterP4
|
||||
|
||||
extension BlockStatement: Compilable {
|
||||
public typealias C = BlockStatement
|
||||
extension AST.BlockStatement: Compilable {
|
||||
public typealias C = AST.BlockStatement
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<BlockStatement> {
|
||||
#RequireNodeType<Node, (P4Statement)>(
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.BlockStatement> {
|
||||
/*
|
||||
#RequireNodeType<Node, AST.BlockStatement>(
|
||||
node: node, type: "blockStatement", nice_type_name: "block statement")
|
||||
|
||||
var walker = Walker(node: node)
|
||||
@@ -35,7 +34,7 @@ extension BlockStatement: Compilable {
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<BlockStatement>.Error(
|
||||
or: Result<AST.BlockStatement>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
|
||||
|
||||
@@ -46,13 +45,13 @@ extension BlockStatement: Compilable {
|
||||
withError: "Missing { on block statement"))
|
||||
}
|
||||
|
||||
var statements: [P4Statement] = Array()
|
||||
var statements: [AST.AnStatement] = Array()
|
||||
var parse_err: (any Errorable)? = .none
|
||||
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<BlockStatement>.Error(
|
||||
or: Result<AST.BlockStatement>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
|
||||
|
||||
@@ -75,7 +74,7 @@ extension BlockStatement: Compilable {
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<BlockStatement>.Error(
|
||||
or: Result<AST.BlockStatement>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
|
||||
|
||||
@@ -86,20 +85,22 @@ extension BlockStatement: Compilable {
|
||||
withError: "Missing } on block statement"))
|
||||
}
|
||||
|
||||
return .Ok(BlockStatement(statements))
|
||||
return .Ok(AST.BlockStatement(statements))
|
||||
*/
|
||||
return .Ok(AST.BlockStatement([]))
|
||||
}
|
||||
}
|
||||
|
||||
@deriveCompilableStatement
|
||||
extension BlockStatement: CompilableStatement {}
|
||||
extension AST.BlockStatement: CompilableStatement {}
|
||||
|
||||
extension ConditionalStatement: Compilable {
|
||||
public typealias C = ConditionalStatement
|
||||
extension AST.ConditionalStatement: Compilable {
|
||||
public typealias C = AST.ConditionalStatement
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<ConditionalStatement> {
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.ConditionalStatement> {
|
||||
|
||||
#RequireNodeType<Node, (P4Statement)>(
|
||||
#RequireNodeType<Node, AST.ConditionalStatement>(
|
||||
node: node, type: "conditionalStatement", nice_type_name: "conditional statement")
|
||||
|
||||
let maybe_condition_expression = node.child(at: 2)
|
||||
@@ -123,7 +124,7 @@ extension ConditionalStatement: Compilable {
|
||||
}
|
||||
|
||||
guard
|
||||
case .Ok(let condition) = Expression.Compile(
|
||||
case .Ok(let condition) = AST.Expression.Compile(
|
||||
node: condition_expression, withContext: context)
|
||||
else {
|
||||
return Result.Error(
|
||||
@@ -131,7 +132,7 @@ extension ConditionalStatement: Compilable {
|
||||
}
|
||||
|
||||
guard
|
||||
case .Ok(let thenns) = Statement.Compile(
|
||||
case .Ok(let thenns) = AST.Statement.Compile(
|
||||
node: thens, withContext: context)
|
||||
else {
|
||||
return Result.Error(
|
||||
@@ -140,10 +141,10 @@ extension ConditionalStatement: Compilable {
|
||||
"Could not parse the then block in a conditional statement"))
|
||||
}
|
||||
|
||||
let optional_elss: Result<any P4Statement>? =
|
||||
let optional_elss: Result<AST.AnStatement>? =
|
||||
if let elss = node.child(at: 6) {
|
||||
.some(
|
||||
Statement.Compile(
|
||||
AST.Statement.Compile(
|
||||
node: elss, withContext: context))
|
||||
} else {
|
||||
.none
|
||||
@@ -159,22 +160,22 @@ extension ConditionalStatement: Compilable {
|
||||
"Could not parse the else block in a conditional statement"))
|
||||
}
|
||||
return .Ok(
|
||||
ConditionalStatement(condition: condition, withThen: thenns, andElse: elss))
|
||||
AST.ConditionalStatement(condition: condition, withThen: thenns, andElse: elss))
|
||||
}
|
||||
return .Ok(ConditionalStatement(condition: condition, withThen: thenns))
|
||||
return .Ok(AST.ConditionalStatement(condition: condition, withThen: thenns))
|
||||
}
|
||||
}
|
||||
|
||||
@deriveCompilableStatement
|
||||
extension ConditionalStatement: CompilableStatement {}
|
||||
extension AST.ConditionalStatement: CompilableStatement {}
|
||||
|
||||
extension VariableDeclarationStatement: Compilable {
|
||||
public typealias C = VariableDeclarationStatement
|
||||
extension AST.VariableDeclarationStatement: Compilable {
|
||||
public typealias C = AST.VariableDeclarationStatement
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<VariableDeclarationStatement> {
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.VariableDeclarationStatement> {
|
||||
|
||||
#RequireNodeType<Node, (P4Statement)>(
|
||||
#RequireNodeType<Node, AST.VariableDeclarationStatement>(
|
||||
node: node, type: "variableDeclaration", nice_type_name: "variable declaration statement")
|
||||
|
||||
let maybe_typeref = node.child(at: 0)
|
||||
@@ -200,20 +201,21 @@ extension VariableDeclarationStatement: Compilable {
|
||||
let maybe_rvalue = node.childCount > 3 ? node.child(at: 3) : .none
|
||||
|
||||
guard
|
||||
case .Ok(let parsed_variablename) = Identifier.Compile(
|
||||
case .Ok(let parsed_variablename) = AST.Identifier.CompileExpression(
|
||||
node: variablename, withContext: context)
|
||||
else {
|
||||
return Result.Error(
|
||||
Error(withMessage: "Could not parse variable name"))
|
||||
}
|
||||
|
||||
guard case .Ok(let declaration_p4_type) = Types.CompileType(type: typeref, withContext: context)
|
||||
guard
|
||||
case .Ok(let declaration_p4_type) = AST.Types.CompileType(type: typeref, withContext: context)
|
||||
else {
|
||||
return Result.Error(
|
||||
Error(withMessage: "Could not parse a P4 type from \(typeref.text!)"))
|
||||
}
|
||||
|
||||
var initializer: P4Expression? = .none
|
||||
var initializer: AST.AnExpression? = .none
|
||||
|
||||
// If there is an initializer, it must be an expression.
|
||||
if let initializer_expression = maybe_rvalue {
|
||||
@@ -224,7 +226,7 @@ extension VariableDeclarationStatement: Compilable {
|
||||
withError: "initial value for declaration statement is not an expression"))
|
||||
}
|
||||
|
||||
let maybe_parsed_rvalue = Expression.Compile(
|
||||
let maybe_parsed_rvalue = AST.Expression.Compile(
|
||||
node: initializer_expression, withContext: context)
|
||||
guard
|
||||
case .Ok(let parsed_rvalue) = maybe_parsed_rvalue
|
||||
@@ -232,67 +234,47 @@ extension VariableDeclarationStatement: Compilable {
|
||||
return .Error(maybe_parsed_rvalue.error()!)
|
||||
}
|
||||
|
||||
if parsed_rvalue.type().eq(declaration_p4_type) {
|
||||
initializer = parsed_rvalue
|
||||
} else {
|
||||
return Result.Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"Cannot initialize \(parsed_variablename) (with type \(declaration_p4_type)) from expression with type \(parsed_rvalue.type())"
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no initializer, then it must be defaultable.
|
||||
|
||||
if initializer == nil {
|
||||
initializer = declaration_p4_type.def()
|
||||
}
|
||||
|
||||
guard let initializer = initializer else {
|
||||
return Result.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "No initializer for declaration"))
|
||||
initializer = parsed_rvalue
|
||||
}
|
||||
|
||||
return Result.Ok(
|
||||
VariableDeclarationStatement(
|
||||
identifier: TypedIdentifier(id: parsed_variablename, withType: declaration_p4_type),
|
||||
AST.VariableDeclarationStatement(
|
||||
identifier: parsed_variablename as! AST.Identifier, withType: declaration_p4_type,
|
||||
withInitializer: initializer),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@deriveCompilableStatement
|
||||
extension VariableDeclarationStatement: CompilableStatement {}
|
||||
extension AST.VariableDeclarationStatement: CompilableStatement {}
|
||||
|
||||
extension ExpressionStatement: Compilable {
|
||||
public typealias C = ExpressionStatement
|
||||
extension AST.ExpressionStatement: Compilable {
|
||||
public typealias C = AST.ExpressionStatement
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<ExpressionStatement> {
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.ExpressionStatement> {
|
||||
#RequireNodeType<Node, (P4Statement)>(
|
||||
node: node, type: "expressionStatement", nice_type_name: "expression statement")
|
||||
|
||||
let expression_node = node.child(at: 0)!
|
||||
|
||||
return switch Expression.Compile(node: expression_node, withContext: context) {
|
||||
case .Ok(let expression): .Ok(ExpressionStatement(expression))
|
||||
return switch AST.Expression.Compile(node: expression_node, withContext: context) {
|
||||
case .Ok(let expression): .Ok(AST.ExpressionStatement(expression))
|
||||
case .Error(let e): .Error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@deriveCompilableStatement
|
||||
extension ExpressionStatement: CompilableStatement {}
|
||||
extension AST.ExpressionStatement: CompilableStatement {}
|
||||
|
||||
extension ParserAssignmentStatement: Compilable {
|
||||
public typealias C = ParserAssignmentStatement
|
||||
extension AST.ParserAssignmentStatement: Compilable {
|
||||
public typealias C = AST.ParserAssignmentStatement
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<ParserAssignmentStatement> {
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.ParserAssignmentStatement> {
|
||||
|
||||
#RequireNodeType<Node, (P4Statement)>(
|
||||
#RequireNodeType<Node, AST.ParserAssignmentStatement>(
|
||||
node: node, type: "assignmentStatement", nice_type_name: "assignment statement")
|
||||
|
||||
guard let lvalue_node = node.child(at: 0),
|
||||
@@ -313,95 +295,77 @@ extension ParserAssignmentStatement: Compilable {
|
||||
withError: "Missing rvalue in assignment statement"))
|
||||
}
|
||||
|
||||
let maybe_parsed_rvalue = Expression.Compile(
|
||||
let maybe_parsed_rvalue = AST.Expression.Compile(
|
||||
node: rvalue_node, withContext: context)
|
||||
guard case Result.Ok(let rvalue) = maybe_parsed_rvalue else {
|
||||
return Result.Error(maybe_parsed_rvalue.error()!)
|
||||
}
|
||||
|
||||
let maybe_parsed_lvalue = LValue.Compile(node: lvalue_node, withContext: context)
|
||||
guard case .Ok(let lvalue_identifier) = maybe_parsed_lvalue else {
|
||||
let maybe_parsed_lvalue = AST.Expression.Compile(node: lvalue_node, withContext: context)
|
||||
guard case .Ok(let lvalue) = maybe_parsed_lvalue else {
|
||||
return Result.Error(maybe_parsed_lvalue.error()!)
|
||||
}
|
||||
|
||||
let check_result = lvalue_identifier.check(to: rvalue, inScopes: context.instances)
|
||||
guard case .Ok(_) = check_result else {
|
||||
return Result.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: lvalue_node.toSourceLocation(),
|
||||
withError: "\(check_result.error()!)"))
|
||||
}
|
||||
|
||||
return Result.Ok(
|
||||
ParserAssignmentStatement(
|
||||
withLValue: lvalue_identifier,
|
||||
AST.ParserAssignmentStatement(
|
||||
withLValue: lvalue,
|
||||
withValue: rvalue
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@deriveCompilableStatement
|
||||
extension ParserAssignmentStatement: CompilableStatement {}
|
||||
extension AST.ParserAssignmentStatement: CompilableStatement {}
|
||||
|
||||
extension ReturnStatement: Compilable {
|
||||
public typealias C = ReturnStatement
|
||||
extension AST.ReturnStatement: Compilable {
|
||||
public typealias C = AST.ReturnStatement
|
||||
public static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<ReturnStatement> {
|
||||
#RequireNodeType<Node, (P4Statement)>(
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.ReturnStatement> {
|
||||
#RequireNodeType<Node, AST.ReturnStatement>(
|
||||
node: node, type: "return_statement", nice_type_name: "return statement")
|
||||
|
||||
let expression_node = node.child(at: 1)!
|
||||
|
||||
return switch Expression.Compile(node: expression_node, withContext: context) {
|
||||
case .Ok(let result):
|
||||
if result.type().baseType().eq(rhs: context.expected_type!.baseType()) {
|
||||
.Ok(ReturnStatement(result))
|
||||
} else {
|
||||
.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError:
|
||||
"Type of expression in return statement (\(result.type())) is not compatible with function return type (\(context.expected_type!))"
|
||||
))
|
||||
}
|
||||
return switch AST.Expression.Compile(node: expression_node, withContext: context) {
|
||||
case .Ok(let result): .Ok(AST.ReturnStatement(result))
|
||||
case .Error(let e): .Error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@deriveCompilableStatement
|
||||
extension ReturnStatement: CompilableStatement {}
|
||||
extension AST.ReturnStatement: CompilableStatement {}
|
||||
|
||||
extension ApplyStatement: Compilable {
|
||||
public typealias C = ApplyStatement
|
||||
extension AST.ApplyStatement: Compilable {
|
||||
public typealias C = AST.ApplyStatement
|
||||
public static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<ApplyStatement> {
|
||||
#RequireNodeType<Node, (P4Statement)>(
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.ApplyStatement> {
|
||||
#RequireNodeType<Node, AST.ApplyStatement>(
|
||||
node: node, type: "apply_statement", nice_type_name: "apply statement")
|
||||
|
||||
let expression_node = node.child(at: 1)!
|
||||
|
||||
return switch BlockStatement.Compile(node: expression_node, withContext: context) {
|
||||
return switch AST.BlockStatement.Compile(node: expression_node, withContext: context) {
|
||||
case .Ok(let statement):
|
||||
.Ok(ApplyStatement(statement))
|
||||
.Ok(AST.ApplyStatement(statement))
|
||||
case .Error(let e): .Error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@deriveCompilableStatement
|
||||
extension ApplyStatement: CompilableStatement {}
|
||||
extension AST.ApplyStatement: CompilableStatement {}
|
||||
|
||||
extension Instantiation: Compilable {
|
||||
public typealias C = Instantiation
|
||||
extension AST.Instantiation: Compilable {
|
||||
public typealias C = AST.Instantiation
|
||||
public static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<Instantiation> {
|
||||
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.Instantiation> {
|
||||
|
||||
let expression = node
|
||||
#RequireNodeType<Node, (Instantiation)>(
|
||||
#RequireNodeType<Node, AST.Instantiation>(
|
||||
node: expression, type: "instantiation", nice_type_name: "instantiation statement")
|
||||
|
||||
var walker = Walker(node: expression)
|
||||
@@ -409,122 +373,48 @@ extension Instantiation: Compilable {
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<Instantiation>.Error(
|
||||
or: Result<AST.Instantiation>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
|
||||
|
||||
let maybe_instantiated_type_name = Identifier.Compile(
|
||||
let maybe_instantiated_type_name = AST.Identifier.CompileExpression(
|
||||
node: current_node!, withContext: context)
|
||||
guard case .Ok(let instantiated_type_name) = maybe_instantiated_type_name else {
|
||||
return Result.Error(maybe_instantiated_type_name.error()!)
|
||||
}
|
||||
|
||||
var maybe_instantiated_type: Result<(P4Lang.Parser?, Declaration?)> =
|
||||
switch context.types.lookup(identifier: instantiated_type_name) {
|
||||
case .Ok(let looked_up):
|
||||
switch looked_up {
|
||||
/// TODO: Further filter instantiable things.
|
||||
case let instantiated_parser as P4Lang.Parser:
|
||||
Result<(P4Lang.Parser?, Declaration?)>.Ok((instantiated_parser, .none)) // What we found is actually a parser declaration
|
||||
default:
|
||||
Result<(P4Lang.Parser?, Declaration?)>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: current_node!.toSourceLocation(),
|
||||
withError: "\(instantiated_type_name) cannot be instantiated"))
|
||||
}
|
||||
case .Error(let e): Result<(P4Lang.Parser?, Declaration?)>.Error(e)
|
||||
}
|
||||
|
||||
maybe_instantiated_type =
|
||||
if case .Error(let e) = maybe_instantiated_type {
|
||||
switch context.externs.lookup(identifier: instantiated_type_name) {
|
||||
case .Ok(let callee as Declaration):
|
||||
// Now, make sure that it is a function declaration!
|
||||
switch callee.identifier.type.baseType() {
|
||||
case is P4Lang.Parser: Result.Ok((.none, callee))
|
||||
default:
|
||||
.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: current_node!.toSourceLocation(),
|
||||
withError: "\(instantiated_type_name) cannot be instantiated"))
|
||||
}
|
||||
default: .Error(e)
|
||||
}
|
||||
} else {
|
||||
maybe_instantiated_type
|
||||
}
|
||||
|
||||
guard case .Ok(let callee) = maybe_instantiated_type else {
|
||||
return .Error(maybe_instantiated_type.error()!)
|
||||
}
|
||||
|
||||
walker.next()
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<Instantiation>.Error(
|
||||
or: Result<AST.Instantiation>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing instantiation component")))
|
||||
|
||||
let maybe_argument_list = ArgumentList.Compile(node: current_node!, withContext: context)
|
||||
let maybe_argument_list = AST.ArgumentList.Compile(node: current_node!, withContext: context)
|
||||
|
||||
guard case .Ok(let arguments) = maybe_argument_list else {
|
||||
return .Error(maybe_argument_list.error()!)
|
||||
}
|
||||
|
||||
// Now, compare the arguments with the parameters:
|
||||
|
||||
let params =
|
||||
switch callee {
|
||||
case (.some(let callee), .none): Optional<ParameterList>.some(callee.parameters)
|
||||
case (.none, .some(let callee)):
|
||||
Optional<ParameterList>.some((callee.ffi!.type().baseType() as! P4Lang.Parser).parameters)
|
||||
default: Optional<ParameterList>.none
|
||||
}
|
||||
|
||||
guard case .some(let params) = params else {
|
||||
return Result.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError:
|
||||
"Could not lookup the parameters for the instantiated parser (\(instantiated_type_name))"
|
||||
))
|
||||
}
|
||||
|
||||
if case .Error(let e) = arguments.compatible(params) {
|
||||
return .Error(e)
|
||||
}
|
||||
|
||||
walker.next()
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<Instantiation>.Error(
|
||||
or: Result<AST.Instantiation>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing instantiation name")))
|
||||
|
||||
let name = Identifier.Compile(node: current_node!, withContext: context)
|
||||
let name = AST.Identifier.CompileExpression(node: current_node!, withContext: context)
|
||||
guard case .Ok(let name) = name else {
|
||||
return .Error(name.error()!)
|
||||
}
|
||||
|
||||
let inst: Result<Instantiation> =
|
||||
switch callee {
|
||||
case (.some(let callee), .none):
|
||||
.Ok(Instantiation(named: name, ofType: callee, withArguments: arguments))
|
||||
case (.none, .some(let callee)):
|
||||
.Ok(Instantiation(named: name, ofType: callee, withArguments: arguments))
|
||||
default:
|
||||
Result.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError:
|
||||
"Unexpected error occurred calling function named (\(instantiated_type_name))"
|
||||
))
|
||||
}
|
||||
return inst
|
||||
return .Ok(
|
||||
AST.Instantiation(
|
||||
named: name as! AST.Identifier, withType: instantiated_type_name as! AST.Identifier,
|
||||
withArguments: arguments))
|
||||
}
|
||||
}
|
||||
|
||||
@deriveCompilableStatement
|
||||
extension Instantiation: CompilableStatement {}
|
||||
extension AST.Instantiation: CompilableStatement {}
|
||||
|
||||
@@ -16,24 +16,22 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import Common
|
||||
import P4Lang
|
||||
import P4Runtime
|
||||
import SwiftTreeSitter
|
||||
import TreeSitterExtensions
|
||||
import TreeSitterP4
|
||||
|
||||
extension P4Boolean: CompilableType {
|
||||
public static func CompileType(
|
||||
type: SwiftTreeSitter.Node, withContext: CompilerContext
|
||||
) -> Common.Result<(any Common.P4Type)?> {
|
||||
return type.text == "bool" ? .Ok(P4Boolean()) : .Ok(.none)
|
||||
extension P4Boolean: MaybeCompilableType {
|
||||
public static func MaybeCompileType(
|
||||
type: SwiftTreeSitter.Node, withContext: ASTCompilerContext
|
||||
) -> Common.Result<(AST.Tipe)?> {
|
||||
return type.text == "bool" ? .Ok(AST.Tipe(P4QualifiedType(P4Boolean()))) : .Ok(.none)
|
||||
}
|
||||
}
|
||||
|
||||
extension P4Int: CompilableType {
|
||||
public static func CompileType(
|
||||
type: SwiftTreeSitter.Node, withContext: CompilerContext
|
||||
) -> Common.Result<(any Common.P4Type)?> {
|
||||
extension P4Int: MaybeCompilableType {
|
||||
public static func MaybeCompileType(
|
||||
type: SwiftTreeSitter.Node, withContext: ASTCompilerContext
|
||||
) -> Common.Result<(AST.Tipe)?> {
|
||||
|
||||
// Drill down, as appropriate.
|
||||
let base_type_node = type.child(at: 0)!
|
||||
@@ -50,7 +48,7 @@ extension P4Int: CompilableType {
|
||||
|
||||
#MustOr(
|
||||
result: int_node, thing: walker.getNext(),
|
||||
or: Result<P4Type?>.Error(
|
||||
or: Result<AST.Tipe?>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: type_node.toSourceLocation(),
|
||||
withError: "Missing elements in int type declaration")))
|
||||
@@ -67,49 +65,30 @@ extension P4Int: CompilableType {
|
||||
sourceLocation: bit_width_node.toSourceLocation(),
|
||||
withError: "Could not parse \(bit_width_node.text!) into integer"))
|
||||
}
|
||||
return .Ok(P4Int(BitWidth.Width(bit_width)))
|
||||
return .Ok(AST.Tipe(P4QualifiedType(P4Int(BitWidth.Width(bit_width)))))
|
||||
}
|
||||
return .Ok(P4Int())
|
||||
return .Ok(AST.Tipe(P4QualifiedType(P4Int(BitWidth.Infinite))))
|
||||
}
|
||||
}
|
||||
|
||||
extension P4String: CompilableType {
|
||||
extension P4String: MaybeCompilableType {
|
||||
public static func MaybeCompileType(
|
||||
type: SwiftTreeSitter.Node, withContext: ASTCompilerContext
|
||||
) -> Common.Result<(AST.Tipe)?> {
|
||||
return type.text == "string" ? .Ok(AST.Tipe(P4QualifiedType(P4String()))) : .Ok(.none)
|
||||
}
|
||||
}
|
||||
|
||||
extension AST.Types: CompilableType {
|
||||
public static func CompileType(
|
||||
type: SwiftTreeSitter.Node, withContext: CompilerContext
|
||||
) -> Common.Result<(any Common.P4Type)?> {
|
||||
return type.text == "string" ? .Ok(P4String()) : .Ok(.none)
|
||||
}
|
||||
}
|
||||
|
||||
extension P4Struct: CompilableType {
|
||||
public static func CompileType(
|
||||
type: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<(any Common.P4Type)?> {
|
||||
|
||||
let maybe_parsed_type_id = Identifier.Compile(node: type, withContext: context)
|
||||
guard case .Ok(let parsed_type_id) = maybe_parsed_type_id else {
|
||||
return .Error(maybe_parsed_type_id.error()!)
|
||||
}
|
||||
|
||||
if case .Ok(let found_type) = context.types.lookup(identifier: parsed_type_id),
|
||||
let found_struct_type = found_type as? P4Struct
|
||||
{
|
||||
return .Ok(found_struct_type)
|
||||
}
|
||||
return .Ok(.none)
|
||||
}
|
||||
}
|
||||
|
||||
public struct Types {
|
||||
static func CompileType(
|
||||
type: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Result<P4QualifiedType> {
|
||||
let type_parsers: [CompilableType.Type] = [
|
||||
P4Boolean.self, P4Int.self, P4String.self, P4Struct.self,
|
||||
type: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.Tipe> {
|
||||
let type_parsers: [MaybeCompilableType.Type] = [
|
||||
P4Boolean.self, P4Int.self, P4String.self, /*P4Struct.self,*/
|
||||
]
|
||||
for type_parser in type_parsers {
|
||||
switch type_parser.CompileType(type: type, withContext: context) {
|
||||
case .Ok(.some(let type)): return .Ok(P4QualifiedType(type))
|
||||
switch type_parser.MaybeCompileType(type: type, withContext: context) {
|
||||
case .Ok(.some(let type)): return .Ok(type)
|
||||
case .Ok(.none): continue
|
||||
case .Error(let e): return .Error(e)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import Common
|
||||
|
||||
public struct ASTVisitorDriver {
|
||||
public init() {}
|
||||
|
||||
public func visit<T>(
|
||||
expression: any AST.AnExpression, visitor: any ASTVisitor<T>, context: T
|
||||
) -> Result<T> {
|
||||
return switch expression {
|
||||
case let e as AST.BinaryOperatorExpression:
|
||||
visitor.visit(node: e, driver: self, context: context)
|
||||
case let e as AST.Literal: visitor.visit(node: e, driver: self, context: context)
|
||||
default: .Error(Error(withMessage: "AST Expression Element Is Not Visitable"))
|
||||
}
|
||||
}
|
||||
|
||||
public func visit<T>(
|
||||
state: any AST.AnState, visitor: any ASTVisitor<T>, context: T
|
||||
) -> Result<T> {
|
||||
return switch state {
|
||||
case let s as AST.ParserStateDirectTransition:
|
||||
visitor.visit(node: s, driver: self, context: context)
|
||||
case let s as AST.ParserStateNoTransition:
|
||||
visitor.visit(node: s, driver: self, context: context)
|
||||
case let s as AST.ParserStateSelectTransition:
|
||||
visitor.visit(node: s, driver: self, context: context)
|
||||
default: .Error(Error(withMessage: "AST State Element (\(state)) Is Not Visitable"))
|
||||
}
|
||||
}
|
||||
|
||||
public func visit<T>(
|
||||
statement: any AST.AnStatement, visitor: any ASTVisitor<T>, context: T
|
||||
) -> Result<T> {
|
||||
return switch statement {
|
||||
case let s as AST.Parser: visitor.visit(node: s, driver: self, context: context)
|
||||
default: .Error(Error(withMessage: "AST Statement Element Is Not Visitable"))
|
||||
}
|
||||
}
|
||||
|
||||
public func visit<T>(
|
||||
program: AST.Program, visitor: any ASTVisitor<T>, context: T
|
||||
) -> Result<T> {
|
||||
|
||||
var context = context
|
||||
for s in program.statements {
|
||||
switch visit(statement: s, visitor: visitor, context: context) {
|
||||
case .Ok(let c): context = c
|
||||
case .Error(let e): return .Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
return .Ok(context)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user