compiler, runtime: Begin Runtime Refactor
Ultimately, the goal is to completely separate the compilation from the runtime to make it possible to have the interpreter/evaluator be "just another" entity that can perform meaningful work when given a parsed GP4 program. Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
@@ -58,7 +58,7 @@ public func Call<T>(
|
||||
param_direction == Direction.InOut || param_direction == Direction.Out
|
||||
{
|
||||
// Let's make sure that it is an evaluatable l value!
|
||||
guard let arg_lvalue = argument.argument as? EvaluatableLValueExpression else {
|
||||
guard let arg_lvalue = argument.argument as? P4LValueExpression else {
|
||||
return (
|
||||
.Error(Error(withMessage: "(in)out parameter argument is not lvalue")),
|
||||
updated_execution.exit_scope()
|
||||
|
||||
@@ -91,10 +91,14 @@ extension Control: LibraryCallable {
|
||||
}
|
||||
}
|
||||
|
||||
extension Action: EvaluatableStatement {
|
||||
extension Action: P4Statement {
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
return context
|
||||
}
|
||||
|
||||
public func evaluate(
|
||||
execution: Common.ProgramExecution
|
||||
) -> (Common.ControlFlow, Common.ProgramExecution) {
|
||||
) -> (ControlFlow, Common.ProgramExecution) {
|
||||
if let body = self.body {
|
||||
return body.evaluate(execution: execution)
|
||||
}
|
||||
|
||||
+135
-109
@@ -22,88 +22,11 @@ extension SelectCaseExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
return (execution.scopes.lookup(identifier: next_state_identifier), execution)
|
||||
}
|
||||
|
||||
public func type() -> P4QualifiedType {
|
||||
return P4QualifiedType(AnyParserState)
|
||||
}
|
||||
}
|
||||
|
||||
extension SelectExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
switch execution.evaluator.EvaluateExpression(self.selector, inExecution: execution) {
|
||||
case (.Ok(let selector_value), let updated_execution):
|
||||
for sce in self.case_expressions {
|
||||
if case (.Ok(let kse), let updated_execution) = updated_execution.evaluator
|
||||
.EvaluateExpression(
|
||||
sce.key, inExecution: updated_execution),
|
||||
kse.eq(selector_value)
|
||||
{
|
||||
//let result = sce.evaluate(execution: updated_execution)
|
||||
let result = updated_execution.evaluator.EvaluateExpression(
|
||||
sce, inExecution: updated_execution)
|
||||
return result
|
||||
}
|
||||
}
|
||||
return (.Error(Error(withMessage: "No key matched the selector")), updated_execution)
|
||||
case (.Error(let e), let updated_execution): return (.Error(e), updated_execution)
|
||||
}
|
||||
}
|
||||
|
||||
public func type() -> P4QualifiedType {
|
||||
return P4QualifiedType(AnyParserState)
|
||||
}
|
||||
}
|
||||
|
||||
// Variables are evaluatable because they can be looked up by identifiers.
|
||||
extension TypedIdentifier: EvaluatableExpression {
|
||||
public func type() -> P4QualifiedType {
|
||||
return self.type
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
return (execution.scopes.lookup(identifier: self), execution)
|
||||
}
|
||||
}
|
||||
|
||||
// Variables are evaluatable because they can be looked up by identifiers.
|
||||
extension TypedIdentifier: EvaluatableLValueExpression {
|
||||
public func set(
|
||||
to: P4Value, inScopes scopes: Common.VarValueScopes,
|
||||
duringExecution execution: ProgramExecution
|
||||
) -> Common.Result<(Common.VarValueScopes, P4Value)> {
|
||||
if case .Error(let e) = scopes.lookup(identifier: self) {
|
||||
return .Error(e)
|
||||
}
|
||||
|
||||
return .Ok((scopes.set(identifier: self, withValue: to), to))
|
||||
}
|
||||
|
||||
public func check(
|
||||
to: any Common.EvaluatableExpression, inScopes scopes: Common.StaticVarValueScopes
|
||||
) -> Result<()> {
|
||||
guard case .Ok(let type) = scopes.lookup(identifier: self) else {
|
||||
return .Error(Error(withMessage: "Cannot assign to identifier not in scope"))
|
||||
}
|
||||
|
||||
return switch type.0.assignableFromType(to.type()) {
|
||||
case TypeCheckResults.IncompatibleTypes:
|
||||
.Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"Cannot assign value with type \(to.type()) to identifier \(self) with type \(type.0)"))
|
||||
case TypeCheckResults.ReadOnly:
|
||||
.Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"Cannot assign value with type \(to.type()) to identifier \(self) that is read only"))
|
||||
case TypeCheckResults.WrongDirection:
|
||||
.Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"Cannot assign value with type \(to.type()) to identifier \(self) that is in parameter")
|
||||
)
|
||||
case TypeCheckResults.Ok: .Ok(())
|
||||
}
|
||||
public func effect(context: CompilerContext) -> CompilerContext {
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +109,7 @@ public func binary_divide_operator_evaluator(left: P4Value, right: P4Value) -> P
|
||||
}
|
||||
|
||||
// swift-format-ignore
|
||||
public typealias BinaryOperatorChecker = (EvaluatableExpression, EvaluatableExpression) -> Result<()>
|
||||
public typealias BinaryOperatorChecker = (EvaluatableExpression, P4Expression) -> Result<()>
|
||||
|
||||
public func binary_and_or_operator_checker(
|
||||
left: EvaluatableExpression, right: EvaluatableExpression
|
||||
@@ -211,6 +134,10 @@ public func binary_int_math_operator_checker(
|
||||
}
|
||||
|
||||
extension BinaryOperatorExpression: EvaluatableExpression {
|
||||
public func effect(context: CompilerContext) -> CompilerContext {
|
||||
return context
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
let updated_execution = execution
|
||||
//let maybe_evaluated_left = self.left.evaluate(execution: updated_execution)
|
||||
@@ -235,7 +162,11 @@ extension BinaryOperatorExpression: EvaluatableExpression {
|
||||
}
|
||||
}
|
||||
|
||||
extension ArrayAccessExpression: EvaluatableExpression {
|
||||
extension ArrayAccessExpression: EvaluatableExpression, EvaluatableLValueExpression {
|
||||
|
||||
public func effect(context: CompilerContext) -> CompilerContext {
|
||||
return context
|
||||
}
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
let updated_execution = execution
|
||||
//let maybe_name = self.name.evaluate(execution: updated_execution)
|
||||
@@ -267,9 +198,7 @@ extension ArrayAccessExpression: EvaluatableExpression {
|
||||
public func type() -> P4QualifiedType {
|
||||
return self.type.value_type()
|
||||
}
|
||||
}
|
||||
|
||||
extension ArrayAccessExpression: EvaluatableLValueExpression {
|
||||
public func set(
|
||||
to: P4Value, inScopes scopes: Common.VarValueScopes,
|
||||
duringExecution execution: ProgramExecution
|
||||
@@ -352,35 +281,13 @@ extension ArrayAccessExpression: EvaluatableLValueExpression {
|
||||
}
|
||||
}
|
||||
|
||||
extension FieldAccessExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
|
||||
let updated_execution = execution
|
||||
//let maybe_struct = self.strct.evaluate(execution: updated_execution)
|
||||
let maybe_struct = updated_execution.evaluator.EvaluateExpression(
|
||||
self.strct, inExecution: updated_execution)
|
||||
guard case (.Ok(let strct), let updated_execution) = maybe_struct else {
|
||||
return maybe_struct
|
||||
}
|
||||
|
||||
guard let struct_strct = strct.dataValue() as? P4StructValue else {
|
||||
return (.Error(Error(withMessage: "\(strct) does not identify a struct")), updated_execution)
|
||||
}
|
||||
|
||||
/// TODO: Create a default value?
|
||||
guard let value = struct_strct.get(field: self.field) else {
|
||||
return (.Error(Error(withMessage: "Missing value")), updated_execution)
|
||||
}
|
||||
|
||||
return (.Ok(value), updated_execution)
|
||||
}
|
||||
|
||||
extension FieldAccessExpression: EvaluatableExpression, EvaluatableLValueExpression {
|
||||
public func type() -> P4QualifiedType {
|
||||
return self.field.type
|
||||
}
|
||||
}
|
||||
|
||||
extension FieldAccessExpression: EvaluatableLValueExpression {
|
||||
public func effect(context: CompilerContext) -> CompilerContext {
|
||||
return context
|
||||
}
|
||||
public func set(
|
||||
to: P4Value, inScopes scopes: Common.VarValueScopes,
|
||||
duringExecution execution: ProgramExecution
|
||||
@@ -459,9 +366,33 @@ extension FieldAccessExpression: EvaluatableLValueExpression {
|
||||
default: .Error(Error(withMessage: "Cannot assign to field \(self.field) of \(self.strct)"))
|
||||
}
|
||||
}
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
|
||||
let updated_execution = execution
|
||||
//let maybe_struct = self.strct.evaluate(execution: updated_execution)
|
||||
let maybe_struct = updated_execution.evaluator.EvaluateExpression(
|
||||
self.strct, inExecution: updated_execution)
|
||||
guard case (.Ok(let strct), let updated_execution) = maybe_struct else {
|
||||
return maybe_struct
|
||||
}
|
||||
|
||||
guard let struct_strct = strct.dataValue() as? P4StructValue else {
|
||||
return (.Error(Error(withMessage: "\(strct) does not identify a struct")), updated_execution)
|
||||
}
|
||||
|
||||
/// TODO: Create a default value?
|
||||
guard let value = struct_strct.get(field: self.field) else {
|
||||
return (.Error(Error(withMessage: "Missing value")), updated_execution)
|
||||
}
|
||||
|
||||
return (.Ok(value), updated_execution)
|
||||
}
|
||||
}
|
||||
|
||||
extension KeysetExpression: EvaluatableExpression {
|
||||
public func effect(context: CompilerContext) -> CompilerContext {
|
||||
return context
|
||||
}
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
//return self.key.evaluate(execution: execution)
|
||||
return execution.evaluator.EvaluateExpression(self.key, inExecution: execution)
|
||||
@@ -473,6 +404,10 @@ extension KeysetExpression: EvaluatableExpression {
|
||||
}
|
||||
|
||||
extension FunctionCall: EvaluatableExpression {
|
||||
|
||||
public func effect(context: CompilerContext) -> CompilerContext {
|
||||
return context
|
||||
}
|
||||
public func evaluate(
|
||||
execution: Common.ProgramExecution
|
||||
) -> (Common.Result<P4Value>, ProgramExecution) {
|
||||
@@ -533,4 +468,95 @@ extension P4Value: EvaluatableExpression {
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
return (.Ok(self), execution)
|
||||
}
|
||||
|
||||
public func effect(context: CompilerContext) -> CompilerContext {
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
||||
extension SelectExpression: EvaluatableExpression {
|
||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||
switch execution.evaluator.EvaluateExpression(self.selector, inExecution: execution) {
|
||||
case (.Ok(let selector_value), let updated_execution):
|
||||
for sce in self.case_expressions {
|
||||
if case (.Ok(let kse), let updated_execution) = updated_execution.evaluator
|
||||
.EvaluateExpression(
|
||||
sce.key, inExecution: updated_execution),
|
||||
kse.eq(selector_value)
|
||||
{
|
||||
//let result = sce.evaluate(execution: updated_execution)
|
||||
let result = updated_execution.evaluator.EvaluateExpression(
|
||||
sce, inExecution: updated_execution)
|
||||
return result
|
||||
}
|
||||
}
|
||||
return (.Error(Error(withMessage: "No key matched the selector")), updated_execution)
|
||||
case (.Error(let e), let updated_execution): return (.Error(e), updated_execution)
|
||||
}
|
||||
}
|
||||
|
||||
public func type() -> P4QualifiedType {
|
||||
return P4QualifiedType(AnyParserState)
|
||||
}
|
||||
|
||||
public func effect(context: CompilerContext) -> CompilerContext {
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
||||
// Variables are evaluatable because they can be looked up by identifiers.
|
||||
extension TypedIdentifier: EvaluatableExpression, EvaluatableLValueExpression {
|
||||
public func evaluate(
|
||||
execution: Common.ProgramExecution
|
||||
) -> (Common.Result<Common.P4Value>, Common.ProgramExecution) {
|
||||
return (execution.scopes.lookup(identifier: self), execution)
|
||||
}
|
||||
|
||||
public func set(
|
||||
to: P4Value, inScopes scopes: Common.VarValueScopes,
|
||||
duringExecution execution: ProgramExecution
|
||||
) -> Common.Result<(Common.VarValueScopes, P4Value)> {
|
||||
if case .Error(let e) = scopes.lookup(identifier: self) {
|
||||
return .Error(e)
|
||||
}
|
||||
|
||||
return .Ok((scopes.set(identifier: self, withValue: to), to))
|
||||
}
|
||||
|
||||
public func type() -> P4QualifiedType {
|
||||
return self.type
|
||||
}
|
||||
|
||||
public func effect(context: CompilerContext) -> CompilerContext {
|
||||
return context
|
||||
}
|
||||
|
||||
// Variables are evaluatable because they can be looked up by identifiers.
|
||||
public func check(
|
||||
to: P4Expression, inScopes scopes: Common.StaticVarValueScopes
|
||||
) -> Result<()> {
|
||||
guard case .Ok(let type) = scopes.lookup(identifier: self) else {
|
||||
return .Error(Error(withMessage: "Cannot assign to identifier not in scope"))
|
||||
}
|
||||
|
||||
return switch type.0.assignableFromType(to.type()) {
|
||||
case TypeCheckResults.IncompatibleTypes:
|
||||
.Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"Cannot assign value with type \(to.type()) to identifier \(self) with type \(type.0)"))
|
||||
case TypeCheckResults.ReadOnly:
|
||||
.Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"Cannot assign value with type \(to.type()) to identifier \(self) that is read only"))
|
||||
case TypeCheckResults.WrongDirection:
|
||||
.Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"Cannot assign value with type \(to.type()) to identifier \(self) that is in parameter")
|
||||
)
|
||||
case TypeCheckResults.Ok: .Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
import Common
|
||||
import P4Lang
|
||||
|
||||
extension ParserAssignmentStatement: EvaluatableStatement {
|
||||
extension ParserAssignmentStatement: P4Statement {
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
return context
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
let updated_execution = execution
|
||||
//let result = self.value.evaluate(execution: updated_execution)
|
||||
@@ -192,3 +196,19 @@ extension ParserValue: LibraryCallable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ParserState: P4Statement {
|
||||
public func evaluate(
|
||||
execution: Common.ProgramExecution
|
||||
) -> (Common.ControlFlow, Common.ProgramExecution) {
|
||||
return (
|
||||
ControlFlow.Error,
|
||||
execution.setError(error: Error(withMessage: "Cannot evaluate unspecialized parser state"))
|
||||
)
|
||||
}
|
||||
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
return context.update(
|
||||
newTypes: context.types.declare(identifier: self.getName(), withValue: self))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
import Common
|
||||
import P4Lang
|
||||
|
||||
extension BlockStatement: EvaluatableStatement {
|
||||
extension BlockStatement: P4Statement {
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
return context
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
return execution.evaluator.ExecuteStatements(
|
||||
self.statements, inExecution: execution
|
||||
@@ -38,7 +42,14 @@ extension BlockStatement: EvaluatableStatement {
|
||||
}
|
||||
}
|
||||
|
||||
extension VariableDeclarationStatement: EvaluatableStatement {
|
||||
extension VariableDeclarationStatement: P4Statement {
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
return context.update(
|
||||
newInstances: context.instances.declare(
|
||||
identifier: self.identifier, withValue: (self.identifier.type(), .none)))
|
||||
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
guard
|
||||
//case (.Ok(let initial_value), let execution) = self.initializer.evaluate(execution: execution)
|
||||
@@ -56,7 +67,11 @@ extension VariableDeclarationStatement: EvaluatableStatement {
|
||||
}
|
||||
}
|
||||
|
||||
extension ConditionalStatement: EvaluatableStatement {
|
||||
extension ConditionalStatement: P4Statement {
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
return context
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
guard
|
||||
//case (.Ok(let evaluated_condition), let execution) = self.condition.evaluate(execution: execution)
|
||||
@@ -105,7 +120,11 @@ extension ConditionalStatement: EvaluatableStatement {
|
||||
}
|
||||
}
|
||||
|
||||
extension ExpressionStatement: EvaluatableStatement {
|
||||
extension ExpressionStatement: P4Statement {
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
return context
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
|
||||
// Evaluate, there might be side effects!
|
||||
@@ -118,7 +137,12 @@ extension ExpressionStatement: EvaluatableStatement {
|
||||
}
|
||||
}
|
||||
|
||||
extension ReturnStatement: EvaluatableStatement {
|
||||
extension ReturnStatement: P4Statement {
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
//return switch self.value.evaluate(execution: execution) {
|
||||
return switch execution.evaluator.EvaluateExpression(self.value, inExecution: execution) {
|
||||
@@ -128,8 +152,42 @@ extension ReturnStatement: EvaluatableStatement {
|
||||
}
|
||||
}
|
||||
|
||||
extension ApplyStatement: EvaluatableStatement {
|
||||
extension ApplyStatement: P4Statement {
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
|
||||
return context
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
return (ControlFlow.Next, execution)
|
||||
}
|
||||
}
|
||||
|
||||
extension Instantiation: P4Statement {
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
return context
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
return (ControlFlow.Next, execution)
|
||||
}
|
||||
}
|
||||
|
||||
extension Declaration: P4Statement {
|
||||
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
|
||||
if self.extern {
|
||||
return context.update(
|
||||
newExterns: context.externs.declare(
|
||||
identifier: self.identifier, withValue: self))
|
||||
}
|
||||
|
||||
return context.update(
|
||||
newTypes: context.types.declare(
|
||||
identifier: self.identifier, withValue: self.identifier.type().baseType()))
|
||||
}
|
||||
|
||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||
//// TODO
|
||||
return (ControlFlow.Next, execution)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user