From a7d8fd130486373d232051ed3865980ca5093cc6 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Mon, 18 May 2026 06:52:21 -0400 Subject: [PATCH] grammar,compiler: Add Support For Fixed-Width Integers Distinguishing between signed and unsigned fixed-width integer types must still be done. Signed-off-by: Will Hawkins --- Sources/Common/DataTypes.swift | 25 +++- Sources/Common/Support.swift | 2 + Sources/Macros/Macros.swift | 35 ++++- Sources/P4Compiler/Expression.swift | 38 ++++- Sources/P4Compiler/Types.swift | 37 ++++- Sources/P4Runtime/CodeGen.swift | 4 +- Tests/p4rseTests/ControlTests/Compile.swift | 2 +- .../ExpressionTests/FunctionCall.swift | 2 +- .../ExpressionTests/SelectExpression.swift | 2 +- Tests/p4rseTests/RuntimeTests.swift | 2 +- Tests/p4rseTests/StructTests.swift | 4 +- Tests/p4rseTests/SupportTests.swift | 2 +- Tests/p4rseTests/ValueTypeParserTests.swift | 134 +++++++++++++++--- tree-sitter-p4/grammar.js | 8 +- tree-sitter-p4/test/corpus/declarations.txt | 71 +++++++++- tree-sitter-p4/test/corpus/statements.txt | 8 +- 16 files changed, 328 insertions(+), 48 deletions(-) diff --git a/Sources/Common/DataTypes.swift b/Sources/Common/DataTypes.swift index 62b96bc..6ffcca0 100644 --- a/Sources/Common/DataTypes.swift +++ b/Sources/Common/DataTypes.swift @@ -424,19 +424,30 @@ public class P4BooleanValue: P4DataValue { } } +public enum BitWidth: Equatable { + case Infinite + case Width(Int) +} + /// A P4 int type public struct P4Int: P4Type { - public init() {} + let width: BitWidth + + public init(_ width: BitWidth = BitWidth.Infinite) { + self.width = width + } public var description: String { - return "Int" + return "Int (width: \(self.width))" } + public func eq(rhs: P4Type) -> Bool { return switch rhs { - case is P4Int: true + case let rrhs as P4Int: rrhs.width == self.width default: false } } + public func def() -> P4DataValue? { return P4IntValue(withValue: 0) } @@ -444,12 +455,16 @@ public struct P4Int: P4Type { /// An instance of a P4 integer public class P4IntValue: P4DataValue { + + let int_type: P4Int + public func type() -> P4Type { - return P4Int() + return int_type } let value: Int - public init(withValue value: Int) { + public init(withValue value: Int, andWidth width: BitWidth = BitWidth.Infinite) { + self.int_type = P4Int(width) self.value = value } diff --git a/Sources/Common/Support.swift b/Sources/Common/Support.swift index b1e2be5..606389b 100644 --- a/Sources/Common/Support.swift +++ b/Sources/Common/Support.swift @@ -101,6 +101,8 @@ public func Fold(input: [T], initial: A, block: (T, A) -> A) -> A { #externalMacro(module: "Macros", type: "RequireNodesType") @freestanding(codeItem) public macro SkipUnlessNodeType(node: N, type: String) = #externalMacro(module: "Macros", type: "SkipUnlessNodeType") +@freestanding(codeItem) public macro SkipUnlessNodesTypes(node: N, types: [String]) = + #externalMacro(module: "Macros", type: "SkipUnlessNodesTypes") @freestanding(codeItem) public macro MustOr(result: E, thing: E?, or: N) = #externalMacro(module: "Macros", type: "MustOr") diff --git a/Sources/Macros/Macros.swift b/Sources/Macros/Macros.swift index fcfa769..2e2f81f 100644 --- a/Sources/Macros/Macros.swift +++ b/Sources/Macros/Macros.swift @@ -229,6 +229,38 @@ public struct SkipUnlessNodeType: CodeItemMacro { } } +public struct SkipUnlessNodesTypes: CodeItemMacro { + public static func expansion( + of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext + ) throws -> [CodeBlockItemSyntax] { + + let arguments = node.arguments.indices + var arg_index = arguments.startIndex + + let node_to_check = node.arguments[arg_index].expression + + arg_index = arguments.index(after: arg_index) + guard let expected_types = node.arguments[arg_index].expression.as(ArrayExprSyntax.self) else { + throw MacroError(withMessage: "Node(s) to check must be in an array") + } + + arg_index = arguments.index(after: arg_index) + + let ifs = expected_types.elements.map { l in + "\(node_to_check).nodeType != \(l.expression)" + }.joined(separator: " && ") + + return [ + CodeBlockItemSyntax( + """ + if \(raw: ifs) { + return Result.Ok(.none) + } + """) + ] + } +} + public struct MustOr: CodeItemMacro { public static func expansion( of node: some FreestandingMacroExpansionSyntax, in context: some MacroExpansionContext @@ -261,6 +293,7 @@ public struct MustOr: CodeItemMacro { struct P4Macros: CompilerPlugin { var providingMacros: [Macro.Type] = [ RequireResult.self, RequireErrorResult.self, UseOkResult.self, UseErrorResult.self, - RequireNodeType.self, SkipUnlessNodeType.self, RequireNodesType.self, MustOr.self, + RequireNodeType.self, SkipUnlessNodeType.self, SkipUnlessNodesTypes.self, RequireNodesType.self, + MustOr.self, ] } diff --git a/Sources/P4Compiler/Expression.swift b/Sources/P4Compiler/Expression.swift index 5937a18..9fa9eae 100644 --- a/Sources/P4Compiler/Expression.swift +++ b/Sources/P4Compiler/Expression.swift @@ -101,9 +101,41 @@ extension P4IntValue: CompilableExpression { node: SwiftTreeSitter.Node, withContext context: CompilerContext ) -> Result { let node = node.child(at: 0)! - #SkipUnlessNodeType(node: node, type: "integer") - if let parsed_int = Int(node.text!) { - return .Ok(P4Value(P4IntValue(withValue: parsed_int))) + + #SkipUnlessNodesTypes( + node: node, types: ["integer", "integer_elaborated"]) + + var bit_width: BitWidth = BitWidth.Infinite + let value_source: String + if node.nodeType == "integer_elaborated" { + let re = /([0-9]+)([ws])([\-0-9]+)/ + let integer_components = node.text!.matches(of: re) + + if integer_components.isEmpty || integer_components.count > 1 { + return .Error( + ErrorWithLocation( + sourceLocation: node.toSourceLocation(), + withError: "Failed to parse elaborated integer: \(node.text!)")) + } + + let width_source = "\(integer_components[0].1)" + guard let width = Int(width_source) else { + return .Error( + ErrorWithLocation( + sourceLocation: node.toSourceLocation(), + withError: "Failed to parse width from elaborated integer: \(width_source)")) + } + + /// TODO: Handle signed vs. unsigned. + + bit_width = BitWidth.Width(width) + value_source = "\(integer_components[0].3)" + } else { + value_source = node.text! + } + + if let parsed_int = Int(value_source) { + return .Ok(P4Value(P4IntValue(withValue: parsed_int, andWidth: bit_width))) } else { return .Error( ErrorWithLocation( diff --git a/Sources/P4Compiler/Types.swift b/Sources/P4Compiler/Types.swift index 4f700f8..512c71d 100644 --- a/Sources/P4Compiler/Types.swift +++ b/Sources/P4Compiler/Types.swift @@ -34,7 +34,42 @@ extension P4Int: CompilableType { public static func CompileType( type: SwiftTreeSitter.Node, withContext: CompilerContext ) -> Common.Result<(any Common.P4Type)?> { - return type.text == "int" ? .Ok(P4Int()) : .Ok(.none) + + // Drill down, as appropriate. + let base_type_node = type.child(at: 0)! + #SkipUnlessNodeType( + node: base_type_node, type: "baseType") + + let type_node = base_type_node.child(at: 0)! + #SkipUnlessNodeType( + node: type_node, type: "int_type") + + var walker = Walker(node: type_node) + + var int_node: Node? = .none + + #MustOr( + result: int_node, thing: walker.getNext(), + or: Result.Error( + ErrorWithLocation( + sourceLocation: type_node.toSourceLocation(), + withError: "Missing elements in int type declaration"))) + + // Move passed the keyword. + walker.next() + + if let bit_width_node = walker.getNext() { + guard let bit_width = Int(bit_width_node.child(at: 1)!.text!), + bit_width != 0 + else { + return .Error( + ErrorWithLocation( + sourceLocation: bit_width_node.toSourceLocation(), + withError: "Could not parse \(bit_width_node.text!) into integer")) + } + return .Ok(P4Int(BitWidth.Width(bit_width))) + } + return .Ok(P4Int()) } } diff --git a/Sources/P4Runtime/CodeGen.swift b/Sources/P4Runtime/CodeGen.swift index a908a5e..0270ac3 100644 --- a/Sources/P4Runtime/CodeGen.swift +++ b/Sources/P4Runtime/CodeGen.swift @@ -17,6 +17,7 @@ import Common import P4Lang +import P4Protos public struct Generated { let gen: String @@ -48,13 +49,12 @@ public struct CodeGenerator: LanguageVisitor { return visitor.start(node, context: generated) } - /// TODO: Can we generate these implementations somehow? - public typealias Context = Generated public func visit( _ v: Program, _ c: VisitorContext ) -> Result> { + var result: Result> = Fold( input: v.types, initial: .Ok(c.next(uc: c.getUserContext().append("["))) ) { (current, acc) in diff --git a/Tests/p4rseTests/ControlTests/Compile.swift b/Tests/p4rseTests/ControlTests/Compile.swift index 713aeef..62b064e 100644 --- a/Tests/p4rseTests/ControlTests/Compile.swift +++ b/Tests/p4rseTests/ControlTests/Compile.swift @@ -283,7 +283,7 @@ import P4Lang #RequireErrorResult( Error( withMessage: - "{57, 10}: Failed to parse a statement element: {57, 1}: Cannot assign value with type Boolean to identifier z with type Int" + "{57, 10}: Failed to parse a statement element: {57, 1}: Cannot assign value with type Boolean to identifier z with type Int (width: Infinite)" ), Program.Compile(simple_parser_declaration)) ) diff --git a/Tests/p4rseTests/ExpressionTests/FunctionCall.swift b/Tests/p4rseTests/ExpressionTests/FunctionCall.swift index 05902ca..81b4249 100644 --- a/Tests/p4rseTests/ExpressionTests/FunctionCall.swift +++ b/Tests/p4rseTests/ExpressionTests/FunctionCall.swift @@ -182,5 +182,5 @@ import TreeSitterP4 let error = try #UseErrorResult(Program.Compile(simple_parser_declaration)) - #expect(error.msg().contains("{29, 12}: Type of expression in return statement (Boolean) is not compatible with function return type (Int)")) + #expect(error.msg().contains("{29, 12}: Type of expression in return statement (Boolean) is not compatible with function return type (Int (width: Infinite))")) } diff --git a/Tests/p4rseTests/ExpressionTests/SelectExpression.swift b/Tests/p4rseTests/ExpressionTests/SelectExpression.swift index 486bc6e..7d10304 100644 --- a/Tests/p4rseTests/ExpressionTests/SelectExpression.swift +++ b/Tests/p4rseTests/ExpressionTests/SelectExpression.swift @@ -132,7 +132,7 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "Error(s) parsing select cases: {81, 4}: Key expression of type Boolean is not compatible with selector type Int" + "Error(s) parsing select cases: {81, 4}: Key expression of type Boolean is not compatible with selector type Int (width: Infinite)" ), Program.Compile(simple_parser_declaration))) } diff --git a/Tests/p4rseTests/RuntimeTests.swift b/Tests/p4rseTests/RuntimeTests.swift index e393f43..63ba3a2 100644 --- a/Tests/p4rseTests/RuntimeTests.swift +++ b/Tests/p4rseTests/RuntimeTests.swift @@ -147,7 +147,7 @@ import TreeSitterP4 #expect( #RequireErrorResult<(InstantiatedParserState, ProgramExecution)>( - Error(withMessage: "Cannot call parser: Argument 1's type (Int) is incompatible with the parameter type (Boolean)"), + Error(withMessage: "Cannot call parser: Argument 1's type (Int (width: Infinite)) is incompatible with the parameter type (Boolean)"), runtime.run(withArguments: args))) } diff --git a/Tests/p4rseTests/StructTests.swift b/Tests/p4rseTests/StructTests.swift index 5e2dd89..81c0425 100644 --- a/Tests/p4rseTests/StructTests.swift +++ b/Tests/p4rseTests/StructTests.swift @@ -327,7 +327,7 @@ import TreeSitterP4 #expect( #RequireErrorResult( Error( - withMessage: "{49, 13}: Failed to parse a statement element: {49, 8}: Cannot assign value of type Int to field yesno of type Boolean" + withMessage: "{49, 13}: Failed to parse a statement element: {49, 8}: Cannot assign value of type Int (width: Infinite) to field yesno of type Boolean" ), Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations)) ) @@ -457,7 +457,7 @@ import TreeSitterP4 #expect( #RequireErrorResult( Error( - withMessage: "{49, 20}: Failed to parse a statement element: {49, 11}: Cannot assign value of type Boolean to field count of type Int" + withMessage: "{49, 20}: Failed to parse a statement element: {49, 11}: Cannot assign value of type Boolean to field count of type Int (width: Infinite)" ), Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations)) ) diff --git a/Tests/p4rseTests/SupportTests.swift b/Tests/p4rseTests/SupportTests.swift index aad8ed8..108855f 100644 --- a/Tests/p4rseTests/SupportTests.swift +++ b/Tests/p4rseTests/SupportTests.swift @@ -45,5 +45,5 @@ struct StringConvertible: CustomStringConvertible { @Test func test_result_type_p4value_convertible() async throws { let result = Result.Ok(P4Value(P4IntValue(withValue: 5))) - #expect("\(result)" == "Ok: Value: 5 of Int type of type Int") + #expect("\(result)" == "Ok: Value: 5 of Int (width: Infinite) type of type Int (width: Infinite)") } \ No newline at end of file diff --git a/Tests/p4rseTests/ValueTypeParserTests.swift b/Tests/p4rseTests/ValueTypeParserTests.swift index 8f5ee8a..365b50e 100644 --- a/Tests/p4rseTests/ValueTypeParserTests.swift +++ b/Tests/p4rseTests/ValueTypeParserTests.swift @@ -18,8 +18,8 @@ import Common import Foundation import Macros -import P4Runtime import P4Lang +import P4Runtime import SwiftTreeSitter import Testing import TreeSitter @@ -36,13 +36,15 @@ import TreeSitterP4 transition reject; } }; - """; + """ let err = Program.Compile(simple_parser_declaration) guard case Result.Error(let e) = err else { assert(false, "Expected an error, but had success") } - #expect(e.msg().contains("Failed to parse a statement element: Could not parse a P4 type from \(invalid_type_name)")) + #expect( + e.msg().contains( + "Failed to parse a statement element: Could not parse a P4 type from \(invalid_type_name)")) } } @@ -62,7 +64,7 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "{112, 16}: Failed to parse a statement element: {112, 8}: Cannot assign value with type Boolean to identifier where_to with type String" + "{112, 16}: Failed to parse a statement element: {112, 8}: Cannot assign value with type Boolean to identifier where_to with type String" ), Program.Compile(simple_parser_declaration))) } @@ -83,7 +85,7 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "{114, 22}: Failed to parse a statement element: {114, 8}: Cannot assign value with type String to identifier where_to with type Boolean" + "{114, 22}: Failed to parse a statement element: {114, 8}: Cannot assign value with type String to identifier where_to with type Boolean" ), Program.Compile(simple_parser_declaration))) } @@ -128,6 +130,90 @@ import TreeSitterP4 Program.Compile(simple_parser_declaration))) } +@Test func test_invalid_type_in_declaration3() async throws { + let simple_parser_declaration = """ + parser main_parser() { + state start { + int<5> specific_width_int = 5; + int unspecific_width_int = specific_width_int; + transition reject; + } + }; + """ + + let error = try! #UseErrorResult(Program.Compile(simple_parser_declaration)) + + #expect( + error.msg().contains( + "Cannot initialize specific_width_int (with type Int (width: Width(5))) from expression with type Int (width: Infinite)" + )) +} + +@Test func test_valid_specific_width_int_type_in_declaration() async throws { + let simple_parser_declaration = """ + parser main_parser() { + state start { + int<5> specific_width_int = 5w5; + int<5> unspecific_width_int = specific_width_int; + transition reject; + } + }; + """ + + #expect(#RequireOkResult(Program.Compile(simple_parser_declaration))) +} + +@Test func test_expression_in_declaration_initializer_specific_width_int_type() async throws { + let simple_parser_declaration = """ + parser main_parser() { + state start { + int<5> specific_width_int = 5w5; + bool where_to = 5w5 == specific_width_int == true; + transition select (where_to) { + true: accept; + false: reject; + }; + } + }; + """ + + let program = try #UseOkResult(Program.Compile(simple_parser_declaration)) + let runtime = try #UseOkResult( + P4Runtime.Runtime.create(program: program)) + let (state_result, _) = try! #UseOkResult(runtime.run()) + + // 5w5 == specific_width_int == true + // true == true + // true + #expect(AsInstantiatedParserState(state_result) == P4Lang.accept) +} + +@Test func test_expression_in_declaration_initializer_specific_width_int_type2() async throws { + let simple_parser_declaration = """ + parser main_parser() { + state start { + int<5> specific_width_int = 5w5; + bool where_to = 5w6 == specific_width_int == false; + transition select (where_to) { + true: accept; + false: reject; + }; + } + }; + """ + + let program = try #UseOkResult(Program.Compile(simple_parser_declaration)) + let runtime = try #UseOkResult( + P4Runtime.Runtime.create(program: program)) + let (state_result, _) = try! #UseOkResult(runtime.run()) + + // 5w6 == specific_width_int == false + // false == false + // true + #expect(AsInstantiatedParserState(state_result) == P4Lang.accept) +} + + @Test func test_expression_in_declaration_initializer() async throws { let simple_parser_declaration = """ parser main_parser() { @@ -141,7 +227,8 @@ import TreeSitterP4 }; """ let program = try #UseOkResult(Program.Compile(simple_parser_declaration)) - let runtime = try #UseOkResult(P4Runtime.Runtime.create(program: program)) + let runtime = try #UseOkResult( + P4Runtime.Runtime.create(program: program)) let (state_result, _) = try! #UseOkResult(runtime.run()) // 5 == 5 == true @@ -163,7 +250,8 @@ import TreeSitterP4 }; """ let program = try #UseOkResult(Program.Compile(simple_parser_declaration)) - let runtime = try #UseOkResult(P4Runtime.Runtime.create(program: program)) + let runtime = try #UseOkResult( + P4Runtime.Runtime.create(program: program)) let (state_result, _) = try! #UseOkResult(runtime.run()) // 5 == 5 == true @@ -185,7 +273,8 @@ import TreeSitterP4 }; """ let program = try #UseOkResult(Program.Compile(simple_parser_declaration)) - let runtime = try #UseOkResult(P4Runtime.Runtime.create(program: program)) + let runtime = try #UseOkResult( + P4Runtime.Runtime.create(program: program)) let (state_result, _) = try! #UseOkResult(runtime.run()) // 6 == 5 == true @@ -207,7 +296,8 @@ import TreeSitterP4 }; """ let program = try #UseOkResult(Program.Compile(simple_parser_declaration)) - let runtime = try #UseOkResult(P4Runtime.Runtime.create(program: program)) + let runtime = try #UseOkResult( + P4Runtime.Runtime.create(program: program)) let (state_result, _) = try! #UseOkResult(runtime.run()) // 6 == 5 == false @@ -229,7 +319,8 @@ import TreeSitterP4 }; """ let program = try #UseOkResult(Program.Compile(simple_parser_declaration)) - let runtime = try #UseOkResult(P4Runtime.Runtime.create(program: program)) + let runtime = try #UseOkResult( + P4Runtime.Runtime.create(program: program)) let (state_result, _) = try! #UseOkResult(runtime.run()) // TODO: This test should throw an error. @@ -253,29 +344,32 @@ import TreeSitterP4 }; """ var test_types = VarTypeScopes().enter() - test_types = test_types.declare(identifier: Identifier(name: "ta"), withValue: P4QualifiedType(P4Array(withValueType: P4QualifiedType(P4Int())))) + test_types = test_types.declare( + identifier: Identifier(name: "ta"), + withValue: P4QualifiedType(P4Array(withValueType: P4QualifiedType(P4Int())))) #expect( #RequireErrorResult( Error( withMessage: - "{49, 22}: Failed to parse a statement element: Cannot initialize where_to (with type Boolean) from expression with type Int" + "{49, 22}: Failed to parse a statement element: Cannot initialize where_to (with type Boolean) from expression with type Int (width: Infinite)" ), Program.Compile(simple_parser_declaration, withGlobalInstances: test_types))) } @Test func test_simple_compiler_parser_parameters_invalid_types() async throws { let simple_parser_declaration = """ - parser main_parser(bool pmtr, string smtr, int imtr) { - state start { - pmtr = 1; - transition accept; - } - }; - """ + parser main_parser(bool pmtr, string smtr, int imtr) { + state start { + pmtr = 1; + transition accept; + } + }; + """ #expect( #RequireErrorResult( Error( - withMessage: "{85, 9}: Failed to parse a statement element: {85, 4}: Cannot assign value with type Int to identifier pmtr with type Boolean" + withMessage: + "{85, 9}: Failed to parse a statement element: {85, 4}: Cannot assign value with type Int (width: Infinite) to identifier pmtr with type Boolean" ), Program.Compile(simple_parser_declaration))) } diff --git a/tree-sitter-p4/grammar.js b/tree-sitter-p4/grammar.js index 5cf9778..ec9a306 100644 --- a/tree-sitter-p4/grammar.js +++ b/tree-sitter-p4/grammar.js @@ -40,9 +40,12 @@ export default grammar({ // Common - Types typeRef: $ => choice($.baseType, $.type_identifier), - baseType: $ => choice($.bool, $.error, $.string, $.int, $.bit /* omitting "templated" types" */), + baseType: $ => choice($.bool, $.error, $.string, $.int_type, $.bit /* omitting "templated" types" */), constructor_parameters: $ => seq('(', optional($.parameter_list), ')'), + int_type: $ => seq($.int, optional($.bit_width)), + bit_width: $ => seq('<', $.integer, '>'), + // Common - Parsers parserType: $ => seq(optional($.annotations), $.parser, field('parser_name', $.identifier), optional($.typeParameters), $.parameters), @@ -120,7 +123,7 @@ export default grammar({ // Expressions expression: $ => choice($.grouped_expression, $.simple_expression), grouped_expression: $ => seq('(', $.expression, ')'), - simple_expression: $ => choice($.identifier, $.integer, $.booleanLiteralExpression, $.string_literal, $.binaryOperatorExpression, $.arrayAccessExpression, $.fieldAccessExpression, $.function_call), // Very limited. + simple_expression: $ => choice($.identifier, $.integer, $.integer_elaborated, $.booleanLiteralExpression, $.string_literal, $.binaryOperatorExpression, $.arrayAccessExpression, $.fieldAccessExpression, $.function_call), // Very limited. booleanLiteralExpression: $ => choice($.true, $.false), selectExpression: $ => seq($.select, '(', $.expression, ')', '{', $.selectBody, '}'), // TODO: Should be expression list and not just a single expression transitionSelectionExpression: $ => choice($.identifier, $.selectExpression), @@ -211,6 +214,7 @@ export default grammar({ type_identifier: $ => /[A-Za-z_]+/, string_literal: $ => /"[^"]*"/, integer: $ => /[0-9]+/, + integer_elaborated: $ => /[0-9]+[ws][-0-9]+/, annotation_literal: $ => /@[A-Za-z_]+/, default_keyset: $=> '_', diff --git a/tree-sitter-p4/test/corpus/declarations.txt b/tree-sitter-p4/test/corpus/declarations.txt index 9412c9c..efc1160 100644 --- a/tree-sitter-p4/test/corpus/declarations.txt +++ b/tree-sitter-p4/test/corpus/declarations.txt @@ -46,7 +46,7 @@ parser simple() { ) ========================= -Simple Declaration (int) +Simple Declaration (infinite-precision int) ========================= parser simple() { state start { @@ -73,7 +73,9 @@ parser simple() { (variableDeclaration (typeRef (baseType - (int) + (int_type + (int) + ) ) ) (identifier) @@ -92,6 +94,59 @@ parser simple() { ) ) +========================= +Simple Declaration (fixed-precision int) +========================= +parser simple() { + state start { + int<55> l; + transition accept; + } +}; + +--- +(p4program + (declaration + (parserDeclaration + (parserType + (parser) + (identifier) + (parameters) + ) + (parserStates + (parserState + (state) + (identifier) + (parserStatements + (parserStatement + (variableDeclaration + (typeRef + (baseType + (int_type + (int) + (bit_width + (integer) + ) + ) + ) + ) + (identifier) + ) + ) + ) + (parserTransitionStatement + (transition) + (transitionSelectionExpression + (identifier) + ) + ) + ) + ) + ) + ) +) + + ========================= Simple Declaration (string) ========================= @@ -331,7 +386,9 @@ bool functionb(bool a, int b) { (parameter (typeRef (baseType - (int) + (int_type + (int) + ) ) ) (identifier) @@ -393,7 +450,9 @@ bool functionb(in bool a, out int b, inout string c) { ) (typeRef (baseType - (int) + (int_type + (int) + ) ) ) (identifier) @@ -468,7 +527,9 @@ extern bool functionb(in bool a, out int b, inout string c); ) (typeRef (baseType - (int) + (int_type + (int) + ) ) ) (identifier) diff --git a/tree-sitter-p4/test/corpus/statements.txt b/tree-sitter-p4/test/corpus/statements.txt index 57d2a09..52f0228 100644 --- a/tree-sitter-p4/test/corpus/statements.txt +++ b/tree-sitter-p4/test/corpus/statements.txt @@ -38,7 +38,9 @@ int fun() { (function_declaration (typeRef (baseType - (int) + (int_type + (int) + ) ) ) (identifier) @@ -382,7 +384,9 @@ parser simple() { (variableDeclaration (typeRef (baseType - (int) + (int_type + (int) + ) ) ) (identifier)