@@ -17,12 +17,27 @@
|
|||||||
|
|
||||||
open class ProgramExecution: CustomStringConvertible {
|
open class ProgramExecution: CustomStringConvertible {
|
||||||
public var scopes: Scopes = Scopes()
|
public var scopes: Scopes = Scopes()
|
||||||
|
var error: Error?
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
|
||||||
open var description: String {
|
open var description: String {
|
||||||
return "Runtime:\nScopes: \(scopes)"
|
return "Runtime:\nScopes: \(scopes)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func hasError() -> Bool {
|
||||||
|
return self.error != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getError() -> Error? {
|
||||||
|
return self.error
|
||||||
|
}
|
||||||
|
|
||||||
|
public func setError(error: Error) -> ProgramExecution {
|
||||||
|
let npe = self
|
||||||
|
npe.error = error
|
||||||
|
return npe
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -96,6 +111,15 @@ public struct Scopes: CustomStringConvertible {
|
|||||||
return s
|
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 {
|
public var count: Int {
|
||||||
get {
|
get {
|
||||||
scopes.count
|
scopes.count
|
||||||
|
|||||||
@@ -65,6 +65,12 @@ open class P4ValueBase<T: P4Type>: P4Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension P4ValueBase: EvaluatableExpression {
|
||||||
|
public func evaluate(execution: ProgramExecution) -> Result<P4Value> {
|
||||||
|
return .Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The type for a P4 struct
|
/// The type for a P4 struct
|
||||||
public struct P4Struct: P4Type {
|
public struct P4Struct: P4Type {
|
||||||
public let name: String
|
public let name: String
|
||||||
@@ -122,6 +128,7 @@ public class P4BooleanValue: P4ValueBase<P4Boolean> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A P4 int type
|
/// A P4 int type
|
||||||
public struct P4Int: P4Type {
|
public struct P4Int: P4Type {
|
||||||
public static func create() -> any P4Type {
|
public static func create() -> any P4Type {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public protocol EvaluatableExpression {
|
|||||||
/// - Parameters
|
/// - Parameters
|
||||||
/// - execution: The execution context in which to evaluate the expression
|
/// - execution: The execution context in which to evaluate the expression
|
||||||
/// - Returns: The value of expression
|
/// - Returns: The value of expression
|
||||||
func evaluate(execution: ProgramExecution) -> P4Value
|
func evaluate(execution: ProgramExecution) -> Result<P4Value>
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol EvaluatableParserStatement {
|
public protocol EvaluatableParserStatement {
|
||||||
|
|||||||
@@ -53,6 +53,13 @@ public enum Result<OKT>: Equatable {
|
|||||||
}
|
}
|
||||||
return nil
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Result where OKT: CustomStringConvertible {
|
extension Result where OKT: CustomStringConvertible {
|
||||||
|
|||||||
+180
-31
@@ -25,8 +25,65 @@ public struct LocalElement {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct KeysetExpression {
|
||||||
|
public let key: EvaluatableExpression
|
||||||
|
public let next_state_name: String
|
||||||
|
public let next_state: ParserState?
|
||||||
|
|
||||||
|
public init(withKey key: EvaluatableExpression, withNextStateName next_state_name: String) {
|
||||||
|
self.key = key
|
||||||
|
self.next_state_name = next_state_name
|
||||||
|
self.next_state = .none
|
||||||
|
}
|
||||||
|
public init(
|
||||||
|
withKey key: EvaluatableExpression, withNextStateName next_state_name: String,
|
||||||
|
withNextState next_state: ParserState
|
||||||
|
) {
|
||||||
|
self.key = key
|
||||||
|
self.next_state_name = next_state_name
|
||||||
|
self.next_state = next_state
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ParserTransitionSelectExpression {
|
||||||
|
public let selector: EvaluatableExpression
|
||||||
|
public let keyset_expressions: [KeysetExpression]
|
||||||
|
|
||||||
|
public init(
|
||||||
|
withSelector selector: EvaluatableExpression, withKeysetExpressions kses: [KeysetExpression]
|
||||||
|
) {
|
||||||
|
self.selector = selector
|
||||||
|
self.keyset_expressions = kses
|
||||||
|
}
|
||||||
|
|
||||||
|
public func append_checked_kse(kse: KeysetExpression) -> ParserTransitionSelectExpression {
|
||||||
|
var new_kse = self.keyset_expressions
|
||||||
|
new_kse.append(kse)
|
||||||
|
return ParserTransitionSelectExpression(
|
||||||
|
withSelector: self.selector, withKeysetExpressions: new_kse)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public struct ParserTransitionStatement {
|
public struct ParserTransitionStatement {
|
||||||
public init() {}
|
public let next_state_name: String?
|
||||||
|
public let transition_expression: ParserTransitionSelectExpression?
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self.next_state_name = .none
|
||||||
|
self.transition_expression = .none
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(withTransitionExpression transition_expression: ParserTransitionSelectExpression) {
|
||||||
|
self.next_state_name = .none
|
||||||
|
self.transition_expression = transition_expression
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(withNextState next_state_name: String) {
|
||||||
|
self.next_state_name = next_state_name
|
||||||
|
self.transition_expression = .none
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct VariableDeclarationStatement {
|
public struct VariableDeclarationStatement {
|
||||||
@@ -36,16 +93,13 @@ public struct VariableDeclarationStatement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ExpressionStatement {
|
public class ParserState: Equatable, CustomStringConvertible {
|
||||||
public init() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct ParserState: Equatable, CustomStringConvertible {
|
|
||||||
|
|
||||||
public private(set) var state_name: String
|
public private(set) var state_name: String
|
||||||
public private(set) var local_elements: [EvaluatableParserStatement]
|
public private(set) var local_elements: [EvaluatableParserStatement]
|
||||||
public private(set) var statements: [EvaluatableParserStatement]
|
public private(set) var statements: [EvaluatableParserStatement]
|
||||||
public private(set) var transition: ParserTransitionStatement?
|
public private(set) var transition: ParserTransitionStatement?
|
||||||
|
public private(set) var next_state: ParserState?
|
||||||
|
|
||||||
public var description: String {
|
public var description: String {
|
||||||
return "Name: \(state_name)"
|
return "Name: \(state_name)"
|
||||||
@@ -67,6 +121,37 @@ public struct ParserState: Equatable, CustomStringConvertible {
|
|||||||
self.statements = statements ?? Array()
|
self.statements = statements ?? Array()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func semantic_check(states: ParserStates) -> Bool {
|
||||||
|
guard let transition = transition else {
|
||||||
|
return self == accept || self == reject
|
||||||
|
}
|
||||||
|
|
||||||
|
if let transition_select_expression = transition.transition_expression {
|
||||||
|
var updated_tse = ParserTransitionSelectExpression(
|
||||||
|
withSelector: transition_select_expression.selector, withKeysetExpressions: [])
|
||||||
|
|
||||||
|
for kse in transition_select_expression.keyset_expressions {
|
||||||
|
guard let next_state = states.find(withName: kse.next_state_name) else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let new_kse = KeysetExpression(
|
||||||
|
withKey: kse.key, withNextStateName: kse.next_state_name, withNextState: next_state)
|
||||||
|
updated_tse = updated_tse.append_checked_kse(kse: new_kse)
|
||||||
|
}
|
||||||
|
self.transition = ParserTransitionStatement(withTransitionExpression: updated_tse)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if let next_state_name = transition.next_state_name,
|
||||||
|
let next_state = states.find(withName: next_state_name)
|
||||||
|
{
|
||||||
|
self.next_state = next_state
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
/// (private) constructor (no transition)
|
/// (private) constructor (no transition)
|
||||||
///
|
///
|
||||||
/// accept and reject are the only final states and they are constructed internally.
|
/// accept and reject are the only final states and they are constructed internally.
|
||||||
@@ -76,24 +161,76 @@ public struct ParserState: Equatable, CustomStringConvertible {
|
|||||||
local_elements = Array()
|
local_elements = Array()
|
||||||
statements = Array()
|
statements = Array()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func direct_transition() -> Bool {
|
||||||
|
return
|
||||||
|
if let transition = self.transition,
|
||||||
|
transition.next_state_name != nil
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ParserStates {
|
public struct ParserStates {
|
||||||
public var states: [ParserState] = Array()
|
public var states: [ParserState] = Array()
|
||||||
|
|
||||||
|
public func count() -> Int {
|
||||||
|
return states.count
|
||||||
|
}
|
||||||
|
|
||||||
|
public func find(withName name: String) -> ParserState? {
|
||||||
|
for state in states {
|
||||||
|
if state.state_name == name {
|
||||||
|
return .some(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .none
|
||||||
|
}
|
||||||
|
|
||||||
|
public func semantic_check() -> Result<()> {
|
||||||
|
// Check whether all the states referred to in the transition statements are
|
||||||
|
// valid.
|
||||||
|
let errors = states.filter { state in
|
||||||
|
return !state.semantic_check(states: self)
|
||||||
|
}.map { state in
|
||||||
|
return Result<()>.Error(Error(withMessage: "State \(state) has invalid transition"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !errors.isEmpty {
|
||||||
|
return errors[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self.states = Array()
|
||||||
|
}
|
||||||
|
|
||||||
|
private init(withStates states: [ParserState]) {
|
||||||
|
self.states = states
|
||||||
|
}
|
||||||
|
|
||||||
|
public func append(state: ParserState) -> ParserStates {
|
||||||
|
var new_states = self.states
|
||||||
|
new_states.append(state)
|
||||||
|
return ParserStates(withStates: new_states)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nonisolated(unsafe) public let accept: ParserState = ParserState(name: "accept")
|
nonisolated(unsafe) public let accept: ParserState = ParserState(name: "accept")
|
||||||
nonisolated(unsafe) public let reject: ParserState = ParserState(name: "reject")
|
nonisolated(unsafe) public let reject: ParserState = ParserState(name: "reject")
|
||||||
|
|
||||||
public struct Parser: P4Type {
|
public struct Parser: P4Type {
|
||||||
public var states: [ParserState] = Array()
|
public var states: ParserStates
|
||||||
public var count: Int {
|
|
||||||
states.count
|
|
||||||
}
|
|
||||||
|
|
||||||
public var name: Identifier
|
public var name: Identifier
|
||||||
|
|
||||||
public init(withName name: Identifier) {
|
public init(withName name: Identifier) {
|
||||||
|
self.states = ParserStates()
|
||||||
self.name = name
|
self.name = name
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,40 +239,52 @@ public struct Parser: P4Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func findStartState() -> ParserState? {
|
public func findStartState() -> ParserState? {
|
||||||
for state in states {
|
for state in states.states {
|
||||||
if state.state_name == "start" {
|
if state.state_name == "start" {
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func semantic_check() -> Result<()> {
|
||||||
|
return self.states.semantic_check()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ParserInstance: ProgramExecution {
|
public class ParserInstance: ProgramExecution {
|
||||||
|
|
||||||
private init(state: ParserState) {
|
public var state: ParserState
|
||||||
self.state = state
|
|
||||||
super.init()
|
private init(state: ParserState) {
|
||||||
|
self.state = state
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func create(_ parser: Parser) -> Result<ParserInstance> {
|
||||||
|
|
||||||
|
var augmented_parser = Parser(withName: parser.name)
|
||||||
|
augmented_parser.states = parser.states.append(state: accept).append(state: reject)
|
||||||
|
|
||||||
|
if case .Error(let e) = augmented_parser.semantic_check() {
|
||||||
|
return .Error(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func create(_ parser: Parser) -> Result<ParserInstance> {
|
guard let start_state = augmented_parser.findStartState() else {
|
||||||
guard let start_state = parser.findStartState() else {
|
return Result.Error(Error(withMessage: "Could not find the start state"))
|
||||||
return Result.Error(Error(withMessage: "Could not find the start state"))
|
|
||||||
}
|
|
||||||
let new = ParserInstance(state: start_state)
|
|
||||||
|
|
||||||
return Result.Ok(new)
|
|
||||||
}
|
}
|
||||||
|
let new = ParserInstance(state: start_state)
|
||||||
|
|
||||||
public var state: ParserState
|
return Result.Ok(new)
|
||||||
|
}
|
||||||
|
|
||||||
public func transition(toNextState state: ParserState) -> ParserInstance {
|
public func transition(toNextState state: ParserState) -> ParserInstance {
|
||||||
let next = self
|
let next = self
|
||||||
next.state = state
|
next.state = state
|
||||||
return next
|
return next
|
||||||
}
|
}
|
||||||
|
|
||||||
public override var description: String {
|
public override var description: String {
|
||||||
return "Execution: \(super.description)\nCurrent State: \(state)"
|
return "Execution: \(super.description)\nCurrent State: \(state)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@
|
|||||||
|
|
||||||
import Common
|
import Common
|
||||||
|
|
||||||
|
public struct ExpressionStatement {
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
|
||||||
public struct Program {
|
public struct Program {
|
||||||
public var types: [P4Type] = Array()
|
public var types: [P4Type] = Array()
|
||||||
|
|
||||||
@@ -29,7 +33,6 @@ public struct Program {
|
|||||||
|
|
||||||
public func find_parser(withName name: Identifier) -> Result<Parser> {
|
public func find_parser(withName name: Identifier) -> Result<Parser> {
|
||||||
for type in self.types {
|
for type in self.types {
|
||||||
print("type: \(type)")
|
|
||||||
guard let parser = type as? Parser else {
|
guard let parser = type as? Parser else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
// expression: $ => choice($.identifier, $.integer, $.true, $.false, $.string_literal), // Very limited.
|
||||||
|
|
||||||
|
import Common
|
||||||
|
import SwiftTreeSitter
|
||||||
|
import TreeSitterP4
|
||||||
|
|
||||||
|
protocol ParseableEvaluatableExpression {
|
||||||
|
static func parse(node: Node, inTree tree: MutableTree) -> Result<EvaluatableExpression?>
|
||||||
|
}
|
||||||
|
|
||||||
|
extension Identifier: ParseableEvaluatableExpression {
|
||||||
|
static func parse(
|
||||||
|
node: SwiftTreeSitter.Node, inTree tree: SwiftTreeSitter.MutableTree
|
||||||
|
) -> Result<EvaluatableExpression?> {
|
||||||
|
|
||||||
|
guard
|
||||||
|
let parser_statement_query = try? SwiftTreeSitter.Query(
|
||||||
|
language: p4lang,
|
||||||
|
data: String(
|
||||||
|
"(expression (identifier) @identifier)"
|
||||||
|
).data(using: String.Encoding.utf8)!)
|
||||||
|
else {
|
||||||
|
return Result.Error(Error(withMessage: "Could not compile the tree sitter query"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let qr = parser_statement_query.execute(node: node, in: tree)
|
||||||
|
|
||||||
|
guard let result = qr.next() else {
|
||||||
|
return .Ok(.none)
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok(Identifier(name: result.captures[0].node.text!))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension P4BooleanValue: ParseableEvaluatableExpression {
|
||||||
|
static func parse(
|
||||||
|
node: SwiftTreeSitter.Node, inTree tree: SwiftTreeSitter.MutableTree
|
||||||
|
) -> Result<EvaluatableExpression?> {
|
||||||
|
|
||||||
|
guard
|
||||||
|
let true_query = try? SwiftTreeSitter.Query(
|
||||||
|
language: p4lang,
|
||||||
|
data: String(
|
||||||
|
"(expression (true))"
|
||||||
|
).data(using: String.Encoding.utf8)!)
|
||||||
|
else {
|
||||||
|
return Result.Error(Error(withMessage: "Could not compile the tree sitter query"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let true_qr = true_query.execute(node: node, in: tree)
|
||||||
|
|
||||||
|
if true_qr.next() != nil {
|
||||||
|
return .Ok(P4BooleanValue(withValue: true))
|
||||||
|
}
|
||||||
|
|
||||||
|
guard
|
||||||
|
let false_query = try? SwiftTreeSitter.Query(
|
||||||
|
language: p4lang,
|
||||||
|
data: String(
|
||||||
|
"(expression (false))"
|
||||||
|
).data(using: String.Encoding.utf8)!)
|
||||||
|
else {
|
||||||
|
return Result.Error(Error(withMessage: "Could not compile the tree sitter query"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let false_qr = false_query.execute(node: node, in: tree)
|
||||||
|
|
||||||
|
if false_qr.next() != nil {
|
||||||
|
return .Ok(P4BooleanValue(withValue: false))
|
||||||
|
}
|
||||||
|
return .Ok(.none)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Expression {
|
||||||
|
public static func Parse(node: Node, inTree: MutableTree) -> Result<EvaluatableExpression> {
|
||||||
|
let localElementsParsers: [ParseableEvaluatableExpression.Type] = [
|
||||||
|
P4BooleanValue.self, Identifier.self,
|
||||||
|
]
|
||||||
|
|
||||||
|
for le_parser in localElementsParsers {
|
||||||
|
if case Result.Ok(.some(let parsed)) = le_parser.parse(
|
||||||
|
node: node, inTree: inTree)
|
||||||
|
{
|
||||||
|
return .Ok(parsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Error(Error(withMessage: "Could not parse into expression."))
|
||||||
|
}
|
||||||
|
}
|
||||||
+110
-9
@@ -229,10 +229,95 @@ public struct Parser {
|
|||||||
return Result.Ok(statements)
|
return Result.Ok(statements)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func TransitionKeysetExpression(
|
||||||
|
node: Node, inTree tree: MutableTree
|
||||||
|
) -> Result<[KeysetExpression]> {
|
||||||
|
guard
|
||||||
|
let transition_selection_expression_query = try? SwiftTreeSitter.Query(
|
||||||
|
language: p4lang,
|
||||||
|
data: String(
|
||||||
|
"((keysetExpression (expression) @ks) (colon) (identifier) @next-state)"
|
||||||
|
).data(using: String.Encoding.utf8)!)
|
||||||
|
else {
|
||||||
|
return Result.Error(Error(withMessage: "Could not compile the tree sitter query"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let qr = transition_selection_expression_query.execute(node: node, in: tree)
|
||||||
|
|
||||||
|
var kses: [KeysetExpression] = Array()
|
||||||
|
|
||||||
|
for expression in qr {
|
||||||
|
let next_state_name = expression.captures[1].node.text!
|
||||||
|
if case .Error(let e) = Expression.Parse(node: expression.captures[0].node, inTree: tree)
|
||||||
|
.map(block: { expression in
|
||||||
|
kses.append(
|
||||||
|
KeysetExpression(
|
||||||
|
withKey: expression, withNextStateName: next_state_name))
|
||||||
|
return .Ok(expression)
|
||||||
|
})
|
||||||
|
{
|
||||||
|
return .Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok(kses)
|
||||||
|
}
|
||||||
|
|
||||||
|
static func TransitionSelectExpression(
|
||||||
|
node: Node, inTree tree: MutableTree
|
||||||
|
) -> Result<ParserTransitionStatement> {
|
||||||
|
guard
|
||||||
|
let transition_selection_expression_query = try? SwiftTreeSitter.Query(
|
||||||
|
language: p4lang,
|
||||||
|
data: String(
|
||||||
|
"(parserTransitionStatement (transition) (transitionSelectionExpression (selectExpression (select) (expression) @selector (selectBody) @body)))"
|
||||||
|
).data(using: String.Encoding.utf8)!)
|
||||||
|
else {
|
||||||
|
return Result.Error(Error(withMessage: "Could not compile the tree sitter query"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let qr = transition_selection_expression_query.execute(node: node, in: tree)
|
||||||
|
|
||||||
|
guard let query_result = qr.next() else {
|
||||||
|
return .Error(Error(withMessage: "Could not find transition select expression"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let selector = query_result.captures(named: "selector")
|
||||||
|
let body = query_result.captures(named: "body")
|
||||||
|
|
||||||
|
return Expression.Parse(node: selector[0].node, inTree: tree).map { expression in
|
||||||
|
return switch TransitionKeysetExpression(node: body[0].node, inTree: tree) {
|
||||||
|
case .Ok(let kse):
|
||||||
|
Result<ParserTransitionStatement>.Ok(
|
||||||
|
ParserTransitionStatement(
|
||||||
|
withTransitionExpression: ParserTransitionSelectExpression(
|
||||||
|
withSelector: expression, withKeysetExpressions: kse)))
|
||||||
|
case .Error(let e): Result<ParserTransitionStatement>.Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static func TransitionStatement(
|
static func TransitionStatement(
|
||||||
node: Node, inTree tree: MutableTree
|
node: Node, inTree tree: MutableTree
|
||||||
) -> ParserTransitionStatement? {
|
) -> Result<ParserTransitionStatement> {
|
||||||
return ParserTransitionStatement()
|
guard
|
||||||
|
let next_state_query = try? SwiftTreeSitter.Query(
|
||||||
|
language: p4lang,
|
||||||
|
data: String(
|
||||||
|
"(parserTransitionStatement (transition) (transitionSelectionExpression (identifier) @next-state))"
|
||||||
|
).data(using: String.Encoding.utf8)!)
|
||||||
|
else {
|
||||||
|
return Result.Error(Error(withMessage: "Could not compile the tree sitter query"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let qr = next_state_query.execute(node: node, in: tree)
|
||||||
|
|
||||||
|
if let next_state_result = qr.next() {
|
||||||
|
let transition_capture = next_state_result.captures(named: "next-state")
|
||||||
|
return .Ok(ParserTransitionStatement(withNextState: transition_capture[0].node.text!))
|
||||||
|
}
|
||||||
|
|
||||||
|
return TransitionSelectExpression(node: node, inTree: tree)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func State(node: Node, inTree tree: MutableTree) -> Result<ParserState> {
|
static func State(node: Node, inTree tree: MutableTree) -> Result<ParserState> {
|
||||||
@@ -259,7 +344,7 @@ public struct Parser {
|
|||||||
guard !state_name_capture.isEmpty,
|
guard !state_name_capture.isEmpty,
|
||||||
!transition_capture.isEmpty,
|
!transition_capture.isEmpty,
|
||||||
let parsed_state_name = state_name_capture[0].node.text,
|
let parsed_state_name = state_name_capture[0].node.text,
|
||||||
let transition_statement = TransitionStatement(
|
case .Ok(let transition_statement) = TransitionStatement(
|
||||||
node: transition_capture[0].node, inTree: tree)
|
node: transition_capture[0].node, inTree: tree)
|
||||||
else {
|
else {
|
||||||
return Result.Error(Error(withMessage: "Could not parse a parser declaration"))
|
return Result.Error(Error(withMessage: "Could not parse a parser declaration"))
|
||||||
@@ -297,7 +382,9 @@ public struct Parser {
|
|||||||
withTransition: transition_statement))
|
withTransition: transition_statement))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static func Parser(withName name: Identifier, node: Node, inTree tree: MutableTree) -> Result<Lang.Parser> {
|
static func Parser(
|
||||||
|
withName name: Identifier, node: Node, inTree tree: MutableTree
|
||||||
|
) -> Result<Lang.Parser> {
|
||||||
guard
|
guard
|
||||||
let parser_state_query = try? SwiftTreeSitter.Query(
|
let parser_state_query = try? SwiftTreeSitter.Query(
|
||||||
language: p4lang,
|
language: p4lang,
|
||||||
@@ -312,12 +399,23 @@ public struct Parser {
|
|||||||
var parser = Lang.Parser(withName: name)
|
var parser = Lang.Parser(withName: name)
|
||||||
|
|
||||||
// Build a state from each one listed.
|
// Build a state from each one listed.
|
||||||
for parser_states in parser_state_query.execute(node: node, in: tree) {
|
let qr = parser_state_query.execute(node: node, in: tree)
|
||||||
switch P4Parser.State(node: parser_states.nodes[0], inTree: tree) {
|
let qr_value = qr.next()!
|
||||||
case Result.Ok(let state): parser.states.append(state)
|
let captures = qr_value.captures(named: "parser-states")
|
||||||
case Result.Error(let error): return Result.Error(error)
|
|
||||||
|
var error: Error? = .none
|
||||||
|
|
||||||
|
// TODO: Assert that there is only one.
|
||||||
|
captures[0].node.enumerateChildren { parser_state in
|
||||||
|
switch P4Parser.State(node: parser_state, inTree: tree) {
|
||||||
|
case Result.Ok(let state): parser.states = parser.states.append(state: state)
|
||||||
|
case Result.Error(let e): error = e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let error = error {
|
||||||
|
return .Error(error)
|
||||||
|
}
|
||||||
return Result.Ok(parser)
|
return Result.Ok(parser)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +452,10 @@ public struct Parser {
|
|||||||
let parser_qc = parser_declaration_query.execute(in: tree)
|
let parser_qc = parser_declaration_query.execute(in: tree)
|
||||||
|
|
||||||
for parser_declaration in parser_qc {
|
for parser_declaration in parser_qc {
|
||||||
switch Parser(withName: Identifier(name: parser_declaration.nodes[0].text!), node: parser_declaration.nodes[1], inTree: tree) {
|
switch Parser(
|
||||||
|
withName: Identifier(name: parser_declaration.nodes[0].text!),
|
||||||
|
node: parser_declaration.nodes[1], inTree: tree)
|
||||||
|
{
|
||||||
case Result.Ok(let parser): program.types.append(parser)
|
case Result.Ok(let parser): program.types.append(parser)
|
||||||
case Result.Error(let error): return Result.Error(error)
|
case Result.Error(let error): return Result.Error(error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,16 +18,7 @@
|
|||||||
import Common
|
import Common
|
||||||
import Lang
|
import Lang
|
||||||
|
|
||||||
|
extension ParserState: EvaluatableParserTransition {
|
||||||
|
|
||||||
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) {
|
public func evaluate(execution: ProgramExecution) -> (ParserState, ProgramExecution) {
|
||||||
var currentExecution = execution
|
var currentExecution = execution
|
||||||
|
|
||||||
@@ -41,10 +32,34 @@ extension ParserState: EvaluatableParserState {
|
|||||||
currentExecution = statement.evaluate(execution: currentExecution)
|
currentExecution = statement.evaluate(execution: currentExecution)
|
||||||
}
|
}
|
||||||
|
|
||||||
return if let transition = transition {
|
if direct_transition() {
|
||||||
transition.transition(execution: currentExecution)
|
return (next_state!, currentExecution)
|
||||||
} else {
|
|
||||||
(reject, currentExecution)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let transition_expression = self.transition,
|
||||||
|
let transition_select_expression = transition_expression.transition_expression
|
||||||
|
{
|
||||||
|
return transition_select_expression.evaluate(execution: currentExecution)
|
||||||
|
}
|
||||||
|
return (reject, currentExecution)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ParserTransitionSelectExpression: EvaluatableParserTransition {
|
||||||
|
func evaluate(execution: Common.ProgramExecution) -> (Lang.ParserState, Common.ProgramExecution) {
|
||||||
|
// First, evaluate the selector.
|
||||||
|
|
||||||
|
switch self.selector.evaluate(execution: execution) {
|
||||||
|
case .Ok(let selector_value):
|
||||||
|
for kse in self.keyset_expressions {
|
||||||
|
if case .Ok(let kse_key) = kse.key.evaluate(execution: execution),
|
||||||
|
kse_key.eq(rhs: selector_value)
|
||||||
|
{
|
||||||
|
return (kse.next_state!, execution)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .Error(let e): return (reject, execution.setError(error: e))
|
||||||
|
}
|
||||||
|
return (reject, execution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,4 +30,11 @@ extension ExpressionStatement: EvaluatableParserStatement {
|
|||||||
public func evaluate(execution: ProgramExecution) -> ProgramExecution {
|
public func evaluate(execution: ProgramExecution) -> ProgramExecution {
|
||||||
return execution
|
return execution
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variables are evaluatable because they can be looked up by identifiers.
|
||||||
|
extension Identifier: EvaluatableExpression {
|
||||||
|
public func evaluate(execution: Common.ProgramExecution) -> Result<P4Value> {
|
||||||
|
return execution.scopes.evaluate(identifier: self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
import Common
|
import Common
|
||||||
import Lang
|
import Lang
|
||||||
|
|
||||||
protocol EvaluatableParserState {
|
protocol EvaluatableParserTransition {
|
||||||
func evaluate(execution: ProgramExecution) -> (ParserState, ProgramExecution)
|
func evaluate(execution: ProgramExecution) -> (ParserState, ProgramExecution)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,14 +20,15 @@ import Lang
|
|||||||
|
|
||||||
/// The runtime for a parser
|
/// The runtime for a parser
|
||||||
public class ParserRuntime: CustomStringConvertible {
|
public class ParserRuntime: CustomStringConvertible {
|
||||||
var execution: ParserInstance
|
var parser: ParserInstance
|
||||||
|
|
||||||
init(execution: ParserInstance) {
|
init(execution: ParserInstance) {
|
||||||
self.execution = execution
|
self.parser = execution
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a parser runtime from a P4 program
|
/// Create a parser runtime from a P4 program
|
||||||
public static func create(program: Lang.Program) -> Result<ParserRuntime> {
|
public static func create(program: Lang.Program) -> Result<ParserRuntime> {
|
||||||
|
|
||||||
return switch program.starting_parser() {
|
return switch program.starting_parser() {
|
||||||
case .Ok(let parser):
|
case .Ok(let parser):
|
||||||
switch ParserInstance.create(parser) {
|
switch ParserInstance.create(parser) {
|
||||||
@@ -40,12 +41,12 @@ public class ParserRuntime: CustomStringConvertible {
|
|||||||
|
|
||||||
/// Run the P4 parser on a given packet
|
/// Run the P4 parser on a given packet
|
||||||
public func run(input: Packet) -> Result<(ParserState, ProgramExecution)> {
|
public func run(input: Packet) -> Result<(ParserState, ProgramExecution)> {
|
||||||
execution.scopes.enter()
|
parser.scopes.enter()
|
||||||
return .Ok(execution.execute())
|
return .Ok(parser.execute())
|
||||||
}
|
}
|
||||||
|
|
||||||
public var description: String {
|
public var description: String {
|
||||||
return "Runtime:\nExecution: \(execution)"
|
return "Runtime:\nExecution: \(parser)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ extension ParserInstance: Execution {
|
|||||||
|
|
||||||
// Evaluate until the state is either accept or reject.
|
// Evaluate until the state is either accept or reject.
|
||||||
while state != accept && state != reject {
|
while state != accept && state != reject {
|
||||||
(state, execution) = self.state.evaluate(execution: execution)
|
(state, execution) = state.evaluate(execution: execution)
|
||||||
}
|
}
|
||||||
return (state, execution)
|
return (state, execution)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,80 +15,84 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import Common
|
||||||
|
import Foundation
|
||||||
|
import Macros
|
||||||
|
import Runtime
|
||||||
|
import SwiftTreeSitter
|
||||||
import Testing
|
import Testing
|
||||||
import TreeSitter
|
import TreeSitter
|
||||||
import SwiftTreeSitter
|
|
||||||
import TreeSitterP4
|
import TreeSitterP4
|
||||||
import Foundation
|
|
||||||
import Runtime
|
|
||||||
import Common
|
|
||||||
|
|
||||||
import Macros
|
|
||||||
|
|
||||||
@testable import Parser
|
@testable import Parser
|
||||||
|
|
||||||
@Test func test_simple_parser() async throws {
|
@Test func test_simple_parser() async throws {
|
||||||
let simple_parser_declaration = """
|
let simple_parser_declaration = """
|
||||||
parser main_parser() {
|
parser main_parser() {
|
||||||
state start {
|
state start {
|
||||||
transition drop;
|
transition start;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
"""
|
"""
|
||||||
|
|
||||||
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
||||||
let parser = try #UseOkResult(program.find_parser(withName: Identifier(name: "main_parser")))
|
let parser = try #UseOkResult(program.find_parser(withName: Identifier(name: "main_parser")))
|
||||||
|
|
||||||
#expect(parser.states.count == 1)
|
#expect(parser.states.count() == 1)
|
||||||
#expect(parser.states[0].state_name == "start")
|
let state = try! #require(parser.states.find(withName: "start"))
|
||||||
#expect(parser.states[0].statements.count == 0)
|
#expect(state.state_name == "start")
|
||||||
|
#expect(state.statements.count == 0)
|
||||||
|
|
||||||
|
#expect(#RequireOkResult(parser.states.semantic_check()))
|
||||||
|
let next_state = try! #require(state.next_state)
|
||||||
|
#expect(next_state == state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func test_simple_parser_syntax_error() async throws {
|
@Test func test_simple_parser_syntax_error() async throws {
|
||||||
let simple_parser_declaration = """
|
let simple_parser_declaration = """
|
||||||
parser main_parser() {
|
parser main_parser() {
|
||||||
state
|
state
|
||||||
transition drop;
|
transition start;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
"""
|
"""
|
||||||
#expect(#RequireErrorResult(Error(withMessage: "Could not compile the P4 program"), Parser.Program(simple_parser_declaration)))
|
#expect(
|
||||||
|
#RequireErrorResult(
|
||||||
|
Error(withMessage: "Could not compile the P4 program"),
|
||||||
|
Parser.Program(simple_parser_declaration)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func test_simple_parser_with_statement() async throws {
|
@Test func test_simple_parser_with_statement() async throws {
|
||||||
let simple_parser_declaration = """
|
let simple_parser_declaration = """
|
||||||
parser main_parser() {
|
parser main_parser() {
|
||||||
state start {
|
state start {
|
||||||
true;
|
true;
|
||||||
transition drop;
|
transition start;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
"""
|
"""
|
||||||
|
|
||||||
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
||||||
let parser = try #UseOkResult(program.find_parser(withName: Identifier(name: "main_parser")))
|
let parser = try #UseOkResult(program.find_parser(withName: Identifier(name: "main_parser")))
|
||||||
|
|
||||||
#expect(parser.states.count == 1)
|
#expect(parser.states.count() == 1)
|
||||||
#expect(parser.states[0].state_name == "start")
|
|
||||||
#expect(parser.states[0].statements.count == 1)
|
let state = try! #require(parser.states.find(withName: "start"))
|
||||||
|
#expect(state.state_name == "start")
|
||||||
|
#expect(state.statements.count == 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test func test_simple_parser_with_instantiation() async throws {
|
@Test func test_simple_parser_with_instantiation() async throws {
|
||||||
let simple_parser_declaration = """
|
let simple_parser_declaration = """
|
||||||
parser main_parser() {
|
parser main_parser() {
|
||||||
state start {
|
state start {
|
||||||
true;
|
true;
|
||||||
transition drop;
|
transition start;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
bool() main;
|
bool() main;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
||||||
|
#expect(#RequireOkResult(program.find_parser(withName: Identifier(name: "main_parser"))))
|
||||||
let parser = try #UseOkResult(program.find_parser(withName: Identifier(name: "main_parser")))
|
|
||||||
#expect(parser.states.count == 1)
|
|
||||||
#expect(parser.states[0].state_name == "start")
|
|
||||||
#expect(parser.states[0].statements.count == 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,30 @@ import TreeSitterP4
|
|||||||
@testable import Parser
|
@testable import Parser
|
||||||
|
|
||||||
@Test func test_simple_runtime() async throws {
|
@Test func test_simple_runtime() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
parser main_parser() {
|
||||||
|
state start {
|
||||||
|
true;
|
||||||
|
transition accept;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
|
||||||
|
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
||||||
|
#expect(#RequireOkResult(Runtime.ParserRuntime.create(program: program)))
|
||||||
|
|
||||||
|
let runtime = try #UseOkResult(Runtime.ParserRuntime.create(program: program))
|
||||||
|
|
||||||
|
guard case Common.Result.Ok(let (state_result, _)) = runtime.run(input: Packet())
|
||||||
|
else {
|
||||||
|
assert(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should be in the accept state.
|
||||||
|
#expect(state_result == Lang.accept)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_runtime_to_accept() async throws {
|
||||||
let simple_parser_declaration = """
|
let simple_parser_declaration = """
|
||||||
parser main_parser() {
|
parser main_parser() {
|
||||||
state start {
|
state start {
|
||||||
@@ -39,8 +63,19 @@ import TreeSitterP4
|
|||||||
|
|
||||||
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
||||||
#expect(#RequireOkResult(Runtime.ParserRuntime.create(program: program)))
|
#expect(#RequireOkResult(Runtime.ParserRuntime.create(program: program)))
|
||||||
|
|
||||||
|
let runtime = try #UseOkResult(Runtime.ParserRuntime.create(program: program))
|
||||||
|
|
||||||
|
guard case Common.Result.Ok(let (state_result, _)) = runtime.run(input: Packet())
|
||||||
|
else {
|
||||||
|
assert(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should be in the accept state.
|
||||||
|
#expect(state_result == Lang.reject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test func test_simple_runtime_no_start_state() async throws {
|
@Test func test_simple_runtime_no_start_state() async throws {
|
||||||
let simple_parser_declaration = """
|
let simple_parser_declaration = """
|
||||||
parser main_parser() {
|
parser main_parser() {
|
||||||
@@ -89,7 +124,7 @@ import TreeSitterP4
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We should be in the accept state.
|
// We should be in the accept state.
|
||||||
#expect(state_result == Lang.accept)
|
#expect(state_result == Lang.reject)
|
||||||
|
|
||||||
// There are two variables declared.
|
// There are two variables declared.
|
||||||
#expect(scope.count == 2)
|
#expect(scope.count == 2)
|
||||||
@@ -100,3 +135,57 @@ import TreeSitterP4
|
|||||||
#expect(b.value_type.eq(rhs: P4BooleanValue(withValue: false)))
|
#expect(b.value_type.eq(rhs: P4BooleanValue(withValue: false)))
|
||||||
#expect(s.value_type.eq(rhs: P4StringValue(withValue: "\"testing\"")))
|
#expect(s.value_type.eq(rhs: P4StringValue(withValue: "\"testing\"")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_parser_with_transition_select_expression() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
parser main_parser() {
|
||||||
|
state start {
|
||||||
|
transition select (true) {
|
||||||
|
false: reject;
|
||||||
|
true: accept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
|
||||||
|
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
||||||
|
#expect(#RequireOkResult(program.find_parser(withName: Identifier(name: "main_parser"))))
|
||||||
|
let parser = try #UseOkResult(program.find_parser(withName: Identifier(name: "main_parser")))
|
||||||
|
|
||||||
|
#expect(parser.states.count() == 1)
|
||||||
|
|
||||||
|
let runtime = try #UseOkResult(Runtime.ParserRuntime.create(program: program))
|
||||||
|
|
||||||
|
guard case Common.Result.Ok(let (state_result, _)) = runtime.run(input: Packet())
|
||||||
|
else {
|
||||||
|
assert(false)
|
||||||
|
}
|
||||||
|
#expect(state_result == Lang.accept)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_parser_with_transition_select_expression_to_reject() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
parser main_parser() {
|
||||||
|
state start {
|
||||||
|
transition select (false) {
|
||||||
|
false: reject;
|
||||||
|
true: accept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
|
||||||
|
let program = try #UseOkResult(Parser.Program(simple_parser_declaration))
|
||||||
|
#expect(#RequireOkResult(program.find_parser(withName: Identifier(name: "main_parser"))))
|
||||||
|
let parser = try #UseOkResult(program.find_parser(withName: Identifier(name: "main_parser")))
|
||||||
|
|
||||||
|
#expect(parser.states.count() == 1)
|
||||||
|
|
||||||
|
let runtime = try #UseOkResult(Runtime.ParserRuntime.create(program: program))
|
||||||
|
|
||||||
|
guard case Common.Result.Ok(let (state_result, _)) = runtime.run(input: Packet())
|
||||||
|
else {
|
||||||
|
assert(false)
|
||||||
|
}
|
||||||
|
#expect(state_result == Lang.reject)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user