diff --git a/Sources/P4Compiler/Compiler.swift b/Sources/P4Compiler/Compiler.swift
index e5f2c68..0a6ea97 100644
--- a/Sources/P4Compiler/Compiler.swift
+++ b/Sources/P4Compiler/Compiler.swift
@@ -42,16 +42,16 @@ public func ErrorOnNode(node: Node, withError error: String) -> Error {
/// Context for compilation.
public struct CompilerContext {
- let names: VarTypeScopes
+ let instances: VarTypeScopes
let types: TypeTypeScopes
- public init(withNames _names: VarTypeScopes) {
- names = _names
+ public init(withInstances _instances: VarTypeScopes) {
+ instances = _instances
types = TypeTypeScopes()
}
- public init(withNames _names: VarTypeScopes, withTypes _types: TypeTypeScopes) {
- names = _names
+ public init(withInstances _instances: VarTypeScopes, withTypes _types: TypeTypeScopes) {
+ instances = _instances
types = _types
}
@@ -61,8 +61,8 @@ public struct CompilerContext {
///
/// - Parameter names: a ``TypeScopes`` with the updated names for the newly created compiler context.
/// - Returns: A new compiler context based on the current with the same types and new names.
- public func update(newNames names: VarTypeScopes) -> CompilerContext {
- return CompilerContext(withNames: names, withTypes: self.types)
+ public func update(newInstances instances: VarTypeScopes) -> CompilerContext {
+ return CompilerContext(withInstances: instances, withTypes: self.types)
}
/// Update a compiler context
@@ -72,7 +72,7 @@ public struct CompilerContext {
/// - Parameter types: a ``TypeScopes`` with the updated types for the newly created compiler context.
/// - Returns: A new compiler context based on the current with the same names and new types.
public func update(newTypes types: TypeTypeScopes) -> CompilerContext {
- return CompilerContext(withNames: self.names, withTypes: types)
+ return CompilerContext(withInstances: self.instances, withTypes: types)
}
}
diff --git a/Sources/P4Compiler/Declarations.swift b/Sources/P4Compiler/Declarations.swift
new file mode 100644
index 0000000..b4d8857
--- /dev/null
+++ b/Sources/P4Compiler/Declarations.swift
@@ -0,0 +1,262 @@
+// 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
+
+extension Declaration: CompilableDeclaration {
+ public static func Compile(
+ node: Node, withContext context: CompilerContext
+ ) -> Result<(P4Type, CompilerContext)?> {
+
+ guard let node_type = node.nodeType,
+ node_type == "type_declaration"
+ else {
+ return .Ok(.none)
+ }
+
+ // Assume that it is a struct declaration
+ return StructDeclaration.Compile(node: node.child(at: 0)!, withContext: context)
+ }
+}
+
+struct StructDeclaration {
+ static func Compile(
+ node: Node, withContext context: CompilerContext
+ ) -> Result<(P4Type, CompilerContext)?> {
+
+ var currentChildIdx = 0
+ var currentChildIdxSafe = 1
+
+ var currentChild: Node? = .none
+
+ guard let node_type = node.nodeType,
+ node_type == "struct_declaration"
+ else {
+ return Result.Error(
+ ErrorOnNode(node: node, withError: "Did not find a struct declaration"))
+ }
+
+ if node.childCount < currentChildIdxSafe {
+ return Result.Error(
+ ErrorOnNode(node: node, withError: "Missing elements in struct declaration"))
+ }
+
+ // Skip the keyword struct
+ currentChildIdx += 1
+ currentChildIdxSafe += 1
+ if node.childCount < currentChildIdxSafe {
+ return Result.Error(
+ ErrorOnNode(node: node, withError: "Missing elements in struct declaration"))
+ }
+
+ // The name of the struct type.
+ currentChild = node.child(at: currentChildIdx)
+ let maybe_struct_identifier = Identifier.Compile(
+ node: currentChild!, withContext: context)
+ guard case Result.Ok(let struct_identifier) = maybe_struct_identifier else {
+ return Result.Error(maybe_struct_identifier.error()!)
+ }
+
+ currentChildIdx += 1
+ currentChildIdxSafe += 1
+
+ // Skip the '{'
+ currentChildIdx += 1
+ currentChildIdxSafe += 1
+ if node.childCount < currentChildIdxSafe {
+ return Result.Error(
+ ErrorOnNode(node: node, withError: "Missing element of struct declaration"))
+ }
+
+ currentChild = node.child(at: currentChildIdx)
+
+ // If there are no fields, it will be a "}"
+ if currentChild!.nodeType == "}" {
+ let struc = P4Struct(withName: struct_identifier, andFields: P4StructFields([]))
+ return Result.Ok(
+ (
+ struc,
+ context.update(
+ newTypes: context.types.declare(identifier: struct_identifier, withValue: struc))
+ ))
+ }
+
+ var parse_errs: [Error] = Array()
+ var current_context = context
+ var parsed_fields: [P4StructFieldIdentifier] = Array()
+
+ if currentChild!.nodeType == "struct_declaration_fields" {
+ currentChild!.enumerateNamedChildren { declaration_field in
+ print("declaration field: \(declaration_field)")
+ switch VariableDeclarationStatement.Compile(
+ node: declaration_field, withContext: current_context)
+ {
+ case .Ok((let declaration, let updated_context)):
+ let variable_declaration = declaration as! VariableDeclarationStatement
+ parsed_fields.append(
+ P4StructFieldIdentifier(
+ id: variable_declaration.identifier, withType: variable_declaration.initializer.type()
+ ))
+ current_context = updated_context
+ case .Error(let e): parse_errs.append(e)
+ }
+ }
+ }
+
+ if !parse_errs.isEmpty {
+ return .Error(
+ Error(
+ withMessage: "Error(s) parsing select cases: "
+ + (parse_errs.map { error in
+ return "\(error.msg)"
+ }.joined(separator: ";"))))
+ }
+
+ let declared_struct = P4Struct(
+ withName: struct_identifier, andFields: P4StructFields(parsed_fields))
+ return .Ok(
+ (
+ declared_struct,
+ current_context.update(
+ newTypes: current_context.types.declare(
+ identifier: struct_identifier, withValue: declared_struct))
+ ))
+ }
+}
+
+extension P4Lang.Parser: CompilableDeclaration {
+ public static func Compile(
+ node: Node, withContext context: CompilerContext
+ ) -> Result<(P4Type, CompilerContext)?> {
+
+ let parser_node = node
+ if parser_node.nodeType != "parserDeclaration" {
+ return .Ok(.none)
+ }
+
+ var currentChildIdx = 0
+ var currentChildIdxSafe = 1
+ var currentChild: Node? = .none
+
+ if parser_node.childCount < currentChildIdxSafe {
+ return .Error(
+ ErrorOnNode(node: parser_node, withError: "Missing elements of parser declaration"))
+ }
+
+ currentChild = parser_node.child(at: currentChildIdx)
+ if currentChild!.nodeType != "parserType" {
+ return .Error(
+ ErrorOnNode(node: currentChild!, withError: "Missing type for parser declaration"))
+ }
+
+ let type_node = currentChild
+ var parser_name: Common.Identifier? = .none
+
+ do {
+ // Parse the parser type (type_node)
+ var currentChildIdx = 0
+ var currentChildIdxSafe = 1
+
+ if type_node!.childCount < currentChildIdxSafe {
+ return .Error(
+ ErrorOnNode(
+ node: parser_node, withError: "Missing elements of parser type in parser declaration"))
+ }
+
+ var currentChild = type_node!.child(at: currentChildIdx)
+ if currentChild!.nodeType == "annotations" {
+ return .Error(
+ ErrorOnNode(
+ node: currentChild!, withError: "Annotations in parser type are not yet handled."))
+ // Will increment indexes here.
+ }
+
+ // Skip the parser keyword
+ currentChildIdx += 1
+ currentChildIdxSafe += 1
+ if type_node!.childCount < currentChildIdxSafe {
+ return .Error(
+ ErrorOnNode(node: type_node!, withError: "Missing name in parser type declaration"))
+ }
+ currentChild = type_node?.child(at: currentChildIdx)
+
+ switch Identifier.Compile(node: currentChild!, withContext: context) {
+ case .Ok(let id): parser_name = id
+ case .Error(let e):
+ return .Error(e)
+ }
+ }
+
+ currentChildIdx += 1
+ currentChildIdxSafe += 1
+ if parser_node.childCount < currentChildIdxSafe {
+ return .Error(
+ ErrorOnNode(node: parser_node, withError: "Missing elements of parser declaration"))
+ }
+
+ if currentChild!.nodeType == "constructorParameters" {
+ return .Error(
+ ErrorOnNode(node: currentChild!, withError: "Constructor parameters are not yet handled.")
+ )
+ // Will increment indexes here.
+ }
+
+ // Skip the '{'
+ currentChildIdx += 1
+ currentChildIdxSafe += 1
+ if parser_node.childCount < currentChildIdxSafe {
+ return .Error((Error(withMessage: "Missing body of parser declaration")))
+ }
+ currentChild = parser_node.child(at: currentChildIdx)
+
+ if currentChild!.nodeType == "parserLocalElements" {
+ return .Error(
+ ErrorOnNode(node: currentChild!, withError: "Parser Local Elements are not yet handled."))
+ // Will increment indexes here.
+ }
+
+ if parser_node.childCount < currentChildIdxSafe {
+ return .Error((Error(withMessage: "Missing body of parser declaration")))
+ }
+
+ if currentChild!.nodeType != "parserStates" {
+ return .Error(Error(withMessage: "Missing parser states in parser declaration"))
+ }
+
+ switch Parser.Compile(
+ withName: parser_name!, node: currentChild!, withContext: context)
+ {
+ case Result.Ok((let parser, let updated_context)):
+ // Create a new context with the name of the parser that was just compiled in scope.
+ return .Ok(
+ (
+ parser,
+ context.update(
+ newInstances: updated_context.instances.declare(
+ identifier: parser.name, withValue: parser))
+ ))
+ case Result.Error(let error): return .Error(error)
+ }
+
+ // Assume that there is only '}' after -- the parser guaranteed that for us!
+ }
+}
diff --git a/Sources/P4Compiler/Expression.swift b/Sources/P4Compiler/Expression.swift
index 262b23f..8b58d8d 100644
--- a/Sources/P4Compiler/Expression.swift
+++ b/Sources/P4Compiler/Expression.swift
@@ -43,7 +43,7 @@ extension TypedIdentifier: CompilableExpression {
node: node, type: "identifier")
guard
- case Result.Ok(let type) = context.names.lookup(
+ case Result.Ok(let type) = context.instances.lookup(
identifier: Common.Identifier(name: node.text!))
else {
return .Error(ErrorOnNode(node: node, withError: "Cannot find \(node.text!) in scope"))
diff --git a/Sources/P4Compiler/Parser.swift b/Sources/P4Compiler/Parser.swift
index 510c9ce..6293f0e 100644
--- a/Sources/P4Compiler/Parser.swift
+++ b/Sources/P4Compiler/Parser.swift
@@ -284,7 +284,8 @@ public struct Parser {
// Parse a state in a nested scope.
switch Parser.State.Compile(
- node: parser_state, withContext: context.update(newNames: current_context.names.enter()))
+ node: parser_state,
+ withContext: context.update(newInstances: current_context.instances.enter()))
{
case Result.Ok(let (state, updated_context)):
parser.states = parser.states.append(state: state)
diff --git a/Sources/P4Compiler/Program.swift b/Sources/P4Compiler/Program.swift
index 5bbe881..7327fbc 100644
--- a/Sources/P4Compiler/Program.swift
+++ b/Sources/P4Compiler/Program.swift
@@ -54,13 +54,14 @@ public struct Program {
var program = P4Lang.Program()
// Set up a context for parsing.
- var compilation_context = CompilerContext(withNames: VarTypeScopes().enter())
+ var compilation_context = CompilerContext(
+ withInstances: VarTypeScopes().enter(), withTypes: TypeTypeScopes().enter())
var errors: [Error] = Array()
// If the caller gave any global instances, add them here.
if let globalInstances = globalInstances {
- compilation_context = compilation_context.update(newNames: globalInstances)
+ compilation_context = compilation_context.update(newInstances: globalInstances)
}
// If the caller gave any global types, add them here.
@@ -68,135 +69,36 @@ public struct Program {
compilation_context = compilation_context.update(newTypes: globalTypes)
}
- result?.rootNode?.enumerateNamedChildren { declaration_node in
- if declaration_node.nodeType != "declaration" {
- return
- }
+ // Try to parse all top-level declarations.
+ result?.rootNode?.enumerateNamedChildren { (declaration_node: Node) in
+ let specific_declaration_node = declaration_node.child(at: 0)!
- let parser_node = declaration_node.child(at: 0)!
- if parser_node.nodeType != "parserDeclaration" {
- return
- }
+ let declaration_parsers: [CompilableDeclaration.Type] = [
+ Declaration.self, P4Lang.Parser.self,
+ ]
+ var found_parser = false
- var currentChildIdx = 0
- var currentChildIdxSafe = 1
- var currentChild: Node? = .none
-
- if parser_node.childCount < currentChildIdxSafe {
- errors.append(
- ErrorOnNode(node: parser_node, withError: "Missing elements of parser declaration"))
- return
- }
- currentChild = parser_node.child(at: currentChildIdx)
- if currentChild!.nodeType != "parserType" {
- errors.append(
- ErrorOnNode(node: currentChild!, withError: "Missing type for parser declaration"))
- return
- }
-
- let type_node = currentChild
- var parser_name: Common.Identifier? = .none
-
- do {
- // Parse the parser type (type_node)
- var currentChildIdx = 0
- var currentChildIdxSafe = 1
-
- if type_node!.childCount < currentChildIdxSafe {
- errors.append(
- ErrorOnNode(
- node: parser_node, withError: "Missing elements of parser type in parser declaration")
- )
- return
- }
-
- var currentChild = type_node!.child(at: currentChildIdx)
- if currentChild!.nodeType == "annotations" {
- errors.append(
- ErrorOnNode(
- node: currentChild!, withError: "Annotations in parser type are not yet handled."))
- return
-
- // Will increment indexes here.
- }
-
- // Skip the parser keyword
- currentChildIdx += 1
- currentChildIdxSafe += 1
- if type_node!.childCount < currentChildIdxSafe {
- errors.append(
- ErrorOnNode(node: type_node!, withError: "Missing name in parser type declaration"))
- return
- }
- currentChild = type_node?.child(at: currentChildIdx)
-
- switch Identifier.Compile(node: currentChild!, withContext: compilation_context) {
- case .Ok(let id): parser_name = id
+ for parser in declaration_parsers {
+ switch parser.Compile(node: specific_declaration_node, withContext: compilation_context) {
+ case .Ok(.none): {}()
+ case .Ok(.some((_, let updated_context))):
+ found_parser = true
+ compilation_context = updated_context
+ break
case .Error(let e):
+ found_parser = true
errors.append(e)
- return
+ break
}
}
- // It's an error if there is no parser name.
- if parser_name == .none {
- return
- }
-
- currentChildIdx += 1
- currentChildIdxSafe += 1
- if parser_node.childCount < currentChildIdxSafe {
+ // If none of the declaration parsers chose to parse, that's an error, too!
+ if !found_parser {
errors.append(
- ErrorOnNode(node: parser_node, withError: "Constructor parameters are not yet handled."))
- return
+ ErrorOnNode(
+ node: specific_declaration_node, withError: "Could not find parser for declaration node"
+ ))
}
-
- if currentChild!.nodeType == "constructorParameters" {
- errors.append(
- ErrorOnNode(node: currentChild!, withError: "Constructor parameters are not yet handled.")
- )
- return
-
- // Will increment indexes here.
- }
-
- // Skip the '{'
- currentChildIdx += 1
- currentChildIdxSafe += 1
- if parser_node.childCount < currentChildIdxSafe {
- errors.append(Error(withMessage: "Missing body of parser declaration"))
- return
- }
- currentChild = parser_node.child(at: currentChildIdx)
-
- if currentChild!.nodeType == "parserLocalElements" {
- errors.append(
- ErrorOnNode(node: currentChild!, withError: "Parser Local Elements are not yet handled."))
- return
- // Will increment indexes here.
- }
-
- if parser_node.childCount < currentChildIdxSafe {
- errors.append(Error(withMessage: "Missing body of parser declaration"))
- return
- }
-
- if currentChild!.nodeType != "parserStates" {
- errors.append(Error(withMessage: "Missing parser states in parser declaration"))
- return
- }
-
- switch Parser.Compile(
- withName: parser_name!, node: currentChild!, withContext: compilation_context)
- {
- case Result.Ok((let parser, let updated_context)):
- // Create a new context with the name of the parser that was just compiled in scope.
- compilation_context = compilation_context.update(
- newNames: updated_context.names.declare(identifier: parser.name, withValue: parser))
- case Result.Error(let error): errors.append(error)
- }
-
- // Assume that there is only '}' after -- the parser guaranteed that for us!
}
if !errors.isEmpty {
@@ -207,9 +109,15 @@ public struct Program {
}.joined(separator: ";")))
}
+ // Any of the instances that are in the top-level scope should go into the program!
+ program.instances = Array(
+ compilation_context.instances.map { (_, v) in
+ v
+ })
+
// Any of the types that are in the top-level scope should go into the program!
program.types = Array(
- compilation_context.names.map { (_, v) in
+ compilation_context.types.map { (_, v) in
v
})
return Result.Ok(program)
diff --git a/Sources/P4Compiler/Protocols.swift b/Sources/P4Compiler/Protocols.swift
index ee3b562..60d725f 100644
--- a/Sources/P4Compiler/Protocols.swift
+++ b/Sources/P4Compiler/Protocols.swift
@@ -37,3 +37,9 @@ public protocol CompilableType {
type: SwiftTreeSitter.Node, withContext: CompilerContext
) -> Result
}
+
+public protocol CompilableDeclaration {
+ static func Compile(
+ node: Node, withContext context: CompilerContext
+ ) -> Result<(P4Type, CompilerContext)?>
+}
diff --git a/Sources/P4Compiler/Statement.swift b/Sources/P4Compiler/Statement.swift
index 42e0328..fa60e72 100644
--- a/Sources/P4Compiler/Statement.swift
+++ b/Sources/P4Compiler/Statement.swift
@@ -230,7 +230,7 @@ extension VariableDeclarationStatement: CompilableStatement {
identifier: parsed_variablename, withInitializer: initializer),
// Context with updated names to include the newly declared name.
context.update(
- newNames: context.names.declare(
+ newInstances: context.instances.declare(
identifier: parsed_variablename, withValue: declaration_p4_type))
))
}
@@ -282,7 +282,7 @@ extension ParserAssignmentStatement: CompilableStatement {
return Result.Error(maybe_parsed_lvalue.error()!)
}
- let check_result = lvalue_identifier.check(to: rvalue, inScopes: context.names)
+ let check_result = lvalue_identifier.check(to: rvalue, inScopes: context.instances)
guard case .Ok(_) = check_result else {
return Result.Error(
ErrorOnNode(
diff --git a/Sources/P4Compiler/Types.swift b/Sources/P4Compiler/Types.swift
index 904312e..fa5540d 100644
--- a/Sources/P4Compiler/Types.swift
+++ b/Sources/P4Compiler/Types.swift
@@ -50,10 +50,14 @@ 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()!)
}
+
+ print("Looking up \(parsed_type_id) in \(context.types)")
+
if case .Ok(let found_type) = context.types.lookup(identifier: parsed_type_id),
let found_struct_type = found_type as? P4Struct
{
diff --git a/Sources/P4Lang/Declarations.swift b/Sources/P4Lang/Declarations.swift
new file mode 100644
index 0000000..4562d5f
--- /dev/null
+++ b/Sources/P4Lang/Declarations.swift
@@ -0,0 +1,20 @@
+// 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
+
+public struct Declaration {}
diff --git a/Sources/P4Lang/Program.swift b/Sources/P4Lang/Program.swift
index 600640a..a2450ae 100644
--- a/Sources/P4Lang/Program.swift
+++ b/Sources/P4Lang/Program.swift
@@ -23,6 +23,7 @@ public struct ExpressionStatement {
public struct Program {
public var types: [P4Type] = Array()
+ public var instances: [P4Type] = Array()
/// Find the program's main parser
///
@@ -32,8 +33,8 @@ public struct Program {
}
public func find_parser(withName name: Identifier) -> Result {
- for type in self.types {
- guard let parser = type as? Parser else {
+ for instances in self.instances {
+ guard let parser = instances as? Parser else {
continue
}
if parser.name == name {
diff --git a/Tests/p4rseTests/Declarations.swift b/Tests/p4rseTests/Declarations.swift
new file mode 100644
index 0000000..08c71d1
--- /dev/null
+++ b/Tests/p4rseTests/Declarations.swift
@@ -0,0 +1,53 @@
+// 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 Foundation
+import Macros
+import P4Runtime
+import P4Lang
+import SwiftTreeSitter
+import Testing
+import TreeSitter
+import TreeSitterP4
+
+@testable import P4Compiler
+
+@Test func test_struct_declaration_and_field_write() async throws {
+ let simple_parser_declaration = """
+ struct Testing {
+ bool yesno;
+ int count;
+ };
+ parser main_parser() {
+ state start {
+ Testing ts;
+ ts.yesno = true;
+ bool where_to = ts.yesno;
+ transition select (where_to) {
+ true: accept;
+ false: reject;
+ };
+ }
+ };
+ """
+ let program = try #UseOkResult(
+ Program.Compile(simple_parser_declaration))
+ let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program))
+ let (state_result, _) = try! #UseOkResult(runtime.run())
+ #expect(state_result == P4Lang.accept)
+}
\ No newline at end of file
diff --git a/Tests/p4rseTests/ParserCompilerTests.swift b/Tests/p4rseTests/ParserCompilerTests.swift
index de86ec5..0b59392 100644
--- a/Tests/p4rseTests/ParserCompilerTests.swift
+++ b/Tests/p4rseTests/ParserCompilerTests.swift
@@ -61,22 +61,6 @@ import P4Lang
#expect(state.statements.count == 1)
}
-@Test func test_simple_compilation_with_instantiation() async throws {
- let simple_parser_declaration = """
- parser main_parser() {
- state start {
- true;
- false;
- transition start;
- }
- };
- bool() main;
- """
-
- let program = try #UseOkResult(Program.Compile(simple_parser_declaration))
- #expect(#RequireOkResult(program.find_parser(withName: Identifier(name: "main_parser"))))
-}
-
@Test func test_invalid_transition_expression_keyset_expressions() async throws {
let simple_parser_declaration = """
parser main_parser() {
@@ -114,5 +98,5 @@ import P4Lang
#RequireErrorResult<(EvaluatableStatement, CompilerContext)>(
Error(withMessage: "{2, 154}: Did not find assignment statement"),
ParserAssignmentStatement.Compile( // Note: Calling ParserAssignmentStatement compilation directly.
- node: result.rootNode!, withContext: CompilerContext(withNames: VarTypeScopes()))))
+ node: result.rootNode!, withContext: CompilerContext(withInstances: VarTypeScopes()))))
}
diff --git a/tree-sitter-p4/grammar.js b/tree-sitter-p4/grammar.js
index 3c6b363..0a061e9 100644
--- a/tree-sitter-p4/grammar.js
+++ b/tree-sitter-p4/grammar.js
@@ -63,7 +63,11 @@ export default grammar({
instantiation: $ => seq($.typeRef, '(', optional($.parameterList), ')', $.identifier),
// Declarations
- declaration: $ => seq(choice($.parserDeclaration, $.parserTypeDeclaration)),
+ declaration: $ => seq(choice($.parserDeclaration, $.parserTypeDeclaration, $.type_declaration)),
+
+ type_declaration: $=> choice($.struct_declaration),
+ struct_declaration: $ => seq($.struct, $.identifier, '{', optional($.struct_declaration_fields), '}'),
+ struct_declaration_fields: $=> repeat1(seq($.variableDeclaration)),
// Make separate productions for the parser type and the parser type declaration because the latter can have type parameters.
parserTypeDeclaration: $ => seq(optional($.annotations), $.parser, field('parser_name', $.identifier), optional($.typeParameters), '(', optional($.parameterList), ')'),
diff --git a/tree-sitter-p4/test/corpus/declarations.txt b/tree-sitter-p4/test/corpus/declarations.txt
index 0499221..de1321e 100644
--- a/tree-sitter-p4/test/corpus/declarations.txt
+++ b/tree-sitter-p4/test/corpus/declarations.txt
@@ -232,3 +232,31 @@ parser simple() {
)
)
+=========================
+Simple Struct Type Declaration
+=========================
+struct Testing {
+ string fieldA;
+};
+---
+(p4program
+ (declaration
+ (type_declaration
+ (struct_declaration
+ (struct)
+ (identifier)
+ (struct_declaration_fields
+ (variableDeclaration
+ (typeRef
+ (baseType
+ (string)
+ )
+ )
+ (identifier)
+ )
+ )
+ )
+ )
+ )
+)
+