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