From 97a672bd6d8f456ad2a4b2a59f4e78fd5dbc7f2b Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Fri, 22 May 2026 20:42:35 -0400 Subject: [PATCH] compiler: Type Check All Binary Operators Signed-off-by: Will Hawkins --- Sources/P4Compiler/Expression.swift | 5 + .../BinaryOperatorTests/Integer.swift | 118 +++--------------- Tests/p4rseTests/StructTests.swift | 29 +++++ Tests/p4rseTests/ValueTypeParserTests.swift | 16 ++- 4 files changed, 57 insertions(+), 111 deletions(-) diff --git a/Sources/P4Compiler/Expression.swift b/Sources/P4Compiler/Expression.swift index 9fa9eae..ab98151 100644 --- a/Sources/P4Compiler/Expression.swift +++ b/Sources/P4Compiler/Expression.swift @@ -495,6 +495,11 @@ extension BinaryOperatorExpression: CompilableExpression { ), ] + 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")) + } + guard let selected_evaluator = evaluators[binary_operator_expression_node.nodeType!] else { return Result.Error( Error(withMessage: "No evaluator for \(binary_operator_expression_node.nodeType!)")) diff --git a/Tests/p4rseTests/BinaryOperatorTests/Integer.swift b/Tests/p4rseTests/BinaryOperatorTests/Integer.swift index 9a826d0..6dff8c7 100644 --- a/Tests/p4rseTests/BinaryOperatorTests/Integer.swift +++ b/Tests/p4rseTests/BinaryOperatorTests/Integer.swift @@ -321,7 +321,7 @@ import TreeSitterP4 let simple = """ parser main_parser() { state start { - transition select (10 == (true + 5)) { + transition select (true + false) { true: accept; false: reject; }; @@ -333,7 +333,7 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "{72, 16}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" + "{72, 12}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" ), Program.Compile(simple))) } @@ -342,7 +342,7 @@ import TreeSitterP4 let simple = """ parser main_parser() { state start { - transition select (10 == (5 + false)) { + transition select (5 + false) { true: accept; false: reject; }; @@ -354,28 +354,7 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "{72, 17}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" - ), - Program.Compile(simple))) -} - -@Test func test_simple_parser_binary_operator_add_non_integer3() async throws { - let simple = """ - parser main_parser() { - state start { - transition select (10 == (false + false)) { - true: accept; - false: reject; - }; - } - }; - """ - - #expect( - #RequireErrorResult( - Error( - withMessage: - "{72, 21}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" + "{72, 9}: Could not parse transition select expression selector expression: Types of values used with binary expression are not the same" ), Program.Compile(simple))) } @@ -405,7 +384,7 @@ import TreeSitterP4 let simple = """ parser main_parser() { state start { - transition select (10 == (true - 5)) { + transition select (true - false) { true: accept; false: reject; }; @@ -417,7 +396,7 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "{72, 16}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" + "{72, 12}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" ), Program.Compile(simple))) } @@ -426,7 +405,7 @@ import TreeSitterP4 let simple = """ parser main_parser() { state start { - transition select (10 == (5 - false)) { + transition select (5 - false) { true: accept; false: reject; }; @@ -438,33 +417,11 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "{72, 17}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" + "{72, 9}: Could not parse transition select expression selector expression: Types of values used with binary expression are not the same" ), Program.Compile(simple))) } -@Test func test_simple_parser_binary_operator_subtract_non_integer3() async throws { - let simple = """ - parser main_parser() { - state start { - transition select (10 == (false - false)) { - true: accept; - false: reject; - }; - } - }; - """ - - #expect( - #RequireErrorResult( - Error( - withMessage: - "{72, 21}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" - ), - Program.Compile(simple))) -} - - // Multiply Integers @Test func test_simple_parser_binary_operator_multiply_integer() async throws { @@ -490,7 +447,7 @@ import TreeSitterP4 let simple = """ parser main_parser() { state start { - transition select (10 == (true * 5)) { + transition select (true * false) { true: accept; false: reject; }; @@ -502,7 +459,7 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "{72, 16}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" + "{72, 12}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" ), Program.Compile(simple))) } @@ -511,7 +468,7 @@ import TreeSitterP4 let simple = """ parser main_parser() { state start { - transition select (10 == (5 * false)) { + transition select (5 * false) { true: accept; false: reject; }; @@ -523,28 +480,7 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "{72, 17}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" - ), - Program.Compile(simple))) -} - -@Test func test_simple_parser_binary_operator_multiply_non_integer3() async throws { - let simple = """ - parser main_parser() { - state start { - transition select (10 == (false * false)) { - true: accept; - false: reject; - }; - } - }; - """ - - #expect( - #RequireErrorResult( - Error( - withMessage: - "{72, 21}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" + "{72, 9}: Could not parse transition select expression selector expression: Types of values used with binary expression are not the same" ), Program.Compile(simple))) } @@ -574,7 +510,7 @@ import TreeSitterP4 let simple = """ parser main_parser() { state start { - transition select (10 == (true / 5)) { + transition select (true / false) { true: accept; false: reject; }; @@ -586,7 +522,7 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "{72, 16}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" + "{72, 12}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" ), Program.Compile(simple))) } @@ -595,7 +531,7 @@ import TreeSitterP4 let simple = """ parser main_parser() { state start { - transition select (10 == (5 / false)) { + transition select (5 / false) { true: accept; false: reject; }; @@ -607,29 +543,7 @@ import TreeSitterP4 #RequireErrorResult( Error( withMessage: - "{72, 17}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" + "{72, 9}: Could not parse transition select expression selector expression: Types of values used with binary expression are not the same" ), Program.Compile(simple))) } - -@Test func test_simple_parser_binary_operator_divide_non_integer3() async throws { - let simple = """ - parser main_parser() { - state start { - transition select (10 == (false / false)) { - true: accept; - false: reject; - }; - } - }; - """ - - #expect( - #RequireErrorResult( - Error( - withMessage: - "{72, 21}: Could not parse transition select expression selector expression: Mathematical operation on operands with non-int type is not allowed" - ), - Program.Compile(simple))) -} - diff --git a/Tests/p4rseTests/StructTests.swift b/Tests/p4rseTests/StructTests.swift index 81c0425..e7f78fc 100644 --- a/Tests/p4rseTests/StructTests.swift +++ b/Tests/p4rseTests/StructTests.swift @@ -463,3 +463,32 @@ import TreeSitterP4 ) } + +@Test func test_field_read_equality_invalid_type() async throws { + let simple_parser_declaration = """ + parser main_parser() { + state start { + transition select (ts.yesno == "testing") { + true: accept; + false: reject; + }; + } + }; + """ + var test_declarations = VarTypeScopes().enter() + let fields = P4StructFields([ + P4StructFieldIdentifier(name: "yesno", withType: P4QualifiedType(P4Boolean())), + P4StructFieldIdentifier(name: "count", withType: P4QualifiedType(P4Int())), + ]) + let struct_type = P4Struct(withName: Identifier(name: "Testing"), andFields: fields) + test_declarations = test_declarations.declare(identifier: Identifier(name: "ts"), withValue: P4QualifiedType(struct_type)) + + #expect( + #RequireErrorResult( + Error( + withMessage: "{68, 21}: Could not parse transition select expression selector expression: Types of values used with binary expression are not the same" + ), + Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations)) + ) +} + diff --git a/Tests/p4rseTests/ValueTypeParserTests.swift b/Tests/p4rseTests/ValueTypeParserTests.swift index 365b50e..14820d8 100644 --- a/Tests/p4rseTests/ValueTypeParserTests.swift +++ b/Tests/p4rseTests/ValueTypeParserTests.swift @@ -318,17 +318,15 @@ import TreeSitterP4 } }; """ - 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()) - // TODO: This test should throw an error. + #expect( + #RequireErrorResult( + Error( + withMessage: + "{49, 35}: Failed to parse a statement element: Types of values used with binary expression are not the same" + ), + Program.Compile(simple_parser_declaration))) - // false == 5 == true - // false == true - // false - #expect(AsInstantiatedParserState(state_result) == P4Lang.reject) } @Test func test_expression_in_declaration_initializer_invalid_types2() async throws {