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
+241
View File
@@ -0,0 +1,241 @@
// p4rse, Copyright 2026, Will Hawkins
//
// This file is part of p4rse.
//
// This file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// 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 enum TypeCheckResults: Equatable {
case Ok
case ReadOnly
case WrongDirection
case IncompatibleTypes
}
public enum Direction: Equatable, CustomStringConvertible {
case In
case Out
case InOut
public var description: String {
return switch self {
case Direction.In: "In"
case Direction.Out: "Out"
case Direction.InOut: "InOut"
}
}
/// Compare two optional ``Direction``s
static public func eqopt(_ lhs: Direction?, _ rhs: Direction?) -> Bool {
// If both are empty, they are the same.
if lhs == .none && rhs == .none {
return true
}
// If one is empty, they are different
if lhs == .none || rhs == .none {
return false
}
// Both have values -- compare them natively.
return lhs! == rhs!
}
}
public enum P4TypeQualifier: Equatable {
case Direction(Direction)
case Readonly // Not yet used -- here to keep Swift warnings at bay
}
public struct P4TypeQualifiers: CustomStringConvertible {
let _qualifiers: [P4TypeQualifier]
public init(_ qualifiers: [P4TypeQualifier]) {
self._qualifiers = qualifiers
}
public func direction() -> Direction? {
let result = _qualifiers.firstIndex { attribute in
return switch attribute {
case .Direction(_): true
default: false
}
}
return result.flatMap { index in
return switch _qualifiers[index] {
case .Direction(let d): d
default: Optional<Direction>.none
}
}
}
public func readOnly() -> Bool {
return _qualifiers.contains { attribute in
return switch attribute {
case .Readonly: true
default: false
}
}
}
public func update(removeAttribute attributeToRemove: P4TypeQualifier) -> P4TypeQualifiers {
var new_attributes = self._qualifiers
new_attributes.removeAll { item in
return item == attributeToRemove
}
return P4TypeQualifiers(new_attributes)
}
public func update(addAttribute attributeToAdd: P4TypeQualifier) -> P4TypeQualifiers {
return P4TypeQualifiers(self._qualifiers + [attributeToAdd])
}
public var description: String {
return self._qualifiers.map { qualifier in
return "\(qualifier)"
}.joined(separator: ",")
}
public static func ReadOnly() -> P4TypeQualifiers {
return P4TypeQualifiers([P4TypeQualifier.Readonly])
}
}
public struct P4QualifiedType: CustomStringConvertible {
let _attributes: P4TypeQualifiers
let base_type: P4Type
public init(_ base_type: P4Type, _ attributes: P4TypeQualifiers = P4TypeQualifiers([])) {
self._attributes = attributes
self.base_type = base_type
}
public func update(removeAttribute attribute: P4TypeQualifier) -> P4QualifiedType {
return P4QualifiedType(self.base_type, self._attributes.update(removeAttribute: attribute))
}
public func update(addAttribute attribute: P4TypeQualifier) -> P4QualifiedType {
return P4QualifiedType(self.base_type, self._attributes.update(addAttribute: attribute))
}
public func direction() -> Direction? {
return self._attributes.direction()
}
public func readOnly() -> Bool {
return self._attributes.readOnly()
}
public func baseType() -> P4Type {
return self.base_type
}
public func def() -> P4Value? {
if let default_value = self.base_type.def() {
return P4Value(default_value, self)
}
return .none
}
public func eq(_ rhs: P4QualifiedType) -> Bool {
return self.direction() == rhs.direction() && self.readOnly() == self.readOnly()
&& self.baseType().eq(rhs: rhs.baseType())
}
public func assignable() -> TypeCheckResults {
if self.readOnly() {
return TypeCheckResults.ReadOnly
}
if let direction = direction(),
direction == Direction.In
{
return TypeCheckResults.WrongDirection
}
return TypeCheckResults.Ok
}
public func assignableFromType(_ rhs: P4QualifiedType) -> TypeCheckResults {
if !self.baseType().eq(rhs: rhs.baseType()) {
return TypeCheckResults.IncompatibleTypes
}
if self.readOnly() {
return TypeCheckResults.ReadOnly
}
if let direction = direction(),
direction == Direction.In
{
return TypeCheckResults.WrongDirection
}
return TypeCheckResults.Ok
}
public static func ReadOnly(_ type: P4Type) -> P4QualifiedType {
return P4QualifiedType(type, P4TypeQualifiers.ReadOnly())
}
public var description: String {
var attributes_description = "\(self._attributes)"
if !attributes_description.isEmpty {
attributes_description += " "
}
return "\(attributes_description)\(self.base_type)"
}
}
public struct P4Value: CustomStringConvertible {
let _value: P4DataValue
let _type: P4QualifiedType
public init(_ value: P4DataValue, _ type: P4QualifiedType? = .none) {
self._value = value
self._type = type != nil ? type! : P4QualifiedType(value.type())
}
public func update(withNewValue value: P4DataValue) -> Result<P4Value> {
/// TODO: Check that the types match.
return .Ok(P4Value(value, self._type))
}
public var description: String {
return "Value: \(self._value) of type \(self._type)"
}
public func type() -> P4QualifiedType {
return self._type
}
public func dataValue() -> P4DataValue {
return self._value
}
public func eq(_ rhs: P4Value) -> Bool {
return self._value.eq(rhs: rhs.dataValue())
}
public func lt(_ rhs: P4Value) -> Bool {
return self._value.lt(rhs: rhs.dataValue())
}
public func lte(_ rhs: P4Value) -> Bool {
return self._value.lte(rhs: rhs.dataValue())
}
public func gt(_ rhs: P4Value) -> Bool {
return self._value.gt(rhs: rhs.dataValue())
}
public func gte(_ rhs: P4Value) -> Bool {
return self._value.gte(rhs: rhs.dataValue())
}
}