61d8f601e8
In P4, parsers are considered types. Those parsers are instantiated. The instantiated parsers are values. Previously, gp4 treated a parser type and a parser value as identical. This PR makes that difference clear _and_ sets the stage for the future. TODO: Make the same distinction between control and action types and values. Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
195 lines
6.6 KiB
Swift
195 lines
6.6 KiB
Swift
// 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 ParserAssignmentStatement: EvaluatableStatement {
|
|
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
|
let updated_execution = execution
|
|
//let result = self.value.evaluate(execution: updated_execution)
|
|
let result = updated_execution.evaluator.EvaluateExpression(
|
|
self.value, inExecution: updated_execution)
|
|
guard case (.Ok(let value), let updated_execution) = result else {
|
|
return (ControlFlow.Error, execution.setError(error: result.0.error()!))
|
|
}
|
|
|
|
let maybe_updated_scopes = self.lvalue.set(
|
|
to: value, inScopes: execution.scopes, duringExecution: updated_execution)
|
|
guard case Result.Ok(let updated_scopes) = maybe_updated_scopes else {
|
|
return (ControlFlow.Error, execution.setError(error: maybe_updated_scopes.error()!))
|
|
}
|
|
execution.scopes = updated_scopes.0
|
|
|
|
return (ControlFlow.Next, updated_execution)
|
|
}
|
|
}
|
|
|
|
extension ParserStateDirectTransitionValue: EvaluatableParserState {
|
|
public func execute(
|
|
program: Common.ProgramExecution
|
|
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
|
var program = program.enter_scope()
|
|
|
|
let (control_flow, next_execution) = program.evaluator.ExecuteStatements(
|
|
self.state.statements, inExecution: program)
|
|
|
|
switch control_flow {
|
|
case .Next: program = next_execution
|
|
case .Error: return (reject, next_execution.exit_scope())
|
|
default:
|
|
return (
|
|
reject,
|
|
next_execution.exit_scope().setError(
|
|
error: Error(withMessage: "Invalid control flow (\(control_flow) in parser)"))
|
|
)
|
|
}
|
|
|
|
return (self.next_state as! EvaluatableParserState, program.exit_scope())
|
|
}
|
|
|
|
public func done() -> Bool {
|
|
return false
|
|
}
|
|
|
|
public func state() -> P4Lang.ParserState {
|
|
return self.state
|
|
}
|
|
}
|
|
|
|
extension ParserStateNoTransitionValue: EvaluatableParserState {
|
|
public func execute(
|
|
program: Common.ProgramExecution
|
|
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
|
return (self, program)
|
|
}
|
|
|
|
public func done() -> Bool {
|
|
return true
|
|
}
|
|
|
|
public func state() -> P4Lang.ParserState {
|
|
return self.state
|
|
}
|
|
}
|
|
|
|
extension ParserStateSelectTransitionValue: EvaluatableParserState {
|
|
public func execute(
|
|
program: Common.ProgramExecution
|
|
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
|
var program = program.enter_scope()
|
|
|
|
let (control_flow, next_execution) = program.evaluator.ExecuteStatements(
|
|
self.state.statements, inExecution: program)
|
|
switch control_flow {
|
|
case .Next: program = next_execution
|
|
case .Error: return (reject, next_execution.exit_scope())
|
|
default:
|
|
return (
|
|
reject,
|
|
next_execution.exit_scope().setError(
|
|
error: Error(withMessage: "Invalid control flow (\(control_flow) in parser)"))
|
|
)
|
|
}
|
|
|
|
switch program.evaluator.EvaluateExpression(self.te, inExecution: program) {
|
|
case (.Ok(let value), let program):
|
|
if AnyParserState.eq(rhs: value.type().baseType()) {
|
|
return (value.dataValue() as! EvaluatableParserState, program.exit_scope())
|
|
} else {
|
|
return (
|
|
self,
|
|
program.setError(
|
|
error: Error(withMessage: "Select transition transitioned to a none state"))
|
|
)
|
|
}
|
|
case (.Error(let e), let program): return (self, program.setError(error: e).exit_scope())
|
|
}
|
|
}
|
|
|
|
public func done() -> Bool {
|
|
return false
|
|
}
|
|
|
|
public func state() -> P4Lang.ParserState {
|
|
return self.state
|
|
}
|
|
}
|
|
|
|
extension ParserValue: LibraryCallable {
|
|
public typealias T = InstantiatedParserState
|
|
public func call(
|
|
execution: Common.ProgramExecution, arguments: ArgumentList
|
|
) -> (P4Lang.InstantiatedParserState, Common.ProgramExecution) {
|
|
var execution = execution.enter_scope()
|
|
|
|
execution = execution.declare(
|
|
identifier: accept.state().getName(),
|
|
withValue: P4Value(accept, P4QualifiedType.ReadOnly(accept.type())))
|
|
execution = execution.declare(
|
|
identifier: reject.state().getName(),
|
|
withValue: P4Value(reject, P4QualifiedType.ReadOnly(reject.type())))
|
|
|
|
// Add initial values to the global scope
|
|
for (name, value) in execution.getGlobalValues() {
|
|
execution = execution.declare(identifier: name, withValue: value)
|
|
}
|
|
|
|
// First, add every state to the scope!
|
|
for state in self.tipe.states.states {
|
|
guard let instantiated_state = state.instantiate(state.getName()) else {
|
|
return (
|
|
reject,
|
|
execution.setError(error: Error(withMessage: "Could not instantiate \(state.getName())"))
|
|
)
|
|
}
|
|
execution = execution.declare(
|
|
identifier: state.getName(), withValue: P4Value(instantiated_state))
|
|
}
|
|
|
|
guard let _current_state = self.tipe.findStartState(),
|
|
var current_state = _current_state.instantiate(Identifier(name: "start"))
|
|
as? EvaluatableParserState
|
|
else {
|
|
return (
|
|
reject, execution.setError(error: Error(withMessage: "Could not find the start state"))
|
|
)
|
|
}
|
|
|
|
let call_body: (ProgramExecution) -> (Result<P4Value>, ProgramExecution) = {
|
|
(execution: ProgramExecution) in
|
|
var current_execution = execution
|
|
// Evaluate until the state is either accept or reject.
|
|
while !current_state.done() && !current_execution.hasError() {
|
|
(current_state, current_execution) = current_state.execute(program: current_execution)
|
|
}
|
|
return (.Ok(P4Value((current_state))), current_execution)
|
|
}
|
|
|
|
return
|
|
switch Call(
|
|
body: call_body, withArguments: arguments, withParameters: self.tipe.parameters,
|
|
inExecution: execution)
|
|
{
|
|
case (.Ok(let value), let updated_execution):
|
|
(value.dataValue() as! InstantiatedParserState, updated_execution)
|
|
case (.Error(let e), let updated_execution):
|
|
(reject, updated_execution.setError(error: Error(withMessage: "Cannot call parser: \(e)")))
|
|
}
|
|
}
|
|
}
|