aa12974dd6
As a use case, use it to implement text serialization of the CST. Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
257 lines
8.6 KiB
Swift
257 lines
8.6 KiB
Swift
// 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 <https://www.gnu.org/licenses/>.
|
|
|
|
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<CSTTextSerializerContext> {
|
|
public func visit(
|
|
node: P4Parser.CST.KeysetExpression, driver: P4Parser.CSTVisitorDriver,
|
|
context: CSTTextSerializerContext
|
|
) -> Common.Result<CSTTextSerializerContext> {
|
|
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<CSTTextSerializerContext> {
|
|
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<CSTTextSerializerContext> {
|
|
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<CSTTextSerializerContext> {
|
|
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<CSTTextSerializerContext> {
|
|
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<CSTTextSerializerContext> {
|
|
return .Ok(context.append("Control Declaration"))
|
|
}
|
|
|
|
public func visit(
|
|
node: P4Parser.CST.ExternDeclaration, driver: P4Parser.CSTVisitorDriver,
|
|
context: CSTTextSerializerContext
|
|
) -> Common.Result<CSTTextSerializerContext> {
|
|
return .Ok(context.append("Extern Declaration"))
|
|
}
|
|
|
|
public func visit(
|
|
node: P4Parser.CST.FunctionDeclaration, driver: P4Parser.CSTVisitorDriver,
|
|
context: CSTTextSerializerContext
|
|
) -> Common.Result<CSTTextSerializerContext> {
|
|
return .Ok(context.append("Function Declaration"))
|
|
}
|
|
|
|
public func visit(
|
|
node: P4Parser.CST.StructDeclaration, driver: P4Parser.CSTVisitorDriver,
|
|
context: CSTTextSerializerContext
|
|
) -> Common.Result<CSTTextSerializerContext> {
|
|
return .Ok(context.append("Struct Declaration"))
|
|
}
|
|
|
|
public func visit(
|
|
node: P4Parser.CST.VariableDeclarationStatement, driver: P4Parser.CSTVisitorDriver,
|
|
context: CSTTextSerializerContext
|
|
) -> Common.Result<CSTTextSerializerContext> {
|
|
return .Ok(context.append("Variable Declaration Statement"))
|
|
}
|
|
|
|
public func visit(
|
|
node: CST.BinaryOperatorExpression, driver: CSTVisitorDriver,
|
|
context: CSTTextSerializerContext
|
|
) -> Common.Result<CSTTextSerializerContext> {
|
|
return .Ok(context.append("Binary Operator Expression"))
|
|
}
|
|
|
|
public func visit(
|
|
node: CST.Literal, driver: CSTVisitorDriver,
|
|
context: CSTTextSerializerContext
|
|
) -> Common.Result<CSTTextSerializerContext> {
|
|
return .Ok(context.append("Literal Expression"))
|
|
}
|
|
|
|
public func visit(
|
|
node: CST.Identifier, driver: CSTVisitorDriver,
|
|
context: CSTTextSerializerContext
|
|
) -> Common.Result<CSTTextSerializerContext> {
|
|
return .Ok(context.append("Identifier: \(node.id)"))
|
|
}
|
|
|
|
public func visit(
|
|
node: CST.Parser, driver: CSTVisitorDriver, context: CSTTextSerializerContext
|
|
) -> Common.Result<CSTTextSerializerContext> {
|
|
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<CSTTextSerializerContext> {
|
|
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<CSTTextSerializerContext> {
|
|
return .Ok(context.append("State: No Transition"))
|
|
}
|
|
|
|
public func visit(
|
|
node: CST.ParserStateSelectTransition, driver: CSTVisitorDriver,
|
|
context: CSTTextSerializerContext
|
|
) -> Common.Result<CSTTextSerializerContext> {
|
|
|
|
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())
|
|
}
|
|
}
|