Skip to content

Commit 392c637

Browse files
committed
Implements antlr#1665 for Swift target. Slightly different because antlr#899 was not addressed in Swift target.
1 parent ec428d1 commit 392c637

File tree

3 files changed

+112
-53
lines changed

3 files changed

+112
-53
lines changed

runtime/Swift/Sources/Antlr4/ANTLRErrorStrategy.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@ public protocol ANTLRErrorStrategy {
7272
/// the parsing process
7373
func sync(_ recognizer: Parser) throws // RecognitionException;
7474

75-
/// Tests whether or not {@code recognizer} is in the process of recovering
75+
/// Tests whether or not recognizer} is in the process of recovering
7676
/// from an error. In error recovery mode, {@link org.antlr.v4.runtime.Parser#consume} adds
7777
/// symbols to the parse tree by calling
78-
/// {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode(org.antlr.v4.runtime.Token)} instead of
79-
/// {@link org.antlr.v4.runtime.ParserRuleContext#addChild(org.antlr.v4.runtime.Token)}.
78+
/// {@link Parser#createErrorNode(ParserRuleContext, Token)} then
79+
/// {@link ParserRuleContext#addErrorNode(ErrorNode)} instead of
80+
/// {@link Parser#createTerminalNode(ParserRuleContext, Token)}.
8081
///
8182
/// - parameter recognizer: the parser instance
8283
/// - returns: {@code true} if the parser is currently recovering from a parse

runtime/Swift/Sources/Antlr4/Parser.swift

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
/* Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
2-
* Use of this file is governed by the BSD 3-clause license that
3-
* can be found in the LICENSE.txt file in the project root.
4-
*/
5-
6-
7-
/** This is all the parsing support code essentially; most of it is error recovery stuff. */
8-
//public abstract class Parser : Recognizer<Token, ParserATNSimulator> {
1+
///
2+
/// Copyright (c) 2012-2016 The ANTLR Project. All rights reserved.
3+
/// Use of this file is governed by the BSD 3-clause license that
4+
/// can be found in the LICENSE.txt file in the project root.
5+
///
96

107
import Foundation
118

9+
/// This is all the parsing support code essentially; most of it is error recovery stuff.
1210
open class Parser: Recognizer<ParserATNSimulator> {
1311
public static let EOF: Int = -1
1412
public static var ConsoleError = true
15-
//false
1613

1714
public class TraceListener: ParseTreeListener {
1815
var host: Parser
@@ -62,10 +59,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
6259

6360

6461
public func exitEveryRule(_ ctx: ParserRuleContext) {
65-
//TODO: check necessary
66-
// if (ctx.children is ArrayList) {
67-
// (ctx.children as ArrayList<?>).trimToSize();
68-
// }
62+
// TODO: Print exit info.
6963
}
7064
}
7165

@@ -75,18 +69,15 @@ open class Parser: Recognizer<ParserATNSimulator> {
7569
*
7670
* @see org.antlr.v4.runtime.atn.ATNDeserializationOptions#isGenerateRuleBypassTransitions()
7771
*/
78-
//private let bypassAltsAtnCache : Dictionary<String, ATN> =
79-
// WeakHashMap<String, ATN>(); MapTable<NSString, ATN>
80-
8172
private let bypassAltsAtnCache: HashMap<String, ATN> = HashMap<String, ATN>()
73+
8274
/**
8375
* The error handling strategy for the parser. The default value is a new
8476
* instance of {@link org.antlr.v4.runtime.DefaultErrorStrategy}.
8577
*
8678
* @see #getErrorHandler
8779
* @see #setErrorHandler
8880
*/
89-
9081
public var _errHandler: ANTLRErrorStrategy = DefaultErrorStrategy()
9182

9283
/**
@@ -177,14 +168,15 @@ open class Parser: Recognizer<ParserATNSimulator> {
177168
* strategy to attempt recovery. If {@link #getBuildParseTree} is
178169
* {@code true} and the token index of the symbol returned by
179170
* {@link org.antlr.v4.runtime.ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
180-
* the parse tree by calling {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode}.</p>
171+
* the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then
172+
* {@link ParserRuleContext#addErrorNode(ErrorNode)}.</p>
181173
*
182174
* @param ttype the token type to match
183175
* @return the matched symbol
184176
* @throws org.antlr.v4.runtime.RecognitionException if the current input symbol did not match
185177
* {@code ttype} and the error strategy could not recover from the
186178
* mismatched symbol
187-
*///; RecognitionException
179+
*/
188180
@discardableResult
189181
public func match(_ ttype: Int) throws -> Token {
190182
var t: Token = try getCurrentToken()
@@ -196,7 +188,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
196188
if _buildParseTrees && t.getTokenIndex() == -1 {
197189
// we must have conjured up a new token during single token insertion
198190
// if it's not the current symbol
199-
_ctx!.addErrorNode(t)
191+
_ctx!.addErrorNode(createErrorNode(parent: _ctx!, t: t))
200192
}
201193
}
202194
return t
@@ -212,7 +204,8 @@ open class Parser: Recognizer<ParserATNSimulator> {
212204
* strategy to attempt recovery. If {@link #getBuildParseTree} is
213205
* {@code true} and the token index of the symbol returned by
214206
* {@link org.antlr.v4.runtime.ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
215-
* the parse tree by calling {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode}.</p>
207+
* the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then
208+
* {@link ParserRuleContext#addErrorNode(ErrorNode)}.</p>
216209
*
217210
* @return the matched symbol
218211
* @throws org.antlr.v4.runtime.RecognitionException if the current input symbol did not match
@@ -230,7 +223,7 @@ open class Parser: Recognizer<ParserATNSimulator> {
230223
if _buildParseTrees && t.getTokenIndex() == -1 {
231224
// we must have conjured up a new token during single token insertion
232225
// if it's not the current symbol
233-
_ctx!.addErrorNode(t)
226+
_ctx!.addErrorNode(createErrorNode(parent: _ctx!, t: t))
234227
}
235228
}
236229

@@ -562,11 +555,11 @@ open class Parser: Recognizer<ParserATNSimulator> {
562555
* </pre>
563556
*
564557
* If the parser is not in error recovery mode, the consumed symbol is added
565-
* to the parse tree using {@link org.antlr.v4.runtime.ParserRuleContext#addChild(org.antlr.v4.runtime.Token)}, and
558+
* to the parse tree using {@link ParserRuleContext#addChild(TerminalNode)}, and
566559
* {@link org.antlr.v4.runtime.tree.ParseTreeListener#visitTerminal} is called on any parse listeners.
567560
* If the parser <em>is</em> in error recovery mode, the consumed symbol is
568-
* added to the parse tree using
569-
* {@link org.antlr.v4.runtime.ParserRuleContext#addErrorNode(org.antlr.v4.runtime.Token)}, and
561+
* added to the parse tree using {@link #createErrorNode(ParserRuleContext, Token)} then
562+
* {@link ParserRuleContext#addErrorNode(ErrorNode)} and
570563
* {@link org.antlr.v4.runtime.tree.ParseTreeListener#visitErrorNode} is called on any parse
571564
* listeners.
572565
*/
@@ -583,14 +576,14 @@ open class Parser: Recognizer<ParserATNSimulator> {
583576

584577
if _buildParseTrees || hasListener {
585578
if _errHandler.inErrorRecoveryMode(self) {
586-
let node: ErrorNode = _ctx.addErrorNode(o)
579+
let node: ErrorNode = _ctx.addErrorNode(createErrorNode(parent: _ctx, t: o))
587580
if let _parseListeners = _parseListeners {
588581
for listener: ParseTreeListener in _parseListeners {
589582
listener.visitErrorNode(node)
590583
}
591584
}
592585
} else {
593-
let node: TerminalNode = _ctx.addChild(o)
586+
let node: TerminalNode = _ctx.addChild(createTerminalNode(parent: _ctx, t: o))
594587
if let _parseListeners = _parseListeners {
595588
for listener: ParseTreeListener in _parseListeners {
596589
listener.visitTerminal(node)
@@ -600,6 +593,38 @@ open class Parser: Recognizer<ParserATNSimulator> {
600593
}
601594
return o
602595
}
596+
597+
/** How to create a token leaf node associated with a parent.
598+
* Typically, the terminal node to create is not a function of the parent
599+
* but this method must still set the parent pointer of the terminal node
600+
* returned. I would prefer having {@link ParserRuleContext#addAnyChild(ParseTree)}
601+
* set the parent pointer, but the parent pointer is implementation dependent
602+
* and currently there is no setParent() in {@link TerminalNode} (and can't
603+
* add method in Java 1.7 without breaking backward compatibility).
604+
*
605+
* @since 4.6.1
606+
*/
607+
public func createTerminalNode(parent: ParserRuleContext, t: Token) -> TerminalNode {
608+
let node = TerminalNodeImpl(t);
609+
node.parent = parent;
610+
return node;
611+
}
612+
613+
/** How to create an error node, given a token, associated with a parent.
614+
* Typically, the error node to create is not a function of the parent
615+
* but this method must still set the parent pointer of the terminal node
616+
* returned. I would prefer having {@link ParserRuleContext#addAnyChild(ParseTree)}
617+
* set the parent pointer, but the parent pointer is implementation dependent
618+
* and currently there is no setParent() in {@link ErrorNode} (and can't
619+
* add method in Java 1.7 without breaking backward compatibility).
620+
*
621+
* @since 4.6.1
622+
*/
623+
public func createErrorNode(parent: ParserRuleContext, t: Token) -> ErrorNode {
624+
let node = ErrorNode(t);
625+
node.parent = parent;
626+
return node;
627+
}
603628

604629
internal func addContextToParseTree() {
605630

runtime/Swift/Sources/Antlr4/ParserRuleContext.swift

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -105,51 +105,84 @@ open class ParserRuleContext: RuleContext {
105105
open func exitRule(_ listener: ParseTreeListener) {
106106
}
107107

108-
/** Does not set parent link; other add methods do that */
108+
/** Add a parse tree node to this as a child. Works for
109+
* internal and leaf nodes. Does not set parent link;
110+
* other add methods must do that. Other addChild methods
111+
* call this.
112+
*
113+
* We cannot set the parent pointer of the incoming node
114+
* because the existing interfaces do not have a setParent()
115+
* method and I don't want to break backward compatibility for this.
116+
*
117+
* @since 4.6.1
118+
*/
109119
@discardableResult
110-
open func addChild(_ t: TerminalNode) -> TerminalNode {
120+
open func addAnyChild<T: ParseTree>(_ t: T) -> T {
111121
if children == nil {
112-
children = Array<ParseTree>()
122+
children = [T]()
113123
}
114124
children!.append(t)
115125
return t
116126
}
127+
117128
@discardableResult
118129
open func addChild(_ ruleInvocation: RuleContext) -> RuleContext {
119-
if children == nil {
120-
children = Array<ParseTree>()
121-
}
122-
children!.append(ruleInvocation)
123-
return ruleInvocation
130+
return addAnyChild(ruleInvocation)
124131
}
125-
126-
/** Used by enterOuterAlt to toss out a RuleContext previously added as
127-
* we entered a rule. If we have # label, we will need to remove
128-
* generic ruleContext object.
129-
*/
130-
open func removeLastChild() {
131-
children?.removeLast()
132-
//children.remove(children.size()-1);
132+
133+
@discardableResult
134+
open func addChild(_ t: TerminalNode) -> TerminalNode {
135+
return addAnyChild(t)
136+
}
137+
138+
/** Add an error node child. @since 4.6.1 */
139+
@discardableResult
140+
open func addErrorNode(_ errorNode: ErrorNode) -> ErrorNode {
141+
return addAnyChild(errorNode)
133142
}
134143

135-
// public void trace(int s) {
136-
// if ( states==null ) states = new ArrayList<Integer>();
137-
// states.add(s);
138-
// }
139-
144+
/** Add a child to this node based upon matchedToken. It
145+
* creates a TerminalNodeImpl rather than using
146+
* {@link Parser#createTerminalNode(ParserRuleContext, Token)}. I'm leaving this
147+
* in for compatibility but the parser doesn't use this anymore.
148+
*/
149+
@available(*, deprecated)
140150
open func addChild(_ matchedToken: Token) -> TerminalNode {
141151
let t: TerminalNodeImpl = TerminalNodeImpl(matchedToken)
142-
addChild(t)
152+
addAnyChild(t)
143153
t.parent = self
144154
return t
145155
}
156+
157+
/** Add a child to this node based upon badToken. It
158+
* creates a ErrorNodeImpl rather than using
159+
* {@link Parser#createErrorNode(ParserRuleContext, Token)}. I'm leaving this
160+
* in for compatibility but the parser doesn't use this anymore.
161+
*/
146162
@discardableResult
163+
@available(*, deprecated)
147164
open func addErrorNode(_ badToken: Token) -> ErrorNode {
148165
let t: ErrorNode = ErrorNode(badToken)
149-
addChild(t)
166+
addAnyChild(t)
150167
t.parent = self
151168
return t
152169
}
170+
171+
// public void trace(int s) {
172+
// if ( states==null ) states = new ArrayList<Integer>();
173+
// states.add(s);
174+
// }
175+
176+
/** Used by enterOuterAlt to toss out a RuleContext previously added as
177+
* we entered a rule. If we have # label, we will need to remove
178+
* generic ruleContext object.
179+
*/
180+
open func removeLastChild() {
181+
if children != nil {
182+
children!.remove(at: children!.count-1)
183+
}
184+
}
185+
153186

154187
override
155188
/** Override to make type more specific */

0 commit comments

Comments
 (0)