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>
This commit is contained in:
Will Hawkins
2026-05-29 17:33:19 -04:00
parent 297288e2b0
commit 4f6de341cc
3 changed files with 146 additions and 77 deletions
+81 -67
View File
@@ -28,88 +28,102 @@ 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
) -> Result<ParserState> {
extension TransitionStatement: Compilable {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<ParserState> {
#RequireNodeType<Node, P4Statement>(
node: node, type: "parserTransitionStatement", nice_type_name: "parser transition statement"
)
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 tse_node = node.child(at: 1),
tse_node.nodeType! == "transitionSelectionExpression"
else {
return .Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Could not find transition select expression"))
}
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."))
}
guard let next_node = tse_node.child(at: 0) else {
return .Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Could not find the next token in a transition selection expression"))
}
// If the next node is an identifier, we have the simple form ...
if next_node.nodeType == "identifier" {
let maybe_parsed_next_state_id = Identifier.Compile(
node: next_node, withContext: context)
if case .Ok(let next_state_id) = maybe_parsed_next_state_id {
if case .Ok(let next_state) = context.instances.lookup(identifier: next_state_id) {
switch next_state {
case (_, .some(let instance)):
return .Ok(
ParserStateDirectTransition(
name: state_identifier,
withNextState: instance.dataValue() as! InstantiatedParserState,
withStatements: stmts,
)
#RequireNodeType<Node, P4Statement>(
node: node, type: "parserTransitionStatement", nice_type_name: "parser transition statement"
)
guard let tse_node = node.child(at: 1),
tse_node.nodeType! == "transitionSelectionExpression"
else {
return .Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Could not find transition select expression"))
}
guard let next_node = tse_node.child(at: 0) else {
return .Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Could not find the next token in a transition selection expression"))
}
// If the next node is an identifier, we have the simple form ...
if next_node.nodeType == "identifier" {
let maybe_parsed_next_state_id = Identifier.Compile(
node: next_node, withContext: context)
if case .Ok(let next_state_id) = maybe_parsed_next_state_id {
if case .Ok(let next_state) = context.instances.lookup(identifier: next_state_id) {
switch next_state {
case (_, .some(let instance)):
return .Ok(
ParserStateDirectTransition(
name: state_identifier,
withNextState: instance.dataValue() as! InstantiatedParserState,
withStatements: stmts,
)
case (_, .none):
return .Ok(
ParserStateDirectTransition(
name: state_identifier,
withNextStateIdentifier: next_state_id, withStatements: stmts)
)
}
} else {
return .Error(
Error(
withMessage:
"\(next_state_id) does not name a parser state in scope"
))
)
case (_, .none):
return .Ok(
ParserStateDirectTransition(
name: state_identifier,
withNextStateIdentifier: next_state_id, withStatements: stmts)
)
}
} else {
return .Error(
Error(
withMessage:
"Could not parse the next state in a transition statement: \(maybe_parsed_next_state_id.error()!)"
"\(next_state_id) does not name a parser state in scope"
))
}
}
// We know that the next node is a select expression.
return
switch SelectExpression.compile(node: next_node, withContext: context)
{
case .Ok(let tse):
.Ok(
ParserStateSelectTransition(
name: state_identifier, withTransitionExpression: tse as! SelectExpression,
withStatements: stmts,
)
)
case .Error(let e): .Error(e)
} else {
return .Error(
Error(
withMessage:
"Could not parse the next state in a transition statement: \(maybe_parsed_next_state_id.error()!)"
))
}
}
}
// We know that the next node is a select expression.
return
switch SelectExpression.compile(node: next_node, withContext: context)
{
case .Ok(let tse):
.Ok(
ParserStateSelectTransition(
name: state_identifier, withTransitionExpression: tse as! SelectExpression,
withStatements: stmts,
)
)
case .Error(let e): .Error(e)
}
}
}
public struct SpecialCompilers {
public struct Statements {
static func Compile(
node: Node, withContext context: CompilerContext