diff --git a/Sources/Common/Compiler.swift b/Sources/Common/Compiler.swift index 33371bb..a6bf391 100644 --- a/Sources/Common/Compiler.swift +++ b/Sources/Common/Compiler.swift @@ -43,6 +43,8 @@ public struct CompilerContext { public let ffis: [P4FFI] public let expected_type: P4QualifiedType? public let extern_context: Bool + public let lexical_context_name: Identifier? + public let lexical_context_statements: [P4Statement]? public init() { instances = StaticVarValueScopes().enter() @@ -51,6 +53,8 @@ public struct CompilerContext { expected_type = .none extern_context = false ffis = Array() + lexical_context_name = .none + lexical_context_statements = .none } public init(withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes) { @@ -60,12 +64,16 @@ public struct CompilerContext { expected_type = .none extern_context = false ffis = Array() + lexical_context_name = .none + lexical_context_statements = .none } public init( withInstances _instances: StaticVarValueScopes, withTypes _types: TypeTypeScopes, withExpectation expectation: P4QualifiedType?, withExtern extern: Bool, - withExterns externs: TypeTypeScopes, withFFIs foreigns: [P4FFI] + withExterns externs: TypeTypeScopes, withFFIs foreigns: [P4FFI], + withLexicalContextName lexical_context_name: Identifier?, + withLexicalContextStatements lexical_context_statements: [P4Statement]? ) { instances = _instances types = _types @@ -73,6 +81,8 @@ public struct CompilerContext { extern_context = extern self.externs = externs ffis = foreigns + self.lexical_context_name = lexical_context_name + self.lexical_context_statements = lexical_context_statements } /// Update a compiler context @@ -84,7 +94,9 @@ public struct 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) + withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis, + withLexicalContextName: self.lexical_context_name, + withLexicalContextStatements: self.lexical_context_statements) } /// Update a compiler context @@ -96,7 +108,9 @@ public struct CompilerContext { 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) + withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis, + withLexicalContextName: self.lexical_context_name, + withLexicalContextStatements: self.lexical_context_statements) } /// Update a compiler context @@ -108,7 +122,9 @@ public struct CompilerContext { 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) + withExtern: self.extern_context, withExterns: self.externs, withFFIs: self.ffis, + withLexicalContextName: self.lexical_context_name, + withLexicalContextStatements: self.lexical_context_statements) } /// Update a compiler context @@ -120,7 +136,9 @@ public struct CompilerContext { 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) + withExtern: extern, withExterns: self.externs, withFFIs: self.ffis, + withLexicalContextName: self.lexical_context_name, + withLexicalContextStatements: self.lexical_context_statements) } /// Update a compiler context @@ -132,7 +150,9 @@ public struct CompilerContext { 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) + withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis, + withLexicalContextName: self.lexical_context_name, + withLexicalContextStatements: self.lexical_context_statements) } /// Update a compiler context @@ -144,6 +164,40 @@ public struct CompilerContext { 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) + withExtern: self.extern_context, withExterns: externs, withFFIs: foreigns, + withLexicalContextName: self.lexical_context_name, + withLexicalContextStatements: self.lexical_context_statements) } + + /// Update a compiler context + /// + /// Create a new compiler context based on the current but with a new lexical context name. + /// + /// - Parameter new_lexical_context_name: an optional new lexical context name; passing `.none` resets. + /// - Returns: A new compiler context based on the current but with a new lexical context name. + public func update(newLexicalContextName new_lexical_context_name: Identifier?) -> CompilerContext + { + return CompilerContext( + withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type, + withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis, + withLexicalContextName: new_lexical_context_name, + withLexicalContextStatements: self.lexical_context_statements) + } + + /// Update a compiler context + /// + /// Create a new compiler context based on the current but with a new set of lexical context statements. + /// + /// - Parameter new_lexical_context_statements: an optional new set of lexical context statements; passing `.none` resets. + /// - Returns: A new compiler context based on the current but with a new set of lexical context statements. + public func update( + newLexicalContextStatements new_lexical_context_statements: [P4Statement]? + ) -> CompilerContext { + return CompilerContext( + withInstances: self.instances, withTypes: self.types, withExpectation: self.expected_type, + withExtern: self.extern_context, withExterns: externs, withFFIs: self.ffis, + withLexicalContextName: self.lexical_context_name, + withLexicalContextStatements: new_lexical_context_statements) + } + } diff --git a/Sources/P4Compiler/Parser.swift b/Sources/P4Compiler/Parser.swift index 8543213..8576f32 100644 --- a/Sources/P4Compiler/Parser.swift +++ b/Sources/P4Compiler/Parser.swift @@ -178,8 +178,9 @@ extension ParserState: Compilable { sourceLocation: node.toSourceLocation(), withError: "Missing transition statement of state declaration"))) - return SpecialCompilers.TransitionStatement.Compile( - node: current_node!, forState: state_identifier, withStatements: parsed_s, - withContext: SpecialCompilers.Statements.effect(statements: parsed_s, context: context)) + let updated_context = SpecialCompilers.Statements.effect(statements: parsed_s, context: context) + .update(newLexicalContextName: state_identifier).update(newLexicalContextStatements: parsed_s) + + return TransitionStatement.Compile(node: current_node!, withContext: updated_context) } } diff --git a/Sources/P4Compiler/SpecialCompilers.swift b/Sources/P4Compiler/SpecialCompilers.swift index 514391f..0dffc23 100644 --- a/Sources/P4Compiler/SpecialCompilers.swift +++ b/Sources/P4Compiler/SpecialCompilers.swift @@ -28,88 +28,102 @@ protocol AnyCompilable { ) -> Common.Result<(Any, CompilerContext)> } -public struct SpecialCompilers { - public struct TransitionStatement { - static func Compile( - node: Node, forState state_identifier: Common.Identifier, - withStatements stmts: [P4Statement], withContext context: CompilerContext - ) -> Result { +extension TransitionStatement: Compilable { + public static func Compile( + node: Node, withContext context: CompilerContext + ) -> Result { - #RequireNodeType( - node: node, type: "parserTransitionStatement", nice_type_name: "parser transition statement" - ) + guard let state_identifier = context.lexical_context_name else { + return .Error( + ErrorWithLocation( + sourceLocation: node.toSourceLocation(), + withError: "Cannot parse a transition statement without the name of the containing state.")) + } - guard let tse_node = node.child(at: 1), - tse_node.nodeType! == "transitionSelectionExpression" - else { - return .Error( - ErrorWithLocation( - sourceLocation: node.toSourceLocation(), - withError: "Could not find transition select expression")) - } + guard let stmts = context.lexical_context_statements else { + return .Error( + ErrorWithLocation( + sourceLocation: node.toSourceLocation(), + withError: "Cannot parse a transition statement without statements of the containing state.")) + } - guard let next_node = tse_node.child(at: 0) else { - return .Error( - ErrorWithLocation( - sourceLocation: node.toSourceLocation(), - withError: "Could not find the next token in a transition selection expression")) - } - // 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( - 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, - ) + #RequireNodeType( + node: node, type: "parserTransitionStatement", nice_type_name: "parser transition statement" + ) + + guard let tse_node = node.child(at: 1), + tse_node.nodeType! == "transitionSelectionExpression" + else { + return .Error( + ErrorWithLocation( + sourceLocation: node.toSourceLocation(), + withError: "Could not find transition select expression")) + } + + guard let next_node = tse_node.child(at: 0) else { + return .Error( + ErrorWithLocation( + sourceLocation: node.toSourceLocation(), + withError: "Could not find the next token in a transition selection expression")) + } + + // 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( + 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" - )) + ) + case (_, .none): + return .Ok( + ParserStateDirectTransition( + name: state_identifier, + withNextStateIdentifier: next_state_id, withStatements: stmts) + ) } } else { + return .Error( Error( withMessage: - "Could not parse the next state in a transition statement: \(maybe_parsed_next_state_id.error()!)" + "\(next_state_id) does not name a parser state in scope" )) } - } - - // We know that the next node is a select expression. - return - switch SelectExpression.compile(node: next_node, withContext: context) - { - case .Ok(let tse): - .Ok( - ParserStateSelectTransition( - name: state_identifier, withTransitionExpression: tse as! SelectExpression, - withStatements: stmts, - ) - ) - case .Error(let e): .Error(e) + } else { + return .Error( + Error( + withMessage: + "Could not parse the next state in a transition statement: \(maybe_parsed_next_state_id.error()!)" + )) } } - } + // We know that the next node is a select expression. + return + switch SelectExpression.compile(node: next_node, withContext: context) + { + case .Ok(let tse): + .Ok( + ParserStateSelectTransition( + name: state_identifier, withTransitionExpression: tse as! SelectExpression, + withStatements: stmts, + ) + ) + case .Error(let e): .Error(e) + } + } +} + +public struct SpecialCompilers { public struct Statements { static func Compile( node: Node, withContext context: CompilerContext