// p4rse, Copyright 2026, Will Hawkins // // This file is part of p4rse. // // This file is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . import Common // Witness the parts of a P4 Program that are visitable. extension Program: Visitable {} extension Parser: Visitable {} extension ParserState: Visitable {} extension VariableDeclarationStatement: Visitable {} extension ConditionalStatement: Visitable {} extension BlockStatement: Visitable {} extension ReturnStatement: Visitable {} extension ApplyStatement: Visitable {} extension KeysetExpression: Visitable {} extension SelectCaseExpression: Visitable {} extension SelectExpression: Visitable {} extension ArrayAccessExpression: Visitable {} extension FieldAccessExpression: Visitable {} extension FunctionCall: Visitable {} extension BinaryOperatorExpression: Visitable {} extension Declaration: Visitable {} extension ExternDeclaration: Visitable {} extension FunctionDeclaration: Visitable {} extension Action: Visitable {} extension TableKeyEntry: Visitable {} extension TablePropertyList: Visitable {} extension Table: Visitable {} extension Control: Visitable {} /// Context for the visiting process. public struct VisitorContext { let visitor: VisitorDriver let uc: UserContext public init(_ v: VisitorDriver, _ uc: UserContext) { self.visitor = v self.uc = uc } public func getUserContext() -> UserContext { return self.uc } public func getVisitorDriver() -> VisitorDriver { return self.visitor } public func next(uc: UserContext) -> VisitorContext { return VisitorContext(self.visitor, uc) } } /// A driver for visiting the components of a parsed P4 program. public struct VisitorDriver { let visitor: any LanguageVisitor public init(_ visitor: any LanguageVisitor) { self.visitor = visitor } public func generateContext(uc: UserContext) -> VisitorContext { return VisitorContext(self, uc) } /// Visit a `P4Type`. public func visit( _ t: P4Type, context: VisitorContext ) -> Result> { return switch t { case let vv as Control: visitor.visit(vv, context) case let vv as Parser: visitor.visit(vv, context) default: .Error(Error(withMessage: "Could not visit type \(t)")) } } /// Visit a part of a P4 program. public func visit( _ v: Visitable, context: VisitorContext ) -> Result> { return switch v { case let vv as Program: visitor.visit(vv, context) case let vv as Parser: visitor.visit(vv, context) case let vv as InstantiatedParserState: visitor.visit(vv, context) case let vv as VariableDeclarationStatement: visitor.visit(vv, context) case let vv as ConditionalStatement: visitor.visit(vv, context) case let vv as BlockStatement: visitor.visit(vv, context) case let vv as ReturnStatement: visitor.visit(vv, context) case let vv as ApplyStatement: visitor.visit(vv, context) case let vv as KeysetExpression: visitor.visit(vv, context) case let vv as SelectCaseExpression: visitor.visit(vv, context) case let vv as SelectExpression: visitor.visit(vv, context) case let vv as ArrayAccessExpression: visitor.visit(vv, context) case let vv as FieldAccessExpression: visitor.visit(vv, context) case let vv as FunctionCall: visitor.visit(vv, context) case let vv as BinaryOperatorExpression: visitor.visit(vv, context) case let vv as Declaration: visitor.visit(vv, context) case let vv as ExternDeclaration: visitor.visit(vv, context) case let vv as FunctionDeclaration: visitor.visit(vv, context) case let vv as Action: visitor.visit(vv, context) case let vv as TableKeyEntry: visitor.visit(vv, context) case let vv as TablePropertyList: visitor.visit(vv, context) case let vv as Table: visitor.visit(vv, context) case let vv as Control: visitor.visit(vv, context) default: .Error(Error(withMessage: "Could not visit \(v)")) } } /// Start the process of visiting a P4 program. public func start(_ v: Visitable, context: UserContext) -> Result { let visit_result = self.visit(v, context: VisitorContext(self, context)) return switch visit_result { case .Ok(let vc): .Ok(vc.getUserContext()) case .Error(let e): .Error(e) } } }