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:
@@ -72,14 +72,16 @@ public struct CodeGenerator: LanguageVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: Handle instances.
|
||||
/*
|
||||
result = Fold(
|
||||
input: v.instances, initial: result
|
||||
) { (current, acc) in
|
||||
return switch acc {
|
||||
case .Ok(let acc): acc.getVisitorDriver().visit(current.baseType(), context: acc)
|
||||
case .Ok(let acc): acc.getVisitorDriver().visit(current, context: acc)
|
||||
case .Error(let e): .Error(e)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
result = result.map {
|
||||
.Ok($0.next(uc: $0.getUserContext().append("]")))
|
||||
@@ -115,7 +117,7 @@ public struct CodeGenerator: LanguageVisitor {
|
||||
}
|
||||
|
||||
public func visit(
|
||||
_ v: InstantiatedParserState, _ c: VisitorContext<Generated>
|
||||
_ v: ParserState, _ c: VisitorContext<Generated>
|
||||
) -> Result<VisitorContext<Generated>> {
|
||||
let direct_transition_codegen = {
|
||||
(
|
||||
@@ -135,14 +137,14 @@ public struct CodeGenerator: LanguageVisitor {
|
||||
(
|
||||
state: ParserStateSelectTransition, c: VisitorContext<Generated>
|
||||
) -> Result<VisitorContext<Generated>> in
|
||||
return switch self.visit(state.selectExpression, c.next(uc: c.getUserContext().append("["))) {
|
||||
return switch self.visit(state.te, c.next(uc: c.getUserContext().append("["))) {
|
||||
case .Ok(let res): .Ok(res.next(uc: res.getUserContext().append("]")))
|
||||
case .Error(let e): .Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
var initial = "{"
|
||||
initial += "name: \"\(v.state)\","
|
||||
initial += "name: \"\(v.getName())\","
|
||||
initial += "transitions: "
|
||||
|
||||
let result: Result<VisitorContext<Generated>> =
|
||||
@@ -281,4 +283,9 @@ public struct CodeGenerator: LanguageVisitor {
|
||||
) -> Result<VisitorContext<Generated>> {
|
||||
return .Ok(c)
|
||||
}
|
||||
public func visit(
|
||||
_ parser_state: P4Lang.InstantiatedParserState, _ c: P4Lang.VisitorContext<Generated>
|
||||
) -> Common.Result<P4Lang.VisitorContext<Generated>> {
|
||||
return .Ok(c)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ extension SelectCaseExpression: EvaluatableExpression {
|
||||
}
|
||||
|
||||
public func type() -> P4QualifiedType {
|
||||
return P4QualifiedType(ParserState())
|
||||
return P4QualifiedType(AnyParserState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ extension SelectExpression: EvaluatableExpression {
|
||||
}
|
||||
|
||||
public func type() -> P4QualifiedType {
|
||||
return P4QualifiedType(ParserState())
|
||||
return P4QualifiedType(AnyParserState)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,18 +79,18 @@ extension TypedIdentifier: EvaluatableLValueExpression {
|
||||
}
|
||||
|
||||
public func check(
|
||||
to: any Common.EvaluatableExpression, inScopes scopes: Common.VarTypeScopes
|
||||
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.assignableFromType(to.type()) {
|
||||
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)"))
|
||||
"Cannot assign value with type \(to.type()) to identifier \(self) with type \(type.0)"))
|
||||
case TypeCheckResults.ReadOnly:
|
||||
.Error(
|
||||
Error(
|
||||
@@ -318,7 +318,7 @@ extension ArrayAccessExpression: EvaluatableLValueExpression {
|
||||
}
|
||||
|
||||
public func check(
|
||||
to: any Common.EvaluatableExpression, inScopes scopes: Common.VarTypeScopes
|
||||
to: any Common.EvaluatableExpression, inScopes scopes: Common.StaticVarValueScopes
|
||||
) -> Common.Result<()> {
|
||||
|
||||
return switch self.type.value_type().assignableFromType(to.type()) {
|
||||
@@ -426,7 +426,7 @@ extension FieldAccessExpression: EvaluatableLValueExpression {
|
||||
}
|
||||
|
||||
public func check(
|
||||
to: any Common.EvaluatableExpression, inScopes scopes: Common.VarTypeScopes
|
||||
to: any Common.EvaluatableExpression, inScopes scopes: Common.StaticVarValueScopes
|
||||
) -> Common.Result<()> {
|
||||
return switch self.field.type().assignableFromType(to.type()) {
|
||||
case TypeCheckResults.IncompatibleTypes:
|
||||
|
||||
@@ -39,14 +39,14 @@ extension ParserAssignmentStatement: EvaluatableStatement {
|
||||
}
|
||||
}
|
||||
|
||||
extension ParserStateDirectTransition: EvaluatableParserState {
|
||||
extension ParserStateDirectTransitionValue: EvaluatableParserState {
|
||||
public func execute(
|
||||
program: Common.ProgramExecution
|
||||
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
||||
var program = program.enter_scope()
|
||||
|
||||
let (control_flow, next_execution) = program.evaluator.ExecuteStatements(
|
||||
statements, inExecution: program)
|
||||
self.state.statements, inExecution: program)
|
||||
|
||||
switch control_flow {
|
||||
case .Next: program = next_execution
|
||||
@@ -59,17 +59,7 @@ extension ParserStateDirectTransition: EvaluatableParserState {
|
||||
)
|
||||
}
|
||||
|
||||
let res = program.scopes.lookup(identifier: get_next_state())
|
||||
|
||||
if case .Ok(let value) = res {
|
||||
if value.type().baseType().eq(rhs: self) {
|
||||
return (value.dataValue() as! EvaluatableParserState, program.exit_scope())
|
||||
}
|
||||
}
|
||||
|
||||
program = program.setError(error: res.error()!).exit_scope()
|
||||
|
||||
return (self, program.exit_scope())
|
||||
return (self.next_state as! EvaluatableParserState, program.exit_scope())
|
||||
}
|
||||
|
||||
public func done() -> Bool {
|
||||
@@ -77,11 +67,11 @@ extension ParserStateDirectTransition: EvaluatableParserState {
|
||||
}
|
||||
|
||||
public func state() -> P4Lang.ParserState {
|
||||
return self
|
||||
return self.state
|
||||
}
|
||||
}
|
||||
|
||||
extension ParserStateNoTransition: EvaluatableParserState {
|
||||
extension ParserStateNoTransitionValue: EvaluatableParserState {
|
||||
public func execute(
|
||||
program: Common.ProgramExecution
|
||||
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
||||
@@ -93,18 +83,18 @@ extension ParserStateNoTransition: EvaluatableParserState {
|
||||
}
|
||||
|
||||
public func state() -> P4Lang.ParserState {
|
||||
return self
|
||||
return self.state
|
||||
}
|
||||
}
|
||||
|
||||
extension ParserStateSelectTransition: EvaluatableParserState {
|
||||
extension ParserStateSelectTransitionValue: EvaluatableParserState {
|
||||
public func execute(
|
||||
program: Common.ProgramExecution
|
||||
) -> (any EvaluatableParserState, Common.ProgramExecution) {
|
||||
var program = program.enter_scope()
|
||||
|
||||
let (control_flow, next_execution) = program.evaluator.ExecuteStatements(
|
||||
statements, inExecution: program)
|
||||
self.state.statements, inExecution: program)
|
||||
switch control_flow {
|
||||
case .Next: program = next_execution
|
||||
case .Error: return (reject, next_execution.exit_scope())
|
||||
@@ -116,10 +106,9 @@ extension ParserStateSelectTransition: EvaluatableParserState {
|
||||
)
|
||||
}
|
||||
|
||||
//switch self.selectExpression.evaluate(execution: program) {
|
||||
switch program.evaluator.EvaluateExpression(self.selectExpression, inExecution: program) {
|
||||
switch program.evaluator.EvaluateExpression(self.te, inExecution: program) {
|
||||
case (.Ok(let value), let program):
|
||||
if value.type().baseType().eq(rhs: self) {
|
||||
if AnyParserState.eq(rhs: value.type().baseType()) {
|
||||
return (value.dataValue() as! EvaluatableParserState, program.exit_scope())
|
||||
} else {
|
||||
return (
|
||||
@@ -137,11 +126,11 @@ extension ParserStateSelectTransition: EvaluatableParserState {
|
||||
}
|
||||
|
||||
public func state() -> P4Lang.ParserState {
|
||||
return self
|
||||
return self.state
|
||||
}
|
||||
}
|
||||
|
||||
extension Parser: LibraryCallable {
|
||||
extension ParserValue: LibraryCallable {
|
||||
public typealias T = InstantiatedParserState
|
||||
public func call(
|
||||
execution: Common.ProgramExecution, arguments: ArgumentList
|
||||
@@ -149,10 +138,10 @@ extension Parser: LibraryCallable {
|
||||
var execution = execution.enter_scope()
|
||||
|
||||
execution = execution.declare(
|
||||
identifier: AsInstantiatedParserState(accept.state()).state,
|
||||
identifier: accept.state().getName(),
|
||||
withValue: P4Value(accept, P4QualifiedType.ReadOnly(accept.type())))
|
||||
execution = execution.declare(
|
||||
identifier: AsInstantiatedParserState(reject.state()).state,
|
||||
identifier: reject.state().getName(),
|
||||
withValue: P4Value(reject, P4QualifiedType.ReadOnly(reject.type())))
|
||||
|
||||
// Add initial values to the global scope
|
||||
@@ -161,13 +150,20 @@ extension Parser: LibraryCallable {
|
||||
}
|
||||
|
||||
// First, add every state to the scope!
|
||||
for state in self.states.states {
|
||||
for state in self.tipe.states.states {
|
||||
guard let instantiated_state = state.instantiate(state.getName()) else {
|
||||
return (
|
||||
reject,
|
||||
execution.setError(error: Error(withMessage: "Could not instantiate \(state.getName())"))
|
||||
)
|
||||
}
|
||||
execution = execution.declare(
|
||||
identifier: state.state, withValue: P4Value(state))
|
||||
identifier: state.getName(), withValue: P4Value(instantiated_state))
|
||||
}
|
||||
|
||||
guard let _current_state = self.findStartState(),
|
||||
var current_state = _current_state as? EvaluatableParserState
|
||||
guard let _current_state = self.tipe.findStartState(),
|
||||
var current_state = _current_state.instantiate(Identifier(name: "start"))
|
||||
as? EvaluatableParserState
|
||||
else {
|
||||
return (
|
||||
reject, execution.setError(error: Error(withMessage: "Could not find the start state"))
|
||||
@@ -181,12 +177,12 @@ extension Parser: LibraryCallable {
|
||||
while !current_state.done() && !current_execution.hasError() {
|
||||
(current_state, current_execution) = current_state.execute(program: current_execution)
|
||||
}
|
||||
return (.Ok(P4Value(AsInstantiatedParserState(current_state.state()))), current_execution)
|
||||
return (.Ok(P4Value((current_state))), current_execution)
|
||||
}
|
||||
|
||||
return
|
||||
switch Call(
|
||||
body: call_body, withArguments: arguments, withParameters: parameters,
|
||||
body: call_body, withArguments: arguments, withParameters: self.tipe.parameters,
|
||||
inExecution: execution)
|
||||
{
|
||||
case (.Ok(let value), let updated_execution):
|
||||
|
||||
@@ -37,18 +37,19 @@ public struct Runtime<U, T: LibraryCallable<U>>: CustomStringConvertible {
|
||||
/// Create a parser runtime from a P4 program
|
||||
public static func create(
|
||||
program: P4Lang.Program
|
||||
) -> Result<Runtime<InstantiatedParserState, Parser>> {
|
||||
) -> Result<Runtime<InstantiatedParserState, ParserValue>> {
|
||||
return Runtime.create(program: program, withGlobalValues: .none)
|
||||
}
|
||||
|
||||
public static func create(
|
||||
program: P4Lang.Program, withGlobalValues initial: VarValueScopes?
|
||||
) -> Result<Runtime<InstantiatedParserState, Parser>> {
|
||||
) -> Result<Runtime<InstantiatedParserState, ParserValue>> {
|
||||
return switch program.starting_parser() {
|
||||
case .Ok(let parser):
|
||||
.Ok(
|
||||
P4Runtime.Runtime<InstantiatedParserState, Parser>(
|
||||
callable: parser, withGlobalValues: initial))
|
||||
P4Runtime.Runtime<InstantiatedParserState, ParserValue>(
|
||||
callable: parser.instantiate(Identifier(name: "starting_parser")),
|
||||
withGlobalValues: initial))
|
||||
case .Error(let error): .Error(error)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user