compiler, runtime: Begin Runtime Refactor
Continuous Integration / Grammar Tests (push) Failing after 39s
Continuous Integration / Library Format Tests (push) Successful in 1m46s
Continuous Integration / Library Tests (push) Successful in 4m38s

Ultimately, the goal is to completely separate the compilation from
the runtime to make it possible to have the interpreter/evaluator
be "just another" entity that can perform meaningful work when
given a parsed GP4 program.

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-05-29 08:41:49 -04:00
parent 18461a9215
commit 44e93e4cda
30 changed files with 1264 additions and 854 deletions
+3 -3
View File
@@ -42,7 +42,7 @@ public struct Parameter: CustomStringConvertible, Equatable {
if let param_direction = self.type.direction(),
param_direction == Direction.In || param_direction == Direction.InOut
{
if !(argument.argument is EvaluatableLValueExpression) {
if !(argument.argument is P4LValueExpression) {
return false
}
}
@@ -125,9 +125,9 @@ public struct ArgumentList {
public struct Argument {
public let index: Int
public let argument: EvaluatableExpression
public let argument: P4Expression
public init(_ argument: EvaluatableExpression, atIndex index: Int) {
public init(_ argument: P4Expression, atIndex index: Int) {
self.argument = argument
self.index = index
}
+121
View File
@@ -26,3 +26,124 @@ public typealias TypeTypeScope = Scope<P4Type>
/// Scopes that resolve type identifiers to their types.
public typealias TypeTypeScopes = Scopes<P4Type>
/// Context for compilation
///
/// It contains (at least) three important pieces of information:
/// 1. Instances: A ``VarTypeScopes`` that contains information about instantiated objects
/// (and their types) in scope
/// 1. Types: A ``TypeTypeScopes`` that contains information about declared types in scope.
/// 1. Expected Type: In certain situations, to typecheck an element of a P4 program requires
/// knowledge of an expected type. For instance, when compiling a return statement, the
/// compiler must know the return type of the function to type check.
public struct CompilerContext {
public let instances: StaticVarValueScopes
public let types: TypeTypeScopes
public let externs: TypeTypeScopes
public let ffis: [P4FFI]
public let expected_type: P4QualifiedType?
public let extern_context: Bool
public init() {
instances = StaticVarValueScopes().enter()
types = TypeTypeScopes().enter()
externs = TypeTypeScopes().enter()
expected_type = .none
extern_context = false
ffis = Array()
}
public init(withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes) {
instances = _instances
types = _types
externs = TypeTypeScopes().enter()
expected_type = .none
extern_context = false
ffis = Array()
}
public init(
withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes,
withExpectation expectation: P4QualifiedType?, withExtern extern: Bool,
withExterns externs: TypeTypeScopes, withFFIs foreigns: [P4FFI]
) {
instances = _instances
types = _types
expected_type = expectation
extern_context = extern
self.externs = externs
ffis = foreigns
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new instances.
///
/// - Parameter instances: a ``VarTypeScopes`` with the updated instances for the newly created compiler context.
/// - Returns: A new compiler context based on the current but new instances.
public func update(newInstances instances: StaticVarValueScopes) -> CompilerContext {
return CompilerContext(
withInstances: instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new types.
///
/// - Parameter types: a ``TypeTypeScopes`` with the updated types for the newly created compiler context.
/// - Returns: A new compiler context based on the current but new types.
public func update(newTypes types: TypeTypeScopes) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new expected type.
///
/// - Parameter expectation: a ``P4Type?`` to (re)set the type the compiler is expecting.
/// - Returns: A new compiler context based on the current but new expected type.
public func update(newExpectation expectation: P4QualifiedType?) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: expectation,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new extern context value.
///
/// - Parameter extern: a ``Bool`` to (re)set whether the compiler is compiling in an extern context.
/// - Returns: A new compiler context based on the current but new extern context value.
public func update(newExtern extern: Bool) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: extern, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new externs.
///
/// - Parameter externs: a ``TypeTypeScopes`` to (re)set the list of extern-al declarations.
/// - Returns: A new compiler context based on the current but new list of external-al declarations.
public func update(newExterns externs: TypeTypeScopes) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new FFIs.
///
/// - Parameter foreigns: an array of ``P4FFI`` to (re)set the list of foreign functions.
/// - Returns: A new compiler context based on the current but with a new list of foreign functions.
public func update(newFFIs foreigns: [P4FFI]) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: foreigns)
}
}
+13 -1
View File
@@ -109,6 +109,18 @@ public struct InterloperEvaluator: ProgramExecutionEvaluator {
return CanonicalExecuteStatements(statements, inExecution: execution) { statement, execution in
let (cf, value) = statement.evaluate(execution: execution)
let (handled_cf, handled_value) =
if let handler = handler {
handler(cf, value)
} else {
(cf, value)
}
if hasDebugInterloper {
debugger!(statement, handled_cf, handled_value)
}
return (handled_cf, handled_value)
/*
let (handled_cf, handled_value) =
if let handler = handler {
handler(cf, value)
@@ -119,7 +131,7 @@ public struct InterloperEvaluator: ProgramExecutionEvaluator {
if hasDebugInterloper {
debugger!(statement, handled_cf, handled_value)
}
return (handled_cf, handled_value)
*/
}
}
+65 -41
View File
@@ -15,28 +15,16 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
public protocol EvaluatableExpression {
/// Evaluate an expression for a given execution
/// - Parameters
/// - execution: The execution context in which to evaluate the expression
/// - Returns: The value of expression
func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution)
func type() -> P4QualifiedType
}
public protocol EvaluatableStatement {
/// Evaluate a statement for a given execution
/// - Parameters
/// - execution: The execution context in which to evaluate the parser statement
/// - Returns: A tuple of
/// 1. Whether this statement affects control flow.
/// 2. An updated execution after evaluating the parser statement
func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution)
}
public protocol P4Type: CustomStringConvertible {
func eq(rhs: any P4Type) -> Bool
func def() -> P4DataValue?
func instantiable() -> Bool
}
extension P4Type {
public func instantiable() -> Bool {
return false
}
}
public protocol P4DataValue: CustomStringConvertible {
@@ -48,28 +36,6 @@ public protocol P4DataValue: CustomStringConvertible {
func gte(rhs: P4DataValue) -> Bool
}
public protocol EvaluatableLValueExpression: EvaluatableExpression {
func set(
to: P4Value, inScopes scopes: VarValueScopes, duringExecution execution: ProgramExecution
) -> Result<(VarValueScopes, P4Value)>
func check(to: EvaluatableExpression, inScopes scopes: StaticVarValueScopes) -> Result<()>
}
public protocol ProgramExecutionEvaluator {
func ExecuteStatements(
_ statements: [EvaluatableStatement], inExecution execution: ProgramExecution,
_ handler: ExecuteStatementResultHandlerT?
) -> (ControlFlow, ProgramExecution)
func ExecuteStatements(
_ statements: [EvaluatableStatement], inExecution execution: ProgramExecution
) -> (ControlFlow, ProgramExecution)
func EvaluateExpression(
_ expression: EvaluatableExpression, inExecution execution: ProgramExecution,
) -> (Result<P4Value>, ProgramExecution)
}
public protocol Errorable: CustomStringConvertible {
func format(_ formatter: Formattable) -> String
func format(_ formatter: Formattable, _ sc: SourceCode) -> String
@@ -91,6 +57,64 @@ public protocol Formattable {
func formatWithStyle(_ value: String, _ style: Style) -> String
}
public protocol P4Statement {
/// Evaluate a statement for a given execution
/// - Parameters
/// - execution: The execution context in which to evaluate the parser statement
/// - Returns: A tuple of
/// 1. Whether this statement affects control flow.
/// 2. An updated execution after evaluating the parser statement
func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution)
func effect(context: CompilerContext) -> CompilerContext
}
public protocol P4Expression {
func effect(context: CompilerContext) -> CompilerContext
func type() -> P4QualifiedType
/// Evaluate an expression for a given execution
/// - Parameters
/// - execution: The execution context in which to evaluate the expression
/// - Returns: The value of expression
func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution)
}
extension P4Expression {
func effect(context: CompilerContext) -> CompilerContext {
return context
}
}
public protocol P4LValueExpression {
func effect(context: CompilerContext) -> CompilerContext
func type() -> P4QualifiedType
func check(to: P4Expression, inScopes scopes: StaticVarValueScopes) -> Result<()>
func set(
to: P4Value, inScopes scopes: VarValueScopes, duringExecution execution: ProgramExecution
) -> Result<(VarValueScopes, P4Value)>
}
/// TODO: Only generate these after going through the codegen!
public typealias EvaluatableStatement = P4Statement
public typealias EvaluatableLValueExpression = P4LValueExpression
public typealias EvaluatableExpression = P4Expression
public protocol ProgramExecutionEvaluator {
func ExecuteStatements(
_ statements: [EvaluatableStatement], inExecution execution: ProgramExecution,
_ handler: ExecuteStatementResultHandlerT?
) -> (ControlFlow, ProgramExecution)
func ExecuteStatements(
_ statements: [EvaluatableStatement], inExecution execution: ProgramExecution
) -> (ControlFlow, ProgramExecution)
func EvaluateExpression(
_ expression: EvaluatableExpression, inExecution execution: ProgramExecution,
) -> (Result<P4Value>, ProgramExecution)
}
extension ProgramExecutionEvaluator {
public func ExecuteStatements(
_ statements: [EvaluatableStatement], inExecution execution: ProgramExecution
+3
View File
@@ -106,3 +106,6 @@ public func Fold<T, A>(input: [T], initial: A, block: (T, A) -> A) -> A {
@freestanding(codeItem) public macro MustOr<E, N>(result: E, thing: E?, or: N) =
#externalMacro(module: "Macros", type: "MustOr")
@attached(peer) public macro DeriveCompilableStatement() =
#externalMacro(module: "Macros", type: "DeriveCompilableStatement")
+26 -1
View File
@@ -439,11 +439,36 @@ public struct CliTestDeclarationMacro: PeerMacro, Sendable {
}
}
public struct DeriveCompilableStatement: PeerMacro, Sendable {
public static func expansion(
of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
let type_name = declaration.cast(ExtensionDeclSyntax.self).extendedType
let implementation = DeclSyntax(
"""
extension VariableDeclarationStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
""")
return [implementation]
}
}
@main
struct P4Macros: CompilerPlugin {
var providingMacros: [Macro.Type] = [
RequireResult.self, RequireErrorResult.self, UseOkResult.self, UseErrorResult.self,
RequireNodeType.self, SkipUnlessNodeType.self, SkipUnlessNodesTypes.self, RequireNodesType.self,
MustOr.self, CliTestDeclarationMacro.self,
MustOr.self, CliTestDeclarationMacro.self, DeriveCompilableStatement.self,
]
}
+49 -52
View File
@@ -24,30 +24,30 @@ import TreeSitterP4
func parameter_list_compiler(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(ParameterList, CompilerContext)> {
) -> Common.Result<ParameterList> {
var walker = Walker(node: node)
var current_node: Node? = .none
if node.text == ")" {
// There are no parameters!
return Result.Ok((ParameterList([]), context))
return Result.Ok(ParameterList([]))
}
#RequireNodeType<Node, (ParameterList, CompilerContext)>(
#RequireNodeType<Node, ParameterList>(
node: node, type: "parameter_list", nice_type_name: "Parameter List")
var parameters: ParameterList = ParameterList([])
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error(
or: Result<ParameterList>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
if current_node?.nodeType == "parameter_list" {
switch parameter_list_compiler(node: current_node!, withContext: context) {
case .Ok(let (ps, _)):
case .Ok(let ps):
parameters = ps
case .Error(let e): return Result.Error(e)
}
@@ -56,13 +56,13 @@ func parameter_list_compiler(
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error(
or: Result<ParameterList>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
// If this is a ')', we are done.
if current_node?.text == ")" {
return Result.Ok((parameters, context))
return Result.Ok(parameters)
}
// If this is a comma, we skip it!
@@ -72,26 +72,26 @@ func parameter_list_compiler(
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error(
or: Result<ParameterList>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
// Otherwise, there should be one parameter left!
switch Parameter.Compile(node: current_node!, withContext: context) {
case .Ok(let (parsed_parameter, updated_context)):
return Result.Ok((parameters.addParameter(parsed_parameter), updated_context))
case .Ok(let parsed_parameter):
return Result.Ok(parameters.addParameter(parsed_parameter))
case .Error(let e): return Result.Error(e)
}
}
extension ParameterList: Compilable {
public typealias T = ParameterList
public typealias C = ParameterList
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(ParameterList, CompilerContext)> {
) -> Common.Result<ParameterList> {
let parameter_node = node
#RequireNodeType<Node, (ParameterList, CompilerContext)>(
#RequireNodeType<Node, ParameterList>(
node: parameter_node, type: "parameters", nice_type_name: "Parameters")
var walker = Walker(node: parameter_node)
@@ -100,7 +100,7 @@ extension ParameterList: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error(
or: Result<ParameterList>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing '(' in parameter list component")))
@@ -108,7 +108,7 @@ extension ParameterList: Compilable {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ParameterList, CompilerContext)>.Error(
or: Result<ParameterList>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing parameter list component")))
@@ -117,12 +117,12 @@ extension ParameterList: Compilable {
}
extension Direction: Compilable {
public typealias T = Direction
public typealias C = Direction
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(Direction, CompilerContext)> {
) -> Result<Direction> {
let direction_node = node
#RequireNodeType<Node, (Direction, CompilerContext)>(
#RequireNodeType<Node, Direction>(
node: direction_node, type: "direction", nice_type_name: "direction")
let directions = [
"in": Direction.In,
@@ -137,17 +137,17 @@ extension Direction: Compilable {
withError: "\(direction_node.text!) is not a valid direction"))
}
return .Ok((parsed_direction, context))
return .Ok(parsed_direction)
}
}
extension Parameter: Compilable {
public typealias T = Parameter
public typealias C = Parameter
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(Parameter, CompilerContext)> {
) -> Result<Parameter> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
#RequireNodeType<Node, P4Statement>(
node: node, type: "parameter", nice_type_name: "parameter")
var walker = Walker(node: node)
@@ -155,7 +155,7 @@ extension Parameter: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Parameter, CompilerContext)>.Error(
or: Result<Parameter>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing parameter declaration component")))
@@ -171,7 +171,7 @@ extension Parameter: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Parameter, CompilerContext)>.Error(
or: Result<Parameter>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing parameter declaration component")))
@@ -181,7 +181,7 @@ extension Parameter: Compilable {
if current_node!.nodeType == "direction" {
let maybe_parsed_direction = Direction.Compile(node: current_node!, withContext: context)
guard case .Ok((let parsed_direction, _)) = maybe_parsed_direction else {
guard case .Ok(let parsed_direction) = maybe_parsed_direction else {
return .Error(maybe_parsed_direction.error()!)
}
direction = parsed_direction
@@ -191,7 +191,7 @@ extension Parameter: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Parameter, CompilerContext)>.Error(
or: Result<Parameter>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing parameter declaration component")))
@@ -213,7 +213,7 @@ extension Parameter: Compilable {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Parameter, CompilerContext)>.Error(
or: Result<Parameter>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing parameter declaration component")))
@@ -233,43 +233,41 @@ extension Parameter: Compilable {
}
return Result.Ok(
(
Parameter(
identifier: parameter_name,
withType: direction != nil
? parameter_type.update(addAttribute: P4TypeQualifier.Direction(direction!))
: parameter_type),
context
))
)
}
}
func argument_list_compiler(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(ArgumentList, CompilerContext)> {
) -> Common.Result<ArgumentList> {
var walker = Walker(node: node)
var current_node: Node? = .none
if node.text == ")" {
// There are no arguments!
return Result.Ok((ArgumentList([]), context))
return Result.Ok(ArgumentList([]))
}
#RequireNodeType<Node, (ArgumentList, CompilerContext)>(
#RequireNodeType<Node, ArgumentList>(
node: node, type: "argument_list", nice_type_name: "argument List")
var arguments: ArgumentList = ArgumentList([])
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error(
or: Result<ArgumentList>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
if current_node?.nodeType == "argument_list" {
switch argument_list_compiler(node: current_node!, withContext: context) {
case .Ok(let (ps, _)):
case .Ok(let ps):
arguments = ps
case .Error(let e): return Result.Error(e)
}
@@ -280,13 +278,13 @@ func argument_list_compiler(
// We may have moved nodes, check/reset current_node.
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error(
or: Result<ArgumentList>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
// If this is a ')', we are done.
if current_node?.text == ")" {
return Result.Ok((arguments, context))
return Result.Ok(arguments)
}
// If this is a comma, we skip it!
@@ -296,27 +294,27 @@ func argument_list_compiler(
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error(
or: Result<ArgumentList>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
// Otherwise, there should be one argument left!
switch Argument.Compile(node: current_node!, withContext: context) {
case .Ok(let (ce, updated_context)):
case .Ok(let ce):
return Result.Ok(
(arguments.addArgument(Argument(ce, atIndex: arguments.count() + 1)), updated_context))
arguments.addArgument(Argument(ce, atIndex: arguments.count() + 1)))
case .Error(let e): return Result.Error(e)
}
}
extension ArgumentList: Compilable {
public typealias T = ArgumentList
public typealias C = ArgumentList
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(ArgumentList, CompilerContext)> {
) -> Common.Result<ArgumentList> {
let argument_node = node
#RequireNodeType<Node, (ArgumentList, CompilerContext)>(
#RequireNodeType<Node, ArgumentList>(
node: argument_node, type: "arguments", nice_type_name: "arguments")
var walker = Walker(node: argument_node)
@@ -324,7 +322,7 @@ extension ArgumentList: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error(
or: Result<ArgumentList>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing '(' in argument list component")))
@@ -333,7 +331,7 @@ extension ArgumentList: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ArgumentList, CompilerContext)>.Error(
or: Result<ArgumentList>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing argument list component")))
@@ -342,25 +340,25 @@ extension ArgumentList: Compilable {
}
extension Argument: Compilable {
public typealias T = EvaluatableExpression
public typealias C = P4Expression
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(EvaluatableExpression, CompilerContext)> {
) -> Common.Result<P4Expression> {
let argument_node = node
#RequireNodeType<Node, (EvaluatableExpression, CompilerContext)>(
#RequireNodeType<Node, P4Expression>(
node: argument_node, type: "argument", nice_type_name: "argument")
let expression_node = node.child(at: 0)!
return switch Expression.Compile(node: expression_node, withContext: context) {
case .Ok(let compiled_expression): .Ok((compiled_expression, context))
case .Ok(let compiled_expression): .Ok(compiled_expression)
case .Error(let e): .Error(e)
}
}
}
func ContainsInvalidStatements(
statement: EvaluatableStatement, invalids: [EvaluatableStatement.Type]
statement: P4Statement, invalids: [P4Statement.Type]
) -> Bool {
for es in invalids {
if type(of: statement) == es {
@@ -370,8 +368,7 @@ func ContainsInvalidStatements(
return false
}
func ContainsInvalidStatements(block: BlockStatement, invalids: [EvaluatableStatement.Type]) -> Bool
{
func ContainsInvalidStatements(block: BlockStatement, invalids: [P4Statement.Type]) -> Bool {
return block.statements.contains { statement in
for es in invalids {
if type(of: statement) == es {
-121
View File
@@ -34,124 +34,3 @@ public func ConfigureP4Parser() -> Result<SwiftTreeSitter.Parser> {
return .Ok(p)
}
/// Context for compilation
///
/// It contains (at least) three important pieces of information:
/// 1. Instances: A ``VarTypeScopes`` that contains information about instantiated objects
/// (and their types) in scope
/// 1. Types: A ``TypeTypeScopes`` that contains information about declared types in scope.
/// 1. Expected Type: In certain situations, to typecheck an element of a P4 program requires
/// knowledge of an expected type. For instance, when compiling a return statement, the
/// compiler must know the return type of the function to type check.
public struct CompilerContext {
let instances: StaticVarValueScopes
let types: TypeTypeScopes
let externs: TypeTypeScopes
let ffis: [P4FFI]
let expected_type: P4QualifiedType?
let extern_context: Bool
public init() {
instances = StaticVarValueScopes().enter()
types = TypeTypeScopes().enter()
externs = TypeTypeScopes().enter()
expected_type = .none
extern_context = false
ffis = Array()
}
public init(withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes) {
instances = _instances
types = _types
externs = TypeTypeScopes().enter()
expected_type = .none
extern_context = false
ffis = Array()
}
public init(
withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes,
withExpectation expectation: P4QualifiedType?, withExtern extern: Bool,
withExterns externs: TypeTypeScopes, withFFIs foreigns: [P4FFI]
) {
instances = _instances
types = _types
expected_type = expectation
extern_context = extern
self.externs = externs
ffis = foreigns
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new instances.
///
/// - Parameter instances: a ``VarTypeScopes`` with the updated instances for the newly created compiler context.
/// - Returns: A new compiler context based on the current but new instances.
public func update(newInstances instances: StaticVarValueScopes) -> CompilerContext {
return CompilerContext(
withInstances: instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new types.
///
/// - Parameter types: a ``TypeTypeScopes`` with the updated types for the newly created compiler context.
/// - Returns: A new compiler context based on the current but new types.
public func update(newTypes types: TypeTypeScopes) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new expected type.
///
/// - Parameter expectation: a ``P4Type?`` to (re)set the type the compiler is expecting.
/// - Returns: A new compiler context based on the current but new expected type.
public func update(newExpectation expectation: P4QualifiedType?) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: expectation,
withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new extern context value.
///
/// - Parameter extern: a ``Bool`` to (re)set whether the compiler is compiling in an extern context.
/// - Returns: A new compiler context based on the current but new extern context value.
public func update(newExtern extern: Bool) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: extern, withExterns: self.externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new externs.
///
/// - Parameter externs: a ``TypeTypeScopes`` to (re)set the list of extern-al declarations.
/// - Returns: A new compiler context based on the current but new list of external-al declarations.
public func update(newExterns externs: TypeTypeScopes) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis)
}
/// Update a compiler context
///
/// Create a new compiler context based on the current but new FFIs.
///
/// - Parameter foreigns: an array of ``P4FFI`` to (re)set the list of foreign functions.
/// - Returns: A new compiler context based on the current but with a new list of foreign functions.
public func update(newFFIs foreigns: [P4FFI]) -> CompilerContext {
return CompilerContext(
withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type,
withExtern: self.extern_context, withExterns: externs, withFFIs: foreigns)
}
}
+135 -155
View File
@@ -22,33 +22,61 @@ import SwiftTreeSitter
import TreeSitterExtensions
import TreeSitterP4
extension Declaration: CompilableDeclaration {
extension Declaration: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension Declaration: Compilable {
public typealias C = Declaration
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(Declaration, CompilerContext)?> {
) -> Result<Declaration> {
let declaration_compilers: [String: CompilableDeclaration.Type] = [
// Be kind to our user -- if we are at a declaration node, dive into it!
let declaration_node =
if node.nodeType == "declaration" {
node.child(at: 0)!
} else {
node
}
let declaration_compilers: [String: any Compilable<Declaration>.Type] = [
"function_declaration": FunctionDeclaration.self,
"control_declaration": Control.self,
"type_declaration": P4Struct.self,
"parserDeclaration": Parser.self,
/// ASSUME: Type declarations are struct declarations.
"extern_declaration": ExternDeclaration.self,
]
guard let declaration_compiler = declaration_compilers[node.nodeType!] else {
return .Ok(.none)
guard let declaration_compiler = declaration_compilers[declaration_node.nodeType!] else {
return .Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Could not find parser for declaration \(declaration_node.nodeType!)"))
}
return declaration_compiler.Compile(node: node, withContext: context)
return declaration_compiler.Compile(node: declaration_node, withContext: context).map {
result in
.Ok(result)
}
}
}
extension FunctionDeclaration: CompilableDeclaration {
extension FunctionDeclaration: Compilable {
public typealias C = Declaration
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Declaration, CompilerContext)?> {
) -> Common.Result<Declaration> {
let function_declaration_node = node
#RequireNodeType<Node, (ParameterList, CompilerContext)>(
#RequireNodeType<Node, ParameterList>(
node: function_declaration_node, type: "function_declaration",
nice_type_name: "Function Declaration")
@@ -59,7 +87,7 @@ extension FunctionDeclaration: CompilableDeclaration {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: function_declaration_node.toSourceLocation(),
withError: "Missing function declaration component")))
@@ -72,7 +100,7 @@ extension FunctionDeclaration: CompilableDeclaration {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: function_declaration_node.toSourceLocation(),
withError: "Missing function declaration component")))
@@ -85,17 +113,16 @@ extension FunctionDeclaration: CompilableDeclaration {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: function_declaration_node.toSourceLocation(),
withError: "Missing function declaration component")))
let maybe_function_parameters = ParameterList.Compile(node: current_node!, withContext: context)
guard case .Ok((let function_parameters, let updated_context)) = maybe_function_parameters
guard case .Ok(let function_parameters) = maybe_function_parameters
else {
return .Error(maybe_function_parameters.error()!)
}
context = updated_context
var function_body: BlockStatement? = .none
@@ -113,10 +140,10 @@ extension FunctionDeclaration: CompilableDeclaration {
withContext: context.update(newInstances: function_scope).update(
newExpectation: function_type))
guard case .Ok((let parsed_function_body, _)) = maybe_function_body else {
guard case .Ok(let parsed_function_body) = maybe_function_body else {
return .Error(maybe_function_body.error()!)
}
function_body = (parsed_function_body as! BlockStatement)
function_body = parsed_function_body
} else {
// If we are in an extern context, no body is okay!
@@ -142,33 +169,29 @@ extension FunctionDeclaration: CompilableDeclaration {
// And, do not update the context if we are compiling in an
// extern context -- the wrapping extern declaration will take care of that.
return .Ok(
(
function_declaration,
context.extern_context
? context
: context.update(
newTypes: context.types.declare(
identifier: function_name, withValue: function_declaration.identifier.type.baseType())
)
))
}
}
extension P4Struct: CompilableDeclaration {
extension P4Struct: Compilable {
public typealias C = Declaration
static public func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(Declaration, CompilerContext)?> {
) -> Result<Declaration> {
let struct_declaration_node = node.child(at: 0)!
var walker = Walker(node: struct_declaration_node)
var currentNode: Node? = .none
#SkipUnlessNodeType(node: struct_declaration_node, type: "struct_declaration")
#RequireNodeType<Node, Result<Declaration>>(
node: struct_declaration_node, type: "struct_declaration",
nice_type_name: "struct declaration")
// Skip the keyword struct
walker.next()
#MustOr(
result: currentNode, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: struct_declaration_node.toSourceLocation(),
withError: "Missing function declaration component")))
@@ -185,7 +208,7 @@ extension P4Struct: CompilableDeclaration {
walker.next()
#MustOr(
result: currentNode, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: struct_declaration_node.toSourceLocation(),
withError: "Missing function declaration component")))
@@ -197,15 +220,7 @@ extension P4Struct: CompilableDeclaration {
id: struct_identifier,
withType: P4QualifiedType(
P4Struct(withName: struct_identifier, andFields: P4StructFields([])))))
return Result.Ok(
(
struc,
context.extern_context
? context
: context.update(
newTypes: context.types.declare(
identifier: struct_identifier, withValue: struc.identifier.type.baseType()))
))
return Result.Ok(struc)
}
var parse_errs: (any Errorable)? = .none
@@ -217,13 +232,12 @@ extension P4Struct: CompilableDeclaration {
switch VariableDeclarationStatement.Compile(
node: declaration_field, withContext: current_context)
{
case .Ok((let declaration, let updated_context)):
case .Ok(let declaration):
let variable_declaration = declaration as! VariableDeclarationStatement
parsed_fields.append(
P4StructFieldIdentifier(
id: variable_declaration.identifier, withType: variable_declaration.initializer.type()
))
current_context = updated_context
case .Error(let e):
parse_errs =
if let e = parse_errs {
@@ -245,24 +259,19 @@ extension P4Struct: CompilableDeclaration {
withType: P4QualifiedType(
P4Struct(
withName: struct_identifier, andFields: P4StructFields(parsed_fields)))))
return .Ok(
(
declared_struct,
current_context.extern_context
? current_context
: current_context.update(
newTypes: current_context.types.declare(
identifier: struct_identifier, withValue: declared_struct.identifier.type.baseType()))
))
return .Ok(declared_struct)
}
}
extension P4Lang.Parser: CompilableDeclaration {
extension P4Lang.Parser: Compilable {
public typealias C = Declaration
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(Declaration, CompilerContext)?> {
) -> Result<Declaration> {
let parser_node = node
#SkipUnlessNodeType<Node>(node: parser_node, type: "parserDeclaration")
#RequireNodeType<Node, Result<Declaration>>(
node: parser_node, type: "parserDeclaration", nice_type_name: "parser declaration")
var current_context = context
var walker = Walker(node: parser_node)
@@ -270,7 +279,7 @@ extension P4Lang.Parser: CompilableDeclaration {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: parser_node.toSourceLocation(),
withError: "Missing elements of parser declaration")))
@@ -294,7 +303,7 @@ extension P4Lang.Parser: CompilableDeclaration {
#MustOr(
result: type_node_child, thing: type_node_walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: parser_node.toSourceLocation(),
withError: "Missing elements of parser type in parser declaration")))
@@ -310,7 +319,7 @@ extension P4Lang.Parser: CompilableDeclaration {
type_node_walker.next()
#MustOr(
result: type_node_child, thing: type_node_walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: type_node_child!.toSourceLocation(),
withError: "Missing name in parser type declaration")))
@@ -324,15 +333,14 @@ extension P4Lang.Parser: CompilableDeclaration {
type_node_walker.next()
#MustOr(
result: type_node_child, thing: type_node_walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: type_node_child!.toSourceLocation(),
withError: "Missing parser parameters")))
switch ParameterList.Compile(node: type_node_child!, withContext: current_context) {
case .Ok(let (parsed_parameter_list, updated_context)):
case .Ok(let parsed_parameter_list):
parameter_list = parsed_parameter_list
current_context = updated_context
case .Error(let e):
return .Error(e)
}
@@ -348,7 +356,7 @@ extension P4Lang.Parser: CompilableDeclaration {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: parser_node.toSourceLocation(),
withError: "Missing parser declaration component")))
@@ -356,7 +364,7 @@ extension P4Lang.Parser: CompilableDeclaration {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: parser_node.toSourceLocation(),
withError: "Missing elements of parser declaration")))
@@ -371,7 +379,7 @@ extension P4Lang.Parser: CompilableDeclaration {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: parser_node.toSourceLocation(),
withError: "Missing body of parser declaration")))
@@ -381,7 +389,7 @@ extension P4Lang.Parser: CompilableDeclaration {
}
/// TODO: Handle extern parsers.
switch SpecialCompilers.Compile(
switch SpecialCompilers.CompileParserBody(
withName: parser_name!, withParameters: parameter_list, node: current_node!,
withContext: current_context)
{
@@ -390,24 +398,21 @@ extension P4Lang.Parser: CompilableDeclaration {
TypedIdentifier(id: parser.name, withType: P4QualifiedType(parser)))
// Create a new context with the name of the parser that was just compiled in scope.
return .Ok(
(
parser_declaration,
context.extern_context
? context
: updated_context.update(
newTypes: updated_context.types.declare(identifier: parser.name, withValue: parser))
))
)
case Result.Error(let error): return .Error(error)
}
}
}
extension Control: CompilableDeclaration {
extension Control: Compilable {
public typealias C = Declaration
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Declaration, CompilerContext)?> {
) -> Common.Result<Declaration> {
#SkipUnlessNodeType<Node>(node: node, type: "control_declaration")
#RequireNodeType<Node, Result<Declaration>>(
node: node, type: "control_declaration", nice_type_name: "control declaration")
var walker = Walker(node: node)
var current_node: Node? = .none
@@ -417,7 +422,7 @@ extension Control: CompilableDeclaration {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing control declaration component")))
@@ -433,18 +438,17 @@ extension Control: CompilableDeclaration {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing control declaration component")))
let maybe_control_parameters = ParameterList.Compile(
node: current_node!, withContext: local_context)
guard case .Ok((let control_parameters, let updated_context)) = maybe_control_parameters
guard case .Ok(let control_parameters) = maybe_control_parameters
else {
return .Error(maybe_control_parameters.error()!)
}
local_context = updated_context
// Before continuing, make sure to put the parameters into context.
var control_scope = local_context.instances.enter()
@@ -459,7 +463,7 @@ extension Control: CompilableDeclaration {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Declaration, CompilerContext)?>.Error(
or: Result<Declaration>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing control declaration component")))
@@ -476,12 +480,11 @@ extension Control: CompilableDeclaration {
let maybe_action_declaration = Action.Compile(
node: current_node, withContext: local_context)
guard
case .Ok((let action_declaration, let updated_context)) = maybe_action_declaration
case .Ok(let action_declaration) = maybe_action_declaration
else {
return .Error(maybe_action_declaration.error()!)
}
actions.append(action_declaration)
local_context = updated_context
// Now, add the declaration into the context.
local_context = local_context.update(
newTypes: local_context.types.declare(
@@ -490,22 +493,20 @@ extension Control: CompilableDeclaration {
let maybe_table_declaration = Table.Compile(
node: current_node, withContext: local_context)
guard
case .Ok((let table_declaration, let updated_context)) = maybe_table_declaration
case .Ok(let table_declaration) = maybe_table_declaration
else {
return .Error(maybe_table_declaration.error()!)
}
tables.append(table_declaration)
local_context = updated_context
} else if current_node.nodeType == "apply_statement" {
// When we see an apply, that is it for the actions and the tables.
let maybe_apply_statement = ApplyStatement.Compile(
node: current_node, withContext: local_context)
guard
case .Ok((let apply_statement, let updated_context)) = maybe_apply_statement
case .Ok(let apply_statement) = maybe_apply_statement
else {
return .Error(maybe_apply_statement.error()!)
}
local_context = updated_context
apply = (apply_statement as! ApplyStatement)
// The apply is the last thing in a control declaration.
@@ -555,24 +556,16 @@ extension Control: CompilableDeclaration {
// Don't forget to add the newly declared Control to the instance that we were given
// (and not the one that we entered to do the parsing of this Control).
return .Ok(
(
declared_control,
context.extern_context
? context
: context.update(
newTypes: context.types.declare(
identifier: control_name, withValue: control))
))
return .Ok(declared_control)
}
}
extension Action: Compilable {
public typealias T = Action
public typealias C = Action
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Action, CompilerContext)> {
#RequireNodeType<Node, (P4Type, CompilerContext)>(
) -> Result<Action> {
#RequireNodeType<Node, P4Type>(
node: node, type: "action_declaration", nice_type_name: "Action Declaration")
var walker = Walker(node: node)
@@ -584,7 +577,7 @@ extension Action: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Action, CompilerContext)>.Error(
or: Result<Action>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing action declaration component"
))
@@ -601,7 +594,7 @@ extension Action: Compilable {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Action, CompilerContext)>.Error(
or: Result<Action>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing action declaration component"
))
@@ -609,11 +602,10 @@ extension Action: Compilable {
let maybe_action_parameters = ParameterList.Compile(
node: current_node!, withContext: current_context)
guard case .Ok((let action_parameters, let updated_context)) = maybe_action_parameters
guard case .Ok(let action_parameters) = maybe_action_parameters
else {
return .Error(maybe_action_parameters.error()!)
}
current_context = updated_context
// Check whether the parameters are in the proper order.
let remaining_parameters = action_parameters.parameters.drop(while: {
@@ -629,7 +621,7 @@ extension Action: Compilable {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Action, CompilerContext)>.Error(
or: Result<Action>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing action declaration component"
))
@@ -644,29 +636,26 @@ extension Action: Compilable {
let maybe_action_body = BlockStatement.Compile(
node: current_node!, withContext: context.update(newInstances: function_scope))
guard case .Ok((let action_body, _)) = maybe_action_body else {
guard case .Ok(let action_body) = maybe_action_body else {
return .Error(maybe_action_body.error()!)
}
/// TODO: Actions cannot contain switches!
return .Ok(
(
Action(
named: action_name, withParameters: action_parameters,
withBody: (action_body as! BlockStatement)),
current_context
))
withBody: (action_body as! BlockStatement)))
}
}
extension TableKeyEntry: Compilable {
public typealias T = TableKeyEntry
public typealias C = TableKeyEntry
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TableKeyEntry, CompilerContext)> {
) -> Result<TableKeyEntry> {
#RequireNodeType<Node, (P4Type, CompilerContext)>(
#RequireNodeType<Node, TableKeyEntry>(
node: node, type: "table_key_entry", nice_type_name: "Table Key Entry")
var walker = Walker(node: node)
@@ -677,7 +666,7 @@ extension TableKeyEntry: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(TableKeyEntry, CompilerContext)>.Error(
or: Result<TableKeyEntry>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing table key entry declaration component")))
@@ -693,31 +682,31 @@ extension TableKeyEntry: Compilable {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(TableKeyEntry, CompilerContext)>.Error(
or: Result<TableKeyEntry>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing table key entry declaration component")))
let maybe_match_type = TableKeyMatchType.Compile(
node: current_node!, withContext: current_context)
guard case .Ok((let match_type, _)) = maybe_match_type else {
guard case .Ok(let match_type) = maybe_match_type else {
return .Error(maybe_match_type.error()!)
}
return .Ok((TableKeyEntry(keyset_expression as! KeysetExpression, match_type), current_context))
return .Ok(TableKeyEntry(keyset_expression as! KeysetExpression, match_type))
}
}
extension TableKeyMatchType: Compilable {
public typealias T = TableKeyMatchType
public typealias C = TableKeyMatchType
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TableKeyMatchType, CompilerContext)> {
#RequireNodeType<Node, (TableKeyMatchType, CompilerContext)>(
) -> Result<TableKeyMatchType> {
#RequireNodeType<Node, TableKeyMatchType>(
node: node, type: "table_key_match_type", nice_type_name: "Table Key Match Type")
if node.text! == "exact" {
return .Ok((TableKeyMatchType.Exact, context))
return .Ok(TableKeyMatchType.Exact)
}
return .Error(
ErrorWithLocation(
@@ -727,11 +716,11 @@ extension TableKeyMatchType: Compilable {
}
extension TableKeys: Compilable {
public typealias T = TableKeys
public typealias C = TableKeys
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TableKeys, CompilerContext)> {
#RequireNodeType<Node, (TableKeyMatchType, CompilerContext)>(
) -> Result<TableKeys> {
#RequireNodeType<Node, TableKeyMatchType>(
node: node, type: "table_keys", nice_type_name: "Table Keys")
var walker = Walker(node: node)
@@ -746,7 +735,7 @@ extension TableKeys: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(TableKeys, CompilerContext)>.Error(
or: Result<TableKeys>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing table keys declaration component in control declaration"))
@@ -754,7 +743,7 @@ extension TableKeys: Compilable {
let (keys, errors) = walker.try_map(n: node.childCount - 1, onlyNamed: true) { current_node in
return switch TableKeyEntry.Compile(node: current_node, withContext: context) {
case .Ok((let keyset_expression, _)): .Ok(keyset_expression)
case .Ok(let keyset_expression): .Ok(keyset_expression)
case .Error(let e): .Error(e)
}
}
@@ -769,16 +758,16 @@ extension TableKeys: Compilable {
}.joined(separator: ";"))))
}
return .Ok((TableKeys(withEntries: keys), context))
return .Ok(TableKeys(withEntries: keys))
}
}
extension TableActionsProperty: Compilable {
public typealias T = TableActionsProperty
public typealias C = TableActionsProperty
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TableActionsProperty, CompilerContext)> {
#RequireNodeType<Node, (TableActionsProperty, CompilerContext)>(
) -> Result<TableActionsProperty> {
#RequireNodeType<Node, TableActionsProperty>(
node: node, type: "table_actions", nice_type_name: "Table Actions")
var walker = Walker(node: node)
@@ -793,7 +782,7 @@ extension TableActionsProperty: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(TableActionsProperty, CompilerContext)>.Error(
or: Result<TableActionsProperty>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing table actions declaration component in control declaration"))
@@ -828,16 +817,16 @@ extension TableActionsProperty: Compilable {
}.joined(separator: ";"))))
}
return .Ok((TableActionsProperty(actions), context))
return .Ok(TableActionsProperty(actions))
}
}
extension TablePropertyList: Compilable {
public typealias T = TablePropertyList
public typealias C = TablePropertyList
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(TablePropertyList, CompilerContext)> {
) -> Result<TablePropertyList> {
#RequireNodeType<Node, (P4Type, CompilerContext)>(
#RequireNodeType<Node, TablePropertyList>(
node: node, type: "table_property_list", nice_type_name: "Table Property List")
var current_context = context
@@ -849,15 +838,13 @@ extension TablePropertyList: Compilable {
node.enumerateNamedChildren { child in
if child.nodeType == "table_keys" {
switch TableKeys.Compile(node: child, withContext: current_context) {
case .Ok((let table_key, let updated_context)):
current_context = updated_context
case .Ok(let table_key):
keys.append(table_key)
case .Error(let e): errors.append(e)
}
} else if child.nodeType == "table_actions" {
switch TableActionsProperty.Compile(node: child, withContext: current_context) {
case .Ok((let table_action_property, let updated_context)):
current_context = updated_context
case .Ok(let table_action_property):
actions.append(table_action_property)
case .Error(let e): errors.append(e)
}
@@ -900,19 +887,19 @@ extension TablePropertyList: Compilable {
actions.append(TableActionsProperty())
}
return .Ok((TablePropertyList(withActions: actions[0], withKeys: keys[0]), current_context))
return .Ok(TablePropertyList(withActions: actions[0], withKeys: keys[0]))
}
}
extension Table: Compilable {
public typealias T = Table
public typealias C = Table
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Table, CompilerContext)> {
) -> Result<Table> {
let table_declaration_node = node
#RequireNodeType<Node, (P4Type, CompilerContext)>(
#RequireNodeType<Node, Table>(
node: table_declaration_node, type: "table_declaration", nice_type_name: "Table Declaration")
var walker = Walker(node: table_declaration_node)
@@ -924,7 +911,7 @@ extension Table: Compilable {
walker.next() // Skip the XXX?
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Table, CompilerContext)>.Error(
or: Result<Table>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing table declaration component")
))
@@ -942,46 +929,43 @@ extension Table: Compilable {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(Table, CompilerContext)>.Error(
or: Result<Table>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing table declaration component")
))
let maybe_table_property_list = TablePropertyList.Compile(
node: current_node!, withContext: current_context)
guard case .Ok((let table_property_list, _)) = maybe_table_property_list else {
guard case .Ok(let table_property_list) = maybe_table_property_list else {
return Result.Error(maybe_table_property_list.error()!)
}
return .Ok(
(Table(withName: table_name, withPropertyList: table_property_list), current_context))
return .Ok(Table(withName: table_name, withPropertyList: table_property_list))
}
}
extension ExternDeclaration: CompilableDeclaration {
extension ExternDeclaration: Compilable {
public typealias C = Declaration
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Declaration, CompilerContext)?> {
) -> Result<Declaration> {
let extern_declaration_node = node
#RequireNodeType<Node, (Declaration, CompilerContext)>(
#RequireNodeType<Node, Declaration>(
node: extern_declaration_node, type: "extern_declaration",
nice_type_name: "Extern Declaration")
let declaration_node = extern_declaration_node.child(at: 1)!
#RequireNodeType<Node, (Declaration, CompilerContext)>(
#RequireNodeType<Node, Declaration>(
node: declaration_node, type: "declaration", nice_type_name: "Declaration")
let declarationed_node = declaration_node.child(at: 0)!
let maybe_declared = Declaration.Compile(
node: declarationed_node, withContext: context.update(newExtern: true))
guard case .Ok(let maybe_declared) = maybe_declared else {
guard case .Ok(let declared) = maybe_declared else {
return .Error(maybe_declared.error()!)
}
guard case .some((let declared, _)) = maybe_declared else {
return .Ok(.none)
}
// Before we are okay with this declaration, it must already be registered as an extern
// with the matching "stuff".
@@ -1000,11 +984,7 @@ extension ExternDeclaration: CompilableDeclaration {
let extern_declaration = Declaration(extern: declared, ffi: found_ffi)
return .Ok(
(
extern_declaration,
context.update(
newExterns: context.externs.declare(
identifier: declared.identifier, withValue: extern_declaration))
))
)
}
}
+78 -65
View File
@@ -21,22 +21,10 @@ import P4Runtime
import SwiftTreeSitter
import TreeSitterP4
protocol CompilableExpression {
static func compile(
node: Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?>
}
protocol CompilableLValueExpression {
static func compile_as_lvalue(
node: Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression?>
}
extension TypedIdentifier: CompilableExpression {
static func compile(
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> {
) -> Result<P4Expression?> {
let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
@@ -57,9 +45,9 @@ extension TypedIdentifier: CompilableExpression {
}
extension TypedIdentifier: CompilableLValueExpression {
static func compile_as_lvalue(
public static func compile_as_lvalue(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression?> {
) -> Result<P4LValueExpression?> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
@@ -77,9 +65,9 @@ extension TypedIdentifier: CompilableLValueExpression {
}
extension P4BooleanValue: CompilableExpression {
static func compile(
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> {
) -> Result<P4Expression?> {
let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: node, type: "booleanLiteralExpression")
@@ -98,9 +86,9 @@ extension P4BooleanValue: CompilableExpression {
}
extension P4IntValue: CompilableExpression {
static func compile(
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> {
) -> Result<P4Expression?> {
let node = node.child(at: 0)!
#SkipUnlessNodesTypes<SwiftTreeSitter.Node>(
@@ -147,9 +135,9 @@ extension P4IntValue: CompilableExpression {
}
extension P4StringValue: CompilableExpression {
static func compile(
public static func compile(
node: SwiftTreeSitter.Node, withContext scopes: CompilerContext
) -> Result<EvaluatableExpression?> {
) -> Result<P4Expression?> {
let node = node.child(at: 0)!
#SkipUnlessNodeType<SwiftTreeSitter.Node>(
node: node, type: "string_literal")
@@ -158,12 +146,12 @@ extension P4StringValue: CompilableExpression {
}
extension KeysetExpression: CompilableExpression {
static func compile(
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableExpression)?> {
) -> Result<P4Expression?> {
let keyset_expression_node = node.child(at: 0)!
#RequireNodesType<Node, EvaluatableExpression>(
#RequireNodesType<Node, P4Expression>(
nodes: keyset_expression_node, type: ["expression", "default_keyset"],
nice_type_names: ["expression", "default keyset"])
@@ -186,12 +174,12 @@ extension KeysetExpression: CompilableExpression {
struct Expression {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression> {
#RequireNodeType<Node, EvaluatableExpression>(
) -> Result<P4Expression> {
#RequireNodeType<Node, P4Expression>(
node: node, type: "expression", nice_type_name: "expression")
let expression_node = node.child(at: 0)!
#RequireNodesType<Node, EvaluatableExpression>(
#RequireNodesType<Node, P4Expression>(
nodes: expression_node, type: ["grouped_expression", "simple_expression"],
nice_type_names: ["grouped expression", "simple expression"])
@@ -223,12 +211,12 @@ struct Expression {
struct LValue {
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression> {
#RequireNodeType<Node, EvaluatableExpression>(
) -> Result<P4LValueExpression> {
#RequireNodeType<Node, P4Expression>(
node: node, type: "expression", nice_type_name: "expression")
let expression_node = node.child(at: 0)!
#RequireNodesType<Node, EvaluatableExpression>(
#RequireNodesType<Node, P4Expression>(
nodes: expression_node, type: ["grouped_expression", "simple_expression"],
nice_type_names: ["grouped expression", "simple expression"])
@@ -268,9 +256,9 @@ struct Identifier {
}
extension SelectExpression: CompilableExpression {
static func compile(
public static func compile(
node: Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> {
) -> Result<P4Expression?> {
#RequireNodeType<Node, (SelectExpression, CompilerContext)>(
node: node, type: "selectExpression", nice_type_name: "parser select expression")
@@ -330,9 +318,9 @@ extension SelectExpression: CompilableExpression {
}
extension SelectCaseExpression: CompilableExpression {
static func compile(
public static func compile(
node: Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> {
) -> Result<P4Expression?> {
if node.nodeType != "selectCase" {
return Result.Error(Error(withMessage: "Expected select case not found"))
}
@@ -383,10 +371,35 @@ extension SelectCaseExpression: CompilableExpression {
}
}
// swift-format-ignore
public typealias BinaryOperatorChecker = (P4Expression, P4Expression) -> Result<()>
public func binary_and_or_operator_checker(
left: P4Expression, right: P4Expression
) -> Result<()> {
// Check that both are Boolean-typed things!
if !(left.type().baseType().eq(rhs: P4Boolean()) && right.type().baseType().eq(rhs: P4Boolean()))
{
return .Error(Error(withMessage: "And/Or on operands with non-bool type is not allowed"))
}
return .Ok(())
}
public func binary_int_math_operator_checker(
left: P4Expression, right: P4Expression
) -> Result<()> {
// Check that both are int-typed things!
if !(left.type().baseType().eq(rhs: P4Int()) && right.type().baseType().eq(rhs: P4Int())) {
return .Error(
Error(withMessage: "Mathematical operation on operands with non-int type is not allowed"))
}
return .Ok(())
}
extension BinaryOperatorExpression: CompilableExpression {
static func compile(
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<(EvaluatableExpression)?> {
) -> Result<(P4Expression)?> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
@@ -398,20 +411,20 @@ extension BinaryOperatorExpression: CompilableExpression {
var current_node: Node? = .none
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed binary operator expression"
)))
/// TODO: This macro cannot handle new lines in the arrays
// swift-format-ignore
#RequireNodesType<Node, EvaluatableExpression?>(
#RequireNodesType<Node, P4Expression?>(
nodes: binary_operator_expression_node,
type: ["binaryEqualOperatorExpression", "binaryLessThanOperatorExpression", "binaryLessThanEqualOperatorExpression", "binaryGreaterThanOperatorExpression", "binaryGreaterThanEqualOperatorExpression", "binaryAndOperatorExpression", "binaryOrOperatorExpression", "binaryAddOperatorExpression", "binarySubtractOperatorExpression", "binaryMultiplyOperatorExpression", "binaryDivideOperatorExpression"],
nice_type_names: [ "binary equal operator", "binary less than operator", "binary less than or equal to operator", "binary greater than operator", "binary greater than or equal to operator", "binary and operator", "binary or operator", "binary add operator", "binary subtract operator", "binary multiply operator", "binary divide operator"])
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing LHS for binary operator expression")))
@@ -421,7 +434,7 @@ extension BinaryOperatorExpression: CompilableExpression {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing binary operator for binary operator expression")))
@@ -429,7 +442,7 @@ extension BinaryOperatorExpression: CompilableExpression {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing RHS for binary operator expression")))
@@ -520,9 +533,9 @@ extension BinaryOperatorExpression: CompilableExpression {
}
extension ArrayAccessExpression: CompilableExpression {
static func compile(
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<EvaluatableExpression?> {
) -> Result<P4Expression?> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
@@ -535,11 +548,11 @@ extension ArrayAccessExpression: CompilableExpression {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed array access expression")))
#RequireNodeType<Node, EvaluatableExpression?>(
#RequireNodeType<Node, P4Expression?>(
node: current_node!, type: "expression",
nice_type_name: "array identifier expression")
let array_access_identifier_node = current_node!
@@ -547,7 +560,7 @@ extension ArrayAccessExpression: CompilableExpression {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing [ for array access expression")))
@@ -556,12 +569,12 @@ extension ArrayAccessExpression: CompilableExpression {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing indexor expression for array access expression")))
#RequireNodeType<Node, EvaluatableExpression?>(
#RequireNodeType<Node, P4Expression?>(
node: current_node!, type: "expression",
nice_type_name: "array indexor expression")
@@ -595,9 +608,9 @@ extension ArrayAccessExpression: CompilableExpression {
}
extension FieldAccessExpression: CompilableExpression {
static func compile(
public static func compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableExpression)?> {
) -> Result<P4Expression?> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
@@ -610,11 +623,11 @@ extension FieldAccessExpression: CompilableExpression {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed field access expression")))
#RequireNodeType<Node, EvaluatableExpression?>(
#RequireNodeType<Node, P4Expression?>(
node: current_node!, type: "expression",
nice_type_name: "struct identifier expression")
let struct_identifier_node = current_node!
@@ -622,7 +635,7 @@ extension FieldAccessExpression: CompilableExpression {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing . for field access expression")))
@@ -630,12 +643,12 @@ extension FieldAccessExpression: CompilableExpression {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing field name for field access expression")))
#RequireNodeType<Node, EvaluatableExpression?>(
#RequireNodeType<Node, P4Expression?>(
node: current_node!, type: "identifier",
nice_type_name: "field name")
@@ -677,9 +690,9 @@ extension FieldAccessExpression: CompilableExpression {
}
extension FieldAccessExpression: CompilableLValueExpression {
static func compile_as_lvalue(
public static func compile_as_lvalue(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression?> {
) -> Result<P4LValueExpression?> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
node: expression, type: "fieldAccessExpression")
@@ -696,9 +709,9 @@ extension FieldAccessExpression: CompilableLValueExpression {
}
extension ArrayAccessExpression: CompilableLValueExpression {
static func compile_as_lvalue(
public static func compile_as_lvalue(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<EvaluatableLValueExpression?> {
) -> Result<P4LValueExpression?> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
node: expression, type: "arrayAccessExpression")
@@ -715,9 +728,9 @@ extension ArrayAccessExpression: CompilableLValueExpression {
}
extension FunctionCall: CompilableExpression {
static func compile(
public static func compile(
node: Node, withContext context: CompilerContext
) -> Result<EvaluatableExpression?> {
) -> Result<P4Expression?> {
let expression = node.child(at: 0)!
#SkipUnlessNodeType<Node>(
@@ -728,7 +741,7 @@ extension FunctionCall: CompilableExpression {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
@@ -780,13 +793,13 @@ extension FunctionCall: CompilableExpression {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<EvaluatableExpression?>.Error(
or: Result<P4Expression?>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
let maybe_argument_list = ArgumentList.Compile(node: current_node!, withContext: context)
guard case .Ok((let arguments, _)) = maybe_argument_list else {
guard case .Ok(let arguments) = maybe_argument_list else {
return .Error(maybe_argument_list.error()!)
}
+21 -22
View File
@@ -23,10 +23,10 @@ import TreeSitterExtensions
import TreeSitterP4
extension Statement: Compilable {
public typealias T = EvaluatableStatement
public typealias C = P4Statement
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(EvaluatableStatement, CompilerContext)> {
) -> Result<P4Statement> {
if node.nodeType != "parserStatement" && node.nodeType != "statement" {
return Result.Error(
@@ -51,9 +51,9 @@ extension Statement: Compilable {
withError:
"Unparseable statement type (\(statement.nodeType ?? "Unknown Statement Type"))"))
}
switch parser.Compile(node: statement, withContext: context) {
case Result.Ok(let (parsed, updated_context)):
return .Ok((parsed, updated_context))
switch parser.CompileStatement(node: statement, withContext: context) {
case Result.Ok(let parsed):
return .Ok(parsed)
case Result.Error(let e):
return .Error(
ErrorWithLocation(
@@ -62,11 +62,12 @@ extension Statement: Compilable {
}
}
}
extension LocalElements: Compilable {
public typealias T = EvaluatableStatement
public typealias C = P4Statement
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
) -> Result<P4Statement> {
let localElementsParsers: [String: CompilableStatement.Type] = [
"variableDeclaration": VariableDeclarationStatement.self
]
@@ -78,9 +79,9 @@ extension LocalElements: Compilable {
withError: "Unparseable statement type (\(node.nodeType ?? "Unknown Statement Type"))"))
}
switch parser.Compile(node: node, withContext: context) {
case Result.Ok(let (parsed, parsed_updated_scopes)):
return Result.Ok((parsed, parsed_updated_scopes))
switch parser.CompileStatement(node: node, withContext: context) {
case Result.Ok(let parsed):
return Result.Ok(parsed)
case Result.Error(let e):
return Result.Error(Error(withMessage: "Failed to parse local element: \(e)"))
}
@@ -88,10 +89,10 @@ extension LocalElements: Compilable {
}
extension ParserState: Compilable {
public typealias T = ParserState
public typealias C = ParserState
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(ParserState, CompilerContext)> {
) -> Result<ParserState> {
var walker = Walker(node: node)
var current_node: Node? = .none
@@ -107,7 +108,7 @@ extension ParserState: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ParserState, CompilerContext)>.Error(
or: Result<ParserState>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing elements in parser state declaration")))
@@ -125,7 +126,7 @@ extension ParserState: Compilable {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ParserState, CompilerContext)>.Error(
or: Result<ParserState>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing elements in parser state declaration")))
@@ -141,22 +142,20 @@ extension ParserState: Compilable {
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ParserState, CompilerContext)>.Error(
or: Result<ParserState>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing body of state declaration")
))
var errors: (any Errorable)? = .none
var current_context = context
var parsed_s: [EvaluatableStatement] = Array()
var parsed_s: [P4Statement] = Array()
if current_node!.nodeType == "parserStatements" {
switch SpecialCompilers.Statements.Compile(
node: current_node!, withContext: current_context)
node: current_node!, withContext: context)
{
case .Ok(let (state_statements, updated_context)):
case .Ok(let state_statements):
parsed_s = state_statements
current_context = updated_context
case .Error(let error):
errors =
if let errors = errors {
@@ -174,13 +173,13 @@ extension ParserState: Compilable {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(ParserState, CompilerContext)>.Error(
or: Result<ParserState>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError: "Missing transition statement of state declaration")))
return SpecialCompilers.TransitionStatement.Compile(
node: current_node!, forState: state_identifier, withStatements: parsed_s,
withContext: current_context)
withContext: SpecialCompilers.Statements.effect(statements: parsed_s, context: context))
}
}
+18 -16
View File
@@ -22,12 +22,6 @@ import SwiftTreeSitter
import TreeSitterExtensions
import TreeSitterP4
public protocol CompilableStatement {
static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)>
}
public protocol CompilableValue {
static func CompileValue(withValue value: String) -> Result<P4DataValue>
}
@@ -38,19 +32,27 @@ public protocol CompilableType {
) -> Result<P4Type?>
}
public protocol CompilableDeclaration {
/// Info
///
/// Extensions should update the context with the newly declared item _unless_
/// they are in an extern context (``CompilerContext.extern_context``).
static func Compile(
public protocol CompilableExpression {
static func compile(
node: Node, withContext context: CompilerContext
) -> Result<(Declaration, CompilerContext)?>
) -> Result<P4Expression?>
}
public protocol Compilable<T> {
associatedtype T
public protocol CompilableLValueExpression {
static func compile_as_lvalue(
node: Node, withContext context: CompilerContext
) -> Result<P4LValueExpression?>
}
public protocol Compilable<C> {
associatedtype C
static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(T, CompilerContext)>
) -> Result<C>
}
public protocol CompilableStatement {
static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement>
}
+52 -45
View File
@@ -22,14 +22,20 @@ import SwiftTreeSitter
import TreeSitterExtensions
import TreeSitterP4
protocol AnyCompilable {
static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(Any, CompilerContext)>
}
public struct SpecialCompilers {
public struct TransitionStatement {
static func Compile(
node: Node, forState state_identifier: Common.Identifier,
withStatements stmts: [EvaluatableStatement], withContext context: CompilerContext
) -> Result<(ParserState, CompilerContext)> {
withStatements stmts: [P4Statement], withContext context: CompilerContext
) -> Result<ParserState> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
#RequireNodeType<Node, P4Statement>(
node: node, type: "parserTransitionStatement", nice_type_name: "parser transition statement"
)
@@ -58,19 +64,18 @@ public struct SpecialCompilers {
switch next_state {
case (_, .some(let instance)):
return .Ok(
(
ParserStateDirectTransition(
name: state_identifier,
withNextState: instance.dataValue() as! InstantiatedParserState,
withStatements: stmts), context
))
withStatements: stmts,
)
)
case (_, .none):
return .Ok(
(
ParserStateDirectTransition(
name: state_identifier,
withNextStateIdentifier: next_state_id, withStatements: stmts), context
))
withNextStateIdentifier: next_state_id, withStatements: stmts)
)
}
} else {
@@ -95,12 +100,11 @@ public struct SpecialCompilers {
{
case .Ok(let tse):
.Ok(
(
ParserStateSelectTransition(
name: state_identifier, withTransitionExpression: tse as! SelectExpression,
withStatements: stmts,
), context
))
)
)
case .Error(let e): .Error(e)
}
}
@@ -109,7 +113,7 @@ public struct SpecialCompilers {
public struct Statements {
static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<([EvaluatableStatement], CompilerContext)> {
) -> Result<[P4Statement]> {
if node.nodeType != "statements" && node.nodeType != "parserStatements" {
return Result.Error(
ErrorWithLocation(
@@ -118,15 +122,15 @@ public struct SpecialCompilers {
var errors: (any Errorable)? = .none
var current_context = context
var parsed_s: [EvaluatableStatement] = Array()
var parsed_s: [P4Statement] = Array()
node.enumerateNamedChildren { node in
switch Statement.Compile(
node: node, withContext: current_context)
{
case .Ok((let parsed_statement, let updated_context)):
current_context = updated_context
case .Ok(let parsed_statement):
parsed_s.append(parsed_statement)
current_context = parsed_statement.effect(context: current_context)
case .Error(let e):
errors =
if let errors = errors {
@@ -141,11 +145,20 @@ public struct SpecialCompilers {
return .Error(errors)
}
return Result.Ok((parsed_s, current_context))
}
return Result.Ok(parsed_s)
}
static func Compile(
static func effect(statements: [P4Statement], context: CompilerContext) -> CompilerContext {
var current = context
for s in statements {
current = s.effect(context: current)
}
return current
}
}
static func CompileParserBody(
withName name: Common.Identifier, withParameters parameters: ParameterList, node: Node,
withContext context: CompilerContext
) -> Result<(P4Lang.Parser, CompilerContext)> {
@@ -167,9 +180,10 @@ public struct SpecialCompilers {
node: parser_state,
withContext: context.update(newInstances: current_context.instances.enter()))
{
case Result.Ok(let (state, updated_context)):
case Result.Ok(let state):
let statement = state as P4Statement
current_context = statement.effect(context: current_context)
parser.states = parser.states.append(state: state)
current_context = updated_context
case Result.Error(let e): error = e
}
}
@@ -245,43 +259,35 @@ public struct SpecialCompilers {
// Try to parse all top-level declarations.
result?.rootNode?.enumerateNamedChildren { (declaration_node: Node) in
let specific_declaration_node = declaration_node.child(at: 0)!
let declaration_parsers: [CompilableDeclaration.Type] = [
Declaration.self, P4Lang.Parser.self,
let declaration_parsers: [String: CompilableStatement.Type] = [
"declaration": Declaration.self,
"instantiation": Instantiation.self,
]
var found_parser = false
for parser in declaration_parsers {
switch parser.Compile(node: specific_declaration_node, withContext: compilation_context) {
case .Ok(.none): {}()
case .Ok(.some((_, let updated_context))):
found_parser = true
compilation_context = updated_context
break
if let parser = declaration_parsers[declaration_node.nodeType!] {
let r = parser.CompileStatement(node: declaration_node, withContext: compilation_context)
switch r {
case .Ok(let compiled):
compilation_context = compiled.effect(context: compilation_context)
case .Error(let e):
found_parser = true
errors =
if let errors = errors {
errors.append(error: e)
} else {
e
}
break
}
}
// If none of the declaration parsers chose to parse, that's an error, too!
if !found_parser {
let no_parser_error = ErrorWithLocation(
sourceLocation: specific_declaration_node.toSourceLocation(),
withError: "Could not find parser for declaration node"
)
}
} else {
let e = ErrorWithLocation(
sourceLocation: declaration_node.toSourceLocation(),
withError:
"\(declaration_node.nodeType!) cannot be at a P4 program top level")
errors =
if let errors = errors {
errors.append(error: no_parser_error)
errors.append(error: e)
} else {
no_parser_error
e
}
}
}
@@ -313,4 +319,5 @@ public struct SpecialCompilers {
return Result.Ok(program)
}
}
}
+273 -55
View File
@@ -22,11 +22,12 @@ import SwiftTreeSitter
import TreeSitterExtensions
import TreeSitterP4
extension BlockStatement: CompilableStatement {
extension BlockStatement: Compilable {
public typealias C = BlockStatement
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
) -> Result<BlockStatement> {
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "blockStatement", nice_type_name: "block statement")
var walker = Walker(node: node)
@@ -34,7 +35,7 @@ extension BlockStatement: CompilableStatement {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error(
or: Result<BlockStatement>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
@@ -45,23 +46,21 @@ extension BlockStatement: CompilableStatement {
withError: "Missing { on block statement"))
}
var statements: [EvaluatableStatement] = Array()
var statements: [P4Statement] = Array()
var parse_err: (any Errorable)? = .none
var current_context = context
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error(
or: Result<BlockStatement>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
if current_node!.nodeType == "statements" {
switch SpecialCompilers.Statements.Compile(
node: current_node!, withContext: current_context)
node: current_node!, withContext: context)
{
case .Ok(let (parsed_statements, updated_context)):
current_context = updated_context
case .Ok(let parsed_statements):
statements = parsed_statements
case .Error(let error):
parse_err = error
@@ -76,7 +75,7 @@ extension BlockStatement: CompilableStatement {
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<(EvaluatableStatement, CompilerContext)>.Error(
or: Result<BlockStatement>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Malformed block statement")))
@@ -87,16 +86,28 @@ extension BlockStatement: CompilableStatement {
withError: "Missing } on block statement"))
}
return .Ok((BlockStatement(statements), current_context))
return .Ok(BlockStatement(statements))
}
}
extension ConditionalStatement: CompilableStatement {
extension BlockStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension ConditionalStatement: Compilable {
public typealias C = ConditionalStatement
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
) -> Result<ConditionalStatement> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "conditionalStatement", nice_type_name: "conditional statement")
let maybe_condition_expression = node.child(at: 2)
@@ -128,7 +139,7 @@ extension ConditionalStatement: CompilableStatement {
}
guard
case .Ok((let thenns, _)) = Statement.Compile(
case .Ok(let thenns) = Statement.Compile(
node: thens, withContext: context)
else {
return Result.Error(
@@ -137,7 +148,7 @@ extension ConditionalStatement: CompilableStatement {
"Could not parse the then block in a conditional statement"))
}
let optional_elss: Result<(any EvaluatableStatement, CompilerContext)>? =
let optional_elss: Result<any P4Statement>? =
if let elss = node.child(at: 6) {
.some(
Statement.Compile(
@@ -148,7 +159,7 @@ extension ConditionalStatement: CompilableStatement {
if let parsed_elss = optional_elss {
guard
case .Ok((let elss, _)) = parsed_elss
case .Ok(let elss) = parsed_elss
else {
return Result.Error(
Error(
@@ -156,18 +167,30 @@ extension ConditionalStatement: CompilableStatement {
"Could not parse the else block in a conditional statement"))
}
return .Ok(
(ConditionalStatement(condition: condition, withThen: thenns, andElse: elss), context))
ConditionalStatement(condition: condition, withThen: thenns, andElse: elss))
}
return .Ok((ConditionalStatement(condition: condition, withThen: thenns), context))
return .Ok(ConditionalStatement(condition: condition, withThen: thenns))
}
}
extension VariableDeclarationStatement: CompilableStatement {
extension ConditionalStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension VariableDeclarationStatement: Compilable {
public typealias C = VariableDeclarationStatement
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
) -> Result<VariableDeclarationStatement> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "variableDeclaration", nice_type_name: "variable declaration statement")
let maybe_typeref = node.child(at: 0)
@@ -206,7 +229,7 @@ extension VariableDeclarationStatement: CompilableStatement {
Error(withMessage: "Could not parse a P4 type from \(typeref.text!)"))
}
var initializer: EvaluatableExpression? = .none
var initializer: P4Expression? = .none
// If there is an initializer, it must be an expression.
if let initializer_expression = maybe_rvalue {
@@ -249,40 +272,59 @@ extension VariableDeclarationStatement: CompilableStatement {
}
return Result.Ok(
(
VariableDeclarationStatement(
identifier: parsed_variablename, withInitializer: initializer),
// Context with updated names to include the newly declared name.
context.update(
newInstances: context.instances.declare(
identifier: parsed_variablename, withValue: (declaration_p4_type, .none)))
)
identifier: TypedIdentifier(id: parsed_variablename, withType: declaration_p4_type),
withInitializer: initializer),
)
}
}
extension ExpressionStatement: CompilableStatement {
public static func Compile(
extension VariableDeclarationStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
node: node, type: "expressionStatement", nice_type_name: "expression statement")
let expression_node = node.child(at: 0)!
return switch Expression.Compile(node: expression_node, withContext: context) {
case .Ok(let expression): .Ok((ExpressionStatement(expression), context))
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension ParserAssignmentStatement: CompilableStatement {
extension ExpressionStatement: Compilable {
public typealias C = ExpressionStatement
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<(EvaluatableStatement, CompilerContext)> {
) -> Result<ExpressionStatement> {
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "expressionStatement", nice_type_name: "expression statement")
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
let expression_node = node.child(at: 0)!
return switch Expression.Compile(node: expression_node, withContext: context) {
case .Ok(let expression): .Ok(ExpressionStatement(expression))
case .Error(let e): .Error(e)
}
}
}
extension ExpressionStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension ParserAssignmentStatement: Compilable {
public typealias C = ParserAssignmentStatement
public static func Compile(
node: Node, withContext context: CompilerContext
) -> Result<ParserAssignmentStatement> {
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "assignmentStatement", nice_type_name: "assignment statement")
guard let lvalue_node = node.child(at: 0),
@@ -323,20 +365,30 @@ extension ParserAssignmentStatement: CompilableStatement {
}
return Result.Ok(
(
ParserAssignmentStatement(
withLValue: lvalue_identifier,
withValue: rvalue
), context
))
}
}
extension ReturnStatement: CompilableStatement {
extension ParserAssignmentStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension ReturnStatement: Compilable {
public typealias C = ReturnStatement
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
) -> Result<ReturnStatement> {
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "return_statement", nice_type_name: "return statement")
let expression_node = node.child(at: 1)!
@@ -344,7 +396,7 @@ extension ReturnStatement: CompilableStatement {
return switch Expression.Compile(node: expression_node, withContext: context) {
case .Ok(let result):
if result.type().baseType().eq(rhs: context.expected_type!.baseType()) {
.Ok((ReturnStatement(result), context))
.Ok(ReturnStatement(result))
} else {
.Error(
ErrorWithLocation(
@@ -358,18 +410,184 @@ extension ReturnStatement: CompilableStatement {
}
}
extension ApplyStatement: CompilableStatement {
extension ReturnStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension ApplyStatement: Compilable {
public typealias C = ApplyStatement
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Common.Result<(any Common.EvaluatableStatement, CompilerContext)> {
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
) -> Result<ApplyStatement> {
#RequireNodeType<Node, (P4Statement)>(
node: node, type: "apply_statement", nice_type_name: "apply statement")
let expression_node = node.child(at: 1)!
return switch BlockStatement.Compile(node: expression_node, withContext: context) {
case .Ok((let statement, let updated_context)):
.Ok((ApplyStatement(statement as! BlockStatement), updated_context))
case .Ok(let statement):
.Ok(ApplyStatement(statement as! BlockStatement))
case .Error(let e): .Error(e)
}
}
}
extension ApplyStatement: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
}
extension Instantiation: Compilable {
public typealias C = Instantiation
public static func Compile(
node: SwiftTreeSitter.Node, withContext context: CompilerContext
) -> Result<Instantiation> {
let expression = node
#RequireNodeType<Node, (Instantiation)>(
node: expression, type: "instantiation", nice_type_name: "instantiation statement")
var walker = Walker(node: expression)
var current_node: Node? = .none
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<Instantiation>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing function call component")))
let maybe_instantiated_type_name = Identifier.Compile(
node: current_node!, withContext: context)
guard case .Ok(let instantiated_type_name) = maybe_instantiated_type_name else {
return Result.Error(maybe_instantiated_type_name.error()!)
}
var maybe_instantiated_type: Result<(P4Lang.Parser?, Declaration?)> =
switch context.types.lookup(identifier: instantiated_type_name) {
case .Ok(let looked_up):
switch looked_up {
/// TODO: Further filter instantiable things.
case let instantiated_parser as P4Lang.Parser:
Result<(P4Lang.Parser?, Declaration?)>.Ok((instantiated_parser, .none)) // What we found is actually a parser declaration
default:
Result<(P4Lang.Parser?, Declaration?)>.Error(
ErrorWithLocation(
sourceLocation: current_node!.toSourceLocation(),
withError: "\(instantiated_type_name) cannot be instantiated"))
}
case .Error(let e): Result<(P4Lang.Parser?, Declaration?)>.Error(e)
}
maybe_instantiated_type =
if case .Error(let e) = maybe_instantiated_type {
switch context.externs.lookup(identifier: instantiated_type_name) {
case .Ok(let callee as Declaration):
// Now, make sure that it is a function declaration!
switch callee.identifier.type.baseType() {
case is P4Lang.Parser: Result.Ok((.none, callee))
default:
.Error(
ErrorWithLocation(
sourceLocation: current_node!.toSourceLocation(),
withError: "\(instantiated_type_name) cannot be instantiated"))
}
default: .Error(e)
}
} else {
maybe_instantiated_type
}
guard case .Ok(let callee) = maybe_instantiated_type else {
return .Error(maybe_instantiated_type.error()!)
}
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<Instantiation>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing instantiation component")))
let maybe_argument_list = ArgumentList.Compile(node: current_node!, withContext: context)
guard case .Ok(let arguments) = maybe_argument_list else {
return .Error(maybe_argument_list.error()!)
}
// Now, compare the arguments with the parameters:
let params =
switch callee {
case (.some(let callee), .none): Optional<ParameterList>.some(callee.parameters)
case (.none, .some(let callee)):
Optional<ParameterList>.some((callee.ffi!.type().baseType() as! P4Lang.Parser).parameters)
default: Optional<ParameterList>.none
}
guard case .some(let params) = params else {
return Result.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError:
"Could not lookup the parameters for the instantiated parser (\(instantiated_type_name))"
))
}
if case .Error(let e) = arguments.compatible(params) {
return .Error(e)
}
walker.next()
#MustOr(
result: current_node, thing: walker.getNext(),
or: Result<Instantiation>.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(), withError: "Missing instantiation name")))
let name = Identifier.Compile(node: current_node!, withContext: context)
guard case .Ok(let name) = name else {
return .Error(name.error()!)
}
let inst: Result<Instantiation> =
switch callee {
case (.some(let callee), .none):
.Ok(Instantiation(named: name, ofType: callee, withArguments: arguments))
case (.none, .some(let callee)):
.Ok(Instantiation(named: name, ofType: callee, withArguments: arguments))
default:
Result.Error(
ErrorWithLocation(
sourceLocation: node.toSourceLocation(),
withError:
"Unexpected error occurred calling function named (\(instantiated_type_name))"
))
}
return inst
}
}
extension Instantiation: CompilableStatement {
public static func CompileStatement(
node: Node, withContext context: CompilerContext
) -> Result<P4Statement> {
return switch Compile(node: node, withContext: context) {
case .Ok(let res): .Ok(res)
case .Error(let e): .Error(e)
}
}
-95
View File
@@ -1,95 +0,0 @@
// p4rse, Copyright 2026, Will Hawkins
//
// This file is part of p4rse.
//
// This file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
import Common
public protocol Visitable {
}
public protocol LanguageVisitor<Context> {
associatedtype Context
// Program
func visit(_ program: Program, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
// Parser
func visit(_ parser: Parser, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ parser_state: InstantiatedParserState, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Statements
func visit(
_ variable_declaration: VariableDeclarationStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ conditional: ConditionalStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ block: BlockStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ rtn: ReturnStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ apply: ApplyStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Expressions
func visit(
_ keyset: KeysetExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ select_case: SelectCaseExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ select: SelectExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ array_access: ArrayAccessExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ field_access: FieldAccessExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ function_call: FunctionCall, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ binary_operator: BinaryOperatorExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Declarations
func visit(_ decl: Declaration, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ extern_decl: ExternDeclaration, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ func_decl: FunctionDeclaration, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Control
func visit(_ action: Action, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ table_key_entry: TableKeyEntry, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ table_property_list: TablePropertyList, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(_ table: Table, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(_ control: Control, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
}
+13 -1
View File
@@ -52,7 +52,7 @@ public struct Declaration: P4Type {
return self
}
public var description: String {
return "Extern \(self.identifier)"
return self.extern ? "Extern " : "" + "\(self.identifier)"
}
}
@@ -130,3 +130,15 @@ public struct FunctionDeclaration: P4Type, P4DataValue {
self.body = body
}
}
public struct Instantiation {
public let name: Identifier
public let tipe: P4Type
public let arguments: ArgumentList
public init(named name: Identifier, ofType tipe: P4Type, withArguments arguments: ArgumentList) {
self.name = name
self.tipe = tipe
self.arguments = arguments
}
}
+10 -10
View File
@@ -18,9 +18,9 @@
import Common
public struct KeysetExpression {
public let key: EvaluatableExpression
public let key: P4Expression
public init(_ key: EvaluatableExpression) {
public init(_ key: P4Expression) {
self.key = key
}
@@ -65,11 +65,11 @@ public struct SelectCaseExpression {
}
public struct SelectExpression {
public let selector: EvaluatableExpression
public let selector: P4Expression
public let case_expressions: [SelectCaseExpression]
public init(
withSelector selector: EvaluatableExpression,
withSelector selector: P4Expression,
withSelectCaseExpressions sces: [SelectCaseExpression]
) {
self.selector = selector
@@ -105,13 +105,13 @@ public struct BinaryOperatorExpression {
}
public struct ArrayAccessExpression {
public let indexor: EvaluatableExpression
public let name: EvaluatableExpression
public let indexor: P4Expression
public let name: P4Expression
public let type: P4Array
public init(
withName name: EvaluatableExpression, withType type: P4Array,
withIndexor indexor: EvaluatableExpression
withName name: P4Expression, withType type: P4Array,
withIndexor indexor: P4Expression
) {
self.name = name
self.type = type
@@ -121,9 +121,9 @@ public struct ArrayAccessExpression {
public struct FieldAccessExpression {
public let field: P4StructFieldIdentifier
public let strct: EvaluatableExpression
public let strct: P4Expression
public init(withStruct strct: EvaluatableExpression, withField field: P4StructFieldIdentifier) {
public init(withStruct strct: P4Expression, withField field: P4StructFieldIdentifier) {
self.strct = strct
self.field = field
}
+10 -13
View File
@@ -22,11 +22,11 @@ public struct LocalElements {}
public struct LocalElement {}
public struct ParserAssignmentStatement {
public let lvalue: EvaluatableLValueExpression
public let value: EvaluatableExpression
public let lvalue: P4LValueExpression
public let value: P4Expression
public init(
withLValue lvalue: EvaluatableLValueExpression, withValue value: EvaluatableExpression
withLValue lvalue: P4LValueExpression, withValue value: P4Expression
) {
self.lvalue = lvalue
self.value = value
@@ -34,12 +34,9 @@ public struct ParserAssignmentStatement {
}
/// A P4 Parser State
///
/// Note: A P4 Parser State is both a type and a value.
/// This "bare" parser state represents the state more as a type than a value.
public class ParserState: P4Type, Equatable, CustomStringConvertible {
let name: Identifier
public let statements: [EvaluatableStatement]
public let statements: [P4Statement]
public static func == (lhs: ParserState, rhs: ParserState) -> Bool {
return lhs.eq(rhs: rhs)
@@ -60,12 +57,12 @@ public class ParserState: P4Type, Equatable, CustomStringConvertible {
return self.name
}
public func getStatements() -> [EvaluatableStatement] {
public func getStatements() -> [P4Statement] {
return self.statements
}
/// Construct a ParserState
public init(_ name: Identifier, _ statements: [EvaluatableStatement] = Array()) {
public init(_ name: Identifier, _ statements: [P4Statement] = Array()) {
self.name = name
self.statements = statements
}
@@ -100,7 +97,7 @@ public class ParserStateDirectTransition: ParserState {
/// Construct a ParserState
public init(
name: Identifier, withNextState next_state: InstantiatedParserState,
withStatements stmts: [EvaluatableStatement] = Array(),
withStatements stmts: [P4Statement] = Array(),
) {
self.next_state = next_state
self.next_state_identifier = .none
@@ -109,7 +106,7 @@ public class ParserStateDirectTransition: ParserState {
public init(
name: Identifier, withNextStateIdentifier next_state_id: Identifier,
withStatements stmts: [EvaluatableStatement] = Array(),
withStatements stmts: [P4Statement] = Array(),
) {
self.next_state = .none
self.next_state_identifier = next_state_id
@@ -129,7 +126,7 @@ public class ParserStateDirectTransition: ParserState {
public class ParserStateNoTransition: ParserState {
/// Construct a ParserState
public init(
name: Identifier, withStatements stmts: [EvaluatableStatement] = Array(),
name: Identifier, withStatements stmts: [P4Statement] = Array(),
) {
super.init(name, stmts)
}
@@ -145,7 +142,7 @@ public class ParserStateSelectTransition: ParserState {
public init(
name: Identifier, withTransitionExpression te: SelectExpression,
withStatements stmts: [EvaluatableStatement] = Array()
withStatements stmts: [P4Statement] = Array()
) {
self.te = te
super.init(name, stmts)
+2 -2
View File
@@ -18,9 +18,9 @@
import Common
public struct ExpressionStatement {
public let expression: EvaluatableExpression
public let expression: P4Expression
public init(_ expr: EvaluatableExpression) {
public init(_ expr: P4Expression) {
self.expression = expr
}
}
+95
View File
@@ -0,0 +1,95 @@
// 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
public protocol Visitable {
}
public protocol LanguageVisitor<Context> {
associatedtype Context
// Program
func visit(_ program: Program, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
// Parser
func visit(_ parser: Parser, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ parser_state: InstantiatedParserState, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Statements
func visit(
_ variable_declaration: VariableDeclarationStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ conditional: ConditionalStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ block: BlockStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ rtn: ReturnStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ apply: ApplyStatement, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Expressions
func visit(
_ keyset: KeysetExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ select_case: SelectCaseExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ select: SelectExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ array_access: ArrayAccessExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ field_access: FieldAccessExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ function_call: FunctionCall, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ binary_operator: BinaryOperatorExpression, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Declarations
func visit(_ decl: Declaration, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ extern_decl: ExternDeclaration, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ func_decl: FunctionDeclaration, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
// Control
func visit(_ action: Action, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(
_ table_key_entry: TableKeyEntry, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(
_ table_property_list: TablePropertyList, _ c: VisitorContext<Context>
) -> Result<VisitorContext<Context>>
func visit(_ table: Table, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
func visit(_ control: Control, _ c: VisitorContext<Context>) -> Result<VisitorContext<Context>>
}
+13 -13
View File
@@ -20,28 +20,28 @@ import Common
public struct Statement {}
public struct VariableDeclarationStatement {
public var initializer: EvaluatableExpression
public var identifier: Identifier
public init(identifier: Identifier, withInitializer initializer: EvaluatableExpression) {
public var initializer: P4Expression
public var identifier: TypedIdentifier
public init(identifier: TypedIdentifier, withInitializer initializer: P4Expression) {
self.identifier = identifier
self.initializer = initializer
}
}
public struct ConditionalStatement {
public var condition: EvaluatableExpression
public var thenn: EvaluatableStatement
public var elss: EvaluatableStatement?
public var condition: P4Expression
public var thenn: P4Statement
public var elss: P4Statement?
public init(condition: EvaluatableExpression, withThen thenn: EvaluatableStatement) {
public init(condition: P4Expression, withThen thenn: P4Statement) {
self.condition = condition
self.thenn = thenn
self.elss = .none
}
public init(
condition: EvaluatableExpression, withThen thenn: EvaluatableStatement,
andElse elss: EvaluatableStatement
condition: P4Expression, withThen thenn: P4Statement,
andElse elss: P4Statement
) {
self.condition = condition
self.thenn = thenn
@@ -50,18 +50,18 @@ public struct ConditionalStatement {
}
public struct BlockStatement {
public var statements: [EvaluatableStatement]
public var statements: [P4Statement]
public init(_ statements: [EvaluatableStatement]) {
public init(_ statements: [P4Statement]) {
self.statements = statements
}
}
public struct ReturnStatement {
public let value: EvaluatableExpression
public let value: P4Expression
public init(_ value: EvaluatableExpression) {
public init(_ value: P4Expression) {
self.value = value
}
}
+1 -1
View File
@@ -58,7 +58,7 @@ public func Call<T>(
param_direction == Direction.InOut || param_direction == Direction.Out
{
// Let's make sure that it is an evaluatable l value!
guard let arg_lvalue = argument.argument as? EvaluatableLValueExpression else {
guard let arg_lvalue = argument.argument as? P4LValueExpression else {
return (
.Error(Error(withMessage: "(in)out parameter argument is not lvalue")),
updated_execution.exit_scope()
+6 -2
View File
@@ -91,10 +91,14 @@ extension Control: LibraryCallable {
}
}
extension Action: EvaluatableStatement {
extension Action: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(
execution: Common.ProgramExecution
) -> (Common.ControlFlow, Common.ProgramExecution) {
) -> (ControlFlow, Common.ProgramExecution) {
if let body = self.body {
return body.evaluate(execution: execution)
}
+134 -108
View File
@@ -22,88 +22,11 @@ extension SelectCaseExpression: EvaluatableExpression {
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
return (execution.scopes.lookup(identifier: next_state_identifier), execution)
}
public func type() -> P4QualifiedType {
return P4QualifiedType(AnyParserState)
}
}
extension SelectExpression: EvaluatableExpression {
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
switch execution.evaluator.EvaluateExpression(self.selector, inExecution: execution) {
case (.Ok(let selector_value), let updated_execution):
for sce in self.case_expressions {
if case (.Ok(let kse), let updated_execution) = updated_execution.evaluator
.EvaluateExpression(
sce.key, inExecution: updated_execution),
kse.eq(selector_value)
{
//let result = sce.evaluate(execution: updated_execution)
let result = updated_execution.evaluator.EvaluateExpression(
sce, inExecution: updated_execution)
return result
}
}
return (.Error(Error(withMessage: "No key matched the selector")), updated_execution)
case (.Error(let e), let updated_execution): return (.Error(e), updated_execution)
}
}
public func type() -> P4QualifiedType {
return P4QualifiedType(AnyParserState)
}
}
// Variables are evaluatable because they can be looked up by identifiers.
extension TypedIdentifier: EvaluatableExpression {
public func type() -> P4QualifiedType {
return self.type
}
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
return (execution.scopes.lookup(identifier: self), execution)
}
}
// Variables are evaluatable because they can be looked up by identifiers.
extension TypedIdentifier: EvaluatableLValueExpression {
public func set(
to: P4Value, inScopes scopes: Common.VarValueScopes,
duringExecution execution: ProgramExecution
) -> Common.Result<(Common.VarValueScopes, P4Value)> {
if case .Error(let e) = scopes.lookup(identifier: self) {
return .Error(e)
}
return .Ok((scopes.set(identifier: self, withValue: to), to))
}
public func check(
to: any Common.EvaluatableExpression, inScopes scopes: Common.StaticVarValueScopes
) -> Result<()> {
guard case .Ok(let type) = scopes.lookup(identifier: self) else {
return .Error(Error(withMessage: "Cannot assign to identifier not in scope"))
}
return switch type.0.assignableFromType(to.type()) {
case TypeCheckResults.IncompatibleTypes:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) with type \(type.0)"))
case TypeCheckResults.ReadOnly:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) that is read only"))
case TypeCheckResults.WrongDirection:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) that is in parameter")
)
case TypeCheckResults.Ok: .Ok(())
}
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
}
@@ -186,7 +109,7 @@ public func binary_divide_operator_evaluator(left: P4Value, right: P4Value) -> P
}
// swift-format-ignore
public typealias BinaryOperatorChecker = (EvaluatableExpression, EvaluatableExpression) -> Result<()>
public typealias BinaryOperatorChecker = (EvaluatableExpression, P4Expression) -> Result<()>
public func binary_and_or_operator_checker(
left: EvaluatableExpression, right: EvaluatableExpression
@@ -211,6 +134,10 @@ public func binary_int_math_operator_checker(
}
extension BinaryOperatorExpression: EvaluatableExpression {
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
let updated_execution = execution
//let maybe_evaluated_left = self.left.evaluate(execution: updated_execution)
@@ -235,7 +162,11 @@ extension BinaryOperatorExpression: EvaluatableExpression {
}
}
extension ArrayAccessExpression: EvaluatableExpression {
extension ArrayAccessExpression: EvaluatableExpression, EvaluatableLValueExpression {
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
let updated_execution = execution
//let maybe_name = self.name.evaluate(execution: updated_execution)
@@ -267,9 +198,7 @@ extension ArrayAccessExpression: EvaluatableExpression {
public func type() -> P4QualifiedType {
return self.type.value_type()
}
}
extension ArrayAccessExpression: EvaluatableLValueExpression {
public func set(
to: P4Value, inScopes scopes: Common.VarValueScopes,
duringExecution execution: ProgramExecution
@@ -352,35 +281,13 @@ extension ArrayAccessExpression: EvaluatableLValueExpression {
}
}
extension FieldAccessExpression: EvaluatableExpression {
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
let updated_execution = execution
//let maybe_struct = self.strct.evaluate(execution: updated_execution)
let maybe_struct = updated_execution.evaluator.EvaluateExpression(
self.strct, inExecution: updated_execution)
guard case (.Ok(let strct), let updated_execution) = maybe_struct else {
return maybe_struct
}
guard let struct_strct = strct.dataValue() as? P4StructValue else {
return (.Error(Error(withMessage: "\(strct) does not identify a struct")), updated_execution)
}
/// TODO: Create a default value?
guard let value = struct_strct.get(field: self.field) else {
return (.Error(Error(withMessage: "Missing value")), updated_execution)
}
return (.Ok(value), updated_execution)
}
extension FieldAccessExpression: EvaluatableExpression, EvaluatableLValueExpression {
public func type() -> P4QualifiedType {
return self.field.type
}
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
extension FieldAccessExpression: EvaluatableLValueExpression {
public func set(
to: P4Value, inScopes scopes: Common.VarValueScopes,
duringExecution execution: ProgramExecution
@@ -459,9 +366,33 @@ extension FieldAccessExpression: EvaluatableLValueExpression {
default: .Error(Error(withMessage: "Cannot assign to field \(self.field) of \(self.strct)"))
}
}
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
let updated_execution = execution
//let maybe_struct = self.strct.evaluate(execution: updated_execution)
let maybe_struct = updated_execution.evaluator.EvaluateExpression(
self.strct, inExecution: updated_execution)
guard case (.Ok(let strct), let updated_execution) = maybe_struct else {
return maybe_struct
}
guard let struct_strct = strct.dataValue() as? P4StructValue else {
return (.Error(Error(withMessage: "\(strct) does not identify a struct")), updated_execution)
}
/// TODO: Create a default value?
guard let value = struct_strct.get(field: self.field) else {
return (.Error(Error(withMessage: "Missing value")), updated_execution)
}
return (.Ok(value), updated_execution)
}
}
extension KeysetExpression: EvaluatableExpression {
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
//return self.key.evaluate(execution: execution)
return execution.evaluator.EvaluateExpression(self.key, inExecution: execution)
@@ -473,6 +404,10 @@ extension KeysetExpression: EvaluatableExpression {
}
extension FunctionCall: EvaluatableExpression {
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
public func evaluate(
execution: Common.ProgramExecution
) -> (Common.Result<P4Value>, ProgramExecution) {
@@ -533,4 +468,95 @@ extension P4Value: EvaluatableExpression {
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
return (.Ok(self), execution)
}
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
}
extension SelectExpression: EvaluatableExpression {
public func evaluate(execution: ProgramExecution) -> (Result<P4Value>, ProgramExecution) {
switch execution.evaluator.EvaluateExpression(self.selector, inExecution: execution) {
case (.Ok(let selector_value), let updated_execution):
for sce in self.case_expressions {
if case (.Ok(let kse), let updated_execution) = updated_execution.evaluator
.EvaluateExpression(
sce.key, inExecution: updated_execution),
kse.eq(selector_value)
{
//let result = sce.evaluate(execution: updated_execution)
let result = updated_execution.evaluator.EvaluateExpression(
sce, inExecution: updated_execution)
return result
}
}
return (.Error(Error(withMessage: "No key matched the selector")), updated_execution)
case (.Error(let e), let updated_execution): return (.Error(e), updated_execution)
}
}
public func type() -> P4QualifiedType {
return P4QualifiedType(AnyParserState)
}
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
}
// Variables are evaluatable because they can be looked up by identifiers.
extension TypedIdentifier: EvaluatableExpression, EvaluatableLValueExpression {
public func evaluate(
execution: Common.ProgramExecution
) -> (Common.Result<Common.P4Value>, Common.ProgramExecution) {
return (execution.scopes.lookup(identifier: self), execution)
}
public func set(
to: P4Value, inScopes scopes: Common.VarValueScopes,
duringExecution execution: ProgramExecution
) -> Common.Result<(Common.VarValueScopes, P4Value)> {
if case .Error(let e) = scopes.lookup(identifier: self) {
return .Error(e)
}
return .Ok((scopes.set(identifier: self, withValue: to), to))
}
public func type() -> P4QualifiedType {
return self.type
}
public func effect(context: CompilerContext) -> CompilerContext {
return context
}
// Variables are evaluatable because they can be looked up by identifiers.
public func check(
to: P4Expression, inScopes scopes: Common.StaticVarValueScopes
) -> Result<()> {
guard case .Ok(let type) = scopes.lookup(identifier: self) else {
return .Error(Error(withMessage: "Cannot assign to identifier not in scope"))
}
return switch type.0.assignableFromType(to.type()) {
case TypeCheckResults.IncompatibleTypes:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) with type \(type.0)"))
case TypeCheckResults.ReadOnly:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) that is read only"))
case TypeCheckResults.WrongDirection:
.Error(
Error(
withMessage:
"Cannot assign value with type \(to.type()) to identifier \(self) that is in parameter")
)
case TypeCheckResults.Ok: .Ok(())
}
}
}
+21 -1
View File
@@ -18,7 +18,11 @@
import Common
import P4Lang
extension ParserAssignmentStatement: EvaluatableStatement {
extension ParserAssignmentStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
let updated_execution = execution
//let result = self.value.evaluate(execution: updated_execution)
@@ -192,3 +196,19 @@ extension ParserValue: LibraryCallable {
}
}
}
extension ParserState: P4Statement {
public func evaluate(
execution: Common.ProgramExecution
) -> (Common.ControlFlow, Common.ProgramExecution) {
return (
ControlFlow.Error,
execution.setError(error: Error(withMessage: "Cannot evaluate unspecialized parser state"))
)
}
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context.update(
newTypes: context.types.declare(identifier: self.getName(), withValue: self))
}
}
+64 -6
View File
@@ -18,7 +18,11 @@
import Common
import P4Lang
extension BlockStatement: EvaluatableStatement {
extension BlockStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
return execution.evaluator.ExecuteStatements(
self.statements, inExecution: execution
@@ -38,7 +42,14 @@ extension BlockStatement: EvaluatableStatement {
}
}
extension VariableDeclarationStatement: EvaluatableStatement {
extension VariableDeclarationStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context.update(
newInstances: context.instances.declare(
identifier: self.identifier, withValue: (self.identifier.type(), .none)))
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
guard
//case (.Ok(let initial_value), let execution) = self.initializer.evaluate(execution: execution)
@@ -56,7 +67,11 @@ extension VariableDeclarationStatement: EvaluatableStatement {
}
}
extension ConditionalStatement: EvaluatableStatement {
extension ConditionalStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
guard
//case (.Ok(let evaluated_condition), let execution) = self.condition.evaluate(execution: execution)
@@ -105,7 +120,11 @@ extension ConditionalStatement: EvaluatableStatement {
}
}
extension ExpressionStatement: EvaluatableStatement {
extension ExpressionStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
// Evaluate, there might be side effects!
@@ -118,7 +137,12 @@ extension ExpressionStatement: EvaluatableStatement {
}
}
extension ReturnStatement: EvaluatableStatement {
extension ReturnStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
//return switch self.value.evaluate(execution: execution) {
return switch execution.evaluator.EvaluateExpression(self.value, inExecution: execution) {
@@ -128,8 +152,42 @@ extension ReturnStatement: EvaluatableStatement {
}
}
extension ApplyStatement: EvaluatableStatement {
extension ApplyStatement: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
return (ControlFlow.Next, execution)
}
}
extension Instantiation: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
return context
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
return (ControlFlow.Next, execution)
}
}
extension Declaration: P4Statement {
public func effect(context: Common.CompilerContext) -> Common.CompilerContext {
if self.extern {
return context.update(
newExterns: context.externs.declare(
identifier: self.identifier, withValue: self))
}
return context.update(
newTypes: context.types.declare(
identifier: self.identifier, withValue: self.identifier.type().baseType()))
}
public func evaluate(execution: ProgramExecution) -> (ControlFlow, ProgramExecution) {
//// TODO
return (ControlFlow.Next, execution)
}
}
+14 -1
View File
@@ -95,7 +95,7 @@ import P4Lang
let result = try! #require(p.parse(simple))
#expect(
#RequireErrorResult<(EvaluatableStatement, CompilerContext)>(
#RequireErrorResult<ParserAssignmentStatement>(
ErrorWithLocation(sourceLocation: SourceLocation(2, 154), withError: "Did not find assignment statement"),
ParserAssignmentStatement.Compile( // Note: Calling ParserAssignmentStatement compilation directly.
node: result.rootNode!, withContext: CompilerContext())))
@@ -182,3 +182,16 @@ import P4Lang
#expect(#RequireOkResult(SpecialCompilers.ProgramCompiler.Compile(simple)))
}
@Test func test_simple_compiler_with_instantiation() async throws {
let simple_instantiation_program = """
parser MainParser() {
state start {
transition accept;
}
};
MainParser() mp;
"""
#expect(#RequireOkResult(SpecialCompilers.ProgramCompiler.Compile(simple_instantiation_program)))
}
+1 -1
View File
@@ -68,7 +68,7 @@ export default grammar({
// Instantiation
instantiation: $ => seq($.typeRef, '(', optional($.parameter_list), ')', $.identifier),
instantiation: $ => seq($.typeRef, $.arguments, $.identifier),
// Declarations
declaration: $ => seq(choice($.parserDeclaration, $.parserTypeDeclaration, $.type_declaration, $.function_declaration, $.control_declaration, $.extern_declaration)),