Merge pull request #1665 from parrt/factor-create-leaves
factor out the creation of error nodes and terminal nodes in the parser
This commit is contained in:
commit
628aa8ff02
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
package org.antlr.v4.runtime;
|
package org.antlr.v4.runtime;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.tree.ErrorNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interface for defining strategies to deal with syntax errors encountered
|
* The interface for defining strategies to deal with syntax errors encountered
|
||||||
* during a parse by ANTLR-generated parsers. We distinguish between three
|
* during a parse by ANTLR-generated parsers. We distinguish between three
|
||||||
|
@ -89,8 +91,9 @@ public interface ANTLRErrorStrategy {
|
||||||
* Tests whether or not {@code recognizer} is in the process of recovering
|
* Tests whether or not {@code recognizer} is in the process of recovering
|
||||||
* from an error. In error recovery mode, {@link Parser#consume} adds
|
* from an error. In error recovery mode, {@link Parser#consume} adds
|
||||||
* symbols to the parse tree by calling
|
* symbols to the parse tree by calling
|
||||||
* {@link ParserRuleContext#addErrorNode(Token)} instead of
|
* {@link Parser#createErrorNode(ParserRuleContext, Token)} then
|
||||||
* {@link ParserRuleContext#addChild(Token)}.
|
* {@link ParserRuleContext#addErrorNode(ErrorNode)} instead of
|
||||||
|
* {@link Parser#createTerminalNode(ParserRuleContext, Token)}.
|
||||||
*
|
*
|
||||||
* @param recognizer the parser instance
|
* @param recognizer the parser instance
|
||||||
* @return {@code true} if the parser is currently recovering from a parse
|
* @return {@code true} if the parser is currently recovering from a parse
|
||||||
|
|
|
@ -19,9 +19,12 @@ import org.antlr.v4.runtime.dfa.DFA;
|
||||||
import org.antlr.v4.runtime.misc.IntegerStack;
|
import org.antlr.v4.runtime.misc.IntegerStack;
|
||||||
import org.antlr.v4.runtime.misc.IntervalSet;
|
import org.antlr.v4.runtime.misc.IntervalSet;
|
||||||
import org.antlr.v4.runtime.tree.ErrorNode;
|
import org.antlr.v4.runtime.tree.ErrorNode;
|
||||||
|
import org.antlr.v4.runtime.tree.ErrorNodeImpl;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
import org.antlr.v4.runtime.tree.ParseTreeListener;
|
import org.antlr.v4.runtime.tree.ParseTreeListener;
|
||||||
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
import org.antlr.v4.runtime.tree.ParseTreeWalker;
|
||||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
|
import org.antlr.v4.runtime.tree.TerminalNodeImpl;
|
||||||
import org.antlr.v4.runtime.tree.pattern.ParseTreePattern;
|
import org.antlr.v4.runtime.tree.pattern.ParseTreePattern;
|
||||||
import org.antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher;
|
import org.antlr.v4.runtime.tree.pattern.ParseTreePatternMatcher;
|
||||||
|
|
||||||
|
@ -182,7 +185,8 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
|
||||||
* strategy to attempt recovery. If {@link #getBuildParseTree} is
|
* strategy to attempt recovery. If {@link #getBuildParseTree} is
|
||||||
* {@code true} and the token index of the symbol returned by
|
* {@code true} and the token index of the symbol returned by
|
||||||
* {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
|
* {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
|
||||||
* the parse tree by calling {@link ParserRuleContext#addErrorNode}.</p>
|
* the parse tree by calling {@link #createErrorNode(ParserRuleContext, Token)} then
|
||||||
|
* {@link ParserRuleContext#addErrorNode(ErrorNode)}.</p>
|
||||||
*
|
*
|
||||||
* @param ttype the token type to match
|
* @param ttype the token type to match
|
||||||
* @return the matched symbol
|
* @return the matched symbol
|
||||||
|
@ -204,7 +208,7 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
|
||||||
if ( _buildParseTrees && t.getTokenIndex()==-1 ) {
|
if ( _buildParseTrees && t.getTokenIndex()==-1 ) {
|
||||||
// we must have conjured up a new token during single token insertion
|
// we must have conjured up a new token during single token insertion
|
||||||
// if it's not the current symbol
|
// if it's not the current symbol
|
||||||
_ctx.addErrorNode(t);
|
_ctx.addErrorNode(createErrorNode(_ctx,t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
|
@ -220,7 +224,8 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
|
||||||
* strategy to attempt recovery. If {@link #getBuildParseTree} is
|
* strategy to attempt recovery. If {@link #getBuildParseTree} is
|
||||||
* {@code true} and the token index of the symbol returned by
|
* {@code true} and the token index of the symbol returned by
|
||||||
* {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
|
* {@link ANTLRErrorStrategy#recoverInline} is -1, the symbol is added to
|
||||||
* the parse tree by calling {@link ParserRuleContext#addErrorNode}.</p>
|
* the parse tree by calling {@link Parser#createErrorNode(ParserRuleContext, Token)}. then
|
||||||
|
* {@link ParserRuleContext#addErrorNode(ErrorNode)}</p>
|
||||||
*
|
*
|
||||||
* @return the matched symbol
|
* @return the matched symbol
|
||||||
* @throws RecognitionException if the current input symbol did not match
|
* @throws RecognitionException if the current input symbol did not match
|
||||||
|
@ -238,7 +243,7 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
|
||||||
if (_buildParseTrees && t.getTokenIndex() == -1) {
|
if (_buildParseTrees && t.getTokenIndex() == -1) {
|
||||||
// we must have conjured up a new token during single token insertion
|
// we must have conjured up a new token during single token insertion
|
||||||
// if it's not the current symbol
|
// if it's not the current symbol
|
||||||
_ctx.addErrorNode(t);
|
_ctx.addErrorNode(createErrorNode(_ctx,t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -553,11 +558,11 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* If the parser is not in error recovery mode, the consumed symbol is added
|
* If the parser is not in error recovery mode, the consumed symbol is added
|
||||||
* to the parse tree using {@link ParserRuleContext#addChild(Token)}, and
|
* to the parse tree using {@link ParserRuleContext#addChild(TerminalNode)}, and
|
||||||
* {@link ParseTreeListener#visitTerminal} is called on any parse listeners.
|
* {@link ParseTreeListener#visitTerminal} is called on any parse listeners.
|
||||||
* If the parser <em>is</em> in error recovery mode, the consumed symbol is
|
* If the parser <em>is</em> in error recovery mode, the consumed symbol is
|
||||||
* added to the parse tree using
|
* added to the parse tree using {@link #createErrorNode(ParserRuleContext, Token)} then
|
||||||
* {@link ParserRuleContext#addErrorNode(Token)}, and
|
* {@link ParserRuleContext#addErrorNode(ErrorNode)} and
|
||||||
* {@link ParseTreeListener#visitErrorNode} is called on any parse
|
* {@link ParseTreeListener#visitErrorNode} is called on any parse
|
||||||
* listeners.
|
* listeners.
|
||||||
*/
|
*/
|
||||||
|
@ -569,7 +574,7 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
|
||||||
boolean hasListener = _parseListeners != null && !_parseListeners.isEmpty();
|
boolean hasListener = _parseListeners != null && !_parseListeners.isEmpty();
|
||||||
if (_buildParseTrees || hasListener) {
|
if (_buildParseTrees || hasListener) {
|
||||||
if ( _errHandler.inErrorRecoveryMode(this) ) {
|
if ( _errHandler.inErrorRecoveryMode(this) ) {
|
||||||
ErrorNode node = _ctx.addErrorNode(o);
|
ErrorNode node = _ctx.addErrorNode(createErrorNode(_ctx,o));
|
||||||
if (_parseListeners != null) {
|
if (_parseListeners != null) {
|
||||||
for (ParseTreeListener listener : _parseListeners) {
|
for (ParseTreeListener listener : _parseListeners) {
|
||||||
listener.visitErrorNode(node);
|
listener.visitErrorNode(node);
|
||||||
|
@ -577,7 +582,7 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TerminalNode node = _ctx.addChild(o);
|
TerminalNode node = _ctx.addChild(createTerminalNode(_ctx,o));
|
||||||
if (_parseListeners != null) {
|
if (_parseListeners != null) {
|
||||||
for (ParseTreeListener listener : _parseListeners) {
|
for (ParseTreeListener listener : _parseListeners) {
|
||||||
listener.visitTerminal(node);
|
listener.visitTerminal(node);
|
||||||
|
@ -588,6 +593,38 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
|
||||||
return o;
|
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 TerminalNode createTerminalNode(ParserRuleContext parent, Token t) {
|
||||||
|
TerminalNodeImpl node = new 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 ErrorNode createErrorNode(ParserRuleContext parent, Token t) {
|
||||||
|
ErrorNodeImpl node = new ErrorNodeImpl(t);
|
||||||
|
node.parent = parent;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
protected void addContextToParseTree() {
|
protected void addContextToParseTree() {
|
||||||
ParserRuleContext parent = (ParserRuleContext)_ctx.parent;
|
ParserRuleContext parent = (ParserRuleContext)_ctx.parent;
|
||||||
// add current context to parent if we have a parent
|
// add current context to parent if we have a parent
|
||||||
|
@ -925,3 +962,4 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
|
||||||
return _tracer != null;
|
return _tracer != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -414,7 +414,7 @@ public class ParserInterpreter extends Parser {
|
||||||
Token.DEFAULT_CHANNEL,
|
Token.DEFAULT_CHANNEL,
|
||||||
-1, -1, // invalid start/stop
|
-1, -1, // invalid start/stop
|
||||||
tok.getLine(), tok.getCharPositionInLine());
|
tok.getLine(), tok.getCharPositionInLine());
|
||||||
_ctx.addErrorNode(errToken);
|
_ctx.addErrorNode(createErrorNode(_ctx,errToken));
|
||||||
}
|
}
|
||||||
else { // NoViableAlt
|
else { // NoViableAlt
|
||||||
Token tok = e.getOffendingToken();
|
Token tok = e.getOffendingToken();
|
||||||
|
@ -424,7 +424,7 @@ public class ParserInterpreter extends Parser {
|
||||||
Token.DEFAULT_CHANNEL,
|
Token.DEFAULT_CHANNEL,
|
||||||
-1, -1, // invalid start/stop
|
-1, -1, // invalid start/stop
|
||||||
tok.getLine(), tok.getCharPositionInLine());
|
tok.getLine(), tok.getCharPositionInLine());
|
||||||
_ctx.addErrorNode(errToken);
|
_ctx.addErrorNode(createErrorNode(_ctx,errToken));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -445,3 +445,4 @@ public class ParserInterpreter extends Parser {
|
||||||
return rootContext;
|
return rootContext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,8 +63,8 @@ public class ParserRuleContext extends RuleContext {
|
||||||
*
|
*
|
||||||
* The parser setState() method updates field s and adds it to this list
|
* The parser setState() method updates field s and adds it to this list
|
||||||
* if we are debugging/tracing.
|
* if we are debugging/tracing.
|
||||||
*
|
*
|
||||||
* This does not trace states visited during prediction.
|
* This does not trace states visited during prediction.
|
||||||
*/
|
*/
|
||||||
// public List<Integer> states;
|
// public List<Integer> states;
|
||||||
|
|
||||||
|
@ -118,27 +118,60 @@ public class ParserRuleContext extends RuleContext {
|
||||||
public void enterRule(ParseTreeListener listener) { }
|
public void enterRule(ParseTreeListener listener) { }
|
||||||
public void exitRule(ParseTreeListener listener) { }
|
public void exitRule(ParseTreeListener listener) { }
|
||||||
|
|
||||||
/** Does not set parent link; other add methods do that */
|
/** Add a parse tree node to this as a child. Works for
|
||||||
public TerminalNode addChild(TerminalNode t) {
|
* internal and leaf nodes. Does not set parent link;
|
||||||
if ( children==null ) children = new ArrayList<ParseTree>();
|
* 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
|
||||||
|
*/
|
||||||
|
public <T extends ParseTree> T addAnyChild(T t) {
|
||||||
|
if ( children==null ) children = new ArrayList<>();
|
||||||
children.add(t);
|
children.add(t);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RuleContext addChild(RuleContext ruleInvocation) {
|
public RuleContext addChild(RuleContext ruleInvocation) {
|
||||||
if ( children==null ) children = new ArrayList<ParseTree>();
|
return addAnyChild(ruleInvocation);
|
||||||
children.add(ruleInvocation);
|
|
||||||
return ruleInvocation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used by enterOuterAlt to toss out a RuleContext previously added as
|
public TerminalNode addChild(TerminalNode t) {
|
||||||
* we entered a rule. If we have # label, we will need to remove
|
return addAnyChild(t);
|
||||||
* generic ruleContext object.
|
}
|
||||||
*/
|
|
||||||
public void removeLastChild() {
|
/** Add an error node child. @since 4.6.1 */
|
||||||
if ( children!=null ) {
|
public ErrorNode addErrorNode(ErrorNode errorNode) {
|
||||||
children.remove(children.size()-1);
|
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.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public TerminalNode addChild(Token matchedToken) {
|
||||||
|
TerminalNodeImpl t = new TerminalNodeImpl(matchedToken);
|
||||||
|
addAnyChild(t);
|
||||||
|
t.parent = this;
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public ErrorNode addErrorNode(Token badToken) {
|
||||||
|
ErrorNodeImpl t = new ErrorNodeImpl(badToken);
|
||||||
|
addAnyChild(t);
|
||||||
|
t.parent = this;
|
||||||
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void trace(int s) {
|
// public void trace(int s) {
|
||||||
|
@ -146,18 +179,14 @@ public class ParserRuleContext extends RuleContext {
|
||||||
// states.add(s);
|
// states.add(s);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
public TerminalNode addChild(Token matchedToken) {
|
/** Used by enterOuterAlt to toss out a RuleContext previously added as
|
||||||
TerminalNodeImpl t = new TerminalNodeImpl(matchedToken);
|
* we entered a rule. If we have # label, we will need to remove
|
||||||
addChild(t);
|
* generic ruleContext object.
|
||||||
t.parent = this;
|
*/
|
||||||
return t;
|
public void removeLastChild() {
|
||||||
}
|
if ( children!=null ) {
|
||||||
|
children.remove(children.size()-1);
|
||||||
public ErrorNode addErrorNode(Token badToken) {
|
}
|
||||||
ErrorNodeImpl t = new ErrorNodeImpl(badToken);
|
|
||||||
addChild(t);
|
|
||||||
t.parent = this;
|
|
||||||
return t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -290,13 +319,14 @@ public class ParserRuleContext extends RuleContext {
|
||||||
*/
|
*/
|
||||||
public Token getStop() { return stop; }
|
public Token getStop() { return stop; }
|
||||||
|
|
||||||
/** Used for rule context info debugging during parse-time, not so much for ATN debugging */
|
/** Used for rule context info debugging during parse-time, not so much for ATN debugging */
|
||||||
public String toInfoString(Parser recognizer) {
|
public String toInfoString(Parser recognizer) {
|
||||||
List<String> rules = recognizer.getRuleInvocationStack(this);
|
List<String> rules = recognizer.getRuleInvocationStack(this);
|
||||||
Collections.reverse(rules);
|
Collections.reverse(rules);
|
||||||
return "ParserRuleContext"+rules+"{" +
|
return "ParserRuleContext"+rules+"{" +
|
||||||
"start=" + start +
|
"start=" + start +
|
||||||
", stop=" + stop +
|
", stop=" + stop +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue