Compare commits

..

5 Commits

Author SHA1 Message Date
Will Hawkins 6908d9a91d compiler: Clean Up Warnings In Compiler
Continuous Integration / Grammar Tests (push) Successful in 37s
Continuous Integration / Library Format Tests (push) Successful in 1m47s
Continuous Integration / Library Tests (push) Successful in 4m51s
Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
2026-05-29 17:47:05 -04:00
Will Hawkins 6882a32858 Make Formatter Happy
Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
2026-05-29 17:37:42 -04:00
Will Hawkins 3ee1eab2f8 compiler: Parser Compile Should Match Compile Protocol
Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
2026-05-29 17:37:26 -04:00
Will Hawkins d2797e1acc compiler: Use Macro to Derive CompilableStatement Implementations
Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
2026-05-29 17:36:44 -04:00
Will Hawkins 4f6de341cc compiler: Refactor Transition Statement Compilation
Make it follow the standard protocol(s). Unfortunately that means
that some additional information will have to be carried in
the compilation context. It seems like a decent tradeoff -- but
it may be revisited in the future.

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
2026-05-29 17:33:23 -04:00
8 changed files with 186 additions and 194 deletions
+61 -7
View File
@@ -43,6 +43,8 @@ public struct CompilerContext {
public let ffis: [P4FFI]
public let expected_type: P4QualifiedType?
public let extern_context: Bool
public let lexical_context_name: Identifier?
public let lexical_context_statements: [P4Statement]?
public init() {
instances = StaticVarValueScopes().enter()
@@ -51,6 +53,8 @@ public struct CompilerContext {
expected_type = .none
extern_context = false
ffis = Array()
lexical_context_name = .none
lexical_context_statements = .none
}
public init(withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes) {
@@ -60,12 +64,16 @@ public struct CompilerContext {
expected_type = .none
extern_context = false
ffis = Array()
lexical_context_name = .none
lexical_context_statements = .none
}
public init(
withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes,
withExpectation expectation: P4QualifiedType?, withExtern extern: Bool,
withExterns externs: TypeTypeScopes, withFFIs foreigns: [P4FFI]
withExterns externs: TypeTypeScopes, withFFIs foreigns: [P4FFI],
withLexicalContextName lexical_context_name: Identifier?,
withLexicalContextStatements lexical_context_statements: [P4Statement]?
) {
instances = _instances
types = _types
@@ -73,6 +81,8 @@ public struct CompilerContext {
extern_context = extern
self.externs = externs
ffis = foreigns
self.lexical_context_name = lexical_context_name
self.lexical_context_statements = lexical_context_statements
}
/// Update a compiler context
@@ -84,7 +94,9 @@ public struct CompilerContext {
public func update(newInstances instances: StaticVarValueScopes) -> CompilerContext {
return CompilerContext(
withInstances: instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis,
withLexicalContextName: self.lexical_context_name,
withLexicalContextStatements: self.lexical_context_statements)
}
/// Update a compiler context
@@ -96,7 +108,9 @@ public struct CompilerContext {
public func update(newTypes types: TypeTypeScopes) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis,
withLexicalContextName: self.lexical_context_name,
withLexicalContextStatements: self.lexical_context_statements)
}
/// Update a compiler context
@@ -108,7 +122,9 @@ public struct CompilerContext {
public func update(newExpectation expectation: P4QualifiedType?) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: expectation,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis,
withLexicalContextName: self.lexical_context_name,
withLexicalContextStatements: self.lexical_context_statements)
}
/// Update a compiler context
@@ -120,7 +136,9 @@ public struct CompilerContext {
public func update(newExtern extern: Bool) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: extern, withExterns: self.externs, withFFIs: self.ffis)
withExtern: extern, withExterns: self.externs, withFFIs: self.ffis,
withLexicalContextName: self.lexical_context_name,
withLexicalContextStatements: self.lexical_context_statements)
}
/// Update a compiler context
@@ -132,7 +150,9 @@ public struct CompilerContext {
public func update(newExterns externs: TypeTypeScopes) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis)
withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis,
withLexicalContextName: self.lexical_context_name,
withLexicalContextStatements: self.lexical_context_statements)
}
/// Update a compiler context
@@ -144,6 +164,40 @@ public struct CompilerContext {
public func update(newFFIs foreigns: [P4FFI]) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: foreigns)
withExtern: self.extern_context, withExterns: externs, withFFIs: foreigns,
withLexicalContextName: self.lexical_context_name,
withLexicalContextStatements: self.lexical_context_statements)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but with a new lexical context name.
///
/// - Parameter new_lexical_context_name: an optional new lexical context name; passing `.none` resets.
/// - Returns: A new compiler context based on the current but with a new lexical context name.
public func update(newLexicalContextName new_lexical_context_name: Identifier?) -> CompilerContext
{
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis,
withLexicalContextName: new_lexical_context_name,
withLexicalContextStatements: self.lexical_context_statements)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but with a new set of lexical context statements.
///
/// - Parameter new_lexical_context_statements: an optional new set of lexical context statements; passing `.none` resets.
/// - Returns: A new compiler context based on the current but with a new set of lexical context statements.
public func update(
newLexicalContextStatements new_lexical_context_statements: [P4Statement]?
) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis,
withLexicalContextName: self.lexical_context_name,
withLexicalContextStatements: new_lexical_context_statements)
}
}
-3
View File
@@ -106,6 +106,3 @@ public func Fold<T, A>(input: [T], initial: A, block: (T, A) -> A) -> A {
@freestanding(codeItem) public macro MustOr<E, N>(result: E, thing: E?, or: N) =
#externalMacro(module: "Macros", type: "MustOr")
@attached(peer) public macro DeriveCompilableStatement() =
#externalMacro(module: "Macros", type: "DeriveCompilableStatement")
+3 -7
View File
@@ -439,17 +439,14 @@ public struct CliTestDeclarationMacro: PeerMacro, Sendable {
}
}
public struct DeriveCompilableStatement: PeerMacro, Sendable {
public enum DeriveCompilableStatement: MemberMacro {
public static func expansion(
of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
of: AttributeSyntax, providingMembersOf type: some DeclGroupSyntax, conformingTo: [TypeSyntax],
in: some MacroExpansionContext
) throws -> [DeclSyntax] {
let type_name = declaration.cast(ExtensionDeclSyntax.self).extendedType
let implementation = DeclSyntax(
"""
extension VariableDeclarationStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
@@ -458,7 +455,6 @@ public struct DeriveCompilableStatement: PeerMacro, Sendable {
case .Error(let e): .Error(e)
}
}
}
""")
return [implementation]
}
+4
View File
@@ -384,3 +384,7 @@ extension Node {
return SourceLocation(self.range.location, self.range.length)
}
}
@attached(member, names: named(CompileStatement))
public macro deriveCompilableStatement() =
#externalMacro(module: "Macros", type: "DeriveCompilableStatement")
+13 -24
View File
@@ -81,8 +81,6 @@ extension FunctionDeclaration: Compilable {
nice_type_name: "Function Declaration")
var walker = Walker(node: function_declaration_node)
var context = context
var current_node: Node? = .none
#MustOr(
@@ -224,16 +222,14 @@ extension P4Struct: Compilable {
}
var parse_errs: (any Errorable)? = .none
var current_context = context
var parsed_fields: [P4StructFieldIdentifier] = Array()
if currentNode!.nodeType == "struct_declaration_fields" {
currentNode!.enumerateNamedChildren { declaration_field in
switch VariableDeclarationStatement.Compile(
node: declaration_field, withContext: current_context)
node: declaration_field, withContext: context)
{
case .Ok(let declaration):
let variable_declaration = declaration as! VariableDeclarationStatement
case .Ok(let variable_declaration):
parsed_fields.append(
P4StructFieldIdentifier(
id: variable_declaration.identifier, withType: variable_declaration.initializer.type()
@@ -393,7 +389,7 @@ extension P4Lang.Parser: Compilable {
withName: parser_name!, withParameters: parameter_list, node: current_node!,
withContext: current_context)
{
case Result.Ok((let parser, let updated_context)):
case Result.Ok(let parser):
let parser_declaration = Declaration(
TypedIdentifier(id: parser.name, withType: P4QualifiedType(parser)))
// Create a new context with the name of the parser that was just compiled in scope.
@@ -507,7 +503,7 @@ extension Control: Compilable {
else {
return .Error(maybe_apply_statement.error()!)
}
apply = (apply_statement as! ApplyStatement)
apply = apply_statement
// The apply is the last thing in a control declaration.
// But, that is handled by the compiler.
@@ -570,7 +566,6 @@ extension Action: Compilable {
var walker = Walker(node: node)
var current_node: Node? = .none
var current_context = context
// Skip action keyword
walker.next()
@@ -585,7 +580,7 @@ extension Action: Compilable {
guard
case .Ok(let action_name) = Identifier.Compile(
node: current_node!, withContext: current_context)
node: current_node!, withContext: context)
else {
return Result.Error(
Error(withMessage: "Could not parse an action name from \(current_node!.text!)"))
@@ -601,7 +596,7 @@ extension Action: Compilable {
)
let maybe_action_parameters = ParameterList.Compile(
node: current_node!, withContext: current_context)
node: current_node!, withContext: context)
guard case .Ok(let action_parameters) = maybe_action_parameters
else {
return .Error(maybe_action_parameters.error()!)
@@ -645,7 +640,7 @@ extension Action: Compilable {
return .Ok(
Action(
named: action_name, withParameters: action_parameters,
withBody: (action_body as! BlockStatement)))
withBody: action_body))
}
}
@@ -662,8 +657,6 @@ extension TableKeyEntry: Compilable {
var current_node: Node? = .none
let current_context = context
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<TableKeyEntry>.Error(
@@ -672,7 +665,7 @@ extension TableKeyEntry: Compilable {
withError: "Missing table key entry declaration component")))
let maybe_keyset_expression = KeysetExpression.compile(
node: current_node!, withContext: current_context)
node: current_node!, withContext: context)
guard case .Ok(let keyset_expression) = maybe_keyset_expression else {
return Result.Error(maybe_keyset_expression.error()!)
}
@@ -688,7 +681,7 @@ extension TableKeyEntry: Compilable {
withError: "Missing table key entry declaration component")))
let maybe_match_type = TableKeyMatchType.Compile(
node: current_node!, withContext: current_context)
node: current_node!, withContext: context)
guard case .Ok(let match_type) = maybe_match_type else {
return .Error(maybe_match_type.error()!)
}
@@ -829,21 +822,19 @@ extension TablePropertyList: Compilable {
#RequireNodeType<Node, TablePropertyList>(
node: node, type: "table_property_list", nice_type_name: "Table Property List")
var current_context = context
var keys: [TableKeys] = Array()
var actions: [TableActionsProperty] = Array()
var errors: [any Errorable] = Array()
node.enumerateNamedChildren { child in
if child.nodeType == "table_keys" {
switch TableKeys.Compile(node: child, withContext: current_context) {
switch TableKeys.Compile(node: child, withContext: context) {
case .Ok(let table_key):
keys.append(table_key)
case .Error(let e): errors.append(e)
}
} else if child.nodeType == "table_actions" {
switch TableActionsProperty.Compile(node: child, withContext: current_context) {
switch TableActionsProperty.Compile(node: child, withContext: context) {
case .Ok(let table_action_property):
actions.append(table_action_property)
case .Error(let e): errors.append(e)
@@ -906,8 +897,6 @@ extension Table: Compilable {
var current_node: Node? = .none
let current_context = context
walker.next() // Skip the XXX?
#MustOr(
result: current_node, thing: walker.getNext(),
@@ -918,7 +907,7 @@ extension Table: Compilable {
guard
case .Ok(let table_name) = Identifier.Compile(
node: current_node!, withContext: current_context)
node: current_node!, withContext: context)
else {
return Result.Error(
Error(withMessage: "Could not parse a table name from \(current_node!.text!)"))
@@ -935,7 +924,7 @@ extension Table: Compilable {
))
let maybe_table_property_list = TablePropertyList.Compile(
node: current_node!, withContext: current_context)
node: current_node!, withContext: context)
guard case .Ok(let table_property_list) = maybe_table_property_list else {
return Result.Error(maybe_table_property_list.error()!)
}
+4 -3
View File
@@ -178,8 +178,9 @@ extension ParserState: Compilable {
sourceLocation: node.toSourceLocation(),
withError: "Missing transition statement of state declaration")))
return SpecialCompilers.TransitionStatement.Compile(
node: current_node!, forState: state_identifier, withStatements: parsed_s,
withContext: SpecialCompilers.Statements.effect(statements: parsed_s, context: context))
let updated_context = SpecialCompilers.Statements.effect(statements: parsed_s, context: context)
.update(newLexicalContextName: state_identifier).update(newLexicalContextStatements: parsed_s)
return TransitionStatement.Compile(node: current_node!, withContext: updated_context)
}
}
+22 -7
View File
@@ -28,13 +28,27 @@ protocol AnyCompilable {
) -> Common.Result<(Any, CompilerContext)>
}
public struct SpecialCompilers {
public struct TransitionStatement {
static func Compile(
node: Node, forState state_identifier: Common.Identifier,
withStatements stmts: [P4Statement], withContext context: CompilerContext
extension TransitionStatement: Compilable {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<ParserState> {
guard let state_identifier = context.lexical_context_name else {
return .Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Cannot parse a transition statement without the name of the containing state."
))
}
guard let stmts = context.lexical_context_statements else {
return .Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError:
"Cannot parse a transition statement without statements of the containing state."))
}
#RequireNodeType<Node, P4Statement>(
node: node, type: "parserTransitionStatement", nice_type_name: "parser transition statement"
)
@@ -110,6 +124,7 @@ public struct SpecialCompilers {
}
}
public struct SpecialCompilers {
public struct Statements {
static func Compile(
node: Node, withContext context: CompilerContext
@@ -161,7 +176,7 @@ public struct SpecialCompilers {
static func CompileParserBody(
withName name: Common.Identifier, withParameters parameters: ParameterList, node: Node,
withContext context: CompilerContext
) -> Result<(P4Lang.Parser, CompilerContext)> {
) -> Result<P4Lang.Parser> {
var parser = P4Lang.Parser(withName: name, withParameters: parameters)
@@ -192,7 +207,7 @@ public struct SpecialCompilers {
return .Error(error)
}
return Result.Ok((parser, current_context))
return Result.Ok(parser)
}
public struct ProgramCompiler {
+17 -81
View File
@@ -90,16 +90,8 @@ extension BlockStatement: Compilable {
}
}
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)
}
}
}
@deriveCompilableStatement
extension BlockStatement: CompilableStatement {}
extension ConditionalStatement: Compilable {
public typealias C = ConditionalStatement
@@ -173,16 +165,8 @@ extension ConditionalStatement: Compilable {
}
}
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)
}
}
}
@deriveCompilableStatement
extension ConditionalStatement: CompilableStatement {}
extension VariableDeclarationStatement: Compilable {
public typealias C = VariableDeclarationStatement
@@ -279,16 +263,8 @@ extension VariableDeclarationStatement: Compilable {
}
}
extension VariableDeclarationStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
@deriveCompilableStatement
extension VariableDeclarationStatement: CompilableStatement {}
extension ExpressionStatement: Compilable {
public typealias C = ExpressionStatement
@@ -307,16 +283,8 @@ extension ExpressionStatement: Compilable {
}
}
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)
}
}
}
@deriveCompilableStatement
extension ExpressionStatement: CompilableStatement {}
extension ParserAssignmentStatement: Compilable {
public typealias C = ParserAssignmentStatement
@@ -372,16 +340,8 @@ extension ParserAssignmentStatement: Compilable {
}
}
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)
}
}
}
@deriveCompilableStatement
extension ParserAssignmentStatement: CompilableStatement {}
extension ReturnStatement: Compilable {
public typealias C = ReturnStatement
@@ -410,16 +370,8 @@ extension ReturnStatement: Compilable {
}
}
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)
}
}
}
@deriveCompilableStatement
extension ReturnStatement: CompilableStatement {}
extension ApplyStatement: Compilable {
public typealias C = ApplyStatement
@@ -433,22 +385,14 @@ extension ApplyStatement: Compilable {
return switch BlockStatement.Compile(node: expression_node, withContext: context) {
case .Ok(let statement):
.Ok(ApplyStatement(statement as! BlockStatement))
.Ok(ApplyStatement(statement))
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)
}
}
}
@deriveCompilableStatement
extension ApplyStatement: CompilableStatement {}
extension Instantiation: Compilable {
public typealias C = Instantiation
@@ -582,13 +526,5 @@ extension Instantiation: Compilable {
}
}
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)
}
}
}
@deriveCompilableStatement
extension Instantiation: CompilableStatement {}