// 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 import P4Parser public struct CSTTextSerializer { public init() {} } public struct CSTTextSerializerContext { public let serialized: String public let indents: Int public init(_ serialized: String = "", _ indents: Int = 0) { self.serialized = serialized self.indents = indents } static func produceIndent(_ indent: Int, _ marker: String) -> String { return repeatElement(marker, count: indent).joined() } public func append(_ a: String) -> CSTTextSerializerContext { return CSTTextSerializerContext( self.serialized + Self.produceIndent(self.indents, "\t") + a + "\n", self.indents) } public func indent() -> CSTTextSerializerContext { return CSTTextSerializerContext(self.serialized, self.indents + 1) } public func unindent() -> CSTTextSerializerContext { return CSTTextSerializerContext(self.serialized, self.indents - 1) } } extension CSTTextSerializer: CSTVisitor { public func visit( node: P4Parser.CST.KeysetExpression, driver: P4Parser.CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { var context = context.append("Keyset Expression:").indent() return .Ok(context.unindent()) if case CST.KeysetExpression.Value(let x) = node { switch driver.visit(x, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } } return .Ok(context.unindent()) } public func visit( node: P4Parser.CST.SelectCaseExpression, driver: P4Parser.CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { var context = context.append("Case Expression:").indent() switch driver.visit(node.key, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } context = context.append("Next State:").indent() switch driver.visit(node.next_state_identifier, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } context = context.unindent() return .Ok(context.unindent()) } public func visit( node: P4Parser.CST.SelectExpression, driver: P4Parser.CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { var context = context.append("Select Expression:").indent() context = context.append("Selector:").indent() switch driver.visit(node.selector, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } context = context.unindent() context = context.append("Case Expressions:").indent() for ce in node.case_expressions { switch driver.visit(ce, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } } context = context.unindent() return .Ok(context.unindent()) } public func visit( node: P4Parser.CST.Statements, driver: P4Parser.CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { var context = context for s in node.statements { switch driver.visit(s, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } } return .Ok(context) } public func visit( node: P4Parser.CST.ExpressionStatement, driver: P4Parser.CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { var context = context.append("Expression Statement:").indent() switch driver.visit(node.expression, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } return .Ok(context.unindent()) } public func visit( node: P4Parser.CST.Control, driver: P4Parser.CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { return .Ok(context.append("Control Declaration")) } public func visit( node: P4Parser.CST.ExternDeclaration, driver: P4Parser.CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { return .Ok(context.append("Extern Declaration")) } public func visit( node: P4Parser.CST.FunctionDeclaration, driver: P4Parser.CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { return .Ok(context.append("Function Declaration")) } public func visit( node: P4Parser.CST.StructDeclaration, driver: P4Parser.CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { return .Ok(context.append("Struct Declaration")) } public func visit( node: P4Parser.CST.VariableDeclarationStatement, driver: P4Parser.CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { return .Ok(context.append("Variable Declaration Statement")) } public func visit( node: CST.BinaryOperatorExpression, driver: CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { return .Ok(context.append("Binary Operator Expression")) } public func visit( node: CST.Literal, driver: CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { return .Ok(context.append("Literal Expression")) } public func visit( node: CST.Identifier, driver: CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { return .Ok(context.append("Identifier: \(node.id)")) } public func visit( node: CST.Parser, driver: CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { var context = context.append("Parser Expression") context = context.indent() for s in node.states.states { switch driver.visit(s, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } } return .Ok(context.unindent()) } public func visit( node: CST.ParserStateDirectTransition, driver: CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { var context = context.append("State: Direct Transition").indent() context = context.append("Statements:") context = context.indent() if let statements = node.statements { switch driver.visit(statements, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } } context = context.unindent() context = context.append("Next State:").indent() switch driver.visit(node.next_state_identifier!, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } context = context.unindent() return .Ok(context.unindent()) } public func visit( node: CST.ParserStateNoTransition, driver: CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { return .Ok(context.append("State: No Transition")) } public func visit( node: CST.ParserStateSelectTransition, driver: CSTVisitorDriver, context: CSTTextSerializerContext ) -> Common.Result { var context = context.append("State: Select Transition").indent() if let statements = node.statements { context = context.indent() switch driver.visit(statements, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } context = context.unindent() } switch driver.visit(node.te, visitor: self, context: context) { case .Ok(let c): context = c case .Error(let e): return .Error(e) } return .Ok(context.unindent()) } }