// 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: P4TypeQualifier.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
}
}