@@ -16,22 +16,14 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import Common
|
||||
import P4Lang
|
||||
import P4Runtime
|
||||
import SwiftTreeSitter
|
||||
import TreeSitterExtensions
|
||||
import TreeSitterP4
|
||||
|
||||
protocol AnyCompilable {
|
||||
static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<(Any, CompilerContext)>
|
||||
}
|
||||
|
||||
extension TransitionStatement: Compilable {
|
||||
extension AST.TransitionStatement: Compilable {
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<ParserState> {
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<AST.AnState> {
|
||||
|
||||
guard let state_identifier = context.lexical_context_name else {
|
||||
return .Error(
|
||||
@@ -71,51 +63,27 @@ extension TransitionStatement: Compilable {
|
||||
|
||||
// If the next node is an identifier, we have the simple form ...
|
||||
if next_node.nodeType == "identifier" {
|
||||
let maybe_parsed_next_state_id = Identifier.Compile(
|
||||
let maybe_parsed_next_state_id = AST.Identifier.CompileExpression(
|
||||
node: next_node, withContext: context)
|
||||
if case .Ok(let next_state_id) = maybe_parsed_next_state_id {
|
||||
if case .Ok(let next_state) = context.instances.lookup(identifier: next_state_id) {
|
||||
switch next_state {
|
||||
case (_, .some(let instance)):
|
||||
return .Ok(
|
||||
ParserStateDirectTransition(
|
||||
name: state_identifier,
|
||||
withNextState: instance.dataValue() as! InstantiatedParserState,
|
||||
withStatements: stmts,
|
||||
)
|
||||
)
|
||||
case (_, .none):
|
||||
return .Ok(
|
||||
ParserStateDirectTransition(
|
||||
name: state_identifier,
|
||||
withNextStateIdentifier: next_state_id, withStatements: stmts)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
||||
return .Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"\(next_state_id) does not name a parser state in scope"
|
||||
))
|
||||
}
|
||||
} else {
|
||||
return .Error(
|
||||
Error(
|
||||
withMessage:
|
||||
"Could not parse the next state in a transition statement: \(maybe_parsed_next_state_id.error()!)"
|
||||
))
|
||||
switch maybe_parsed_next_state_id {
|
||||
case .Ok(let next_state_id):
|
||||
return .Ok(
|
||||
AST.ParserStateDirectTransition(
|
||||
name: (state_identifier),
|
||||
withNextStateIdentifier: next_state_id as! AST.Identifier, withStatements: stmts))
|
||||
case .Error(let e):
|
||||
return .Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
// We know that the next node is a select expression.
|
||||
return
|
||||
switch SelectExpression.compile(node: next_node, withContext: context)
|
||||
switch AST.SelectExpression.CompileExpression(node: next_node, withContext: context)
|
||||
{
|
||||
case .Ok(let tse):
|
||||
.Ok(
|
||||
ParserStateSelectTransition(
|
||||
name: state_identifier, withTransitionExpression: tse as! SelectExpression,
|
||||
AST.ParserStateSelectTransition(
|
||||
name: state_identifier, withTransitionExpression: tse as! AST.SelectExpression,
|
||||
withStatements: stmts,
|
||||
)
|
||||
)
|
||||
@@ -127,8 +95,8 @@ extension TransitionStatement: Compilable {
|
||||
public struct SpecialCompilers {
|
||||
public struct Statements {
|
||||
static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<[P4Statement]> {
|
||||
node: Node, withContext context: ASTCompilerContext
|
||||
) -> Result<[AST.AnStatement]> {
|
||||
if node.nodeType != "statements" && node.nodeType != "parserStatements" {
|
||||
return Result.Error(
|
||||
ErrorWithLocation(
|
||||
@@ -136,16 +104,14 @@ public struct SpecialCompilers {
|
||||
}
|
||||
|
||||
var errors: (any Errorable)? = .none
|
||||
var current_context = context
|
||||
var parsed_s: [P4Statement] = Array()
|
||||
var parsed_s: [AST.AnStatement] = Array()
|
||||
|
||||
node.enumerateNamedChildren { node in
|
||||
switch Statement.Compile(
|
||||
node: node, withContext: current_context)
|
||||
switch AST.Statement.Compile(
|
||||
node: node, withContext: 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 {
|
||||
@@ -162,28 +128,18 @@ public struct SpecialCompilers {
|
||||
|
||||
return Result.Ok(parsed_s)
|
||||
}
|
||||
|
||||
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> {
|
||||
withName name: AST.Identifier, withParameters parameters: AST.ParameterList, node: Node,
|
||||
withContext context: ASTCompilerContext
|
||||
) -> Result<AST.Parser> {
|
||||
|
||||
var parser = P4Lang.Parser(withName: name, withParameters: parameters)
|
||||
var parser = AST.Parser(withName: name, withParameters: parameters)
|
||||
|
||||
// Build a state from each one listed.
|
||||
var error: (any Errorable)? = .none
|
||||
var errors: (any Errorable)? = .none
|
||||
|
||||
var current_context = context
|
||||
/// TODO: Assert that there is only one.
|
||||
node.enumerateNamedChildren { parser_state in
|
||||
if parser_state.nodeType != "parserState" {
|
||||
@@ -191,53 +147,32 @@ public struct SpecialCompilers {
|
||||
}
|
||||
|
||||
// Parse a state in a nested scope.
|
||||
switch ParserState.Compile(
|
||||
switch AST.ParserState.Compile(
|
||||
node: parser_state,
|
||||
withContext: context.update(newInstances: current_context.instances.enter()))
|
||||
withContext: context)
|
||||
{
|
||||
case Result.Ok(let state):
|
||||
let statement = state as P4Statement
|
||||
current_context = statement.effect(context: current_context)
|
||||
// All states are instances inside the parser.
|
||||
parser.states = parser.states.append(state: state)
|
||||
case Result.Error(let e): error = e
|
||||
case Result.Error(let e):
|
||||
errors =
|
||||
if let errors = errors {
|
||||
errors.append(error: e)
|
||||
} else {
|
||||
e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let error = error {
|
||||
return .Error(error)
|
||||
if let errors = errors {
|
||||
return .Error(errors)
|
||||
}
|
||||
|
||||
return Result.Ok(parser)
|
||||
return .Ok(parser)
|
||||
}
|
||||
|
||||
public struct ProgramCompiler {
|
||||
public static func Compile(_ source: String) -> Result<P4Lang.Program> {
|
||||
|
||||
// Certain names are always in scope during compilation.
|
||||
var globals = StaticVarValueScopes().enter()
|
||||
globals = globals.declare(
|
||||
identifier: accept.state().getName(),
|
||||
withValue: (P4QualifiedType(accept.type()), P4Value(accept))
|
||||
)
|
||||
.declare(
|
||||
identifier: reject.state.getName(),
|
||||
withValue: (P4QualifiedType(reject.type()), P4Value(reject)))
|
||||
|
||||
return ProgramCompiler.Compile(
|
||||
source, withGlobalInstances: globals, withGlobalTypes: .none, withFFIs: [])
|
||||
}
|
||||
|
||||
public static func Compile(
|
||||
_ source: String, withGlobalInstances globalInstances: StaticVarValueScopes
|
||||
) -> Result<P4Lang.Program> {
|
||||
return ProgramCompiler.Compile(
|
||||
source, withGlobalInstances: globalInstances, withGlobalTypes: .none, withFFIs: [])
|
||||
}
|
||||
|
||||
public static func Compile(
|
||||
_ source: String, withGlobalInstances globalInstances: StaticVarValueScopes?,
|
||||
withGlobalTypes globalTypes: TypeTypeScopes?, withFFIs ffis: [P4FFI] = Array()
|
||||
) -> Result<P4Lang.Program> {
|
||||
public static func Compile(_ source: String) -> Result<AST.Program> {
|
||||
|
||||
let maybe_parser = ConfigureP4Parser()
|
||||
guard case .Ok(let p) = maybe_parser else {
|
||||
@@ -252,38 +187,25 @@ public struct SpecialCompilers {
|
||||
return Result.Error(Error(withMessage: "Could not compile the P4 program"))
|
||||
}
|
||||
|
||||
var program = P4Lang.Program()
|
||||
var program = AST.Program()
|
||||
|
||||
// Set up a context for parsing.
|
||||
var compilation_context = CompilerContext()
|
||||
|
||||
// Add our FFIs
|
||||
compilation_context = compilation_context.update(newFFIs: ffis)
|
||||
let compilation_context = ASTCompilerContext()
|
||||
|
||||
var errors: (any Errorable)? = .none
|
||||
|
||||
// If the caller gave any global instances, add them here.
|
||||
if let globalInstances = globalInstances {
|
||||
compilation_context = compilation_context.update(newInstances: globalInstances)
|
||||
}
|
||||
|
||||
// If the caller gave any global types, add them here.
|
||||
if let globalTypes = globalTypes {
|
||||
compilation_context = compilation_context.update(newTypes: globalTypes)
|
||||
}
|
||||
|
||||
// Try to parse all top-level declarations.
|
||||
result?.rootNode?.enumerateNamedChildren { (declaration_node: Node) in
|
||||
let declaration_parsers: [String: CompilableStatement.Type] = [
|
||||
"declaration": Declaration.self,
|
||||
"instantiation": Instantiation.self,
|
||||
"declaration": AST.Declaration.self,
|
||||
"instantiation": AST.Instantiation.self,
|
||||
]
|
||||
|
||||
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)
|
||||
program.statements = program.statements + [compiled]
|
||||
case .Error(let e):
|
||||
errors =
|
||||
if let errors = errors {
|
||||
@@ -310,28 +232,8 @@ public struct SpecialCompilers {
|
||||
if let errors = errors {
|
||||
return .Error(errors)
|
||||
}
|
||||
|
||||
// Any of the instances that are in the top-level scope should go into the program!
|
||||
program.instances = Array(
|
||||
compilation_context.instances.filter { (_, v) in
|
||||
v.1 != nil
|
||||
}.map { (_, v) in
|
||||
v.1!
|
||||
})
|
||||
|
||||
// Any of the types that are in the top-level scope should go into the program!
|
||||
program.types = Array(
|
||||
compilation_context.types.map { (_, v) in
|
||||
v
|
||||
})
|
||||
|
||||
// Any of the extern types that are in the top-level scope should go into the program!
|
||||
program.externs = Array(
|
||||
compilation_context.externs.map { (_, v) in
|
||||
v
|
||||
})
|
||||
|
||||
return Result.Ok(program)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user