compiler, runtime, testing, common: Centralize Execution/Evaluation

Centralize the execution of statements and evaluation of expressions
so that the user can specify a debugging "callback" after every
execution/evaluation.

The callback can be used for myriad things, but it seems likely that
it will be useful for implementing:
1. Testing
2. Debugger

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-04-20 05:48:09 -04:00
parent c6f086f67f
commit d33066c543
13 changed files with 346 additions and 115 deletions
+7 -7
View File
@@ -49,7 +49,7 @@ import TreeSitterP4
])))
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
@@ -101,7 +101,7 @@ import TreeSitterP4
])))
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
@@ -128,7 +128,7 @@ import TreeSitterP4
])))
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
@@ -155,7 +155,7 @@ import TreeSitterP4
])))
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
@@ -187,7 +187,7 @@ import TreeSitterP4
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
@@ -216,7 +216,7 @@ import TreeSitterP4
])))
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
@@ -249,7 +249,7 @@ import TreeSitterP4
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
+114
View File
@@ -0,0 +1,114 @@
// 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/>.
import Common
import Foundation
import Macros
import P4Runtime
import P4Lang
import SwiftTreeSitter
import Testing
import TreeSitter
import TreeSitterP4
@testable import P4Compiler
@Test func test_statement_interloper() async throws {
let simple_parser_declaration = """
parser main_parser() {
state starts {
bool where_to = false;
int va = 5;
transition accept;
}
state start {
bool where_to = true;
where_to = true;
transition select (where_to) {
false: reject;
true: starts;
};
}
};
"""
let program = try #UseOkResult(Program.Compile(simple_parser_declaration))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program))
var statements_executed: [String] = Array()
let pe = ProgramExecution().setStatementInterloper({ (statement, cf, execution) in
statements_executed.append("\(statement)")
})
let (state_result, _) = try! #UseOkResult(runtime.run(withArguments: ArgumentList(), inExecution: pe))
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
#expect(statements_executed[0].hasPrefix("VariableDeclarationStatement"))
#expect(statements_executed[1].hasPrefix("ParserAssignmentStatement"))
// Moved into starts
#expect(statements_executed[2].hasPrefix("VariableDeclarationStatement"))
#expect(statements_executed[3].hasPrefix("VariableDeclarationStatement"))
}
@Test func test_expression_interloper() async throws {
let simple_parser_declaration = """
parser main_parser() {
state starts {
bool where_to = false;
int va = 5;
transition accept;
}
state start {
bool where_to = true;
where_to = true;
transition select (where_to) {
false: reject;
true: starts;
};
}
};
"""
let program = try #UseOkResult(Program.Compile(simple_parser_declaration))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program))
var expressions_evaluated: [String] = Array()
let pe = ProgramExecution().setExpressionInterloper() { expression, result, execution in
print("Expression: \(expression)")
expressions_evaluated.append("\(expression)")
}
let (state_result, _) = try! #UseOkResult(runtime.run(withArguments: ArgumentList(), inExecution: pe))
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
#expect(expressions_evaluated[0].hasPrefix("Value: true of Boolean"))
#expect(expressions_evaluated[1].hasPrefix("Value: true of Boolean"))
#expect(expressions_evaluated[2].hasPrefix("where_to"))
#expect(expressions_evaluated[3].hasPrefix("Value: false of Boolean"))
#expect(expressions_evaluated[4].hasPrefix("KeysetExpression"))
#expect(expressions_evaluated[5].hasPrefix("Value: true of Boolean"))
#expect(expressions_evaluated[6].hasPrefix("KeysetExpression"))
#expect(expressions_evaluated[7].hasPrefix("SelectCaseExpression"))
#expect(expressions_evaluated[8].hasPrefix("SelectExpression"))
// Moved into starts
#expect(expressions_evaluated[9].hasPrefix("Value: false of Boolean"))
#expect(expressions_evaluated[10].hasPrefix("Value: 5 of Int"))
}
+8 -8
View File
@@ -57,7 +57,7 @@ import TreeSitterP4
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
}
@@ -151,7 +151,7 @@ import TreeSitterP4
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
}
@@ -186,7 +186,7 @@ import TreeSitterP4
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
}
@@ -220,7 +220,7 @@ import TreeSitterP4
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
}
@@ -266,7 +266,7 @@ import TreeSitterP4
])))
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
}
@@ -302,7 +302,7 @@ import TreeSitterP4
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
}
@@ -375,7 +375,7 @@ import TreeSitterP4
])))
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
}
@@ -423,7 +423,7 @@ import TreeSitterP4
])))
let program = try #UseOkResult(
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withInitialValues: test_values))
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program, withGlobalValues: test_values))
let (state_result, _) = try! #UseOkResult(runtime.run())
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
}
+7 -2
View File
@@ -35,10 +35,15 @@ struct StringConvertible: CustomStringConvertible {
@Test func test_result_type_description_not_convertible() async throws {
let result: Result<NotStringConvertible> = Result.Ok(NotStringConvertible());
#expect(result.description == "Ok")
#expect("\(result)" == "Ok(Tests.NotStringConvertible())")
}
@Test func test_result_type_description_convertible() async throws {
let result: Result<StringConvertible> = Result.Ok(StringConvertible());
#expect(result.description == "CONVERTED")
#expect("\(result)" == "Ok: CONVERTED")
}
@Test func test_result_type_p4value_convertible() async throws {
let result = Result.Ok(P4Value(P4IntValue(withValue: 5)))
#expect("\(result)" == "Ok: Value: 5 of Int type of type Int")
}