compiler, runtime: Begin Runtime Refactor
Continuous Integration / Grammar Tests (push) Failing after 39s
Continuous Integration / Library Format Tests (push) Successful in 1m46s
Continuous Integration / Library Tests (push) Successful in 4m38s

Ultimately, the goal is to completely separate the compilation from
the runtime to make it possible to have the interpreter/evaluator
be "just another" entity that can perform meaningful work when
given a parsed GP4 program.

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-05-29 08:41:49 -04:00
parent 18461a9215
commit 44e93e4cda
30 changed files with 1264 additions and 854 deletions
+3 -3
View File
@@ -42,7 +42,7 @@ public struct Parameter: CustomStringConvertible, Equatable {
if let param_direction = self.type.direction(), if let param_direction = self.type.direction(),
param_direction == Direction.In || param_direction == Direction.InOut param_direction == Direction.In || param_direction == Direction.InOut
{ {
if !(argument.argument is EvaluatableLValueExpression) { if !(argument.argument is P4LValueExpression) {
return false return false
} }
} }
@@ -125,9 +125,9 @@ public struct ArgumentList {
public struct Argument { public struct Argument {
public let index: Int public let index: Int
public let argument: EvaluatableExpression public let argument: P4Expression
public init(_ argument: EvaluatableExpression, atIndex index: Int) { public init(_ argument: P4Expression, atIndex index: Int) {
self.argument = argument self.argument = argument
self.index = index self.index = index
} }
+121
View File
@@ -26,3 +26,124 @@ public typealias TypeTypeScope = Scope<P4Type>
/// Scopes that resolve type identifiers to their types. /// Scopes that resolve type identifiers to their types.
public typealias TypeTypeScopes = Scopes<P4Type> public typealias TypeTypeScopes = Scopes<P4Type>
/// Context for compilation
///
/// It contains (at least) three important pieces of information:
/// 1. Instances: A ``VarTypeScopes`` that contains information about instantiated objects
/// (and their types) in scope
/// 1. Types: A ``TypeTypeScopes`` that contains information about declared types in scope.
/// 1. Expected Type: In certain situations, to typecheck an element of a P4 program requires
/// knowledge of an expected type. For instance, when compiling a return statement, the
/// compiler must know the return type of the function to type check.
public struct CompilerContext {
public let instances: StaticVarValueScopes
public let types: TypeTypeScopes
public let externs: TypeTypeScopes
public let ffis: [P4FFI]
public let expected_type: P4QualifiedType?
public let extern_context: Bool
public init() {
instances = StaticVarValueScopes().enter()
types = TypeTypeScopes().enter()
externs = TypeTypeScopes().enter()
expected_type = .none
extern_context = false
ffis = Array()
}
public init(withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes) {
instances = _instances
types = _types
externs = TypeTypeScopes().enter()
expected_type = .none
extern_context = false
ffis = Array()
}
public init(
withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes,
withExpectation expectation: P4QualifiedType?, withExtern extern: Bool,
withExterns externs: TypeTypeScopes, withFFIs foreigns: [P4FFI]
) {
instances = _instances
types = _types
expected_type = expectation
extern_context = extern
self.externs = externs
ffis = foreigns
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new instances.
///
/// - Parameter instances: a ``VarTypeScopes`` with the updated instances for the newly created compiler context.
/// - Returns: A new compiler context based on the current but new instances.
public func update(newInstances instances: StaticVarValueScopes) -> CompilerContext {
return CompilerContext(
withInstances: instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new types.
///
/// - Parameter types: a ``TypeTypeScopes`` with the updated types for the newly created compiler context.
/// - Returns: A new compiler context based on the current but new types.
public func update(newTypes types: TypeTypeScopes) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new expected type.
///
/// - Parameter expectation: a ``P4Type?`` to (re)set the type the compiler is expecting.
/// - Returns: A new compiler context based on the current but new expected type.
public func update(newExpectation expectation: P4QualifiedType?) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: expectation,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new extern context value.
///
/// - Parameter extern: a ``Bool`` to (re)set whether the compiler is compiling in an extern context.
/// - Returns: A new compiler context based on the current but new extern context value.
public func update(newExtern extern: Bool) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: extern, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new externs.
///
/// - Parameter externs: a ``TypeTypeScopes`` to (re)set the list of extern-al declarations.
/// - Returns: A new compiler context based on the current but new list of external-al declarations.
public func update(newExterns externs: TypeTypeScopes) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new FFIs.
///
/// - Parameter foreigns: an array of ``P4FFI`` to (re)set the list of foreign functions.
/// - Returns: A new compiler context based on the current but with a new list of foreign functions.
public func update(newFFIs foreigns: [P4FFI]) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: foreigns)
}
}
+13 -1
View File
@@ -109,6 +109,18 @@ public struct InterloperEvaluator: ProgramExecutionEvaluator {
return CanonicalExecuteStatements(statements, inExecution: execution) { statement, execution in return CanonicalExecuteStatements(statements, inExecution: execution) { statement, execution in
let (cf, value) = statement.evaluate(execution: execution) let (cf, value) = statement.evaluate(execution: execution)
let (handled_cf, handled_value) =
if let handler = handler {
handler(cf, value)
} else {
(cf, value)
}
if hasDebugInterloper {
debugger!(statement, handled_cf, handled_value)
}
return (handled_cf, handled_value)
/*
let (handled_cf, handled_value) = let (handled_cf, handled_value) =
if let handler = handler { if let handler = handler {
handler(cf, value) handler(cf, value)
@@ -119,7 +131,7 @@ public struct InterloperEvaluator: ProgramExecutionEvaluator {
if hasDebugInterloper { if hasDebugInterloper {
debugger!(statement, handled_cf, handled_value) debugger!(statement, handled_cf, handled_value)
} }
return (handled_cf, handled_value) */
} }
} }
+65 -41
View File
@@ -15,28 +15,16 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
public protocol EvaluatableExpression {
/// Evaluate an expression for a given execution
/// - Parameters
/// - execution: The execution context in which to evaluate the expression
/// - Returns: The value of expression
func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution)
func type() -> P4QualifiedType
}
public protocol EvaluatableStatement {
/// Evaluate a statement for a given execution
/// - Parameters
/// - execution: The execution context in which to evaluate the parser statement
/// - Returns: A tuple of
/// 1. Whether this statement affects control flow.
/// 2. An updated execution after evaluating the parser statement
func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution)
}
public protocol P4Type: CustomStringConvertible { public protocol P4Type: CustomStringConvertible {
func eq(rhs: any P4Type) -> Bool func eq(rhs: any P4Type) -> Bool
func def() -> P4DataValue? func def() -> P4DataValue?
func instantiable() -> Bool
}
extension P4Type {
public func instantiable() -> Bool {
return false
}
} }
public protocol P4DataValue: CustomStringConvertible { public protocol P4DataValue: CustomStringConvertible {
@@ -48,28 +36,6 @@ public protocol P4DataValue: CustomStringConvertible {
func gte(rhs: P4DataValue) -> Bool func gte(rhs: P4DataValue) -> Bool
} }
public protocol EvaluatableLValueExpression: EvaluatableExpression {
func set(
to: P4Value, inScopes scopes: VarValueScopes, duringExecution execution: ProgramExecution
) -> Result<(VarValueScopes, P4Value)>
func check(to: EvaluatableExpression, inScopes scopes: StaticVarValueScopes) -> Result<()>
}
public protocol ProgramExecutionEvaluator {
func ExecuteStatements(
_ statements: [EvaluatableStatement], inExecution execution: ProgramExecution,
_ handler: ExecuteStatementResultHandlerT?
) -> (ControlFlow, ProgramExecution)
func ExecuteStatements(
_ statements: [EvaluatableStatement], inExecution execution: ProgramExecution
) -> (ControlFlow, ProgramExecution)
func EvaluateExpression(
_ expression: EvaluatableExpression, inExecution execution: ProgramExecution,
) -> (Result<P4Value>, ProgramExecution)
}
public protocol Errorable: CustomStringConvertible { public protocol Errorable: CustomStringConvertible {
func format(_ formatter: Formattable) -> String func format(_ formatter: Formattable) -> String
func format(_ formatter: Formattable, _ sc: SourceCode) -> String func format(_ formatter: Formattable, _ sc: SourceCode) -> String
@@ -91,6 +57,64 @@ public protocol Formattable {
func formatWithStyle(_ value: String, _ style: Style) -> String func formatWithStyle(_ value: String, _ style: Style) -> String
} }
public protocol P4Statement {
/// Evaluate a statement for a given execution
/// - Parameters
/// - execution: The execution context in which to evaluate the parser statement
/// - Returns: A tuple of
/// 1. Whether this statement affects control flow.
/// 2. An updated execution after evaluating the parser statement
func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution)
func effect(context: CompilerContext) -> CompilerContext
}
public protocol P4Expression {
func effect(context: CompilerContext) -> CompilerContext
func type() -> P4QualifiedType
/// Evaluate an expression for a given execution
/// - Parameters
/// - execution: The execution context in which to evaluate the expression
/// - Returns: The value of expression
func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution)
}
extension P4Expression {
func effect(context: CompilerContext) -> CompilerContext {
return context
}
}
public protocol P4LValueExpression {
func effect(context: CompilerContext) -> CompilerContext
func type() -> P4QualifiedType
func check(to: P4Expression, inScopes scopes: StaticVarValueScopes) -> Result<()>
func set(
to: P4Value, inScopes scopes: VarValueScopes, duringExecution execution: ProgramExecution
) -> Result<(VarValueScopes, P4Value)>
}
/// TODO: Only generate these after going through the codegen!
public typealias EvaluatableStatement = P4Statement
public typealias EvaluatableLValueExpression = P4LValueExpression
public typealias EvaluatableExpression = P4Expression
public protocol ProgramExecutionEvaluator {
func ExecuteStatements(
_ statements: [EvaluatableStatement], inExecution execution: ProgramExecution,
_ handler: ExecuteStatementResultHandlerT?
) -> (ControlFlow, ProgramExecution)
func ExecuteStatements(
_ statements: [EvaluatableStatement], inExecution execution: ProgramExecution
) -> (ControlFlow, ProgramExecution)
func EvaluateExpression(
_ expression: EvaluatableExpression, inExecution execution: ProgramExecution,
) -> (Result<P4Value>, ProgramExecution)
}
extension ProgramExecutionEvaluator { extension ProgramExecutionEvaluator {
public func ExecuteStatements( public func ExecuteStatements(
_ statements: [EvaluatableStatement], inExecution execution: ProgramExecution _ statements: [EvaluatableStatement], inExecution execution: ProgramExecution
+3
View File
@@ -106,3 +106,6 @@ public func Fold<T, A>(input: [T], initial: A, block: (T, A) -> A) -> A {
@freestanding(codeItem) public macro MustOr<E, N>(result: E, thing: E?, or: N) = @freestanding(codeItem) public macro MustOr<E, N>(result: E, thing: E?, or: N) =
#externalMacro(module: "Macros", type: "MustOr") #externalMacro(module: "Macros", type: "MustOr")
@attached(peer) public macro DeriveCompilableStatement() =
#externalMacro(module: "Macros", type: "DeriveCompilableStatement")
+26 -1
View File
@@ -439,11 +439,36 @@ public struct CliTestDeclarationMacro: PeerMacro, Sendable {
} }
} }
public struct DeriveCompilableStatement: PeerMacro, Sendable {
public static func expansion(
of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
let type_name = declaration.cast(ExtensionDeclSyntax.self).extendedType
let implementation = DeclSyntax(
"""
extension VariableDeclarationStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
""")
return [implementation]
}
}
@main @main
struct P4Macros: CompilerPlugin { struct P4Macros: CompilerPlugin {
var providingMacros: [Macro.Type] = [ var providingMacros: [Macro.Type] = [
RequireResult.self, RequireErrorResult.self, UseOkResult.self, UseErrorResult.self, RequireResult.self, RequireErrorResult.self, UseOkResult.self, UseErrorResult.self,
RequireNodeType.self, SkipUnlessNodeType.self, SkipUnlessNodesTypes.self, RequireNodesType.self, RequireNodeType.self, SkipUnlessNodeType.self, SkipUnlessNodesTypes.self, RequireNodesType.self,
MustOr.self, CliTestDeclarationMacro.self, MustOr.self, CliTestDeclarationMacro.self, DeriveCompilableStatement.self,
] ]
} }
+49 -52
View File
@@ -24,30 +24,30 @@ import TreeSitterP4
func parameter_list_compiler( func parameter_list_compiler(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(ParameterList, CompilerContext)> { ) -> Common.Result<ParameterList> {
var walker = Walker(node: node) var walker = Walker(node: node)
var current_node: Node? = .none var current_node: Node? = .none
if node.text == ")" { if node.text == ")" {
// There are no parameters! // There are no parameters!
return Result.Ok((ParameterList([]), context)) return Result.Ok(ParameterList([]))
} }
#RequireNodeType<Node, (ParameterList, CompilerContext)>( #RequireNodeType<Node, ParameterList>(
node: node, type: "parameter_list", nice_type_name: "Parameter List") node: node, type: "parameter_list", nice_type_name: "Parameter List")
var parameters: ParameterList = ParameterList([]) var parameters: ParameterList = ParameterList([])
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error( or: Result<ParameterList>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component"))) sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
if current_node?.nodeType == "parameter_list" { if current_node?.nodeType == "parameter_list" {
switch parameter_list_compiler(node: current_node!, withContext: context) { switch parameter_list_compiler(node: current_node!, withContext: context) {
case .Ok(let (ps, _)): case .Ok(let ps):
parameters = ps parameters = ps
case .Error(let e): return Result.Error(e) case .Error(let e): return Result.Error(e)
} }
@@ -56,13 +56,13 @@ func parameter_list_compiler(
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error( or: Result<ParameterList>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component"))) sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
// If this is a ')', we are done. // If this is a ')', we are done.
if current_node?.text == ")" { if current_node?.text == ")" {
return Result.Ok((parameters, context)) return Result.Ok(parameters)
} }
// If this is a comma, we skip it! // If this is a comma, we skip it!
@@ -72,26 +72,26 @@ func parameter_list_compiler(
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error( or: Result<ParameterList>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component"))) sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
// Otherwise, there should be one parameter left! // Otherwise, there should be one parameter left!
switch Parameter.Compile(node: current_node!, withContext: context) { switch Parameter.Compile(node: current_node!, withContext: context) {
case .Ok(let (parsed_parameter, updated_context)): case .Ok(let parsed_parameter):
return Result.Ok((parameters.addParameter(parsed_parameter), updated_context)) return Result.Ok(parameters.addParameter(parsed_parameter))
case .Error(let e): return Result.Error(e) case .Error(let e): return Result.Error(e)
} }
} }
extension ParameterList: Compilable { extension ParameterList: Compilable {
public typealias T = ParameterList public typealias C = ParameterList
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(ParameterList, CompilerContext)> { ) -> Common.Result<ParameterList> {
let parameter_node = node let parameter_node = node
#RequireNodeType<Node, (ParameterList, CompilerContext)>( #RequireNodeType<Node, ParameterList>(
node: parameter_node, type: "parameters", nice_type_name: "Parameters") node: parameter_node, type: "parameters", nice_type_name: "Parameters")
var walker = Walker(node: parameter_node) var walker = Walker(node: parameter_node)
@@ -100,7 +100,7 @@ extension ParameterList: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error( or: Result<ParameterList>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing '(' in parameter list component"))) withError: "Missing '(' in parameter list component")))
@@ -108,7 +108,7 @@ extension ParameterList: Compilable {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error( or: Result<ParameterList>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component"))) sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
@@ -117,12 +117,12 @@ extension ParameterList: Compilable {
} }
extension Direction: Compilable { extension Direction: Compilable {
public typealias T = Direction public typealias C = Direction
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(Direction, CompilerContext)> { ) -> Result<Direction> {
let direction_node = node let direction_node = node
#RequireNodeType<Node, (Direction, CompilerContext)>( #RequireNodeType<Node, Direction>(
node: direction_node, type: "direction", nice_type_name: "direction") node: direction_node, type: "direction", nice_type_name: "direction")
let directions = [ let directions = [
"in": Direction.In, "in": Direction.In,
@@ -137,17 +137,17 @@ extension Direction: Compilable {
withError: "\(direction_node.text!) is not a valid direction")) withError: "\(direction_node.text!) is not a valid direction"))
} }
return .Ok((parsed_direction, context)) return .Ok(parsed_direction)
} }
} }
extension Parameter: Compilable { extension Parameter: Compilable {
public typealias T = Parameter public typealias C = Parameter
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(Parameter, CompilerContext)> { ) -> Result<Parameter> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( #RequireNodeType<Node, P4Statement>(
node: node, type: "parameter", nice_type_name: "parameter") node: node, type: "parameter", nice_type_name: "parameter")
var walker = Walker(node: node) var walker = Walker(node: node)
@@ -155,7 +155,7 @@ extension Parameter: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Parameter, CompilerContext)>.Error( or: Result<Parameter>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing parameter declaration component"))) withError: "Missing parameter declaration component")))
@@ -171,7 +171,7 @@ extension Parameter: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Parameter, CompilerContext)>.Error( or: Result<Parameter>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing parameter declaration component"))) withError: "Missing parameter declaration component")))
@@ -181,7 +181,7 @@ extension Parameter: Compilable {
if current_node!.nodeType == "direction" { if current_node!.nodeType == "direction" {
let maybe_parsed_direction = Direction.Compile(node: current_node!, withContext: context) let maybe_parsed_direction = Direction.Compile(node: current_node!, withContext: context)
guard case .Ok((let parsed_direction, _)) = maybe_parsed_direction else { guard case .Ok(let parsed_direction) = maybe_parsed_direction else {
return .Error(maybe_parsed_direction.error()!) return .Error(maybe_parsed_direction.error()!)
} }
direction = parsed_direction direction = parsed_direction
@@ -191,7 +191,7 @@ extension Parameter: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Parameter, CompilerContext)>.Error( or: Result<Parameter>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing parameter declaration component"))) withError: "Missing parameter declaration component")))
@@ -213,7 +213,7 @@ extension Parameter: Compilable {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Parameter, CompilerContext)>.Error( or: Result<Parameter>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing parameter declaration component"))) withError: "Missing parameter declaration component")))
@@ -233,43 +233,41 @@ extension Parameter: Compilable {
} }
return Result.Ok( return Result.Ok(
(
Parameter( Parameter(
identifier: parameter_name, identifier: parameter_name,
withType: direction != nil withType: direction != nil
? parameter_type.update(addAttribute: P4TypeQualifier.Direction(direction!)) ? parameter_type.update(addAttribute: P4TypeQualifier.Direction(direction!))
: parameter_type), : parameter_type),
context )
))
} }
} }
func argument_list_compiler( func argument_list_compiler(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(ArgumentList, CompilerContext)> { ) -> Common.Result<ArgumentList> {
var walker = Walker(node: node) var walker = Walker(node: node)
var current_node: Node? = .none var current_node: Node? = .none
if node.text == ")" { if node.text == ")" {
// There are no arguments! // There are no arguments!
return Result.Ok((ArgumentList([]), context)) return Result.Ok(ArgumentList([]))
} }
#RequireNodeType<Node, (ArgumentList, CompilerContext)>( #RequireNodeType<Node, ArgumentList>(
node: node, type: "argument_list", nice_type_name: "argument List") node: node, type: "argument_list", nice_type_name: "argument List")
var arguments: ArgumentList = ArgumentList([]) var arguments: ArgumentList = ArgumentList([])
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error( or: Result<ArgumentList>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component"))) sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
if current_node?.nodeType == "argument_list" { if current_node?.nodeType == "argument_list" {
switch argument_list_compiler(node: current_node!, withContext: context) { switch argument_list_compiler(node: current_node!, withContext: context) {
case .Ok(let (ps, _)): case .Ok(let ps):
arguments = ps arguments = ps
case .Error(let e): return Result.Error(e) case .Error(let e): return Result.Error(e)
} }
@@ -280,13 +278,13 @@ func argument_list_compiler(
// We may have moved nodes, check/reset current_node. // We may have moved nodes, check/reset current_node.
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error( or: Result<ArgumentList>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component"))) sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
// If this is a ')', we are done. // If this is a ')', we are done.
if current_node?.text == ")" { if current_node?.text == ")" {
return Result.Ok((arguments, context)) return Result.Ok(arguments)
} }
// If this is a comma, we skip it! // If this is a comma, we skip it!
@@ -296,27 +294,27 @@ func argument_list_compiler(
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error( or: Result<ArgumentList>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component"))) sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
// Otherwise, there should be one argument left! // Otherwise, there should be one argument left!
switch Argument.Compile(node: current_node!, withContext: context) { switch Argument.Compile(node: current_node!, withContext: context) {
case .Ok(let (ce, updated_context)): case .Ok(let ce):
return Result.Ok( return Result.Ok(
(arguments.addArgument(Argument(ce, atIndex: arguments.count() + 1)), updated_context)) arguments.addArgument(Argument(ce, atIndex: arguments.count() + 1)))
case .Error(let e): return Result.Error(e) case .Error(let e): return Result.Error(e)
} }
} }
extension ArgumentList: Compilable { extension ArgumentList: Compilable {
public typealias T = ArgumentList public typealias C = ArgumentList
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(ArgumentList, CompilerContext)> { ) -> Common.Result<ArgumentList> {
let argument_node = node let argument_node = node
#RequireNodeType<Node, (ArgumentList, CompilerContext)>( #RequireNodeType<Node, ArgumentList>(
node: argument_node, type: "arguments", nice_type_name: "arguments") node: argument_node, type: "arguments", nice_type_name: "arguments")
var walker = Walker(node: argument_node) var walker = Walker(node: argument_node)
@@ -324,7 +322,7 @@ extension ArgumentList: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error( or: Result<ArgumentList>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing '(' in argument list component"))) withError: "Missing '(' in argument list component")))
@@ -333,7 +331,7 @@ extension ArgumentList: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error( or: Result<ArgumentList>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component"))) sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
@@ -342,25 +340,25 @@ extension ArgumentList: Compilable {
} }
extension Argument: Compilable { extension Argument: Compilable {
public typealias T = EvaluatableExpression public typealias C = P4Expression
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(EvaluatableExpression, CompilerContext)> { ) -> Common.Result<P4Expression> {
let argument_node = node let argument_node = node
#RequireNodeType<Node, (EvaluatableExpression, CompilerContext)>( #RequireNodeType<Node, P4Expression>(
node: argument_node, type: "argument", nice_type_name: "argument") node: argument_node, type: "argument", nice_type_name: "argument")
let expression_node = node.child(at: 0)! let expression_node = node.child(at: 0)!
return switch Expression.Compile(node: expression_node, withContext: context) { return switch Expression.Compile(node: expression_node, withContext: context) {
case .Ok(let compiled_expression): .Ok((compiled_expression, context)) case .Ok(let compiled_expression): .Ok(compiled_expression)
case .Error(let e): .Error(e) case .Error(let e): .Error(e)
} }
} }
} }
func ContainsInvalidStatements( func ContainsInvalidStatements(
statement: EvaluatableStatement, invalids: [EvaluatableStatement.Type] statement: P4Statement, invalids: [P4Statement.Type]
) -> Bool { ) -> Bool {
for es in invalids { for es in invalids {
if type(of: statement) == es { if type(of: statement) == es {
@@ -370,8 +368,7 @@ func ContainsInvalidStatements(
return false return false
} }
func ContainsInvalidStatements(block: BlockStatement, invalids: [EvaluatableStatement.Type]) -> Bool func ContainsInvalidStatements(block: BlockStatement, invalids: [P4Statement.Type]) -> Bool {
{
return block.statements.contains { statement in return block.statements.contains { statement in
for es in invalids { for es in invalids {
if type(of: statement) == es { if type(of: statement) == es {
-121
View File
@@ -34,124 +34,3 @@ public func ConfigureP4Parser() -> Result<SwiftTreeSitter.Parser> {
return .Ok(p) return .Ok(p)
} }
/// Context for compilation
///
/// It contains (at least) three important pieces of information:
/// 1. Instances: A ``VarTypeScopes`` that contains information about instantiated objects
/// (and their types) in scope
/// 1. Types: A ``TypeTypeScopes`` that contains information about declared types in scope.
/// 1. Expected Type: In certain situations, to typecheck an element of a P4 program requires
/// knowledge of an expected type. For instance, when compiling a return statement, the
/// compiler must know the return type of the function to type check.
public struct CompilerContext {
let instances: StaticVarValueScopes
let types: TypeTypeScopes
let externs: TypeTypeScopes
let ffis: [P4FFI]
let expected_type: P4QualifiedType?
let extern_context: Bool
public init() {
instances = StaticVarValueScopes().enter()
types = TypeTypeScopes().enter()
externs = TypeTypeScopes().enter()
expected_type = .none
extern_context = false
ffis = Array()
}
public init(withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes) {
instances = _instances
types = _types
externs = TypeTypeScopes().enter()
expected_type = .none
extern_context = false
ffis = Array()
}
public init(
withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes,
withExpectation expectation: P4QualifiedType?, withExtern extern: Bool,
withExterns externs: TypeTypeScopes, withFFIs foreigns: [P4FFI]
) {
instances = _instances
types = _types
expected_type = expectation
extern_context = extern
self.externs = externs
ffis = foreigns
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new instances.
///
/// - Parameter instances: a ``VarTypeScopes`` with the updated instances for the newly created compiler context.
/// - Returns: A new compiler context based on the current but new instances.
public func update(newInstances instances: StaticVarValueScopes) -> CompilerContext {
return CompilerContext(
withInstances: instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new types.
///
/// - Parameter types: a ``TypeTypeScopes`` with the updated types for the newly created compiler context.
/// - Returns: A new compiler context based on the current but new types.
public func update(newTypes types: TypeTypeScopes) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new expected type.
///
/// - Parameter expectation: a ``P4Type?`` to (re)set the type the compiler is expecting.
/// - Returns: A new compiler context based on the current but new expected type.
public func update(newExpectation expectation: P4QualifiedType?) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: expectation,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new extern context value.
///
/// - Parameter extern: a ``Bool`` to (re)set whether the compiler is compiling in an extern context.
/// - Returns: A new compiler context based on the current but new extern context value.
public func update(newExtern extern: Bool) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: extern, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new externs.
///
/// - Parameter externs: a ``TypeTypeScopes`` to (re)set the list of extern-al declarations.
/// - Returns: A new compiler context based on the current but new list of external-al declarations.
public func update(newExterns externs: TypeTypeScopes) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new FFIs.
///
/// - Parameter foreigns: an array of ``P4FFI`` to (re)set the list of foreign functions.
/// - Returns: A new compiler context based on the current but with a new list of foreign functions.
public func update(newFFIs foreigns: [P4FFI]) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: foreigns)
}
}
+135 -155
View File
@@ -22,33 +22,61 @@ import SwiftTreeSitter
import TreeSitterExtensions import TreeSitterExtensions
import TreeSitterP4 import TreeSitterP4
extension Declaration: CompilableDeclaration { extension Declaration: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension Declaration: Compilable {
public typealias C = Declaration
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(Declaration, CompilerContext)?> { ) -> Result<Declaration> {
let declaration_compilers: [String: CompilableDeclaration.Type] = [ // Be kind to our user -- if we are at a declaration node, dive into it!
let declaration_node =
if node.nodeType == "declaration" {
node.child(at: 0)!
} else {
node
}
let declaration_compilers: [String: any Compilable<Declaration>.Type] = [
"function_declaration": FunctionDeclaration.self, "function_declaration": FunctionDeclaration.self,
"control_declaration": Control.self, "control_declaration": Control.self,
"type_declaration": P4Struct.self, "type_declaration": P4Struct.self,
"parserDeclaration": Parser.self,
/// ASSUME: Type declarations are struct declarations. /// ASSUME: Type declarations are struct declarations.
"extern_declaration": ExternDeclaration.self, "extern_declaration": ExternDeclaration.self,
] ]
guard let declaration_compiler = declaration_compilers[node.nodeType!] else { guard let declaration_compiler = declaration_compilers[declaration_node.nodeType!] else {
return .Ok(.none) return .Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Could not find parser for declaration \(declaration_node.nodeType!)"))
} }
return declaration_compiler.Compile(node: node, withContext: context) return declaration_compiler.Compile(node: declaration_node, withContext: context).map {
result in
.Ok(result)
}
} }
} }
extension FunctionDeclaration: CompilableDeclaration { extension FunctionDeclaration: Compilable {
public typealias C = Declaration
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Declaration, CompilerContext)?> { ) -> Common.Result<Declaration> {
let function_declaration_node = node let function_declaration_node = node
#RequireNodeType<Node, (ParameterList, CompilerContext)>( #RequireNodeType<Node, ParameterList>(
node: function_declaration_node, type: "function_declaration", node: function_declaration_node, type: "function_declaration",
nice_type_name: "Function Declaration") nice_type_name: "Function Declaration")
@@ -59,7 +87,7 @@ extension FunctionDeclaration: CompilableDeclaration {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: function_declaration_node.toSourceLocation(), sourceLocation: function_declaration_node.toSourceLocation(),
withError: "Missing function declaration component"))) withError: "Missing function declaration component")))
@@ -72,7 +100,7 @@ extension FunctionDeclaration: CompilableDeclaration {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: function_declaration_node.toSourceLocation(), sourceLocation: function_declaration_node.toSourceLocation(),
withError: "Missing function declaration component"))) withError: "Missing function declaration component")))
@@ -85,17 +113,16 @@ extension FunctionDeclaration: CompilableDeclaration {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: function_declaration_node.toSourceLocation(), sourceLocation: function_declaration_node.toSourceLocation(),
withError: "Missing function declaration component"))) withError: "Missing function declaration component")))
let maybe_function_parameters = ParameterList.Compile(node: current_node!, withContext: context) let maybe_function_parameters = ParameterList.Compile(node: current_node!, withContext: context)
guard case .Ok((let function_parameters, let updated_context)) = maybe_function_parameters guard case .Ok(let function_parameters) = maybe_function_parameters
else { else {
return .Error(maybe_function_parameters.error()!) return .Error(maybe_function_parameters.error()!)
} }
context = updated_context
var function_body: BlockStatement? = .none var function_body: BlockStatement? = .none
@@ -113,10 +140,10 @@ extension FunctionDeclaration: CompilableDeclaration {
withContext: context.update(newInstances: function_scope).update( withContext: context.update(newInstances: function_scope).update(
newExpectation: function_type)) newExpectation: function_type))
guard case .Ok((let parsed_function_body, _)) = maybe_function_body else { guard case .Ok(let parsed_function_body) = maybe_function_body else {
return .Error(maybe_function_body.error()!) return .Error(maybe_function_body.error()!)
} }
function_body = (parsed_function_body as! BlockStatement) function_body = parsed_function_body
} else { } else {
// If we are in an extern context, no body is okay! // If we are in an extern context, no body is okay!
@@ -142,33 +169,29 @@ extension FunctionDeclaration: CompilableDeclaration {
// And, do not update the context if we are compiling in an // And, do not update the context if we are compiling in an
// extern context -- the wrapping extern declaration will take care of that. // extern context -- the wrapping extern declaration will take care of that.
return .Ok( return .Ok(
(
function_declaration, function_declaration,
context.extern_context
? context
: context.update(
newTypes: context.types.declare(
identifier: function_name, withValue: function_declaration.identifier.type.baseType())
) )
))
} }
} }
extension P4Struct: CompilableDeclaration { extension P4Struct: Compilable {
public typealias C = Declaration
static public func Compile( static public func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(Declaration, CompilerContext)?> { ) -> Result<Declaration> {
let struct_declaration_node = node.child(at: 0)! let struct_declaration_node = node.child(at: 0)!
var walker = Walker(node: struct_declaration_node) var walker = Walker(node: struct_declaration_node)
var currentNode: Node? = .none var currentNode: Node? = .none
#SkipUnlessNodeType(node: struct_declaration_node, type: "struct_declaration") #RequireNodeType<Node, Result<Declaration>>(
node: struct_declaration_node, type: "struct_declaration",
nice_type_name: "struct declaration")
// Skip the keyword struct // Skip the keyword struct
walker.next() walker.next()
#MustOr( #MustOr(
result: currentNode, thing: walker.getNext(), result: currentNode, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: struct_declaration_node.toSourceLocation(), sourceLocation: struct_declaration_node.toSourceLocation(),
withError: "Missing function declaration component"))) withError: "Missing function declaration component")))
@@ -185,7 +208,7 @@ extension P4Struct: CompilableDeclaration {
walker.next() walker.next()
#MustOr( #MustOr(
result: currentNode, thing: walker.getNext(), result: currentNode, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: struct_declaration_node.toSourceLocation(), sourceLocation: struct_declaration_node.toSourceLocation(),
withError: "Missing function declaration component"))) withError: "Missing function declaration component")))
@@ -197,15 +220,7 @@ extension P4Struct: CompilableDeclaration {
id: struct_identifier, id: struct_identifier,
withType: P4QualifiedType( withType: P4QualifiedType(
P4Struct(withName: struct_identifier, andFields: P4StructFields([]))))) P4Struct(withName: struct_identifier, andFields: P4StructFields([])))))
return Result.Ok( return Result.Ok(struc)
(
struc,
context.extern_context
? context
: context.update(
newTypes: context.types.declare(
identifier: struct_identifier, withValue: struc.identifier.type.baseType()))
))
} }
var parse_errs: (any Errorable)? = .none var parse_errs: (any Errorable)? = .none
@@ -217,13 +232,12 @@ extension P4Struct: CompilableDeclaration {
switch VariableDeclarationStatement.Compile( switch VariableDeclarationStatement.Compile(
node: declaration_field, withContext: current_context) node: declaration_field, withContext: current_context)
{ {
case .Ok((let declaration, let updated_context)): case .Ok(let declaration):
let variable_declaration = declaration as! VariableDeclarationStatement let variable_declaration = declaration as! VariableDeclarationStatement
parsed_fields.append( parsed_fields.append(
P4StructFieldIdentifier( P4StructFieldIdentifier(
id: variable_declaration.identifier, withType: variable_declaration.initializer.type() id: variable_declaration.identifier, withType: variable_declaration.initializer.type()
)) ))
current_context = updated_context
case .Error(let e): case .Error(let e):
parse_errs = parse_errs =
if let e = parse_errs { if let e = parse_errs {
@@ -245,24 +259,19 @@ extension P4Struct: CompilableDeclaration {
withType: P4QualifiedType( withType: P4QualifiedType(
P4Struct( P4Struct(
withName: struct_identifier, andFields: P4StructFields(parsed_fields))))) withName: struct_identifier, andFields: P4StructFields(parsed_fields)))))
return .Ok( return .Ok(declared_struct)
(
declared_struct,
current_context.extern_context
? current_context
: current_context.update(
newTypes: current_context.types.declare(
identifier: struct_identifier, withValue: declared_struct.identifier.type.baseType()))
))
} }
} }
extension P4Lang.Parser: CompilableDeclaration { extension P4Lang.Parser: Compilable {
public typealias C = Declaration
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(Declaration, CompilerContext)?> { ) -> Result<Declaration> {
let parser_node = node let parser_node = node
#SkipUnlessNodeType<Node>(node: parser_node, type: "parserDeclaration") #RequireNodeType<Node, Result<Declaration>>(
node: parser_node, type: "parserDeclaration", nice_type_name: "parser declaration")
var current_context = context var current_context = context
var walker = Walker(node: parser_node) var walker = Walker(node: parser_node)
@@ -270,7 +279,7 @@ extension P4Lang.Parser: CompilableDeclaration {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: parser_node.toSourceLocation(), sourceLocation: parser_node.toSourceLocation(),
withError: "Missing elements of parser declaration"))) withError: "Missing elements of parser declaration")))
@@ -294,7 +303,7 @@ extension P4Lang.Parser: CompilableDeclaration {
#MustOr( #MustOr(
result: type_node_child, thing: type_node_walker.getNext(), result: type_node_child, thing: type_node_walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: parser_node.toSourceLocation(), sourceLocation: parser_node.toSourceLocation(),
withError: "Missing elements of parser type in parser declaration"))) withError: "Missing elements of parser type in parser declaration")))
@@ -310,7 +319,7 @@ extension P4Lang.Parser: CompilableDeclaration {
type_node_walker.next() type_node_walker.next()
#MustOr( #MustOr(
result: type_node_child, thing: type_node_walker.getNext(), result: type_node_child, thing: type_node_walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: type_node_child!.toSourceLocation(), sourceLocation: type_node_child!.toSourceLocation(),
withError: "Missing name in parser type declaration"))) withError: "Missing name in parser type declaration")))
@@ -324,15 +333,14 @@ extension P4Lang.Parser: CompilableDeclaration {
type_node_walker.next() type_node_walker.next()
#MustOr( #MustOr(
result: type_node_child, thing: type_node_walker.getNext(), result: type_node_child, thing: type_node_walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: type_node_child!.toSourceLocation(), sourceLocation: type_node_child!.toSourceLocation(),
withError: "Missing parser parameters"))) withError: "Missing parser parameters")))
switch ParameterList.Compile(node: type_node_child!, withContext: current_context) { switch ParameterList.Compile(node: type_node_child!, withContext: current_context) {
case .Ok(let (parsed_parameter_list, updated_context)): case .Ok(let parsed_parameter_list):
parameter_list = parsed_parameter_list parameter_list = parsed_parameter_list
current_context = updated_context
case .Error(let e): case .Error(let e):
return .Error(e) return .Error(e)
} }
@@ -348,7 +356,7 @@ extension P4Lang.Parser: CompilableDeclaration {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: parser_node.toSourceLocation(), sourceLocation: parser_node.toSourceLocation(),
withError: "Missing parser declaration component"))) withError: "Missing parser declaration component")))
@@ -356,7 +364,7 @@ extension P4Lang.Parser: CompilableDeclaration {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: parser_node.toSourceLocation(), sourceLocation: parser_node.toSourceLocation(),
withError: "Missing elements of parser declaration"))) withError: "Missing elements of parser declaration")))
@@ -371,7 +379,7 @@ extension P4Lang.Parser: CompilableDeclaration {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: parser_node.toSourceLocation(), sourceLocation: parser_node.toSourceLocation(),
withError: "Missing body of parser declaration"))) withError: "Missing body of parser declaration")))
@@ -381,7 +389,7 @@ extension P4Lang.Parser: CompilableDeclaration {
} }
/// TODO: Handle extern parsers. /// TODO: Handle extern parsers.
switch SpecialCompilers.Compile( switch SpecialCompilers.CompileParserBody(
withName: parser_name!, withParameters: parameter_list, node: current_node!, withName: parser_name!, withParameters: parameter_list, node: current_node!,
withContext: current_context) withContext: current_context)
{ {
@@ -390,24 +398,21 @@ extension P4Lang.Parser: CompilableDeclaration {
TypedIdentifier(id: parser.name, withType: P4QualifiedType(parser))) TypedIdentifier(id: parser.name, withType: P4QualifiedType(parser)))
// Create a new context with the name of the parser that was just compiled in scope. // Create a new context with the name of the parser that was just compiled in scope.
return .Ok( return .Ok(
(
parser_declaration, parser_declaration,
context.extern_context )
? context
: updated_context.update(
newTypes: updated_context.types.declare(identifier: parser.name, withValue: parser))
))
case Result.Error(let error): return .Error(error) case Result.Error(let error): return .Error(error)
} }
} }
} }
extension Control: CompilableDeclaration { extension Control: Compilable {
public typealias C = Declaration
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Declaration, CompilerContext)?> { ) -> Common.Result<Declaration> {
#SkipUnlessNodeType<Node>(node: node, type: "control_declaration") #RequireNodeType<Node, Result<Declaration>>(
node: node, type: "control_declaration", nice_type_name: "control declaration")
var walker = Walker(node: node) var walker = Walker(node: node)
var current_node: Node? = .none var current_node: Node? = .none
@@ -417,7 +422,7 @@ extension Control: CompilableDeclaration {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing control declaration component"))) withError: "Missing control declaration component")))
@@ -433,18 +438,17 @@ extension Control: CompilableDeclaration {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing control declaration component"))) withError: "Missing control declaration component")))
let maybe_control_parameters = ParameterList.Compile( let maybe_control_parameters = ParameterList.Compile(
node: current_node!, withContext: local_context) node: current_node!, withContext: local_context)
guard case .Ok((let control_parameters, let updated_context)) = maybe_control_parameters guard case .Ok(let control_parameters) = maybe_control_parameters
else { else {
return .Error(maybe_control_parameters.error()!) return .Error(maybe_control_parameters.error()!)
} }
local_context = updated_context
// Before continuing, make sure to put the parameters into context. // Before continuing, make sure to put the parameters into context.
var control_scope = local_context.instances.enter() var control_scope = local_context.instances.enter()
@@ -459,7 +463,7 @@ extension Control: CompilableDeclaration {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error( or: Result<Declaration>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing control declaration component"))) withError: "Missing control declaration component")))
@@ -476,12 +480,11 @@ extension Control: CompilableDeclaration {
let maybe_action_declaration = Action.Compile( let maybe_action_declaration = Action.Compile(
node: current_node, withContext: local_context) node: current_node, withContext: local_context)
guard guard
case .Ok((let action_declaration, let updated_context)) = maybe_action_declaration case .Ok(let action_declaration) = maybe_action_declaration
else { else {
return .Error(maybe_action_declaration.error()!) return .Error(maybe_action_declaration.error()!)
} }
actions.append(action_declaration) actions.append(action_declaration)
local_context = updated_context
// Now, add the declaration into the context. // Now, add the declaration into the context.
local_context = local_context.update( local_context = local_context.update(
newTypes: local_context.types.declare( newTypes: local_context.types.declare(
@@ -490,22 +493,20 @@ extension Control: CompilableDeclaration {
let maybe_table_declaration = Table.Compile( let maybe_table_declaration = Table.Compile(
node: current_node, withContext: local_context) node: current_node, withContext: local_context)
guard guard
case .Ok((let table_declaration, let updated_context)) = maybe_table_declaration case .Ok(let table_declaration) = maybe_table_declaration
else { else {
return .Error(maybe_table_declaration.error()!) return .Error(maybe_table_declaration.error()!)
} }
tables.append(table_declaration) tables.append(table_declaration)
local_context = updated_context
} else if current_node.nodeType == "apply_statement" { } else if current_node.nodeType == "apply_statement" {
// When we see an apply, that is it for the actions and the tables. // When we see an apply, that is it for the actions and the tables.
let maybe_apply_statement = ApplyStatement.Compile( let maybe_apply_statement = ApplyStatement.Compile(
node: current_node, withContext: local_context) node: current_node, withContext: local_context)
guard guard
case .Ok((let apply_statement, let updated_context)) = maybe_apply_statement case .Ok(let apply_statement) = maybe_apply_statement
else { else {
return .Error(maybe_apply_statement.error()!) return .Error(maybe_apply_statement.error()!)
} }
local_context = updated_context
apply = (apply_statement as! ApplyStatement) apply = (apply_statement as! ApplyStatement)
// The apply is the last thing in a control declaration. // The apply is the last thing in a control declaration.
@@ -555,24 +556,16 @@ extension Control: CompilableDeclaration {
// Don't forget to add the newly declared Control to the instance that we were given // Don't forget to add the newly declared Control to the instance that we were given
// (and not the one that we entered to do the parsing of this Control). // (and not the one that we entered to do the parsing of this Control).
return .Ok( return .Ok(declared_control)
(
declared_control,
context.extern_context
? context
: context.update(
newTypes: context.types.declare(
identifier: control_name, withValue: control))
))
} }
} }
extension Action: Compilable { extension Action: Compilable {
public typealias T = Action public typealias C = Action
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Action, CompilerContext)> { ) -> Result<Action> {
#RequireNodeType<Node, (P4Type, CompilerContext)>( #RequireNodeType<Node, P4Type>(
node: node, type: "action_declaration", nice_type_name: "Action Declaration") node: node, type: "action_declaration", nice_type_name: "Action Declaration")
var walker = Walker(node: node) var walker = Walker(node: node)
@@ -584,7 +577,7 @@ extension Action: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Action, CompilerContext)>.Error( or: Result<Action>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing action declaration component" sourceLocation: node.toSourceLocation(), withError: "Missing action declaration component"
)) ))
@@ -601,7 +594,7 @@ extension Action: Compilable {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Action, CompilerContext)>.Error( or: Result<Action>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing action declaration component" sourceLocation: node.toSourceLocation(), withError: "Missing action declaration component"
)) ))
@@ -609,11 +602,10 @@ extension Action: Compilable {
let maybe_action_parameters = ParameterList.Compile( let maybe_action_parameters = ParameterList.Compile(
node: current_node!, withContext: current_context) node: current_node!, withContext: current_context)
guard case .Ok((let action_parameters, let updated_context)) = maybe_action_parameters guard case .Ok(let action_parameters) = maybe_action_parameters
else { else {
return .Error(maybe_action_parameters.error()!) return .Error(maybe_action_parameters.error()!)
} }
current_context = updated_context
// Check whether the parameters are in the proper order. // Check whether the parameters are in the proper order.
let remaining_parameters = action_parameters.parameters.drop(while: { let remaining_parameters = action_parameters.parameters.drop(while: {
@@ -629,7 +621,7 @@ extension Action: Compilable {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Action, CompilerContext)>.Error( or: Result<Action>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing action declaration component" sourceLocation: node.toSourceLocation(), withError: "Missing action declaration component"
)) ))
@@ -644,29 +636,26 @@ extension Action: Compilable {
let maybe_action_body = BlockStatement.Compile( let maybe_action_body = BlockStatement.Compile(
node: current_node!, withContext: context.update(newInstances: function_scope)) node: current_node!, withContext: context.update(newInstances: function_scope))
guard case .Ok((let action_body, _)) = maybe_action_body else { guard case .Ok(let action_body) = maybe_action_body else {
return .Error(maybe_action_body.error()!) return .Error(maybe_action_body.error()!)
} }
/// TODO: Actions cannot contain switches! /// TODO: Actions cannot contain switches!
return .Ok( return .Ok(
(
Action( Action(
named: action_name, withParameters: action_parameters, named: action_name, withParameters: action_parameters,
withBody: (action_body as! BlockStatement)), withBody: (action_body as! BlockStatement)))
current_context
))
} }
} }
extension TableKeyEntry: Compilable { extension TableKeyEntry: Compilable {
public typealias T = TableKeyEntry public typealias C = TableKeyEntry
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TableKeyEntry, CompilerContext)> { ) -> Result<TableKeyEntry> {
#RequireNodeType<Node, (P4Type, CompilerContext)>( #RequireNodeType<Node, TableKeyEntry>(
node: node, type: "table_key_entry", nice_type_name: "Table Key Entry") node: node, type: "table_key_entry", nice_type_name: "Table Key Entry")
var walker = Walker(node: node) var walker = Walker(node: node)
@@ -677,7 +666,7 @@ extension TableKeyEntry: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(TableKeyEntry, CompilerContext)>.Error( or: Result<TableKeyEntry>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing table key entry declaration component"))) withError: "Missing table key entry declaration component")))
@@ -693,31 +682,31 @@ extension TableKeyEntry: Compilable {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(TableKeyEntry, CompilerContext)>.Error( or: Result<TableKeyEntry>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing table key entry declaration component"))) withError: "Missing table key entry declaration component")))
let maybe_match_type = TableKeyMatchType.Compile( let maybe_match_type = TableKeyMatchType.Compile(
node: current_node!, withContext: current_context) node: current_node!, withContext: current_context)
guard case .Ok((let match_type, _)) = maybe_match_type else { guard case .Ok(let match_type) = maybe_match_type else {
return .Error(maybe_match_type.error()!) return .Error(maybe_match_type.error()!)
} }
return .Ok((TableKeyEntry(keyset_expression as! KeysetExpression, match_type), current_context)) return .Ok(TableKeyEntry(keyset_expression as! KeysetExpression, match_type))
} }
} }
extension TableKeyMatchType: Compilable { extension TableKeyMatchType: Compilable {
public typealias T = TableKeyMatchType public typealias C = TableKeyMatchType
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TableKeyMatchType, CompilerContext)> { ) -> Result<TableKeyMatchType> {
#RequireNodeType<Node, (TableKeyMatchType, CompilerContext)>( #RequireNodeType<Node, TableKeyMatchType>(
node: node, type: "table_key_match_type", nice_type_name: "Table Key Match Type") node: node, type: "table_key_match_type", nice_type_name: "Table Key Match Type")
if node.text! == "exact" { if node.text! == "exact" {
return .Ok((TableKeyMatchType.Exact, context)) return .Ok(TableKeyMatchType.Exact)
} }
return .Error( return .Error(
ErrorWithLocation( ErrorWithLocation(
@@ -727,11 +716,11 @@ extension TableKeyMatchType: Compilable {
} }
extension TableKeys: Compilable { extension TableKeys: Compilable {
public typealias T = TableKeys public typealias C = TableKeys
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TableKeys, CompilerContext)> { ) -> Result<TableKeys> {
#RequireNodeType<Node, (TableKeyMatchType, CompilerContext)>( #RequireNodeType<Node, TableKeyMatchType>(
node: node, type: "table_keys", nice_type_name: "Table Keys") node: node, type: "table_keys", nice_type_name: "Table Keys")
var walker = Walker(node: node) var walker = Walker(node: node)
@@ -746,7 +735,7 @@ extension TableKeys: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(TableKeys, CompilerContext)>.Error( or: Result<TableKeys>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing table keys declaration component in control declaration")) withError: "Missing table keys declaration component in control declaration"))
@@ -754,7 +743,7 @@ extension TableKeys: Compilable {
let (keys, errors) = walker.try_map(n: node.childCount - 1, onlyNamed: true) { current_node in let (keys, errors) = walker.try_map(n: node.childCount - 1, onlyNamed: true) { current_node in
return switch TableKeyEntry.Compile(node: current_node, withContext: context) { return switch TableKeyEntry.Compile(node: current_node, withContext: context) {
case .Ok((let keyset_expression, _)): .Ok(keyset_expression) case .Ok(let keyset_expression): .Ok(keyset_expression)
case .Error(let e): .Error(e) case .Error(let e): .Error(e)
} }
} }
@@ -769,16 +758,16 @@ extension TableKeys: Compilable {
}.joined(separator: ";")))) }.joined(separator: ";"))))
} }
return .Ok((TableKeys(withEntries: keys), context)) return .Ok(TableKeys(withEntries: keys))
} }
} }
extension TableActionsProperty: Compilable { extension TableActionsProperty: Compilable {
public typealias T = TableActionsProperty public typealias C = TableActionsProperty
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TableActionsProperty, CompilerContext)> { ) -> Result<TableActionsProperty> {
#RequireNodeType<Node, (TableActionsProperty, CompilerContext)>( #RequireNodeType<Node, TableActionsProperty>(
node: node, type: "table_actions", nice_type_name: "Table Actions") node: node, type: "table_actions", nice_type_name: "Table Actions")
var walker = Walker(node: node) var walker = Walker(node: node)
@@ -793,7 +782,7 @@ extension TableActionsProperty: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(TableActionsProperty, CompilerContext)>.Error( or: Result<TableActionsProperty>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing table actions declaration component in control declaration")) withError: "Missing table actions declaration component in control declaration"))
@@ -828,16 +817,16 @@ extension TableActionsProperty: Compilable {
}.joined(separator: ";")))) }.joined(separator: ";"))))
} }
return .Ok((TableActionsProperty(actions), context)) return .Ok(TableActionsProperty(actions))
} }
} }
extension TablePropertyList: Compilable { extension TablePropertyList: Compilable {
public typealias T = TablePropertyList public typealias C = TablePropertyList
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TablePropertyList, CompilerContext)> { ) -> Result<TablePropertyList> {
#RequireNodeType<Node, (P4Type, CompilerContext)>( #RequireNodeType<Node, TablePropertyList>(
node: node, type: "table_property_list", nice_type_name: "Table Property List") node: node, type: "table_property_list", nice_type_name: "Table Property List")
var current_context = context var current_context = context
@@ -849,15 +838,13 @@ extension TablePropertyList: Compilable {
node.enumerateNamedChildren { child in node.enumerateNamedChildren { child in
if child.nodeType == "table_keys" { if child.nodeType == "table_keys" {
switch TableKeys.Compile(node: child, withContext: current_context) { switch TableKeys.Compile(node: child, withContext: current_context) {
case .Ok((let table_key, let updated_context)): case .Ok(let table_key):
current_context = updated_context
keys.append(table_key) keys.append(table_key)
case .Error(let e): errors.append(e) case .Error(let e): errors.append(e)
} }
} else if child.nodeType == "table_actions" { } else if child.nodeType == "table_actions" {
switch TableActionsProperty.Compile(node: child, withContext: current_context) { switch TableActionsProperty.Compile(node: child, withContext: current_context) {
case .Ok((let table_action_property, let updated_context)): case .Ok(let table_action_property):
current_context = updated_context
actions.append(table_action_property) actions.append(table_action_property)
case .Error(let e): errors.append(e) case .Error(let e): errors.append(e)
} }
@@ -900,19 +887,19 @@ extension TablePropertyList: Compilable {
actions.append(TableActionsProperty()) actions.append(TableActionsProperty())
} }
return .Ok((TablePropertyList(withActions: actions[0], withKeys: keys[0]), current_context)) return .Ok(TablePropertyList(withActions: actions[0], withKeys: keys[0]))
} }
} }
extension Table: Compilable { extension Table: Compilable {
public typealias T = Table public typealias C = Table
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Table, CompilerContext)> { ) -> Result<Table> {
let table_declaration_node = node let table_declaration_node = node
#RequireNodeType<Node, (P4Type, CompilerContext)>( #RequireNodeType<Node, Table>(
node: table_declaration_node, type: "table_declaration", nice_type_name: "Table Declaration") node: table_declaration_node, type: "table_declaration", nice_type_name: "Table Declaration")
var walker = Walker(node: table_declaration_node) var walker = Walker(node: table_declaration_node)
@@ -924,7 +911,7 @@ extension Table: Compilable {
walker.next() // Skip the XXX? walker.next() // Skip the XXX?
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Table, CompilerContext)>.Error( or: Result<Table>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing table declaration component") sourceLocation: node.toSourceLocation(), withError: "Missing table declaration component")
)) ))
@@ -942,46 +929,43 @@ extension Table: Compilable {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(Table, CompilerContext)>.Error( or: Result<Table>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing table declaration component") sourceLocation: node.toSourceLocation(), withError: "Missing table declaration component")
)) ))
let maybe_table_property_list = TablePropertyList.Compile( let maybe_table_property_list = TablePropertyList.Compile(
node: current_node!, withContext: current_context) node: current_node!, withContext: current_context)
guard case .Ok((let table_property_list, _)) = maybe_table_property_list else { guard case .Ok(let table_property_list) = maybe_table_property_list else {
return Result.Error(maybe_table_property_list.error()!) return Result.Error(maybe_table_property_list.error()!)
} }
return .Ok( return .Ok(Table(withName: table_name, withPropertyList: table_property_list))
(Table(withName: table_name, withPropertyList: table_property_list), current_context))
} }
} }
extension ExternDeclaration: CompilableDeclaration { extension ExternDeclaration: Compilable {
public typealias C = Declaration
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Declaration, CompilerContext)?> { ) -> Result<Declaration> {
let extern_declaration_node = node let extern_declaration_node = node
#RequireNodeType<Node, (Declaration, CompilerContext)>( #RequireNodeType<Node, Declaration>(
node: extern_declaration_node, type: "extern_declaration", node: extern_declaration_node, type: "extern_declaration",
nice_type_name: "Extern Declaration") nice_type_name: "Extern Declaration")
let declaration_node = extern_declaration_node.child(at: 1)! let declaration_node = extern_declaration_node.child(at: 1)!
#RequireNodeType<Node, (Declaration, CompilerContext)>( #RequireNodeType<Node, Declaration>(
node: declaration_node, type: "declaration", nice_type_name: "Declaration") node: declaration_node, type: "declaration", nice_type_name: "Declaration")
let declarationed_node = declaration_node.child(at: 0)! let declarationed_node = declaration_node.child(at: 0)!
let maybe_declared = Declaration.Compile( let maybe_declared = Declaration.Compile(
node: declarationed_node, withContext: context.update(newExtern: true)) node: declarationed_node, withContext: context.update(newExtern: true))
guard case .Ok(let maybe_declared) = maybe_declared else { guard case .Ok(let declared) = maybe_declared else {
return .Error(maybe_declared.error()!) return .Error(maybe_declared.error()!)
} }
guard case .some((let declared, _)) = maybe_declared else {
return .Ok(.none)
}
// Before we are okay with this declaration, it must already be registered as an extern // Before we are okay with this declaration, it must already be registered as an extern
// with the matching "stuff". // with the matching "stuff".
@@ -1000,11 +984,7 @@ extension ExternDeclaration: CompilableDeclaration {
let extern_declaration = Declaration(extern: declared, ffi: found_ffi) let extern_declaration = Declaration(extern: declared, ffi: found_ffi)
return .Ok( return .Ok(
(
extern_declaration, extern_declaration,
context.update( )
newExterns: context.externs.declare(
identifier: declared.identifier, withValue: extern_declaration))
))
} }
} }
+78 -65
View File
@@ -21,22 +21,10 @@ import P4Runtime
import SwiftTreeSitter import SwiftTreeSitter
import TreeSitterP4 import TreeSitterP4
protocol CompilableExpression {
static func compile(
node: Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?>
}
protocol CompilableLValueExpression {
static func compile_as_lvalue(
node: Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression?>
}
extension TypedIdentifier: CompilableExpression { extension TypedIdentifier: CompilableExpression {
static func compile( public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> { ) -> Result<P4Expression?> {
let node = node.child(at: 0)! let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>( #SkipUnlessNodeType<SwiftTreeSitter.Node>(
@@ -57,9 +45,9 @@ extension TypedIdentifier: CompilableExpression {
} }
extension TypedIdentifier: CompilableLValueExpression { extension TypedIdentifier: CompilableLValueExpression {
static func compile_as_lvalue( public static func compile_as_lvalue(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression?> { ) -> Result<P4LValueExpression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>( #SkipUnlessNodeType<SwiftTreeSitter.Node>(
@@ -77,9 +65,9 @@ extension TypedIdentifier: CompilableLValueExpression {
} }
extension P4BooleanValue: CompilableExpression { extension P4BooleanValue: CompilableExpression {
static func compile( public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> { ) -> Result<P4Expression?> {
let node = node.child(at: 0)! let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>( #SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: node, type: "booleanLiteralExpression") node: node, type: "booleanLiteralExpression")
@@ -98,9 +86,9 @@ extension P4BooleanValue: CompilableExpression {
} }
extension P4IntValue: CompilableExpression { extension P4IntValue: CompilableExpression {
static func compile( public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> { ) -> Result<P4Expression?> {
let node = node.child(at: 0)! let node = node.child(at: 0)!
#SkipUnlessNodesTypes<SwiftTreeSitter.Node>( #SkipUnlessNodesTypes<SwiftTreeSitter.Node>(
@@ -147,9 +135,9 @@ extension P4IntValue: CompilableExpression {
} }
extension P4StringValue: CompilableExpression { extension P4StringValue: CompilableExpression {
static func compile( public static func compile(
node: SwiftTreeSitter.Node, withContext scopes: CompilerContext node: SwiftTreeSitter.Node, withContext scopes: CompilerContext
) -> Result<EvaluatableExpression?> { ) -> Result<P4Expression?> {
let node = node.child(at: 0)! let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>( #SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: node, type: "string_literal") node: node, type: "string_literal")
@@ -158,12 +146,12 @@ extension P4StringValue: CompilableExpression {
} }
extension KeysetExpression: CompilableExpression { extension KeysetExpression: CompilableExpression {
static func compile( public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableExpression)?> { ) -> Result<P4Expression?> {
let keyset_expression_node = node.child(at: 0)! let keyset_expression_node = node.child(at: 0)!
#RequireNodesType<Node, EvaluatableExpression>( #RequireNodesType<Node, P4Expression>(
nodes: keyset_expression_node, type: ["expression", "default_keyset"], nodes: keyset_expression_node, type: ["expression", "default_keyset"],
nice_type_names: ["expression", "default keyset"]) nice_type_names: ["expression", "default keyset"])
@@ -186,12 +174,12 @@ extension KeysetExpression: CompilableExpression {
struct Expression { struct Expression {
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression> { ) -> Result<P4Expression> {
#RequireNodeType<Node, EvaluatableExpression>( #RequireNodeType<Node, P4Expression>(
node: node, type: "expression", nice_type_name: "expression") node: node, type: "expression", nice_type_name: "expression")
let expression_node = node.child(at: 0)! let expression_node = node.child(at: 0)!
#RequireNodesType<Node, EvaluatableExpression>( #RequireNodesType<Node, P4Expression>(
nodes: expression_node, type: ["grouped_expression", "simple_expression"], nodes: expression_node, type: ["grouped_expression", "simple_expression"],
nice_type_names: ["grouped expression", "simple expression"]) nice_type_names: ["grouped expression", "simple expression"])
@@ -223,12 +211,12 @@ struct Expression {
struct LValue { struct LValue {
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression> { ) -> Result<P4LValueExpression> {
#RequireNodeType<Node, EvaluatableExpression>( #RequireNodeType<Node, P4Expression>(
node: node, type: "expression", nice_type_name: "expression") node: node, type: "expression", nice_type_name: "expression")
let expression_node = node.child(at: 0)! let expression_node = node.child(at: 0)!
#RequireNodesType<Node, EvaluatableExpression>( #RequireNodesType<Node, P4Expression>(
nodes: expression_node, type: ["grouped_expression", "simple_expression"], nodes: expression_node, type: ["grouped_expression", "simple_expression"],
nice_type_names: ["grouped expression", "simple expression"]) nice_type_names: ["grouped expression", "simple expression"])
@@ -268,9 +256,9 @@ struct Identifier {
} }
extension SelectExpression: CompilableExpression { extension SelectExpression: CompilableExpression {
static func compile( public static func compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> { ) -> Result<P4Expression?> {
#RequireNodeType<Node, (SelectExpression, CompilerContext)>( #RequireNodeType<Node, (SelectExpression, CompilerContext)>(
node: node, type: "selectExpression", nice_type_name: "parser select expression") node: node, type: "selectExpression", nice_type_name: "parser select expression")
@@ -330,9 +318,9 @@ extension SelectExpression: CompilableExpression {
} }
extension SelectCaseExpression: CompilableExpression { extension SelectCaseExpression: CompilableExpression {
static func compile( public static func compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> { ) -> Result<P4Expression?> {
if node.nodeType != "selectCase" { if node.nodeType != "selectCase" {
return Result.Error(Error(withMessage: "Expected select case not found")) return Result.Error(Error(withMessage: "Expected select case not found"))
} }
@@ -383,10 +371,35 @@ extension SelectCaseExpression: CompilableExpression {
} }
} }
// 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 { extension BinaryOperatorExpression: CompilableExpression {
static func compile( public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<(EvaluatableExpression)?> { ) -> Result<(P4Expression)?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>( #SkipUnlessNodeType<Node>(
@@ -398,20 +411,20 @@ extension BinaryOperatorExpression: CompilableExpression {
var current_node: Node? = .none var current_node: Node? = .none
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed binary operator expression" sourceLocation: node.toSourceLocation(), withError: "Malformed binary operator expression"
))) )))
/// TODO: This macro cannot handle new lines in the arrays /// TODO: This macro cannot handle new lines in the arrays
// swift-format-ignore // swift-format-ignore
#RequireNodesType<Node, EvaluatableExpression?>( #RequireNodesType<Node, P4Expression?>(
nodes: binary_operator_expression_node, nodes: binary_operator_expression_node,
type: ["binaryEqualOperatorExpression", "binaryLessThanOperatorExpression", "binaryLessThanEqualOperatorExpression", "binaryGreaterThanOperatorExpression", "binaryGreaterThanEqualOperatorExpression", "binaryAndOperatorExpression", "binaryOrOperatorExpression", "binaryAddOperatorExpression", "binarySubtractOperatorExpression", "binaryMultiplyOperatorExpression", "binaryDivideOperatorExpression"], 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"]) 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( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing LHS for binary operator expression"))) withError: "Missing LHS for binary operator expression")))
@@ -421,7 +434,7 @@ extension BinaryOperatorExpression: CompilableExpression {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing binary operator for binary operator expression"))) withError: "Missing binary operator for binary operator expression")))
@@ -429,7 +442,7 @@ extension BinaryOperatorExpression: CompilableExpression {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing RHS for binary operator expression"))) withError: "Missing RHS for binary operator expression")))
@@ -520,9 +533,9 @@ extension BinaryOperatorExpression: CompilableExpression {
} }
extension ArrayAccessExpression: CompilableExpression { extension ArrayAccessExpression: CompilableExpression {
static func compile( public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<EvaluatableExpression?> { ) -> Result<P4Expression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>( #SkipUnlessNodeType<Node>(
@@ -535,11 +548,11 @@ extension ArrayAccessExpression: CompilableExpression {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed array access expression"))) sourceLocation: node.toSourceLocation(), withError: "Malformed array access expression")))
#RequireNodeType<Node, EvaluatableExpression?>( #RequireNodeType<Node, P4Expression?>(
node: current_node!, type: "expression", node: current_node!, type: "expression",
nice_type_name: "array identifier expression") nice_type_name: "array identifier expression")
let array_access_identifier_node = current_node! let array_access_identifier_node = current_node!
@@ -547,7 +560,7 @@ extension ArrayAccessExpression: CompilableExpression {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing [ for array access expression"))) withError: "Missing [ for array access expression")))
@@ -556,12 +569,12 @@ extension ArrayAccessExpression: CompilableExpression {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing indexor expression for array access expression"))) withError: "Missing indexor expression for array access expression")))
#RequireNodeType<Node, EvaluatableExpression?>( #RequireNodeType<Node, P4Expression?>(
node: current_node!, type: "expression", node: current_node!, type: "expression",
nice_type_name: "array indexor expression") nice_type_name: "array indexor expression")
@@ -595,9 +608,9 @@ extension ArrayAccessExpression: CompilableExpression {
} }
extension FieldAccessExpression: CompilableExpression { extension FieldAccessExpression: CompilableExpression {
static func compile( public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableExpression)?> { ) -> Result<P4Expression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>( #SkipUnlessNodeType<Node>(
@@ -610,11 +623,11 @@ extension FieldAccessExpression: CompilableExpression {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed field access expression"))) sourceLocation: node.toSourceLocation(), withError: "Malformed field access expression")))
#RequireNodeType<Node, EvaluatableExpression?>( #RequireNodeType<Node, P4Expression?>(
node: current_node!, type: "expression", node: current_node!, type: "expression",
nice_type_name: "struct identifier expression") nice_type_name: "struct identifier expression")
let struct_identifier_node = current_node! let struct_identifier_node = current_node!
@@ -622,7 +635,7 @@ extension FieldAccessExpression: CompilableExpression {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing . for field access expression"))) withError: "Missing . for field access expression")))
@@ -630,12 +643,12 @@ extension FieldAccessExpression: CompilableExpression {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing field name for field access expression"))) withError: "Missing field name for field access expression")))
#RequireNodeType<Node, EvaluatableExpression?>( #RequireNodeType<Node, P4Expression?>(
node: current_node!, type: "identifier", node: current_node!, type: "identifier",
nice_type_name: "field name") nice_type_name: "field name")
@@ -677,9 +690,9 @@ extension FieldAccessExpression: CompilableExpression {
} }
extension FieldAccessExpression: CompilableLValueExpression { extension FieldAccessExpression: CompilableLValueExpression {
static func compile_as_lvalue( public static func compile_as_lvalue(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression?> { ) -> Result<P4LValueExpression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>( #SkipUnlessNodeType<Node>(
node: expression, type: "fieldAccessExpression") node: expression, type: "fieldAccessExpression")
@@ -696,9 +709,9 @@ extension FieldAccessExpression: CompilableLValueExpression {
} }
extension ArrayAccessExpression: CompilableLValueExpression { extension ArrayAccessExpression: CompilableLValueExpression {
static func compile_as_lvalue( public static func compile_as_lvalue(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression?> { ) -> Result<P4LValueExpression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>( #SkipUnlessNodeType<Node>(
node: expression, type: "arrayAccessExpression") node: expression, type: "arrayAccessExpression")
@@ -715,9 +728,9 @@ extension ArrayAccessExpression: CompilableLValueExpression {
} }
extension FunctionCall: CompilableExpression { extension FunctionCall: CompilableExpression {
static func compile( public static func compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> { ) -> Result<P4Expression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>( #SkipUnlessNodeType<Node>(
@@ -728,7 +741,7 @@ extension FunctionCall: CompilableExpression {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing function call component"))) sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
@@ -780,13 +793,13 @@ extension FunctionCall: CompilableExpression {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error( or: Result<P4Expression?>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing function call component"))) sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
let maybe_argument_list = ArgumentList.Compile(node: current_node!, withContext: context) let maybe_argument_list = ArgumentList.Compile(node: current_node!, withContext: context)
guard case .Ok((let arguments, _)) = maybe_argument_list else { guard case .Ok(let arguments) = maybe_argument_list else {
return .Error(maybe_argument_list.error()!) return .Error(maybe_argument_list.error()!)
} }
+21 -22
View File
@@ -23,10 +23,10 @@ import TreeSitterExtensions
import TreeSitterP4 import TreeSitterP4
extension Statement: Compilable { extension Statement: Compilable {
public typealias T = EvaluatableStatement public typealias C = P4Statement
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(EvaluatableStatement, CompilerContext)> { ) -> Result<P4Statement> {
if node.nodeType != "parserStatement" && node.nodeType != "statement" { if node.nodeType != "parserStatement" && node.nodeType != "statement" {
return Result.Error( return Result.Error(
@@ -51,9 +51,9 @@ extension Statement: Compilable {
withError: withError:
"Unparseable statement type (\(statement.nodeType ?? "Unknown Statement Type"))")) "Unparseable statement type (\(statement.nodeType ?? "Unknown Statement Type"))"))
} }
switch parser.Compile(node: statement, withContext: context) { switch parser.CompileStatement(node: statement, withContext: context) {
case Result.Ok(let (parsed, updated_context)): case Result.Ok(let parsed):
return .Ok((parsed, updated_context)) return .Ok(parsed)
case Result.Error(let e): case Result.Error(let e):
return .Error( return .Error(
ErrorWithLocation( ErrorWithLocation(
@@ -62,11 +62,12 @@ extension Statement: Compilable {
} }
} }
} }
extension LocalElements: Compilable { extension LocalElements: Compilable {
public typealias T = EvaluatableStatement public typealias C = P4Statement
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> { ) -> Result<P4Statement> {
let localElementsParsers: [String: CompilableStatement.Type] = [ let localElementsParsers: [String: CompilableStatement.Type] = [
"variableDeclaration": VariableDeclarationStatement.self "variableDeclaration": VariableDeclarationStatement.self
] ]
@@ -78,9 +79,9 @@ extension LocalElements: Compilable {
withError: "Unparseable statement type (\(node.nodeType ?? "Unknown Statement Type"))")) withError: "Unparseable statement type (\(node.nodeType ?? "Unknown Statement Type"))"))
} }
switch parser.Compile(node: node, withContext: context) { switch parser.CompileStatement(node: node, withContext: context) {
case Result.Ok(let (parsed, parsed_updated_scopes)): case Result.Ok(let parsed):
return Result.Ok((parsed, parsed_updated_scopes)) return Result.Ok(parsed)
case Result.Error(let e): case Result.Error(let e):
return Result.Error(Error(withMessage: "Failed to parse local element: \(e)")) return Result.Error(Error(withMessage: "Failed to parse local element: \(e)"))
} }
@@ -88,10 +89,10 @@ extension LocalElements: Compilable {
} }
extension ParserState: Compilable { extension ParserState: Compilable {
public typealias T = ParserState public typealias C = ParserState
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(ParserState, CompilerContext)> { ) -> Result<ParserState> {
var walker = Walker(node: node) var walker = Walker(node: node)
var current_node: Node? = .none var current_node: Node? = .none
@@ -107,7 +108,7 @@ extension ParserState: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ParserState, CompilerContext)>.Error( or: Result<ParserState>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing elements in parser state declaration"))) withError: "Missing elements in parser state declaration")))
@@ -125,7 +126,7 @@ extension ParserState: Compilable {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ParserState, CompilerContext)>.Error( or: Result<ParserState>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing elements in parser state declaration"))) withError: "Missing elements in parser state declaration")))
@@ -141,22 +142,20 @@ extension ParserState: Compilable {
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ParserState, CompilerContext)>.Error( or: Result<ParserState>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing body of state declaration") sourceLocation: node.toSourceLocation(), withError: "Missing body of state declaration")
)) ))
var errors: (any Errorable)? = .none var errors: (any Errorable)? = .none
var current_context = context var parsed_s: [P4Statement] = Array()
var parsed_s: [EvaluatableStatement] = Array()
if current_node!.nodeType == "parserStatements" { if current_node!.nodeType == "parserStatements" {
switch SpecialCompilers.Statements.Compile( switch SpecialCompilers.Statements.Compile(
node: current_node!, withContext: current_context) node: current_node!, withContext: context)
{ {
case .Ok(let (state_statements, updated_context)): case .Ok(let state_statements):
parsed_s = state_statements parsed_s = state_statements
current_context = updated_context
case .Error(let error): case .Error(let error):
errors = errors =
if let errors = errors { if let errors = errors {
@@ -174,13 +173,13 @@ extension ParserState: Compilable {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(ParserState, CompilerContext)>.Error( or: Result<ParserState>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), sourceLocation: node.toSourceLocation(),
withError: "Missing transition statement of state declaration"))) withError: "Missing transition statement of state declaration")))
return SpecialCompilers.TransitionStatement.Compile( return SpecialCompilers.TransitionStatement.Compile(
node: current_node!, forState: state_identifier, withStatements: parsed_s, node: current_node!, forState: state_identifier, withStatements: parsed_s,
withContext: current_context) withContext: SpecialCompilers.Statements.effect(statements: parsed_s, context: context))
} }
} }
+18 -16
View File
@@ -22,12 +22,6 @@ import SwiftTreeSitter
import TreeSitterExtensions import TreeSitterExtensions
import TreeSitterP4 import TreeSitterP4
public protocol CompilableStatement {
static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)>
}
public protocol CompilableValue { public protocol CompilableValue {
static func CompileValue(withValue value: String) -> Result<P4DataValue> static func CompileValue(withValue value: String) -> Result<P4DataValue>
} }
@@ -38,19 +32,27 @@ public protocol CompilableType {
) -> Result<P4Type?> ) -> Result<P4Type?>
} }
public protocol CompilableDeclaration { public protocol CompilableExpression {
/// Info static func compile(
///
/// Extensions should update the context with the newly declared item _unless_
/// they are in an extern context (``CompilerContext.extern_context``).
static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(Declaration, CompilerContext)?> ) -> Result<P4Expression?>
} }
public protocol Compilable<T> { public protocol CompilableLValueExpression {
associatedtype T static func compile_as_lvalue(
node: Node, withContext context: CompilerContext
) -> Result<P4LValueExpression?>
}
public protocol Compilable<C> {
associatedtype C
static func Compile( static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(T, CompilerContext)> ) -> Result<C>
}
public protocol CompilableStatement {
static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement>
} }
+52 -45
View File
@@ -22,14 +22,20 @@ import SwiftTreeSitter
import TreeSitterExtensions import TreeSitterExtensions
import TreeSitterP4 import TreeSitterP4
protocol AnyCompilable {
static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Any, CompilerContext)>
}
public struct SpecialCompilers { public struct SpecialCompilers {
public struct TransitionStatement { public struct TransitionStatement {
static func Compile( static func Compile(
node: Node, forState state_identifier: Common.Identifier, node: Node, forState state_identifier: Common.Identifier,
withStatements stmts: [EvaluatableStatement], withContext context: CompilerContext withStatements stmts: [P4Statement], withContext context: CompilerContext
) -> Result<(ParserState, CompilerContext)> { ) -> Result<ParserState> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( #RequireNodeType<Node, P4Statement>(
node: node, type: "parserTransitionStatement", nice_type_name: "parser transition statement" node: node, type: "parserTransitionStatement", nice_type_name: "parser transition statement"
) )
@@ -58,19 +64,18 @@ public struct SpecialCompilers {
switch next_state { switch next_state {
case (_, .some(let instance)): case (_, .some(let instance)):
return .Ok( return .Ok(
(
ParserStateDirectTransition( ParserStateDirectTransition(
name: state_identifier, name: state_identifier,
withNextState: instance.dataValue() as! InstantiatedParserState, withNextState: instance.dataValue() as! InstantiatedParserState,
withStatements: stmts), context withStatements: stmts,
)) )
)
case (_, .none): case (_, .none):
return .Ok( return .Ok(
(
ParserStateDirectTransition( ParserStateDirectTransition(
name: state_identifier, name: state_identifier,
withNextStateIdentifier: next_state_id, withStatements: stmts), context withNextStateIdentifier: next_state_id, withStatements: stmts)
)) )
} }
} else { } else {
@@ -95,12 +100,11 @@ public struct SpecialCompilers {
{ {
case .Ok(let tse): case .Ok(let tse):
.Ok( .Ok(
(
ParserStateSelectTransition( ParserStateSelectTransition(
name: state_identifier, withTransitionExpression: tse as! SelectExpression, name: state_identifier, withTransitionExpression: tse as! SelectExpression,
withStatements: stmts, withStatements: stmts,
), context )
)) )
case .Error(let e): .Error(e) case .Error(let e): .Error(e)
} }
} }
@@ -109,7 +113,7 @@ public struct SpecialCompilers {
public struct Statements { public struct Statements {
static func Compile( static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<([EvaluatableStatement], CompilerContext)> { ) -> Result<[P4Statement]> {
if node.nodeType != "statements" && node.nodeType != "parserStatements" { if node.nodeType != "statements" && node.nodeType != "parserStatements" {
return Result.Error( return Result.Error(
ErrorWithLocation( ErrorWithLocation(
@@ -118,15 +122,15 @@ public struct SpecialCompilers {
var errors: (any Errorable)? = .none var errors: (any Errorable)? = .none
var current_context = context var current_context = context
var parsed_s: [EvaluatableStatement] = Array() var parsed_s: [P4Statement] = Array()
node.enumerateNamedChildren { node in node.enumerateNamedChildren { node in
switch Statement.Compile( switch Statement.Compile(
node: node, withContext: current_context) node: node, withContext: current_context)
{ {
case .Ok((let parsed_statement, let updated_context)): case .Ok(let parsed_statement):
current_context = updated_context
parsed_s.append(parsed_statement) parsed_s.append(parsed_statement)
current_context = parsed_statement.effect(context: current_context)
case .Error(let e): case .Error(let e):
errors = errors =
if let errors = errors { if let errors = errors {
@@ -141,11 +145,20 @@ public struct SpecialCompilers {
return .Error(errors) return .Error(errors)
} }
return Result.Ok((parsed_s, current_context)) return Result.Ok(parsed_s)
}
} }
static func Compile( 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, withName name: Common.Identifier, withParameters parameters: ParameterList, node: Node,
withContext context: CompilerContext withContext context: CompilerContext
) -> Result<(P4Lang.Parser, CompilerContext)> { ) -> Result<(P4Lang.Parser, CompilerContext)> {
@@ -167,9 +180,10 @@ public struct SpecialCompilers {
node: parser_state, node: parser_state,
withContext: context.update(newInstances: current_context.instances.enter())) withContext: context.update(newInstances: current_context.instances.enter()))
{ {
case Result.Ok(let (state, updated_context)): case Result.Ok(let state):
let statement = state as P4Statement
current_context = statement.effect(context: current_context)
parser.states = parser.states.append(state: state) parser.states = parser.states.append(state: state)
current_context = updated_context
case Result.Error(let e): error = e case Result.Error(let e): error = e
} }
} }
@@ -245,43 +259,35 @@ public struct SpecialCompilers {
// Try to parse all top-level declarations. // Try to parse all top-level declarations.
result?.rootNode?.enumerateNamedChildren { (declaration_node: Node) in result?.rootNode?.enumerateNamedChildren { (declaration_node: Node) in
let specific_declaration_node = declaration_node.child(at: 0)! let declaration_parsers: [String: CompilableStatement.Type] = [
"declaration": Declaration.self,
let declaration_parsers: [CompilableDeclaration.Type] = [ "instantiation": Instantiation.self,
Declaration.self, P4Lang.Parser.self,
] ]
var found_parser = false
for parser in declaration_parsers { if let parser = declaration_parsers[declaration_node.nodeType!] {
switch parser.Compile(node: specific_declaration_node, withContext: compilation_context) { let r = parser.CompileStatement(node: declaration_node, withContext: compilation_context)
case .Ok(.none): {}() switch r {
case .Ok(.some((_, let updated_context))): case .Ok(let compiled):
found_parser = true compilation_context = compiled.effect(context: compilation_context)
compilation_context = updated_context
break
case .Error(let e): case .Error(let e):
found_parser = true
errors = errors =
if let errors = errors { if let errors = errors {
errors.append(error: e) errors.append(error: e)
} else { } else {
e e
} }
break
}
}
// If none of the declaration parsers chose to parse, that's an error, too! }
if !found_parser { } else {
let no_parser_error = ErrorWithLocation( let e = ErrorWithLocation(
sourceLocation: specific_declaration_node.toSourceLocation(), sourceLocation: declaration_node.toSourceLocation(),
withError: "Could not find parser for declaration node" withError:
) "\(declaration_node.nodeType!) cannot be at a P4 program top level")
errors = errors =
if let errors = errors { if let errors = errors {
errors.append(error: no_parser_error) errors.append(error: e)
} else { } else {
no_parser_error e
} }
} }
} }
@@ -313,4 +319,5 @@ public struct SpecialCompilers {
return Result.Ok(program) return Result.Ok(program)
} }
} }
} }
+273 -55
View File
@@ -22,11 +22,12 @@ import SwiftTreeSitter
import TreeSitterExtensions import TreeSitterExtensions
import TreeSitterP4 import TreeSitterP4
extension BlockStatement: CompilableStatement { extension BlockStatement: Compilable {
public typealias C = BlockStatement
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> { ) -> Result<BlockStatement> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( #RequireNodeType<Node, (P4Statement)>(
node: node, type: "blockStatement", nice_type_name: "block statement") node: node, type: "blockStatement", nice_type_name: "block statement")
var walker = Walker(node: node) var walker = Walker(node: node)
@@ -34,7 +35,7 @@ extension BlockStatement: CompilableStatement {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error( or: Result<BlockStatement>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement"))) sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
@@ -45,23 +46,21 @@ extension BlockStatement: CompilableStatement {
withError: "Missing { on block statement")) withError: "Missing { on block statement"))
} }
var statements: [EvaluatableStatement] = Array() var statements: [P4Statement] = Array()
var parse_err: (any Errorable)? = .none var parse_err: (any Errorable)? = .none
var current_context = context
walker.next() walker.next()
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error( or: Result<BlockStatement>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement"))) sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
if current_node!.nodeType == "statements" { if current_node!.nodeType == "statements" {
switch SpecialCompilers.Statements.Compile( switch SpecialCompilers.Statements.Compile(
node: current_node!, withContext: current_context) node: current_node!, withContext: context)
{ {
case .Ok(let (parsed_statements, updated_context)): case .Ok(let parsed_statements):
current_context = updated_context
statements = parsed_statements statements = parsed_statements
case .Error(let error): case .Error(let error):
parse_err = error parse_err = error
@@ -76,7 +75,7 @@ extension BlockStatement: CompilableStatement {
#MustOr( #MustOr(
result: current_node, thing: walker.getNext(), result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error( or: Result<BlockStatement>.Error(
ErrorWithLocation( ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement"))) sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
@@ -87,16 +86,28 @@ extension BlockStatement: CompilableStatement {
withError: "Missing } on block statement")) withError: "Missing } on block statement"))
} }
return .Ok((BlockStatement(statements), current_context)) return .Ok(BlockStatement(statements))
} }
} }
extension ConditionalStatement: CompilableStatement { extension BlockStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension ConditionalStatement: Compilable {
public typealias C = ConditionalStatement
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> { ) -> Result<ConditionalStatement> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( #RequireNodeType<Node, (P4Statement)>(
node: node, type: "conditionalStatement", nice_type_name: "conditional statement") node: node, type: "conditionalStatement", nice_type_name: "conditional statement")
let maybe_condition_expression = node.child(at: 2) let maybe_condition_expression = node.child(at: 2)
@@ -128,7 +139,7 @@ extension ConditionalStatement: CompilableStatement {
} }
guard guard
case .Ok((let thenns, _)) = Statement.Compile( case .Ok(let thenns) = Statement.Compile(
node: thens, withContext: context) node: thens, withContext: context)
else { else {
return Result.Error( return Result.Error(
@@ -137,7 +148,7 @@ extension ConditionalStatement: CompilableStatement {
"Could not parse the then block in a conditional statement")) "Could not parse the then block in a conditional statement"))
} }
let optional_elss: Result<(any EvaluatableStatement, CompilerContext)>? = let optional_elss: Result<any P4Statement>? =
if let elss = node.child(at: 6) { if let elss = node.child(at: 6) {
.some( .some(
Statement.Compile( Statement.Compile(
@@ -148,7 +159,7 @@ extension ConditionalStatement: CompilableStatement {
if let parsed_elss = optional_elss { if let parsed_elss = optional_elss {
guard guard
case .Ok((let elss, _)) = parsed_elss case .Ok(let elss) = parsed_elss
else { else {
return Result.Error( return Result.Error(
Error( Error(
@@ -156,18 +167,30 @@ extension ConditionalStatement: CompilableStatement {
"Could not parse the else block in a conditional statement")) "Could not parse the else block in a conditional statement"))
} }
return .Ok( return .Ok(
(ConditionalStatement(condition: condition, withThen: thenns, andElse: elss), context)) ConditionalStatement(condition: condition, withThen: thenns, andElse: elss))
} }
return .Ok((ConditionalStatement(condition: condition, withThen: thenns), context)) return .Ok(ConditionalStatement(condition: condition, withThen: thenns))
} }
} }
extension VariableDeclarationStatement: CompilableStatement { extension ConditionalStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension VariableDeclarationStatement: Compilable {
public typealias C = VariableDeclarationStatement
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> { ) -> Result<VariableDeclarationStatement> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( #RequireNodeType<Node, (P4Statement)>(
node: node, type: "variableDeclaration", nice_type_name: "variable declaration statement") node: node, type: "variableDeclaration", nice_type_name: "variable declaration statement")
let maybe_typeref = node.child(at: 0) let maybe_typeref = node.child(at: 0)
@@ -206,7 +229,7 @@ extension VariableDeclarationStatement: CompilableStatement {
Error(withMessage: "Could not parse a P4 type from \(typeref.text!)")) Error(withMessage: "Could not parse a P4 type from \(typeref.text!)"))
} }
var initializer: EvaluatableExpression? = .none var initializer: P4Expression? = .none
// If there is an initializer, it must be an expression. // If there is an initializer, it must be an expression.
if let initializer_expression = maybe_rvalue { if let initializer_expression = maybe_rvalue {
@@ -249,40 +272,59 @@ extension VariableDeclarationStatement: CompilableStatement {
} }
return Result.Ok( return Result.Ok(
(
VariableDeclarationStatement( VariableDeclarationStatement(
identifier: parsed_variablename, withInitializer: initializer), identifier: TypedIdentifier(id: parsed_variablename, withType: declaration_p4_type),
// Context with updated names to include the newly declared name. withInitializer: initializer),
context.update(
newInstances: context.instances.declare(
identifier: parsed_variablename, withValue: (declaration_p4_type, .none)))
)
) )
} }
} }
extension ExpressionStatement: CompilableStatement { extension VariableDeclarationStatement: CompilableStatement {
public static func Compile( public static func CompileStatement(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> { ) -> Result<P4Statement> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( return switch Compile(node: node, withContext: context) {
node: node, type: "expressionStatement", nice_type_name: "expression statement") case .Ok(let res): .Ok(res)
let expression_node = node.child(at: 0)!
return switch Expression.Compile(node: expression_node, withContext: context) {
case .Ok(let expression): .Ok((ExpressionStatement(expression), context))
case .Error(let e): .Error(e) case .Error(let e): .Error(e)
} }
} }
} }
extension ParserAssignmentStatement: CompilableStatement { extension ExpressionStatement: Compilable {
public typealias C = ExpressionStatement
public static func Compile( public static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> { ) -> Result<ExpressionStatement> {
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "expressionStatement", nice_type_name: "expression statement")
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( let expression_node = node.child(at: 0)!
return switch Expression.Compile(node: expression_node, withContext: context) {
case .Ok(let expression): .Ok(ExpressionStatement(expression))
case .Error(let e): .Error(e)
}
}
}
extension ExpressionStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension ParserAssignmentStatement: Compilable {
public typealias C = ParserAssignmentStatement
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<ParserAssignmentStatement> {
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "assignmentStatement", nice_type_name: "assignment statement") node: node, type: "assignmentStatement", nice_type_name: "assignment statement")
guard let lvalue_node = node.child(at: 0), guard let lvalue_node = node.child(at: 0),
@@ -323,20 +365,30 @@ extension ParserAssignmentStatement: CompilableStatement {
} }
return Result.Ok( return Result.Ok(
(
ParserAssignmentStatement( ParserAssignmentStatement(
withLValue: lvalue_identifier, withLValue: lvalue_identifier,
withValue: rvalue withValue: rvalue
), context
)) ))
} }
} }
extension ReturnStatement: CompilableStatement { extension ParserAssignmentStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension ReturnStatement: Compilable {
public typealias C = ReturnStatement
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableStatement, CompilerContext)> { ) -> Result<ReturnStatement> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( #RequireNodeType<Node, (P4Statement)>(
node: node, type: "return_statement", nice_type_name: "return statement") node: node, type: "return_statement", nice_type_name: "return statement")
let expression_node = node.child(at: 1)! let expression_node = node.child(at: 1)!
@@ -344,7 +396,7 @@ extension ReturnStatement: CompilableStatement {
return switch Expression.Compile(node: expression_node, withContext: context) { return switch Expression.Compile(node: expression_node, withContext: context) {
case .Ok(let result): case .Ok(let result):
if result.type().baseType().eq(rhs: context.expected_type!.baseType()) { if result.type().baseType().eq(rhs: context.expected_type!.baseType()) {
.Ok((ReturnStatement(result), context)) .Ok(ReturnStatement(result))
} else { } else {
.Error( .Error(
ErrorWithLocation( ErrorWithLocation(
@@ -358,18 +410,184 @@ extension ReturnStatement: CompilableStatement {
} }
} }
extension ApplyStatement: CompilableStatement { extension ReturnStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension ApplyStatement: Compilable {
public typealias C = ApplyStatement
public static func Compile( public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableStatement, CompilerContext)> { ) -> Result<ApplyStatement> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( #RequireNodeType<Node, (P4Statement)>(
node: node, type: "apply_statement", nice_type_name: "apply statement") node: node, type: "apply_statement", nice_type_name: "apply statement")
let expression_node = node.child(at: 1)! let expression_node = node.child(at: 1)!
return switch BlockStatement.Compile(node: expression_node, withContext: context) { return switch BlockStatement.Compile(node: expression_node, withContext: context) {
case .Ok((let statement, let updated_context)): case .Ok(let statement):
.Ok((ApplyStatement(statement as! BlockStatement), updated_context)) .Ok(ApplyStatement(statement as! BlockStatement))
case .Error(let e): .Error(e)
}
}
}
extension ApplyStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension Instantiation: Compilable {
public typealias C = Instantiation
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<Instantiation> {
let expression = node
#RequireNodeType<Node, (Instantiation)>(
node: expression, type: "instantiation", nice_type_name: "instantiation statement")
var walker = Walker(node: expression)
var current_node: Node? = .none
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<Instantiation>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
let maybe_instantiated_type_name = Identifier.Compile(
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(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing instantiation component")))
let maybe_argument_list = 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(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing instantiation name")))
let name = Identifier.Compile(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
}
}
extension Instantiation: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e) case .Error(let e): .Error(e)
} }
} }
-95
View File
@@ -1,95 +0,0 @@
// 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
public protocol Visitable {
}
public protocol LanguageVisitor<Context> {
associatedtype Context
// Program
func visit(_ program: Program, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
// Parser
func visit(_ parser: Parser, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ parser_state: InstantiatedParserState, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Statements
func visit(
_ variable_declaration: VariableDeclarationStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ conditional: ConditionalStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ block: BlockStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ rtn: ReturnStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ apply: ApplyStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Expressions
func visit(
_ keyset: KeysetExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ select_case: SelectCaseExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ select: SelectExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ array_access: ArrayAccessExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ field_access: FieldAccessExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ function_call: FunctionCall, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ binary_operator: BinaryOperatorExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Declarations
func visit(_ decl: Declaration, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ extern_decl: ExternDeclaration, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ func_decl: FunctionDeclaration, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Control
func visit(_ action: Action, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ table_key_entry: TableKeyEntry, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ table_property_list: TablePropertyList, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(_ table: Table, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(_ control: Control, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
}
+13 -1
View File
@@ -52,7 +52,7 @@ public struct Declaration: P4Type {
return self return self
} }
public var description: String { public var description: String {
return "Extern \(self.identifier)" return self.extern ? "Extern " : "" + "\(self.identifier)"
} }
} }
@@ -130,3 +130,15 @@ public struct FunctionDeclaration: P4Type, P4DataValue {
self.body = body self.body = body
} }
} }
public struct Instantiation {
public let name: Identifier
public let tipe: P4Type
public let arguments: ArgumentList
public init(named name: Identifier, ofType tipe: P4Type, withArguments arguments: ArgumentList) {
self.name = name
self.tipe = tipe
self.arguments = arguments
}
}
+10 -10
View File
@@ -18,9 +18,9 @@
import Common import Common
public struct KeysetExpression { public struct KeysetExpression {
public let key: EvaluatableExpression public let key: P4Expression
public init(_ key: EvaluatableExpression) { public init(_ key: P4Expression) {
self.key = key self.key = key
} }
@@ -65,11 +65,11 @@ public struct SelectCaseExpression {
} }
public struct SelectExpression { public struct SelectExpression {
public let selector: EvaluatableExpression public let selector: P4Expression
public let case_expressions: [SelectCaseExpression] public let case_expressions: [SelectCaseExpression]
public init( public init(
withSelector selector: EvaluatableExpression, withSelector selector: P4Expression,
withSelectCaseExpressions sces: [SelectCaseExpression] withSelectCaseExpressions sces: [SelectCaseExpression]
) { ) {
self.selector = selector self.selector = selector
@@ -105,13 +105,13 @@ public struct BinaryOperatorExpression {
} }
public struct ArrayAccessExpression { public struct ArrayAccessExpression {
public let indexor: EvaluatableExpression public let indexor: P4Expression
public let name: EvaluatableExpression public let name: P4Expression
public let type: P4Array public let type: P4Array
public init( public init(
withName name: EvaluatableExpression, withType type: P4Array, withName name: P4Expression, withType type: P4Array,
withIndexor indexor: EvaluatableExpression withIndexor indexor: P4Expression
) { ) {
self.name = name self.name = name
self.type = type self.type = type
@@ -121,9 +121,9 @@ public struct ArrayAccessExpression {
public struct FieldAccessExpression { public struct FieldAccessExpression {
public let field: P4StructFieldIdentifier public let field: P4StructFieldIdentifier
public let strct: EvaluatableExpression public let strct: P4Expression
public init(withStruct strct: EvaluatableExpression, withField field: P4StructFieldIdentifier) { public init(withStruct strct: P4Expression, withField field: P4StructFieldIdentifier) {
self.strct = strct self.strct = strct
self.field = field self.field = field
} }
+10 -13
View File
@@ -22,11 +22,11 @@ public struct LocalElements {}
public struct LocalElement {} public struct LocalElement {}
public struct ParserAssignmentStatement { public struct ParserAssignmentStatement {
public let lvalue: EvaluatableLValueExpression public let lvalue: P4LValueExpression
public let value: EvaluatableExpression public let value: P4Expression
public init( public init(
withLValue lvalue: EvaluatableLValueExpression, withValue value: EvaluatableExpression withLValue lvalue: P4LValueExpression, withValue value: P4Expression
) { ) {
self.lvalue = lvalue self.lvalue = lvalue
self.value = value self.value = value
@@ -34,12 +34,9 @@ public struct ParserAssignmentStatement {
} }
/// A P4 Parser State /// A P4 Parser State
///
/// Note: A P4 Parser State is both a type and a value.
/// This "bare" parser state represents the state more as a type than a value.
public class ParserState: P4Type, Equatable, CustomStringConvertible { public class ParserState: P4Type, Equatable, CustomStringConvertible {
let name: Identifier let name: Identifier
public let statements: [EvaluatableStatement] public let statements: [P4Statement]
public static func == (lhs: ParserState, rhs: ParserState) -> Bool { public static func == (lhs: ParserState, rhs: ParserState) -> Bool {
return lhs.eq(rhs: rhs) return lhs.eq(rhs: rhs)
@@ -60,12 +57,12 @@ public class ParserState: P4Type, Equatable, CustomStringConvertible {
return self.name return self.name
} }
public func getStatements() -> [EvaluatableStatement] { public func getStatements() -> [P4Statement] {
return self.statements return self.statements
} }
/// Construct a ParserState /// Construct a ParserState
public init(_ name: Identifier, _ statements: [EvaluatableStatement] = Array()) { public init(_ name: Identifier, _ statements: [P4Statement] = Array()) {
self.name = name self.name = name
self.statements = statements self.statements = statements
} }
@@ -100,7 +97,7 @@ public class ParserStateDirectTransition: ParserState {
/// Construct a ParserState /// Construct a ParserState
public init( public init(
name: Identifier, withNextState next_state: InstantiatedParserState, name: Identifier, withNextState next_state: InstantiatedParserState,
withStatements stmts: [EvaluatableStatement] = Array(), withStatements stmts: [P4Statement] = Array(),
) { ) {
self.next_state = next_state self.next_state = next_state
self.next_state_identifier = .none self.next_state_identifier = .none
@@ -109,7 +106,7 @@ public class ParserStateDirectTransition: ParserState {
public init( public init(
name: Identifier, withNextStateIdentifier next_state_id: Identifier, name: Identifier, withNextStateIdentifier next_state_id: Identifier,
withStatements stmts: [EvaluatableStatement] = Array(), withStatements stmts: [P4Statement] = Array(),
) { ) {
self.next_state = .none self.next_state = .none
self.next_state_identifier = next_state_id self.next_state_identifier = next_state_id
@@ -129,7 +126,7 @@ public class ParserStateDirectTransition: ParserState {
public class ParserStateNoTransition: ParserState { public class ParserStateNoTransition: ParserState {
/// Construct a ParserState /// Construct a ParserState
public init( public init(
name: Identifier, withStatements stmts: [EvaluatableStatement] = Array(), name: Identifier, withStatements stmts: [P4Statement] = Array(),
) { ) {
super.init(name, stmts) super.init(name, stmts)
} }
@@ -145,7 +142,7 @@ public class ParserStateSelectTransition: ParserState {
public init( public init(
name: Identifier, withTransitionExpression te: SelectExpression, name: Identifier, withTransitionExpression te: SelectExpression,
withStatements stmts: [EvaluatableStatement] = Array() withStatements stmts: [P4Statement] = Array()
) { ) {
self.te = te self.te = te
super.init(name, stmts) super.init(name, stmts)
+2 -2
View File
@@ -18,9 +18,9 @@
import Common import Common
public struct ExpressionStatement { public struct ExpressionStatement {
public let expression: EvaluatableExpression public let expression: P4Expression
public init(_ expr: EvaluatableExpression) { public init(_ expr: P4Expression) {
self.expression = expr self.expression = expr
} }
} }
+95
View File
@@ -0,0 +1,95 @@
// 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
public protocol Visitable {
}
public protocol LanguageVisitor<Context> {
associatedtype Context
// Program
func visit(_ program: Program, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
// Parser
func visit(_ parser: Parser, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ parser_state: InstantiatedParserState, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Statements
func visit(
_ variable_declaration: VariableDeclarationStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ conditional: ConditionalStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ block: BlockStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ rtn: ReturnStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ apply: ApplyStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Expressions
func visit(
_ keyset: KeysetExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ select_case: SelectCaseExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ select: SelectExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ array_access: ArrayAccessExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ field_access: FieldAccessExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ function_call: FunctionCall, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ binary_operator: BinaryOperatorExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Declarations
func visit(_ decl: Declaration, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ extern_decl: ExternDeclaration, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ func_decl: FunctionDeclaration, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Control
func visit(_ action: Action, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ table_key_entry: TableKeyEntry, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ table_property_list: TablePropertyList, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(_ table: Table, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(_ control: Control, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
}
+13 -13
View File
@@ -20,28 +20,28 @@ import Common
public struct Statement {} public struct Statement {}
public struct VariableDeclarationStatement { public struct VariableDeclarationStatement {
public var initializer: EvaluatableExpression public var initializer: P4Expression
public var identifier: Identifier public var identifier: TypedIdentifier
public init(identifier: Identifier, withInitializer initializer: EvaluatableExpression) { public init(identifier: TypedIdentifier, withInitializer initializer: P4Expression) {
self.identifier = identifier self.identifier = identifier
self.initializer = initializer self.initializer = initializer
} }
} }
public struct ConditionalStatement { public struct ConditionalStatement {
public var condition: EvaluatableExpression public var condition: P4Expression
public var thenn: EvaluatableStatement public var thenn: P4Statement
public var elss: EvaluatableStatement? public var elss: P4Statement?
public init(condition: EvaluatableExpression, withThen thenn: EvaluatableStatement) { public init(condition: P4Expression, withThen thenn: P4Statement) {
self.condition = condition self.condition = condition
self.thenn = thenn self.thenn = thenn
self.elss = .none self.elss = .none
} }
public init( public init(
condition: EvaluatableExpression, withThen thenn: EvaluatableStatement, condition: P4Expression, withThen thenn: P4Statement,
andElse elss: EvaluatableStatement andElse elss: P4Statement
) { ) {
self.condition = condition self.condition = condition
self.thenn = thenn self.thenn = thenn
@@ -50,18 +50,18 @@ public struct ConditionalStatement {
} }
public struct BlockStatement { public struct BlockStatement {
public var statements: [EvaluatableStatement] public var statements: [P4Statement]
public init(_ statements: [EvaluatableStatement]) { public init(_ statements: [P4Statement]) {
self.statements = statements self.statements = statements
} }
} }
public struct ReturnStatement { public struct ReturnStatement {
public let value: EvaluatableExpression public let value: P4Expression
public init(_ value: EvaluatableExpression) { public init(_ value: P4Expression) {
self.value = value self.value = value
} }
} }
+1 -1
View File
@@ -58,7 +58,7 @@ public func Call<T>(
param_direction == Direction.InOut || param_direction == Direction.Out param_direction == Direction.InOut || param_direction == Direction.Out
{ {
// Let's make sure that it is an evaluatable l value! // Let's make sure that it is an evaluatable l value!
guard let arg_lvalue = argument.argument as? EvaluatableLValueExpression else { guard let arg_lvalue = argument.argument as? P4LValueExpression else {
return ( return (
.Error(Error(withMessage: "(in)out parameter argument is not lvalue")), .Error(Error(withMessage: "(in)out parameter argument is not lvalue")),
updated_execution.exit_scope() updated_execution.exit_scope()
+6 -2
View File
@@ -91,10 +91,14 @@ extension Control: LibraryCallable {
} }
} }
extension Action: EvaluatableStatement { extension Action: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate( public func evaluate(
execution: Common.ProgramExecution execution: Common.ProgramExecution
) -> (Common.ControlFlow, Common.ProgramExecution) { ) -> (ControlFlow, Common.ProgramExecution) {
if let body = self.body { if let body = self.body {
return body.evaluate(execution: execution) return body.evaluate(execution: execution)
} }
+135 -109
View File
@@ -22,88 +22,11 @@ extension SelectCaseExpression: EvaluatableExpression {
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
return (execution.scopes.lookup(identifier: next_state_identifier), execution) return (execution.scopes.lookup(identifier: next_state_identifier), execution)
} }
public func type() -> P4QualifiedType { public func type() -> P4QualifiedType {
return P4QualifiedType(AnyParserState) return P4QualifiedType(AnyParserState)
} }
} public func effect(context: CompilerContext) -> CompilerContext {
return context
extension SelectExpression: EvaluatableExpression {
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
switch execution.evaluator.EvaluateExpression(self.selector, inExecution: execution) {
case (.Ok(let selector_value), let updated_execution):
for sce in self.case_expressions {
if case (.Ok(let kse), let updated_execution) = updated_execution.evaluator
.EvaluateExpression(
sce.key, inExecution: updated_execution),
kse.eq(selector_value)
{
//let result = sce.evaluate(execution: updated_execution)
let result = updated_execution.evaluator.EvaluateExpression(
sce, inExecution: updated_execution)
return result
}
}
return (.Error(Error(withMessage: "No key matched the selector")), updated_execution)
case (.Error(let e), let updated_execution): return (.Error(e), updated_execution)
}
}
public func type() -> P4QualifiedType {
return P4QualifiedType(AnyParserState)
}
}
// Variables are evaluatable because they can be looked up by identifiers.
extension TypedIdentifier: EvaluatableExpression {
public func type() -> P4QualifiedType {
return self.type
}
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
return (execution.scopes.lookup(identifier: self), execution)
}
}
// Variables are evaluatable because they can be looked up by identifiers.
extension TypedIdentifier: EvaluatableLValueExpression {
public func set(
to: P4Value, inScopes scopes: Common.VarValueScopes,
duringExecution execution: ProgramExecution
) -> Common.Result<(Common.VarValueScopes, P4Value)> {
if case .Error(let e) = scopes.lookup(identifier: self) {
return .Error(e)
}
return .Ok((scopes.set(identifier: self, withValue: to), to))
}
public func check(
to: any Common.EvaluatableExpression, inScopes scopes: Common.StaticVarValueScopes
) -> Result<()> {
guard case .Ok(let type) = scopes.lookup(identifier: self) else {
return .Error(Error(withMessage: "Cannot assign to identifier not in scope"))
}
return switch type.0.assignableFromType(to.type()) {
case TypeCheckResults.IncompatibleTypes:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) with type \(type.0)"))
case TypeCheckResults.ReadOnly:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) that is read only"))
case TypeCheckResults.WrongDirection:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) that is in parameter")
)
case TypeCheckResults.Ok: .Ok(())
}
} }
} }
@@ -186,7 +109,7 @@ public func binary_divide_operator_evaluator(left: P4Value, right: P4Value) -> P
} }
// swift-format-ignore // swift-format-ignore
public typealias BinaryOperatorChecker = (EvaluatableExpression, EvaluatableExpression) -> Result<()> public typealias BinaryOperatorChecker = (EvaluatableExpression, P4Expression) -> Result<()>
public func binary_and_or_operator_checker( public func binary_and_or_operator_checker(
left: EvaluatableExpression, right: EvaluatableExpression left: EvaluatableExpression, right: EvaluatableExpression
@@ -211,6 +134,10 @@ public func binary_int_math_operator_checker(
} }
extension BinaryOperatorExpression: EvaluatableExpression { extension BinaryOperatorExpression: EvaluatableExpression {
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
let updated_execution = execution let updated_execution = execution
//let maybe_evaluated_left = self.left.evaluate(execution: updated_execution) //let maybe_evaluated_left = self.left.evaluate(execution: updated_execution)
@@ -235,7 +162,11 @@ extension BinaryOperatorExpression: EvaluatableExpression {
} }
} }
extension ArrayAccessExpression: EvaluatableExpression { extension ArrayAccessExpression: EvaluatableExpression, EvaluatableLValueExpression {
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
let updated_execution = execution let updated_execution = execution
//let maybe_name = self.name.evaluate(execution: updated_execution) //let maybe_name = self.name.evaluate(execution: updated_execution)
@@ -267,9 +198,7 @@ extension ArrayAccessExpression: EvaluatableExpression {
public func type() -> P4QualifiedType { public func type() -> P4QualifiedType {
return self.type.value_type() return self.type.value_type()
} }
}
extension ArrayAccessExpression: EvaluatableLValueExpression {
public func set( public func set(
to: P4Value, inScopes scopes: Common.VarValueScopes, to: P4Value, inScopes scopes: Common.VarValueScopes,
duringExecution execution: ProgramExecution duringExecution execution: ProgramExecution
@@ -352,35 +281,13 @@ extension ArrayAccessExpression: EvaluatableLValueExpression {
} }
} }
extension FieldAccessExpression: EvaluatableExpression { extension FieldAccessExpression: EvaluatableExpression, EvaluatableLValueExpression {
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
let updated_execution = execution
//let maybe_struct = self.strct.evaluate(execution: updated_execution)
let maybe_struct = updated_execution.evaluator.EvaluateExpression(
self.strct, inExecution: updated_execution)
guard case (.Ok(let strct), let updated_execution) = maybe_struct else {
return maybe_struct
}
guard let struct_strct = strct.dataValue() as? P4StructValue else {
return (.Error(Error(withMessage: "\(strct) does not identify a struct")), updated_execution)
}
/// TODO: Create a default value?
guard let value = struct_strct.get(field: self.field) else {
return (.Error(Error(withMessage: "Missing value")), updated_execution)
}
return (.Ok(value), updated_execution)
}
public func type() -> P4QualifiedType { public func type() -> P4QualifiedType {
return self.field.type return self.field.type
} }
} public func effect(context: CompilerContext) -> CompilerContext {
return context
extension FieldAccessExpression: EvaluatableLValueExpression { }
public func set( public func set(
to: P4Value, inScopes scopes: Common.VarValueScopes, to: P4Value, inScopes scopes: Common.VarValueScopes,
duringExecution execution: ProgramExecution duringExecution execution: ProgramExecution
@@ -459,9 +366,33 @@ extension FieldAccessExpression: EvaluatableLValueExpression {
default: .Error(Error(withMessage: "Cannot assign to field \(self.field) of \(self.strct)")) default: .Error(Error(withMessage: "Cannot assign to field \(self.field) of \(self.strct)"))
} }
} }
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
let updated_execution = execution
//let maybe_struct = self.strct.evaluate(execution: updated_execution)
let maybe_struct = updated_execution.evaluator.EvaluateExpression(
self.strct, inExecution: updated_execution)
guard case (.Ok(let strct), let updated_execution) = maybe_struct else {
return maybe_struct
}
guard let struct_strct = strct.dataValue() as? P4StructValue else {
return (.Error(Error(withMessage: "\(strct) does not identify a struct")), updated_execution)
}
/// TODO: Create a default value?
guard let value = struct_strct.get(field: self.field) else {
return (.Error(Error(withMessage: "Missing value")), updated_execution)
}
return (.Ok(value), updated_execution)
}
} }
extension KeysetExpression: EvaluatableExpression { extension KeysetExpression: EvaluatableExpression {
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
//return self.key.evaluate(execution: execution) //return self.key.evaluate(execution: execution)
return execution.evaluator.EvaluateExpression(self.key, inExecution: execution) return execution.evaluator.EvaluateExpression(self.key, inExecution: execution)
@@ -473,6 +404,10 @@ extension KeysetExpression: EvaluatableExpression {
} }
extension FunctionCall: EvaluatableExpression { extension FunctionCall: EvaluatableExpression {
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
public func evaluate( public func evaluate(
execution: Common.ProgramExecution execution: Common.ProgramExecution
) -> (Common.Result<P4Value>, ProgramExecution) { ) -> (Common.Result<P4Value>, ProgramExecution) {
@@ -533,4 +468,95 @@ extension P4Value: EvaluatableExpression {
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
return (.Ok(self), execution) return (.Ok(self), execution)
} }
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
}
extension SelectExpression: EvaluatableExpression {
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
switch execution.evaluator.EvaluateExpression(self.selector, inExecution: execution) {
case (.Ok(let selector_value), let updated_execution):
for sce in self.case_expressions {
if case (.Ok(let kse), let updated_execution) = updated_execution.evaluator
.EvaluateExpression(
sce.key, inExecution: updated_execution),
kse.eq(selector_value)
{
//let result = sce.evaluate(execution: updated_execution)
let result = updated_execution.evaluator.EvaluateExpression(
sce, inExecution: updated_execution)
return result
}
}
return (.Error(Error(withMessage: "No key matched the selector")), updated_execution)
case (.Error(let e), let updated_execution): return (.Error(e), updated_execution)
}
}
public func type() -> P4QualifiedType {
return P4QualifiedType(AnyParserState)
}
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
}
// Variables are evaluatable because they can be looked up by identifiers.
extension TypedIdentifier: EvaluatableExpression, EvaluatableLValueExpression {
public func evaluate(
execution: Common.ProgramExecution
) -> (Common.Result<Common.P4Value>, Common.ProgramExecution) {
return (execution.scopes.lookup(identifier: self), execution)
}
public func set(
to: P4Value, inScopes scopes: Common.VarValueScopes,
duringExecution execution: ProgramExecution
) -> Common.Result<(Common.VarValueScopes, P4Value)> {
if case .Error(let e) = scopes.lookup(identifier: self) {
return .Error(e)
}
return .Ok((scopes.set(identifier: self, withValue: to), to))
}
public func type() -> P4QualifiedType {
return self.type
}
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
// Variables are evaluatable because they can be looked up by identifiers.
public func check(
to: P4Expression, inScopes scopes: Common.StaticVarValueScopes
) -> Result<()> {
guard case .Ok(let type) = scopes.lookup(identifier: self) else {
return .Error(Error(withMessage: "Cannot assign to identifier not in scope"))
}
return switch type.0.assignableFromType(to.type()) {
case TypeCheckResults.IncompatibleTypes:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) with type \(type.0)"))
case TypeCheckResults.ReadOnly:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) that is read only"))
case TypeCheckResults.WrongDirection:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) that is in parameter")
)
case TypeCheckResults.Ok: .Ok(())
}
}
} }
+21 -1
View File
@@ -18,7 +18,11 @@
import Common import Common
import P4Lang import P4Lang
extension ParserAssignmentStatement: EvaluatableStatement { extension ParserAssignmentStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
let updated_execution = execution let updated_execution = execution
//let result = self.value.evaluate(execution: updated_execution) //let result = self.value.evaluate(execution: updated_execution)
@@ -192,3 +196,19 @@ extension ParserValue: LibraryCallable {
} }
} }
} }
extension ParserState: P4Statement {
public func evaluate(
execution: Common.ProgramExecution
) -> (Common.ControlFlow, Common.ProgramExecution) {
return (
ControlFlow.Error,
execution.setError(error: Error(withMessage: "Cannot evaluate unspecialized parser state"))
)
}
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context.update(
newTypes: context.types.declare(identifier: self.getName(), withValue: self))
}
}
+64 -6
View File
@@ -18,7 +18,11 @@
import Common import Common
import P4Lang import P4Lang
extension BlockStatement: EvaluatableStatement { extension BlockStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
return execution.evaluator.ExecuteStatements( return execution.evaluator.ExecuteStatements(
self.statements, inExecution: execution self.statements, inExecution: execution
@@ -38,7 +42,14 @@ extension BlockStatement: EvaluatableStatement {
} }
} }
extension VariableDeclarationStatement: EvaluatableStatement { extension VariableDeclarationStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context.update(
newInstances: context.instances.declare(
identifier: self.identifier, withValue: (self.identifier.type(), .none)))
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
guard guard
//case (.Ok(let initial_value), let execution) = self.initializer.evaluate(execution: execution) //case (.Ok(let initial_value), let execution) = self.initializer.evaluate(execution: execution)
@@ -56,7 +67,11 @@ extension VariableDeclarationStatement: EvaluatableStatement {
} }
} }
extension ConditionalStatement: EvaluatableStatement { extension ConditionalStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
guard guard
//case (.Ok(let evaluated_condition), let execution) = self.condition.evaluate(execution: execution) //case (.Ok(let evaluated_condition), let execution) = self.condition.evaluate(execution: execution)
@@ -105,7 +120,11 @@ extension ConditionalStatement: EvaluatableStatement {
} }
} }
extension ExpressionStatement: EvaluatableStatement { extension ExpressionStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
// Evaluate, there might be side effects! // Evaluate, there might be side effects!
@@ -118,7 +137,12 @@ extension ExpressionStatement: EvaluatableStatement {
} }
} }
extension ReturnStatement: EvaluatableStatement { extension ReturnStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
//return switch self.value.evaluate(execution: execution) { //return switch self.value.evaluate(execution: execution) {
return switch execution.evaluator.EvaluateExpression(self.value, inExecution: execution) { return switch execution.evaluator.EvaluateExpression(self.value, inExecution: execution) {
@@ -128,8 +152,42 @@ extension ReturnStatement: EvaluatableStatement {
} }
} }
extension ApplyStatement: EvaluatableStatement { extension ApplyStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) { public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
return (ControlFlow.Next, execution) return (ControlFlow.Next, execution)
} }
} }
extension Instantiation: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
return (ControlFlow.Next, execution)
}
}
extension Declaration: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
if self.extern {
return context.update(
newExterns: context.externs.declare(
identifier: self.identifier, withValue: self))
}
return context.update(
newTypes: context.types.declare(
identifier: self.identifier, withValue: self.identifier.type().baseType()))
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
//// TODO
return (ControlFlow.Next, execution)
}
}
+14 -1
View File
@@ -95,7 +95,7 @@ import P4Lang
let result = try! #require(p.parse(simple)) let result = try! #require(p.parse(simple))
#expect( #expect(
#RequireErrorResult<(EvaluatableStatement, CompilerContext)>( #RequireErrorResult<ParserAssignmentStatement>(
ErrorWithLocation(sourceLocation: SourceLocation(2, 154), withError: "Did not find assignment statement"), ErrorWithLocation(sourceLocation: SourceLocation(2, 154), withError: "Did not find assignment statement"),
ParserAssignmentStatement.Compile( // Note: Calling ParserAssignmentStatement compilation directly. ParserAssignmentStatement.Compile( // Note: Calling ParserAssignmentStatement compilation directly.
node: result.rootNode!, withContext: CompilerContext()))) node: result.rootNode!, withContext: CompilerContext())))
@@ -182,3 +182,16 @@ import P4Lang
#expect(#RequireOkResult(SpecialCompilers.ProgramCompiler.Compile(simple))) #expect(#RequireOkResult(SpecialCompilers.ProgramCompiler.Compile(simple)))
} }
@Test func test_simple_compiler_with_instantiation() async throws {
let simple_instantiation_program = """
parser MainParser() {
state start {
transition accept;
}
};
MainParser() mp;
"""
#expect(#RequireOkResult(SpecialCompilers.ProgramCompiler.Compile(simple_instantiation_program)))
}
+1 -1
View File
@@ -68,7 +68,7 @@ export default grammar({
// Instantiation // Instantiation
instantiation: $ => seq($.typeRef, '(', optional($.parameter_list), ')', $.identifier), instantiation: $ => seq($.typeRef, $.arguments, $.identifier),
// Declarations // Declarations
declaration: $ => seq(choice($.parserDeclaration, $.parserTypeDeclaration, $.type_declaration, $.function_declaration, $.control_declaration, $.extern_declaration)), declaration: $ => seq(choice($.parserDeclaration, $.parserTypeDeclaration, $.type_declaration, $.function_declaration, $.control_declaration, $.extern_declaration)),