Files
gp4/Sources/P4Compiler/Statement.swift
T
Will Hawkins 2f7d05a3fd Refactor Compilation Interface
Compilation interface(s) now contain a compilation context.
The change will make it easier to expand on what each step
of the compilation process needs to know to complete its task
without having to make major changes to the interface.

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
2026-03-13 06:25:30 -04:00

250 lines
8.1 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 P4Lang
import P4Runtime
import SwiftTreeSitter
import TreeSitterExtensions
import TreeSitterP4
extension BlockStatement: CompilableStatement {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
node: node, type: "blockStatement", nice_type_name: "block statement")
var currentChildIdx = 0
var currentChildIdxSafe = 1
var currentChild: Node? = .none
if node.childCount < currentChildIdxSafe {
return Result.Error(
ErrorOnNode(node: node, withError: "Malformed block statement"))
}
currentChild = node.child(at: currentChildIdx)
if currentChild!.nodeType != "{" {
return Result.Error(
ErrorOnNode(node: currentChild!, withError: "Missing { on block statement"))
}
currentChildIdx += 1
currentChildIdxSafe += 1
var statements: [EvaluatableStatement] = Array()
var parse_err: Error? = .none
var current_context = context
if node.childCount < currentChildIdxSafe {
return Result.Error(
ErrorOnNode(node: node, withError: "Malformed block statement"))
}
currentChild = node.child(at: currentChildIdx)
if currentChild!.nodeType == "statements" {
switch Parser.Statements.Compile(
node: currentChild!, withContext: current_context)
{
case .Ok(let (parsed_statements, updated_context)):
current_context = updated_context
statements = parsed_statements
case .Error(let error):
parse_err = error
}
currentChildIdx += 1
currentChildIdxSafe += 1
}
if let err = parse_err {
return .Error(err)
}
if node.childCount < currentChildIdxSafe {
return Result.Error(
ErrorOnNode(node: node, withError: "Malformed block statement"))
}
currentChild = node.child(at: currentChildIdx)
if currentChild!.nodeType != "}" {
return Result.Error(
ErrorOnNode(node: currentChild!, withError: "Missing } on block statement"))
}
return .Ok((BlockStatement(statements), current_context))
}
}
extension ConditionalStatement: CompilableStatement {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
node: node, type: "conditionalStatement", nice_type_name: "conditional statement")
let maybe_condition_expression = node.child(at: 2)
guard let condition_expression = maybe_condition_expression,
condition_expression.nodeType == "expression"
else {
return Result.Error(
ErrorOnNode(node: node, withError: "Did not find condition for conditional statement"))
}
let maybe_thens = node.child(at: 4)
guard let thens = maybe_thens,
thens.nodeType == "statement"
else {
return Result.Error(
ErrorOnNode(
node: node, withError: "Did not find then statement block for conditional statement"))
}
guard
case .Ok(let condition) = Expression.Compile(
node: condition_expression, withContext: context)
else {
return Result.Error(
Error(withMessage: "Could not parse a conditional expression in a conditional statement"))
}
guard
case .Ok((let thenns, _)) = Parser.Statement.Compile(
node: thens, withContext: context)
else {
return Result.Error(
Error(
withMessage:
"Could not parse the then block in a conditional statement"))
}
let optional_elss: Result<(any EvaluatableStatement, CompilerContext)>? =
if let elss = node.child(at: 6) {
.some(
Parser.Statement.Compile(
node: elss, withContext: context))
} else {
.none
}
if let parsed_elss = optional_elss {
guard
case .Ok((let elss, _)) = parsed_elss
else {
return Result.Error(
Error(
withMessage:
"Could not parse the else block in a conditional statement"))
}
return .Ok(
(ConditionalStatement(condition: condition, withThen: thenns, andElse: elss), context))
}
return .Ok((ConditionalStatement(condition: condition, withThen: thenns), context))
}
}
extension VariableDeclarationStatement: CompilableStatement {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
node: node, type: "variableDeclaration", nice_type_name: "variable declaration statement")
let maybe_typeref = node.child(at: 0)
guard let typeref = maybe_typeref,
typeref.nodeType == "typeRef"
else {
return Result.Error(
ErrorOnNode(
node: node, withError: "Did not find type name for variable declaration statement"))
}
let maybe_variablename = node.child(at: 1)
guard let variablename = maybe_variablename,
variablename.nodeType == "identifier"
else {
return Result.Error(
ErrorOnNode(
node: node, withError: "Did not find identifier name for variable declaration statement"))
}
let maybe_rvalue = node.childCount > 3 ? node.child(at: 3) : .none
guard let rvalue = maybe_rvalue,
rvalue.nodeType == "expression"
else {
return Result.Error(
ErrorOnNode(
node: node,
withError: "Did not find initial value expression for variable declaration statement"))
}
guard
case .Ok(let parsed_variablename) = Identifier.Compile(
node: variablename, withContext: context)
else {
return Result.Error(
Error(withMessage: "Could not parse variable name"))
}
guard
case .Ok(let parsed_rvalue) = Expression.Compile(
node: rvalue, withContext: context)
else {
return Result.Error(
Error(
withMessage:
"Could not parse initial value expression in a variable declaration statement"))
}
guard case .Ok(let declaration_p4_type) = Types.CompileBasicType(type: typeref.text!) else {
return Result.Error(
Error(withMessage: "Could not parse a P4 type from \(typeref.text!)"))
}
if parsed_rvalue.type().eq(rhs: declaration_p4_type) {
return Result.Ok(
(
VariableDeclarationStatement(
identifier: parsed_variablename, withInitializer: parsed_rvalue),
// Context with updated names to include the newly declared name.
CompilerContext(withNames: context.names.declare(
identifier: parsed_variablename, withValue: declaration_p4_type))
))
} else {
return Result.Error(
Error(
withMessage:
"Cannot initialize \(parsed_variablename) (with type \(declaration_p4_type)) from rvalue with type \(parsed_rvalue.type())"
))
}
}
}
extension ExpressionStatement: CompilableStatement {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
node: node, type: "expressionStatement", nice_type_name: "expression statement")
let _ = node.child(at: 0)
return Result.Ok((ExpressionStatement(), context))
}
}