compiler: Flesh Out CST Visitor Framework

As a use case, use it to implement text serialization
of the CST.

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-06-15 23:37:04 -04:00
parent d22776b018
commit aa12974dd6
5 changed files with 277 additions and 31 deletions
+56 -15
View File
@@ -21,17 +21,56 @@ public struct CSTVisitorDriver {
public init() {}
public func visit<T>(
expression: any CST.Categories.Expression, visitor: any CSTVisitor<T>, context: T
_ elem: any CST.Categories.LanguageElement, visitor: any CSTVisitor<T>, context: T
) -> Result<T> {
return switch expression {
case let e as CST.BinaryOperatorExpression:
visitor.visit(node: e, driver: self, context: context)
case let e as CST.Literal: visitor.visit(node: e, driver: self, context: context)
default: .Error(Error(withMessage: "AST Expression Element Is Not Visitable"))
return switch elem {
case let elem as CST.Categories.Expression:
visit(expression: elem, visitor: visitor, context: context)
case let elem as CST.Categories.Statement:
visit(statement: elem, visitor: visitor, context: context)
case let elem as CST.Categories.State: visit(state: elem, visitor: visitor, context: context)
case let elem as CST.Categories.Declaration:
visit(declaration: elem, visitor: visitor, context: context)
default: .Error(Error(withMessage: "AST Language Element (\(elem)) Is Not Visitable"))
}
}
public func visit<T>(
func visit<T>(
declaration: any CST.Categories.Declaration, visitor: any CSTVisitor<T>, context: T
) -> Result<T> {
return switch declaration {
case let elem as CST.Control: visitor.visit(node: elem, driver: self, context: context)
case let elem as CST.ExternDeclaration:
visitor.visit(node: elem, driver: self, context: context)
case let elem as CST.FunctionDeclaration:
visitor.visit(node: elem, driver: self, context: context)
case let elem as CST.StructDeclaration:
visitor.visit(node: elem, driver: self, context: context)
case let elem as CST.Parser: visitor.visit(node: elem, driver: self, context: context)
default: .Error(Error(withMessage: "AST Declaration Element (\(declaration)) Is Not Visitable"))
}
}
func visit<T>(
expression: any CST.Categories.Expression, visitor: any CSTVisitor<T>, context: T
) -> Result<T> {
return switch expression {
case let s as CST.Identifier:
visitor.visit(node: s, driver: self, context: context)
case let s as CST.KeysetExpression:
visitor.visit(node: s, driver: self, context: context)
case let s as CST.SelectCaseExpression:
visitor.visit(node: s, driver: self, context: context)
case let e as CST.SelectExpression:
visitor.visit(node: e, driver: self, context: context)
case let e as CST.BinaryOperatorExpression:
visitor.visit(node: e, driver: self, context: context)
case let e as CST.Literal: visitor.visit(node: e, driver: self, context: context)
default: .Error(Error(withMessage: "AST Expression Element (\(expression)) Is Not Visitable"))
}
}
func visit<T>(
state: any CST.Categories.State, visitor: any CSTVisitor<T>, context: T
) -> Result<T> {
return switch state {
@@ -45,25 +84,27 @@ public struct CSTVisitorDriver {
}
}
public func visit<T>(
func visit<T>(
statement: any CST.Categories.Statement, visitor: any CSTVisitor<T>, context: T
) -> Result<T> {
return switch statement {
case let s as CST.Statements: visitor.visit(node: s, driver: self, context: context)
case let s as CST.ExpressionStatement: visitor.visit(node: s, driver: self, context: context)
case let s as CST.VariableDeclarationStatement:
visitor.visit(node: s, driver: self, context: context)
case let s as CST.Parser: visitor.visit(node: s, driver: self, context: context)
default: .Error(Error(withMessage: "AST Statement Element Is Not Visitable"))
default: .Error(Error(withMessage: "AST Statement Element (\(statement)) Is Not Visitable"))
}
}
public func visit<T>(
public func start<T>(
program: CST.Program, visitor: any CSTVisitor<T>, context: T
) -> Result<T> {
var context = context
for s in program.statements.statements {
switch visit(statement: s, visitor: visitor, context: context) {
case .Ok(let c): context = c
case .Error(let e): return .Error(e)
}
switch visit(statement: program.statements, visitor: visitor, context: context) {
case .Ok(let c): context = c
case .Error(let e): return .Error(e)
}
return .Ok(context)