diff --git a/Tests/p4rseTests/ControlTests/Runtime.swift b/Tests/p4rseTests/ControlTests/Runtime.swift index 7fa1368..6418a83 100644 --- a/Tests/p4rseTests/ControlTests/Runtime.swift +++ b/Tests/p4rseTests/ControlTests/Runtime.swift @@ -370,11 +370,11 @@ import TreeSitterP4 let (hit_miss, updated_execution) = try #UseOkResult(runtime.run( withArguments: ArgumentList([ Argument(TypedIdentifier(name: "result_arg", withType: P4QualifiedType(P4Int())), atIndex: 0), - Argument(P4Value(P4BooleanValue(withValue: false)), atIndex: 1), + Argument(P4Value(P4BooleanValue(withValue: false)), atIndex: 1), // false will make the x key miss. Argument(P4Value(P4IntValue(withValue: 5)), atIndex: 2), ]))) - // We expect there to be a hit. + // We expect there to be a hit -- but from the second key! #expect(hit_miss == P4TableHitMissValue.Hit) // And that the proper action was invoked. @@ -384,7 +384,11 @@ import TreeSitterP4 @Test func test_control_key_from_struct() async throws { let simple_parser_declaration = """ - control simple(inout int result, bool x, int f) { + struct K { + int i; + int j; + }; + control simple(inout int result, K k) { action a() { result = 5; } @@ -393,8 +397,7 @@ import TreeSitterP4 } table t { key = { - x: exact; - f: exact; + k.i: exact; } actions = { a; @@ -417,15 +420,26 @@ import TreeSitterP4 } var control = ((controls[0].baseType() as P4Type) as! Control) + let k_fields = P4StructFields([ + P4StructFieldIdentifier(name: "i", withType: P4QualifiedType(P4Int())), + P4StructFieldIdentifier(name: "j", withType: P4QualifiedType(P4Int())), + ]) + let k_type = P4Struct(withName: Identifier(name: "K"), andFields: k_fields) + + let k_instance = P4StructValue(withType: k_type, andInitializers: [ + P4Value(P4IntValue(withValue: 5)), + P4Value(P4IntValue(withValue: 1)), + ]) + // Add entries to the table. control = control.updateTable( addEntry: ( - P4Value(P4BooleanValue(withValue: true)), + P4Value(P4IntValue(withValue: 5)), TypedIdentifier(name: "a", withType: P4QualifiedType(Action())) ) ).updateTable( addEntry: ( - P4Value(P4IntValue(withValue: 5)), + P4Value(P4IntValue(withValue: 4)), TypedIdentifier(name: "b", withType: P4QualifiedType(Action())) )) @@ -443,8 +457,7 @@ import TreeSitterP4 let (hit_miss, updated_execution) = try #UseOkResult(runtime.run( withArguments: ArgumentList([ Argument(TypedIdentifier(name: "result_arg", withType: P4QualifiedType(P4Int())), atIndex: 0), - Argument(P4Value(P4BooleanValue(withValue: false)), atIndex: 1), - Argument(P4Value(P4IntValue(withValue: 5)), atIndex: 2), + Argument(P4Value(k_instance), atIndex: 1), ]))) // We expect there to be a hit. @@ -452,6 +465,122 @@ import TreeSitterP4 // And that the proper action was invoked. let result_arg = try #UseOkResult(updated_execution.scopes.lookup(identifier: Identifier(name: "result_arg"))) - #expect(result_arg.eq(P4Value(P4IntValue(withValue: 7)))) + #expect(result_arg.eq(P4Value(P4IntValue(withValue: 5)))) + + + // Now, check whether the b action can be invoked. + let k_instance2 = P4StructValue(withType: k_type, andInitializers: [ + P4Value(P4IntValue(withValue: 4)), + P4Value(P4IntValue(withValue: 1)), + ]) + + // Set a variable in the global scope for the inout first parameter. + var next_global_values = VarValueScopes().enter() + next_global_values = global_values.declare( + identifier: Identifier(name: "result_arg"), + withValue: P4Value( + P4IntValue(withValue: 0), + P4QualifiedType(P4Int()))) + + let runtime2 = try #UseOkResult( + P4Runtime.Runtime.create(control: control, withGlobalValues: next_global_values)) + + let (hit_miss2, updated_execution2) = try #UseOkResult(runtime2.run( + withArguments: ArgumentList([ + Argument(TypedIdentifier(name: "result_arg", withType: P4QualifiedType(P4Int())), atIndex: 0), + Argument(P4Value(k_instance2), atIndex: 1), + ]))) + + // We expect there to be a hit. + #expect(hit_miss2 == P4TableHitMissValue.Hit) + + // And that the proper action was invoked. + let result_arg2 = try #UseOkResult(updated_execution2.scopes.lookup(identifier: Identifier(name: "result_arg"))) + #expect(result_arg2.eq(P4Value(P4IntValue(withValue: 7)))) } +@Test func test_control_key_from_struct_miss() async throws { + let simple_parser_declaration = """ + struct K { + int i; + int j; + }; + control simple(inout int result, K k) { + action a() { + result = 5; + } + action b() { + result = 7; + } + table t { + key = { + k.i: exact; + } + actions = { + a; + b; + } + } + apply { + } + }; + """ + + let program = try! #UseOkResult(Program.Compile(simple_parser_declaration)) + + // Pull the control out of the compiled program. + let controls = program.InstancesWithTypes() { (tipe: P4QualifiedType) -> Bool in + switch tipe.baseType() { + case let c as Control: c.name == "simple" + default: false + } + } + var control = ((controls[0].baseType() as P4Type) as! Control) + + let k_fields = P4StructFields([ + P4StructFieldIdentifier(name: "i", withType: P4QualifiedType(P4Int())), + P4StructFieldIdentifier(name: "j", withType: P4QualifiedType(P4Int())), + ]) + let k_type = P4Struct(withName: Identifier(name: "K"), andFields: k_fields) + + let k_instance = P4StructValue(withType: k_type, andInitializers: [ + P4Value(P4IntValue(withValue: 8)), + P4Value(P4IntValue(withValue: 1)), + ]) + + // Add entries to the table. + control = control.updateTable( + addEntry: ( + P4Value(P4IntValue(withValue: 5)), + TypedIdentifier(name: "a", withType: P4QualifiedType(Action())) + ) + ).updateTable( + addEntry: ( + P4Value(P4IntValue(withValue: 4)), + TypedIdentifier(name: "b", withType: P4QualifiedType(Action())) + )) + + // Set a variable in the global scope for the inout first parameter. + var global_values = VarValueScopes().enter() + global_values = global_values.declare( + identifier: Identifier(name: "result_arg"), + withValue: P4Value( + P4IntValue(withValue: 0), + P4QualifiedType(P4Int()))) + + let runtime = try #UseOkResult( + P4Runtime.Runtime.create(control: control, withGlobalValues: global_values)) + + let (hit_miss, updated_execution) = try #UseOkResult(runtime.run( + withArguments: ArgumentList([ + Argument(TypedIdentifier(name: "result_arg", withType: P4QualifiedType(P4Int())), atIndex: 0), + Argument(P4Value(k_instance), atIndex: 1), + ]))) + + // We expect there to be a hit. + #expect(hit_miss == P4TableHitMissValue.Miss) + + // And that the proper action was invoked. + let result_arg = try #UseOkResult(updated_execution.scopes.lookup(identifier: Identifier(name: "result_arg"))) + #expect(result_arg.eq(P4Value(P4IntValue(withValue: 0)))) +} \ No newline at end of file