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:
+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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user