// 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 . 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, 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: P4Statement { public func effect(context: Common.CompilerContext) -> Common.CompilerContext { return context } public func evaluate( execution: Common.ProgramExecution ) -> (ControlFlow, Common.ProgramExecution) { if let body = self.body { return body.evaluate(execution: execution) } return (ControlFlow.Next, execution) } }