| /// |
| /// |
| /// Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. |
| /// Use of this file is governed by the BSD 3-clause license that |
| /// can be found in the LICENSE.txt file in the project root. |
| /// |
| /// |
| |
| import Foundation |
| |
| /// |
| /// This field maps from the serialized ATN string to the deserialized _org.antlr.v4.runtime.atn.ATN_ with |
| /// bypass alternatives. |
| /// |
| /// - SeeAlso: `ATNDeserializationOptions.generateRuleBypassTransitions` |
| /// |
| private var bypassAltsAtnCache : ATN? = nil |
| |
| /// |
| /// mutex for bypassAltsAtnCache updates |
| /// |
| private let bypassAltsAtnCacheMutex = Mutex() |
| |
| |
| /// |
| /// This is all the parsing support code essentially; most of it is error recovery stuff. |
| /// |
| open class Parser: Recognizer<ParserATNSimulator> { |
| public static let EOF = -1 |
| public static var ConsoleError = true |
| |
| public class TraceListener: ParseTreeListener { |
| var host: Parser |
| init(_ host: Parser) { |
| self.host = host |
| } |
| |
| public func enterEveryRule(_ ctx: ParserRuleContext) throws { |
| let ruleName = host.getRuleNames()[ctx.getRuleIndex()] |
| let lt1 = try host._input.LT(1)!.getText()! |
| print("enter \(ruleName), LT(1)=\(lt1)") |
| } |
| |
| public func visitTerminal(_ node: TerminalNode) { |
| print("consume \(String(describing: node.getSymbol())) rule \(host.getRuleNames()[host._ctx!.getRuleIndex()])") |
| } |
| |
| public func visitErrorNode(_ node: ErrorNode) { |
| } |
| |
| public func exitEveryRule(_ ctx: ParserRuleContext) throws { |
| let ruleName = host.getRuleNames()[ctx.getRuleIndex()] |
| let lt1 = try host._input.LT(1)!.getText()! |
| print("exit \(ruleName), LT(1)=\(lt1)") |
| } |
| } |
| |
| public class TrimToSizeListener: ParseTreeListener { |
| public static let INSTANCE = TrimToSizeListener() |
| |
| public func enterEveryRule(_ ctx: ParserRuleContext) { |
| } |
| |
| public func visitTerminal(_ node: TerminalNode) { |
| } |
| |
| public func visitErrorNode(_ node: ErrorNode) { |
| } |
| |
| public func exitEveryRule(_ ctx: ParserRuleContext) { |
| // TODO: Print exit info. |
| } |
| } |
| |
| /// |
| /// The error handling strategy for the parser. The default value is a new |
| /// instance of _org.antlr.v4.runtime.DefaultErrorStrategy_. |
| /// |
| /// - SeeAlso: #getErrorHandler |
| /// - SeeAlso: #setErrorHandler |
| /// |
| public var _errHandler: ANTLRErrorStrategy = DefaultErrorStrategy() |
| |
| /// |
| /// The input stream. |
| /// |
| /// - SeeAlso: #getInputStream |
| /// - SeeAlso: #setInputStream |
| /// |
| public var _input: TokenStream! |
| |
| internal var _precedenceStack: Stack<Int> = { |
| var precedenceStack = Stack<Int>() |
| precedenceStack.push(0) |
| return precedenceStack |
| }() |
| |
| |
| /// |
| /// The _org.antlr.v4.runtime.ParserRuleContext_ object for the currently executing rule. |
| /// This is always non-null during the parsing process. |
| /// |
| public var _ctx: ParserRuleContext? = nil |
| |
| /// |
| /// Specifies whether or not the parser should construct a parse tree during |
| /// the parsing process. The default value is `true`. |
| /// |
| /// - SeeAlso: #getBuildParseTree |
| /// - SeeAlso: #setBuildParseTree |
| /// |
| internal var _buildParseTrees: Bool = true |
| |
| /// |
| /// When _#setTrace_`(true)` is called, a reference to the |
| /// _org.antlr.v4.runtime.Parser.TraceListener_ is stored here so it can be easily removed in a |
| /// later call to _#setTrace_`(false)`. The listener itself is |
| /// implemented as a parser listener so this field is not directly used by |
| /// other parser methods. |
| /// |
| private var _tracer: TraceListener? |
| |
| /// |
| /// The list of _org.antlr.v4.runtime.tree.ParseTreeListener_ listeners registered to receive |
| /// events during the parse. |
| /// |
| /// - SeeAlso: #addParseListener |
| /// |
| public var _parseListeners: Array<ParseTreeListener>? |
| |
| /// |
| /// The number of syntax errors reported during parsing. This value is |
| /// incremented each time _#notifyErrorListeners_ is called. |
| /// |
| internal var _syntaxErrors: Int = 0 |
| |
| public init(_ input: TokenStream) throws { |
| self._input = input |
| super.init() |
| try setInputStream(input) |
| } |
| |
| /// reset the parser's state |
| public func reset() throws { |
| try getInputStream()?.seek(0) |
| _errHandler.reset(self) |
| _ctx = nil |
| _syntaxErrors = 0 |
| setTrace(false) |
| _precedenceStack.clear() |
| _precedenceStack.push(0) |
| |
| // getInterpreter(); |
| if let interpreter = _interp { |
| interpreter.reset() |
| } |
| } |
| |
| /// |
| /// Match current input symbol against `ttype`. If the symbol type |
| /// matches, _org.antlr.v4.runtime.ANTLRErrorStrategy#reportMatch_ and _#consume_ are |
| /// called to complete the match process. |
| /// |
| /// If the symbol type does not match, |
| /// _org.antlr.v4.runtime.ANTLRErrorStrategy#recoverInline_ is called on the current error |
| /// strategy to attempt recovery. If _#getBuildParseTree_ is |
| /// `true` and the token index of the symbol returned by |
| /// _org.antlr.v4.runtime.ANTLRErrorStrategy#recoverInline_ is -1, the symbol is added to |
| /// the parse tree by calling _#createErrorNode(ParserRuleContext, Token)_ then |
| /// _ParserRuleContext#addErrorNode(ErrorNode)_. |
| /// |
| /// - Parameter ttype: the token type to match |
| /// - Throws: org.antlr.v4.runtime.RecognitionException if the current input symbol did not match |
| /// `ttype` and the error strategy could not recover from the |
| /// mismatched symbol |
| /// - Returns: the matched symbol |
| /// |
| @discardableResult |
| public func match(_ ttype: Int) throws -> Token { |
| var t = try getCurrentToken() |
| if t.getType() == ttype { |
| _errHandler.reportMatch(self) |
| try consume() |
| } else { |
| t = try _errHandler.recoverInline(self) |
| if _buildParseTrees && t.getTokenIndex() == -1 { |
| // we must have conjured up a new token during single token insertion |
| // if it's not the current symbol |
| _ctx!.addErrorNode(createErrorNode(parent: _ctx!, t: t)) |
| } |
| } |
| return t |
| } |
| |
| /// |
| /// Match current input symbol as a wildcard. If the symbol type matches |
| /// (i.e. has a value greater than 0), _org.antlr.v4.runtime.ANTLRErrorStrategy#reportMatch_ |
| /// and _#consume_ are called to complete the match process. |
| /// |
| /// If the symbol type does not match, |
| /// _org.antlr.v4.runtime.ANTLRErrorStrategy#recoverInline_ is called on the current error |
| /// strategy to attempt recovery. If _#getBuildParseTree_ is |
| /// `true` and the token index of the symbol returned by |
| /// _org.antlr.v4.runtime.ANTLRErrorStrategy#recoverInline_ is -1, the symbol is added to |
| /// the parse tree by calling _#createErrorNode(ParserRuleContext, Token)_ then |
| /// _ParserRuleContext#addErrorNode(ErrorNode)_. |
| /// |
| /// - Throws: org.antlr.v4.runtime.RecognitionException if the current input symbol did not match |
| /// a wildcard and the error strategy could not recover from the mismatched |
| /// symbol |
| /// - Returns: the matched symbol |
| /// |
| @discardableResult |
| public func matchWildcard() throws -> Token { |
| var t = try getCurrentToken() |
| if t.getType() > 0 { |
| _errHandler.reportMatch(self) |
| try consume() |
| } else { |
| t = try _errHandler.recoverInline(self) |
| if _buildParseTrees && t.getTokenIndex() == -1 { |
| // we must have conjured up a new token during single token insertion |
| // if it's not the current symbol |
| _ctx!.addErrorNode(createErrorNode(parent: _ctx!, t: t)) |
| } |
| } |
| |
| return t |
| } |
| |
| /// |
| /// Track the _org.antlr.v4.runtime.ParserRuleContext_ objects during the parse and hook |
| /// them up using the _org.antlr.v4.runtime.ParserRuleContext#children_ list so that it |
| /// forms a parse tree. The _org.antlr.v4.runtime.ParserRuleContext_ returned from the start |
| /// rule represents the root of the parse tree. |
| /// |
| /// Note that if we are not building parse trees, rule contexts only point |
| /// upwards. When a rule exits, it returns the context but that gets garbage |
| /// collected if nobody holds a reference. It points upwards but nobody |
| /// points at it. |
| /// |
| /// When we build parse trees, we are adding all of these contexts to |
| /// _org.antlr.v4.runtime.ParserRuleContext#children_ list. Contexts are then not candidates |
| /// for garbage collection. |
| /// |
| public func setBuildParseTree(_ buildParseTrees: Bool) { |
| self._buildParseTrees = buildParseTrees |
| } |
| |
| /// |
| /// Gets whether or not a complete parse tree will be constructed while |
| /// parsing. This property is `true` for a newly constructed parser. |
| /// |
| /// - Returns: `true` if a complete parse tree will be constructed while |
| /// parsing, otherwise `false` |
| /// |
| public func getBuildParseTree() -> Bool { |
| return _buildParseTrees |
| } |
| |
| /// |
| /// Trim the internal lists of the parse tree during parsing to conserve memory. |
| /// This property is set to `false` by default for a newly constructed parser. |
| /// |
| /// - Parameter trimParseTrees: `true` to trim the capacity of the _org.antlr.v4.runtime.ParserRuleContext#children_ |
| /// list to its size after a rule is parsed. |
| /// |
| public func setTrimParseTree(_ trimParseTrees: Bool) { |
| if trimParseTrees { |
| if getTrimParseTree() { |
| return |
| } |
| addParseListener(TrimToSizeListener.INSTANCE) |
| } else { |
| removeParseListener(TrimToSizeListener.INSTANCE) |
| } |
| } |
| |
| /// |
| /// - Returns: `true` if the _org.antlr.v4.runtime.ParserRuleContext#children_ list is trimmed |
| /// using the default _org.antlr.v4.runtime.Parser.TrimToSizeListener_ during the parse process. |
| /// |
| public func getTrimParseTree() -> Bool { |
| return !getParseListeners().filter({ $0 === TrimToSizeListener.INSTANCE }).isEmpty |
| } |
| |
| public func getParseListeners() -> [ParseTreeListener] { |
| return _parseListeners ?? [ParseTreeListener]() |
| } |
| |
| /// |
| /// Registers `listener` to receive events during the parsing process. |
| /// |
| /// To support output-preserving grammar transformations (including but not |
| /// limited to left-recursion removal, automated left-factoring, and |
| /// optimized code generation), calls to listener methods during the parse |
| /// may differ substantially from calls made by |
| /// _org.antlr.v4.runtime.tree.ParseTreeWalker#DEFAULT_ used after the parse is complete. In |
| /// particular, rule entry and exit events may occur in a different order |
| /// during the parse than after the parser. In addition, calls to certain |
| /// rule entry methods may be omitted. |
| /// |
| /// With the following specific exceptions, calls to listener events are |
| /// __deterministic__, i.e. for identical input the calls to listener |
| /// methods will be the same. |
| /// |
| /// * Alterations to the grammar used to generate code may change the |
| /// behavior of the listener calls. |
| /// * Alterations to the command line options passed to ANTLR 4 when |
| /// generating the parser may change the behavior of the listener calls. |
| /// * Changing the version of the ANTLR Tool used to generate the parser |
| /// may change the behavior of the listener calls. |
| /// |
| /// - Parameter listener: the listener to add |
| /// |
| public func addParseListener(_ listener: ParseTreeListener) { |
| if _parseListeners == nil { |
| _parseListeners = [ParseTreeListener]() |
| } |
| |
| _parseListeners!.append(listener) |
| } |
| |
| /// |
| /// Remove `listener` from the list of parse listeners. |
| /// |
| /// If `listener` is `null` or has not been added as a parse |
| /// listener, this method does nothing. |
| /// |
| /// - SeeAlso: #addParseListener |
| /// |
| /// - Parameter listener: the listener to remove |
| /// |
| |
| public func removeParseListener(_ listener: ParseTreeListener?) { |
| if _parseListeners != nil { |
| if !_parseListeners!.filter({ $0 === listener }).isEmpty { |
| _parseListeners = _parseListeners!.filter({ |
| $0 !== listener |
| }) |
| if _parseListeners!.isEmpty { |
| _parseListeners = nil |
| } |
| } |
| } |
| } |
| |
| /// |
| /// Remove all parse listeners. |
| /// |
| /// - SeeAlso: #addParseListener |
| /// |
| public func removeParseListeners() { |
| _parseListeners = nil |
| } |
| |
| /// |
| /// Notify any parse listeners of an enter rule event. |
| /// |
| /// - SeeAlso: #addParseListener |
| /// |
| public func triggerEnterRuleEvent() throws { |
| if let _parseListeners = _parseListeners, let _ctx = _ctx { |
| for listener: ParseTreeListener in _parseListeners { |
| try listener.enterEveryRule(_ctx) |
| _ctx.enterRule(listener) |
| } |
| } |
| } |
| |
| /// |
| /// Notify any parse listeners of an exit rule event. |
| /// |
| /// - SeeAlso: #addParseListener |
| /// |
| public func triggerExitRuleEvent() throws { |
| // reverse order walk of listeners |
| if let _parseListeners = _parseListeners, let _ctx = _ctx { |
| for listener in _parseListeners.reversed() { |
| _ctx.exitRule(listener) |
| try listener.exitEveryRule(_ctx) |
| } |
| } |
| } |
| |
| /// |
| /// Gets the number of syntax errors reported during parsing. This value is |
| /// incremented each time _#notifyErrorListeners_ is called. |
| /// |
| /// - SeeAlso: #notifyErrorListeners |
| /// |
| public func getNumberOfSyntaxErrors() -> Int { |
| return _syntaxErrors |
| } |
| |
| override |
| open func getTokenFactory() -> TokenFactory { |
| return _input.getTokenSource().getTokenFactory() |
| } |
| |
| /// Tell our token source and error strategy about a new way to create tokens. |
| override |
| open func setTokenFactory(_ factory: TokenFactory) { |
| _input.getTokenSource().setTokenFactory(factory) |
| } |
| |
| /// |
| /// The ATN with bypass alternatives is expensive to create so we create it |
| /// lazily. |
| /// |
| public func getATNWithBypassAlts() -> ATN { |
| let serializedAtn = getSerializedATN() |
| |
| return bypassAltsAtnCacheMutex.synchronized { |
| if let cachedResult = bypassAltsAtnCache { |
| return cachedResult |
| } |
| |
| var opts = ATNDeserializationOptions() |
| opts.generateRuleBypassTransitions = true |
| let result = try! ATNDeserializer(opts).deserialize(serializedAtn) |
| bypassAltsAtnCache = result |
| return bypassAltsAtnCache! |
| } |
| } |
| |
| /// |
| /// The preferred method of getting a tree pattern. For example, here's a |
| /// sample use: |
| /// |
| /// |
| /// ParseTree t = parser.expr(); |
| /// ParseTreePattern p = parser.compileParseTreePattern("<ID>+0", MyParser.RULE_expr); |
| /// ParseTreeMatch m = p.match(t); |
| /// String id = m.get("ID"); |
| /// |
| /// |
| public func compileParseTreePattern(_ pattern: String, _ patternRuleIndex: Int) throws -> ParseTreePattern { |
| if let tokenStream = getTokenStream() { |
| let tokenSource = tokenStream.getTokenSource() |
| if let lexer = tokenSource as? Lexer { |
| return try compileParseTreePattern(pattern, patternRuleIndex, lexer) |
| } |
| } |
| throw ANTLRError.unsupportedOperation(msg: "Parser can't discover a lexer to use") |
| } |
| |
| /// |
| /// The same as _#compileParseTreePattern(String, int)_ but specify a |
| /// _org.antlr.v4.runtime.Lexer_ rather than trying to deduce it from this parser. |
| /// |
| public func compileParseTreePattern(_ pattern: String, _ patternRuleIndex: Int, |
| _ lexer: Lexer) throws -> ParseTreePattern { |
| let m = ParseTreePatternMatcher(lexer, self) |
| return try m.compile(pattern, patternRuleIndex) |
| } |
| |
| |
| public func getErrorHandler() -> ANTLRErrorStrategy { |
| return _errHandler |
| } |
| |
| public func setErrorHandler(_ handler: ANTLRErrorStrategy) { |
| self._errHandler = handler |
| } |
| |
| override |
| open func getInputStream() -> IntStream? { |
| return getTokenStream() |
| } |
| |
| override |
| public final func setInputStream(_ input: IntStream) throws { |
| try setTokenStream(input as! TokenStream) |
| } |
| |
| public func getTokenStream() -> TokenStream? { |
| return _input |
| } |
| |
| /// Set the token stream and reset the parser. |
| public func setTokenStream(_ input: TokenStream) throws { |
| //TODO self._input = nil; |
| self._input = nil; |
| try reset() |
| self._input = input |
| } |
| |
| /// Match needs to return the current input symbol, which gets put |
| /// into the label for the associated token ref; e.g., x=ID. |
| /// |
| |
| public func getCurrentToken() throws -> Token { |
| return try _input.LT(1)! |
| } |
| |
| public final func notifyErrorListeners(_ msg: String) { |
| let token = try? getCurrentToken() |
| notifyErrorListeners(token, msg, nil) |
| } |
| |
| public func notifyErrorListeners(_ offendingToken: Token?, _ msg: String, _ e: AnyObject?) { |
| _syntaxErrors += 1 |
| var line = -1 |
| var charPositionInLine = -1 |
| if let offendingToken = offendingToken { |
| line = offendingToken.getLine() |
| charPositionInLine = offendingToken.getCharPositionInLine() |
| } |
| |
| let listener = getErrorListenerDispatch() |
| listener.syntaxError(self, offendingToken, line, charPositionInLine, msg, e) |
| } |
| |
| /// |
| /// Consume and return the |: #getCurrentToken current symbol:|. |
| /// |
| /// E.g., given the following input with `A` being the current |
| /// lookahead symbol, this function moves the cursor to `B` and returns |
| /// `A`. |
| /// |
| /// |
| /// A B |
| /// ^ |
| /// |
| /// |
| /// If the parser is not in error recovery mode, the consumed symbol is added |
| /// to the parse tree using _ParserRuleContext#addChild(TerminalNode)_, and |
| /// _org.antlr.v4.runtime.tree.ParseTreeListener#visitTerminal_ is called on any parse listeners. |
| /// If the parser __is__ in error recovery mode, the consumed symbol is |
| /// added to the parse tree using _#createErrorNode(ParserRuleContext, Token)_ then |
| /// _ParserRuleContext#addErrorNode(ErrorNode)_ and |
| /// _org.antlr.v4.runtime.tree.ParseTreeListener#visitErrorNode_ is called on any parse |
| /// listeners. |
| /// |
| @discardableResult |
| public func consume() throws -> Token { |
| let o = try getCurrentToken() |
| if o.getType() != Parser.EOF { |
| try getInputStream()!.consume() |
| } |
| guard let _ctx = _ctx else { |
| return o |
| } |
| let hasListener = _parseListeners != nil && !_parseListeners!.isEmpty |
| |
| if _buildParseTrees || hasListener { |
| if _errHandler.inErrorRecoveryMode(self) { |
| let node = createErrorNode(parent: _ctx, t: o) |
| _ctx.addErrorNode(node) |
| if let _parseListeners = _parseListeners { |
| for listener in _parseListeners { |
| listener.visitErrorNode(node) |
| } |
| } |
| } else { |
| let node = createTerminalNode(parent: _ctx, t: o) |
| _ctx.addChild(node) |
| if let _parseListeners = _parseListeners { |
| for listener in _parseListeners { |
| listener.visitTerminal(node) |
| } |
| } |
| } |
| } |
| return o |
| } |
| |
| /// How to create a token leaf node associated with a parent. |
| /// Typically, the terminal node to create is not a function of the parent. |
| /// |
| /// - Since: 4.7 |
| /// |
| public func createTerminalNode(parent: ParserRuleContext, t: Token) -> TerminalNode { |
| return TerminalNodeImpl(t) |
| } |
| |
| /// How to create an error node, given a token, associated with a parent. |
| /// Typically, the error node to create is not a function of the parent. |
| /// |
| /// - Since: 4.7 |
| /// |
| public func createErrorNode(parent: ParserRuleContext, t: Token) -> ErrorNode { |
| return ErrorNode(t) |
| } |
| |
| internal func addContextToParseTree() { |
| |
| // add current context to parent if we have a parent |
| if let parent = _ctx?.parent as? ParserRuleContext { |
| parent.addChild(_ctx!) |
| } |
| } |
| |
| /// |
| /// Always called by generated parsers upon entry to a rule. Access field |
| /// _#_ctx_ get the current context. |
| /// |
| public func enterRule(_ localctx: ParserRuleContext, _ state: Int, _ ruleIndex: Int) throws { |
| setState(state) |
| _ctx = localctx |
| _ctx!.start = try _input.LT(1) |
| if _buildParseTrees { |
| addContextToParseTree() |
| } |
| } |
| |
| public func exitRule() throws { |
| guard let ctx = _ctx else { |
| return |
| } |
| ctx.stop = try _input.LT(-1) |
| // trigger event on _ctx, before it reverts to parent |
| if _parseListeners != nil { |
| try triggerExitRuleEvent() |
| } |
| setState(ctx.invokingState) |
| _ctx = ctx.parent as? ParserRuleContext |
| } |
| |
| public func enterOuterAlt(_ localctx: ParserRuleContext, _ altNum: Int) throws { |
| localctx.setAltNumber(altNum) |
| // if we have new localctx, make sure we replace existing ctx |
| // that is previous child of parse tree |
| if _buildParseTrees && _ctx! !== localctx { |
| if let parent = _ctx?.parent as? ParserRuleContext { |
| parent.removeLastChild() |
| parent.addChild(localctx) |
| } |
| } |
| _ctx = localctx |
| if _parseListeners != nil { |
| try triggerEnterRuleEvent() |
| } |
| } |
| |
| /// |
| /// Get the precedence level for the top-most precedence rule. |
| /// |
| /// - Returns: The precedence level for the top-most precedence rule, or -1 if |
| /// the parser context is not nested within a precedence rule. |
| /// |
| public final func getPrecedence() -> Int { |
| if _precedenceStack.isEmpty { |
| return -1 |
| } |
| |
| return _precedenceStack.peek() ?? -1 |
| } |
| |
| /// |
| /// Use |
| /// _#enterRecursionRule(org.antlr.v4.runtime.ParserRuleContext, int, int, int)_ instead. |
| /// |
| /// |
| /// /@Deprecated |
| /// |
| public func enterRecursionRule(_ localctx: ParserRuleContext, _ ruleIndex: Int) throws { |
| try enterRecursionRule(localctx, getATN().ruleToStartState[ruleIndex].stateNumber, ruleIndex, 0) |
| } |
| |
| public func enterRecursionRule(_ localctx: ParserRuleContext, _ state: Int, _ ruleIndex: Int, _ precedence: Int) throws { |
| setState(state) |
| _precedenceStack.push(precedence) |
| _ctx = localctx |
| _ctx!.start = try _input.LT(1) |
| if _parseListeners != nil { |
| try triggerEnterRuleEvent() // simulates rule entry for left-recursive rules |
| } |
| } |
| |
| /// Like _#enterRule_ but for recursive rules. |
| /// Make the current context the child of the incoming localctx. |
| /// |
| public func pushNewRecursionContext(_ localctx: ParserRuleContext, _ state: Int, _ ruleIndex: Int) throws { |
| let previous = _ctx! |
| previous.parent = localctx |
| previous.invokingState = state |
| previous.stop = try _input.LT(-1) |
| |
| _ctx = localctx |
| _ctx!.start = previous.start |
| if _buildParseTrees { |
| _ctx!.addChild(previous) |
| } |
| |
| if _parseListeners != nil { |
| try triggerEnterRuleEvent() // simulates rule entry for left-recursive rules |
| } |
| } |
| |
| public func unrollRecursionContexts(_ _parentctx: ParserRuleContext?) throws { |
| _precedenceStack.pop() |
| _ctx!.stop = try _input.LT(-1) |
| let retctx = _ctx! // save current ctx (return value) |
| |
| // unroll so _ctx is as it was before call to recursive method |
| if _parseListeners != nil { |
| while let ctxWrap = _ctx, ctxWrap !== _parentctx { |
| try triggerExitRuleEvent() |
| _ctx = ctxWrap.parent as? ParserRuleContext |
| } |
| } else { |
| _ctx = _parentctx |
| } |
| |
| // hook into tree |
| retctx.parent = _parentctx |
| |
| if _buildParseTrees && _parentctx != nil { |
| // add return ctx into invoking rule's tree |
| _parentctx!.addChild(retctx) |
| } |
| } |
| |
| public func getInvokingContext(_ ruleIndex: Int) -> ParserRuleContext? { |
| var p = _ctx |
| while let pWrap = p { |
| if pWrap.getRuleIndex() == ruleIndex { |
| return pWrap |
| } |
| p = pWrap.parent as? ParserRuleContext |
| } |
| return nil |
| } |
| |
| public func getContext() -> ParserRuleContext? { |
| return _ctx |
| } |
| |
| public func setContext(_ ctx: ParserRuleContext) { |
| _ctx = ctx |
| } |
| |
| override |
| open func precpred(_ localctx: RuleContext?, _ precedence: Int) -> Bool { |
| return precedence >= _precedenceStack.peek()! |
| } |
| |
| public func inContext(_ context: String) -> Bool { |
| // TODO: useful in parser? |
| return false |
| } |
| |
| /// Given an AmbiguityInfo object that contains information about an |
| /// ambiguous decision event, return the list of ambiguous parse trees. |
| /// An ambiguity occurs when a specific token sequence can be recognized |
| /// in more than one way by the grammar. These ambiguities are detected only |
| /// at decision points. |
| /// |
| /// The list of trees includes the actual interpretation (that for |
| /// the minimum alternative number) and all ambiguous alternatives. |
| /// The actual interpretation is always first. |
| /// |
| /// This method reuses the same physical input token stream used to |
| /// detect the ambiguity by the original parser in the first place. |
| /// This method resets/seeks within but does not alter originalParser. |
| /// The input position is restored upon exit from this method. |
| /// Parsers using a _org.antlr.v4.runtime.UnbufferedTokenStream_ may not be able to |
| /// perform the necessary save index() / seek(saved_index) operation. |
| /// |
| /// The trees are rooted at the node whose start..stop token indices |
| /// include the start and stop indices of this ambiguity event. That is, |
| /// the trees returns will always include the complete ambiguous subphrase |
| /// identified by the ambiguity event. |
| /// |
| /// Be aware that this method does NOT notify error or parse listeners as |
| /// it would trigger duplicate or otherwise unwanted events. |
| /// |
| /// This uses a temporary ParserATNSimulator and a ParserInterpreter |
| /// so we don't mess up any statistics, event lists, etc... |
| /// The parse tree constructed while identifying/making ambiguityInfo is |
| /// not affected by this method as it creates a new parser interp to |
| /// get the ambiguous interpretations. |
| /// |
| /// Nodes in the returned ambig trees are independent of the original parse |
| /// tree (constructed while identifying/creating ambiguityInfo). |
| /// |
| /// - Since: 4.5.1 |
| /// |
| /// - Parameter originalParser: The parser used to create ambiguityInfo; it |
| /// is not modified by this routine and can be either |
| /// a generated or interpreted parser. It's token |
| /// stream *is* reset/seek()'d. |
| /// - Parameter ambiguityInfo: The information about an ambiguous decision event |
| /// for which you want ambiguous parse trees. |
| /// - Parameter startRuleIndex: The start rule for the entire grammar, not |
| /// the ambiguous decision. We re-parse the entire input |
| /// and so we need the original start rule. |
| /// |
| /// - Throws: org.antlr.v4.runtime.RecognitionException Throws upon syntax error while matching |
| /// ambig input. |
| /// - Returns: The list of all possible interpretations of |
| /// the input for the decision in ambiguityInfo. |
| /// The actual interpretation chosen by the parser |
| /// is always given first because this method |
| /// retests the input in alternative order and |
| /// ANTLR always resolves ambiguities by choosing |
| /// the first alternative that matches the input. |
| /// |
| /// |
| // public class func getAmbiguousParseTrees(originalParser : Parser, |
| // _ ambiguityInfo : AmbiguityInfo, |
| // _ startRuleIndex : Int) throws -> Array<ParserRuleContext> //; RecognitionException |
| // { |
| // var trees : Array<ParserRuleContext> = Array<ParserRuleContext>(); |
| // var saveTokenInputPosition : Int = originalParser.getTokenStream().index(); |
| // //try { |
| // // Create a new parser interpreter to parse the ambiguous subphrase |
| // var parser : ParserInterpreter; |
| // if ( originalParser is ParserInterpreter ) { |
| // parser = ParserInterpreter( originalParser as! ParserInterpreter); |
| // } |
| // else { |
| // var serializedAtn : [Character] = ATNSerializer.getSerializedAsChars(originalParser.getATN()); |
| // var deserialized : ATN = ATNDeserializer().deserialize(serializedAtn); |
| // parser = ParserInterpreter(originalParser.getGrammarFileName(), |
| // originalParser.getVocabulary(), |
| // originalParser.getRuleNames() , |
| // deserialized, |
| // originalParser.getTokenStream()); |
| // } |
| // |
| // // Make sure that we don't get any error messages from using this temporary parser |
| // parser.removeErrorListeners(); |
| // parser.removeParseListeners(); |
| // parser.getInterpreter()!.setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION); |
| // |
| // // get ambig trees |
| // var alt : Int = ambiguityInfo.ambigAlts.firstSetBit(); |
| // while alt>=0 { |
| // // re-parse entire input for all ambiguous alternatives |
| // // (don't have to do first as it's been parsed, but do again for simplicity |
| // // using this temp parser.) |
| // parser.reset(); |
| // parser.getTokenStream().seek(0); // rewind the input all the way for re-parsing |
| // parser.overrideDecision = ambiguityInfo.decision; |
| // parser.overrideDecisionInputIndex = ambiguityInfo.startIndex; |
| // parser.overrideDecisionAlt = alt; |
| // var t : ParserRuleContext = parser.parse(startRuleIndex); |
| // var ambigSubTree : ParserRuleContext = |
| // Trees.getRootOfSubtreeEnclosingRegion(t, ambiguityInfo.startIndex, ambiguityInfo.stopIndex)!; |
| // trees.append(ambigSubTree); |
| // alt = ambiguityInfo.ambigAlts.nextSetBit(alt+1); |
| // } |
| // //} |
| // defer { |
| // originalParser.getTokenStream().seek(saveTokenInputPosition); |
| // } |
| // |
| // return trees; |
| // } |
| |
| /// |
| /// Checks whether or not `symbol` can follow the current state in the |
| /// ATN. The behavior of this method is equivalent to the following, but is |
| /// implemented such that the complete context-sensitive follow set does not |
| /// need to be explicitly constructed. |
| /// |
| /// |
| /// return getExpectedTokens().contains(symbol); |
| /// |
| /// |
| /// - Parameter symbol: the symbol type to check |
| /// - Returns: `true` if `symbol` can follow the current state in |
| /// the ATN, otherwise `false`. |
| /// |
| public func isExpectedToken(_ symbol: Int) -> Bool { |
| let atn = getInterpreter().atn |
| var ctx: ParserRuleContext? = _ctx |
| let s = atn.states[getState()]! |
| var following = atn.nextTokens(s) |
| if following.contains(symbol) { |
| return true |
| } |
| // System.out.println("following "+s+"="+following); |
| if !following.contains(CommonToken.EPSILON) { |
| return false |
| } |
| |
| while let ctxWrap = ctx, ctxWrap.invokingState >= 0 && following.contains(CommonToken.EPSILON) { |
| let invokingState = atn.states[ctxWrap.invokingState]! |
| let rt = invokingState.transition(0) as! RuleTransition |
| following = atn.nextTokens(rt.followState) |
| if following.contains(symbol) { |
| return true |
| } |
| |
| ctx = ctxWrap.parent as? ParserRuleContext |
| } |
| |
| if following.contains(CommonToken.EPSILON) && symbol == CommonToken.EOF { |
| return true |
| } |
| |
| return false |
| } |
| |
| /// |
| /// Computes the set of input symbols which could follow the current parser |
| /// state and context, as given by _#getState_ and _#getContext_, |
| /// respectively. |
| /// |
| /// - SeeAlso: org.antlr.v4.runtime.atn.ATN#getExpectedTokens(int, org.antlr.v4.runtime.RuleContext) |
| /// |
| public func getExpectedTokens() throws -> IntervalSet { |
| return try getATN().getExpectedTokens(getState(), getContext()!) |
| } |
| |
| |
| public func getExpectedTokensWithinCurrentRule() -> IntervalSet { |
| let atn = getInterpreter().atn |
| let s = atn.states[getState()]! |
| return atn.nextTokens(s) |
| } |
| |
| /// Get a rule's index (i.e., `RULE_ruleName` field) or -1 if not found. |
| public func getRuleIndex(_ ruleName: String) -> Int { |
| return getRuleIndexMap()[ruleName] ?? -1 |
| } |
| |
| public func getRuleContext() -> ParserRuleContext? { |
| return _ctx |
| } |
| |
| /// Return List<String> of the rule names in your parser instance |
| /// leading up to a call to the current rule. You could override if |
| /// you want more details such as the file/line info of where |
| /// in the ATN a rule is invoked. |
| /// |
| /// This is very useful for error messages. |
| /// |
| public func getRuleInvocationStack() -> [String] { |
| return getRuleInvocationStack(_ctx) |
| } |
| |
| public func getRuleInvocationStack(_ p: RuleContext?) -> [String] { |
| var p = p |
| let ruleNames = getRuleNames() |
| var stack = [String]() |
| while let pWrap = p { |
| // compute what follows who invoked us |
| let ruleIndex = pWrap.getRuleIndex() |
| if ruleIndex < 0 { |
| stack.append("n/a") |
| } else { |
| stack.append(ruleNames[ruleIndex]) |
| } |
| p = pWrap.parent |
| } |
| return stack |
| } |
| |
| /// For debugging and other purposes. |
| public func getDFAStrings() -> [String] { |
| guard let _interp = _interp else { |
| return [] |
| } |
| let vocab = getVocabulary() |
| return _interp.decisionToDFA.map { |
| $0.toString(vocab) |
| } |
| } |
| |
| /// For debugging and other purposes. |
| public func dumpDFA() { |
| guard let _interp = _interp else { |
| return |
| } |
| var seenOne = false |
| let vocab = getVocabulary() |
| for dfa in _interp.decisionToDFA { |
| if !dfa.states.isEmpty { |
| if seenOne { |
| print("") |
| } |
| print("Decision \(dfa.decision):") |
| print(dfa.toString(vocab), terminator: "") |
| seenOne = true |
| } |
| } |
| } |
| |
| public func getSourceName() -> String { |
| return _input.getSourceName() |
| } |
| |
| override |
| open func getParseInfo() -> ParseInfo? { |
| let interp = getInterpreter() |
| if let interp = interp as? ProfilingATNSimulator { |
| return ParseInfo(interp) |
| } |
| return nil |
| } |
| |
| /// |
| /// - Since: 4.3 |
| /// |
| public func setProfile(_ profile: Bool) { |
| let interp = getInterpreter() |
| let saveMode = interp.getPredictionMode() |
| if profile { |
| if !(interp is ProfilingATNSimulator) { |
| setInterpreter(ProfilingATNSimulator(self)) |
| } |
| } |
| else if interp is ProfilingATNSimulator { |
| let sim = ParserATNSimulator(self, getATN(), interp.decisionToDFA, interp.getSharedContextCache()) |
| setInterpreter(sim) |
| } |
| getInterpreter().setPredictionMode(saveMode) |
| } |
| |
| /// During a parse is sometimes useful to listen in on the rule entry and exit |
| /// events as well as token matches. This is for quick and dirty debugging. |
| /// |
| public func setTrace(_ trace: Bool) { |
| if !trace { |
| removeParseListener(_tracer) |
| _tracer = nil |
| } else { |
| if let _tracer = _tracer { |
| removeParseListener(_tracer) |
| } else { |
| _tracer = TraceListener(self) |
| } |
| addParseListener(_tracer!) |
| } |
| } |
| |
| /// |
| /// Gets whether a _org.antlr.v4.runtime.Parser.TraceListener_ is registered as a parse listener |
| /// for the parser. |
| /// |
| /// - SeeAlso: #setTrace(boolean) |
| /// |
| public func isTrace() -> Bool { |
| return _tracer != nil |
| } |
| } |