parser, compiler: Support Table Actions
Continuous Integration / Grammar Tests (push) Has been cancelled
Continuous Integration / Library Tests (push) Has been cancelled
Continuous Integration / Library Format Tests (push) Has been cancelled

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-04-30 05:38:29 -04:00
parent 833979a5c9
commit b97aa1af72
6 changed files with 342 additions and 17 deletions
+75 -7
View File
@@ -459,6 +459,10 @@ extension Control: CompilableDeclaration {
}
actions.append(action_declaration)
local_context = updated_context
// Now, add the declaration into the context.
local_context = local_context.update(
newTypes: local_context.types.declare(
identifier: action_declaration.name, withValue: action_declaration))
} else if current_node.nodeType == "table_declaration" {
let maybe_table_declaration = Table.Compile(
node: current_node, withContext: local_context)
@@ -721,6 +725,58 @@ extension TableKeys: Compilable {
}
}
extension TableActionsProperty: Compilable {
public typealias T = TableActionsProperty
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TableActionsProperty, CompilerContext)> {
#RequireNodeType<Node, (TableActionsProperty, CompilerContext)>(
node: node, type: "table_actions", nice_type_name: "Table Actions")
var walker = Walker(node: node)
// Skip the
// actions = {
// 1 2 3
walker.next() // 1
walker.next() // 2
walker.next() // 3
var current_node: Node? = .none
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(TableActionsProperty, CompilerContext)>.Error(
ErrorOnNode(
node: node, withError: "Missing table actions declaration component in control declaration"))
)
let (actions, errors) = walker.try_map(n: node.childCount - 1, onlyNamed: true) { current_node in
switch Identifier.Compile(node: current_node, withContext: context) {
case .Ok(let listed_action):
switch context.types.lookup(identifier: listed_action) {
case .Ok(let maybe_action):
if maybe_action.eq(rhs: Action()) {
return .Ok(TypedIdentifier(id: listed_action, withType: P4Type(maybe_action)))
}
return .Error(
ErrorOnNode(node: node, withError: "\(listed_action) does not name an action"))
case .Error(let e): return .Error(e)
}
case .Error(let e): return .Error(e)
}
}
if !errors.isEmpty {
return .Error(
ErrorOnNode(node: node, withError: "Error(s) parsing table actions: "
+ (errors.map { error in
return "\(error.msg)"
}.joined(separator: ";"))))
}
return .Ok((TableActionsProperty(actions), context))
}
}
extension TablePropertyList: Compilable {
public typealias T = TablePropertyList
public static func Compile(
@@ -733,7 +789,7 @@ extension TablePropertyList: Compilable {
var current_context = context
var keys: [TableKeys] = Array()
var _: [Action] = Array() // Actions are not yet supported
var actions: [TableActionsProperty] = Array()
var errors: [Error] = Array()
node.enumerateNamedChildren { child in
@@ -745,9 +801,12 @@ extension TablePropertyList: Compilable {
case .Error(let e): errors.append(e)
}
} else if child.nodeType == "table_actions" {
errors.append(
ErrorOnNode(
node: child, withError: "Actions in table property lists are not yet supported"))
switch TableActionsProperty.Compile(node: child, withContext: current_context) {
case .Ok((let table_action_property, let updated_context)):
current_context = updated_context
actions.append(table_action_property)
case .Error(let e): errors.append(e)
}
} else {
errors.append(
ErrorOnNode(node: child, withError: "Uknown node type in control declaration"))
@@ -756,8 +815,7 @@ extension TablePropertyList: Compilable {
if !errors.isEmpty {
return .Error(
Error(
withMessage: "Error(s) parsing property list: "
ErrorOnNode(node: node, withError: "Error(s) parsing property list: "
+ (errors.map { error in
return "\(error.msg)"
}.joined(separator: ";"))))
@@ -770,7 +828,17 @@ extension TablePropertyList: Compilable {
ErrorOnNode(node: node, withError: "More than one key set in table property list"))
}
return .Ok((TablePropertyList(withActions: TableActions(), withKeys: keys[0]), current_context))
// There should be only one table keys!
if actions.count > 1 {
// Todo: Make this error message better.
return .Error(
ErrorOnNode(node: node, withError: "More than one actions in table property list"))
}
if actions.isEmpty {
actions.append(TableActionsProperty())
}
return .Ok((TablePropertyList(withActions: actions[0], withKeys: keys[0]), current_context))
}
}
+17
View File
@@ -51,4 +51,21 @@ public struct Walker {
}
return Result.Ok(())
}
public func try_map<T>(n: Int, onlyNamed: Bool = false, todo: (Node) -> Result<T>) -> ([T], [Error]) {
var errors: [Error] = Array()
var results: [T] = Array()
for currentChildIdx in currentChildIdx..<n {
let currentChild = node.child(at: currentChildIdx)!
if onlyNamed && !currentChild.isNamed {
continue
}
switch todo(currentChild) {
case .Ok(let r): results.append(r)
case .Error(let e): errors.append(e)
}
}
return (results, errors)
}
}
+69 -9
View File
@@ -17,7 +17,57 @@
import Common
public struct Action: CustomStringConvertible {
public struct Action: CustomStringConvertible, P4DataType, P4DataValue {
public func type() -> any Common.P4DataType {
return self
}
public func eq(rhs: any Common.P4DataValue) -> Bool {
return switch rhs {
case let arhs as Action: self.name == arhs.name
default: false
}
}
public func eq(rhs: any Common.P4DataType) -> Bool {
return switch rhs {
case is Action: true
default: false
}
}
public func lt(rhs: any Common.P4DataValue) -> Bool {
switch rhs {
case let arhs as Action: return self.name < arhs.name
default: return false
}
}
public func lte(rhs: any Common.P4DataValue) -> Bool {
switch rhs {
case let arhs as Action: return self.name <= arhs.name
default: return false
}
}
public func gt(rhs: any Common.P4DataValue) -> Bool {
switch rhs {
case let arhs as Action: return self.name > arhs.name
default: return false
}
}
public func gte(rhs: any Common.P4DataValue) -> Bool {
switch rhs {
case let arhs as Action: return self.name >= arhs.name
default: return false
}
}
public func def() -> any Common.P4DataValue {
return Action()
}
public var description: String {
return "Action: "
+ "\(self.name) with parameters \(self.params) and body \(String(describing: self.body))"
@@ -28,8 +78,8 @@ public struct Action: CustomStringConvertible {
public var name: Identifier
public init(
named name: Identifier, withParameters parameters: ParameterList,
withBody body: BlockStatement?
named name: Identifier = Identifier(name: ""), withParameters parameters: ParameterList = ParameterList([]),
withBody body: BlockStatement? = .none
) {
self.name = name
self.params = parameters
@@ -88,15 +138,24 @@ public struct TableKeys: CustomStringConvertible {
}
}
/// TODO
public struct TableActions {
public init() {}
public struct TableActionsProperty: CustomStringConvertible {
public let actions: [TypedIdentifier]
public init(_ actions: [TypedIdentifier] = []) {
self.actions = actions
}
public var description: String {
return "Table Actions: "
+ self.actions.map { action in
return action.description
}.joined(separator: ";")
}
}
public struct TablePropertyList: CustomStringConvertible {
let actions: TableActions
let actions: TableActionsProperty
let keys: TableKeys
public init(withActions actions: TableActions, withKeys keys: TableKeys) {
public init(withActions actions: TableActionsProperty, withKeys keys: TableKeys) {
self.actions = actions
self.keys = keys
}
@@ -208,7 +267,8 @@ public struct Control: P4DataType, P4DataValue, Equatable, CustomStringConvertib
withParameters: ParameterList(),
withTable: Table(
withName: Identifier(name: "empty"),
withPropertyList: TablePropertyList(withActions: TableActions(), withKeys: TableKeys())),
withPropertyList: TablePropertyList(
withActions: TableActionsProperty(), withKeys: TableKeys())),
withActions: Actions(withActions: []), withApply: ApplyStatement())
}