Allow Declaring Instances of Structs

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-03-20 04:25:36 -04:00
parent f0d816b99f
commit aac007f1f2
7 changed files with 178 additions and 58 deletions
+12 -11
View File
@@ -64,9 +64,6 @@ public struct Parser {
"variableDeclaration": VariableDeclarationStatement.self,
"conditionalStatement": ConditionalStatement.self, "blockStatement": BlockStatement.self,
]
// Iterate through statement parsers and give each one a chance.
guard let parser = statementParsers[statement.nodeType ?? ""] else {
return Result.Error(
ErrorOnNode(
@@ -151,7 +148,7 @@ public struct Parser {
return Result.Error(ErrorOnNode(node: node, withError: "Did not find expected statements"))
}
var parse_err: Error? = .none
var parse_errs: [Error] = Array()
var current_context = context
var parsed_s: [EvaluatableStatement] = Array()
@@ -163,12 +160,14 @@ public struct Parser {
current_context = updated_context
parsed_s.append(parsed_statement)
case .Error(let e):
parse_err = e
parse_errs.append(e)
}
}
if let parse_err = parse_err {
return Result.Error(parse_err)
if !parse_errs.isEmpty {
return Result.Error(Error(withMessage: parse_errs.map() { err in
return String(err.msg)
}.joined(separator: ";")))
}
return Result.Ok((parsed_s, current_context))
}
@@ -224,7 +223,7 @@ public struct Parser {
currentChildIdx += 2
currentChildIdxSafe += 2
var parse_err: Error? = .none
var parse_errs: [Error] = Array()
var current_context = context
var parsed_s: [EvaluatableStatement] = Array()
@@ -240,14 +239,16 @@ public struct Parser {
parsed_s = state_statements
current_context = updated_context
case .Error(let error):
parse_err = error
parse_errs.append(error)
}
currentChildIdx += 1
currentChildIdxSafe += 1
}
if let parse_err = parse_err {
return Result.Error(parse_err)
if !parse_errs.isEmpty {
return Result.Error(Error(withMessage: parse_errs.map() { err in
return String(err.msg)
}.joined(separator: ";")))
}
if node.childCount < currentChildIdxSafe {
+1 -1
View File
@@ -33,5 +33,5 @@ public protocol CompilableValue {
}
public protocol CompilableType {
static func CompileType(type: String) -> Result<P4Type?>
static func CompileType(type: SwiftTreeSitter.Node, withContext: CompilerContext) -> Result<P4Type?>
}
+34 -33
View File
@@ -182,14 +182,6 @@ extension VariableDeclarationStatement: CompilableStatement {
}
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(
@@ -199,38 +191,47 @@ extension VariableDeclarationStatement: CompilableStatement {
Error(withMessage: "Could not parse variable name"))
}
let maybe_parsed_rvalue = Expression.Compile(node: rvalue, withContext: context)
guard
case .Ok(let parsed_rvalue) = maybe_parsed_rvalue
else {
return .Error(maybe_parsed_rvalue.error()!)
}
guard case .Ok(let declaration_p4_type) = Types.CompileBasicType(type: typeref.text!) else {
guard case .Ok(let declaration_p4_type) = Types.CompileType(type: typeref, withContext: context) 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.
context.update(
newNames: context.names.declare(
identifier: parsed_variablename, withValue: declaration_p4_type))
))
var initializer: EvaluatableExpression = declaration_p4_type.def()
// If there is an initializer, it must be an expression.
if let rvalue = maybe_rvalue {
guard rvalue.nodeType == "expression" else {
return Result.Error(
ErrorOnNode(
node: node,
withError: "initial value for declaration statement is not an expression"))
}
} else {
return Result.Error(
Error(
withMessage:
"Cannot initialize \(parsed_variablename) (with type \(declaration_p4_type)) from rvalue with type \(parsed_rvalue.type())"
))
let maybe_parsed_rvalue = Expression.Compile(node: rvalue, withContext: context)
guard
case .Ok(let parsed_rvalue) = maybe_parsed_rvalue
else {
return .Error(maybe_parsed_rvalue.error()!)
}
if parsed_rvalue.type().eq(rhs: declaration_p4_type) {
initializer = parsed_rvalue
} else {
return Result.Error(
Error(
withMessage:
"Cannot initialize \(parsed_variablename) (with type \(declaration_p4_type)) from rvalue with type \(parsed_rvalue.type())"
))
}
}
return Result.Ok(
(
VariableDeclarationStatement(
identifier: parsed_variablename, withInitializer: initializer),
// Context with updated names to include the newly declared name.
context.update(
newNames: context.names.declare(
identifier: parsed_variablename, withValue: declaration_p4_type))
))
}
}
+24 -9
View File
@@ -23,27 +23,42 @@ import TreeSitterExtensions
import TreeSitterP4
extension P4Boolean: CompilableType {
public static func CompileType(type: String) -> Common.Result<(any Common.P4Type)?> {
return type == "bool" ? .Ok(P4Boolean()) : .Ok(.none)
public static func CompileType(type: SwiftTreeSitter.Node, withContext: CompilerContext) -> Common.Result<(any Common.P4Type)?> {
return type.text == "bool" ? .Ok(P4Boolean()) : .Ok(.none)
}
}
extension P4Int: CompilableType {
public static func CompileType(type: String) -> Common.Result<(any Common.P4Type)?> {
return type == "int" ? .Ok(P4Int()) : .Ok(.none)
public static func CompileType(type: SwiftTreeSitter.Node, withContext: CompilerContext) -> Common.Result<(any Common.P4Type)?> {
return type.text == "int" ? .Ok(P4Int()) : .Ok(.none)
}
}
extension P4String: CompilableType {
public static func CompileType(type: String) -> Common.Result<(any Common.P4Type)?> {
return type == "string" ? .Ok(P4String()) : .Ok(.none)
public static func CompileType(type: SwiftTreeSitter.Node, withContext: CompilerContext) -> Common.Result<(any Common.P4Type)?> {
return type.text == "string" ? .Ok(P4String()) : .Ok(.none)
}
}
extension P4Struct: CompilableType {
public static func CompileType(type: SwiftTreeSitter.Node, withContext context: CompilerContext) -> Common.Result<(any Common.P4Type)?> {
let maybe_parsed_type_id = Identifier.Compile(node: type, withContext: context)
guard case .Ok(let parsed_type_id) = maybe_parsed_type_id else {
return .Error(maybe_parsed_type_id.error()!)
}
if case .Ok(let found_type) = context.types.lookup(identifier: parsed_type_id),
let found_struct_type = found_type as? P4Struct {
return .Ok(found_struct_type)
}
return .Ok(.none)
}
}
public struct Types {
static func CompileBasicType(type: String) -> Result<P4Type> {
let type_parsers: [CompilableType.Type] = [P4Boolean.self, P4Int.self, P4String.self]
static func CompileType(type: SwiftTreeSitter.Node, withContext context: CompilerContext) -> Result<P4Type> {
let type_parsers: [CompilableType.Type] = [P4Boolean.self, P4Int.self, P4String.self, P4Struct.self]
for type_parser in type_parsers {
switch type_parser.CompileType(type: type) {
switch type_parser.CompileType(type: type, withContext: context) {
case .Ok(.some(let type)): return .Ok(type)
case .Ok(.none): continue
case .Error(let e): return .Error(e)