Start Rewrite
Continuous Integration / Grammar Tests (push) Successful in 3m54s
Continuous Integration / Library Format Tests (push) Failing after 4m49s
Continuous Integration / Library Tests (push) Successful in 7m40s

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-06-12 06:24:53 -04:00
parent 6908d9a91d
commit b9ff228362
73 changed files with 1779 additions and 11477 deletions
+199 -463
View File
@@ -16,66 +16,34 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import Common
import P4Lang
import P4Runtime
import SwiftTreeSitter
import TreeSitterP4
extension TypedIdentifier: CompilableExpression {
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<P4Expression?> {
extension AST.Identifier: CompilableExpression {
public static func CompileExpression(
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: node, type: "identifier")
guard
case Result.Ok(let type) = context.instances.lookup(
identifier: Common.Identifier(name: node.text!))
else {
return .Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Cannot find \(node.text!) in scope"))
}
#RequireNodeType<Node, AST.AnExpression>(
node: node, type: "identifier", nice_type_name: "Identifier")
/// TODO: If there is a value here, then we can make this a compile-time constant!
return .Ok(TypedIdentifier(name: node.text!, withType: type.0))
}
}
extension TypedIdentifier: CompilableLValueExpression {
public static func compile_as_lvalue(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<P4LValueExpression?> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: expression, type: "identifier")
let maybe_parsed_expression = TypedIdentifier.compile(node: node, withContext: context)
guard case .Ok(let maybe_typed_identifier) = maybe_parsed_expression else {
return .Error(maybe_parsed_expression.error()!)
}
let typed_identifier_expression = maybe_typed_identifier as! TypedIdentifier
return Result.Ok(typed_identifier_expression)
return .Ok(AST.Identifier(Common.Identifier(name: node.text!)))
}
}
extension P4BooleanValue: CompilableExpression {
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<P4Expression?> {
public static func CompileExpression(
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: node, type: "booleanLiteralExpression")
#RequireNodeType<Node, AST.AnExpression>(
node: node, type: "booleanLiteralExpression", nice_type_name: "Boolean Literal Expression")
if node.text == "false" {
return .Ok(P4Value(P4BooleanValue(withValue: false)))
return .Ok(AST.Literal(P4Value(P4BooleanValue(withValue: false))))
} else if node.text == "true" {
return .Ok(P4Value(P4BooleanValue(withValue: true)))
return .Ok(AST.Literal(P4Value(P4BooleanValue(withValue: true))))
}
return .Error(
@@ -86,13 +54,14 @@ extension P4BooleanValue: CompilableExpression {
}
extension P4IntValue: CompilableExpression {
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<P4Expression?> {
public static func CompileExpression(
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
let node = node.child(at: 0)!
#SkipUnlessNodesTypes<SwiftTreeSitter.Node>(
node: node, types: ["integer", "integer_elaborated"])
#RequireNodesType<Node, AST.AnExpression>(
nodes: node, type: ["integer", "integer_elaborated"],
nice_type_names: ["Integer", "Elaborated Integer"])
var bit_width: BitWidth = BitWidth.Infinite
let value_source: String
@@ -124,7 +93,7 @@ extension P4IntValue: CompilableExpression {
}
if let parsed_int = Int(value_source) {
return .Ok(P4Value(P4IntValue(withValue: parsed_int, andWidth: bit_width)))
return .Ok(AST.Literal(P4Value(P4IntValue(withValue: parsed_int, andWidth: bit_width))))
} else {
return .Error(
ErrorWithLocation(
@@ -135,131 +104,83 @@ extension P4IntValue: CompilableExpression {
}
extension P4StringValue: CompilableExpression {
public static func compile(
node: SwiftTreeSitter.Node, withContext scopes: CompilerContext
) -> Result<P4Expression?> {
public static func CompileExpression(
node: SwiftTreeSitter.Node, withContext scopes: ASTCompilerContext
) -> Result<AST.AnExpression> {
let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: node, type: "string_literal")
return .Ok(P4Value(P4StringValue(withValue: node.text!)))
#RequireNodeType<Node, AST.AnExpression>(
node: node, type: "string_literal", nice_type_name: "String Literal")
return .Ok(AST.Literal(P4Value(P4StringValue(withValue: node.text!))))
}
}
extension KeysetExpression: CompilableExpression {
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<P4Expression?> {
extension AST.Expression: Compilable {
public static func Compile(
node: Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
#RequireNodeType<Node, AST.AnExpression>(
node: node, type: "expression", nice_type_name: "expression")
let expression_node = node.child(at: 0)!
#RequireNodesType<Node, AST.AnExpression>(
nodes: expression_node, type: ["grouped_expression", "simple_expression"],
nice_type_names: ["grouped expression", "simple expression"])
// If this is a grouped expression, recurse!
if expression_node.nodeType == "grouped_expression" {
return AST.Expression.Compile(node: expression_node.child(at: 1)!, withContext: context)
}
let expression_parsers: [CompilableExpression.Type] = [
P4BooleanValue.self, P4StringValue.self, P4IntValue.self, AST.Identifier.self,
AST.BinaryOperatorExpression.self, AST.ArrayAccessExpression.self, AST.FieldAccessExpression.self,
AST.FunctionCall.self,
]
for candidate_expression_parser in expression_parsers {
switch candidate_expression_parser.CompileExpression(
node: expression_node, withContext: context)
{
case .Ok(let parsed): return .Ok(parsed)
case .Error(let e): return .Error(e)
}
}
return Result.Error(Error(withMessage: "\(node.range): Could not parse into expression"))
}
}
extension AST.KeysetExpression: CompilableExpression {
public static func CompileExpression(
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
let keyset_expression_node = node.child(at: 0)!
#RequireNodesType<Node, P4Expression>(
#RequireNodesType<Node, AST.AnExpression>(
nodes: keyset_expression_node, type: ["expression", "default_keyset"],
nice_type_names: ["expression", "default keyset"])
// If there is a default keyset, that's easy!
if keyset_expression_node.nodeType == "default_keyset" {
return .Ok(KeysetExpression(P4Value(P4SetDefaultValue(withType: context.expected_type!))))
return .Ok(AST.KeysetExpression.Default)
}
// Compile the expression:
let maybe_compiled_set_expression = Expression.Compile(
let maybe_compiled_set_expression = AST.Expression.Compile(
node: keyset_expression_node, withContext: context)
guard case .Ok(let compiled_expression) = maybe_compiled_set_expression else {
return .Error(maybe_compiled_set_expression.error()!)
}
return .Ok(KeysetExpression(compiled_expression))
return .Ok(AST.KeysetExpression.Value(compiled_expression))
}
}
struct Expression {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<P4Expression> {
#RequireNodeType<Node, P4Expression>(
node: node, type: "expression", nice_type_name: "expression")
let expression_node = node.child(at: 0)!
#RequireNodesType<Node, P4Expression>(
nodes: expression_node, type: ["grouped_expression", "simple_expression"],
nice_type_names: ["grouped expression", "simple expression"])
// If this is a grouped expression, recurse!
if expression_node.nodeType == "grouped_expression" {
return Expression.Compile(node: expression_node.child(at: 1)!, withContext: context)
}
let expression_parsers: [CompilableExpression.Type] = [
P4BooleanValue.self, P4StringValue.self, P4IntValue.self, TypedIdentifier.self,
BinaryOperatorExpression.self, ArrayAccessExpression.self, FieldAccessExpression.self,
FunctionCall.self,
]
for candidate_expression_parser in expression_parsers {
switch candidate_expression_parser.compile(
node: expression_node, withContext: context)
{
case .Ok(.some(let parsed)): return .Ok(parsed)
case .Error(let e): return .Error(e)
default: continue
}
}
return Result.Error(Error(withMessage: "\(node.range): Could not parse into expression"))
}
}
struct LValue {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<P4LValueExpression> {
#RequireNodeType<Node, P4Expression>(
node: node, type: "expression", nice_type_name: "expression")
let expression_node = node.child(at: 0)!
#RequireNodesType<Node, P4Expression>(
nodes: expression_node, type: ["grouped_expression", "simple_expression"],
nice_type_names: ["grouped expression", "simple expression"])
// If this is a grouped expression, recurse!
if expression_node.nodeType == "grouped_expression" {
return LValue.Compile(node: expression_node.child(at: 1)!, withContext: context)
}
let lvalue_parsers: [CompilableLValueExpression.Type] = [
TypedIdentifier.self, FieldAccessExpression.self, ArrayAccessExpression.self,
]
for candidate_lvalue_parser in lvalue_parsers {
switch candidate_lvalue_parser.compile_as_lvalue(
node: expression_node, withContext: context)
{
case .Ok(.some(let parsed)): return .Ok(parsed)
case .Error(let e): return .Error(e)
default: continue
}
}
return Result.Error(Error(withMessage: "\(node.range): Could not parse into expression"))
}
}
struct Identifier {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<Common.Identifier> {
return if let node_text_value = node.text {
.Ok(Common.Identifier(name: node_text_value))
} else {
.Error(Error(withMessage: "Could not parse an identifier from \(node)"))
}
}
}
extension SelectExpression: CompilableExpression {
public static func compile(
node: Node, withContext context: CompilerContext
) -> Result<P4Expression?> {
#RequireNodeType<Node, (SelectExpression, CompilerContext)>(
extension AST.SelectExpression: CompilableExpression {
public static func CompileExpression(
node: Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
#RequireNodeType<Node, (AST.SelectExpression, ASTCompilerContext)>(
node: node, type: "selectExpression", nice_type_name: "parser select expression")
guard let selector_node = node.child(at: 2),
@@ -279,7 +200,7 @@ extension SelectExpression: CompilableExpression {
withError: "Could not find select expression body"))
}
let maybe_selector = Expression.Compile(node: selector_node, withContext: context)
let maybe_selector = AST.Expression.Compile(node: selector_node, withContext: context)
guard case .Ok(let selector) = maybe_selector else {
return .Error(
ErrorWithLocation(
@@ -289,14 +210,14 @@ extension SelectExpression: CompilableExpression {
))
}
var sces: [SelectCaseExpression] = Array()
var sces: [AST.SelectCaseExpression] = Array()
var sces_errors: (any Errorable)? = .none
select_body_node.enumerateNamedChildren { current_node in
let maybe_parsed_cse = SelectCaseExpression.compile(
node: current_node, withContext: context.update(newExpectation: selector.type()))
let maybe_parsed_cse = AST.SelectCaseExpression.CompileExpression(
node: current_node, withContext: context)
switch maybe_parsed_cse {
case .Ok(let parsed_cse): sces.append(parsed_cse as! SelectCaseExpression)
case .Ok(let parsed_cse): sces.append(parsed_cse as! AST.SelectCaseExpression)
case .Error(let e):
sces_errors =
if let sces_errors = sces_errors {
@@ -312,18 +233,18 @@ extension SelectExpression: CompilableExpression {
}
return .Ok(
SelectExpression(withSelector: selector, withSelectCaseExpressions: sces),
AST.SelectExpression(withSelector: selector, withSelectCaseExpressions: sces),
)
}
}
extension SelectCaseExpression: CompilableExpression {
public static func compile(
node: Node, withContext context: CompilerContext
) -> Result<P4Expression?> {
if node.nodeType != "selectCase" {
return Result.Error(Error(withMessage: "Expected select case not found"))
}
extension AST.SelectCaseExpression: CompilableExpression {
public static func CompileExpression(
node: Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
#RequireNodeType<Node, AST.AnExpression>(
node: node, type: "selectCase", nice_type_name: "Select Case")
guard let keysetexpression_node = node.child(at: 0),
keysetexpression_node.nodeType == "keysetExpression"
@@ -337,94 +258,56 @@ extension SelectCaseExpression: CompilableExpression {
return Result.Error(Error(withMessage: "Missing target state in select case"))
}
let maybe_parsed_keysetexpression = KeysetExpression.compile(
let maybe_parsed_keysetexpression = AST.KeysetExpression.CompileExpression(
node: keysetexpression_node, withContext: context)
guard case Result.Ok(let maybe_keysetexpression) = maybe_parsed_keysetexpression else {
return Result.Error(maybe_parsed_keysetexpression.error()!)
}
guard let maybe_keysetexpression = maybe_keysetexpression else {
return Result.Error(
ErrorWithLocation(
sourceLocation: keysetexpression_node.toSourceLocation(),
withError: "Missing expected keyset expression"))
}
let keysetexpression = maybe_keysetexpression as! AST.KeysetExpression
let keysetexpression = maybe_keysetexpression as! KeysetExpression
if case .Error(let e) = keysetexpression.compatible(type: context.expected_type!) {
return .Error(
ErrorWithLocation(
sourceLocation: keysetexpression_node.toSourceLocation(), withError: e.msg()))
}
let maybe_parsed_targetstate = Identifier.Compile(
let maybe_parsed_targetstate = AST.Identifier.CompileExpression(
node: targetstate_node, withContext: context)
guard case .Ok(let targetstate) = maybe_parsed_targetstate else {
return Result.Error(maybe_parsed_targetstate.error()!)
}
return .Ok(
SelectCaseExpression(
withKey: keysetexpression, withNextState: targetstate)
AST.SelectCaseExpression(
withKey: keysetexpression, withNextState: targetstate as! AST.Identifier)
)
}
}
// swift-format-ignore
public typealias BinaryOperatorChecker = (P4Expression, P4Expression) -> Result<()>
public func binary_and_or_operator_checker(
left: P4Expression, right: P4Expression
) -> Result<()> {
// Check that both are Boolean-typed things!
if !(left.type().baseType().eq(rhs: P4Boolean()) && right.type().baseType().eq(rhs: P4Boolean()))
{
return .Error(Error(withMessage: "And/Or on operands with non-bool type is not allowed"))
}
return .Ok(())
}
public func binary_int_math_operator_checker(
left: P4Expression, right: P4Expression
) -> Result<()> {
// Check that both are int-typed things!
if !(left.type().baseType().eq(rhs: P4Int()) && right.type().baseType().eq(rhs: P4Int())) {
return .Error(
Error(withMessage: "Mathematical operation on operands with non-int type is not allowed"))
}
return .Ok(())
}
extension BinaryOperatorExpression: CompilableExpression {
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<(P4Expression)?> {
extension AST.BinaryOperatorExpression: CompilableExpression {
public static func CompileExpression(
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
node: expression, type: "binaryOperatorExpression")
#RequireNodeType<Node, AST.AnExpression>(
node: expression, type: "binaryOperatorExpression",
nice_type_name: "Binary Operator Expression")
let binary_operator_expression_node = expression.child(at: 0)!
var walker = Walker(node: binary_operator_expression_node)
var current_node: Node? = .none
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed binary operator expression"
)))
/// TODO: This macro cannot handle new lines in the arrays
// swift-format-ignore
#RequireNodesType<Node, P4Expression?>(
#RequireNodesType<Node, AST.AnExpression>(
nodes: binary_operator_expression_node,
type: ["binaryEqualOperatorExpression", "binaryLessThanOperatorExpression", "binaryLessThanEqualOperatorExpression", "binaryGreaterThanOperatorExpression", "binaryGreaterThanEqualOperatorExpression", "binaryAndOperatorExpression", "binaryOrOperatorExpression", "binaryAddOperatorExpression", "binarySubtractOperatorExpression", "binaryMultiplyOperatorExpression", "binaryDivideOperatorExpression"],
nice_type_names: [ "binary equal operator", "binary less than operator", "binary less than or equal to operator", "binary greater than operator", "binary greater than or equal to operator", "binary and operator", "binary or operator", "binary add operator", "binary subtract operator", "binary multiply operator", "binary divide operator"])
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing LHS for binary operator expression")))
@@ -434,7 +317,7 @@ extension BinaryOperatorExpression: CompilableExpression {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing binary operator for binary operator expression")))
@@ -442,105 +325,92 @@ extension BinaryOperatorExpression: CompilableExpression {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing RHS for binary operator expression")))
let right_hand_side_raw = current_node!
let maybe_left_hand_side = Expression.Compile(node: left_hand_side_raw, withContext: context)
let maybe_left_hand_side = AST.Expression.Compile(
node: left_hand_side_raw, withContext: context)
guard case Result.Ok(let left_hand_side) = maybe_left_hand_side else {
return Result.Error(maybe_left_hand_side.error()!)
}
let maybe_right_hand_side = Expression.Compile(node: right_hand_side_raw, withContext: context)
let maybe_right_hand_side = AST.Expression.Compile(
node: right_hand_side_raw, withContext: context)
guard case Result.Ok(let right_hand_side) = maybe_right_hand_side else {
return Result.Error(maybe_right_hand_side.error()!)
}
let evaluators:
[String: (String, P4QualifiedType, BinaryOperatorChecker?, BinaryOperatorEvaluator)] = [
"binaryEqualOperatorExpression": (
"Binary Equal", P4QualifiedType(P4Boolean()), Optional<BinaryOperatorChecker>.none,
binary_equal_operator_evaluator
),
"binaryLessThanOperatorExpression": (
"Binary Less Than", P4QualifiedType(P4Boolean()), Optional<BinaryOperatorChecker>.none,
binary_lt_operator_evaluator
),
"binaryLessThanEqualOperatorExpression": (
"Binary Less Than Or Equal", P4QualifiedType(P4Boolean()),
Optional<BinaryOperatorChecker>.none,
binary_lte_operator_evaluator
),
"binaryGreaterThanOperatorExpression": (
"Binary Greater Than", P4QualifiedType(P4Boolean()), Optional<BinaryOperatorChecker>.none,
binary_gt_operator_evaluator
),
"binaryGreaterThanEqualOperatorExpression": (
"Binary Greater Than Or Equal", P4QualifiedType(P4Boolean()),
Optional<BinaryOperatorChecker>.none,
binary_gte_operator_evaluator
),
"binaryAndOperatorExpression": (
"Binary Or", P4QualifiedType(P4Boolean()), binary_and_or_operator_checker,
binary_and_operator_evaluator
),
"binaryOrOperatorExpression": (
"Binary And", P4QualifiedType(P4Boolean()), binary_and_or_operator_checker,
binary_or_operator_evaluator
),
"binaryAddOperatorExpression": (
"Binary Add", P4QualifiedType(P4Int()), binary_int_math_operator_checker,
binary_add_operator_evaluator
),
"binarySubtractOperatorExpression": (
"Binary Subtract", P4QualifiedType(P4Int()), binary_int_math_operator_checker,
binary_subtract_operator_evaluator
),
"binaryMultiplyOperatorExpression": (
"Binary Multiply", P4QualifiedType(P4Int()), binary_int_math_operator_checker,
binary_multiply_operator_evaluator
),
"binaryDivideOperatorExpression": (
"Binary Divide", P4QualifiedType(P4Int()), binary_int_math_operator_checker,
binary_divide_operator_evaluator
),
]
if !left_hand_side.type().eq(right_hand_side.type()) {
return Result.Error(
Error(withMessage: "Types of values used with binary expression are not the same"))
}
let evaluators: [String: (String, P4QualifiedType, AST.BinaryOperatorExpressionType)] = [
"binaryEqualOperatorExpression": (
"Binary Equal", P4QualifiedType(P4Boolean()),
AST.BinaryOperatorExpressionType.Eq
),
"binaryLessThanOperatorExpression": (
"Binary Less Than", P4QualifiedType(P4Boolean()),
AST.BinaryOperatorExpressionType.Lt
),
"binaryLessThanEqualOperatorExpression": (
"Binary Less Than Or Equal", P4QualifiedType(P4Boolean()),
AST.BinaryOperatorExpressionType.Lte
),
"binaryGreaterThanOperatorExpression": (
"Binary Greater Than", P4QualifiedType(P4Boolean()),
AST.BinaryOperatorExpressionType.Gt
),
"binaryGreaterThanEqualOperatorExpression": (
"Binary Greater Than Or Equal", P4QualifiedType(P4Boolean()),
AST.BinaryOperatorExpressionType.Gte
),
"binaryAndOperatorExpression": (
"Binary Or", P4QualifiedType(P4Boolean()),
AST.BinaryOperatorExpressionType.And
),
"binaryOrOperatorExpression": (
"Binary And", P4QualifiedType(P4Boolean()),
AST.BinaryOperatorExpressionType.Or
),
"binaryAddOperatorExpression": (
"Binary Add", P4QualifiedType(P4Int()),
AST.BinaryOperatorExpressionType.Add
),
"binarySubtractOperatorExpression": (
"Binary Subtract", P4QualifiedType(P4Int()),
AST.BinaryOperatorExpressionType.Subtract
),
"binaryMultiplyOperatorExpression": (
"Binary Multiply", P4QualifiedType(P4Int()),
AST.BinaryOperatorExpressionType.Multiply
),
"binaryDivideOperatorExpression": (
"Binary Divide", P4QualifiedType(P4Int()),
AST.BinaryOperatorExpressionType.Divide
),
]
guard let selected_evaluator = evaluators[binary_operator_expression_node.nodeType!] else {
return Result.Error(
Error(withMessage: "No evaluator for \(binary_operator_expression_node.nodeType!)"))
}
if let checker = selected_evaluator.2,
case .Error(let e) = checker(left_hand_side, right_hand_side)
{
return Result.Error(e)
}
return .Ok(
BinaryOperatorExpression(
withEvaluator: (selected_evaluator.0, selected_evaluator.1, selected_evaluator.3),
AST.BinaryOperatorExpression(
withType: selected_evaluator.2,
withLhs: left_hand_side, withRhs: right_hand_side))
}
}
extension ArrayAccessExpression: CompilableExpression {
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<P4Expression?> {
extension AST.ArrayAccessExpression: CompilableExpression {
public static func CompileExpression(
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
node: expression, type: "arrayAccessExpression")
#RequireNodeType<Node, AST.AnExpression>(
node: expression, type: "arrayAccessExpression", nice_type_name: "Array Access Expression")
let array_access_expression_node = expression
var walker = Walker(node: array_access_expression_node)
@@ -548,11 +418,11 @@ extension ArrayAccessExpression: CompilableExpression {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed array access expression")))
#RequireNodeType<Node, P4Expression?>(
#RequireNodeType<Node, AST.AnExpression>(
node: current_node!, type: "expression",
nice_type_name: "array identifier expression")
let array_access_identifier_node = current_node!
@@ -560,7 +430,7 @@ extension ArrayAccessExpression: CompilableExpression {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing [ for array access expression")))
@@ -569,52 +439,43 @@ extension ArrayAccessExpression: CompilableExpression {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing indexor expression for array access expression")))
#RequireNodeType<Node, P4Expression?>(
#RequireNodeType<Node, AST.AnExpression>(
node: current_node!, type: "expression",
nice_type_name: "array indexor expression")
let array_access_indexor_node = current_node!
let maybe_array_identifier = Expression.Compile(
let maybe_array_identifier = AST.Expression.Compile(
node: array_access_identifier_node, withContext: context)
guard case Result.Ok(let array_identifier) = maybe_array_identifier else {
return Result.Error(maybe_array_identifier.error()!)
}
let maybe_array_type = array_identifier.type()
guard let array_type = maybe_array_type.baseType() as? P4Array else {
return Result.Error(
ErrorWithLocation(
sourceLocation: array_access_identifier_node.toSourceLocation(),
withError: "\(array_identifier) does not name an array type")
)
}
let maybe_array_indexor = Expression.Compile(
let maybe_array_indexor = AST.Expression.Compile(
node: array_access_indexor_node, withContext: context)
guard case Result.Ok(let array_indexor) = maybe_array_indexor else {
return Result.Error(maybe_array_indexor.error()!)
}
return .Ok(
ArrayAccessExpression(
withName: array_identifier, withType: array_type, withIndexor: array_indexor))
AST.ArrayAccessExpression(
withName: array_identifier, withIndexor: array_indexor))
}
}
extension FieldAccessExpression: CompilableExpression {
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<P4Expression?> {
extension AST.FieldAccessExpression: CompilableExpression {
public static func CompileExpression(
node: SwiftTreeSitter.Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
node: expression, type: "fieldAccessExpression")
#RequireNodeType<Node, AST.AnExpression>(
node: expression, type: "fieldAccessExpression", nice_type_name: "Array Access Expression")
let field_access_expression_node = expression
@@ -623,11 +484,11 @@ extension FieldAccessExpression: CompilableExpression {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed field access expression")))
#RequireNodeType<Node, P4Expression?>(
#RequireNodeType<Node, AST.AnExpression>(
node: current_node!, type: "expression",
nice_type_name: "struct identifier expression")
let struct_identifier_node = current_node!
@@ -635,7 +496,7 @@ extension FieldAccessExpression: CompilableExpression {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing . for field access expression")))
@@ -643,198 +504,73 @@ extension FieldAccessExpression: CompilableExpression {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing field name for field access expression")))
#RequireNodeType<Node, P4Expression?>(
#RequireNodeType<Node, AST.AnExpression>(
node: current_node!, type: "identifier",
nice_type_name: "field name")
let field_name_node = current_node!
// Make sure that the identifier really identifies a struct.
let maybe_struct_identifier = Expression.Compile(
let maybe_struct_identifier = AST.Expression.Compile(
node: struct_identifier_node, withContext: context)
guard case Result.Ok(let struct_identifier) = maybe_struct_identifier else {
return Result.Error(maybe_struct_identifier.error()!)
}
guard let struct_type = struct_identifier.type().baseType() as? P4Struct else {
return .Error(
ErrorWithLocation(
sourceLocation: struct_identifier_node.toSourceLocation(),
withError: "\(struct_identifier_node.text!) does not have struct type"))
}
let maybe_field_name = Identifier.Compile(
let maybe_field_name = AST.Identifier.CompileExpression(
node: field_name_node, withContext: context)
guard case Result.Ok(let field_name) = maybe_field_name else {
return Result.Error(maybe_field_name.error()!)
}
// Make sure that the field is valid for the struct type.
let maybe_field_type = struct_type.fields.get_field_type(field_name)
guard let field_type = maybe_field_type else {
return .Error(
ErrorWithLocation(
sourceLocation: field_name_node.toSourceLocation(),
withError: "\(field_name) is not a valid field for struct with type \(struct_type)"))
}
return .Ok(
FieldAccessExpression(
AST.FieldAccessExpression(
withStruct: struct_identifier,
withField: P4StructFieldIdentifier(id: field_name, withType: field_type)))
withField: field_name as! AST.Identifier))
}
}
extension FieldAccessExpression: CompilableLValueExpression {
public static func compile_as_lvalue(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<P4LValueExpression?> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
node: expression, type: "fieldAccessExpression")
let maybe_parsed_expression = FieldAccessExpression.compile(node: node, withContext: context)
guard case .Ok(let maybe_field_access_expression) = maybe_parsed_expression else {
return .Error(maybe_parsed_expression.error()!)
}
let field_access_expression = maybe_field_access_expression as! FieldAccessExpression
return Result.Ok(field_access_expression)
}
}
extension ArrayAccessExpression: CompilableLValueExpression {
public static func compile_as_lvalue(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<P4LValueExpression?> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
node: expression, type: "arrayAccessExpression")
let maybe_parsed_expression = ArrayAccessExpression.compile(node: node, withContext: context)
guard case .Ok(let maybe_array_access_expression) = maybe_parsed_expression else {
return .Error(maybe_parsed_expression.error()!)
}
let array_access_expression = maybe_array_access_expression as! ArrayAccessExpression
return Result.Ok(array_access_expression)
}
}
extension FunctionCall: CompilableExpression {
public static func compile(
node: Node, withContext context: CompilerContext
) -> Result<P4Expression?> {
extension AST.FunctionCall: CompilableExpression {
public static func CompileExpression(
node: Node, withContext context: ASTCompilerContext
) -> Result<AST.AnExpression> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
node: expression, type: "function_call")
#RequireNodeType<Node, AST.AnExpression>(
node: expression, type: "function_call", nice_type_name: "Function Call")
var walker = Walker(node: expression)
var current_node: Node? = .none
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
let maybe_callee_name = Identifier.Compile(
let maybe_callee_name = AST.Identifier.CompileExpression(
node: current_node!, withContext: context)
guard case .Ok(let callee_name) = maybe_callee_name else {
return Result.Error(maybe_callee_name.error()!)
}
var maybe_callee: Result<(FunctionDeclaration?, Declaration?)> =
switch context.types.lookup(identifier: callee_name) {
case .Ok(let looked_up):
switch looked_up {
case let callee as FunctionDeclaration:
Result<(FunctionDeclaration?, Declaration?)>.Ok((callee, .none)) // What we found is actually a function declaration
default:
Result<(FunctionDeclaration?, Declaration?)>.Error(
ErrorWithLocation(
sourceLocation: current_node!.toSourceLocation(),
withError: "\(callee_name) is not a function"))
}
case .Error(let e): Result<(FunctionDeclaration?, Declaration?)>.Error(e)
}
maybe_callee =
if case .Error(let e) = maybe_callee {
switch context.externs.lookup(identifier: callee_name) {
case .Ok(let callee as Declaration):
// Now, make sure that it is a function declaration!
switch callee.identifier.type.baseType() {
case is FunctionDeclaration: Result.Ok((.none, callee))
default:
.Error(
ErrorWithLocation(
sourceLocation: current_node!.toSourceLocation(),
withError: "\(callee_name) is not a function"))
}
default: .Error(e)
}
} else {
maybe_callee
}
guard case .Ok(let callee) = maybe_callee else {
return .Error(maybe_callee.error()!)
}
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<P4Expression?>.Error(
or: Result<AST.AnExpression>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
let maybe_argument_list = ArgumentList.Compile(node: current_node!, withContext: context)
let maybe_argument_list = AST.ArgumentList.Compile(node: current_node!, withContext: context)
guard case .Ok(let arguments) = maybe_argument_list else {
return .Error(maybe_argument_list.error()!)
}
// Now, compare the arguments with the parameters:
let params =
switch callee {
case (.some(let callee), .none): Optional<ParameterList>.some(callee.params)
case (.none, .some(let callee)):
Optional<ParameterList>.some((callee.ffi!.type().baseType() as! FunctionDeclaration).params)
default: Optional<ParameterList>.none
}
guard case .some(let params) = params else {
return Result.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Could not lookup the parameters for the called function (\(callee_name))"))
}
if case .Error(let e) = arguments.compatible(params) {
return .Error(e)
}
// All good!
return switch callee {
case (.some(let callee), .none): .Ok(FunctionCall(callee, withArguments: arguments))
case (.none, .some(let callee)): .Ok(FunctionCall(callee.ffi!, withArguments: arguments))
default:
Result.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Unexpected error occurred calling function named (\(callee_name))"
))
}
return .Ok(AST.FunctionCall(callee_name as! AST.Identifier, withArguments: arguments))
}
}