runtime: Refactor Expression/Statement Evaluators
Allow the user to customize the evaluation/execution of expressions/ statements with something that implements functions that perform those tasks. This additional functionality will make it possible for the "classic" evaluator not to waste time checking for the presence of interlopers and give implementers additional customization opportunities. Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
+137
-30
@@ -15,6 +15,137 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
public typealias ExecuteStatementResultHandler = (ControlFlow, ProgramExecution) -> (
|
||||
ControlFlow, ProgramExecution
|
||||
)
|
||||
|
||||
public struct ClassicEvaluator: ProgramExecutionEvaluator {
|
||||
public func ExecuteStatement(
|
||||
_ statements: [EvaluatableStatement], handleResult handler: ExecuteStatementResultHandler,
|
||||
inExecution execution: ProgramExecution,
|
||||
) -> (ControlFlow, ProgramExecution) {
|
||||
|
||||
var execution = execution
|
||||
for s in statements {
|
||||
let (control_flow, next_execution) = s.evaluate(execution: execution)
|
||||
|
||||
switch handler(control_flow, next_execution) {
|
||||
case (ControlFlow.Next, let handled_next_execution): execution = handled_next_execution
|
||||
case (ControlFlow.Return(let value), let handled_next_execution):
|
||||
return (ControlFlow.Return(value), handled_next_execution)
|
||||
case (let handled_control_flow, let handled_next_execution):
|
||||
return (handled_control_flow, handled_next_execution)
|
||||
}
|
||||
}
|
||||
return (ControlFlow.Next, execution)
|
||||
}
|
||||
|
||||
public func ExecuteStatement(
|
||||
_ statement: EvaluatableStatement, handleResult handler: ExecuteStatementResultHandler,
|
||||
inExecution execution: ProgramExecution
|
||||
) -> (ControlFlow, ProgramExecution) {
|
||||
return ExecuteStatement([statement], handleResult: handler, inExecution: execution)
|
||||
}
|
||||
|
||||
public func EvaluateExpression(
|
||||
_ expression: EvaluatableExpression, inExecution execution: ProgramExecution,
|
||||
) -> (Result<P4Value>, ProgramExecution) {
|
||||
return expression.evaluate(execution: execution)
|
||||
}
|
||||
}
|
||||
|
||||
public struct InterloperEvaluator: ProgramExecutionEvaluator {
|
||||
var statement_interloper: StatementInterloper?
|
||||
var expression_interloper: ExpressionInterloper?
|
||||
|
||||
public init() {}
|
||||
|
||||
public func getStatementInterloper() -> StatementInterloper? {
|
||||
return self.statement_interloper
|
||||
}
|
||||
|
||||
public func setStatementInterloper(
|
||||
_ interloper: @escaping StatementInterloper
|
||||
) -> InterloperEvaluator {
|
||||
var pe = self
|
||||
pe.statement_interloper = interloper
|
||||
return pe
|
||||
}
|
||||
|
||||
public func getExpressionInterloper() -> ExpressionInterloper? {
|
||||
return self.expression_interloper
|
||||
}
|
||||
|
||||
public func setExpressionInterloper(
|
||||
_ interloper: @escaping ExpressionInterloper
|
||||
) -> InterloperEvaluator {
|
||||
var pe = self
|
||||
pe.expression_interloper = interloper
|
||||
return pe
|
||||
}
|
||||
|
||||
public func ExecuteStatement(
|
||||
_ statements: [EvaluatableStatement], handleResult handler: ExecuteStatementResultHandler,
|
||||
inExecution execution: ProgramExecution,
|
||||
) -> (ControlFlow, ProgramExecution) {
|
||||
|
||||
var debugger: StatementInterloper? = .none
|
||||
var hasDebugInterloper = false
|
||||
if let found_deb = self.getStatementInterloper() {
|
||||
debugger = found_deb
|
||||
hasDebugInterloper = true
|
||||
}
|
||||
|
||||
var execution = execution
|
||||
for s in statements {
|
||||
let (control_flow, next_execution) = s.evaluate(execution: execution)
|
||||
|
||||
if hasDebugInterloper {
|
||||
debugger!(s, control_flow, next_execution)
|
||||
}
|
||||
|
||||
switch handler(control_flow, next_execution) {
|
||||
case (ControlFlow.Next, let handled_next_execution): execution = handled_next_execution
|
||||
case (ControlFlow.Return(let value), let handled_next_execution):
|
||||
return (ControlFlow.Return(value), handled_next_execution)
|
||||
case (let handled_control_flow, let handled_next_execution):
|
||||
return (handled_control_flow, handled_next_execution)
|
||||
}
|
||||
}
|
||||
return (ControlFlow.Next, execution)
|
||||
}
|
||||
|
||||
public func ExecuteStatement(
|
||||
_ statement: EvaluatableStatement, handleResult handler: ExecuteStatementResultHandler,
|
||||
inExecution execution: ProgramExecution
|
||||
) -> (ControlFlow, ProgramExecution) {
|
||||
return ExecuteStatement([statement], handleResult: handler, inExecution: execution)
|
||||
}
|
||||
|
||||
public func EvaluateExpression(
|
||||
_ expression: EvaluatableExpression, inExecution execution: ProgramExecution,
|
||||
) -> (Result<P4Value>, ProgramExecution) {
|
||||
|
||||
var debugger: ExpressionInterloper? = .none
|
||||
var hasDebugInterloper = false
|
||||
if let found_deb = self.getExpressionInterloper() {
|
||||
debugger = found_deb
|
||||
hasDebugInterloper = true
|
||||
}
|
||||
|
||||
let (result, execution) = expression.evaluate(execution: execution)
|
||||
|
||||
if hasDebugInterloper {
|
||||
debugger!(expression, result, execution)
|
||||
}
|
||||
|
||||
return (result, execution)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public typealias StatementInterloper = (EvaluatableStatement, ControlFlow, ProgramExecution) -> Void
|
||||
public typealias ExpressionInterloper = (EvaluatableExpression, Result<P4Value>, ProgramExecution)
|
||||
-> Void
|
||||
@@ -24,24 +155,24 @@ open class ProgramExecution: CustomStringConvertible {
|
||||
var globalValues: VarValueScopes?
|
||||
var error: Error?
|
||||
var debug: DebugLevel = DebugLevel.Error
|
||||
var statement_interloper: StatementInterloper?
|
||||
var expression_interloper: ExpressionInterloper?
|
||||
public let evaluator: ProgramExecutionEvaluator
|
||||
|
||||
init(copy: ProgramExecution) {
|
||||
self.scopes = copy.scopes
|
||||
self.globalValues = copy.globalValues
|
||||
self.error = copy.error
|
||||
self.debug = copy.debug
|
||||
self.statement_interloper = copy.statement_interloper
|
||||
self.expression_interloper = copy.expression_interloper
|
||||
self.evaluator = copy.evaluator
|
||||
}
|
||||
|
||||
public init() {
|
||||
globalValues = .none
|
||||
evaluator = ClassicEvaluator()
|
||||
}
|
||||
|
||||
public init(withGlobalValues values: VarValueScopes) {
|
||||
globalValues = values
|
||||
public init(_ evaluator: ProgramExecutionEvaluator) {
|
||||
globalValues = .none
|
||||
self.evaluator = evaluator
|
||||
}
|
||||
|
||||
open var description: String {
|
||||
@@ -72,30 +203,6 @@ open class ProgramExecution: CustomStringConvertible {
|
||||
return pe
|
||||
}
|
||||
|
||||
public func getStatementInterloper() -> StatementInterloper? {
|
||||
return self.statement_interloper
|
||||
}
|
||||
|
||||
public func setStatementInterloper(
|
||||
_ interloper: @escaping StatementInterloper
|
||||
) -> ProgramExecution {
|
||||
let pe = ProgramExecution(copy: self)
|
||||
pe.statement_interloper = interloper
|
||||
return pe
|
||||
}
|
||||
|
||||
public func getExpressionInterloper() -> ExpressionInterloper? {
|
||||
return self.expression_interloper
|
||||
}
|
||||
|
||||
public func setExpressionInterloper(
|
||||
_ interloper: @escaping ExpressionInterloper
|
||||
) -> ProgramExecution {
|
||||
let pe = ProgramExecution(copy: self)
|
||||
pe.expression_interloper = interloper
|
||||
return pe
|
||||
}
|
||||
|
||||
open func isDone() -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user