You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
338 lines
10 KiB
338 lines
10 KiB
/* |
|
* Copyright (c) 2012-2017 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. |
|
*/ |
|
package com.fr.third.org.antlr.v4.runtime; |
|
|
|
import com.fr.third.org.antlr.v4.runtime.misc.Interval; |
|
import com.fr.third.org.antlr.v4.runtime.tree.ErrorNode; |
|
import com.fr.third.org.antlr.v4.runtime.tree.ErrorNodeImpl; |
|
import com.fr.third.org.antlr.v4.runtime.tree.ParseTree; |
|
import com.fr.third.org.antlr.v4.runtime.tree.ParseTreeListener; |
|
import com.fr.third.org.antlr.v4.runtime.tree.TerminalNode; |
|
import com.fr.third.org.antlr.v4.runtime.tree.TerminalNodeImpl; |
|
|
|
import java.util.ArrayList; |
|
import java.util.Collections; |
|
import java.util.List; |
|
|
|
/** A rule invocation record for parsing. |
|
* |
|
* Contains all of the information about the current rule not stored in the |
|
* RuleContext. It handles parse tree children list, Any ATN state |
|
* tracing, and the default values available for rule invocations: |
|
* start, stop, rule index, current alt number. |
|
* |
|
* Subclasses made for each rule and grammar track the parameters, |
|
* return values, locals, and labels specific to that rule. These |
|
* are the objects that are returned from rules. |
|
* |
|
* Note text is not an actual field of a rule return value; it is computed |
|
* from start and stop using the input stream's toString() method. I |
|
* could add a ctor to this so that we can pass in and store the input |
|
* stream, but I'm not sure we want to do that. It would seem to be undefined |
|
* to get the .text property anyway if the rule matches tokens from multiple |
|
* input streams. |
|
* |
|
* I do not use getters for fields of objects that are used simply to |
|
* group values such as this aggregate. The getters/setters are there to |
|
* satisfy the superclass interface. |
|
*/ |
|
public class ParserRuleContext extends RuleContext { |
|
/** If we are debugging or building a parse tree for a visitor, |
|
* we need to track all of the tokens and rule invocations associated |
|
* with this rule's context. This is empty for parsing w/o tree constr. |
|
* operation because we don't the need to track the details about |
|
* how we parse this rule. |
|
*/ |
|
public List<ParseTree> children; |
|
|
|
/** For debugging/tracing purposes, we want to track all of the nodes in |
|
* the ATN traversed by the parser for a particular rule. |
|
* This list indicates the sequence of ATN nodes used to match |
|
* the elements of the children list. This list does not include |
|
* ATN nodes and other rules used to match rule invocations. It |
|
* traces the rule invocation node itself but nothing inside that |
|
* other rule's ATN submachine. |
|
* |
|
* There is NOT a one-to-one correspondence between the children and |
|
* states list. There are typically many nodes in the ATN traversed |
|
* for each element in the children list. For example, for a rule |
|
* invocation there is the invoking state and the following state. |
|
* |
|
* The parser setState() method updates field s and adds it to this list |
|
* if we are debugging/tracing. |
|
* |
|
* This does not trace states visited during prediction. |
|
*/ |
|
// public List<Integer> states; |
|
|
|
public Token start, stop; |
|
|
|
/** |
|
* The exception that forced this rule to return. If the rule successfully |
|
* completed, this is {@code null}. |
|
*/ |
|
public RecognitionException exception; |
|
|
|
public ParserRuleContext() { } |
|
|
|
/** COPY a ctx (I'm deliberately not using copy constructor) to avoid |
|
* confusion with creating node with parent. Does not copy children |
|
* (except error leaves). |
|
* |
|
* 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! |
|
*/ |
|
public void copyFrom(ParserRuleContext ctx) { |
|
this.parent = ctx.parent; |
|
this.invokingState = ctx.invokingState; |
|
|
|
this.start = ctx.start; |
|
this.stop = ctx.stop; |
|
|
|
// copy any error nodes to alt label node |
|
if ( ctx.children!=null ) { |
|
this.children = new ArrayList<>(); |
|
// reset parent pointer for any error nodes |
|
for (ParseTree child : ctx.children) { |
|
if ( child instanceof ErrorNode ) { |
|
addChild((ErrorNode)child); |
|
} |
|
} |
|
} |
|
} |
|
|
|
public ParserRuleContext(ParserRuleContext parent, int invokingStateNumber) { |
|
super(parent, invokingStateNumber); |
|
} |
|
|
|
// Double dispatch methods for listeners |
|
|
|
public void enterRule(ParseTreeListener listener) { } |
|
public void exitRule(ParseTreeListener listener) { } |
|
|
|
/** 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.7 |
|
*/ |
|
public <T extends ParseTree> T addAnyChild(T t) { |
|
if ( children==null ) children = new ArrayList<>(); |
|
children.add(t); |
|
return t; |
|
} |
|
|
|
public RuleContext addChild(RuleContext ruleInvocation) { |
|
return addAnyChild(ruleInvocation); |
|
} |
|
|
|
/** Add a token leaf node child and force its parent to be this node. */ |
|
public TerminalNode addChild(TerminalNode t) { |
|
t.setParent(this); |
|
return addAnyChild(t); |
|
} |
|
|
|
/** Add an error node child and force its parent to be this node. |
|
* |
|
* @since 4.7 |
|
*/ |
|
public ErrorNode addErrorNode(ErrorNode errorNode) { |
|
errorNode.setParent(this); |
|
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.setParent(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.setParent(this); |
|
return t; |
|
} |
|
|
|
// public void trace(int s) { |
|
// if ( states==null ) states = new ArrayList<Integer>(); |
|
// 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. |
|
*/ |
|
public void removeLastChild() { |
|
if ( children!=null ) { |
|
children.remove(children.size()-1); |
|
} |
|
} |
|
|
|
@Override |
|
/** Override to make type more specific */ |
|
public ParserRuleContext getParent() { |
|
return (ParserRuleContext)super.getParent(); |
|
} |
|
|
|
@Override |
|
public ParseTree getChild(int i) { |
|
return children!=null && i>=0 && i<children.size() ? children.get(i) : null; |
|
} |
|
|
|
public <T extends ParseTree> T getChild(Class<? extends T> ctxType, int i) { |
|
if ( children==null || i < 0 || i >= children.size() ) { |
|
return null; |
|
} |
|
|
|
int j = -1; // what element have we found with ctxType? |
|
for (ParseTree o : children) { |
|
if ( ctxType.isInstance(o) ) { |
|
j++; |
|
if ( j == i ) { |
|
return ctxType.cast(o); |
|
} |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
public TerminalNode getToken(int ttype, int i) { |
|
if ( children==null || i < 0 || i >= children.size() ) { |
|
return null; |
|
} |
|
|
|
int j = -1; // what token with ttype have we found? |
|
for (ParseTree o : children) { |
|
if ( o instanceof TerminalNode ) { |
|
TerminalNode tnode = (TerminalNode)o; |
|
Token symbol = tnode.getSymbol(); |
|
if ( symbol.getType()==ttype ) { |
|
j++; |
|
if ( j == i ) { |
|
return tnode; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return null; |
|
} |
|
|
|
public List<TerminalNode> getTokens(int ttype) { |
|
if ( children==null ) { |
|
return Collections.emptyList(); |
|
} |
|
|
|
List<TerminalNode> tokens = null; |
|
for (ParseTree o : children) { |
|
if ( o instanceof TerminalNode ) { |
|
TerminalNode tnode = (TerminalNode)o; |
|
Token symbol = tnode.getSymbol(); |
|
if ( symbol.getType()==ttype ) { |
|
if ( tokens==null ) { |
|
tokens = new ArrayList<TerminalNode>(); |
|
} |
|
tokens.add(tnode); |
|
} |
|
} |
|
} |
|
|
|
if ( tokens==null ) { |
|
return Collections.emptyList(); |
|
} |
|
|
|
return tokens; |
|
} |
|
|
|
public <T extends ParserRuleContext> T getRuleContext(Class<? extends T> ctxType, int i) { |
|
return getChild(ctxType, i); |
|
} |
|
|
|
public <T extends ParserRuleContext> List<T> getRuleContexts(Class<? extends T> ctxType) { |
|
if ( children==null ) { |
|
return Collections.emptyList(); |
|
} |
|
|
|
List<T> contexts = null; |
|
for (ParseTree o : children) { |
|
if ( ctxType.isInstance(o) ) { |
|
if ( contexts==null ) { |
|
contexts = new ArrayList<T>(); |
|
} |
|
|
|
contexts.add(ctxType.cast(o)); |
|
} |
|
} |
|
|
|
if ( contexts==null ) { |
|
return Collections.emptyList(); |
|
} |
|
|
|
return contexts; |
|
} |
|
|
|
@Override |
|
public int getChildCount() { return children!=null ? children.size() : 0; } |
|
|
|
@Override |
|
public Interval getSourceInterval() { |
|
if ( start == null ) { |
|
return Interval.INVALID; |
|
} |
|
if ( stop==null || stop.getTokenIndex()<start.getTokenIndex() ) { |
|
return Interval.of(start.getTokenIndex(), start.getTokenIndex()-1); // empty |
|
} |
|
return Interval.of(start.getTokenIndex(), stop.getTokenIndex()); |
|
} |
|
|
|
/** |
|
* Get the initial token in this context. |
|
* Note that the range from start to stop is inclusive, so for rules that do not consume anything |
|
* (for example, zero length or error productions) this token may exceed stop. |
|
*/ |
|
public Token getStart() { return start; } |
|
/** |
|
* Get the final token in this context. |
|
* Note that the range from start to stop is inclusive, so for rules that do not consume anything |
|
* (for example, zero length or error productions) this token may precede start. |
|
*/ |
|
public Token getStop() { return stop; } |
|
|
|
/** Used for rule context info debugging during parse-time, not so much for ATN debugging */ |
|
public String toInfoString(Parser recognizer) { |
|
List<String> rules = recognizer.getRuleInvocationStack(this); |
|
Collections.reverse(rules); |
|
return "ParserRuleContext"+rules+"{" + |
|
"start=" + start + |
|
", stop=" + stop + |
|
'}'; |
|
} |
|
} |
|
|
|
|