compiler, runtime: Begin Runtime Refactor
Continuous Integration / Grammar Tests (push) Failing after 39s
Continuous Integration / Library Format Tests (push) Successful in 1m46s
Continuous Integration / Library Tests (push) Successful in 4m38s

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:
Will Hawkins
2026-05-29 08:41:49 -04:00
parent 18461a9215
commit 44e93e4cda
30 changed files with 1264 additions and 854 deletions
+1 -1
View File
@@ -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()
+6 -2
View File
@@ -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
View File
@@ -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(())
}
}
}
+21 -1
View File
@@ -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))
}
}
+64 -6
View File
@@ -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)
}
}