// 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 P4Lang import P4Runtime import SwiftTreeSitter import TreeSitterExtensions import TreeSitterP4 func parameter_list_compiler( node: SwiftTreeSitter.Node, withContext context: CompilerContext ) -> Common.Result<(ParameterList, CompilerContext)> { var walker = Walker(node: node) var current_node: Node? = .none if node.text == ")" { // There are no parameters! return Result.Ok((ParameterList([]), context)) } #RequireNodeType( node: node, type: "parameter_list", nice_type_name: "Parameter List") var parameters: ParameterList = ParameterList([]) #MustOr( result: current_node, thing: walker.getNext(), or: Result<(ParameterList, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing parameter list component"))) if current_node?.nodeType == "parameter_list" { switch parameter_list_compiler(node: current_node!, withContext: context) { case .Ok(let (ps, _)): parameters = ps case .Error(let e): return Result.Error(e) } walker.next() } #MustOr( result: current_node, thing: walker.getNext(), or: Result<(ParameterList, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing parameter list component"))) // If this is a ')', we are done. if current_node?.text == ")" { return Result.Ok((parameters, context)) } // If this is a comma, we skip it! if current_node?.text == "," { walker.next() } #MustOr( result: current_node, thing: walker.getNext(), or: Result<(ParameterList, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing parameter list component"))) // Otherwise, there should be one parameter left! switch Parameter.Compile(node: current_node!, withContext: context) { case .Ok(let (parsed_parameter, updated_context)): return Result.Ok((parameters.addParameter(parsed_parameter), updated_context)) case .Error(let e): return Result.Error(e) } } extension ParameterList: Compilable { public typealias T = ParameterList public static func Compile( node: SwiftTreeSitter.Node, withContext context: CompilerContext ) -> Common.Result<(ParameterList, CompilerContext)> { let parameter_node = node #RequireNodeType( node: parameter_node, type: "parameters", nice_type_name: "Parameters") var walker = Walker(node: parameter_node) var current_node: Node? = .none #MustOr( result: current_node, thing: walker.getNext(), or: Result<(ParameterList, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing '(' in parameter list component"))) walker.next() #MustOr( result: current_node, thing: walker.getNext(), or: Result<(ParameterList, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing parameter list component"))) return parameter_list_compiler(node: current_node!, withContext: context) } } extension Direction: Compilable { public typealias T = Direction public static func Compile( node: Node, withContext context: CompilerContext ) -> Result<(Direction, CompilerContext)> { let direction_node = node #RequireNodeType( node: direction_node, type: "direction", nice_type_name: "direction") let directions = [ "in": Direction.In, "out": Direction.Out, "inout": Direction.InOut, ] guard let parsed_direction = directions[direction_node.text!] else { return .Error( ErrorOnNode( node: direction_node, withError: "\(direction_node.text!) is not a valid direction")) } return .Ok((parsed_direction, context)) } } extension Parameter: Compilable { public typealias T = Parameter public static func Compile( node: Node, withContext context: CompilerContext ) -> Result<(Parameter, CompilerContext)> { #RequireNodeType( node: node, type: "parameter", nice_type_name: "parameter") var walker = Walker(node: node) var current_node: Node? = .none #MustOr( result: current_node, thing: walker.getNext(), or: Result<(Parameter, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing parameter declaration component"))) // Annotation? if current_node!.nodeType == "annotations" { return .Error( ErrorOnNode( node: current_node!, withError: "Annotations in parameter declarations are not yet handled")) // Will increment indexes here. } #MustOr( result: current_node, thing: walker.getNext(), or: Result<(Parameter, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing parameter declaration component"))) var direction: Direction? = .none // Direction? if current_node!.nodeType == "direction" { let maybe_parsed_direction = Direction.Compile(node: current_node!, withContext: context) guard case .Ok((let parsed_direction, _)) = maybe_parsed_direction else { return .Error(maybe_parsed_direction.error()!) } direction = parsed_direction walker.next() } #MustOr( result: current_node, thing: walker.getNext(), or: Result<(Parameter, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing parameter declaration component"))) if current_node!.nodeType != "typeRef" { return Result.Error( ErrorOnNode( node: node, withError: "Did not find type name for parameter declaration")) } guard case .Ok(let parameter_type) = Types.CompileType(type: current_node!, withContext: context) else { return Result.Error( Error(withMessage: "Could not parse a P4 type from \(current_node!.text!)")) } walker.next() #MustOr( result: current_node, thing: walker.getNext(), or: Result<(Parameter, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing parameter declaration component"))) if current_node!.nodeType != "identifier" { return Result.Error( ErrorOnNode( node: node, withError: "Did not find identifier for parameter statement")) } guard case .Ok(let parameter_name) = Identifier.Compile(node: current_node!, withContext: context) else { return Result.Error( Error(withMessage: "Could not parse a parameter name from \(current_node!.text!)")) } return Result.Ok( ( Parameter( identifier: parameter_name, withType: direction != nil ? parameter_type.update(addAttribute: P4TypeAttribute.Direction(direction!)) : parameter_type), context )) } } func argument_list_compiler( node: SwiftTreeSitter.Node, withContext context: CompilerContext ) -> Common.Result<(ArgumentList, CompilerContext)> { var walker = Walker(node: node) var current_node: Node? = .none if node.text == ")" { // There are no arguments! return Result.Ok((ArgumentList([]), context)) } #RequireNodeType( node: node, type: "argument_list", nice_type_name: "argument List") var arguments: ArgumentList = ArgumentList([]) #MustOr( result: current_node, thing: walker.getNext(), or: Result<(ArgumentList, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing argument list component"))) if current_node?.nodeType == "argument_list" { switch argument_list_compiler(node: current_node!, withContext: context) { case .Ok(let (ps, _)): arguments = ps case .Error(let e): return Result.Error(e) } walker.next() } // We may have moved nodes, check/reset current_node. #MustOr( result: current_node, thing: walker.getNext(), or: Result<(ArgumentList, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing argument list component"))) // If this is a ')', we are done. if current_node?.text == ")" { return Result.Ok((arguments, context)) } // If this is a comma, we skip it! if current_node?.text == "," { walker.next() } #MustOr( result: current_node, thing: walker.getNext(), or: Result<(ArgumentList, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing argument list component"))) // Otherwise, there should be one argument left! switch Argument.Compile(node: current_node!, withContext: context) { case .Ok(let (ce, updated_context)): return Result.Ok( (arguments.addArgument(Argument(ce, atIndex: arguments.count() + 1)), updated_context)) case .Error(let e): return Result.Error(e) } } extension ArgumentList: Compilable { public typealias T = ArgumentList public static func Compile( node: SwiftTreeSitter.Node, withContext context: CompilerContext ) -> Common.Result<(ArgumentList, CompilerContext)> { let argument_node = node #RequireNodeType( node: argument_node, type: "arguments", nice_type_name: "arguments") var walker = Walker(node: argument_node) var current_node: Node? = .none #MustOr( result: current_node, thing: walker.getNext(), or: Result<(ArgumentList, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing '(' in argument list component"))) walker.next() #MustOr( result: current_node, thing: walker.getNext(), or: Result<(ArgumentList, CompilerContext)>.Error( ErrorOnNode( node: node, withError: "Missing argument list component"))) return argument_list_compiler(node: current_node!, withContext: context) } } extension Argument: Compilable { public typealias T = EvaluatableExpression public static func Compile( node: SwiftTreeSitter.Node, withContext context: CompilerContext ) -> Common.Result<(EvaluatableExpression, CompilerContext)> { let argument_node = node #RequireNodeType( node: argument_node, type: "argument", nice_type_name: "argument") let expression_node = node.child(at: 0)! return switch Expression.Compile(node: expression_node, withContext: context) { case .Ok(let compiled_expression): .Ok((compiled_expression, context)) case .Error(let e): .Error(e) } } } func ContainsInvalidStatements( statement: EvaluatableStatement, invalids: [EvaluatableStatement.Type] ) -> Bool { for es in invalids { if type(of: statement) == es { return true } } return false } func ContainsInvalidStatements(block: BlockStatement, invalids: [EvaluatableStatement.Type]) -> Bool { return block.statements.contains { statement in for es in invalids { if type(of: statement) == es { return true } } return false } }