diff --git a/Package.swift b/Package.swift
index 3b2148d..62edd3c 100644
--- a/Package.swift
+++ b/Package.swift
@@ -14,8 +14,16 @@ let package = Package(
targets: ["Parser"]
),
.library(
- name: "P4",
- targets: ["P4"]
+ name: "Common",
+ targets: ["Common"]
+ ),
+ .library(
+ name: "Lang",
+ targets: ["Lang"]
+ ),
+ .library(
+ name: "Runtime",
+ targets: ["Runtime"]
),
],
dependencies: [
@@ -38,7 +46,8 @@ let package = Package(
.product(name: "SwiftTreeSitterLayer", package: "swift-tree-sitter"),
.product(name: "TreeSitterP4", package: "tree-sitter-p4"),
.target(name: "TreeSitterExtensions"),
- .target(name: "P4"),
+ .target(name: "Common"),
+ .target(name: "Lang"),
],
),
.target(
@@ -49,12 +58,20 @@ let package = Package(
],
),
.target(
- name: "P4",
- dependencies: ["Macros", "TreeSitterExtensions"]
+ name: "Common",
+ dependencies: ["Macros"]
+ ),
+ .target(
+ name: "Lang",
+ dependencies: ["Common"]
+ ),
+ .target(
+ name: "Runtime",
+ dependencies: ["Lang", "Common"]
),
.testTarget(
name: "ParserTests",
- dependencies: ["Parser", "P4", "Macros", "TreeSitterExtensions"]
+ dependencies: ["Parser", "Runtime", "Lang", "Macros", "TreeSitterExtensions", "Common"]
),
]
)
diff --git a/Sources/P4/Program.swift b/Sources/Common/Execution.swift
similarity index 69%
rename from Sources/P4/Program.swift
rename to Sources/Common/Execution.swift
index 523f7a6..467918d 100644
--- a/Sources/P4/Program.swift
+++ b/Sources/Common/Execution.swift
@@ -1,7 +1,7 @@
// 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
@@ -15,42 +15,16 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-public class Identifier: CustomStringConvertible, Equatable {
- var name: String
+open class ProgramExecution: CustomStringConvertible {
+ public var scopes: Scopes = Scopes()
- public init(name: String) {
- self.name = name
- }
+ public init() {}
- public var description: String {
- return "\(name)"
- }
-
- public static func ==(lhs: Identifier, rhs: Identifier) -> Bool {
- return lhs.name == rhs.name
+ open var description: String {
+ return "Runtime:\nScopes: \(scopes)"
}
}
-public class Variable: Identifier {
- var constant: Bool
- var value: ValueType
-
- public init(name: String, withValue value: ValueType, isConstant constant: Bool) {
- self.constant = constant
- self.value = value
- super.init(name: name)
- }
-
- public override var description: String {
- return "\(super.description) = \(value) \(constant ? "(constant)" : "")"
- }
-
- public var value_type: ValueType {
- get {
- value
- }
- }
-}
public struct Scope: CustomStringConvertible{
var variables: [Variable] = Array()
@@ -78,6 +52,12 @@ public struct Scope: CustomStringConvertible{
}
return .none
}
+
+ public mutating func declare(variable: Variable) -> Scope {
+ var s = self
+ s.variables.append(variable)
+ return s
+ }
}
public struct Scopes: CustomStringConvertible {
@@ -108,14 +88,17 @@ public struct Scopes: CustomStringConvertible {
}
}
+ 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 var count: Int {
get {
scopes.count
}
}
}
-
-public struct Program {
- public var parsers: [P4.Parser] = Array()
- public init() {}
-}
diff --git a/Sources/P4/Types.swift b/Sources/Common/ProgramTypes.swift
similarity index 69%
rename from Sources/P4/Types.swift
rename to Sources/Common/ProgramTypes.swift
index dc0ae7d..d7454d1 100644
--- a/Sources/P4/Types.swift
+++ b/Sources/Common/ProgramTypes.swift
@@ -1,7 +1,7 @@
// 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
@@ -15,6 +15,44 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
+
+public class Identifier: CustomStringConvertible, Equatable {
+ var name: String
+
+ public init(name: String) {
+ self.name = name
+ }
+
+ public var description: String {
+ return "\(name)"
+ }
+
+ public static func ==(lhs: Identifier, rhs: Identifier) -> Bool {
+ return lhs.name == rhs.name
+ }
+}
+
+public class Variable: Identifier {
+ var constant: Bool
+ var value: ValueType
+
+ public init(name: String, withValue value: ValueType, isConstant constant: Bool) {
+ self.constant = constant
+ self.value = value
+ super.init(name: name)
+ }
+
+ public override var description: String {
+ return "\(super.description) = \(value) \(constant ? "(constant)" : "")"
+ }
+
+ public var value_type: ValueType {
+ get {
+ value
+ }
+ }
+}
+
public enum ValueType: CustomStringConvertible, Equatable {
case Boolean(Bool)
case Int(Int)
diff --git a/Sources/Common/Protocols.swift b/Sources/Common/Protocols.swift
new file mode 100644
index 0000000..b9aceff
--- /dev/null
+++ b/Sources/Common/Protocols.swift
@@ -0,0 +1,33 @@
+// 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 .
+
+public protocol EvaluatableExpression {
+ /// Evaluate an expression for a given execution
+ /// - Parameters
+ /// - execution: The execution context in which to evaluate the expression
+ /// - Returns: The value of expression
+ func evaluate(execution: ProgramExecution) -> ValueType
+}
+
+public protocol EvaluatableParserStatement {
+ /// Evaluate a statement for a given execution
+ /// - Parameters
+ /// - execution: The execution context in which to evaluate the parser statement
+ /// - Returns: An updated execution after evaluating the parser statement
+ func evaluate(execution: ProgramExecution) -> ProgramExecution
+}
+
diff --git a/Sources/P4/Support.swift b/Sources/Common/Support.swift
similarity index 99%
rename from Sources/P4/Support.swift
rename to Sources/Common/Support.swift
index d054ce0..22b1f16 100644
--- a/Sources/P4/Support.swift
+++ b/Sources/Common/Support.swift
@@ -1,7 +1,7 @@
// 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
diff --git a/Sources/Lang/Parser.swift b/Sources/Lang/Parser.swift
new file mode 100644
index 0000000..6fb1909
--- /dev/null
+++ b/Sources/Lang/Parser.swift
@@ -0,0 +1,133 @@
+// 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 .
+
+import Common
+
+public struct LocalElements {
+
+}
+
+public struct LocalElement {
+
+}
+
+public struct ParserTransitionStatement {
+ public init() {}
+}
+
+public struct VariableDeclarationStatement {
+ public var variable: Variable
+ public init(withVariable variable: Variable) {
+ self.variable = variable
+ }
+}
+
+public struct ExpressionStatement {
+ public init() {}
+}
+
+public struct ParserState: Equatable, CustomStringConvertible {
+
+ public private(set) var state_name: String
+ public private(set) var local_elements: [EvaluatableParserStatement]
+ public private(set) var statements: [EvaluatableParserStatement]
+ public private(set) var transition: ParserTransitionStatement?
+
+ public var description: String {
+ return "Name: \(state_name)"
+ }
+
+ public static func == (lhs: ParserState, rhs: ParserState) -> Bool {
+ return lhs.state_name == rhs.state_name
+ }
+
+ /// Construct a ParserState
+ public init(
+ name: String, withLocalElements localElements: [EvaluatableParserStatement]?,
+ withStatements statements: [EvaluatableParserStatement]?,
+ withTransition transitionStatement: ParserTransitionStatement
+ ) {
+ state_name = name
+ transition = transitionStatement
+ local_elements = localElements ?? Array()
+ self.statements = statements ?? Array()
+ }
+
+ /// (private) constructor (no transition)
+ ///
+ /// accept and reject are the only final states and they are constructed internally.
+ init(name: String) {
+ state_name = name
+ transition = .none
+ local_elements = Array()
+ statements = Array()
+ }
+}
+
+public struct ParserStates {
+ public var states: [ParserState] = Array()
+}
+
+nonisolated(unsafe) public let accept: ParserState = ParserState(name: "accept")
+nonisolated(unsafe) public let reject: ParserState = ParserState(name: "reject")
+
+public struct Parser {
+ public var states: [ParserState] = Array()
+ public var count: Int {
+ states.count
+ }
+
+ public init() {}
+
+ public func findStartState() -> ParserState? {
+ for state in states {
+ if state.state_name == "start" {
+ return state
+ }
+ }
+ return .none
+ }
+}
+
+public class ParserExecution: ProgramExecution {
+
+ private init(state: ParserState) {
+ self.state = state
+ super.init()
+ }
+
+ public static func create(_ parser: Parser) -> Result {
+ guard let start_state = parser.findStartState() else {
+ return Result.Error(Error(withMessage: "Could not find the start state"))
+ }
+ let new = ParserExecution(state: start_state)
+
+ return Result.Ok(new)
+ }
+
+ public var state: ParserState
+
+ public func transition(toNextState state: ParserState) -> ParserExecution {
+ let next = self
+ next.state = state
+ return next
+ }
+
+ public override var description: String {
+ return "Execution: \(super.description)\nCurrent State: \(state)"
+ }
+}
\ No newline at end of file
diff --git a/Sources/Lang/Program.swift b/Sources/Lang/Program.swift
new file mode 100644
index 0000000..471c5bd
--- /dev/null
+++ b/Sources/Lang/Program.swift
@@ -0,0 +1,21 @@
+// 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 .
+
+public struct Program {
+ public var parsers: [Parser] = Array()
+ public init() {}
+}
\ No newline at end of file
diff --git a/Sources/Parser/Execution.swift b/Sources/Lang/Types.swift
similarity index 99%
rename from Sources/Parser/Execution.swift
rename to Sources/Lang/Types.swift
index 79b9de0..aca375f 100644
--- a/Sources/Parser/Execution.swift
+++ b/Sources/Lang/Types.swift
@@ -1,7 +1,7 @@
// 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
diff --git a/Sources/Macros/Macros.swift b/Sources/Macros/Macros.swift
index ff0593b..a0ec8f5 100644
--- a/Sources/Macros/Macros.swift
+++ b/Sources/Macros/Macros.swift
@@ -1,7 +1,7 @@
// 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
diff --git a/Sources/P4/Parser.swift b/Sources/P4/Parser.swift
deleted file mode 100644
index 40f6e31..0000000
--- a/Sources/P4/Parser.swift
+++ /dev/null
@@ -1,163 +0,0 @@
-// 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 .
-
-public struct LocalElements {
-
-}
-
-public struct LocalElement {
-
-}
-
-public class ParserExecution: ProgramExecution {
- public var state: ParserState
-
- public init(_ state: ParserState) {
- self.state = state
- }
-
- public func transition(toNextState state: ParserState) -> ParserExecution {
- let next = self
- next.state = state
- return next
- }
-
- public override var description: String {
- return "Execution: \(super.description)\nCurrent State: \(state)"
- }
-}
-
-public protocol Expression {
- /// Evaluate an expression for a given execution
- /// - Parameters
- /// - execution: The execution context in which to evaluate the expression
- /// - Returns: The value of expression
- func evaluate(execution: ParserExecution) -> Value
-}
-
-public protocol ParserStatement {
- /// Evaluate a statement for a given execution
- /// - Parameters
- /// - execution: The execution context in which to evaluate the parser statement
- /// - Returns: An updated execution after evaluating the parser statement
- func evaluate(execution: ParserExecution) -> ParserExecution
-}
-
-public struct ParserTransitionStatement: ParserStatement {
- public init() {}
- public func evaluate(execution: ParserExecution) -> ParserExecution {
- return execution
- }
-}
-
-public struct VariableDeclarationStatement: ParserStatement {
- public var variable: Variable
- public init(withVariable variable: Variable) {
- self.variable = variable
- }
-
- public func evaluate(execution: ParserExecution) -> ParserExecution {
- execution.scopes.scopes[0].variables.append(self.variable)
- return execution
- }
-}
-
-public struct ExpressionStatement: ParserStatement {
- public init() {}
- public func evaluate(execution: ParserExecution) -> ParserExecution {
- return execution
- }
-}
-
-public struct ParserState: Equatable, CustomStringConvertible {
-
- public private(set) var state_name: String
- public private(set) var local_elements: [ParserStatement]
- public private(set) var statements: [ParserStatement]
- public private(set) var transition: ParserTransitionStatement?
-
- public var description: String {
- return "Name: \(state_name)"
- }
-
- public static func == (lhs: ParserState, rhs: ParserState) -> Bool {
- return lhs.state_name == rhs.state_name
- }
-
- /// Construct a ParserState
- public init(name: String, withLocalElements localElements: [ParserStatement]?, withStatements statements: [ParserStatement]?, withTransition transitionStatement: ParserTransitionStatement) {
- state_name = name
- transition = transitionStatement
- local_elements = localElements ?? Array()
- self.statements = statements ?? Array()
- }
-
- func evaluate(execution: ParserExecution) -> ParserExecution {
- var currentExecution = execution
-
- // First, evaluate the local elements.
- for local_element in local_elements {
- currentExecution = local_element.evaluate(execution: currentExecution)
- }
-
- // Then, evaluate the statements.
- for statement in statements {
- currentExecution = statement.evaluate(execution: currentExecution)
- }
-
- return if let transition = transition {
- currentExecution.transition(toNextState: accept)
- } else {
- currentExecution.transition(toNextState: reject)
- }
- }
-
- /// (private) constructor (no transition)
- ///
- /// accept and reject are the only final states and they are constructed internally.
- init(name: String) {
- state_name = name
- transition = .none
- local_elements = Array()
- statements = Array()
- }
-}
-
-public struct ParserStates {
- public var states: [ParserState] = Array()
-}
-
-nonisolated(unsafe) public let accept: ParserState = ParserState(name: "accept")
-nonisolated(unsafe) public let reject: ParserState = ParserState(name: "reject")
-
-public struct Parser {
- public var states: [ParserState] = Array()
- public var count: Int {
- states.count
- }
-
- public init() {}
-
- public func findStartState() -> Optional {
- for state in states {
- if state.state_name == "start" {
- return state
- }
- }
- return .none
- }
-}
diff --git a/Sources/P4/Runtime.swift b/Sources/P4/Runtime.swift
deleted file mode 100644
index 581e981..0000000
--- a/Sources/P4/Runtime.swift
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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 .
-
-public class ProgramExecution: CustomStringConvertible {
- public var scopes: Scopes = Scopes()
-
- public init() {}
-
- public var description: String {
- return "Runtime:\nScopes: \(scopes)"
- }
-}
-
-//public struct ParserRuntime: ProgramRuntime {
-public class ParserRuntime: CustomStringConvertible {
- var execution: ParserExecution
-
- init(execution: ParserExecution) {
- self.execution = execution
- }
-
- public static func create(program: P4.Parser) -> Result {
- // First, find the start state.
- guard let start_state = program.findStartState() else {
- return Result.Error(Error(withMessage: "Could not find the start state"))
- }
- return Result.Ok(P4.ParserRuntime(execution: P4.ParserExecution(start_state)))
- }
-
- public func run(input: P4.Packet) -> Result {
- execution.scopes.enter()
- while execution.state != P4.accept && execution.state != P4.reject {
- execution = execution.state.evaluate(execution: execution)
- }
- return .Ok(execution)
- }
-
- public var description: String {
- //return "\(super.description)\nState: \(execution?.description ?? "N/A")\nError: \(error?.description ?? "None")"
- return "Runtime:\nExecution: \(execution)"
- }
-}
diff --git a/Sources/Parser/Parser.swift b/Sources/Parser/Parser.swift
index a9ca741..7acf744 100644
--- a/Sources/Parser/Parser.swift
+++ b/Sources/Parser/Parser.swift
@@ -1,7 +1,7 @@
// 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
@@ -15,46 +15,48 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-import P4
+import Common
+import Lang
+import Runtime
import SwiftTreeSitter
-import TreeSitterP4
import TreeSitterExtensions
+import TreeSitterP4
let p4lang = Language(tree_sitter_p4())
public protocol ParseableValueType {
- static func Parse(type: String, withValue value: String) -> Result
+ static func Parse(type: String, withValue value: String) -> Result
}
// This seems unnecessary because all the value types are in a single enum?
-extension P4.ValueType: ParseableValueType {
- public static func Parse(type: String, withValue value: String) -> Result {
+extension ValueType: ParseableValueType {
+ public static func Parse(type: String, withValue value: String) -> Result {
if type == "bool" {
// Default
if value == "" {
- return .Ok(P4.ValueType.Boolean(false))
+ return .Ok(ValueType.Boolean(false))
}
if value == "true" {
- return .Ok(P4.ValueType.Boolean(true))
+ return .Ok(ValueType.Boolean(true))
} else if value == "false" {
- return .Ok(P4.ValueType.Boolean(false))
+ return .Ok(ValueType.Boolean(false))
}
return .Error(Error(withMessage: "Cannot convert \(value) into boolean value"))
} else if type == "string" {
- return .Ok(P4.ValueType.String(value))
+ return .Ok(ValueType.String(value))
} else if type == "int" {
// Default
if value == "" {
- return .Ok(P4.ValueType.Int(0))
+ return .Ok(ValueType.Int(0))
}
guard let parsed_value = Swift.Int(value) else {
return .Error(Error(withMessage: "Cannot convert \(value) into integer value"))
}
- return .Ok(P4.ValueType.Int(parsed_value))
+ return .Ok(ValueType.Int(parsed_value))
}
return .Error(Error(withMessage: "Invalid type"))
@@ -62,11 +64,13 @@ extension P4.ValueType: ParseableValueType {
}
public protocol ParseableParserStatement {
- static func Parse(node: Node, inTree tree: MutableTree) -> Result
+ static func Parse(node: Node, inTree tree: MutableTree) -> Result
}
-extension P4.ExpressionStatement: ParseableParserStatement {
- public static func Parse(node: Node, inTree tree: MutableTree) -> Result {
+extension ExpressionStatement: ParseableParserStatement {
+ public static func Parse(
+ node: Node, inTree tree: MutableTree
+ ) -> Result {
guard
let parser_state_query = try? SwiftTreeSitter.Query(
language: p4lang,
@@ -82,16 +86,16 @@ extension P4.ExpressionStatement: ParseableParserStatement {
let expression_capture = query_result.captures(named: "expression")
if !expression_capture.isEmpty {
// TODO: Actually create an ExpressionStatement
- return Result.Ok(P4.ExpressionStatement())
+ return Result.Ok(ExpressionStatement())
}
-
return Result.Ok(.none)
-
}
}
-extension P4.VariableDeclarationStatement: ParseableParserStatement {
- public static func Parse(node: Node, inTree tree: MutableTree) -> Result {
+extension VariableDeclarationStatement: ParseableParserStatement {
+ public static func Parse(
+ node: Node, inTree tree: MutableTree
+ ) -> Result {
guard
let parser_state_query = try? SwiftTreeSitter.Query(
language: p4lang,
@@ -125,10 +129,10 @@ extension P4.VariableDeclarationStatement: ParseableParserStatement {
""
}
- return switch P4.ValueType.Parse(type: type_name, withValue: value) {
+ return switch ValueType.Parse(type: type_name, withValue: value) {
case Result.Ok(let value_type):
Result.Ok(
- P4.VariableDeclarationStatement(
+ VariableDeclarationStatement(
withVariable: Variable(name: variable_name, withValue: value_type, isConstant: false)))
case Result.Error(let e):
Result.Error(e)
@@ -139,9 +143,10 @@ extension P4.VariableDeclarationStatement: ParseableParserStatement {
public struct Parser {
public struct P4Parser {
+
static func LocalElements(
node: Node, inTree tree: MutableTree
- ) -> Result<[P4.ParserStatement]> {
+ ) -> Result<[EvaluatableParserStatement]> {
guard
let parser_le_statement_query = try? SwiftTreeSitter.Query(
@@ -154,15 +159,15 @@ public struct Parser {
}
let localElementsParsers: [ParseableParserStatement.Type] = [
- P4.VariableDeclarationStatement.self
+ VariableDeclarationStatement.self
]
- var localElements: [P4.ParserStatement] = Array()
+ var localElements: [EvaluatableParserStatement] = Array()
let qr = parser_le_statement_query.execute(node: node, in: tree)
for raw_le_statement in qr {
let raw_le_statement_capture = raw_le_statement.captures(named: "parser-local-element")
- var parsed_le_statement: P4.ParserStatement? = .none
+ var parsed_le_statement: EvaluatableParserStatement? = .none
for le_parser in localElementsParsers {
if case Result.Ok(.some(let parsed)) = le_parser.Parse(
@@ -187,7 +192,7 @@ public struct Parser {
static func Statements(
node: Node, inTree tree: MutableTree
- ) -> Result<[P4.ParserStatement]> {
+ ) -> Result<[EvaluatableParserStatement]> {
guard
let parser_statement_query = try? SwiftTreeSitter.Query(
@@ -200,16 +205,16 @@ public struct Parser {
}
let statementParsers: [ParseableParserStatement.Type] = [
- P4.ExpressionStatement.self, P4.VariableDeclarationStatement.self,
+ ExpressionStatement.self, VariableDeclarationStatement.self,
]
- var statements: [P4.ParserStatement] = Array()
+ var statements: [EvaluatableParserStatement] = Array()
let qr = parser_statement_query.execute(node: node, in: tree)
for raw_statement in qr {
let raw_statement_capture = raw_statement.captures(named: "parser-statement")
- var parsed_statement: P4.ParserStatement? = .none
+ var parsed_statement: EvaluatableParserStatement? = .none
// Iterate through statement parsers and give each one a chance.
for parser in statementParsers {
@@ -234,12 +239,11 @@ public struct Parser {
static func TransitionStatement(
node: Node, inTree tree: MutableTree
- ) -> P4.ParserTransitionStatement?
- {
- return P4.ParserTransitionStatement()
+ ) -> ParserTransitionStatement? {
+ return ParserTransitionStatement()
}
- static func State(node: Node, inTree tree: MutableTree) -> Result {
+ static func State(node: Node, inTree tree: MutableTree) -> Result {
guard
let parser_state_query = try? SwiftTreeSitter.Query(
language: p4lang,
@@ -273,10 +277,10 @@ public struct Parser {
if !state_le_capture.isEmpty {
LocalElements(node: state_le_capture[0].node, inTree: tree)
} else {
- Result.Ok([P4.ParserStatement]())
+ Result.Ok([EvaluatableParserStatement]())
}
- guard case Result<[P4.ParserStatement]>.Ok(let parsed_les) = maybe_parsed_les else {
+ guard case Result<[EvaluatableParserStatement]>.Ok(let parsed_les) = maybe_parsed_les else {
return Result.Error(maybe_parsed_les.error()!)
}
@@ -284,22 +288,24 @@ public struct Parser {
if !statements_capture.isEmpty {
Statements(node: statements_capture[0].node, inTree: tree)
} else {
- Result.Ok([P4.ParserStatement]())
+ Result.Ok([EvaluatableParserStatement]())
}
- guard case Result<[P4.ParserStatement]>.Ok(let parsed_statements) = maybe_parsed_statements
+ guard
+ case Result<[EvaluatableParserStatement]>.Ok(let parsed_statements) =
+ maybe_parsed_statements
else {
return Result.Error(maybe_parsed_statements.error()!)
}
// TODO: Validate that there is only one!
return Result.Ok(
- P4.ParserState(
+ ParserState(
name: parsed_state_name, withLocalElements: parsed_les,
withStatements: parsed_statements,
withTransition: transition_statement))
}
}
- static func Parser(node: Node, inTree tree: MutableTree) -> Result {
+ static func Parser(node: Node, inTree tree: MutableTree) -> Result {
guard
let parser_state_query = try? SwiftTreeSitter.Query(
language: p4lang,
@@ -311,7 +317,7 @@ public struct Parser {
Error(withMessage: "Could not compile the parser state tree sitter query"))
}
- var parser = P4.Parser()
+ var parser = Lang.Parser()
// Build a state from each one listed.
for parser_states in parser_state_query.execute(node: node, in: tree) {
@@ -323,7 +329,7 @@ public struct Parser {
return Result.Ok(parser)
}
- public static func Program(_ source: String) -> Result {
+ public static func Program(_ source: String) -> Result {
let p = SwiftTreeSitter.Parser.init()
do {
@@ -350,7 +356,7 @@ public struct Parser {
Error(withMessage: "Could not compile the parser declaration tree sitter query"))
}
- var program: P4.Program = P4.Program()
+ var program = Lang.Program()
let parser_qc = parser_declaration_query.execute(in: tree)
diff --git a/Sources/Runtime/Parser.swift b/Sources/Runtime/Parser.swift
new file mode 100644
index 0000000..9b13e96
--- /dev/null
+++ b/Sources/Runtime/Parser.swift
@@ -0,0 +1,50 @@
+// 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 .
+
+import Common
+import Lang
+
+
+
+extension ParserTransitionStatement: EvaluatableParserTransitionStatement {
+ // TODO: Currently transitions to accept.
+ func transition(execution: ProgramExecution) -> (ParserState, ProgramExecution) {
+ return (accept, execution)
+ }
+}
+
+extension ParserState: EvaluatableParserState {
+ public func evaluate(execution: ProgramExecution) -> (ParserState, ProgramExecution) {
+ var currentExecution = execution
+
+ // First, evaluate the local elements.
+ for local_element in local_elements {
+ currentExecution = local_element.evaluate(execution: currentExecution)
+ }
+
+ // Then, evaluate the statements.
+ for statement in statements {
+ currentExecution = statement.evaluate(execution: currentExecution)
+ }
+
+ return if let transition = transition {
+ transition.transition(execution: currentExecution)
+ } else {
+ (reject, currentExecution)
+ }
+ }
+}
diff --git a/Sources/Runtime/Program.swift b/Sources/Runtime/Program.swift
new file mode 100644
index 0000000..a594c90
--- /dev/null
+++ b/Sources/Runtime/Program.swift
@@ -0,0 +1,33 @@
+// 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 .
+
+import Lang
+import Common
+
+extension VariableDeclarationStatement: EvaluatableParserStatement {
+ public func evaluate(execution: ProgramExecution) -> ProgramExecution {
+ let new_scopes = execution.scopes.declare(variable: self.variable)
+ execution.scopes = new_scopes
+ return execution
+ }
+}
+
+extension ExpressionStatement: EvaluatableParserStatement {
+ public func evaluate(execution: ProgramExecution) -> ProgramExecution {
+ return execution
+ }
+}
\ No newline at end of file
diff --git a/Sources/Runtime/Protocols.swift b/Sources/Runtime/Protocols.swift
new file mode 100644
index 0000000..098b62c
--- /dev/null
+++ b/Sources/Runtime/Protocols.swift
@@ -0,0 +1,31 @@
+// 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 .
+
+import Common
+import Lang
+
+protocol EvaluatableParserState {
+ func evaluate(execution: ProgramExecution) -> (ParserState, ProgramExecution)
+}
+
+protocol EvaluatableParserTransitionStatement {
+ func transition(execution: ProgramExecution) -> (ParserState, ProgramExecution)
+}
+
+public protocol Execution {
+ func execute() -> (ParserState, ProgramExecution)
+}
\ No newline at end of file
diff --git a/Sources/Runtime/Runtime.swift b/Sources/Runtime/Runtime.swift
new file mode 100644
index 0000000..0a769d1
--- /dev/null
+++ b/Sources/Runtime/Runtime.swift
@@ -0,0 +1,58 @@
+// 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 .
+
+import Common
+import Lang
+
+public class ParserRuntime: CustomStringConvertible {
+ var execution: ParserExecution
+
+ init(execution: ParserExecution) {
+ self.execution = execution
+ }
+
+ public static func create(program: Lang.Parser) -> Result {
+ switch ParserExecution.create(program) {
+ case .Ok(let execution): return .Ok(Runtime.ParserRuntime(execution: execution))
+ case .Error(let error): return .Error(error)
+
+ }
+ }
+
+ public func run(input: Packet) -> Result<(ParserState, ProgramExecution)> {
+ execution.scopes.enter()
+ return .Ok(execution.execute())
+ }
+
+ public var description: String {
+ //return "\(super.description)\nState: \(execution?.description ?? "N/A")\nError: \(error?.description ?? "None")"
+ return "Runtime:\nExecution: \(execution)"
+ }
+}
+
+extension ParserExecution: Execution {
+ public func execute() -> (ParserState, ProgramExecution) {
+ var execution = self as ProgramExecution
+ var state = self.state
+
+ // Evaluate until the state is either accept or reject.
+ while state != accept && state != reject {
+ (state, execution) = self.state.evaluate(execution: execution)
+ }
+ return (state, execution)
+ }
+}
diff --git a/Sources/TreeSitterExtensions/Extensions.swift b/Sources/TreeSitterExtensions/Extensions.swift
index 1c8840f..643f22e 100644
--- a/Sources/TreeSitterExtensions/Extensions.swift
+++ b/Sources/TreeSitterExtensions/Extensions.swift
@@ -1,7 +1,7 @@
// 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
diff --git a/Tests/p4lmTests/ParserTests.swift b/Tests/p4lmTests/ParserTests.swift
index e27d116..9964525 100644
--- a/Tests/p4lmTests/ParserTests.swift
+++ b/Tests/p4lmTests/ParserTests.swift
@@ -1,7 +1,7 @@
// 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
@@ -20,7 +20,8 @@ import TreeSitter
import SwiftTreeSitter
import TreeSitterP4
import Foundation
-import P4
+import Runtime
+import Common
import Macros
diff --git a/Tests/p4lmTests/RuntimeTests.swift b/Tests/p4lmTests/RuntimeTests.swift
index df8aec3..d001cab 100644
--- a/Tests/p4lmTests/RuntimeTests.swift
+++ b/Tests/p4lmTests/RuntimeTests.swift
@@ -1,7 +1,7 @@
// 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
@@ -16,7 +16,9 @@
// along with this program. If not, see .
import Foundation
-import P4
+import Runtime
+import Common
+import Lang
import Macros
import SwiftTreeSitter
import Testing
@@ -36,7 +38,7 @@ import TreeSitterP4
"""
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
- #expect(#RequireOkResult(P4.ParserRuntime.create(program: program.parsers[0])))
+ #expect(#RequireOkResult(Runtime.ParserRuntime.create(program: program.parsers[0])))
}
@Test func test_simple_runtime_no_start_state() async throws {
@@ -53,7 +55,7 @@ import TreeSitterP4
#expect(
#RequireErrorResult(
Error(withMessage: "Could not find the start state"),
- P4.ParserRuntime.create(program: program.parsers[0])))
+ Runtime.ParserRuntime.create(program: program.parsers[0])))
}
@Test func test_simple_local_element_variable_declaration() async throws {
@@ -70,11 +72,11 @@ import TreeSitterP4
"""
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
- let runtime = try #UseOkResult(P4.ParserRuntime.create(program: program.parsers[0]))
+ let runtime = try #UseOkResult(Runtime.ParserRuntime.create(program: program.parsers[0]))
// This seems awkward to me!
// TODO: Is there a better way?
- guard case P4.Result.Ok(let execution_result) = runtime.run(input: P4.Packet()) else {
+ guard case Common.Result.Ok(let (state_result, execution_result)) = runtime.run(input: Packet()) else {
assert(false)
}
@@ -85,6 +87,9 @@ import TreeSitterP4
assert(false)
}
+ // We should be in the accept state.
+ #expect(state_result == Lang.accept)
+
// There are two variables declared.
#expect(scope.count == 2)
@@ -93,4 +98,7 @@ import TreeSitterP4
let s = try #require(scope.lookup(identifier: Identifier(name: "s")))
#expect(b.value_type == ValueType.Boolean(false))
#expect(s.value_type == ValueType.String("\"testing\""))
+
+
+
}
diff --git a/Tests/p4lmTests/SupportTests.swift b/Tests/p4lmTests/SupportTests.swift
index 30ab8e1..7e72b57 100644
--- a/Tests/p4lmTests/SupportTests.swift
+++ b/Tests/p4lmTests/SupportTests.swift
@@ -1,7 +1,7 @@
// 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
@@ -16,7 +16,7 @@
// along with this program. If not, see .
import Foundation
-import P4
+import Common
import Macros
import SwiftTreeSitter
import Testing