compiler, language, runtime: Separate Parser Type From Instances
In P4, parsers are considered types. Those parsers are instantiated. The instantiated parsers are values. Previously, gp4 treated a parser type and a parser value as identical. This PR makes that difference clear _and_ sets the stage for the future. TODO: Make the same distinction between control and action types and values. Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
@@ -46,7 +46,7 @@ public func ConfigureP4Parser() -> Result<SwiftTreeSitter.Parser> {
|
||||
/// 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: VarTypeScopes
|
||||
let instances: StaticVarValueScopes
|
||||
let types: TypeTypeScopes
|
||||
let externs: TypeTypeScopes
|
||||
let ffis: [P4FFI]
|
||||
@@ -54,7 +54,7 @@ public struct CompilerContext {
|
||||
let extern_context: Bool
|
||||
|
||||
public init() {
|
||||
instances = VarTypeScopes().enter()
|
||||
instances = StaticVarValueScopes().enter()
|
||||
types = TypeTypeScopes().enter()
|
||||
externs = TypeTypeScopes().enter()
|
||||
expected_type = .none
|
||||
@@ -62,7 +62,7 @@ public struct CompilerContext {
|
||||
ffis = Array()
|
||||
}
|
||||
|
||||
public init(withInstances _instances: VarTypeScopes, withTypes _types: TypeTypeScopes) {
|
||||
public init(withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes) {
|
||||
instances = _instances
|
||||
types = _types
|
||||
externs = TypeTypeScopes().enter()
|
||||
@@ -72,7 +72,7 @@ public struct CompilerContext {
|
||||
}
|
||||
|
||||
public init(
|
||||
withInstances _instances: VarTypeScopes, withTypes _types: TypeTypeScopes,
|
||||
withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes,
|
||||
withExpectation expectation: P4QualifiedType?, withExtern extern: Bool,
|
||||
withExterns externs: TypeTypeScopes, withFFIs foreigns: [P4FFI]
|
||||
) {
|
||||
@@ -90,7 +90,7 @@ public struct CompilerContext {
|
||||
///
|
||||
/// - 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: VarTypeScopes) -> CompilerContext {
|
||||
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)
|
||||
|
||||
@@ -105,7 +105,7 @@ extension FunctionDeclaration: CompilableDeclaration {
|
||||
var function_scope = context.instances.enter()
|
||||
for parameter in function_parameters.parameters {
|
||||
function_scope = function_scope.declare(
|
||||
identifier: parameter.name, withValue: parameter.type)
|
||||
identifier: parameter.name, withValue: (parameter.type, .none))
|
||||
}
|
||||
|
||||
let maybe_function_body = BlockStatement.Compile(
|
||||
@@ -342,7 +342,7 @@ extension P4Lang.Parser: CompilableDeclaration {
|
||||
for parameter in parameter_list.parameters {
|
||||
current_context = current_context.update(
|
||||
newInstances: current_context.instances.declare(
|
||||
identifier: parameter.name, withValue: parameter.type))
|
||||
identifier: parameter.name, withValue: (parameter.type, .none)))
|
||||
}
|
||||
|
||||
walker.next()
|
||||
@@ -380,6 +380,7 @@ extension P4Lang.Parser: CompilableDeclaration {
|
||||
return .Error(Error(withMessage: "Missing parser states in parser declaration"))
|
||||
}
|
||||
|
||||
/// TODO: Handle extern parsers.
|
||||
switch Parser.Compile(
|
||||
withName: parser_name!, withParameters: parameter_list, node: current_node!,
|
||||
withContext: current_context)
|
||||
@@ -392,10 +393,11 @@ extension P4Lang.Parser: CompilableDeclaration {
|
||||
(
|
||||
parser_declaration,
|
||||
context.extern_context
|
||||
? context
|
||||
: context.update(
|
||||
newInstances: updated_context.instances.declare(
|
||||
identifier: parser.name, withValue: parser_declaration.identifier.type))
|
||||
? updated_context.update(
|
||||
newExterns: updated_context.externs.declare(
|
||||
identifier: parser.name, withValue: parser_declaration))
|
||||
: updated_context.update(
|
||||
newTypes: updated_context.types.declare(identifier: parser.name, withValue: parser))
|
||||
))
|
||||
case Result.Error(let error): return .Error(error)
|
||||
}
|
||||
@@ -450,7 +452,7 @@ extension Control: CompilableDeclaration {
|
||||
var control_scope = local_context.instances.enter()
|
||||
for parameter in control_parameters.parameters {
|
||||
control_scope = control_scope.declare(
|
||||
identifier: parameter.name, withValue: parameter.type)
|
||||
identifier: parameter.name, withValue: (parameter.type, .none))
|
||||
}
|
||||
local_context = local_context.update(newInstances: control_scope)
|
||||
|
||||
@@ -543,14 +545,15 @@ extension Control: CompilableDeclaration {
|
||||
))
|
||||
}
|
||||
|
||||
let control = Control(
|
||||
named: control_name, withParameters: control_parameters, withTable: tables[0],
|
||||
withActions: Actions(withActions: actions), withApply: apply)
|
||||
|
||||
let declared_control =
|
||||
Declaration(
|
||||
TypedIdentifier(
|
||||
id: control_name,
|
||||
withType: P4QualifiedType(
|
||||
Control(
|
||||
named: control_name, withParameters: control_parameters, withTable: tables[0],
|
||||
withActions: Actions(withActions: actions), withApply: apply))))
|
||||
withType: P4QualifiedType(control)))
|
||||
|
||||
// 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).
|
||||
@@ -558,10 +561,12 @@ extension Control: CompilableDeclaration {
|
||||
(
|
||||
declared_control,
|
||||
context.extern_context
|
||||
? context
|
||||
? context.update(
|
||||
newTypes: context.externs.declare(
|
||||
identifier: control_name, withValue: declared_control))
|
||||
: context.update(
|
||||
newInstances: context.instances.declare(
|
||||
identifier: control_name, withValue: declared_control.identifier.type))
|
||||
newTypes: context.types.declare(
|
||||
identifier: control_name, withValue: control))
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -638,7 +643,7 @@ extension Action: Compilable {
|
||||
var function_scope = context.instances.enter()
|
||||
for parameter in action_parameters.parameters {
|
||||
function_scope = function_scope.declare(
|
||||
identifier: parameter.name, withValue: parameter.type)
|
||||
identifier: parameter.name, withValue: (parameter.type, .none))
|
||||
}
|
||||
|
||||
let maybe_action_body = BlockStatement.Compile(
|
||||
|
||||
@@ -51,7 +51,8 @@ extension TypedIdentifier: CompilableExpression {
|
||||
sourceLocation: node.toSourceLocation(), withError: "Cannot find \(node.text!) in scope"))
|
||||
}
|
||||
|
||||
return .Ok(TypedIdentifier(name: node.text!, withType: type))
|
||||
/// TODO: If there is a value here, then we can make this a compile-time constant!
|
||||
return .Ok(TypedIdentifier(name: node.text!, withType: type.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ public struct Parser {
|
||||
static func Compile(
|
||||
node: Node, forState state_identifier: Common.Identifier,
|
||||
withStatements stmts: [EvaluatableStatement], withContext context: CompilerContext
|
||||
) -> Result<(InstantiatedParserState, CompilerContext)> {
|
||||
) -> Result<(ParserState, CompilerContext)> {
|
||||
|
||||
#RequireNodeType<Node, (EvaluatableStatement, CompilerContext)>(
|
||||
node: node, type: "parserTransitionStatement", nice_type_name: "parser transition statement"
|
||||
@@ -114,19 +114,40 @@ public struct Parser {
|
||||
|
||||
// If the next node is an identifier, we have the simple form ...
|
||||
if next_node.nodeType == "identifier" {
|
||||
let maybe_parsed_next_state = Identifier.Compile(
|
||||
let maybe_parsed_next_state_id = Identifier.Compile(
|
||||
node: next_node, withContext: context)
|
||||
if case .Ok(let next_state) = maybe_parsed_next_state {
|
||||
return .Ok(
|
||||
(
|
||||
ParserStateDirectTransition(
|
||||
name: state_identifier, withStatements: stmts, withNextState: next_state), 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), context
|
||||
))
|
||||
case (_, .none):
|
||||
return .Ok(
|
||||
(
|
||||
ParserStateDirectTransition(
|
||||
name: state_identifier,
|
||||
withNextStateIdentifier: next_state_id, withStatements: stmts), context
|
||||
))
|
||||
}
|
||||
} 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.error()!)"
|
||||
"Could not parse the next state in a transition statement: \(maybe_parsed_next_state_id.error()!)"
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -139,8 +160,9 @@ public struct Parser {
|
||||
.Ok(
|
||||
(
|
||||
ParserStateSelectTransition(
|
||||
name: state_identifier, withStatements: stmts,
|
||||
withTransitioniExpression: tse as! SelectExpression), context
|
||||
name: state_identifier, withTransitionExpression: tse as! SelectExpression,
|
||||
withStatements: stmts,
|
||||
), context
|
||||
))
|
||||
case .Error(let e): .Error(e)
|
||||
}
|
||||
@@ -189,7 +211,7 @@ public struct Parser {
|
||||
public struct State {
|
||||
static func Compile(
|
||||
node: Node, withContext context: CompilerContext
|
||||
) -> Result<(InstantiatedParserState, CompilerContext)> {
|
||||
) -> Result<(ParserState, CompilerContext)> {
|
||||
var walker = Walker(node: node)
|
||||
|
||||
var current_node: Node? = .none
|
||||
@@ -205,7 +227,7 @@ public struct Parser {
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<(InstantiatedParserState, CompilerContext)>.Error(
|
||||
or: Result<(ParserState, CompilerContext)>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing elements in parser state declaration")))
|
||||
@@ -223,7 +245,7 @@ public struct Parser {
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<(InstantiatedParserState, CompilerContext)>.Error(
|
||||
or: Result<(ParserState, CompilerContext)>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing elements in parser state declaration")))
|
||||
@@ -239,7 +261,7 @@ public struct Parser {
|
||||
walker.next()
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<(InstantiatedParserState, CompilerContext)>.Error(
|
||||
or: Result<(ParserState, CompilerContext)>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(), withError: "Missing body of state declaration")
|
||||
))
|
||||
@@ -272,7 +294,7 @@ public struct Parser {
|
||||
|
||||
#MustOr(
|
||||
result: current_node, thing: walker.getNext(),
|
||||
or: Result<(InstantiatedParserState, CompilerContext)>.Error(
|
||||
or: Result<(ParserState, CompilerContext)>.Error(
|
||||
ErrorWithLocation(
|
||||
sourceLocation: node.toSourceLocation(),
|
||||
withError: "Missing transition statement of state declaration")))
|
||||
|
||||
@@ -24,18 +24,30 @@ import TreeSitterP4
|
||||
|
||||
public struct Program {
|
||||
public static func Compile(_ source: String) -> Result<P4Lang.Program> {
|
||||
return Program.Compile(source, withGlobalInstances: .none, withGlobalTypes: .none, withFFIs: [])
|
||||
|
||||
// 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 Program.Compile(
|
||||
source, withGlobalInstances: globals, withGlobalTypes: .none, withFFIs: [])
|
||||
}
|
||||
|
||||
public static func Compile(
|
||||
_ source: String, withGlobalInstances globalInstances: VarTypeScopes
|
||||
_ source: String, withGlobalInstances globalInstances: StaticVarValueScopes
|
||||
) -> Result<P4Lang.Program> {
|
||||
return Program.Compile(
|
||||
source, withGlobalInstances: globalInstances, withGlobalTypes: .none, withFFIs: [])
|
||||
}
|
||||
|
||||
public static func Compile(
|
||||
_ source: String, withGlobalInstances globalInstances: VarTypeScopes?,
|
||||
_ source: String, withGlobalInstances globalInstances: StaticVarValueScopes?,
|
||||
withGlobalTypes globalTypes: TypeTypeScopes?, withFFIs ffis: [P4FFI] = Array()
|
||||
) -> Result<P4Lang.Program> {
|
||||
|
||||
@@ -122,8 +134,10 @@ public struct Program {
|
||||
|
||||
// Any of the instances that are in the top-level scope should go into the program!
|
||||
program.instances = Array(
|
||||
compilation_context.instances.map { (_, v) in
|
||||
v
|
||||
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!
|
||||
|
||||
@@ -255,7 +255,7 @@ extension VariableDeclarationStatement: CompilableStatement {
|
||||
// Context with updated names to include the newly declared name.
|
||||
context.update(
|
||||
newInstances: context.instances.declare(
|
||||
identifier: parsed_variablename, withValue: declaration_p4_type))
|
||||
identifier: parsed_variablename, withValue: (declaration_p4_type, .none)))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user