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
+277 -59
View File
@@ -22,11 +22,12 @@ import SwiftTreeSitter
import TreeSitterExtensions
import TreeSitterP4
extension BlockStatement: CompilableStatement {
extension BlockStatement: Compilable {
public typealias C = BlockStatement
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
) -> Result<BlockStatement> {
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "blockStatement", nice_type_name: "block statement")
var walker = Walker(node: node)
@@ -34,7 +35,7 @@ extension BlockStatement: CompilableStatement {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error(
or: Result<BlockStatement>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
@@ -45,23 +46,21 @@ extension BlockStatement: CompilableStatement {
withError: "Missing { on block statement"))
}
var statements: [EvaluatableStatement] = Array()
var statements: [P4Statement] = Array()
var parse_err: (any Errorable)? = .none
var current_context = context
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error(
or: Result<BlockStatement>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
if current_node!.nodeType == "statements" {
switch SpecialCompilers.Statements.Compile(
node: current_node!, withContext: current_context)
node: current_node!, withContext: context)
{
case .Ok(let (parsed_statements, updated_context)):
current_context = updated_context
case .Ok(let parsed_statements):
statements = parsed_statements
case .Error(let error):
parse_err = error
@@ -76,7 +75,7 @@ extension BlockStatement: CompilableStatement {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error(
or: Result<BlockStatement>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
@@ -87,16 +86,28 @@ extension BlockStatement: CompilableStatement {
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(
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")
let maybe_condition_expression = node.child(at: 2)
@@ -128,7 +139,7 @@ extension ConditionalStatement: CompilableStatement {
}
guard
case .Ok((let thenns, _)) = Statement.Compile(
case .Ok(let thenns) = Statement.Compile(
node: thens, withContext: context)
else {
return Result.Error(
@@ -137,7 +148,7 @@ extension ConditionalStatement: CompilableStatement {
"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) {
.some(
Statement.Compile(
@@ -148,7 +159,7 @@ extension ConditionalStatement: CompilableStatement {
if let parsed_elss = optional_elss {
guard
case .Ok((let elss, _)) = parsed_elss
case .Ok(let elss) = parsed_elss
else {
return Result.Error(
Error(
@@ -156,18 +167,30 @@ extension ConditionalStatement: CompilableStatement {
"Could not parse the else block in a conditional statement"))
}
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(
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")
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!)"))
}
var initializer: EvaluatableExpression? = .none
var initializer: P4Expression? = .none
// If there is an initializer, it must be an expression.
if let initializer_expression = maybe_rvalue {
@@ -249,40 +272,59 @@ extension VariableDeclarationStatement: CompilableStatement {
}
return Result.Ok(
(
VariableDeclarationStatement(
identifier: parsed_variablename, withInitializer: initializer),
// Context with updated names to include the newly declared name.
context.update(
newInstances: context.instances.declare(
identifier: parsed_variablename, withValue: (declaration_p4_type, .none)))
)
VariableDeclarationStatement(
identifier: TypedIdentifier(id: parsed_variablename, withType: declaration_p4_type),
withInitializer: initializer),
)
}
}
extension ExpressionStatement: CompilableStatement {
public static func Compile(
extension VariableDeclarationStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
node: node, type: "expressionStatement", nice_type_name: "expression statement")
let expression_node = node.child(at: 0)!
return switch Expression.Compile(node: expression_node, withContext: context) {
case .Ok(let expression): .Ok((ExpressionStatement(expression), context))
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension ParserAssignmentStatement: CompilableStatement {
extension ExpressionStatement: Compilable {
public typealias C = ExpressionStatement
public static func Compile(
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")
guard let lvalue_node = node.child(at: 0),
@@ -323,20 +365,30 @@ extension ParserAssignmentStatement: CompilableStatement {
}
return Result.Ok(
(
ParserAssignmentStatement(
withLValue: lvalue_identifier,
withValue: rvalue
), context
ParserAssignmentStatement(
withLValue: lvalue_identifier,
withValue: rvalue
))
}
}
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(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
) -> Result<ReturnStatement> {
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "return_statement", nice_type_name: "return statement")
let expression_node = node.child(at: 1)!
@@ -344,7 +396,7 @@ extension ReturnStatement: CompilableStatement {
return switch Expression.Compile(node: expression_node, withContext: context) {
case .Ok(let result):
if result.type().baseType().eq(rhs: context.expected_type!.baseType()) {
.Ok((ReturnStatement(result), context))
.Ok(ReturnStatement(result))
} else {
.Error(
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(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
) -> Result<ApplyStatement> {
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "apply_statement", nice_type_name: "apply statement")
let expression_node = node.child(at: 1)!
return switch BlockStatement.Compile(node: expression_node, withContext: context) {
case .Ok((let statement, let updated_context)):
.Ok((ApplyStatement(statement as! BlockStatement), updated_context))
case .Ok(let statement):
.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)
}
}