Refactor Parsing/Runtime

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-02-24 00:28:41 -05:00
parent f9353c683e
commit 64a0fe4255
29 changed files with 1269 additions and 974 deletions
+3 -128
View File
@@ -16,7 +16,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
open class ProgramExecution: CustomStringConvertible {
public var scopes: Scopes = Scopes()
public var scopes: ValueScopes = ValueScopes()
var error: Error?
var debug: DebugLevel = DebugLevel.Error
@@ -75,130 +75,5 @@ open class ProgramExecution: CustomStringConvertible {
}
public struct Scope: CustomStringConvertible, Equatable {
var variables: [Variable] = Array()
public init() {}
public var description: String {
var result = String()
for v in variables {
result += "\(v)\n"
}
return result
}
public var count: Int {
get {
variables.count
}
}
public func set(identifier: Identifier, value: P4Value) -> Scope? {
var updated = false
var updated_scope: [Variable] = Array()
for v in variables {
if v == identifier && v.value_type.type().eq(rhs: value.type()) {
updated = true
updated_scope.append(Variable(name: v.name, withValue: value, isConstant: false))
} else {
updated_scope.append(v)
}
}
var new_scope = Scope()
new_scope.variables = updated_scope
return if updated {
new_scope
} else {
.none
}
}
public func lookup(identifier: Identifier) -> Variable? {
for v in variables {
if v == identifier {
return v
}
}
return .none
}
public mutating func declare(variable: Variable) -> Scope {
var s = self
s.variables.append(variable)
return s
}
}
public struct Scopes: CustomStringConvertible, Equatable {
var scopes: [Scope] = Array()
public init() {}
init(withScopes scopes: [Scope]) {
self.scopes = scopes
}
public func enter() -> Scopes {
var new_scopes = scopes
new_scopes.append(Scope())
return Scopes(withScopes: new_scopes)
}
public func exit() -> Scopes {
var old_scopes = scopes
_ = old_scopes.popLast()
return Scopes(withScopes: old_scopes)
}
public var description: String {
var result = String()
for s in scopes {
result += "Scope:\n\(s)\n"
}
return result
}
public var current: Scope? {
get {
scopes.last
}
}
public func declare(variable: Variable) -> Scopes {
var s = self
if var scope = s.scopes.popLast() {
s.scopes.append(scope.declare(variable: variable))
}
return s
}
public func evaluate(identifier: Identifier) -> Result<P4Value> {
for scope in scopes {
if let vari = scope.lookup(identifier: identifier) {
return .Ok(vari.value)
}
}
return .Error(Error(withMessage: "Cannot find \(identifier) in scope."))
}
public var count: Int {
get {
scopes.count
}
}
public func set(identifier: Identifier, value: P4Value) -> Scopes {
var new_scopes: [Scope] = Array()
for scope in self.scopes {
if let updated_scope = scope.set(identifier: identifier, value: value) {
new_scopes.append(updated_scope)
} else {
new_scopes.append(scope)
}
}
return Scopes(withScopes: new_scopes)
}
}
public typealias ValueScope = Scope<P4Value>
public typealias ValueScopes = Scopes<P4Value>
+40 -17
View File
@@ -16,7 +16,11 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/// A P4 identifier
public class Identifier: CustomStringConvertible, Equatable {
public class Identifier: CustomStringConvertible, Equatable, Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(self.name)
}
var name: String
public init(name: String) {
@@ -32,22 +36,38 @@ public class Identifier: CustomStringConvertible, Equatable {
}
}
/// A P4 variable
public class Variable: Identifier {
var constant: Bool
var value: P4Value
/// A P4 identifier
public class TypedIdentifier: Identifier {
public var parsed_type: P4Type
public init(name: String, withValue value: P4Value, isConstant constant: Bool) {
public init(name: String, withType type: P4Type) {
self.parsed_type = type
super.init(name: name)
}
public override var description: String {
return "\(name)"
}
}
/// A P4 variable
public class Variable: TypedIdentifier {
var constant: Bool
var value: P4Value?
public init(
name: String, withType type: P4Type, withValue value: P4Value?, isConstant constant: Bool
) {
self.constant = constant
self.value = value
super.init(name: name)
super.init(name: name, withType: type)
}
public override var description: String {
return "\(super.description) = \(value) \(constant ? "(constant)" : "")"
}
public var value_type: P4Value {
public var value_type: P4Value? {
value
}
}
@@ -78,6 +98,7 @@ extension P4ValueBase: EvaluatableExpression {
/// The type for a P4 struct
public struct P4Struct: P4Type {
public let name: String
// The type of the struct created is always anonymous.
public static func create() -> any P4Type {
@@ -105,10 +126,10 @@ public struct P4Struct: P4Type {
/// The field of a P4 struct
public struct P4StructField {
public let name: Identifier
public let name: TypedIdentifier
public let type: P4Type
public init(withName name: Identifier, withType type: P4Type) {
public init(withName name: TypedIdentifier, withType type: P4Type) {
self.name = name
self.type = type
}
@@ -124,6 +145,7 @@ public class P4StructValue: P4ValueBase<P4Struct> {
/// A P4 boolean type
public struct P4Boolean: P4Type {
public static func create() -> any P4Type {
return P4Boolean()
}
@@ -132,8 +154,8 @@ public struct P4Boolean: P4Type {
}
public func eq(rhs: P4Type) -> Bool {
return switch rhs {
case is P4Boolean: true
default: false
case is P4Boolean: true
default: false
}
}
}
@@ -167,8 +189,8 @@ public struct P4Int: P4Type {
}
public func eq(rhs: P4Type) -> Bool {
return switch rhs {
case is P4Int: true
default: false
case is P4Int: true
default: false
}
}
}
@@ -192,16 +214,17 @@ public class P4IntValue: P4ValueBase<P4Int> {
/// A P4 string type
public struct P4String: P4Type {
public static func create() -> any P4Type {
return P4String()
}
public var description: String {
return "String"
}
public func eq(rhs: P4Type) -> Bool {
public func eq(rhs: any P4Type) -> Bool {
return switch rhs {
case is P4String: true
default: false
case is P4String: true
default: false
}
}
}
+5 -4
View File
@@ -21,9 +21,10 @@ public protocol EvaluatableExpression {
/// - execution: The execution context in which to evaluate the expression
/// - Returns: The value of expression
func evaluate(execution: ProgramExecution) -> Result<P4Value>
func type() -> any P4Type
}
public protocol EvaluatableParserStatement {
public protocol EvaluatableStatement {
/// Evaluate a statement for a given execution
/// - Parameters
/// - execution: The execution context in which to evaluate the parser statement
@@ -32,11 +33,11 @@ public protocol EvaluatableParserStatement {
}
public protocol P4Type: CustomStringConvertible {
static func create() -> P4Type
func eq(rhs: P4Type) -> Bool
static func create() -> any P4Type
func eq(rhs: any P4Type) -> Bool
}
public protocol P4Value: CustomStringConvertible {
func type() -> P4Type
func type() -> any P4Type
func eq(rhs: P4Value) -> Bool
}
+88 -85
View File
@@ -16,123 +16,126 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
public enum DebugLevel {
case Trace
case Verbose
case Debug
case Error
case Trace
case Verbose
case Debug
case Error
func value() -> UInt8 {
return switch self {
case DebugLevel.Trace: 3
case DebugLevel.Verbose: 2
case DebugLevel.Debug: 1
case DebugLevel.Error: 0
}
}
public func isTrace() -> Bool {
if self.value() >= DebugLevel.Trace.value() {
return true
}
return false
func value() -> UInt8 {
return switch self {
case DebugLevel.Trace: 3
case DebugLevel.Verbose: 2
case DebugLevel.Debug: 1
case DebugLevel.Error: 0
}
public func isVerbose() -> Bool {
if self.value() >= DebugLevel.Verbose.value() {
return true
}
return false
}
public func isTrace() -> Bool {
if self.value() >= DebugLevel.Trace.value() {
return true
}
public func isDebug() -> Bool {
if self.value() >= DebugLevel.Debug.value() {
return true
}
return false
return false
}
public func isVerbose() -> Bool {
if self.value() >= DebugLevel.Verbose.value() {
return true
}
public func isError() -> Bool {
return true
return false
}
public func isDebug() -> Bool {
if self.value() >= DebugLevel.Debug.value() {
return true
}
return false
}
public func isError() -> Bool {
return true
}
public var description: String {
return switch self {
case DebugLevel.Trace: "Trace"
case DebugLevel.Verbose: "Verbose"
case DebugLevel.Debug: "Debug"
case DebugLevel.Error: "Error"
}
public var description: String {
return switch self {
case DebugLevel.Trace: "Trace"
case DebugLevel.Verbose: "Verbose"
case DebugLevel.Debug: "Debug"
case DebugLevel.Error: "Error"
}
}
}
public struct Error: Equatable {
public private(set) var msg: String
public struct Error: Equatable, CustomStringConvertible {
public private(set) var msg: String
public init(withMessage msg: String) {
self.msg = msg
}
public init(withMessage msg: String) {
self.msg = msg
}
public var description: String {
return self.msg
}
}
public struct Nothing: CustomStringConvertible {
public var description: String {
return "Nothing"
}
public var description: String {
return "Nothing"
}
public init() {}
public init() {}
}
public enum Result<OKT>: Equatable {
case Ok(OKT)
case Error(Error)
case Ok(OKT)
case Error(Error)
public static func == (lhs: Result, rhs: Result) -> Bool {
switch (lhs, rhs) {
case (Ok, Ok):
return true
case (Error(let le), Error(let re)):
return le.msg == re.msg
default:
return false
}
public static func == (lhs: Result, rhs: Result) -> Bool {
switch (lhs, rhs) {
case (Ok, Ok):
return true
case (Error(let le), Error(let re)):
return le.msg == re.msg
default:
return false
}
}
public func error() -> Error? {
if case Result.Error(let e) = self {
return e
}
return nil
public func error() -> Error? {
if case Result.Error(let e) = self {
return e
}
return nil
}
public func map<T>(block: (OKT) -> Result<T>) -> Result<T> {
switch self {
case .Ok(let ok): return block(ok)
case .Error(let e): return .Error(e)
}
public func map<T>(block: (OKT) -> Result<T>) -> Result<T> {
switch self {
case .Ok(let ok): return block(ok)
case .Error(let e): return .Error(e)
}
}
}
extension Result where OKT: CustomStringConvertible {
public var description: String {
switch self {
case Result.Error(let e):
return e.msg
case Result.Ok(let o):
return "\(o)"
}
public var description: String {
switch self {
case Result.Error(let e):
return e.msg
case Result.Ok(let o):
return "\(o)"
}
}
}
extension Result {
public var description: String {
switch self {
case Result.Error(let e):
return e.msg
case Result.Ok(_):
return "Ok"
}
extension Result: CustomStringConvertible {
public var description: String {
switch self {
case Result.Error(let e):
return e.msg
case Result.Ok(_):
return "Ok"
}
}
}
@freestanding(expression) public macro RequireOkResult<T>(_: Result<T>) -> Bool =
#externalMacro(module: "Macros", type: "RequireResult")
#externalMacro(module: "Macros", type: "RequireResult")
@freestanding(expression) public macro RequireErrorResult<T>(_: Error, _: Result<T>) -> Bool =
#externalMacro(module: "Macros", type: "RequireErrorResult")
#externalMacro(module: "Macros", type: "RequireErrorResult")
@freestanding(expression) public macro UseOkResult<T>(_: Result<T>) -> T =
#externalMacro(module: "Macros", type: "UseOkResult")
#externalMacro(module: "Macros", type: "UseOkResult")