compiler, runtime, common: (Initial) Support For extern Declarations
Especially FFI Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
@@ -52,60 +52,111 @@ public func ErrorOnNode(node: Node, withError error: String) -> Error {
|
||||
public struct CompilerContext {
|
||||
let instances: VarTypeScopes
|
||||
let types: TypeTypeScopes
|
||||
let externs: TypeTypeScopes
|
||||
let ffis: [P4FFI]
|
||||
let expected_type: P4Type?
|
||||
let extern_context: Bool
|
||||
|
||||
public init(withInstances _instances: VarTypeScopes) {
|
||||
instances = _instances
|
||||
types = TypeTypeScopes()
|
||||
public init() {
|
||||
instances = VarTypeScopes().enter()
|
||||
types = TypeTypeScopes().enter()
|
||||
externs = TypeTypeScopes().enter()
|
||||
expected_type = .none
|
||||
extern_context = false
|
||||
ffis = Array()
|
||||
}
|
||||
|
||||
public init(withInstances _instances: VarTypeScopes, withTypes _types: TypeTypeScopes) {
|
||||
instances = _instances
|
||||
types = _types
|
||||
externs = TypeTypeScopes().enter()
|
||||
expected_type = .none
|
||||
extern_context = false
|
||||
ffis = Array()
|
||||
}
|
||||
|
||||
public init(
|
||||
withInstances _instances: VarTypeScopes, withTypes _types: TypeTypeScopes,
|
||||
withExpectation expectation: P4Type?
|
||||
withExpectation expectation: P4Type?, 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 with the same types and new names.
|
||||
/// 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 with the same types and new names.
|
||||
/// - Returns: A new compiler context based on the current but new instances.
|
||||
public func update(newInstances instances: VarTypeScopes) -> CompilerContext {
|
||||
return CompilerContext(
|
||||
withInstances: instances, withTypes: self.types, withExpectation: self.expected_type)
|
||||
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 with the same names and new types.
|
||||
/// 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 with the same names and new types.
|
||||
/// - 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)
|
||||
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 with the same names and types but new expected type.
|
||||
/// 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 with the same names and types but new expected type.
|
||||
/// - Returns: A new compiler context based on the current but new expected type.
|
||||
public func update(newExpectation expectation: P4Type?) -> CompilerContext {
|
||||
return CompilerContext(
|
||||
withInstances: self.instances, withTypes: self.types, withExpectation: expectation)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,12 +25,13 @@ import TreeSitterP4
|
||||
extension Declaration: CompilableDeclaration {
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<(P4DataType, CompilerContext)?> {
|
||||
) -> Result<(Declaration, CompilerContext)?> {
|
||||
|
||||
let declaration_compilers: [String: CompilableDeclaration.Type] = [
|
||||
"function_declaration": FunctionDeclaration.self,
|
||||
"control_declaration": Control.self,
|
||||
"type_declaration": StructDeclaration.self, // ASSUME: Type declarations are struct declarations.
|
||||
"type_declaration": P4Struct.self, // ASSUME: Type declarations are struct declarations.
|
||||
"extern_declaration": ExternDeclaration.self,
|
||||
]
|
||||
|
||||
guard let declaration_compiler = declaration_compilers[node.nodeType!] else {
|
||||
@@ -44,7 +45,7 @@ extension Declaration: CompilableDeclaration {
|
||||
extension FunctionDeclaration: CompilableDeclaration {
|
||||
public static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<(any Common.P4DataType, CompilerContext)?> {
|
||||
) -> Common.Result<(Declaration, CompilerContext)?> {
|
||||
let function_declaration_node = node
|
||||
#RequireNodeType<Node, (ParameterList, CompilerContext)>(
|
||||
node: function_declaration_node, type: "function_declaration",
|
||||
@@ -96,52 +97,69 @@ extension FunctionDeclaration: CompilableDeclaration {
|
||||
}
|
||||
context = updated_context
|
||||
|
||||
var function_body: BlockStatement? = .none
|
||||
|
||||
currentChildIdx += 1
|
||||
currentChildIdxSafe += 1
|
||||
if function_declaration_node.childCount < currentChildIdxSafe {
|
||||
return Result.Error(
|
||||
ErrorOnNode(
|
||||
node: function_declaration_node, withError: "Missing function declaration component"))
|
||||
}
|
||||
currentChild = function_declaration_node.child(at: currentChildIdx)
|
||||
if currentChildIdxSafe <= function_declaration_node.childCount {
|
||||
currentChild = function_declaration_node.child(at: currentChildIdx)
|
||||
|
||||
// Add the parameters into scope.
|
||||
var function_scope = context.instances.enter()
|
||||
for parameter in function_parameters.parameters {
|
||||
function_scope = function_scope.declare(
|
||||
identifier: parameter.name, withValue: parameter.type)
|
||||
// Add the parameters into scope.
|
||||
var function_scope = context.instances.enter()
|
||||
for parameter in function_parameters.parameters {
|
||||
function_scope = function_scope.declare(
|
||||
identifier: parameter.name, withValue: parameter.type)
|
||||
}
|
||||
|
||||
let maybe_function_body = BlockStatement.Compile(
|
||||
node: currentChild!,
|
||||
withContext: context.update(newInstances: function_scope).update(
|
||||
newExpectation: function_type))
|
||||
|
||||
guard case .Ok((let parsed_function_body, _)) = maybe_function_body else {
|
||||
return .Error(maybe_function_body.error()!)
|
||||
}
|
||||
function_body = (parsed_function_body as! BlockStatement)
|
||||
} else {
|
||||
|
||||
// If we are in an extern context, no body is okay!
|
||||
|
||||
if !context.extern_context {
|
||||
return Result.Error(
|
||||
ErrorOnNode(
|
||||
node: function_declaration_node, withError: "Missing function declaration component"))
|
||||
}
|
||||
}
|
||||
|
||||
let maybe_function_body = Parser.Statement.Compile(
|
||||
node: currentChild!,
|
||||
withContext: context.update(newInstances: function_scope).update(
|
||||
newExpectation: function_type))
|
||||
guard case .Ok((let function_body, _)) = maybe_function_body else {
|
||||
return .Error(maybe_function_body.error()!)
|
||||
}
|
||||
|
||||
let function_declaration = FunctionDeclaration(
|
||||
named: function_name, ofType: function_type, withParameters: function_parameters,
|
||||
withBody: function_body)
|
||||
let function_declaration = Declaration(
|
||||
TypedIdentifier(
|
||||
id: function_name,
|
||||
withType: P4Type(
|
||||
FunctionDeclaration(
|
||||
named: function_name, ofType: function_type, withParameters: function_parameters,
|
||||
withBody: function_body))))
|
||||
|
||||
// Do not use the updated context returned by parsing the body
|
||||
// and do not use the function_scope, either.
|
||||
// And, do not update the context if we are compiling in an
|
||||
// extern context.
|
||||
return .Ok(
|
||||
(
|
||||
function_declaration,
|
||||
context.update(
|
||||
newTypes: context.types.declare(
|
||||
identifier: function_name, withValue: function_declaration))
|
||||
context.extern_context
|
||||
? context
|
||||
: context.update(
|
||||
newTypes: context.types.declare(
|
||||
identifier: function_name, withValue: function_declaration.identifier.type.dataType())
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
struct StructDeclaration {}
|
||||
|
||||
extension StructDeclaration: CompilableDeclaration {
|
||||
static func Compile(
|
||||
extension P4Struct: CompilableDeclaration {
|
||||
static public func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<(P4DataType, CompilerContext)?> {
|
||||
) -> Result<(Declaration, CompilerContext)?> {
|
||||
|
||||
let struct_declaration_node = node.child(at: 0)!
|
||||
var currentChildIdx = 0
|
||||
@@ -195,12 +213,18 @@ extension StructDeclaration: CompilableDeclaration {
|
||||
|
||||
// If there are no fields, it will be a "}"
|
||||
if currentChild!.nodeType == "}" {
|
||||
let struc = P4Struct(withName: struct_identifier, andFields: P4StructFields([]))
|
||||
let struc = Declaration(
|
||||
TypedIdentifier(
|
||||
id: struct_identifier,
|
||||
withType: P4Type(P4Struct(withName: struct_identifier, andFields: P4StructFields([])))))
|
||||
return Result.Ok(
|
||||
(
|
||||
struc,
|
||||
context.update(
|
||||
newTypes: context.types.declare(identifier: struct_identifier, withValue: struc))
|
||||
context.extern_context
|
||||
? context
|
||||
: context.update(
|
||||
newTypes: context.types.declare(
|
||||
identifier: struct_identifier, withValue: struc.identifier.type.dataType()))
|
||||
))
|
||||
}
|
||||
|
||||
@@ -234,14 +258,20 @@ extension StructDeclaration: CompilableDeclaration {
|
||||
}.joined(separator: ";"))))
|
||||
}
|
||||
|
||||
let declared_struct = P4Struct(
|
||||
withName: struct_identifier, andFields: P4StructFields(parsed_fields))
|
||||
let declared_struct = Declaration(
|
||||
TypedIdentifier(
|
||||
id: struct_identifier,
|
||||
withType: P4Type(
|
||||
P4Struct(
|
||||
withName: struct_identifier, andFields: P4StructFields(parsed_fields)))))
|
||||
return .Ok(
|
||||
(
|
||||
declared_struct,
|
||||
current_context.update(
|
||||
newTypes: current_context.types.declare(
|
||||
identifier: struct_identifier, withValue: declared_struct))
|
||||
current_context.extern_context
|
||||
? current_context
|
||||
: current_context.update(
|
||||
newTypes: current_context.types.declare(
|
||||
identifier: struct_identifier, withValue: declared_struct.identifier.type.dataType()))
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -249,7 +279,7 @@ extension StructDeclaration: CompilableDeclaration {
|
||||
extension P4Lang.Parser: CompilableDeclaration {
|
||||
public static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<(P4DataType, CompilerContext)?> {
|
||||
) -> Result<(Declaration, CompilerContext)?> {
|
||||
let parser_node = node
|
||||
#SkipUnlessNodeType<Node, (P4DataType, CompilerContext)?>(
|
||||
node: parser_node, type: "parserDeclaration")
|
||||
@@ -369,13 +399,17 @@ extension P4Lang.Parser: CompilableDeclaration {
|
||||
withContext: current_context)
|
||||
{
|
||||
case Result.Ok((let parser, let updated_context)):
|
||||
let parser_declaration = Declaration(
|
||||
TypedIdentifier(id: parser.name, withType: P4Type(parser)))
|
||||
// Create a new context with the name of the parser that was just compiled in scope.
|
||||
return .Ok(
|
||||
(
|
||||
parser,
|
||||
context.update(
|
||||
newInstances: updated_context.instances.declare(
|
||||
identifier: parser.name, withValue: P4Type(parser)))
|
||||
parser_declaration,
|
||||
context.extern_context
|
||||
? context
|
||||
: context.update(
|
||||
newInstances: updated_context.instances.declare(
|
||||
identifier: parser.name, withValue: parser_declaration.identifier.type))
|
||||
))
|
||||
case Result.Error(let error): return .Error(error)
|
||||
}
|
||||
@@ -385,7 +419,7 @@ extension P4Lang.Parser: CompilableDeclaration {
|
||||
extension Control: CompilableDeclaration {
|
||||
public static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<(any Common.P4DataType, CompilerContext)?> {
|
||||
) -> Common.Result<(Declaration, CompilerContext)?> {
|
||||
|
||||
#SkipUnlessNodeType<Node, (P4DataType, CompilerContext)?>(
|
||||
node: node, type: "control_declaration")
|
||||
@@ -516,19 +550,24 @@ extension Control: CompilableDeclaration {
|
||||
}
|
||||
|
||||
let declared_control =
|
||||
(Control(
|
||||
named: control_name, withParameters: control_parameters, withTable: tables[0],
|
||||
withActions: Actions(withActions: actions), withApply: apply)
|
||||
as P4DataType)
|
||||
Declaration(
|
||||
TypedIdentifier(
|
||||
id: control_name,
|
||||
withType: P4Type(
|
||||
Control(
|
||||
named: control_name, withParameters: control_parameters, withTable: tables[0],
|
||||
withActions: Actions(withActions: actions), withApply: apply))))
|
||||
|
||||
// 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.update(
|
||||
newInstances: context.instances.declare(
|
||||
identifier: control_name, withValue: P4Type(declared_control)))
|
||||
context.extern_context
|
||||
? context
|
||||
: context.update(
|
||||
newInstances: context.instances.declare(
|
||||
identifier: control_name, withValue: declared_control.identifier.type))
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -823,3 +862,54 @@ extension Table: Compilable {
|
||||
(Table(withName: table_name, withPropertyList: table_property_list), current_context))
|
||||
}
|
||||
}
|
||||
|
||||
extension ExternDeclaration: CompilableDeclaration {
|
||||
public static func Compile(
|
||||
node: SwiftTreeSitter.Node, withContext context: CompilerContext
|
||||
) -> Common.Result<(Declaration, CompilerContext)?> {
|
||||
let extern_declaration_node = node
|
||||
#RequireNodeType<Node, (Declaration, CompilerContext)>(
|
||||
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)>(
|
||||
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 {
|
||||
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".
|
||||
|
||||
let found_ffi = context.ffis.first { ffi in
|
||||
ffi.type().dataType().eq(rhs: declared.identifier.type.dataType())
|
||||
}
|
||||
|
||||
guard let found_ffi = found_ffi else {
|
||||
return .Error(
|
||||
ErrorOnNode(
|
||||
node: declarationed_node,
|
||||
withError:
|
||||
"Could not find a foreign function that matches the extern declaration (\(declared))"))
|
||||
}
|
||||
|
||||
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))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,6 +670,7 @@ extension FunctionCall: CompilableExpression {
|
||||
static func compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<EvaluatableExpression?> {
|
||||
|
||||
let expression = node.child(at: 0)!
|
||||
#SkipUnlessNodeType<Node, EvaluatableExpression?>(
|
||||
node: expression, type: "function_call")
|
||||
@@ -691,16 +692,33 @@ extension FunctionCall: CompilableExpression {
|
||||
return Result.Error(maybe_callee_name.error()!)
|
||||
}
|
||||
|
||||
let maybe_callee =
|
||||
var maybe_callee: Result<(FunctionDeclaration?, Declaration?)> =
|
||||
switch context.types.lookup(identifier: callee_name) {
|
||||
case .Ok(let looked_up):
|
||||
switch looked_up {
|
||||
case let callee as FunctionDeclaration: Result.Ok(callee) // What we found is actually a function declaration
|
||||
case let callee as FunctionDeclaration:
|
||||
Result<(FunctionDeclaration?, Declaration?)>.Ok((callee, .none)) // What we found is actually a function declaration
|
||||
default:
|
||||
Result<FunctionDeclaration>.Error(
|
||||
Result<(FunctionDeclaration?, Declaration?)>.Error(
|
||||
ErrorOnNode(node: currentChild!, withError: "\(callee_name) is not a function"))
|
||||
}
|
||||
case .Error(let e): Result<FunctionDeclaration>.Error(e)
|
||||
case .Error(let e): Result<(FunctionDeclaration?, Declaration?)>.Error(e)
|
||||
}
|
||||
|
||||
maybe_callee =
|
||||
if case .Error(let e) = maybe_callee {
|
||||
switch context.externs.lookup(identifier: callee_name) {
|
||||
case .Ok(let callee as Declaration):
|
||||
// Now, make sure that it is a function declaration!
|
||||
switch callee.identifier.type.dataType() {
|
||||
case is FunctionDeclaration: Result.Ok((.none, callee))
|
||||
default:
|
||||
.Error(ErrorOnNode(node: currentChild!, withError: "\(callee_name) is not a function"))
|
||||
}
|
||||
default: .Error(e)
|
||||
}
|
||||
} else {
|
||||
maybe_callee
|
||||
}
|
||||
|
||||
guard case .Ok(let callee) = maybe_callee else {
|
||||
@@ -723,12 +741,35 @@ extension FunctionCall: CompilableExpression {
|
||||
|
||||
// Now, compare the arguments with the parameters:
|
||||
|
||||
if case .Error(let e) = arguments.compatible(callee.params) {
|
||||
let params =
|
||||
switch callee {
|
||||
case (.some(let callee), .none): Optional<ParameterList>.some(callee.params)
|
||||
case (.none, .some(let callee)):
|
||||
Optional<ParameterList>.some((callee.ffi!.type().dataType() as! FunctionDeclaration).params)
|
||||
default: Optional<ParameterList>.none
|
||||
}
|
||||
|
||||
guard case .some(let params) = params else {
|
||||
return Result.Error(
|
||||
ErrorOnNode(
|
||||
node: node,
|
||||
withError: "Could not lookup the parameters for the called function (\(callee_name))"))
|
||||
}
|
||||
|
||||
if case .Error(let e) = arguments.compatible(params) {
|
||||
return .Error(e)
|
||||
}
|
||||
|
||||
// All good!
|
||||
|
||||
return .Ok(FunctionCall(callee, withArguments: arguments))
|
||||
return switch callee {
|
||||
case (.some(let callee), .none): .Ok(FunctionCall(callee, withArguments: arguments))
|
||||
case (.none, .some(let callee)): .Ok(FunctionCall(callee.ffi!, withArguments: arguments))
|
||||
default:
|
||||
Result.Error(
|
||||
ErrorOnNode(
|
||||
node: node, withError: "Unexpected error occurred calling function named (\(callee_name))"
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,18 +24,19 @@ import TreeSitterP4
|
||||
|
||||
public struct Program {
|
||||
public static func Compile(_ source: String) -> Result<P4Lang.Program> {
|
||||
return Program.Compile(source, withGlobalInstances: .none, withGlobalTypes: .none)
|
||||
return Program.Compile(source, withGlobalInstances: .none, withGlobalTypes: .none, withFFIs: [])
|
||||
}
|
||||
|
||||
public static func Compile(
|
||||
_ source: String, withGlobalInstances globalInstances: VarTypeScopes
|
||||
) -> Result<P4Lang.Program> {
|
||||
return Program.Compile(source, withGlobalInstances: globalInstances, withGlobalTypes: .none)
|
||||
return Program.Compile(
|
||||
source, withGlobalInstances: globalInstances, withGlobalTypes: .none, withFFIs: [])
|
||||
}
|
||||
|
||||
public static func Compile(
|
||||
_ source: String, withGlobalInstances globalInstances: VarTypeScopes?,
|
||||
withGlobalTypes globalTypes: TypeTypeScopes?
|
||||
withGlobalTypes globalTypes: TypeTypeScopes?, withFFIs ffis: [P4FFI] = Array()
|
||||
) -> Result<P4Lang.Program> {
|
||||
|
||||
let maybe_parser = ConfigureP4Parser()
|
||||
@@ -54,8 +55,10 @@ public struct Program {
|
||||
var program = P4Lang.Program()
|
||||
|
||||
// Set up a context for parsing.
|
||||
var compilation_context = CompilerContext(
|
||||
withInstances: VarTypeScopes().enter(), withTypes: TypeTypeScopes().enter())
|
||||
var compilation_context = CompilerContext()
|
||||
|
||||
// Add our FFIs
|
||||
compilation_context = compilation_context.update(newFFIs: ffis)
|
||||
|
||||
var errors: [Error] = Array()
|
||||
|
||||
@@ -120,6 +123,13 @@ public struct Program {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,13 @@ public protocol CompilableType {
|
||||
}
|
||||
|
||||
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(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<(P4DataType, CompilerContext)?>
|
||||
) -> Result<(Declaration, CompilerContext)?>
|
||||
}
|
||||
|
||||
public protocol Compilable<T> {
|
||||
|
||||
Reference in New Issue
Block a user