compiler, testing: Build System for Compilation

The compilation code was written as a precursor for implementation
with macros. The updates in this commit make the switch.

There is still plenty to do:

1. Comment Walker.
2. Comment Macros.

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-04-27 08:39:40 -04:00
parent f2bd53ce5f
commit 0f0662709e
12 changed files with 698 additions and 565 deletions
+2 -1
View File
@@ -75,7 +75,8 @@ let package = Package(
), ),
.testTarget( .testTarget(
name: "Tests", name: "Tests",
dependencies: ["P4Compiler", "P4Runtime", "P4Lang", "Macros", "TreeSitterExtensions", "Common"] dependencies: ["P4Compiler", "P4Runtime", "P4Lang", "Macros", "TreeSitterExtensions", "Common"],
swiftSettings: [.enableExperimentalFeature("CodeItemMacros")],
), ),
], ],
) )
+4 -1
View File
@@ -148,5 +148,8 @@ public func Map<T, U>(input: T, block: (T) -> U) -> U {
nodes: N, type: [String], nice_type_names: [String] nodes: N, type: [String], nice_type_names: [String]
) = ) =
#externalMacro(module: "Macros", type: "RequireNodesType") #externalMacro(module: "Macros", type: "RequireNodesType")
@freestanding(codeItem) public macro SkipUnlessNodeType<N, T>(node: N, type: String) = @freestanding(codeItem) public macro SkipUnlessNodeType<N>(node: N, type: String) =
#externalMacro(module: "Macros", type: "SkipUnlessNodeType") #externalMacro(module: "Macros", type: "SkipUnlessNodeType")
@freestanding(codeItem) public macro MustOr<E, N>(result: E, thing: E?, or: N) =
#externalMacro(module: "Macros", type: "MustOr")
+29 -1
View File
@@ -225,10 +225,38 @@ public struct SkipUnlessNodeType: CodeItemMacro {
} }
} }
public struct MustOr: CodeItemMacro {
public static func expansion(
of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext
) throws -> [CodeBlockItemSyntax] {
let arguments = node.arguments.indices
var arg_index = arguments.startIndex
let result = node.arguments[arg_index].expression
arg_index = arguments.index(after: arg_index)
let thing = node.arguments[arg_index].expression
arg_index = arguments.index(after: arg_index)
let or = node.arguments[arg_index].expression
return [
CodeBlockItemSyntax(
"""
if let __thing = \(thing) {
\(result) = __thing
} else {
return \(or)
}
""")
]
}
}
@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, RequireNodesType.self, RequireNodeType.self, SkipUnlessNodeType.self, RequireNodesType.self, MustOr.self,
] ]
} }
+115 -117
View File
@@ -26,9 +26,8 @@ func parameter_list_compiler(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(ParameterList, CompilerContext)> { ) -> Common.Result<(ParameterList, CompilerContext)> {
var currentChildIdx = 0 var walker = Walker(node: node)
var currentChildIdxSafe = 1 var current_node: Node? = .none
var currentChild: Node? = .none
if node.text == ")" { if node.text == ")" {
// There are no parameters! // There are no parameters!
@@ -40,49 +39,45 @@ func parameter_list_compiler(
var parameters: ParameterList = ParameterList([]) var parameters: ParameterList = ParameterList([])
if node.childCount < currentChildIdxSafe { #MustOr(
return Result.Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing parameter list component")) or: Result<(ParameterList, CompilerContext)>.Error(
} ErrorOnNode(
node: node, withError: "Missing parameter list component")))
currentChild = node.child(at: currentChildIdx) if current_node?.nodeType == "parameter_list" {
if currentChild?.nodeType == "parameter_list" { switch parameter_list_compiler(node: current_node!, withContext: context) {
switch parameter_list_compiler(node: currentChild!, 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)
} }
walker.next()
currentChildIdx += 1
currentChildIdxSafe += 1
} }
// We may have moved nodes, check/reset currentChild. #MustOr(
if node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return Result.Error( or: Result<(ParameterList, CompilerContext)>.Error(
ErrorOnNode(node: node, withError: "Missing parameter list component")) ErrorOnNode(
} node: node, withError: "Missing parameter list component")))
currentChild = node.child(at: currentChildIdx)
// If this is a ')', we are done. // If this is a ')', we are done.
if currentChild?.text == ")" { if current_node?.text == ")" {
return Result.Ok((parameters, context)) return Result.Ok((parameters, context))
} }
// If this is a comma, we skip it! // If this is a comma, we skip it!
if currentChild?.text == "," { if current_node?.text == "," {
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1
} }
if node.childCount < currentChildIdxSafe { #MustOr(
return Result.Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing parameter list component")) or: Result<(ParameterList, CompilerContext)>.Error(
} ErrorOnNode(
currentChild = node.child(at: currentChildIdx) node: node, withError: "Missing parameter list component")))
// Otherwise, there should be one parameter left! // Otherwise, there should be one parameter left!
switch Parameter.Compile(node: currentChild!, withContext: context) { switch Parameter.Compile(node: current_node!, withContext: context) {
case .Ok(let (parsed_parameter, updated_context)): case .Ok(let (parsed_parameter, updated_context)):
return Result.Ok((parameters.addParameter(parsed_parameter), updated_context)) return Result.Ok((parameters.addParameter(parsed_parameter), updated_context))
case .Error(let e): return Result.Error(e) case .Error(let e): return Result.Error(e)
@@ -99,24 +94,24 @@ extension ParameterList: Compilable {
#RequireNodeType<Node, (ParameterList, CompilerContext)>( #RequireNodeType<Node, (ParameterList, CompilerContext)>(
node: parameter_node, type: "parameters", nice_type_name: "Parameters") node: parameter_node, type: "parameters", nice_type_name: "Parameters")
var currentChildIdx = 0 var walker = Walker(node: parameter_node)
var currentChildIdxSafe = 1
// Let's eat the '(' before we start ... var current_node: Node? = .none
if parameter_node.childCount < currentChildIdxSafe {
return .Error(
ErrorOnNode(node: parameter_node, withError: "Missing '(' in parameter list component"))
}
currentChildIdx += 1 #MustOr(
currentChildIdxSafe += 1 result: current_node, thing: walker.getNext(),
if parameter_node.childCount < currentChildIdxSafe { or: Result<(ParameterList, CompilerContext)>.Error(
return .Error( ErrorOnNode(
ErrorOnNode(node: parameter_node, withError: "Missing parameter list component")) node: node, withError: "Missing '(' in parameter list component")))
}
let currentChild = parameter_node.child(at: currentChildIdx)
return parameter_list_compiler(node: currentChild!, withContext: context) walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error(
ErrorOnNode(
node: node, withError: "Missing parameter list component")))
return parameter_list_compiler(node: current_node!, withContext: context)
} }
} }
@@ -153,74 +148,80 @@ extension Parameter: Compilable {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( #RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
node: node, type: "parameter", nice_type_name: "parameter") node: node, type: "parameter", nice_type_name: "parameter")
var currentChildIdx = 0 var walker = Walker(node: node)
var currentChildIdxSafe = 1 var current_node: Node? = .none
var currentChild: Node? = .none
if node.childCount < currentChildIdxSafe { #MustOr(
return .Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing parameter declaration component")) or: Result<(Parameter, CompilerContext)>.Error(
} ErrorOnNode(
node: node, withError: "Missing parameter declaration component")))
currentChild = node.child(at: currentChildIdx)
// Annotation? // Annotation?
if currentChild!.nodeType == "annotations" { if current_node!.nodeType == "annotations" {
return .Error( return .Error(
ErrorOnNode( ErrorOnNode(
node: currentChild!, node: current_node!,
withError: "Annotations in parameter declarations are not yet handled")) withError: "Annotations in parameter declarations are not yet handled"))
// Will increment indexes here. // Will increment indexes here.
} }
currentChild = node.child(at: currentChildIdx)
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Parameter, CompilerContext)>.Error(
ErrorOnNode(
node: node, withError: "Missing parameter declaration component")))
var direction: Direction? = .none var direction: Direction? = .none
// Direction? // Direction?
if currentChild!.nodeType == "direction" { if current_node!.nodeType == "direction" {
let maybe_parsed_direction = Direction.Compile(node: currentChild!, 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
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1
} }
currentChild = node.child(at: currentChildIdx)
if currentChild!.nodeType != "typeRef" { #MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Parameter, CompilerContext)>.Error(
ErrorOnNode(
node: node, withError: "Missing parameter declaration component")))
if current_node!.nodeType != "typeRef" {
return Result.Error( return Result.Error(
ErrorOnNode( ErrorOnNode(
node: node, withError: "Did not find type name for parameter declaration")) node: node, withError: "Did not find type name for parameter declaration"))
} }
guard guard
case .Ok(let parameter_type) = Types.CompileType(type: currentChild!, withContext: context) case .Ok(let parameter_type) = Types.CompileType(type: current_node!, withContext: context)
else { else {
return Result.Error( return Result.Error(
Error(withMessage: "Could not parse a P4 type from \(currentChild!.text!)")) Error(withMessage: "Could not parse a P4 type from \(current_node!.text!)"))
} }
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 #MustOr(
if node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return .Error( or: Result<(Parameter, CompilerContext)>.Error(
ErrorOnNode(node: node, withError: "Missing parameter declaration component")) ErrorOnNode(
} node: node, withError: "Missing parameter declaration component")))
currentChild = node.child(at: currentChildIdx) if current_node!.nodeType != "identifier" {
if currentChild!.nodeType != "identifier" {
return Result.Error( return Result.Error(
ErrorOnNode( ErrorOnNode(
node: node, withError: "Did not find identifier for parameter statement")) node: node, withError: "Did not find identifier for parameter statement"))
} }
guard guard
case .Ok(let parameter_name) = Identifier.Compile(node: currentChild!, withContext: context) case .Ok(let parameter_name) = Identifier.Compile(node: current_node!, withContext: context)
else { else {
return Result.Error( return Result.Error(
Error(withMessage: "Could not parse a parameter name from \(currentChild!.text!)")) Error(withMessage: "Could not parse a parameter name from \(current_node!.text!)"))
} }
return Result.Ok( return Result.Ok(
@@ -239,9 +240,8 @@ func argument_list_compiler(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(ArgumentList, CompilerContext)> { ) -> Common.Result<(ArgumentList, CompilerContext)> {
var currentChildIdx = 0 var walker = Walker(node: node)
var currentChildIdxSafe = 1 var current_node: Node? = .none
var currentChild: Node? = .none
if node.text == ")" { if node.text == ")" {
// There are no arguments! // There are no arguments!
@@ -253,49 +253,47 @@ func argument_list_compiler(
var arguments: ArgumentList = ArgumentList([]) var arguments: ArgumentList = ArgumentList([])
if node.childCount < currentChildIdxSafe { #MustOr(
return Result.Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing argument list component")) or: Result<(ArgumentList, CompilerContext)>.Error(
} ErrorOnNode(
node: node, withError: "Missing argument list component")))
currentChild = node.child(at: currentChildIdx) if current_node?.nodeType == "argument_list" {
if currentChild?.nodeType == "argument_list" { switch argument_list_compiler(node: current_node!, withContext: context) {
switch argument_list_compiler(node: currentChild!, 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)
} }
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1
} }
// We may have moved nodes, check/reset currentChild. // We may have moved nodes, check/reset current_node.
if node.childCount < currentChildIdxSafe { #MustOr(
return Result.Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing argument list component")) or: Result<(ArgumentList, CompilerContext)>.Error(
} ErrorOnNode(
currentChild = node.child(at: currentChildIdx) node: node, withError: "Missing argument list component")))
// If this is a ')', we are done. // If this is a ')', we are done.
if currentChild?.text == ")" { if current_node?.text == ")" {
return Result.Ok((arguments, context)) return Result.Ok((arguments, context))
} }
// If this is a comma, we skip it! // If this is a comma, we skip it!
if currentChild?.text == "," { if current_node?.text == "," {
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1
} }
if node.childCount < currentChildIdxSafe { #MustOr(
return Result.Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing argument list component")) or: Result<(ArgumentList, CompilerContext)>.Error(
} ErrorOnNode(
currentChild = node.child(at: currentChildIdx) node: node, withError: "Missing argument list component")))
// Otherwise, there should be one argument left! // Otherwise, there should be one argument left!
switch Argument.Compile(node: currentChild!, withContext: context) { switch Argument.Compile(node: current_node!, withContext: context) {
case .Ok(let (ce, updated_context)): case .Ok(let (ce, updated_context)):
return Result.Ok( return Result.Ok(
(arguments.addArgument(Argument(ce, atIndex: arguments.count() + 1)), updated_context)) (arguments.addArgument(Argument(ce, atIndex: arguments.count() + 1)), updated_context))
@@ -313,24 +311,24 @@ extension ArgumentList: Compilable {
#RequireNodeType<Node, (ArgumentList, CompilerContext)>( #RequireNodeType<Node, (ArgumentList, CompilerContext)>(
node: argument_node, type: "arguments", nice_type_name: "arguments") node: argument_node, type: "arguments", nice_type_name: "arguments")
var currentChildIdx = 0 var walker = Walker(node: argument_node)
var currentChildIdxSafe = 1 var current_node: Node? = .none
// Let's eat the '(' before we start ... #MustOr(
if argument_node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return .Error( or: Result<(ArgumentList, CompilerContext)>.Error(
ErrorOnNode(node: argument_node, withError: "Missing '(' in argument list component")) ErrorOnNode(
} node: node, withError: "Missing '(' in argument list component")))
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1
if argument_node.childCount < currentChildIdxSafe {
return .Error(
ErrorOnNode(node: argument_node, withError: "Missing argument list component"))
}
let currentChild = argument_node.child(at: currentChildIdx)
return argument_list_compiler(node: currentChild!, withContext: context) #MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error(
ErrorOnNode(
node: node, withError: "Missing argument list component")))
return argument_list_compiler(node: current_node!, withContext: context)
} }
} }
+218 -256
View File
@@ -51,46 +51,42 @@ extension FunctionDeclaration: CompilableDeclaration {
node: function_declaration_node, type: "function_declaration", node: function_declaration_node, type: "function_declaration",
nice_type_name: "Function Declaration") nice_type_name: "Function Declaration")
var walker = Walker(node: function_declaration_node)
var context = context var context = context
var currentChildIdx = 0
var currentChildIdxSafe = 1
var currentChild: Node? = .none
if function_declaration_node.childCount < currentChildIdxSafe {
return Result.Error(
ErrorOnNode(
node: function_declaration_node, withError: "Missing function declaration component"))
}
currentChild = function_declaration_node.child(at: currentChildIdx)
let maybe_function_type = Types.CompileType(type: currentChild!, withContext: context) var current_node: Node? = .none
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode(
node: function_declaration_node, withError: "Missing function declaration component")))
let maybe_function_type = Types.CompileType(type: current_node!, withContext: context)
guard case .Ok(let function_type) = maybe_function_type else { guard case .Ok(let function_type) = maybe_function_type else {
return .Error(maybe_function_type.error()!) return .Error(maybe_function_type.error()!)
} }
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 #MustOr(
if function_declaration_node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return Result.Error( or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode( ErrorOnNode(
node: function_declaration_node, withError: "Missing function declaration component")) node: function_declaration_node, withError: "Missing function declaration component")))
}
currentChild = function_declaration_node.child(at: currentChildIdx)
let maybe_function_name = Identifier.Compile(node: currentChild!, withContext: context) let maybe_function_name = Identifier.Compile(node: current_node!, withContext: context)
guard case .Ok(let function_name) = maybe_function_name else { guard case .Ok(let function_name) = maybe_function_name else {
return .Error(maybe_function_name.error()!) return .Error(maybe_function_name.error()!)
} }
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 #MustOr(
if function_declaration_node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return Result.Error( or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode( ErrorOnNode(
node: function_declaration_node, withError: "Missing function declaration component")) node: function_declaration_node, withError: "Missing function declaration component")))
}
currentChild = function_declaration_node.child(at: currentChildIdx)
let maybe_function_parameters = ParameterList.Compile(node: currentChild!, 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, let updated_context)) = maybe_function_parameters
else { else {
return .Error(maybe_function_parameters.error()!) return .Error(maybe_function_parameters.error()!)
@@ -99,11 +95,8 @@ extension FunctionDeclaration: CompilableDeclaration {
var function_body: BlockStatement? = .none var function_body: BlockStatement? = .none
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 if let body = walker.getNext() {
if currentChildIdxSafe <= function_declaration_node.childCount {
currentChild = function_declaration_node.child(at: currentChildIdx)
// Add the parameters into scope. // Add the parameters into scope.
var function_scope = context.instances.enter() var function_scope = context.instances.enter()
for parameter in function_parameters.parameters { for parameter in function_parameters.parameters {
@@ -112,7 +105,7 @@ extension FunctionDeclaration: CompilableDeclaration {
} }
let maybe_function_body = BlockStatement.Compile( let maybe_function_body = BlockStatement.Compile(
node: currentChild!, node: body,
withContext: context.update(newInstances: function_scope).update( withContext: context.update(newInstances: function_scope).update(
newExpectation: function_type)) newExpectation: function_type))
@@ -160,59 +153,38 @@ extension P4Struct: CompilableDeclaration {
static public func Compile( static public func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(Declaration, CompilerContext)?> { ) -> Result<(Declaration, CompilerContext)?> {
let struct_declaration_node = node.child(at: 0)! let struct_declaration_node = node.child(at: 0)!
var currentChildIdx = 0 var walker = Walker(node: struct_declaration_node)
var currentChildIdxSafe = 1 var currentNode: Node? = .none
var currentChild: Node? = .none #SkipUnlessNodeType(node: struct_declaration_node, type: "struct_declaration")
guard let node_type = struct_declaration_node.nodeType,
node_type == "struct_declaration"
else {
return Result.Error(
ErrorOnNode(node: struct_declaration_node, withError: "Did not find a struct declaration"))
}
if struct_declaration_node.childCount < currentChildIdxSafe {
return Result.Error(
ErrorOnNode(
node: struct_declaration_node, withError: "Missing elements in struct declaration"))
}
// Skip the keyword struct // Skip the keyword struct
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 #MustOr(
if struct_declaration_node.childCount < currentChildIdxSafe { result: currentNode, thing: walker.getNext(),
return Result.Error( or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode( ErrorOnNode(
node: struct_declaration_node, withError: "Missing elements in struct declaration")) node: struct_declaration_node, withError: "Missing function declaration component")))
}
// The name of the struct type. // The name of the struct type.
currentChild = struct_declaration_node.child(at: currentChildIdx)
let maybe_struct_identifier = Identifier.Compile( let maybe_struct_identifier = Identifier.Compile(
node: currentChild!, withContext: context) node: currentNode!, withContext: context)
guard case Result.Ok(let struct_identifier) = maybe_struct_identifier else { guard case Result.Ok(let struct_identifier) = maybe_struct_identifier else {
return Result.Error(maybe_struct_identifier.error()!) return Result.Error(maybe_struct_identifier.error()!)
} }
walker.next()
currentChildIdx += 1
currentChildIdxSafe += 1
// Skip the '{' // Skip the '{'
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 #MustOr(
if struct_declaration_node.childCount < currentChildIdxSafe { result: currentNode, thing: walker.getNext(),
return Result.Error( or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode( ErrorOnNode(
node: struct_declaration_node, withError: "Missing element of struct declaration")) node: struct_declaration_node, withError: "Missing function declaration component")))
}
currentChild = struct_declaration_node.child(at: currentChildIdx)
// If there are no fields, it will be a "}" // If there are no fields, it will be a "}"
if currentChild!.nodeType == "}" { if currentNode!.nodeType == "}" {
let struc = Declaration( let struc = Declaration(
TypedIdentifier( TypedIdentifier(
id: struct_identifier, id: struct_identifier,
@@ -232,8 +204,8 @@ extension P4Struct: CompilableDeclaration {
var current_context = context var current_context = context
var parsed_fields: [P4StructFieldIdentifier] = Array() var parsed_fields: [P4StructFieldIdentifier] = Array()
if currentChild!.nodeType == "struct_declaration_fields" { if currentNode!.nodeType == "struct_declaration_fields" {
currentChild!.enumerateNamedChildren { declaration_field in currentNode!.enumerateNamedChildren { declaration_field in
switch VariableDeclarationStatement.Compile( switch VariableDeclarationStatement.Compile(
node: declaration_field, withContext: current_context) node: declaration_field, withContext: current_context)
{ {
@@ -281,75 +253,67 @@ extension P4Lang.Parser: CompilableDeclaration {
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(Declaration, CompilerContext)?> { ) -> Result<(Declaration, CompilerContext)?> {
let parser_node = node let parser_node = node
#SkipUnlessNodeType<Node, (P4DataType, CompilerContext)?>( #SkipUnlessNodeType<Node>(node: parser_node, type: "parserDeclaration")
node: parser_node, type: "parserDeclaration")
var current_context = context var current_context = context
var currentChildIdx = 0 var walker = Walker(node: parser_node)
var currentChildIdxSafe = 1 var current_node: Node? = .none
var currentChild: Node? = .none
if parser_node.childCount < currentChildIdxSafe { #MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode(
node: parser_node, withError: "Missing elements of parser declaration")))
if current_node!.nodeType != "parserType" {
return .Error( return .Error(
ErrorOnNode(node: parser_node, withError: "Missing elements of parser declaration")) ErrorOnNode(node: current_node!, withError: "Missing type for parser declaration"))
} }
currentChild = parser_node.child(at: currentChildIdx) let type_node = current_node
if currentChild!.nodeType != "parserType" {
return .Error(
ErrorOnNode(node: currentChild!, withError: "Missing type for parser declaration"))
}
let type_node = currentChild
var parser_name: Common.Identifier? = .none var parser_name: Common.Identifier? = .none
// TODO: Handle parser parameter lists. // TODO: Handle parser parameter lists.
var parameter_list = ParameterList() var parameter_list = ParameterList()
do { do {
// Parse the parser type (type_node) var type_node_walker = Walker(node: type_node!)
var currentChildIdx = 0 var type_node_child: Node? = .none
var currentChildIdxSafe = 1
if type_node!.childCount < currentChildIdxSafe { #MustOr(
result: type_node_child, thing: type_node_walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode(
node: parser_node, withError: "Missing elements of parser type in parser declaration")))
if type_node_child!.nodeType == "annotations" {
return .Error( return .Error(
ErrorOnNode( ErrorOnNode(
node: parser_node, withError: "Missing elements of parser type in parser declaration")) node: type_node_child!, withError: "Annotations in parser type are not yet handled."))
}
var currentChild = type_node!.child(at: currentChildIdx)
if currentChild!.nodeType == "annotations" {
return .Error(
ErrorOnNode(
node: currentChild!, withError: "Annotations in parser type are not yet handled."))
// Will increment indexes here. // Will increment indexes here.
} }
// Skip the parser keyword type_node_walker.next()
currentChildIdx += 1 #MustOr(
currentChildIdxSafe += 1 result: type_node_child, thing: type_node_walker.getNext(),
if type_node!.childCount < currentChildIdxSafe { or: Result<(Declaration, CompilerContext)?>.Error(
return .Error( ErrorOnNode(
ErrorOnNode(node: type_node!, withError: "Missing name in parser type declaration")) node: type_node_child!, withError: "Missing name in parser type declaration")))
}
currentChild = type_node?.child(at: currentChildIdx)
switch Identifier.Compile(node: currentChild!, withContext: current_context) { switch Identifier.Compile(node: type_node_child!, withContext: current_context) {
case .Ok(let id): parser_name = id case .Ok(let id): parser_name = id
case .Error(let e): case .Error(let e):
return .Error(e) return .Error(e)
} }
currentChildIdx += 1 type_node_walker.next()
currentChildIdxSafe += 1 #MustOr(
if type_node!.childCount < currentChildIdxSafe { result: type_node_child, thing: type_node_walker.getNext(),
return .Error( or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode(node: type_node!, withError: "Missing parser parameters")) ErrorOnNode(
} node: type_node_child!, withError: "Missing parser parameters")))
currentChild = type_node?.child(at: currentChildIdx) switch ParameterList.Compile(node: type_node_child!, withContext: current_context) {
switch ParameterList.Compile(node: currentChild!, withContext: current_context) {
case .Ok(let (parsed_parameter_list, updated_context)): case .Ok(let (parsed_parameter_list, updated_context)):
parameter_list = parsed_parameter_list parameter_list = parsed_parameter_list
current_context = updated_context current_context = updated_context
@@ -365,37 +329,38 @@ extension P4Lang.Parser: CompilableDeclaration {
identifier: parameter.name, withValue: parameter.type)) identifier: parameter.name, withValue: parameter.type))
} }
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 #MustOr(
if parser_node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return .Error( or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode(node: parser_node, withError: "Missing parser declaration component")) ErrorOnNode(
} node: parser_node, withError: "Missing parser declaration component")))
// Skip the '{' walker.next()
currentChildIdx += 1 #MustOr(
currentChildIdxSafe += 1 result: current_node, thing: walker.getNext(),
if parser_node.childCount < currentChildIdxSafe { or: Result<(Declaration, CompilerContext)?>.Error(
return .Error((Error(withMessage: "Missing body of parser declaration"))) ErrorOnNode(
} node: parser_node, withError: "Missing elements of parser declaration")))
currentChild = parser_node.child(at: currentChildIdx)
if currentChild!.nodeType == "parserLocalElements" { if current_node!.nodeType == "parserLocalElements" {
return .Error( return .Error(
ErrorOnNode(node: currentChild!, withError: "Parser Local Elements are not yet handled.")) ErrorOnNode(node: current_node!, withError: "Parser Local Elements are not yet handled."))
// Will increment indexes here. // Will increment indexes here.
} }
if parser_node.childCount < currentChildIdxSafe { #MustOr(
return .Error((Error(withMessage: "Missing body of parser declaration"))) result: current_node, thing: walker.getNext(),
} or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode(
node: parser_node, withError: "Missing body of parser declaration")))
if currentChild!.nodeType != "parserStates" { if current_node!.nodeType != "parserStates" {
return .Error(Error(withMessage: "Missing parser states in parser declaration")) return .Error(Error(withMessage: "Missing parser states in parser declaration"))
} }
switch Parser.Compile( switch Parser.Compile(
withName: parser_name!, withParameters: parameter_list, node: currentChild!, withName: parser_name!, withParameters: parameter_list, node: current_node!,
withContext: current_context) withContext: current_context)
{ {
case Result.Ok((let parser, let updated_context)): case Result.Ok((let parser, let updated_context)):
@@ -421,47 +386,37 @@ extension Control: CompilableDeclaration {
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Declaration, CompilerContext)?> { ) -> Common.Result<(Declaration, CompilerContext)?> {
#SkipUnlessNodeType<Node, (P4DataType, CompilerContext)?>( #SkipUnlessNodeType<Node>(node: node, type: "control_declaration")
node: node, type: "control_declaration")
var currentChildIdx = 0 var walker = Walker(node: node)
var currentChildIdxSafe = 1 var current_node: Node? = .none
var currentChild: Node? = .none
var local_context = context var local_context = context
// Skip control keyword walker.next()
if node.childCount < currentChildIdxSafe { #MustOr(
return .Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing control declaration component")) or: Result<(Declaration, CompilerContext)?>.Error(
} ErrorOnNode(
node: node, withError: "Missing control declaration component")))
currentChildIdx += 1
currentChildIdxSafe += 1
if node.childCount < currentChildIdxSafe {
return .Error(
ErrorOnNode(node: node, withError: "Missing control declaration component"))
}
currentChild = node.child(at: currentChildIdx)
guard guard
case .Ok(let control_name) = Identifier.Compile( case .Ok(let control_name) = Identifier.Compile(
node: currentChild!, withContext: local_context) node: current_node!, withContext: local_context)
else { else {
return Result.Error( return Result.Error(
Error(withMessage: "Could not parse a parameter name from \(currentChild!.text!)")) Error(withMessage: "Could not parse a parameter name from \(current_node!.text!)"))
} }
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 #MustOr(
if node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return .Error( or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode(node: node, withError: "Missing control declaration component")) ErrorOnNode(
} node: node, withError: "Missing control declaration component")))
currentChild = node.child(at: currentChildIdx)
let maybe_control_parameters = ParameterList.Compile( let maybe_control_parameters = ParameterList.Compile(
node: currentChild!, 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, let updated_context)) = maybe_control_parameters
else { else {
return .Error(maybe_control_parameters.error()!) return .Error(maybe_control_parameters.error()!)
@@ -476,26 +431,26 @@ extension Control: CompilableDeclaration {
} }
local_context = local_context.update(newInstances: control_scope) local_context = local_context.update(newInstances: control_scope)
walker.next()
// Skip the '{' // Skip the '{'
currentChildIdx += 2 walker.next()
currentChildIdxSafe += 2 #MustOr(
if node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return .Error( or: Result<(Declaration, CompilerContext)?>.Error(
ErrorOnNode(node: node, withError: "Missing control declaration component")) ErrorOnNode(
} node: node, withError: "Missing control declaration component")))
var actions: [Action] = Array() var actions: [Action] = Array()
var tables: [Table] = Array() var tables: [Table] = Array()
var apply: ApplyStatement? = .none var apply: ApplyStatement? = .none
// Because the final child // Because the final child
// is the '}'. // is the '}'.
// \/\/ // \/\/
for currentChildIdx in currentChildIdx..<(node.childCount - 1) { let body_parse_results = walker.overUntil(n: node.childCount - 1) { current_node in
let currentChild = node.child(at: currentChildIdx)! if current_node.nodeType == "action_declaration" {
if currentChild.nodeType == "action_declaration" {
let maybe_action_declaration = Action.Compile( let maybe_action_declaration = Action.Compile(
node: currentChild, 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, let updated_context)) = maybe_action_declaration
else { else {
@@ -503,9 +458,9 @@ extension Control: CompilableDeclaration {
} }
actions.append(action_declaration) actions.append(action_declaration)
local_context = updated_context local_context = updated_context
} else if currentChild.nodeType == "table_declaration" { } else if current_node.nodeType == "table_declaration" {
let maybe_table_declaration = Table.Compile( let maybe_table_declaration = Table.Compile(
node: currentChild, 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, let updated_context)) = maybe_table_declaration
else { else {
@@ -513,10 +468,10 @@ extension Control: CompilableDeclaration {
} }
tables.append(table_declaration) tables.append(table_declaration)
local_context = updated_context local_context = updated_context
} else if currentChild.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: currentChild, 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, let updated_context)) = maybe_apply_statement
else { else {
@@ -526,18 +481,23 @@ extension Control: CompilableDeclaration {
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.
break // But, that is handled by the compiler.
} else { } else {
return .Error( return .Error(
ErrorOnNode(node: currentChild, withError: "Uknown node type in control declaration")) ErrorOnNode(node: current_node, withError: "Uknown node type in control declaration"))
} }
return .Ok(())
}
if case .Error(let e) = body_parse_results {
return .Error(e)
} }
// There should only be a single table! // There should only be a single table!
// TODO: Check the semantics here. /// TODO: Check the semantics here.
if tables.count > 1 { if tables.count > 1 {
// TODO: Make this error message better. /// TODO: Make this error message better.
// IDEA: Add a "compilation context" for the error message into the `CompilationContext` /// IDEA: Add a "compilation context" for the error message into the `CompilationContext`
// that can be retrieved to make the error messages nicer. // that can be retrieved to make the error messages nicer.
return .Error( return .Error(
ErrorOnNode(node: node, withError: "More than one table in control declaration")) ErrorOnNode(node: node, withError: "More than one table in control declaration"))
@@ -580,50 +540,48 @@ extension Action: Compilable {
#RequireNodeType<Node, (P4DataType, CompilerContext)>( #RequireNodeType<Node, (P4DataType, CompilerContext)>(
node: node, type: "action_declaration", nice_type_name: "Action Declaration") node: node, type: "action_declaration", nice_type_name: "Action Declaration")
var currentChildIdx = 1 var walker = Walker(node: node)
var currentChildIdxSafe = 2 var current_node: Node? = .none
var currentChild: Node? = .none
var current_context = context var current_context = context
// Skip action keyword // Skip action keyword
if node.childCount < currentChildIdxSafe { walker.next()
return .Error(
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(P4Lang.Action, CompilerContext)>.Error(
ErrorOnNode(node: node, withError: "Missing action declaration component")) ErrorOnNode(node: node, withError: "Missing action declaration component"))
} )
currentChild = node.child(at: currentChildIdx)
guard guard
case .Ok(let action_name) = Identifier.Compile( case .Ok(let action_name) = Identifier.Compile(
node: currentChild!, withContext: current_context) node: current_node!, withContext: current_context)
else { else {
return Result.Error( return Result.Error(
Error(withMessage: "Could not parse an action name from \(currentChild!.text!)")) Error(withMessage: "Could not parse an action name from \(current_node!.text!)"))
} }
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 #MustOr(
if node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return .Error( or: Result<(P4Lang.Action, CompilerContext)>.Error(
ErrorOnNode(node: node, withError: "Missing action declaration component")) ErrorOnNode(node: node, withError: "Missing action declaration component"))
} )
currentChild = node.child(at: currentChildIdx)
let maybe_action_parameters = ParameterList.Compile( let maybe_action_parameters = ParameterList.Compile(
node: currentChild!, 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, let updated_context)) = maybe_action_parameters
else { else {
return .Error(maybe_action_parameters.error()!) return .Error(maybe_action_parameters.error()!)
} }
current_context = updated_context current_context = updated_context
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 #MustOr(
if node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return Result.Error( or: Result<(P4Lang.Action, CompilerContext)>.Error(
ErrorOnNode( ErrorOnNode(node: node, withError: "Missing action declaration component"))
node: node, withError: "Missing action declaration component")) )
}
currentChild = node.child(at: currentChildIdx)
// Add the parameters into scope. // Add the parameters into scope.
var function_scope = context.instances.enter() var function_scope = context.instances.enter()
@@ -633,12 +591,12 @@ extension Action: Compilable {
} }
let maybe_action_body = BlockStatement.Compile( let maybe_action_body = BlockStatement.Compile(
node: currentChild!, 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(
( (
@@ -659,35 +617,35 @@ extension TableKeyEntry: Compilable {
#RequireNodeType<Node, (P4DataType, CompilerContext)>( #RequireNodeType<Node, (P4DataType, CompilerContext)>(
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 currentChildIdx = 0 var walker = Walker(node: node)
var currentChildIdxSafe = 1
var currentChild: Node? = .none var current_node: Node? = .none
let current_context = context let current_context = context
if node.childCount < currentChildIdxSafe { #MustOr(
return .Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing table key entry declaration component")) or: Result<(P4Lang.TableKeyEntry, CompilerContext)>.Error(
} ErrorOnNode(
currentChild = node.child(at: currentChildIdx) node: node, withError: "Missing table key entry declaration component")))
let maybe_keyset_expression = KeysetExpression.compile( let maybe_keyset_expression = KeysetExpression.compile(
node: currentChild!, withContext: current_context) node: current_node!, withContext: current_context)
guard case .Ok(let keyset_expression) = maybe_keyset_expression else { guard case .Ok(let keyset_expression) = maybe_keyset_expression else {
return Result.Error(maybe_keyset_expression.error()!) return Result.Error(maybe_keyset_expression.error()!)
} }
walker.next()
// Skip the ':' // Skip the ':'
currentChildIdx += 2 walker.next()
currentChildIdxSafe += 2 #MustOr(
if node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return .Error( or: Result<(P4Lang.TableKeyEntry, CompilerContext)>.Error(
ErrorOnNode(node: node, withError: "Missing table key entry declaration component")) ErrorOnNode(
} node: node, withError: "Missing table key entry declaration component")))
currentChild = node.child(at: currentChildIdx)
let maybe_match_type = TableKeyMatchType.Compile( let maybe_match_type = TableKeyMatchType.Compile(
node: currentChild!, 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()!)
} }
@@ -719,26 +677,29 @@ extension TableKeys: Compilable {
#RequireNodeType<Node, (TableKeyMatchType, CompilerContext)>( #RequireNodeType<Node, (TableKeyMatchType, CompilerContext)>(
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)
// Skip the // Skip the
// keys = { // keys = {
// 0 1 2 // 1 2 3
let currentChildIdx = 3 walker.next() // 1
let currentChildIdxSafe = 4 walker.next() // 2
var currentChild: Node? = .none walker.next() // 3
var current_node: Node? = .none
var current_context = context var current_context = context
if node.childCount < currentChildIdxSafe { #MustOr(
return .Error( result: current_node, thing: walker.getNext(),
or: Result<(P4Lang.TableKeys, CompilerContext)>.Error(
ErrorOnNode( ErrorOnNode(
node: node, withError: "Missing table keys declaration component in control declaration")) node: node, withError: "Missing table keys declaration component in control declaration"))
} )
currentChild = node.child(at: currentChildIdx)
var entries: [TableKeyEntry] = Array() var entries: [TableKeyEntry] = Array()
var errors: [Error] = Array() var errors: [Error] = Array()
currentChild!.enumerateNamedChildren { entry in current_node!.enumerateNamedChildren { entry in
switch TableKeyEntry.Compile(node: currentChild!, withContext: current_context) { switch TableKeyEntry.Compile(node: current_node!, withContext: current_context) {
case .Ok((let keyset_expression, let updated_context)): case .Ok((let keyset_expression, let updated_context)):
entries.append(keyset_expression) entries.append(keyset_expression)
current_context = updated_context current_context = updated_context
@@ -823,37 +784,38 @@ extension Table: Compilable {
#RequireNodeType<Node, (P4DataType, CompilerContext)>( #RequireNodeType<Node, (P4DataType, CompilerContext)>(
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 currentChildIdx = 1 var walker = Walker(node: table_declaration_node)
var currentChildIdxSafe = 2
var currentChild: Node? = .none var current_node: Node? = .none
let current_context = context let current_context = context
if table_declaration_node.childCount < currentChildIdxSafe { walker.next() // Skip the XXX?
return .Error( #MustOr(
ErrorOnNode(node: table_declaration_node, withError: "Missing table declaration component")) result: current_node, thing: walker.getNext(),
} or: Result<(P4Lang.Table, CompilerContext)>.Error(
currentChild = table_declaration_node.child(at: currentChildIdx) ErrorOnNode(
node: node, withError: "Missing table declaration component")))
guard guard
case .Ok(let table_name) = Identifier.Compile( case .Ok(let table_name) = Identifier.Compile(
node: currentChild!, withContext: current_context) node: current_node!, withContext: current_context)
else { else {
return Result.Error( return Result.Error(
Error(withMessage: "Could not parse a table name from \(currentChild!.text!)")) Error(withMessage: "Could not parse a table name from \(current_node!.text!)"))
} }
walker.next()
// Skip the '{' // Skip the '{'
currentChildIdx += 2 walker.next()
currentChildIdxSafe += 2 #MustOr(
if table_declaration_node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return .Error( or: Result<(P4Lang.Table, CompilerContext)>.Error(
ErrorOnNode(node: table_declaration_node, withError: "Missing table declaration component")) ErrorOnNode(
} node: node, withError: "Missing table declaration component")))
currentChild = table_declaration_node.child(at: currentChildIdx)
let maybe_table_property_list = TablePropertyList.Compile( let maybe_table_property_list = TablePropertyList.Compile(
node: currentChild!, 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()!)
} }
+105 -125
View File
@@ -39,7 +39,7 @@ extension TypedIdentifier: CompilableExpression {
) -> Result<EvaluatableExpression?> { ) -> Result<EvaluatableExpression?> {
let node = node.child(at: 0)! let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node, EvaluatableExpression?>( #SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: node, type: "identifier") node: node, type: "identifier")
guard guard
@@ -59,7 +59,7 @@ extension TypedIdentifier: CompilableLValueExpression {
) -> Result<EvaluatableLValueExpression?> { ) -> Result<EvaluatableLValueExpression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node, EvaluatableExpression?>( #SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: expression, type: "identifier") node: expression, type: "identifier")
let maybe_parsed_expression = TypedIdentifier.compile(node: node, withContext: context) let maybe_parsed_expression = TypedIdentifier.compile(node: node, withContext: context)
@@ -78,7 +78,7 @@ extension P4BooleanValue: CompilableExpression {
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> { ) -> Result<EvaluatableExpression?> {
let node = node.child(at: 0)! let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node, EvaluatableExpression?>( #SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: node, type: "booleanLiteralExpression") node: node, type: "booleanLiteralExpression")
if node.text == "false" { if node.text == "false" {
@@ -97,7 +97,7 @@ extension P4IntValue: CompilableExpression {
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> { ) -> Result<EvaluatableExpression?> {
let node = node.child(at: 0)! let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node, EvaluatableExpression?>(node: node, type: "integer") #SkipUnlessNodeType<SwiftTreeSitter.Node>(node: node, type: "integer")
if let parsed_int = Int(node.text!) { if let parsed_int = Int(node.text!) {
return .Ok(P4Value(P4IntValue(withValue: parsed_int))) return .Ok(P4Value(P4IntValue(withValue: parsed_int)))
} else { } else {
@@ -111,7 +111,7 @@ extension P4StringValue: CompilableExpression {
node: SwiftTreeSitter.Node, withContext scopes: CompilerContext node: SwiftTreeSitter.Node, withContext scopes: CompilerContext
) -> Result<EvaluatableExpression?> { ) -> Result<EvaluatableExpression?> {
let node = node.child(at: 0)! let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node, EvaluatableExpression?>( #SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: node, type: "string_literal") node: node, type: "string_literal")
return .Ok(P4Value(P4StringValue(withValue: node.text!))) return .Ok(P4Value(P4StringValue(withValue: node.text!)))
} }
@@ -339,20 +339,18 @@ extension BinaryOperatorExpression: CompilableExpression {
) -> Result<(EvaluatableExpression)?> { ) -> Result<(EvaluatableExpression)?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node, EvaluatableExpression?>( #SkipUnlessNodeType<Node>(
node: expression, type: "binaryOperatorExpression") node: expression, type: "binaryOperatorExpression")
var currentChildIdx = 0 let binary_operator_expression_node = expression.child(at: 0)!
var currentChildIdxSafe = 1 var walker = Walker(node: binary_operator_expression_node)
var currentChild: Node? = .none
if expression.childCount < currentChildIdxSafe { var current_node: Node? = .none
return Result.Error( #MustOr(
ErrorOnNode(node: node, withError: "Malformed binary operator expression")) result: current_node, thing: walker.getNext(),
} or: Result<EvaluatableExpression?>.Error(
currentChild = expression.child(at: currentChildIdx) ErrorOnNode(
node: node, withError: "Malformed binary operator expression")))
let binary_operator_expression_node = currentChild!
// 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
@@ -360,32 +358,29 @@ extension BinaryOperatorExpression: CompilableExpression {
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(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
ErrorOnNode(
node: node, withError: "Missing LHS for binary operator expression")))
if binary_operator_expression_node.childCount < currentChildIdxSafe { let left_hand_side_raw = current_node!
return Result.Error(
ErrorOnNode(node: node, withError: "Missing LHS for binary operator expression"))
}
currentChild = binary_operator_expression_node.child(at: currentChildIdx)
let left_hand_side_raw = currentChild!
currentChildIdx = currentChildIdx + 1 walker.next()
currentChildIdxSafe = currentChildIdxSafe + 1 #MustOr(
if binary_operator_expression_node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return Result.Error( or: Result<EvaluatableExpression?>.Error(
ErrorOnNode(node: node, withError: "Missing binary operator for binary operator expression") ErrorOnNode(
) node: node, withError: "Missing binary operator for binary operator expression")))
}
currentChild = binary_operator_expression_node.child(at: currentChildIdx)
currentChildIdx = currentChildIdx + 1 walker.next()
currentChildIdxSafe = currentChildIdxSafe + 1 #MustOr(
if binary_operator_expression_node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return Result.Error( or: Result<EvaluatableExpression?>.Error(
ErrorOnNode(node: node, withError: "Missing binary operator for binary operator expression") ErrorOnNode(
) node: node, withError: "Missing RHS for binary operator expression")))
}
currentChild = binary_operator_expression_node.child(at: currentChildIdx) let right_hand_side_raw = current_node!
let right_hand_side_raw = currentChild!
let maybe_left_hand_side = Expression.Compile(node: left_hand_side_raw, withContext: context) let maybe_left_hand_side = Expression.Compile(node: left_hand_side_raw, withContext: context)
guard case Result.Ok(let left_hand_side) = maybe_left_hand_side else { guard case Result.Ok(let left_hand_side) = maybe_left_hand_side else {
@@ -465,54 +460,48 @@ extension BinaryOperatorExpression: CompilableExpression {
extension ArrayAccessExpression: CompilableExpression { extension ArrayAccessExpression: CompilableExpression {
static func compile( static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableExpression)?> { ) -> Common.Result<EvaluatableExpression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node, EvaluatableExpression?>( #SkipUnlessNodeType<Node>(
node: expression, type: "arrayAccessExpression") node: expression, type: "arrayAccessExpression")
let array_access_expression_node = expression let array_access_expression_node = expression
var currentChildIdx = 0 var walker = Walker(node: array_access_expression_node)
var currentChildIdxSafe = 1 var current_node: Node? = .none
var currentChild: Node? = .none
// What is the "name" of the array? #MustOr(
if array_access_expression_node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return Result.Error( or: Result<EvaluatableExpression?>.Error(
ErrorOnNode(node: node, withError: "Malformed array access expression")) ErrorOnNode(
} node: node, withError: "Malformed array access expression")))
currentChild = expression.child(at: currentChildIdx)
#RequireNodeType<Node, EvaluatableExpression?>( #RequireNodeType<Node, EvaluatableExpression?>(
node: currentChild!, type: "expression", node: current_node!, type: "expression",
nice_type_name: "array identifier expression") nice_type_name: "array identifier expression")
let array_access_identifier_node = currentChild! let array_access_identifier_node = current_node!
// Check for the [ walker.next()
currentChildIdx = currentChildIdx + 1 #MustOr(
currentChildIdxSafe = currentChildIdxSafe + 1 result: current_node, thing: walker.getNext(),
if array_access_expression_node.childCount < currentChildIdxSafe { or: Result<EvaluatableExpression?>.Error(
return Result.Error( ErrorOnNode(
ErrorOnNode(node: node, withError: "Missing [ for array access expression") node: node, withError: "Missing [ for array access expression")))
)
}
// What is the indexor of the array? walker.next()
currentChildIdx = currentChildIdx + 1
currentChildIdxSafe = currentChildIdxSafe + 1 #MustOr(
if array_access_expression_node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return Result.Error( or: Result<EvaluatableExpression?>.Error(
ErrorOnNode(node: node, withError: "Missing indexor expression for array access expression") ErrorOnNode(
) node: node, withError: "Missing indexor expression for array access expression")))
}
currentChild = array_access_expression_node.child(at: currentChildIdx)
#RequireNodeType<Node, EvaluatableExpression?>( #RequireNodeType<Node, EvaluatableExpression?>(
node: currentChild!, type: "expression", node: current_node!, type: "expression",
nice_type_name: "array indexor expression") nice_type_name: "array indexor expression")
let array_access_indexor_node = currentChild! let array_access_indexor_node = current_node!
let maybe_array_identifier = Expression.Compile( let maybe_array_identifier = Expression.Compile(
node: array_access_identifier_node, withContext: context) node: array_access_identifier_node, withContext: context)
@@ -547,51 +536,44 @@ extension FieldAccessExpression: CompilableExpression {
) -> Common.Result<(any Common.EvaluatableExpression)?> { ) -> Common.Result<(any Common.EvaluatableExpression)?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node, EvaluatableExpression?>( #SkipUnlessNodeType<Node>(
node: expression, type: "fieldAccessExpression") node: expression, type: "fieldAccessExpression")
let field_access_expression_node = expression let field_access_expression_node = expression
var currentChildIdx = 0 var walker = Walker(node: field_access_expression_node)
var currentChildIdxSafe = 1 var current_node: Node? = .none
var currentChild: Node? = .none
// What is the "name" of the struct? #MustOr(
if field_access_expression_node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return Result.Error( or: Result<EvaluatableExpression?>.Error(
ErrorOnNode(node: node, withError: "Malformed field access expression")) ErrorOnNode(
} node: node, withError: "Malformed field access expression")))
currentChild = expression.child(at: currentChildIdx)
#RequireNodeType<Node, EvaluatableExpression?>( #RequireNodeType<Node, EvaluatableExpression?>(
node: currentChild!, type: "expression", node: current_node!, type: "expression",
nice_type_name: "struct identifier expression") nice_type_name: "struct identifier expression")
let struct_identifier_node = currentChild! let struct_identifier_node = current_node!
// Check for the . walker.next()
currentChildIdx = currentChildIdx + 1 #MustOr(
currentChildIdxSafe = currentChildIdxSafe + 1 result: current_node, thing: walker.getNext(),
if field_access_expression_node.childCount < currentChildIdxSafe { or: Result<EvaluatableExpression?>.Error(
return Result.Error( ErrorOnNode(
ErrorOnNode(node: node, withError: "Missing . for field access expression") node: node, withError: "Missing . for field access expression")))
)
}
// What is the field of the struct? walker.next()
currentChildIdx = currentChildIdx + 1 #MustOr(
currentChildIdxSafe = currentChildIdxSafe + 1 result: current_node, thing: walker.getNext(),
if field_access_expression_node.childCount < currentChildIdxSafe { or: Result<EvaluatableExpression?>.Error(
return Result.Error( ErrorOnNode(
ErrorOnNode(node: node, withError: "Missing field name for field access expression") node: node, withError: "Missing field name for field access expression")))
)
}
currentChild = field_access_expression_node.child(at: currentChildIdx)
#RequireNodeType<Node, EvaluatableExpression?>( #RequireNodeType<Node, EvaluatableExpression?>(
node: currentChild!, type: "identifier", node: current_node!, type: "identifier",
nice_type_name: "field name") nice_type_name: "field name")
let field_name_node = currentChild! let field_name_node = current_node!
// Make sure that the identifier really identifies a struct. // Make sure that the identifier really identifies a struct.
let maybe_struct_identifier = Expression.Compile( let maybe_struct_identifier = Expression.Compile(
@@ -633,7 +615,7 @@ extension FieldAccessExpression: CompilableLValueExpression {
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression?> { ) -> Result<EvaluatableLValueExpression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node, EvaluatableExpression?>( #SkipUnlessNodeType<Node>(
node: expression, type: "fieldAccessExpression") node: expression, type: "fieldAccessExpression")
let maybe_parsed_expression = FieldAccessExpression.compile(node: node, withContext: context) let maybe_parsed_expression = FieldAccessExpression.compile(node: node, withContext: context)
@@ -652,7 +634,7 @@ extension ArrayAccessExpression: CompilableLValueExpression {
node: SwiftTreeSitter.Node, withContext context: CompilerContext node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression?> { ) -> Result<EvaluatableLValueExpression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node, EvaluatableExpression?>( #SkipUnlessNodeType<Node>(
node: expression, type: "arrayAccessExpression") node: expression, type: "arrayAccessExpression")
let maybe_parsed_expression = ArrayAccessExpression.compile(node: node, withContext: context) let maybe_parsed_expression = ArrayAccessExpression.compile(node: node, withContext: context)
@@ -672,22 +654,20 @@ extension FunctionCall: CompilableExpression {
) -> Result<EvaluatableExpression?> { ) -> Result<EvaluatableExpression?> {
let expression = node.child(at: 0)! let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node, EvaluatableExpression?>( #SkipUnlessNodeType<Node>(
node: expression, type: "function_call") node: expression, type: "function_call")
var currentChildIdx = 0 var walker = Walker(node: expression)
var currentChildIdxSafe = 1 var current_node: Node? = .none
var currentChild: Node? = .none
if expression.childCount < currentChildIdxSafe { #MustOr(
return Result.Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing function call component")) or: Result<EvaluatableExpression?>.Error(
} ErrorOnNode(
node: node, withError: "Missing function call component")))
currentChild = expression.child(at: currentChildIdx)
let maybe_callee_name = Identifier.Compile( let maybe_callee_name = Identifier.Compile(
node: currentChild!, withContext: context) node: current_node!, withContext: context)
guard case .Ok(let callee_name) = maybe_callee_name else { guard case .Ok(let callee_name) = maybe_callee_name else {
return Result.Error(maybe_callee_name.error()!) return Result.Error(maybe_callee_name.error()!)
} }
@@ -700,7 +680,7 @@ extension FunctionCall: CompilableExpression {
Result<(FunctionDeclaration?, Declaration?)>.Ok((callee, .none)) // What we found is actually a function declaration Result<(FunctionDeclaration?, Declaration?)>.Ok((callee, .none)) // What we found is actually a function declaration
default: default:
Result<(FunctionDeclaration?, Declaration?)>.Error( Result<(FunctionDeclaration?, Declaration?)>.Error(
ErrorOnNode(node: currentChild!, withError: "\(callee_name) is not a function")) ErrorOnNode(node: current_node!, withError: "\(callee_name) is not a function"))
} }
case .Error(let e): Result<(FunctionDeclaration?, Declaration?)>.Error(e) case .Error(let e): Result<(FunctionDeclaration?, Declaration?)>.Error(e)
} }
@@ -713,7 +693,7 @@ extension FunctionCall: CompilableExpression {
switch callee.identifier.type.dataType() { switch callee.identifier.type.dataType() {
case is FunctionDeclaration: Result.Ok((.none, callee)) case is FunctionDeclaration: Result.Ok((.none, callee))
default: default:
.Error(ErrorOnNode(node: currentChild!, withError: "\(callee_name) is not a function")) .Error(ErrorOnNode(node: current_node!, withError: "\(callee_name) is not a function"))
} }
default: .Error(e) default: .Error(e)
} }
@@ -725,15 +705,15 @@ extension FunctionCall: CompilableExpression {
return .Error(maybe_callee.error()!) return .Error(maybe_callee.error()!)
} }
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1
if expression.childCount < currentChildIdxSafe {
return Result.Error(
ErrorOnNode(node: node, withError: "Missing function call component"))
}
currentChild = expression.child(at: currentChildIdx)
let maybe_argument_list = ArgumentList.Compile(node: currentChild!, withContext: context) #MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
ErrorOnNode(
node: node, withError: "Missing function call component")))
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()!)
+33 -35
View File
@@ -179,11 +179,9 @@ public struct Parser {
static func Compile( static func Compile(
node: Node, withContext context: CompilerContext node: Node, withContext context: CompilerContext
) -> Result<(InstantiatedParserState, CompilerContext)> { ) -> Result<(InstantiatedParserState, CompilerContext)> {
var walker = Walker(node: node)
var currentChildIdx = 0 var current_node: Node? = .none
var currentChildIdxSafe = 1
var currentChild: Node? = .none
guard let node_type = node.nodeType, guard let node_type = node.nodeType,
node_type == "parserState" node_type == "parserState"
@@ -192,50 +190,50 @@ public struct Parser {
ErrorOnNode(node: node, withError: "Did not find a parser state declaration")) ErrorOnNode(node: node, withError: "Did not find a parser state declaration"))
} }
if node.childCount < currentChildIdxSafe { #MustOr(
return Result.Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing elements in parser state declaration")) or: Result<(InstantiatedParserState, CompilerContext)>.Error(
} ErrorOnNode(
node: node, withError: "Missing elements in parser state declaration")))
currentChild = node.child(at: currentChildIdx) if current_node!.nodeType == "annotations" {
if currentChild!.nodeType == "annotations" {
return Result.Error( return Result.Error(
ErrorOnNode( ErrorOnNode(
node: currentChild!, withError: "Annotations in parser state are not yet handled.")) node: current_node!, withError: "Annotations in parser state are not yet handled."))
// Would increment here. // Would increment here.
} }
// Skip the keyword state // Skip the keyword state
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1 #MustOr(
if node.childCount < currentChildIdxSafe { result: current_node, thing: walker.getNext(),
return Result.Error( or: Result<(InstantiatedParserState, CompilerContext)>.Error(
ErrorOnNode(node: node, withError: "Missing elements in parser state declaration")) ErrorOnNode(
} node: node, withError: "Missing elements in parser state declaration")))
currentChild = node.child(at: currentChildIdx)
let maybe_state_identifier = Identifier.Compile( let maybe_state_identifier = Identifier.Compile(
node: currentChild!, withContext: context) node: current_node!, withContext: context)
guard case Result.Ok(let state_identifier) = maybe_state_identifier else { guard case Result.Ok(let state_identifier) = maybe_state_identifier else {
return Result.Error(maybe_state_identifier.error()!) return Result.Error(maybe_state_identifier.error()!)
} }
walker.next()
// Skip the '{' // Skip the '{'
currentChildIdx += 2 walker.next()
currentChildIdxSafe += 2 #MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(InstantiatedParserState, CompilerContext)>.Error(
ErrorOnNode(
node: node, withError: "Missing body of state declaration")))
var parse_errs: [Error] = Array() var parse_errs: [Error] = Array()
var current_context = context var current_context = context
var parsed_s: [EvaluatableStatement] = Array() var parsed_s: [EvaluatableStatement] = Array()
if node.childCount < currentChildIdxSafe { if current_node!.nodeType == "parserStatements" {
return Result.Error(ErrorOnNode(node: node, withError: "Missing body of state declaration"))
}
currentChild = node.child(at: currentChildIdx)
if currentChild!.nodeType == "parserStatements" {
switch Statements.Compile( switch Statements.Compile(
node: currentChild!, withContext: current_context) node: current_node!, withContext: current_context)
{ {
case .Ok(let (state_statements, updated_context)): case .Ok(let (state_statements, updated_context)):
parsed_s = state_statements parsed_s = state_statements
@@ -243,8 +241,7 @@ public struct Parser {
case .Error(let error): case .Error(let error):
parse_errs.append(error) parse_errs.append(error)
} }
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1
} }
if !parse_errs.isEmpty { if !parse_errs.isEmpty {
@@ -255,13 +252,14 @@ public struct Parser {
}.joined(separator: ";"))) }.joined(separator: ";")))
} }
if node.childCount < currentChildIdxSafe { #MustOr(
return Result.Error( result: current_node, thing: walker.getNext(),
ErrorOnNode(node: node, withError: "Missing transition statement of state declaration")) or: Result<(InstantiatedParserState, CompilerContext)>.Error(
} ErrorOnNode(
currentChild = node.child(at: currentChildIdx) node: node, withError: "Missing transition statement of state declaration")))
return TransitionStatement.Compile( return TransitionStatement.Compile(
node: currentChild!, forState: state_identifier, withStatements: parsed_s, node: current_node!, forState: state_identifier, withStatements: parsed_s,
withContext: current_context) withContext: current_context)
} }
} }
+25 -28
View File
@@ -29,34 +29,32 @@ extension BlockStatement: CompilableStatement {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>( #RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
node: node, type: "blockStatement", nice_type_name: "block statement") node: node, type: "blockStatement", nice_type_name: "block statement")
var currentChildIdx = 0 var walker = Walker(node: node)
var currentChildIdxSafe = 1 var current_node: Node? = .none
var currentChild: Node? = .none
if node.childCount < currentChildIdxSafe { #MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error(
ErrorOnNode(node: node, withError: "Malformed block statement")))
if current_node!.nodeType != "{" {
return Result.Error( return Result.Error(
ErrorOnNode(node: node, withError: "Malformed block statement")) ErrorOnNode(node: current_node!, withError: "Missing { on block statement"))
} }
currentChild = node.child(at: currentChildIdx)
if currentChild!.nodeType != "{" {
return Result.Error(
ErrorOnNode(node: currentChild!, withError: "Missing { on block statement"))
}
currentChildIdx += 1
currentChildIdxSafe += 1
var statements: [EvaluatableStatement] = Array() var statements: [EvaluatableStatement] = Array()
var parse_err: Error? = .none var parse_err: Error? = .none
var current_context = context var current_context = context
if node.childCount < currentChildIdxSafe { walker.next()
return Result.Error( #MustOr(
ErrorOnNode(node: node, withError: "Malformed block statement")) result: current_node, thing: walker.getNext(),
} or: Result<(EvaluatableStatement, CompilerContext)>.Error(
currentChild = node.child(at: currentChildIdx) ErrorOnNode(node: node, withError: "Malformed block statement")))
if currentChild!.nodeType == "statements" {
if current_node!.nodeType == "statements" {
switch Parser.Statements.Compile( switch Parser.Statements.Compile(
node: currentChild!, withContext: current_context) node: current_node!, withContext: current_context)
{ {
case .Ok(let (parsed_statements, updated_context)): case .Ok(let (parsed_statements, updated_context)):
current_context = updated_context current_context = updated_context
@@ -65,22 +63,21 @@ extension BlockStatement: CompilableStatement {
parse_err = error parse_err = error
} }
currentChildIdx += 1 walker.next()
currentChildIdxSafe += 1
} }
if let err = parse_err { if let err = parse_err {
return .Error(err) return .Error(err)
} }
if node.childCount < currentChildIdxSafe { #MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error(
ErrorOnNode(node: node, withError: "Malformed block statement")))
if current_node!.nodeType != "}" {
return Result.Error( return Result.Error(
ErrorOnNode(node: node, withError: "Malformed block statement")) ErrorOnNode(node: current_node!, withError: "Missing } on block statement"))
}
currentChild = node.child(at: currentChildIdx)
if currentChild!.nodeType != "}" {
return Result.Error(
ErrorOnNode(node: currentChild!, withError: "Missing } on block statement"))
} }
return .Ok((BlockStatement(statements), current_context)) return .Ok((BlockStatement(statements), current_context))
+54
View File
@@ -0,0 +1,54 @@
// 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
import SwiftTreeSitter
import TreeSitterP4
public struct Walker {
var currentChildIdx: Int
let childCount: Int
let node: Node
public init(node: Node) {
self.currentChildIdx = 0
self.childCount = node.childCount
self.node = node
}
public mutating func next() {
self.currentChildIdx += 1
}
public func getNext() -> Node? {
// If it is safe, then return the node!
if self.currentChildIdx < self.childCount {
return self.node.child(at: self.currentChildIdx)!
}
return .none
}
public func overUntil(n: Int, todo: (Node) -> Result<()>) -> Result<()> {
for currentChildIdx in currentChildIdx..<n {
let currentChild = node.child(at: currentChildIdx)!
if case Result.Error(let e) = todo(currentChild) {
return Result<()>.Error(e)
}
}
return Result.Ok(())
}
}
-1
View File
@@ -64,7 +64,6 @@ public struct FunctionDeclaration: P4DataType, P4DataValue {
} }
public func eq(rhs: any Common.P4DataType) -> Bool { public func eq(rhs: any Common.P4DataType) -> Bool {
print("Checking a type: me: \(self) vs them: \(rhs)!")
switch rhs { switch rhs {
case let frhs as FunctionDeclaration: case let frhs as FunctionDeclaration:
return frhs.tipe.eq(self.tipe) && frhs.params == self.params return frhs.tipe.eq(self.tipe) && frhs.params == self.params
@@ -107,6 +107,36 @@ import P4Lang
#expect(#RequireOkResult(Program.Compile(simple_parser_declaration))) #expect(#RequireOkResult(Program.Compile(simple_parser_declaration)))
} }
@Test func test_simple_control_declaration_with_multiple_tables() async throws {
let simple_parser_declaration = """
control simple(bool x, bool y, bool a, bool b) {
action a() {
}
table t {
key = {
x: exact;
y: exact;
}
}
table u {
key = {
a: exact;
b: exact;
}
}
apply {
}
};
"""
#expect(
#RequireErrorResult(
Error(
withMessage: "{0, 215}: More than one table in control declaration"
),
Program.Compile(simple_parser_declaration))
)
}
@Test func test_simple_control_declaration_with_action_using_parameter() async throws { @Test func test_simple_control_declaration_with_action_using_parameter() async throws {
let simple_parser_declaration = """ let simple_parser_declaration = """
control simple(bool x, bool y) { control simple(bool x, bool y) {
@@ -150,4 +180,36 @@ import P4Lang
), ),
Program.Compile(simple_parser_declaration)) Program.Compile(simple_parser_declaration))
) )
}
@Test func test_simple_control_declaration_with_element_after_apply() async throws {
let simple_parser_declaration = """
control simple(bool x, bool y) {
action a(int z) {
z = false;
}
table t {
key = {
x: exact;
y: exact;
}
}
apply {
}
table x {
key = {
x: exact;
y: exact;
}
}
};
"""
#expect(
#RequireErrorResult(
Error(
withMessage:
"Could not compile the P4 program"
),
Program.Compile(simple_parser_declaration))
)
} }
@@ -0,0 +1,51 @@
// 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
import Foundation
import Macros
import P4Lang
import P4Runtime
import SwiftTreeSitter
import Testing
import TreeSitter
import TreeSitterP4
@testable import Macros
func wrapper_test_mustor() -> Int {
let x: Int? = 2
var i = 0
#MustOr(result: i, thing: x, or: 1)
return i
}
func wrapper_test_mustor_none() -> Int {
let x: Int? = .none
var i = 0
#MustOr(result: i, thing: x, or: 1)
return i
}
@Test func test_mustor() async throws {
#expect(wrapper_test_mustor() == 2)
}
@Test func test_mustor_none() async throws {
#expect(wrapper_test_mustor_none() == 1)
}