Support Calling Parsers With Parameters
Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
@@ -96,6 +96,12 @@ public enum Result<OKT>: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func ok() -> Bool {
|
||||||
|
switch self {
|
||||||
|
case .Ok(_): true
|
||||||
|
case .Error(_): false
|
||||||
|
}
|
||||||
|
}
|
||||||
public func error() -> Error? {
|
public func error() -> Error? {
|
||||||
if case Result.Error(let e) = self {
|
if case Result.Error(let e) = self {
|
||||||
return e
|
return e
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ extension P4Lang.Parser: CompilableDeclaration {
|
|||||||
var parser_name: Common.Identifier? = .none
|
var parser_name: Common.Identifier? = .none
|
||||||
|
|
||||||
// Assume that the parameter list is empty!
|
// Assume that the parameter list is empty!
|
||||||
var parameter_list: ParameterList = ParameterList([])
|
var parameter_list = ParameterList()
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Parse the parser type (type_node)
|
// Parse the parser type (type_node)
|
||||||
@@ -207,23 +207,14 @@ extension P4Lang.Parser: CompilableDeclaration {
|
|||||||
return .Error(e)
|
return .Error(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, see if there are any parameters
|
|
||||||
currentChildIdx += 1
|
|
||||||
currentChildIdxSafe += 1
|
|
||||||
if currentChildIdxSafe < type_node!.childCount {
|
|
||||||
|
|
||||||
// There is something that _should_ be parameters!
|
|
||||||
|
|
||||||
// skip the '('
|
|
||||||
currentChildIdx += 1
|
currentChildIdx += 1
|
||||||
currentChildIdxSafe += 1
|
currentChildIdxSafe += 1
|
||||||
if type_node!.childCount < currentChildIdxSafe {
|
if type_node!.childCount < currentChildIdxSafe {
|
||||||
return .Error(
|
return .Error(
|
||||||
ErrorOnNode(node: currentChild!, withError: "Missing ( before parameter list"))
|
ErrorOnNode(node: type_node!, withError: "Missing parser parameters"))
|
||||||
}
|
}
|
||||||
|
|
||||||
currentChild = type_node?.child(at: currentChildIdx)
|
currentChild = type_node?.child(at: currentChildIdx)
|
||||||
|
|
||||||
switch ParameterList.Compile(node: currentChild!, withContext: current_context) {
|
switch ParameterList.Compile(node: currentChild!, withContext: current_context) {
|
||||||
case .Ok(let (parsed_parameter_list, updated_context)):
|
case .Ok(let (parsed_parameter_list, updated_context)):
|
||||||
parameter_list = parsed_parameter_list
|
parameter_list = parsed_parameter_list
|
||||||
@@ -232,6 +223,12 @@ extension P4Lang.Parser: CompilableDeclaration {
|
|||||||
return .Error(e)
|
return .Error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now, let's put the parameters into scope.
|
||||||
|
for parameter in parameter_list.parameters {
|
||||||
|
current_context = current_context.update(
|
||||||
|
newInstances: current_context.instances.declare(
|
||||||
|
identifier: parameter.name, withValue: parameter.type))
|
||||||
}
|
}
|
||||||
|
|
||||||
currentChildIdx += 1
|
currentChildIdx += 1
|
||||||
@@ -281,53 +278,51 @@ extension P4Lang.Parser: CompilableDeclaration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ParameterList: Compilable {
|
func parameter_list_compiler(
|
||||||
public typealias T = ParameterList
|
|
||||||
public static func Compile(
|
|
||||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||||
) -> Common.Result<(ParameterList, CompilerContext)> {
|
) -> Common.Result<(ParameterList, CompilerContext)> {
|
||||||
|
|
||||||
|
var currentChildIdx = 0
|
||||||
|
var currentChildIdxSafe = 1
|
||||||
|
var currentChild: Node? = .none
|
||||||
|
|
||||||
if node.text == ")" {
|
if node.text == ")" {
|
||||||
// There are no parameters!
|
// There are no parameters!
|
||||||
return .Ok((ParameterList([]), context))
|
return Result.Ok((ParameterList([]), context))
|
||||||
}
|
}
|
||||||
|
|
||||||
#RequireNodeType<Node, (ParameterList, CompilerContext)>(
|
#RequireNodeType<Node, (ParameterList, CompilerContext)>(
|
||||||
node: node, type: "parameter_list", nice_type_name: "Parameter List")
|
node: node, type: "parameter_list", nice_type_name: "Parameter List")
|
||||||
|
|
||||||
var currentChildIdx = 0
|
|
||||||
var currentChildIdxSafe = 1
|
|
||||||
var currentChild: Node? = .none
|
|
||||||
var parameters: ParameterList = ParameterList([])
|
var parameters: ParameterList = ParameterList([])
|
||||||
|
|
||||||
if node.childCount < currentChildIdxSafe {
|
if node.childCount < currentChildIdxSafe {
|
||||||
return .Error(
|
return Result.Error(
|
||||||
ErrorOnNode(node: node, withError: "Missing parameter list component"))
|
ErrorOnNode(node: node, withError: "Missing parameter list component"))
|
||||||
}
|
}
|
||||||
|
|
||||||
currentChild = node.child(at: currentChildIdx)
|
currentChild = node.child(at: currentChildIdx)
|
||||||
if currentChild?.nodeType == "parameter_list" {
|
if currentChild?.nodeType == "parameter_list" {
|
||||||
switch ParameterList.Compile(node: currentChild!, withContext: context) {
|
switch parameter_list_compiler(node: currentChild!, withContext: context) {
|
||||||
case .Ok(let (ps, _)):
|
case .Ok(let (ps, _)):
|
||||||
parameters = ps
|
parameters = ps
|
||||||
case .Error(let e): return .Error(e)
|
case .Error(let e): return Result.Error(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
print("Back here!")
|
|
||||||
currentChildIdx += 1
|
currentChildIdx += 1
|
||||||
currentChildIdxSafe += 1
|
currentChildIdxSafe += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// We may have moved nodes, check/reset currentChild.
|
// We may have moved nodes, check/reset currentChild.
|
||||||
if node.childCount < currentChildIdxSafe {
|
if node.childCount < currentChildIdxSafe {
|
||||||
return .Error(
|
return Result.Error(
|
||||||
ErrorOnNode(node: node, withError: "Missing parameter list component"))
|
ErrorOnNode(node: node, withError: "Missing parameter list component"))
|
||||||
}
|
}
|
||||||
currentChild = node.child(at: currentChildIdx)
|
currentChild = node.child(at: currentChildIdx)
|
||||||
|
|
||||||
// If this is a ')', we are done.
|
// If this is a ')', we are done.
|
||||||
if currentChild?.text == ")" {
|
if currentChild?.text == ")" {
|
||||||
return .Ok((parameters, context))
|
return Result.Ok((parameters, context))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a comma, we skip it!
|
// If this is a comma, we skip it!
|
||||||
@@ -337,7 +332,7 @@ extension ParameterList: Compilable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if node.childCount < currentChildIdxSafe {
|
if node.childCount < currentChildIdxSafe {
|
||||||
return .Error(
|
return Result.Error(
|
||||||
ErrorOnNode(node: node, withError: "Missing parameter list component"))
|
ErrorOnNode(node: node, withError: "Missing parameter list component"))
|
||||||
}
|
}
|
||||||
currentChild = node.child(at: currentChildIdx)
|
currentChild = node.child(at: currentChildIdx)
|
||||||
@@ -345,10 +340,40 @@ extension ParameterList: Compilable {
|
|||||||
// Otherwise, there should be one parameter left!
|
// Otherwise, there should be one parameter left!
|
||||||
switch Parameter.Compile(node: currentChild!, withContext: context) {
|
switch Parameter.Compile(node: currentChild!, withContext: context) {
|
||||||
case .Ok(let (vds, updated_context)):
|
case .Ok(let (vds, updated_context)):
|
||||||
return .Ok((parameters.addParameter(vds), updated_context))
|
return Result.Ok((parameters.addParameter(vds), updated_context))
|
||||||
case .Error(let e): return .Error(e)
|
case .Error(let e): return Result.Error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ParameterList: Compilable {
|
||||||
|
public typealias T = ParameterList
|
||||||
|
public static func Compile(
|
||||||
|
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||||
|
) -> Common.Result<(ParameterList, CompilerContext)> {
|
||||||
|
|
||||||
|
let parameter_node = node
|
||||||
|
#RequireNodeType<Node, (ParameterList, CompilerContext)>(
|
||||||
|
node: parameter_node, type: "parameters", nice_type_name: "Parameters")
|
||||||
|
|
||||||
|
var currentChildIdx = 0
|
||||||
|
var currentChildIdxSafe = 1
|
||||||
|
|
||||||
|
// Let's eat the '(' before we start ...
|
||||||
|
if parameter_node.childCount < currentChildIdxSafe {
|
||||||
|
return .Error(
|
||||||
|
ErrorOnNode(node: parameter_node, withError: "Missing '(' in parameter list component"))
|
||||||
|
}
|
||||||
|
|
||||||
|
currentChildIdx += 1
|
||||||
|
currentChildIdxSafe += 1
|
||||||
|
if parameter_node.childCount < currentChildIdxSafe {
|
||||||
|
return .Error(
|
||||||
|
ErrorOnNode(node: parameter_node, withError: "Missing parameter list component"))
|
||||||
|
}
|
||||||
|
let currentChild = parameter_node.child(at: currentChildIdx)
|
||||||
|
|
||||||
|
return parameter_list_compiler(node: currentChild!, withContext: context)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Parameter: Compilable {
|
extension Parameter: Compilable {
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ public struct Parameter: CustomStringConvertible {
|
|||||||
public struct ParameterList: CustomStringConvertible {
|
public struct ParameterList: CustomStringConvertible {
|
||||||
public var parameters: [Parameter]
|
public var parameters: [Parameter]
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
self.parameters = Array()
|
||||||
|
}
|
||||||
|
|
||||||
public init(_ parameters: [Parameter]) {
|
public init(_ parameters: [Parameter]) {
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,3 +200,34 @@ public struct FieldAccessExpression {
|
|||||||
self.field = field
|
self.field = field
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct ArgumentList {
|
||||||
|
public let arguments: [(Int, EvaluatableExpression)]
|
||||||
|
public init(_ arguments: [EvaluatableExpression]) {
|
||||||
|
self.arguments = zip(1..., arguments).map { (idx, argument) in
|
||||||
|
(idx, argument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func compatible(_ parameters: ParameterList) -> Result<()> {
|
||||||
|
if self.arguments.count != parameters.parameters.count {
|
||||||
|
return .Error(
|
||||||
|
Error(
|
||||||
|
withMessage:
|
||||||
|
"\(self.arguments.count) arguments found but \(parameters.parameters.count) required"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (arg, param) in zip(self.arguments, parameters.parameters) {
|
||||||
|
let arg_index = arg.0
|
||||||
|
let arg_type = arg.1.type()
|
||||||
|
if !arg_type.eq(rhs: param.type) {
|
||||||
|
return .Error(
|
||||||
|
Error(
|
||||||
|
withMessage:
|
||||||
|
"Argument \(arg_index)'s type (\(arg_type)) is incompatible with the parameter type (\(param.type))"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -319,10 +319,11 @@ public struct Parser: P4Type, P4Value {
|
|||||||
public var states: ParserStates
|
public var states: ParserStates
|
||||||
|
|
||||||
public var name: Identifier
|
public var name: Identifier
|
||||||
public var parameters: ParameterList?
|
public var parameters: ParameterList
|
||||||
|
|
||||||
public init(withName name: Identifier) {
|
public init(withName name: Identifier) {
|
||||||
self.states = ParserStates()
|
self.states = ParserStates()
|
||||||
|
self.parameters = ParameterList()
|
||||||
self.name = name
|
self.name = name
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +350,6 @@ public struct Parser: P4Type, P4Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public var description: String {
|
public var description: String {
|
||||||
let parameters = self.parameters?.description ?? "N/A"
|
|
||||||
return "Parser \(self.name) with parameters: \(parameters) and states: \(self.states)"
|
return "Parser \(self.name) with parameters: \(parameters) and states: \(self.states)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,8 +117,11 @@ extension ParserStateSelectTransition: EvaluatableParserState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Parser: ParserExecution {
|
extension Parser: CallableExecution {
|
||||||
public func execute(execution: ProgramExecution) -> (InstantiatedParserState, ProgramExecution) {
|
public typealias T = InstantiatedParserState
|
||||||
|
public func call(
|
||||||
|
execution: Common.ProgramExecution, arguments: P4Lang.ArgumentList
|
||||||
|
) -> (P4Lang.InstantiatedParserState, Common.ProgramExecution) {
|
||||||
var execution = execution.enter_scope()
|
var execution = execution.enter_scope()
|
||||||
|
|
||||||
execution = execution.declare(
|
execution = execution.declare(
|
||||||
@@ -146,10 +149,34 @@ extension Parser: ParserExecution {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that we are assured that there is a start state,
|
||||||
|
// let's set the arguments.
|
||||||
|
|
||||||
|
if case .Error(let e) = arguments.compatible(self.parameters) {
|
||||||
|
return (
|
||||||
|
reject, execution.setError(error: Error(withMessage: "Cannot call parser: \(e)"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (parameter, argument) in zip(self.parameters.parameters, arguments.arguments) {
|
||||||
|
let arg_idx = argument.0
|
||||||
|
let arg_value = argument.1
|
||||||
|
let maybe_argument_value = arg_value.evaluate(execution: execution)
|
||||||
|
guard case .Ok(let argument_value) = maybe_argument_value else {
|
||||||
|
return (
|
||||||
|
reject,
|
||||||
|
execution.setError(
|
||||||
|
error: Error(withMessage: "Cannot evaluate argument \(arg_idx): \(argument)"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
execution = execution.declare(identifier: parameter.name, withValue: argument_value)
|
||||||
|
}
|
||||||
|
|
||||||
// Evaluate until the state is either accept or reject.
|
// Evaluate until the state is either accept or reject.
|
||||||
while !current_state.done() && !execution.hasError() {
|
while !current_state.done() && !execution.hasError() {
|
||||||
(current_state, execution) = current_state.execute(program: execution)
|
(current_state, execution) = current_state.execute(program: execution)
|
||||||
}
|
}
|
||||||
return (AsInstantiatedParserState(current_state.state()), execution)
|
|
||||||
|
return (AsInstantiatedParserState(current_state.state()), execution.exit_scope())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public protocol EvaluatableParserState: P4Value {
|
|||||||
func state() -> ParserState
|
func state() -> ParserState
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol ParserExecution {
|
public protocol CallableExecution<T> {
|
||||||
func execute(execution: ProgramExecution) -> (InstantiatedParserState, ProgramExecution)
|
associatedtype T
|
||||||
|
func call(execution: ProgramExecution, arguments: ArgumentList) -> (T, ProgramExecution)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,14 @@ public struct ParserRuntime: CustomStringConvertible {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the P4 parser on a given packet
|
/// Run a P4 parser with no arguments
|
||||||
public func run() -> Result<(ParserState, ProgramExecution)> {
|
public func run() -> Result<(ParserState, ProgramExecution)> {
|
||||||
|
return self.run(withArguments: ArgumentList([]))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the P4 parser on a given packet
|
||||||
|
public func run(withArguments arguments: ArgumentList) -> Result<(ParserState, ProgramExecution)>
|
||||||
|
{
|
||||||
|
|
||||||
let pe =
|
let pe =
|
||||||
if let initial = initialValues {
|
if let initial = initialValues {
|
||||||
@@ -59,7 +65,7 @@ public struct ParserRuntime: CustomStringConvertible {
|
|||||||
ProgramExecution()
|
ProgramExecution()
|
||||||
}
|
}
|
||||||
|
|
||||||
let (end_state, execution) = parser.execute(execution: pe)
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,3 +160,45 @@ import TreeSitterP4
|
|||||||
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func test_select_expression_from_parser_parameters() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
parser main_parser(bool pmtr, string smtr, int imtr) {
|
||||||
|
state start {
|
||||||
|
transition select (pmtr) {
|
||||||
|
true: accept;
|
||||||
|
false: reject;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
let program = try #UseOkResult(Program.Compile(simple_parser_declaration))
|
||||||
|
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program))
|
||||||
|
|
||||||
|
let args = ArgumentList([
|
||||||
|
P4BooleanValue(withValue: false), P4StringValue(withValue: "Testing"), P4IntValue(withValue: 5),
|
||||||
|
])
|
||||||
|
let (state_result, _) = try! #UseOkResult(runtime.run(withArguments: args))
|
||||||
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.reject)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func test_select_expression_from_parser_parameters2() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
parser main_parser(bool pmtr, string smtr, int imtr) {
|
||||||
|
state start {
|
||||||
|
transition select (imtr == 5) {
|
||||||
|
true: accept;
|
||||||
|
false: reject;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
let program = try #UseOkResult(Program.Compile(simple_parser_declaration))
|
||||||
|
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program))
|
||||||
|
|
||||||
|
let args = ArgumentList([
|
||||||
|
P4BooleanValue(withValue: false), P4StringValue(withValue: "Testing"), P4IntValue(withValue: 5),
|
||||||
|
])
|
||||||
|
let (state_result, _) = try! #UseOkResult(runtime.run(withArguments: args))
|
||||||
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
|
}
|
||||||
@@ -169,3 +169,16 @@ import P4Lang
|
|||||||
#expect(parameters.parameters[2].name == Identifier(name: "imtr"))
|
#expect(parameters.parameters[2].name == Identifier(name: "imtr"))
|
||||||
#expect(parameters.parameters[2].type.eq(rhs: P4Int()))
|
#expect(parameters.parameters[2].type.eq(rhs: P4Int()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_compiler_parser_use_parameters() async throws {
|
||||||
|
let simple = """
|
||||||
|
parser main_parser(bool pmtr, string smtr, int imtr) {
|
||||||
|
state start {
|
||||||
|
pmtr = true;
|
||||||
|
transition accept;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
|
||||||
|
#expect(#RequireOkResult(Program.Compile(simple)))
|
||||||
|
}
|
||||||
|
|||||||
@@ -80,3 +80,94 @@ import TreeSitterP4
|
|||||||
Error(withMessage: "Could not find the start state"),
|
Error(withMessage: "Could not find the start state"),
|
||||||
runtime.run()))
|
runtime.run()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_runtime_parser_with_parameters() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
parser main_parser(bool pmtr, string smtr, int imtr) {
|
||||||
|
state start {
|
||||||
|
transition select (pmtr) {
|
||||||
|
true: accept;
|
||||||
|
false: reject;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
let program = try #UseOkResult(Program.Compile(simple_parser_declaration))
|
||||||
|
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program))
|
||||||
|
|
||||||
|
let args = ArgumentList([
|
||||||
|
P4BooleanValue(withValue: true), P4StringValue(withValue: "Testing"), P4IntValue(withValue: 5),
|
||||||
|
])
|
||||||
|
let (state_result, _) = try! #UseOkResult(runtime.run(withArguments: args))
|
||||||
|
// We should be in the accept state.
|
||||||
|
#expect(AsInstantiatedParserState(state_result) == P4Lang.accept)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_runtime_parser_with_mismatched_parameter_types() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
parser main_parser(bool pmtr, string smtr, int imtr) {
|
||||||
|
state start {
|
||||||
|
transition select (pmtr) {
|
||||||
|
true: accept;
|
||||||
|
false: reject;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
let program = try #UseOkResult(Program.Compile(simple_parser_declaration))
|
||||||
|
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program))
|
||||||
|
|
||||||
|
let args = ArgumentList([
|
||||||
|
P4BooleanValue(withValue: true), P4BooleanValue(withValue: false), P4IntValue(withValue: 5),
|
||||||
|
])
|
||||||
|
|
||||||
|
#expect(
|
||||||
|
#RequireErrorResult<(ParserState, ProgramExecution)>(
|
||||||
|
Error(withMessage: "Cannot call parser: Argument 2's type (Boolean) is incompatible with the parameter type (String)"),
|
||||||
|
runtime.run(withArguments: args)))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_runtime_parser_with_mismatched_parameter_types2() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
parser main_parser(bool pmtr, string smtr, int imtr) {
|
||||||
|
state start {
|
||||||
|
transition select (pmtr) {
|
||||||
|
true: accept;
|
||||||
|
false: reject;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
let program = try #UseOkResult(Program.Compile(simple_parser_declaration))
|
||||||
|
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program))
|
||||||
|
|
||||||
|
let args = ArgumentList([
|
||||||
|
P4IntValue(withValue: 5), P4StringValue(withValue: "Testing"), P4IntValue(withValue: 5),
|
||||||
|
])
|
||||||
|
|
||||||
|
#expect(
|
||||||
|
#RequireErrorResult<(ParserState, ProgramExecution)>(
|
||||||
|
Error(withMessage: "Cannot call parser: Argument 1's type (Int) is incompatible with the parameter type (Boolean)"),
|
||||||
|
runtime.run(withArguments: args)))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_runtime_parser_with_mismatched_parameter_counts() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
parser main_parser(bool pmtr, string smtr, int imtr) {
|
||||||
|
state start {
|
||||||
|
transition select (pmtr) {
|
||||||
|
true: accept;
|
||||||
|
false: reject;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
let program = try #UseOkResult(Program.Compile(simple_parser_declaration))
|
||||||
|
let runtime = try #UseOkResult(P4Runtime.ParserRuntime.create(program: program))
|
||||||
|
let args = ArgumentList([P4BooleanValue(withValue: true)])
|
||||||
|
|
||||||
|
#expect(
|
||||||
|
#RequireErrorResult<(ParserState, ProgramExecution)>(
|
||||||
|
Error(withMessage: "Cannot call parser: 1 arguments found but 3 required"),
|
||||||
|
runtime.run(withArguments: args)))
|
||||||
|
}
|
||||||
|
|||||||
@@ -262,3 +262,20 @@ import TreeSitterP4
|
|||||||
),
|
),
|
||||||
Program.Compile(simple_parser_declaration, withGlobalInstances: test_types)))
|
Program.Compile(simple_parser_declaration, withGlobalInstances: test_types)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test func test_simple_compiler_parser_parameters_invalid_types() async throws {
|
||||||
|
let simple_parser_declaration = """
|
||||||
|
parser main_parser(bool pmtr, string smtr, int imtr) {
|
||||||
|
state start {
|
||||||
|
pmtr = 1;
|
||||||
|
transition accept;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
#expect(
|
||||||
|
#RequireErrorResult(
|
||||||
|
Error(
|
||||||
|
withMessage: "{85, 9}: Failed to parse a statement element: {85, 4}: Cannot assign value with type Int to identifier pmtr with type Boolean"
|
||||||
|
),
|
||||||
|
Program.Compile(simple_parser_declaration)))
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user