diff --git a/runtime/Swift/Sources/Antlr4/ANTLRErrorStrategy.swift b/runtime/Swift/Sources/Antlr4/ANTLRErrorStrategy.swift index ffa726461..395d99b7e 100644 --- a/runtime/Swift/Sources/Antlr4/ANTLRErrorStrategy.swift +++ b/runtime/Swift/Sources/Antlr4/ANTLRErrorStrategy.swift @@ -72,11 +72,12 @@ public protocol ANTLRErrorStrategy { /// the parsing process func sync(_ recognizer: Parser) throws // RecognitionException; - /// Tests whether or not {@code recognizer} is in the process of recovering + /// Tests whether or not recognizer} is in the process of recovering /// from an error. In error recovery mode, {@link org.antlr.v4.runtime.Parser#consume} adds /// symbols to the parse tree by calling - /// {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode(org.antlr.v4.runtime.Token)} instead of - /// {@link org.antlr.v4.runtime.ParserRuleContext#addChild(org.antlr.v4.runtime.Token)}. + /// {@link Parser#createErrorNode(ParserRuleContext, Token)} then + /// {@link ParserRuleContext#addErrorNode(ErrorNode)} instead of + /// {@link Parser#createTerminalNode(ParserRuleContext, Token)}. /// /// - parameter recognizer: the parser instance /// - returns: {@code true} if the parser is currently recovering from a parse diff --git a/runtime/Swift/Sources/Antlr4/Parser.swift b/runtime/Swift/Sources/Antlr4/Parser.swift index f4360c743..7b6522523 100644 --- a/runtime/Swift/Sources/Antlr4/Parser.swift +++ b/runtime/Swift/Sources/Antlr4/Parser.swift @@ -1,18 +1,15 @@ -/* Copyright (c) 2012-2016 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. - */ - - -/** This is all the parsing support code essentially; most of it is error recovery stuff. */ -//public abstract class Parser : Recognizer { +/// +/// Copyright (c) 2012-2016 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 is all the parsing support code essentially; most of it is error recovery stuff. open class Parser: Recognizer { public static let EOF: Int = -1 public static var ConsoleError = true - //false public class TraceListener: ParseTreeListener { var host: Parser @@ -62,10 +59,7 @@ open class Parser: Recognizer { public func exitEveryRule(_ ctx: ParserRuleContext) { - //TODO: check necessary -// if (ctx.children is ArrayList) { -// (ctx.children as ArrayList).trimToSize(); -// } + // TODO: Print exit info. } } @@ -75,10 +69,8 @@ open class Parser: Recognizer { * * @see org.antlr.v4.runtime.atn.ATNDeserializationOptions#isGenerateRuleBypassTransitions() */ - //private let bypassAltsAtnCache : Dictionary = - // WeakHashMap(); MapTable - private let bypassAltsAtnCache: HashMap = HashMap() + /** * The error handling strategy for the parser. The default value is a new * instance of {@link org.antlr.v4.runtime.DefaultErrorStrategy}. @@ -86,7 +78,6 @@ open class Parser: Recognizer { * @see #getErrorHandler * @see #setErrorHandler */ - public var _errHandler: ANTLRErrorStrategy = DefaultErrorStrategy() /** @@ -177,14 +168,15 @@ open class Parser: Recognizer { * strategy to attempt recovery. If {@link #getBuildParseTree} is * {@code true} and the token index of the symbol returned by * {@link org.antlr.v4.runtime.ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to - * the parse tree by calling {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode}.

+ * the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then + * {@link ParserRuleContext#addErrorNode(ErrorNode)}.

* * @param ttype the token type to match * @return the matched symbol * @throws org.antlr.v4.runtime.RecognitionException if the current input symbol did not match * {@code ttype} and the error strategy could not recover from the * mismatched symbol - *///; RecognitionException + */ @discardableResult public func match(_ ttype: Int) throws -> Token { var t: Token = try getCurrentToken() @@ -196,7 +188,7 @@ open class Parser: Recognizer { 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(t) + _ctx!.addErrorNode(createErrorNode(parent: _ctx!, t: t)) } } return t @@ -212,7 +204,8 @@ open class Parser: Recognizer { * strategy to attempt recovery. If {@link #getBuildParseTree} is * {@code true} and the token index of the symbol returned by * {@link org.antlr.v4.runtime.ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to - * the parse tree by calling {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode}.

+ * the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then + * {@link ParserRuleContext#addErrorNode(ErrorNode)}.

* * @return the matched symbol * @throws org.antlr.v4.runtime.RecognitionException if the current input symbol did not match @@ -230,7 +223,7 @@ open class Parser: Recognizer { 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(t) + _ctx!.addErrorNode(createErrorNode(parent: _ctx!, t: t)) } } @@ -562,11 +555,11 @@ open class Parser: Recognizer { * * * If the parser is not in error recovery mode, the consumed symbol is added - * to the parse tree using {@link org.antlr.v4.runtime.ParserRuleContext#addChild(org.antlr.v4.runtime.Token)}, and + * to the parse tree using {@link ParserRuleContext#addChild(TerminalNode)}, and * {@link 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 - * {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode(org.antlr.v4.runtime.Token)}, and + * added to the parse tree using {@link #createErrorNode(ParserRuleContext, Token)} then + * {@link ParserRuleContext#addErrorNode(ErrorNode)} and * {@link org.antlr.v4.runtime.tree.ParseTreeListener#visitErrorNode} is called on any parse * listeners. */ @@ -583,14 +576,14 @@ open class Parser: Recognizer { if _buildParseTrees || hasListener { if _errHandler.inErrorRecoveryMode(self) { - let node: ErrorNode = _ctx.addErrorNode(o) + let node: ErrorNode = _ctx.addErrorNode(createErrorNode(parent: _ctx, t: o)) if let _parseListeners = _parseListeners { for listener: ParseTreeListener in _parseListeners { listener.visitErrorNode(node) } } } else { - let node: TerminalNode = _ctx.addChild(o) + let node: TerminalNode = _ctx.addChild(createTerminalNode(parent: _ctx, t: o)) if let _parseListeners = _parseListeners { for listener: ParseTreeListener in _parseListeners { listener.visitTerminal(node) @@ -600,6 +593,24 @@ open class Parser: Recognizer { } 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.6.1 + */ + 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.6.1 + */ + public func createErrorNode(parent: ParserRuleContext, t: Token) -> ErrorNode { + return ErrorNode(t); + } internal func addContextToParseTree() { diff --git a/runtime/Swift/Sources/Antlr4/ParserRuleContext.swift b/runtime/Swift/Sources/Antlr4/ParserRuleContext.swift index 13c91d6ef..a71f93c19 100644 --- a/runtime/Swift/Sources/Antlr4/ParserRuleContext.swift +++ b/runtime/Swift/Sources/Antlr4/ParserRuleContext.swift @@ -72,6 +72,14 @@ open class ParserRuleContext: RuleContext { /** COPY a ctx (I'm deliberately not using copy constructor) to avoid * confusion with creating node with parent. Does not copy children. + * + * This is used in the generated parser code to flip a generic XContext + * node for rule X to a YContext for alt label Y. In that sense, it is + * not really a generic copy function. + * + * If we do an error sync() at start of a rule, we might add error nodes + * to the generic XContext so this function must copy those nodes to + * the YContext as well else they are lost! */ open func copyFrom(_ ctx: ParserRuleContext) { self.parent = ctx.parent @@ -81,13 +89,12 @@ open class ParserRuleContext: RuleContext { self.stop = ctx.stop // copy any error nodes to alt label node - if ctx.children != nil{ + if ctx.children != nil { self.children = Array() // reset parent pointer for any error nodes - for child: ParseTree in ctx.children! { - if child is ErrorNode{ - self.children?.append(child) - ( (child as! ErrorNode)).parent = self + for child: ParseTree in ctx.children! { + if child is ErrorNode { + addChild(child as! ErrorNode) } } } @@ -105,51 +112,90 @@ open class ParserRuleContext: RuleContext { open func exitRule(_ listener: ParseTreeListener) { } - /** Does not set parent link; other add methods do that */ + /** Add a parse tree node to this as a child. Works for + * internal and leaf nodes. Does not set parent link; + * other add methods must do that. Other addChild methods + * call this. + * + * We cannot set the parent pointer of the incoming node + * because the existing interfaces do not have a setParent() + * method and I don't want to break backward compatibility for this. + * + * @since 4.6.1 + */ @discardableResult - open func addChild(_ t: TerminalNode) -> TerminalNode { + open func addAnyChild(_ t: T) -> T { if children == nil { - children = Array() + children = [T]() } children!.append(t) return t } + @discardableResult open func addChild(_ ruleInvocation: RuleContext) -> RuleContext { - if children == nil { - children = Array() - } - children!.append(ruleInvocation) - return ruleInvocation + return addAnyChild(ruleInvocation) + } + + /** Add a token leaf node child and force its parent to be this node. */ + @discardableResult + open func addChild(_ t: TerminalNode) -> TerminalNode { + t.setParent(self) + return addAnyChild(t) + } + + /** Add an error node child and force its parent to be this node. + * + * @since 4.6.1 + */ + @discardableResult + open func addErrorNode(_ errorNode: ErrorNode) -> ErrorNode { + errorNode.setParent(self) + return addAnyChild(errorNode) } + /** Add a child to this node based upon matchedToken. It + * creates a TerminalNodeImpl rather than using + * {@link Parser#createTerminalNode(ParserRuleContext, Token)}. I'm leaving this + * in for compatibility but the parser doesn't use this anymore. + */ + @available(*, deprecated) + open func addChild(_ matchedToken: Token) -> TerminalNode { + let t: TerminalNodeImpl = TerminalNodeImpl(matchedToken) + addAnyChild(t) + t.setParent(self) + return t + } + + /** Add a child to this node based upon badToken. It + * creates a ErrorNodeImpl rather than using + * {@link Parser#createErrorNode(ParserRuleContext, Token)}. I'm leaving this + * in for compatibility but the parser doesn't use this anymore. + */ + @discardableResult + @available(*, deprecated) + open func addErrorNode(_ badToken: Token) -> ErrorNode { + let t: ErrorNode = ErrorNode(badToken) + addAnyChild(t) + t.setParent(self) + return t + } + + // public void trace(int s) { + // if ( states==null ) states = new ArrayList(); + // states.add(s); + // } + /** Used by enterOuterAlt to toss out a RuleContext previously added as * we entered a rule. If we have # label, we will need to remove * generic ruleContext object. - */ + */ open func removeLastChild() { - children?.removeLast() - //children.remove(children.size()-1); - } - -// public void trace(int s) { -// if ( states==null ) states = new ArrayList(); -// states.add(s); -// } - - open func addChild(_ matchedToken: Token) -> TerminalNode { - let t: TerminalNodeImpl = TerminalNodeImpl(matchedToken) - addChild(t) - t.parent = self - return t - } - @discardableResult - open func addErrorNode(_ badToken: Token) -> ErrorNode { - let t: ErrorNode = ErrorNode(badToken) - addChild(t) - t.parent = self - return t + if children != nil { + children!.remove(at: children!.count-1) + } } + override /** Override to make type more specific */ diff --git a/runtime/Swift/Sources/Antlr4/tree/TerminalNode.swift b/runtime/Swift/Sources/Antlr4/tree/TerminalNode.swift index f3d41f648..0542673dd 100644 --- a/runtime/Swift/Sources/Antlr4/tree/TerminalNode.swift +++ b/runtime/Swift/Sources/Antlr4/tree/TerminalNode.swift @@ -9,4 +9,18 @@ public class TerminalNode: ParseTree { fatalError() } + + /** Set the parent for this leaf node. + * + * Technically, this is not backward compatible as it changes + * the interface but no one was able to create custom + * TerminalNodes anyway so I'm adding as it improves internal + * code quality. + * + * @since 4.6.1 + */ + public func setParent(_ parent: RuleContext) { + RuntimeException(" must overriden !") + fatalError() + } } diff --git a/runtime/Swift/Sources/Antlr4/tree/TerminalNodeImpl.swift b/runtime/Swift/Sources/Antlr4/tree/TerminalNodeImpl.swift index a53f8a6ed..7c03aeee9 100644 --- a/runtime/Swift/Sources/Antlr4/tree/TerminalNodeImpl.swift +++ b/runtime/Swift/Sources/Antlr4/tree/TerminalNodeImpl.swift @@ -27,6 +27,11 @@ public class TerminalNodeImpl: TerminalNode { return parent } + override + public func setParent(_ parent: RuleContext) { + self.parent = parent + } + override public func getPayload() -> AnyObject { return symbol