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:
@@ -15,25 +15,32 @@
|
|||||||
// 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/>.
|
||||||
|
|
||||||
|
public typealias StatementInterloper = (EvaluatableStatement, ControlFlow, ProgramExecution) -> Void
|
||||||
|
public typealias ExpressionInterloper = (EvaluatableExpression, Result<P4Value>, ProgramExecution) -> Void
|
||||||
|
|
||||||
open class ProgramExecution: CustomStringConvertible {
|
open class ProgramExecution: CustomStringConvertible {
|
||||||
public var scopes: VarValueScopes = VarValueScopes()
|
public var scopes: VarValueScopes = VarValueScopes()
|
||||||
let initialValues: VarValueScopes?
|
var globalValues: VarValueScopes?
|
||||||
var error: Error?
|
var error: Error?
|
||||||
var debug: DebugLevel = DebugLevel.Error
|
var debug: DebugLevel = DebugLevel.Error
|
||||||
|
var statement_interloper: StatementInterloper?
|
||||||
|
var expression_interloper: ExpressionInterloper?
|
||||||
|
|
||||||
init(copy: ProgramExecution) {
|
init(copy: ProgramExecution) {
|
||||||
self.scopes = copy.scopes
|
self.scopes = copy.scopes
|
||||||
self.initialValues = copy.initialValues
|
self.globalValues = copy.globalValues
|
||||||
self.error = copy.error
|
self.error = copy.error
|
||||||
self.debug = copy.debug
|
self.debug = copy.debug
|
||||||
|
self.statement_interloper = copy.statement_interloper
|
||||||
|
self.expression_interloper = copy.expression_interloper
|
||||||
}
|
}
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
initialValues = .none
|
globalValues = .none
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(withGlobalValues values: VarValueScopes) {
|
public init(withGlobalValues values: VarValueScopes) {
|
||||||
initialValues = values
|
globalValues = values
|
||||||
}
|
}
|
||||||
|
|
||||||
open var description: String {
|
open var description: String {
|
||||||
@@ -64,6 +71,26 @@ open class ProgramExecution: CustomStringConvertible {
|
|||||||
return pe
|
return pe
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func getStatementInterloper() -> StatementInterloper? {
|
||||||
|
return self.statement_interloper
|
||||||
|
}
|
||||||
|
|
||||||
|
public func setStatementInterloper(_ interloper: @escaping StatementInterloper) -> ProgramExecution {
|
||||||
|
let pe = ProgramExecution(copy: self)
|
||||||
|
pe.statement_interloper = interloper
|
||||||
|
return pe
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getExpressionInterloper() -> ExpressionInterloper? {
|
||||||
|
return self.expression_interloper
|
||||||
|
}
|
||||||
|
|
||||||
|
public func setExpressionInterloper(_ interloper: @escaping ExpressionInterloper) -> ProgramExecution {
|
||||||
|
let pe = ProgramExecution(copy: self)
|
||||||
|
pe.expression_interloper = interloper
|
||||||
|
return pe
|
||||||
|
}
|
||||||
|
|
||||||
open func isDone() -> Bool {
|
open func isDone() -> Bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -101,9 +128,17 @@ open class ProgramExecution: CustomStringConvertible {
|
|||||||
return new_pe
|
return new_pe
|
||||||
}
|
}
|
||||||
|
|
||||||
public func initial_values() -> VarValueScopes? {
|
public func getGlobalValues() -> VarValueScopes {
|
||||||
return self.initialValues
|
return self.globalValues ?? VarValueScopes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func setGlobalValues(_ global_values: VarValueScopes) -> ProgramExecution {
|
||||||
|
let new_pe = ProgramExecution(copy: self)
|
||||||
|
new_pe.globalValues = global_values
|
||||||
|
return new_pe
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A scope that resolves variable identifiers to their values.
|
/// A scope that resolves variable identifiers to their values.
|
||||||
|
|||||||
@@ -117,24 +117,13 @@ public enum Result<OKT>: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Result where OKT: CustomStringConvertible {
|
extension Result: CustomStringConvertible where OKT: CustomStringConvertible {
|
||||||
public var description: String {
|
public var description: String {
|
||||||
switch self {
|
switch self {
|
||||||
case Result.Error(let e):
|
case Result.Error(let e):
|
||||||
return e.msg
|
return e.msg
|
||||||
case Result.Ok(let o):
|
case Result.Ok(let o):
|
||||||
return "\(o)"
|
return "Ok: \(o)"
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Result: CustomStringConvertible {
|
|
||||||
public var description: String {
|
|
||||||
switch self {
|
|
||||||
case Result.Error(let e):
|
|
||||||
return e.msg
|
|
||||||
case Result.Ok(_):
|
|
||||||
return "Ok"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ public struct ParameterList: CustomStringConvertible, Equatable {
|
|||||||
public struct ArgumentList {
|
public struct ArgumentList {
|
||||||
public let arguments: [Argument]
|
public let arguments: [Argument]
|
||||||
|
|
||||||
public init(_ arguments: [Argument]) {
|
public init(_ arguments: [Argument] = []) {
|
||||||
self.arguments = arguments
|
self.arguments = arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ public func Call<T>(
|
|||||||
for (parameter, argument) in zip(params.parameters, args.arguments) {
|
for (parameter, argument) in zip(params.parameters, args.arguments) {
|
||||||
let arg_idx = argument.index
|
let arg_idx = argument.index
|
||||||
let arg_value = argument.argument
|
let arg_value = argument.argument
|
||||||
let maybe_argument_value = arg_value.evaluate(execution: called_execution)
|
//let maybe_argument_value = arg_value.evaluate(execution: called_execution)
|
||||||
|
let maybe_argument_value = EvaluateExpression(arg_value, inExecution: called_execution)
|
||||||
guard case (.Ok(let argument_value), let updated_execution) = maybe_argument_value else {
|
guard case (.Ok(let argument_value), let updated_execution) = maybe_argument_value else {
|
||||||
return (
|
return (
|
||||||
.Error(Error(withMessage: "Cannot evaluate argument \(arg_idx): \(argument)")),
|
.Error(Error(withMessage: "Cannot evaluate argument \(arg_idx): \(argument)")),
|
||||||
@@ -82,3 +83,63 @@ public func Call<T>(
|
|||||||
}
|
}
|
||||||
return (.Ok(call_result), updated_execution.replaceScopes(inout_scopes))
|
return (.Ok(call_result), updated_execution.replaceScopes(inout_scopes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public typealias ExecuteStatementResultHandler = (ControlFlow, ProgramExecution) -> (ControlFlow, ProgramExecution)
|
||||||
|
|
||||||
|
public func ExecuteStatement(
|
||||||
|
_ statements: [EvaluatableStatement], handleResult handler: ExecuteStatementResultHandler,
|
||||||
|
inExecution execution: ProgramExecution,
|
||||||
|
) -> (ControlFlow, ProgramExecution) {
|
||||||
|
|
||||||
|
var debugger: StatementInterloper? = .none
|
||||||
|
var hasDebugInterloper = false
|
||||||
|
if let found_deb = execution.getStatementInterloper() {
|
||||||
|
debugger = found_deb
|
||||||
|
hasDebugInterloper = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var execution = execution
|
||||||
|
for s in statements {
|
||||||
|
let (control_flow, next_execution) = s.evaluate(execution: execution)
|
||||||
|
|
||||||
|
if hasDebugInterloper {
|
||||||
|
debugger!(s, control_flow, next_execution)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch handler(control_flow, next_execution) {
|
||||||
|
case (ControlFlow.Next, let handled_next_execution): execution = handled_next_execution
|
||||||
|
case (ControlFlow.Return(let value), let handled_next_execution):
|
||||||
|
return (ControlFlow.Return(value), handled_next_execution)
|
||||||
|
case (let handled_control_flow, let handled_next_execution):
|
||||||
|
return (handled_control_flow, handled_next_execution)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (ControlFlow.Next, execution)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func ExecuteStatement(
|
||||||
|
_ statement: EvaluatableStatement, handleResult handler: ExecuteStatementResultHandler,
|
||||||
|
inExecution execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||||
|
return ExecuteStatement([statement], handleResult: handler, inExecution: execution)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func EvaluateExpression(
|
||||||
|
_ expression: EvaluatableExpression, inExecution execution: ProgramExecution,
|
||||||
|
) -> (Result<P4Value>, ProgramExecution) {
|
||||||
|
|
||||||
|
var debugger: ExpressionInterloper? = .none
|
||||||
|
var hasDebugInterloper = false
|
||||||
|
if let found_deb = execution.getExpressionInterloper() {
|
||||||
|
debugger = found_deb
|
||||||
|
hasDebugInterloper = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let (result, execution) = expression.evaluate(execution: execution)
|
||||||
|
|
||||||
|
if hasDebugInterloper {
|
||||||
|
debugger!(expression, result, execution)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result, execution)
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,14 +30,14 @@ extension SelectCaseExpression: EvaluatableExpression {
|
|||||||
|
|
||||||
extension SelectExpression: EvaluatableExpression {
|
extension SelectExpression: EvaluatableExpression {
|
||||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||||
switch self.selector.evaluate(execution: execution) {
|
switch EvaluateExpression(self.selector, inExecution: execution) {
|
||||||
case (.Ok(let selector_value), let updated_execution):
|
case (.Ok(let selector_value), let updated_execution):
|
||||||
for sce in self.case_expressions {
|
for sce in self.case_expressions {
|
||||||
if case (.Ok(let kse), let updated_execution) = sce.key.evaluate(
|
if case (.Ok(let kse), let updated_execution) = EvaluateExpression(sce.key, inExecution: updated_execution),
|
||||||
execution: updated_execution),
|
|
||||||
kse.eq(selector_value)
|
kse.eq(selector_value)
|
||||||
{
|
{
|
||||||
let result = sce.evaluate(execution: updated_execution)
|
//let result = sce.evaluate(execution: updated_execution)
|
||||||
|
let result = EvaluateExpression(sce, inExecution: updated_execution)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,12 +210,14 @@ public func binary_int_math_operator_checker(
|
|||||||
extension BinaryOperatorExpression: EvaluatableExpression {
|
extension BinaryOperatorExpression: EvaluatableExpression {
|
||||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||||
let updated_execution = execution
|
let updated_execution = execution
|
||||||
let maybe_evaluated_left = self.left.evaluate(execution: updated_execution)
|
//let maybe_evaluated_left = self.left.evaluate(execution: updated_execution)
|
||||||
|
let maybe_evaluated_left = EvaluateExpression(self.left, inExecution: updated_execution)
|
||||||
guard case (.Ok(let evaluated_left), let updated_execution) = maybe_evaluated_left else {
|
guard case (.Ok(let evaluated_left), let updated_execution) = maybe_evaluated_left else {
|
||||||
return maybe_evaluated_left
|
return maybe_evaluated_left
|
||||||
}
|
}
|
||||||
|
|
||||||
let maybe_evaluated_right = self.right.evaluate(execution: updated_execution)
|
//let maybe_evaluated_right = self.right.evaluate(execution: updated_execution)
|
||||||
|
let maybe_evaluated_right = EvaluateExpression(self.right, inExecution: updated_execution)
|
||||||
guard case (.Ok(let evaluated_right), let updated_execution) = maybe_evaluated_right else {
|
guard case (.Ok(let evaluated_right), let updated_execution) = maybe_evaluated_right else {
|
||||||
return maybe_evaluated_right
|
return maybe_evaluated_right
|
||||||
}
|
}
|
||||||
@@ -231,12 +233,14 @@ extension BinaryOperatorExpression: EvaluatableExpression {
|
|||||||
extension ArrayAccessExpression: EvaluatableExpression {
|
extension ArrayAccessExpression: EvaluatableExpression {
|
||||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||||
let updated_execution = execution
|
let updated_execution = execution
|
||||||
let maybe_name = self.name.evaluate(execution: updated_execution)
|
//let maybe_name = self.name.evaluate(execution: updated_execution)
|
||||||
|
let maybe_name = EvaluateExpression(self.name, inExecution: updated_execution)
|
||||||
guard case (.Ok(let name), let updated_execution) = maybe_name else {
|
guard case (.Ok(let name), let updated_execution) = maybe_name else {
|
||||||
return maybe_name
|
return maybe_name
|
||||||
}
|
}
|
||||||
|
|
||||||
let maybe_indexor = self.indexor.evaluate(execution: updated_execution)
|
//let maybe_indexor = self.indexor.evaluate(execution: updated_execution)
|
||||||
|
let maybe_indexor = EvaluateExpression(self.indexor, inExecution: updated_execution)
|
||||||
guard case (.Ok(let indexor), let updated_execution) = maybe_indexor else {
|
guard case (.Ok(let indexor), let updated_execution) = maybe_indexor else {
|
||||||
return maybe_indexor
|
return maybe_indexor
|
||||||
}
|
}
|
||||||
@@ -265,7 +269,8 @@ extension ArrayAccessExpression: EvaluatableLValueExpression {
|
|||||||
) -> Common.Result<(Common.VarValueScopes, P4Value)> {
|
) -> Common.Result<(Common.VarValueScopes, P4Value)> {
|
||||||
|
|
||||||
let updated_execution = execution
|
let updated_execution = execution
|
||||||
let maybe_value = self.name.evaluate(execution: updated_execution)
|
//let maybe_value = self.name.evaluate(execution: updated_execution)
|
||||||
|
let maybe_value = EvaluateExpression(self.name, inExecution: updated_execution)
|
||||||
guard case (.Ok(let value), let updated_execution) = maybe_value else {
|
guard case (.Ok(let value), let updated_execution) = maybe_value else {
|
||||||
return .Error(
|
return .Error(
|
||||||
Error(withMessage: "\(self.name) cannot be evaluated: \(maybe_value.0.error()!)"))
|
Error(withMessage: "\(self.name) cannot be evaluated: \(maybe_value.0.error()!)"))
|
||||||
@@ -275,7 +280,8 @@ extension ArrayAccessExpression: EvaluatableLValueExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now, get the indexor!
|
// Now, get the indexor!
|
||||||
let maybe_indexor_value = self.indexor.evaluate(execution: updated_execution)
|
//let maybe_indexor_value = self.indexor.evaluate(execution: updated_execution)
|
||||||
|
let maybe_indexor_value = EvaluateExpression(self.indexor, inExecution: updated_execution)
|
||||||
guard case (.Ok(let indexor_value), let updated_execution) = maybe_indexor_value else {
|
guard case (.Ok(let indexor_value), let updated_execution) = maybe_indexor_value else {
|
||||||
return Result.Error(
|
return Result.Error(
|
||||||
Error(withMessage: "\(self.indexor) cannot be evaluated: \(maybe_indexor_value.0.error()!)")
|
Error(withMessage: "\(self.indexor) cannot be evaluated: \(maybe_indexor_value.0.error()!)")
|
||||||
@@ -341,7 +347,8 @@ extension FieldAccessExpression: EvaluatableExpression {
|
|||||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||||
|
|
||||||
let updated_execution = execution
|
let updated_execution = execution
|
||||||
let maybe_struct = self.strct.evaluate(execution: updated_execution)
|
//let maybe_struct = self.strct.evaluate(execution: updated_execution)
|
||||||
|
let maybe_struct = EvaluateExpression(self.strct, inExecution: updated_execution)
|
||||||
guard case (.Ok(let strct), let updated_execution) = maybe_struct else {
|
guard case (.Ok(let strct), let updated_execution) = maybe_struct else {
|
||||||
return maybe_struct
|
return maybe_struct
|
||||||
}
|
}
|
||||||
@@ -375,7 +382,8 @@ extension FieldAccessExpression: EvaluatableLValueExpression {
|
|||||||
|
|
||||||
let updated_execution = execution
|
let updated_execution = execution
|
||||||
// First, evaluate strct_id and make sure that it names a struct.
|
// First, evaluate strct_id and make sure that it names a struct.
|
||||||
let maybe_value = self.strct.evaluate(execution: updated_execution)
|
//let maybe_value = self.strct.evaluate(execution: updated_execution)
|
||||||
|
let maybe_value = EvaluateExpression(self.strct, inExecution: updated_execution)
|
||||||
guard case (.Ok(let value), let updated_execution) = maybe_value else {
|
guard case (.Ok(let value), let updated_execution) = maybe_value else {
|
||||||
return .Error(
|
return .Error(
|
||||||
Error(withMessage: "\(self.strct) cannot be evaluated: \(maybe_value.0.error()!)"))
|
Error(withMessage: "\(self.strct) cannot be evaluated: \(maybe_value.0.error()!)"))
|
||||||
@@ -444,7 +452,8 @@ extension FieldAccessExpression: EvaluatableLValueExpression {
|
|||||||
|
|
||||||
extension KeysetExpression: EvaluatableExpression {
|
extension KeysetExpression: EvaluatableExpression {
|
||||||
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
|
||||||
return self.key.evaluate(execution: execution)
|
//return self.key.evaluate(execution: execution)
|
||||||
|
return EvaluateExpression(self.key, inExecution: execution)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func type() -> P4Type {
|
public func type() -> P4Type {
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ import P4Lang
|
|||||||
extension ParserAssignmentStatement: EvaluatableStatement {
|
extension ParserAssignmentStatement: EvaluatableStatement {
|
||||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||||
let updated_execution = execution
|
let updated_execution = execution
|
||||||
let result = self.value.evaluate(execution: updated_execution)
|
//let result = self.value.evaluate(execution: updated_execution)
|
||||||
|
let result = EvaluateExpression(self.value, inExecution: updated_execution)
|
||||||
guard case (.Ok(let value), let updated_execution) = result else {
|
guard case (.Ok(let value), let updated_execution) = result else {
|
||||||
return (ControlFlow.Error, execution.setError(error: result.0.error()!))
|
return (ControlFlow.Error, execution.setError(error: result.0.error()!))
|
||||||
}
|
}
|
||||||
@@ -43,19 +44,23 @@ extension ParserStateDirectTransition: EvaluatableParserState {
|
|||||||
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
||||||
var program = program.enter_scope()
|
var program = program.enter_scope()
|
||||||
|
|
||||||
for statement in statements {
|
|
||||||
let (control_flow, next_program) = statement.evaluate(execution: program)
|
let (control_flow, next_execution) = ExecuteStatement(statements, handleResult: { (control_flow, execution) in
|
||||||
switch control_flow {
|
return (control_flow, execution)
|
||||||
case .Next: program = next_program // Ok!
|
}, inExecution: program)
|
||||||
case .Error: return (reject, next_program)
|
|
||||||
default:
|
|
||||||
return (
|
switch control_flow {
|
||||||
reject,
|
case .Next: program = next_execution
|
||||||
next_program.setError(
|
case .Error: return (reject, next_execution.exit_scope())
|
||||||
error: Error(withMessage: "Invalid control flow (\(control_flow) in parser)"))
|
default:
|
||||||
)
|
return (
|
||||||
}
|
reject,
|
||||||
|
next_execution.exit_scope().setError(
|
||||||
|
error: Error(withMessage: "Invalid control flow (\(control_flow) in parser)"))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = program.scopes.lookup(identifier: get_next_state())
|
let res = program.scopes.lookup(identifier: get_next_state())
|
||||||
|
|
||||||
if case .Ok(let value) = res {
|
if case .Ok(let value) = res {
|
||||||
@@ -79,7 +84,6 @@ extension ParserStateDirectTransition: EvaluatableParserState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension ParserStateNoTransition: EvaluatableParserState {
|
extension ParserStateNoTransition: EvaluatableParserState {
|
||||||
|
|
||||||
public func execute(
|
public func execute(
|
||||||
program: Common.ProgramExecution
|
program: Common.ProgramExecution
|
||||||
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
||||||
@@ -96,28 +100,30 @@ extension ParserStateNoTransition: EvaluatableParserState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension ParserStateSelectTransition: EvaluatableParserState {
|
extension ParserStateSelectTransition: EvaluatableParserState {
|
||||||
|
|
||||||
public func execute(
|
public func execute(
|
||||||
program: Common.ProgramExecution
|
program: Common.ProgramExecution
|
||||||
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
||||||
var program = program.enter_scope()
|
var program = program.enter_scope()
|
||||||
|
|
||||||
// First, evaluate the statements.
|
let (control_flow, next_execution) = ExecuteStatement(statements, handleResult: { (control_flow, execution) in
|
||||||
for statement in statements {
|
return (control_flow, execution)
|
||||||
let (control_flow, next_program) = statement.evaluate(execution: program)
|
}, inExecution: program)
|
||||||
switch control_flow {
|
|
||||||
case .Next: program = next_program // Ok!
|
|
||||||
case .Error: return (reject, next_program)
|
switch control_flow {
|
||||||
default:
|
case .Next: program = next_execution
|
||||||
return (
|
case .Error: return (reject, next_execution.exit_scope())
|
||||||
reject,
|
default:
|
||||||
next_program.setError(
|
return (
|
||||||
error: Error(withMessage: "Invalid control flow (\(control_flow) in parser)"))
|
reject,
|
||||||
)
|
next_execution.exit_scope().setError(
|
||||||
}
|
error: Error(withMessage: "Invalid control flow (\(control_flow) in parser)"))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch self.selectExpression.evaluate(execution: program) {
|
|
||||||
|
//switch self.selectExpression.evaluate(execution: program) {
|
||||||
|
switch EvaluateExpression(self.selectExpression, inExecution: program) {
|
||||||
case (.Ok(let value), let program):
|
case (.Ok(let value), let program):
|
||||||
if value.type().dataType().eq(rhs: self) {
|
if value.type().dataType().eq(rhs: self) {
|
||||||
return (value.dataValue() as! EvaluatableParserState, program.exit_scope())
|
return (value.dataValue() as! EvaluatableParserState, program.exit_scope())
|
||||||
@@ -156,10 +162,8 @@ extension Parser: LibraryCallable {
|
|||||||
withValue: P4Value(reject, P4Type.ReadOnly(reject.type())))
|
withValue: P4Value(reject, P4Type.ReadOnly(reject.type())))
|
||||||
|
|
||||||
// Add initial values to the global scope
|
// Add initial values to the global scope
|
||||||
if let initial = execution.initial_values() {
|
for (name, value) in execution.getGlobalValues() {
|
||||||
for (name, value) in initial {
|
execution = execution.declare(identifier: name, withValue: value)
|
||||||
execution = execution.declare(identifier: name, withValue: value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, add every state to the scope!
|
// First, add every state to the scope!
|
||||||
|
|||||||
@@ -29,22 +29,22 @@ public struct ParserRuntime: CustomStringConvertible {
|
|||||||
self.initialValues = .none
|
self.initialValues = .none
|
||||||
}
|
}
|
||||||
|
|
||||||
init(parser: Parser, withInitialValues initial: VarValueScopes?) {
|
init(parser: Parser, withGlobalValues initial: VarValueScopes?) {
|
||||||
self.parser = parser
|
self.parser = parser
|
||||||
self.initialValues = initial
|
self.initialValues = initial
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a parser runtime from a P4 program
|
/// Create a parser runtime from a P4 program
|
||||||
public static func create(program: P4Lang.Program) -> Result<ParserRuntime> {
|
public static func create(program: P4Lang.Program) -> Result<ParserRuntime> {
|
||||||
return ParserRuntime.create(program: program, withInitialValues: .none)
|
return ParserRuntime.create(program: program, withGlobalValues: .none)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func create(
|
public static func create(
|
||||||
program: P4Lang.Program, withInitialValues initial: VarValueScopes?
|
program: P4Lang.Program, withGlobalValues initial: VarValueScopes?
|
||||||
) -> Result<ParserRuntime> {
|
) -> Result<ParserRuntime> {
|
||||||
return switch program.starting_parser() {
|
return switch program.starting_parser() {
|
||||||
case .Ok(let parser):
|
case .Ok(let parser):
|
||||||
.Ok(P4Runtime.ParserRuntime(parser: parser, withInitialValues: initial))
|
.Ok(P4Runtime.ParserRuntime(parser: parser, withGlobalValues: initial))
|
||||||
case .Error(let error): .Error(error)
|
case .Error(let error): .Error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,12 +52,10 @@ public struct ParserRuntime: CustomStringConvertible {
|
|||||||
/// Run a P4 parser with no arguments
|
/// Run a P4 parser with no arguments
|
||||||
public func run() -> Result<(ParserState, ProgramExecution)> {
|
public func run() -> Result<(ParserState, ProgramExecution)> {
|
||||||
return self.run(withArguments: ArgumentList([]))
|
return self.run(withArguments: ArgumentList([]))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the P4 parser on a given packet
|
public func run(withArguments arguments: ArgumentList) -> Result<(ParserState, ProgramExecution)> {
|
||||||
public func run(withArguments arguments: ArgumentList) -> Result<(ParserState, ProgramExecution)>
|
|
||||||
{
|
|
||||||
|
|
||||||
let pe =
|
let pe =
|
||||||
if let initial = initialValues {
|
if let initial = initialValues {
|
||||||
ProgramExecution(withGlobalValues: initial)
|
ProgramExecution(withGlobalValues: initial)
|
||||||
@@ -65,6 +63,19 @@ public struct ParserRuntime: CustomStringConvertible {
|
|||||||
ProgramExecution()
|
ProgramExecution()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return self.run(withArguments: arguments, inExecution: pe)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the P4 parser on a given packet
|
||||||
|
public func run(withArguments arguments: ArgumentList, inExecution pe: ProgramExecution) -> Result<(ParserState, ProgramExecution)>
|
||||||
|
{
|
||||||
|
|
||||||
|
let pe = if let globals = initialValues {
|
||||||
|
pe.setGlobalValues(globals)
|
||||||
|
} else {
|
||||||
|
pe
|
||||||
|
}
|
||||||
|
|
||||||
let (end_state, execution) = parser.call(execution: pe, arguments: arguments)
|
let (end_state, execution) = parser.call(execution: pe, arguments: arguments)
|
||||||
if let error = execution.getError() {
|
if let error = execution.getError() {
|
||||||
return .Error(error)
|
return .Error(error)
|
||||||
|
|||||||
@@ -20,29 +20,31 @@ import P4Lang
|
|||||||
|
|
||||||
extension BlockStatement: EvaluatableStatement {
|
extension BlockStatement: EvaluatableStatement {
|
||||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||||
var execution = execution
|
print("I am going to evaluate a block statement?")
|
||||||
for s in self.statements {
|
return ExecuteStatement(
|
||||||
let (control_flow, next_execution) = s.evaluate(execution: execution)
|
self.statements,
|
||||||
switch control_flow {
|
handleResult: { (cf, execution) in
|
||||||
case ControlFlow.Return(let value): return (ControlFlow.Return(value), next_execution)
|
switch cf {
|
||||||
case ControlFlow.Next: execution = next_execution
|
case ControlFlow.Return(let value): return (ControlFlow.Return(value), execution)
|
||||||
case ControlFlow.Error: return (ControlFlow.Error, next_execution)
|
case ControlFlow.Next: return (cf, execution)
|
||||||
default:
|
case ControlFlow.Error: return (ControlFlow.Error, execution)
|
||||||
return (
|
default:
|
||||||
ControlFlow.Next,
|
return (
|
||||||
next_execution.setError(
|
ControlFlow.Error,
|
||||||
error: Error(withMessage: "Invalid control flow \(control_flow) in block statement"))
|
execution.setError(
|
||||||
)
|
error: Error(withMessage: "Invalid control flow \(cf) in block statement"))
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
return (ControlFlow.Next, execution)
|
},
|
||||||
|
inExecution: execution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension VariableDeclarationStatement: EvaluatableStatement {
|
extension VariableDeclarationStatement: EvaluatableStatement {
|
||||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||||
guard
|
guard
|
||||||
case (.Ok(let initial_value), let execution) = self.initializer.evaluate(execution: execution)
|
//case (.Ok(let initial_value), let execution) = self.initializer.evaluate(execution: execution)
|
||||||
|
case (.Ok(let initial_value), let execution) = EvaluateExpression(self.initializer, inExecution: execution)
|
||||||
else {
|
else {
|
||||||
return (
|
return (
|
||||||
ControlFlow.Error,
|
ControlFlow.Error,
|
||||||
@@ -58,8 +60,8 @@ extension VariableDeclarationStatement: EvaluatableStatement {
|
|||||||
extension ConditionalStatement: EvaluatableStatement {
|
extension ConditionalStatement: EvaluatableStatement {
|
||||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||||
guard
|
guard
|
||||||
case (.Ok(let evaluated_condition), let execution) = self.condition.evaluate(
|
//case (.Ok(let evaluated_condition), let execution) = self.condition.evaluate(execution: execution)
|
||||||
execution: execution)
|
case (.Ok(let evaluated_condition), let execution) = EvaluateExpression(self.condition, inExecution: execution)
|
||||||
else {
|
else {
|
||||||
return (
|
return (
|
||||||
ControlFlow.Error,
|
ControlFlow.Error,
|
||||||
@@ -107,7 +109,8 @@ extension ExpressionStatement: EvaluatableStatement {
|
|||||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||||
|
|
||||||
// Evaluate, there might be side effects!
|
// Evaluate, there might be side effects!
|
||||||
return switch self.expression.evaluate(execution: execution) {
|
//return switch self.expression.evaluate(execution: execution) {
|
||||||
|
return switch EvaluateExpression(self.expression, inExecution: execution) {
|
||||||
case (.Ok(_), let updated_context): (ControlFlow.Next, updated_context)
|
case (.Ok(_), let updated_context): (ControlFlow.Next, updated_context)
|
||||||
case (.Error(let e), let updated_context):
|
case (.Error(let e), let updated_context):
|
||||||
(ControlFlow.Next, updated_context.setError(error: e))
|
(ControlFlow.Next, updated_context.setError(error: e))
|
||||||
@@ -117,7 +120,8 @@ extension ExpressionStatement: EvaluatableStatement {
|
|||||||
|
|
||||||
extension ReturnStatement: EvaluatableStatement {
|
extension ReturnStatement: EvaluatableStatement {
|
||||||
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
|
||||||
return switch self.value.evaluate(execution: execution) {
|
//return switch self.value.evaluate(execution: execution) {
|
||||||
|
return switch EvaluateExpression(self.value, inExecution: execution) {
|
||||||
case (.Ok(let v), let execution): (ControlFlow.Return(v), execution)
|
case (.Ok(let v), let execution): (ControlFlow.Return(v), execution)
|
||||||
case (.Error(let e), let execution): (ControlFlow.Error, execution.setError(error: e))
|
case (.Error(let e), let execution): (ControlFlow.Error, execution.setError(error: e))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ import TreeSitterP4
|
|||||||
])))
|
])))
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
|
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
@@ -101,7 +101,7 @@ import TreeSitterP4
|
|||||||
])))
|
])))
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
|
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
|
||||||
@@ -128,7 +128,7 @@ import TreeSitterP4
|
|||||||
])))
|
])))
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
|
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
@@ -155,7 +155,7 @@ import TreeSitterP4
|
|||||||
])))
|
])))
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
|
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
@@ -187,7 +187,7 @@ import TreeSitterP4
|
|||||||
|
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
|
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
@@ -216,7 +216,7 @@ import TreeSitterP4
|
|||||||
])))
|
])))
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
|
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
@@ -249,7 +249,7 @@ import TreeSitterP4
|
|||||||
|
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
|
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
|
|||||||
@@ -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"))
|
||||||
|
}
|
||||||
@@ -57,7 +57,7 @@ import TreeSitterP4
|
|||||||
|
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
}
|
}
|
||||||
@@ -151,7 +151,7 @@ import TreeSitterP4
|
|||||||
|
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
|
||||||
}
|
}
|
||||||
@@ -186,7 +186,7 @@ import TreeSitterP4
|
|||||||
|
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
}
|
}
|
||||||
@@ -220,7 +220,7 @@ import TreeSitterP4
|
|||||||
|
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ import TreeSitterP4
|
|||||||
])))
|
])))
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
}
|
}
|
||||||
@@ -302,7 +302,7 @@ import TreeSitterP4
|
|||||||
|
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
}
|
}
|
||||||
@@ -375,7 +375,7 @@ import TreeSitterP4
|
|||||||
])))
|
])))
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
}
|
}
|
||||||
@@ -423,7 +423,7 @@ import TreeSitterP4
|
|||||||
])))
|
])))
|
||||||
let program = try #UseOkResult(
|
let program = try #UseOkResult(
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_declarations))
|
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())
|
let (state_result, _) = try! #UseOkResult(runtime.run())
|
||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,10 +35,15 @@ struct StringConvertible: CustomStringConvertible {
|
|||||||
|
|
||||||
@Test func test_result_type_description_not_convertible() async throws {
|
@Test func test_result_type_description_not_convertible() async throws {
|
||||||
let result: Result<NotStringConvertible> = Result.Ok(NotStringConvertible());
|
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 {
|
@Test func test_result_type_description_convertible() async throws {
|
||||||
let result: Result<StringConvertible> = Result.Ok(StringConvertible());
|
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")
|
||||||
}
|
}
|
||||||
@@ -111,8 +111,7 @@ export default grammar({
|
|||||||
|
|
||||||
// Parser statements
|
// Parser statements
|
||||||
parserStatements: $ => repeat1($.parserStatement),
|
parserStatements: $ => repeat1($.parserStatement),
|
||||||
parserStatement: $ => choice($.conditionalStatement, $.parserBlockStatement, $.expressionStatement, $.assignmentStatement, $.variableDeclaration), // Limited, so far.
|
parserStatement: $ => choice($.conditionalStatement, $.expressionStatement, $.assignmentStatement, $.variableDeclaration), // Limited, so far.
|
||||||
parserBlockStatement: $ => seq(optional($.annotations), '{', $.parserStatements, '}'),
|
|
||||||
parserTransitionStatement: $ => seq($.transition, $.transitionSelectionExpression, $._semicolon),
|
parserTransitionStatement: $ => seq($.transition, $.transitionSelectionExpression, $._semicolon),
|
||||||
|
|
||||||
// Expressions
|
// Expressions
|
||||||
|
|||||||
Reference in New Issue
Block a user