Compare commits
4 Commits
a1908cc077
...
0c8b9e88cf
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c8b9e88cf | |||
| e53c32f802 | |||
| 5845cb75cc | |||
| 24b0f0284a |
@@ -96,7 +96,8 @@ extension Cli {
|
|||||||
|
|
||||||
let maybe_program = Program.Compile(source.getSource())
|
let maybe_program = Program.Compile(source.getSource())
|
||||||
guard case .Ok(_) = maybe_program else {
|
guard case .Ok(_) = maybe_program else {
|
||||||
print(ErrorWithLabel("Compiler Error", maybe_source.error()!).format(formatter))
|
let feedback = CompilationFeedback(source, [maybe_program.error()!], formatter)
|
||||||
|
print(feedback.feedback)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,29 @@ public struct Error: Errorable, Equatable, CustomStringConvertible {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension String {
|
||||||
|
public func trimmingPostfix(_ in_: String.Element) -> String {
|
||||||
|
return String(self.reversed().drop { $0 == in_ }.reversed())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct ErrorWithLocation: Errorable, Equatable, CustomStringConvertible {
|
public struct ErrorWithLocation: Errorable, Equatable, CustomStringConvertible {
|
||||||
|
|
||||||
|
public func format(_ formatter: any Formattable, _ sc: SourceCode) -> String {
|
||||||
|
guard let (fp, source, prior, after) = sc.getSourceSnippet(location: self.location, context: 5)
|
||||||
|
else {
|
||||||
|
return self.format(formatter)
|
||||||
|
}
|
||||||
|
|
||||||
|
let prior_snipped = prior.trimmingPrefix(["\n"])
|
||||||
|
let after_snipped = after.prefix { $0 != "\n" }
|
||||||
|
return formatter.formatWithStyle("Error: ", Style(StyleColor.Red))
|
||||||
|
+ "In \(fp), there was an error: \n..." + prior_snipped
|
||||||
|
+ formatter.formatWithStyle(source, Style(.none, [StyleFormat.Underline])) + after_snipped
|
||||||
|
+ "...\n"
|
||||||
|
+ self._msg
|
||||||
|
}
|
||||||
|
|
||||||
public func format(_ formatter: any Formattable) -> String {
|
public func format(_ formatter: any Formattable) -> String {
|
||||||
let bold_red = Style(StyleColor.Red, [StyleFormat.Bold])
|
let bold_red = Style(StyleColor.Red, [StyleFormat.Bold])
|
||||||
let formatted_location = formatter.formatWithStyle(self.location.description, bold_red)
|
let formatted_location = formatter.formatWithStyle(self.location.description, bold_red)
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ public protocol ProgramExecutionEvaluator {
|
|||||||
|
|
||||||
public protocol Errorable: CustomStringConvertible {
|
public protocol Errorable: CustomStringConvertible {
|
||||||
func format(_ formatter: Formattable) -> String
|
func format(_ formatter: Formattable) -> String
|
||||||
|
func format(_ formatter: Formattable, _ sc: SourceCode) -> String
|
||||||
func msg() -> String
|
func msg() -> String
|
||||||
func append(error: any Errorable) -> any Errorable
|
func append(error: any Errorable) -> any Errorable
|
||||||
func eq(_ rhs: any Errorable) -> Bool
|
func eq(_ rhs: any Errorable) -> Bool
|
||||||
@@ -81,6 +82,9 @@ extension Errorable {
|
|||||||
public func eq(_ rhs: any Errorable) -> Bool {
|
public func eq(_ rhs: any Errorable) -> Bool {
|
||||||
return self.msg() == rhs.msg()
|
return self.msg() == rhs.msg()
|
||||||
}
|
}
|
||||||
|
public func format(_ formatter: Formattable, _ sc: SourceCode) -> String {
|
||||||
|
return self.format(formatter)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol Formattable {
|
public protocol Formattable {
|
||||||
|
|||||||
@@ -210,6 +210,33 @@ public struct SourceCode {
|
|||||||
return self.code
|
return self.code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func getSourceSnippet(
|
||||||
|
location: SourceLocation, context: Int = 0
|
||||||
|
) -> (FilePath, String, String, String)? {
|
||||||
|
guard let path = self.pathForLocation(location.range.lowerBound) else {
|
||||||
|
return .none
|
||||||
|
}
|
||||||
|
let lower = String.UTF8View.Index(utf16Offset: location.range.lowerBound, in: self.code)
|
||||||
|
let upper = String.UTF8View.Index(utf16Offset: location.range.upperBound, in: self.code)
|
||||||
|
let prior_start =
|
||||||
|
if location.range.lowerBound - context >= 0 {
|
||||||
|
String.UTF8View.Index(utf16Offset: location.range.lowerBound - context, in: self.code)
|
||||||
|
} else {
|
||||||
|
String.UTF8View.Index(utf16Offset: location.range.lowerBound, in: self.code)
|
||||||
|
}
|
||||||
|
let after_end =
|
||||||
|
if location.range.upperBound + context < self.code.count {
|
||||||
|
String.UTF8View.Index(utf16Offset: location.range.upperBound + context, in: self.code)
|
||||||
|
} else {
|
||||||
|
String.UTF8View.Index(utf16Offset: location.range.upperBound, in: self.code)
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = String(self.code.utf16[lower..<upper])!
|
||||||
|
let prior = String(self.code.utf16[prior_start..<lower])!
|
||||||
|
let after = String(self.code.utf16[upper...after_end])!
|
||||||
|
return (path, result, prior, after)
|
||||||
|
}
|
||||||
|
|
||||||
public func getLocations() -> FileSourceLocation {
|
public func getLocations() -> FileSourceLocation {
|
||||||
return self.locations
|
return self.locations
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -614,6 +614,17 @@ extension Action: Compilable {
|
|||||||
}
|
}
|
||||||
current_context = updated_context
|
current_context = updated_context
|
||||||
|
|
||||||
|
// Check whether the parameters are in the proper order.
|
||||||
|
let remaining_parameters = action_parameters.parameters.drop(while: {
|
||||||
|
$0.type.direction() != .none
|
||||||
|
})
|
||||||
|
if remaining_parameters.contains(where: { $0.type.direction() != .none }) {
|
||||||
|
return .Error(
|
||||||
|
ErrorWithLocation(
|
||||||
|
sourceLocation: current_node!.toSourceLocation(),
|
||||||
|
withError: "All parameters with direction must precede directionless parameters"))
|
||||||
|
}
|
||||||
|
|
||||||
walker.next()
|
walker.next()
|
||||||
#MustOr(
|
#MustOr(
|
||||||
result: current_node, thing: walker.getNext(),
|
result: current_node, thing: walker.getNext(),
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// 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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import Common
|
||||||
|
|
||||||
|
public struct CompilationFeedback {
|
||||||
|
public let feedback: String
|
||||||
|
|
||||||
|
static func markup(
|
||||||
|
_ source: SourceCode, _ errors: [any Errorable], _ formatter: any Formattable
|
||||||
|
) -> String {
|
||||||
|
errors.map { $0.format(formatter, source) }.joined(separator: "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(_ source: SourceCode, _ errors: [any Errorable], _ formatter: any Formattable) {
|
||||||
|
self.feedback = Self.markup(source, errors, formatter)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
control simple(int x, int y) {
|
||||||
|
action a(inout bool aa, int ax, inout bool ay) {
|
||||||
|
aa = false;
|
||||||
|
}
|
||||||
|
table t {
|
||||||
|
key = {
|
||||||
|
x: exact;
|
||||||
|
y: exact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apply {
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Error: In /Users/hawkinsw/code/p4ce/TestData/Sources/action-parameters-wrong-order.p4, there was an error:
|
||||||
|
...ion a(inout bool aa, int ax, inout bool ay) {...
|
||||||
|
All parameters with direction must precede directionless parameters
|
||||||
@@ -39,3 +39,8 @@ func simple_cli_preprocessor_test() -> [String] {
|
|||||||
func simple_cli_preprocessor_test_file_not_found() -> [String] {
|
func simple_cli_preprocessor_test_file_not_found() -> [String] {
|
||||||
return ["p4ce", "--plain", "preprocess", "simple.p", "-I", "TestData/Sources/"]
|
return ["p4ce", "--plain", "preprocess", "simple.p", "-I", "TestData/Sources/"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CliTest()
|
||||||
|
func simple_cli_compilation_error() -> [String] {
|
||||||
|
return ["p4ce", "--plain", "compile", "action-parameters-wrong-order.p4", "-I", "TestData/Sources/"]
|
||||||
|
}
|
||||||
@@ -18,12 +18,12 @@
|
|||||||
import Common
|
import Common
|
||||||
import Foundation
|
import Foundation
|
||||||
import Macros
|
import Macros
|
||||||
|
import P4Lang
|
||||||
import Runtime
|
import Runtime
|
||||||
import SwiftTreeSitter
|
import SwiftTreeSitter
|
||||||
import Testing
|
import Testing
|
||||||
import TreeSitter
|
import TreeSitter
|
||||||
import TreeSitterP4
|
import TreeSitterP4
|
||||||
import P4Lang
|
|
||||||
|
|
||||||
@testable import P4Compiler
|
@testable import P4Compiler
|
||||||
|
|
||||||
@@ -136,7 +136,8 @@ import P4Lang
|
|||||||
#expect(
|
#expect(
|
||||||
#RequireErrorResult(
|
#RequireErrorResult(
|
||||||
Error(
|
Error(
|
||||||
withMessage: "{54, 63}: Error(s) parsing property list: {91, 26}: Error(s) parsing table actions: Cannot find b in lexical scope."
|
withMessage:
|
||||||
|
"{54, 63}: Error(s) parsing property list: {91, 26}: Error(s) parsing table actions: Cannot find b in lexical scope."
|
||||||
),
|
),
|
||||||
Program.Compile(simple_parser_declaration))
|
Program.Compile(simple_parser_declaration))
|
||||||
)
|
)
|
||||||
@@ -163,7 +164,8 @@ import P4Lang
|
|||||||
#expect(
|
#expect(
|
||||||
#RequireErrorResult(
|
#RequireErrorResult(
|
||||||
Error(
|
Error(
|
||||||
withMessage: "{54, 72}: Error(s) parsing property list: {91, 35}: Error(s) parsing table actions: Cannot find b in lexical scope."
|
withMessage:
|
||||||
|
"{54, 72}: Error(s) parsing property list: {91, 35}: Error(s) parsing table actions: Cannot find b in lexical scope."
|
||||||
),
|
),
|
||||||
Program.Compile(simple_parser_declaration))
|
Program.Compile(simple_parser_declaration))
|
||||||
)
|
)
|
||||||
@@ -190,7 +192,8 @@ import P4Lang
|
|||||||
#expect(
|
#expect(
|
||||||
#RequireErrorResult(
|
#RequireErrorResult(
|
||||||
Error(
|
Error(
|
||||||
withMessage: "{64, 63}: Error(s) parsing property list: {101, 26}: Error(s) parsing table actions: {101, 26}: a does not name an action"
|
withMessage:
|
||||||
|
"{64, 63}: Error(s) parsing property list: {101, 26}: Error(s) parsing table actions: {101, 26}: a does not name an action"
|
||||||
),
|
),
|
||||||
Program.Compile(simple_parser_declaration))
|
Program.Compile(simple_parser_declaration))
|
||||||
)
|
)
|
||||||
@@ -320,3 +323,80 @@ import P4Lang
|
|||||||
Program.Compile(simple_parser_declaration))
|
Program.Compile(simple_parser_declaration))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_control_declaration_with_action_with_params_right_order() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
control simple(int x, int y) {
|
||||||
|
action a(inout int ax, bool ay) {
|
||||||
|
ax = 5;
|
||||||
|
}
|
||||||
|
table t {
|
||||||
|
key = {
|
||||||
|
x: exact;
|
||||||
|
y: exact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apply {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
|
||||||
|
let x = { (tipe: P4QualifiedType) -> Bool in
|
||||||
|
switch tipe.baseType() {
|
||||||
|
case let c as Control: c.name == "simple"
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let program = try! #UseOkResult(Program.Compile(simple_parser_declaration))
|
||||||
|
#expect(program.InstancesWithTypes(x).count == 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_control_declaration_with_action_with_params_wrong_order() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
control simple(int x, int y) {
|
||||||
|
action a(int ax, inout bool ay) {
|
||||||
|
ay = false;
|
||||||
|
}
|
||||||
|
table t {
|
||||||
|
key = {
|
||||||
|
x: exact;
|
||||||
|
y: exact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apply {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
#expect(
|
||||||
|
#RequireErrorResult(
|
||||||
|
ErrorWithLocation(
|
||||||
|
sourceLocation: SourceLocation(41, 23),
|
||||||
|
withError: "All parameters with direction must precede directionless parameters"),
|
||||||
|
Program.Compile(simple_parser_declaration))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_control_declaration_with_action_with_params_wrong_order_interspersed() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
control simple(int x, int y) {
|
||||||
|
action a(inout bool aa, int ax, inout bool ay) {
|
||||||
|
aa = false;
|
||||||
|
}
|
||||||
|
table t {
|
||||||
|
key = {
|
||||||
|
x: exact;
|
||||||
|
y: exact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apply {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
#expect(
|
||||||
|
#RequireErrorResult(
|
||||||
|
ErrorWithLocation(
|
||||||
|
sourceLocation: SourceLocation(41, 38),
|
||||||
|
withError: "All parameters with direction must precede directionless parameters"),
|
||||||
|
Program.Compile(simple_parser_declaration))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -370,11 +370,11 @@ import TreeSitterP4
|
|||||||
let (hit_miss, updated_execution) = try #UseOkResult(runtime.run(
|
let (hit_miss, updated_execution) = try #UseOkResult(runtime.run(
|
||||||
withArguments: ArgumentList([
|
withArguments: ArgumentList([
|
||||||
Argument(TypedIdentifier(name: "result_arg", withType: P4QualifiedType(P4Int())), atIndex: 0),
|
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),
|
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)
|
#expect(hit_miss == P4TableHitMissValue.Hit)
|
||||||
|
|
||||||
// And that the proper action was invoked.
|
// And that the proper action was invoked.
|
||||||
@@ -384,7 +384,11 @@ import TreeSitterP4
|
|||||||
|
|
||||||
@Test func test_control_key_from_struct() async throws {
|
@Test func test_control_key_from_struct() async throws {
|
||||||
let simple_parser_declaration = """
|
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() {
|
action a() {
|
||||||
result = 5;
|
result = 5;
|
||||||
}
|
}
|
||||||
@@ -393,8 +397,7 @@ import TreeSitterP4
|
|||||||
}
|
}
|
||||||
table t {
|
table t {
|
||||||
key = {
|
key = {
|
||||||
x: exact;
|
k.i: exact;
|
||||||
f: exact;
|
|
||||||
}
|
}
|
||||||
actions = {
|
actions = {
|
||||||
a;
|
a;
|
||||||
@@ -417,15 +420,26 @@ import TreeSitterP4
|
|||||||
}
|
}
|
||||||
var control = ((controls[0].baseType() as P4Type) as! Control)
|
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.
|
// Add entries to the table.
|
||||||
control = control.updateTable(
|
control = control.updateTable(
|
||||||
addEntry: (
|
addEntry: (
|
||||||
P4Value(P4BooleanValue(withValue: true)),
|
P4Value(P4IntValue(withValue: 5)),
|
||||||
TypedIdentifier(name: "a", withType: P4QualifiedType(Action()))
|
TypedIdentifier(name: "a", withType: P4QualifiedType(Action()))
|
||||||
)
|
)
|
||||||
).updateTable(
|
).updateTable(
|
||||||
addEntry: (
|
addEntry: (
|
||||||
P4Value(P4IntValue(withValue: 5)),
|
P4Value(P4IntValue(withValue: 4)),
|
||||||
TypedIdentifier(name: "b", withType: P4QualifiedType(Action()))
|
TypedIdentifier(name: "b", withType: P4QualifiedType(Action()))
|
||||||
))
|
))
|
||||||
|
|
||||||
@@ -443,8 +457,7 @@ import TreeSitterP4
|
|||||||
let (hit_miss, updated_execution) = try #UseOkResult(runtime.run(
|
let (hit_miss, updated_execution) = try #UseOkResult(runtime.run(
|
||||||
withArguments: ArgumentList([
|
withArguments: ArgumentList([
|
||||||
Argument(TypedIdentifier(name: "result_arg", withType: P4QualifiedType(P4Int())), atIndex: 0),
|
Argument(TypedIdentifier(name: "result_arg", withType: P4QualifiedType(P4Int())), atIndex: 0),
|
||||||
Argument(P4Value(P4BooleanValue(withValue: false)), atIndex: 1),
|
Argument(P4Value(k_instance), atIndex: 1),
|
||||||
Argument(P4Value(P4IntValue(withValue: 5)), atIndex: 2),
|
|
||||||
])))
|
])))
|
||||||
|
|
||||||
// We expect there to be a hit.
|
// We expect there to be a hit.
|
||||||
@@ -452,6 +465,122 @@ import TreeSitterP4
|
|||||||
|
|
||||||
// And that the proper action was invoked.
|
// And that the proper action was invoked.
|
||||||
let result_arg = try #UseOkResult(updated_execution.scopes.lookup(identifier: Identifier(name: "result_arg")))
|
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<P4TableHitMissValue, Control>.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<P4TableHitMissValue, Control>.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))))
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ swift format --recursive -i Sources/ 2>&1 >/dev/null
|
|||||||
mc=`git status . | grep modified | wc -l | sed 's/ //g'`
|
mc=`git status . | grep modified | wc -l | sed 's/ //g'`
|
||||||
|
|
||||||
if [ ${mc} -ne 0 ]; then
|
if [ ${mc} -ne 0 ]; then
|
||||||
|
git status .
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user