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:
@@ -22,15 +22,16 @@ extension P4Value: CST.Categories.Expression {}
|
||||
public struct CST {
|
||||
|
||||
public struct Categories {
|
||||
public protocol Expression {}
|
||||
public protocol Statement {}
|
||||
public protocol State {}
|
||||
public protocol LanguageElement {}
|
||||
public protocol Expression: Categories.LanguageElement {}
|
||||
public protocol Statement : Categories.LanguageElement {}
|
||||
public protocol State : Categories.LanguageElement {}
|
||||
public protocol Declaration: Categories.Statement {}
|
||||
}
|
||||
|
||||
struct Expression {}
|
||||
|
||||
public struct Statements {
|
||||
public struct Statements: Categories.Statement {
|
||||
public let statements: [Categories.Statement]
|
||||
|
||||
public init(_ s: [Categories.Statement]) {
|
||||
|
||||
@@ -58,11 +58,28 @@ public protocol ParsableStatement {
|
||||
|
||||
public protocol CSTVisitor<T> {
|
||||
associatedtype T
|
||||
|
||||
// Declarations
|
||||
func visit(node: CST.Control, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.ExternDeclaration, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.FunctionDeclaration, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.StructDeclaration, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.Parser, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
|
||||
// Statements
|
||||
func visit(node: CST.Statements, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.VariableDeclarationStatement, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.ExpressionStatement, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
|
||||
// Expressions
|
||||
func visit(node: CST.KeysetExpression, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.SelectCaseExpression, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.SelectExpression, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.BinaryOperatorExpression, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.Literal, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
func visit(node: CST.Identifier, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
|
||||
func visit(node: CST.Parser, driver: CSTVisitorDriver, context: T) -> Result<T>
|
||||
// Parser
|
||||
func visit(
|
||||
node: CST.ParserStateDirectTransition, driver: CSTVisitorDriver, context: T
|
||||
) -> Result<T>
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user