2f7d05a3fd
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>
250 lines
8.1 KiB
Swift
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))
|
|
}
|
|
}
|