From 392c637565743b8a85a050971c2de1cc7c9319bd Mon Sep 17 00:00:00 2001
From: Hanzhou Shi
Date: Fri, 24 Feb 2017 23:14:24 -0800
Subject: [PATCH 1/2] Implements #1665 for Swift target. Slightly different
because #899 was not addressed in Swift target.
---
.../Sources/Antlr4/ANTLRErrorStrategy.swift | 7 +-
runtime/Swift/Sources/Antlr4/Parser.swift | 79 ++++++++++------
.../Sources/Antlr4/ParserRuleContext.swift | 93 +++++++++++++------
3 files changed, 119 insertions(+), 60 deletions(-)
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..7aa4e1fa8 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,38 @@ 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
+ * but this method must still set the parent pointer of the terminal node
+ * returned. I would prefer having {@link ParserRuleContext#addAnyChild(ParseTree)}
+ * set the parent pointer, but the parent pointer is implementation dependent
+ * and currently there is no setParent() in {@link TerminalNode} (and can't
+ * add method in Java 1.7 without breaking backward compatibility).
+ *
+ * @since 4.6.1
+ */
+ public func createTerminalNode(parent: ParserRuleContext, t: Token) -> TerminalNode {
+ let node = TerminalNodeImpl(t);
+ node.parent = parent;
+ return node;
+ }
+
+ /** 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
+ * but this method must still set the parent pointer of the terminal node
+ * returned. I would prefer having {@link ParserRuleContext#addAnyChild(ParseTree)}
+ * set the parent pointer, but the parent pointer is implementation dependent
+ * and currently there is no setParent() in {@link ErrorNode} (and can't
+ * add method in Java 1.7 without breaking backward compatibility).
+ *
+ * @since 4.6.1
+ */
+ public func createErrorNode(parent: ParserRuleContext, t: Token) -> ErrorNode {
+ let node = ErrorNode(t);
+ node.parent = parent;
+ return node;
+ }
internal func addContextToParseTree() {
diff --git a/runtime/Swift/Sources/Antlr4/ParserRuleContext.swift b/runtime/Swift/Sources/Antlr4/ParserRuleContext.swift
index 13c91d6ef..a39aa8ea1 100644
--- a/runtime/Swift/Sources/Antlr4/ParserRuleContext.swift
+++ b/runtime/Swift/Sources/Antlr4/ParserRuleContext.swift
@@ -105,51 +105,84 @@ 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)
+ }
+
+ @discardableResult
+ open func addChild(_ t: TerminalNode) -> TerminalNode {
+ return addAnyChild(t)
+ }
+
+ /** Add an error node child. @since 4.6.1 */
+ @discardableResult
+ open func addErrorNode(_ errorNode: ErrorNode) -> ErrorNode {
+ 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.parent = 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.parent = 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 */
From 38c3aaae8ff5ac4ea11af42e9ce5c5c4774d64f6 Mon Sep 17 00:00:00 2001
From: Hanzhou Shi
Date: Fri, 24 Feb 2017 23:54:25 -0800
Subject: [PATCH 2/2] Implements #1674 "augment TerminalNode with setParent()"
for Swift target.
---
runtime/Swift/Sources/Antlr4/Parser.swift | 22 +++-----------
.../Sources/Antlr4/ParserRuleContext.swift | 29 ++++++++++++++-----
.../Sources/Antlr4/tree/TerminalNode.swift | 14 +++++++++
.../Antlr4/tree/TerminalNodeImpl.swift | 5 ++++
4 files changed, 44 insertions(+), 26 deletions(-)
diff --git a/runtime/Swift/Sources/Antlr4/Parser.swift b/runtime/Swift/Sources/Antlr4/Parser.swift
index 7aa4e1fa8..7b6522523 100644
--- a/runtime/Swift/Sources/Antlr4/Parser.swift
+++ b/runtime/Swift/Sources/Antlr4/Parser.swift
@@ -595,35 +595,21 @@ open class Parser: Recognizer {
}
/** How to create a token leaf node associated with a parent.
- * Typically, the terminal node to create is not a function of the parent
- * but this method must still set the parent pointer of the terminal node
- * returned. I would prefer having {@link ParserRuleContext#addAnyChild(ParseTree)}
- * set the parent pointer, but the parent pointer is implementation dependent
- * and currently there is no setParent() in {@link TerminalNode} (and can't
- * add method in Java 1.7 without breaking backward compatibility).
+ * 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 {
- let node = TerminalNodeImpl(t);
- node.parent = parent;
- return node;
+ 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
- * but this method must still set the parent pointer of the terminal node
- * returned. I would prefer having {@link ParserRuleContext#addAnyChild(ParseTree)}
- * set the parent pointer, but the parent pointer is implementation dependent
- * and currently there is no setParent() in {@link ErrorNode} (and can't
- * add method in Java 1.7 without breaking backward compatibility).
+ * 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 {
- let node = ErrorNode(t);
- node.parent = parent;
- return node;
+ return ErrorNode(t);
}
internal func addContextToParseTree() {
diff --git a/runtime/Swift/Sources/Antlr4/ParserRuleContext.swift b/runtime/Swift/Sources/Antlr4/ParserRuleContext.swift
index a39aa8ea1..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)
}
}
}
@@ -130,14 +137,20 @@ open class ParserRuleContext: RuleContext {
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. @since 4.6.1 */
+ /** 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)
}
@@ -150,7 +163,7 @@ open class ParserRuleContext: RuleContext {
open func addChild(_ matchedToken: Token) -> TerminalNode {
let t: TerminalNodeImpl = TerminalNodeImpl(matchedToken)
addAnyChild(t)
- t.parent = self
+ t.setParent(self)
return t
}
@@ -164,7 +177,7 @@ open class ParserRuleContext: RuleContext {
open func addErrorNode(_ badToken: Token) -> ErrorNode {
let t: ErrorNode = ErrorNode(badToken)
addAnyChild(t)
- t.parent = self
+ t.setParent(self)
return t
}
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