compiler, runtime: Initial Support For Calling Controls
Support calling (invoking) a Control. There is still plenty more to do here, but we are off to a good start. Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
@@ -691,7 +691,6 @@ extension TableKeys: Compilable {
|
||||
walker.next() // 3
|
||||
|
||||
var current_node: Node? = .none
|
||||
var current_context = context
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
@@ -700,28 +699,22 @@ extension TableKeys: Compilable {
|
||||
node: node, withError: "Missing table keys declaration component in control declaration"))
|
||||
)
|
||||
|
||||
var entries: [TableKeyEntry] = Array()
|
||||
var errors: [Error] = Array()
|
||||
|
||||
current_node!.enumerateNamedChildren { entry in
|
||||
switch TableKeyEntry.Compile(node: current_node!, withContext: current_context) {
|
||||
case .Ok((let keyset_expression, let updated_context)):
|
||||
entries.append(keyset_expression)
|
||||
current_context = updated_context
|
||||
case .Error(let e): errors.append(e)
|
||||
let (keys, errors) = walker.try_map(n: node.childCount - 1, onlyNamed: true) { current_node in
|
||||
return switch TableKeyEntry.Compile(node: current_node, withContext: context) {
|
||||
case .Ok((let keyset_expression, _)): .Ok(keyset_expression)
|
||||
case .Error(let e): .Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
if !errors.isEmpty {
|
||||
return .Error(
|
||||
Error(
|
||||
withMessage: "Error(s) parsing table key: "
|
||||
ErrorOnNode(node: node, withError: "Error(s) parsing table key: "
|
||||
+ (errors.map { error in
|
||||
return "\(error.msg)"
|
||||
}.joined(separator: ";"))))
|
||||
}
|
||||
|
||||
return .Ok((TableKeys(withEntries: entries), current_context))
|
||||
return .Ok((TableKeys(withEntries: keys), context))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -828,7 +821,7 @@ extension TablePropertyList: Compilable {
|
||||
ErrorOnNode(node: node, withError: "More than one key set in table property list"))
|
||||
}
|
||||
|
||||
// There should be only one table keys!
|
||||
// There should be only one table actions!
|
||||
if actions.count > 1 {
|
||||
// Todo: Make this error message better.
|
||||
return .Error(
|
||||
|
||||
@@ -89,7 +89,7 @@ public struct Action: CustomStringConvertible, P4DataType, P4DataValue {
|
||||
}
|
||||
|
||||
public struct Actions: CustomStringConvertible {
|
||||
let actions: [Action]
|
||||
public let actions: [Action]
|
||||
public init(withActions actions: [Action]) {
|
||||
self.actions = actions
|
||||
}
|
||||
@@ -107,8 +107,8 @@ public enum TableKeyMatchType {
|
||||
}
|
||||
|
||||
public struct TableKeyEntry: CustomStringConvertible {
|
||||
let key: KeysetExpression
|
||||
let match_type: TableKeyMatchType
|
||||
public let key: KeysetExpression
|
||||
public let match_type: TableKeyMatchType
|
||||
|
||||
public init(_ key: KeysetExpression, _ match: TableKeyMatchType) {
|
||||
self.key = key
|
||||
@@ -121,19 +121,19 @@ public struct TableKeyEntry: CustomStringConvertible {
|
||||
}
|
||||
|
||||
public struct TableKeys: CustomStringConvertible {
|
||||
let entries: [TableKeyEntry]
|
||||
public let keys: [TableKeyEntry]
|
||||
|
||||
public init(withEntries entries: [TableKeyEntry]) {
|
||||
self.entries = entries
|
||||
self.keys = entries
|
||||
}
|
||||
public init() {
|
||||
self.entries = []
|
||||
self.keys = []
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
return "Table Keys: "
|
||||
+ self.entries.map { entry in
|
||||
return "\(entry)"
|
||||
+ self.keys.map { key in
|
||||
return "\(key)"
|
||||
}.joined(separator: ";")
|
||||
}
|
||||
}
|
||||
@@ -153,8 +153,8 @@ public struct TableActionsProperty: CustomStringConvertible {
|
||||
}
|
||||
|
||||
public struct TablePropertyList: CustomStringConvertible {
|
||||
let actions: TableActionsProperty
|
||||
let keys: TableKeys
|
||||
public let actions: TableActionsProperty
|
||||
public let keys: TableKeys
|
||||
public init(withActions actions: TableActionsProperty, withKeys keys: TableKeys) {
|
||||
self.actions = actions
|
||||
self.keys = keys
|
||||
@@ -166,17 +166,30 @@ public struct TablePropertyList: CustomStringConvertible {
|
||||
}
|
||||
|
||||
public struct Table: CustomStringConvertible {
|
||||
let properties: TablePropertyList
|
||||
public let properties: TablePropertyList
|
||||
let name: Identifier
|
||||
public let entries: [(P4Value, TypedIdentifier)]
|
||||
|
||||
public init(withName name: Identifier, withPropertyList property_list: TablePropertyList) {
|
||||
public init(
|
||||
withName name: Identifier, withPropertyList property_list: TablePropertyList,
|
||||
withEntries entries: [(P4Value, TypedIdentifier)] = []
|
||||
) {
|
||||
self.name = name
|
||||
self.properties = property_list
|
||||
self.entries = entries
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
return "Table named: \(self.name) \(self.properties)"
|
||||
}
|
||||
|
||||
/// When the control is evaluated, the value of the x in the table is
|
||||
/// compared to the entries and the match is assocated with an action
|
||||
/// that is invoked when the match occurs!
|
||||
|
||||
public func update(addEntry entry: (P4Value, TypedIdentifier)) -> Table{
|
||||
return Table(withName: self.name, withPropertyList: self.properties, withEntries: self.entries + [entry])
|
||||
}
|
||||
}
|
||||
|
||||
public struct Control: P4DataType, P4DataValue, Equatable, CustomStringConvertible {
|
||||
@@ -236,8 +249,8 @@ public struct Control: P4DataType, P4DataValue, Equatable, CustomStringConvertib
|
||||
return "Control named \(self._name) \(self.parameters) \(self.actions) \(self.table)"
|
||||
}
|
||||
|
||||
let actions: Actions
|
||||
let table: Table
|
||||
public let actions: Actions
|
||||
public let table: Table
|
||||
let _parameters: ParameterList
|
||||
let _name: Identifier
|
||||
let apply: ApplyStatement
|
||||
@@ -261,6 +274,12 @@ public struct Control: P4DataType, P4DataValue, Equatable, CustomStringConvertib
|
||||
self.apply = apply
|
||||
}
|
||||
|
||||
public func updateTable(addEntry entry: (P4Value, TypedIdentifier)) -> Control {
|
||||
let table = self.table.update(addEntry: entry)
|
||||
|
||||
return Control(named: self.name, withParameters: self.parameters, withTable: table, withActions: self.actions, withApply: self.apply)
|
||||
}
|
||||
|
||||
public func def() -> any P4DataValue {
|
||||
return Control(
|
||||
named: Identifier(name: ""),
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
// 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
|
||||
import P4Lang
|
||||
|
||||
extension Control: LibraryCallable {
|
||||
public typealias T = P4TableHitMissValue
|
||||
public func call(
|
||||
execution: Common.ProgramExecution, arguments: ArgumentList
|
||||
) -> (P4TableHitMissValue, Common.ProgramExecution) {
|
||||
|
||||
var control_execution = execution.enter_scope()
|
||||
|
||||
// Add initial values to the global scope
|
||||
for (name, value) in execution.getGlobalValues() {
|
||||
control_execution = control_execution.declare(identifier: name, withValue: value)
|
||||
}
|
||||
|
||||
let call_body: (ProgramExecution) -> (Result<P4TableHitMissValue>, ProgramExecution) = {
|
||||
execution in
|
||||
var control_execution = execution
|
||||
|
||||
for action in self.actions.actions {
|
||||
control_execution = control_execution.declare(
|
||||
identifier: action.name, withValue: P4Value(action))
|
||||
}
|
||||
|
||||
for key in self.table.properties.keys.keys {
|
||||
// Every evaluation of the key starts from an unchanged execution context.
|
||||
let (key_eval, updated_execution) = key.key.evaluate(execution: control_execution)
|
||||
|
||||
guard case .Ok(let key_val) = key_eval else {
|
||||
return (.Error(key_eval.error()!), updated_execution)
|
||||
}
|
||||
|
||||
/// ASSUME: The first matching entry is the one to do.
|
||||
/// TODO: Check whether this matches architecture.
|
||||
for (val, action) in self.table.entries {
|
||||
|
||||
// Skip those with mismatching types.
|
||||
|
||||
if !val.type().eq(key_val.type()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/// ASSUME: All matches are exact.
|
||||
if val.eq(key_val) {
|
||||
// Lookup action!
|
||||
|
||||
let maybe_action = updated_execution.scopes.lookup(identifier: action)
|
||||
guard case .Ok(let action) = maybe_action else {
|
||||
return (.Error(maybe_action.error()!), updated_execution)
|
||||
}
|
||||
|
||||
let aaction = (action.dataValue() as! Action)
|
||||
|
||||
return switch aaction.evaluate(execution: updated_execution) {
|
||||
case (ControlFlow.Error, let updated_execution):
|
||||
(.Error(updated_execution.getError()!), updated_execution)
|
||||
case (_, let updated_execution): (.Ok(P4TableHitMissValue.Hit), updated_execution)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (.Ok(P4TableHitMissValue.Miss), control_execution)
|
||||
}
|
||||
|
||||
switch Call(body: call_body, withArguments: arguments, withParameters: self.parameters, inExecution: control_execution) {
|
||||
case (.Ok(let r), let updated_execution): return (r, updated_execution)
|
||||
case (.Error(let e), let updated_execution): return (P4TableHitMissValue.Miss, updated_execution.setError(error: e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Action: EvaluatableStatement {
|
||||
public func evaluate(
|
||||
execution: Common.ProgramExecution
|
||||
) -> (Common.ControlFlow, Common.ProgramExecution) {
|
||||
if let body = self.body {
|
||||
return body.evaluate(execution: execution)
|
||||
}
|
||||
|
||||
return (ControlFlow.Next, execution)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
// 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
|
||||
import Foundation
|
||||
import Macros
|
||||
import P4Lang
|
||||
import P4Runtime
|
||||
import SwiftTreeSitter
|
||||
import Testing
|
||||
import TreeSitter
|
||||
import TreeSitterP4
|
||||
|
||||
@testable import P4Compiler
|
||||
|
||||
@Test func test_control_single_key() async throws {
|
||||
let simple_parser_declaration = """
|
||||
control simple(inout int result, bool x) {
|
||||
action a() {
|
||||
result = 5;
|
||||
}
|
||||
action b() {
|
||||
result = 7;
|
||||
}
|
||||
table t {
|
||||
key = {
|
||||
x: 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: P4Type) -> Bool in
|
||||
switch tipe.dataType() {
|
||||
case let c as Control: c.name == "simple"
|
||||
default: false
|
||||
}
|
||||
}
|
||||
var control = ((controls[0].dataType() as P4DataType) as! Control)
|
||||
|
||||
// Add entries to the table.
|
||||
control = control.updateTable(
|
||||
addEntry: (
|
||||
P4Value(P4BooleanValue(withValue: true)),
|
||||
TypedIdentifier(name: "a", withType: P4Type(Action()))
|
||||
)
|
||||
).updateTable(
|
||||
addEntry: (
|
||||
P4Value(P4BooleanValue(withValue: false)),
|
||||
TypedIdentifier(name: "b", withType: P4Type(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),
|
||||
P4Type(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: P4Type(P4Int())), atIndex: 0),
|
||||
Argument(P4Value(P4BooleanValue(withValue: true)), atIndex: 1),
|
||||
])))
|
||||
|
||||
// We expect there to be a hit.
|
||||
#expect(hit_miss == P4TableHitMissValue.Hit)
|
||||
|
||||
// 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: 5))))
|
||||
}
|
||||
|
||||
@Test func test_control_single_key_false() async throws {
|
||||
let simple_parser_declaration = """
|
||||
control simple(inout int result, bool x) {
|
||||
action a() {
|
||||
result = 5;
|
||||
}
|
||||
action b() {
|
||||
result = 7;
|
||||
}
|
||||
table t {
|
||||
key = {
|
||||
x: 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: P4Type) -> Bool in
|
||||
switch tipe.dataType() {
|
||||
case let c as Control: c.name == "simple"
|
||||
default: false
|
||||
}
|
||||
}
|
||||
var control = ((controls[0].dataType() as P4DataType) as! Control)
|
||||
|
||||
// Add entries to the table.
|
||||
control = control.updateTable(
|
||||
addEntry: (
|
||||
P4Value(P4BooleanValue(withValue: true)),
|
||||
TypedIdentifier(name: "a", withType: P4Type(Action()))
|
||||
)
|
||||
).updateTable(
|
||||
addEntry: (
|
||||
P4Value(P4BooleanValue(withValue: false)),
|
||||
TypedIdentifier(name: "b", withType: P4Type(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),
|
||||
P4Type(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: P4Type(P4Int())), atIndex: 0),
|
||||
Argument(P4Value(P4BooleanValue(withValue: false)), atIndex: 1),
|
||||
])))
|
||||
|
||||
// We expect there to be a hit.
|
||||
#expect(hit_miss == P4TableHitMissValue.Hit)
|
||||
|
||||
// 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))))
|
||||
}
|
||||
|
||||
@Test func test_control_single_integer_key_hit() async throws {
|
||||
let simple_parser_declaration = """
|
||||
control simple(inout int result, int x) {
|
||||
action a() {
|
||||
result = 5;
|
||||
}
|
||||
action b() {
|
||||
result = 7;
|
||||
}
|
||||
table t {
|
||||
key = {
|
||||
x: 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: P4Type) -> Bool in
|
||||
switch tipe.dataType() {
|
||||
case let c as Control: c.name == "simple"
|
||||
default: false
|
||||
}
|
||||
}
|
||||
var control = ((controls[0].dataType() as P4DataType) as! Control)
|
||||
|
||||
// Add entries to the table.
|
||||
control = control.updateTable(
|
||||
addEntry: (
|
||||
P4Value(P4IntValue(withValue: 5)),
|
||||
TypedIdentifier(name: "a", withType: P4Type(Action()))
|
||||
)
|
||||
).updateTable(
|
||||
addEntry: (
|
||||
P4Value(P4IntValue(withValue: 2)),
|
||||
TypedIdentifier(name: "b", withType: P4Type(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),
|
||||
P4Type(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: P4Type(P4Int())), atIndex: 0),
|
||||
Argument(P4Value(P4IntValue(withValue: 5)), atIndex: 1),
|
||||
])))
|
||||
|
||||
// We expect there to be a hit.
|
||||
#expect(hit_miss == P4TableHitMissValue.Hit)
|
||||
|
||||
let result_arg = try #UseOkResult(updated_execution.scopes.lookup(identifier: Identifier(name: "result_arg")))
|
||||
#expect(result_arg.eq(P4Value(P4IntValue(withValue: 5))))
|
||||
}
|
||||
|
||||
@Test func test_control_single_integer_key_miss() async throws {
|
||||
let simple_parser_declaration = """
|
||||
control simple(inout int result, int x) {
|
||||
action a() {
|
||||
result = 5;
|
||||
}
|
||||
action b() {
|
||||
result = 7;
|
||||
}
|
||||
table t {
|
||||
key = {
|
||||
x: 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: P4Type) -> Bool in
|
||||
switch tipe.dataType() {
|
||||
case let c as Control: c.name == "simple"
|
||||
default: false
|
||||
}
|
||||
}
|
||||
var control = ((controls[0].dataType() as P4DataType) as! Control)
|
||||
|
||||
// Add entries to the table.
|
||||
control = control.updateTable(
|
||||
addEntry: (
|
||||
P4Value(P4IntValue(withValue: 1)),
|
||||
TypedIdentifier(name: "a", withType: P4Type(Action()))
|
||||
)
|
||||
).updateTable(
|
||||
addEntry: (
|
||||
P4Value(P4IntValue(withValue: 2)),
|
||||
TypedIdentifier(name: "b", withType: P4Type(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),
|
||||
P4Type(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: P4Type(P4Int())), atIndex: 0),
|
||||
Argument(P4Value(P4IntValue(withValue: 3)), atIndex: 1),
|
||||
])))
|
||||
|
||||
// We expect there to be a hit.
|
||||
#expect(hit_miss == P4TableHitMissValue.Miss)
|
||||
|
||||
let result_arg = try #UseOkResult(updated_execution.scopes.lookup(identifier: Identifier(name: "result_arg")))
|
||||
#expect(result_arg.eq(P4Value(P4IntValue(withValue: 0))))
|
||||
}
|
||||
|
||||
@Test func test_control_multiple_keys() async throws {
|
||||
let simple_parser_declaration = """
|
||||
control simple(inout int result, bool x, int f) {
|
||||
action a() {
|
||||
result = 5;
|
||||
}
|
||||
action b() {
|
||||
result = 7;
|
||||
}
|
||||
table t {
|
||||
key = {
|
||||
x: exact;
|
||||
f: 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: P4Type) -> Bool in
|
||||
switch tipe.dataType() {
|
||||
case let c as Control: c.name == "simple"
|
||||
default: false
|
||||
}
|
||||
}
|
||||
var control = ((controls[0].dataType() as P4DataType) as! Control)
|
||||
|
||||
// Add entries to the table.
|
||||
control = control.updateTable(
|
||||
addEntry: (
|
||||
P4Value(P4BooleanValue(withValue: true)),
|
||||
TypedIdentifier(name: "a", withType: P4Type(Action()))
|
||||
)
|
||||
).updateTable(
|
||||
addEntry: (
|
||||
P4Value(P4IntValue(withValue: 5)),
|
||||
TypedIdentifier(name: "b", withType: P4Type(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),
|
||||
P4Type(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: P4Type(P4Int())), atIndex: 0),
|
||||
Argument(P4Value(P4BooleanValue(withValue: false)), atIndex: 1),
|
||||
Argument(P4Value(P4IntValue(withValue: 5)), atIndex: 2),
|
||||
])))
|
||||
|
||||
// We expect there to be a hit.
|
||||
#expect(hit_miss == P4TableHitMissValue.Hit)
|
||||
|
||||
// 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))))
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user