Move primary implementation of getExpectedTokens to ATN, fixes #191
This commit is contained in:
parent
4f29c2fe3d
commit
bc17cd4a28
|
@ -550,31 +550,15 @@ public abstract class Parser extends Recognizer<Token, ParserATNSimulator> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Compute the set of valid tokens reachable from the current
|
/**
|
||||||
* position in the parse.
|
* Computes the set of input symbols which could follow the current parser
|
||||||
|
* state and context, as given by {@link #getState} and {@link #getContext},
|
||||||
|
* respectively.
|
||||||
|
*
|
||||||
|
* @see ATN#getExpectedTokens(int, RuleContext)
|
||||||
*/
|
*/
|
||||||
public IntervalSet getExpectedTokens() {
|
public IntervalSet getExpectedTokens() {
|
||||||
ATN atn = getInterpreter().atn;
|
return getATN().getExpectedTokens(getState(), getContext());
|
||||||
ParserRuleContext ctx = _ctx;
|
|
||||||
ATNState s = atn.states.get(getState());
|
|
||||||
IntervalSet following = atn.nextTokens(s);
|
|
||||||
// System.out.println("following "+s+"="+following);
|
|
||||||
if ( !following.contains(Token.EPSILON) ) return following;
|
|
||||||
IntervalSet expected = new IntervalSet();
|
|
||||||
expected.addAll(following);
|
|
||||||
expected.remove(Token.EPSILON);
|
|
||||||
while ( ctx!=null && ctx.invokingState>=0 && following.contains(Token.EPSILON) ) {
|
|
||||||
ATNState invokingState = atn.states.get(ctx.invokingState);
|
|
||||||
RuleTransition rt = (RuleTransition)invokingState.transition(0);
|
|
||||||
following = atn.nextTokens(rt.followState);
|
|
||||||
expected.addAll(following);
|
|
||||||
expected.remove(Token.EPSILON);
|
|
||||||
ctx = (ParserRuleContext)ctx.parent;
|
|
||||||
}
|
|
||||||
if ( following.contains(Token.EPSILON) ) {
|
|
||||||
expected.add(Token.EOF);
|
|
||||||
}
|
|
||||||
return expected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntervalSet getExpectedTokensWithinCurrentRule() {
|
public IntervalSet getExpectedTokensWithinCurrentRule() {
|
||||||
|
|
|
@ -92,10 +92,10 @@ public class RecognitionException extends RuntimeException {
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntervalSet getExpectedTokens() {
|
public IntervalSet getExpectedTokens() {
|
||||||
// TODO: do we really need this type check?
|
if (recognizer != null) {
|
||||||
if ( recognizer!=null && recognizer instanceof Parser) {
|
return recognizer.getATN().getExpectedTokens(offendingState, ctx);
|
||||||
return ((Parser) recognizer).getExpectedTokens();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,4 +155,55 @@ public class ATN {
|
||||||
public int getNumberOfDecisions() {
|
public int getNumberOfDecisions() {
|
||||||
return decisionToState.size();
|
return decisionToState.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the set of input symbols which could follow ATN state number
|
||||||
|
* {@code stateNumber} in the specified full {@code context}. This method
|
||||||
|
* considers the complete parser context, but does not evaluate semantic
|
||||||
|
* predicates (i.e. all predicates encountered during the calculation are
|
||||||
|
* assumed true). If a path in the ATN exists from the starting state to the
|
||||||
|
* {@link RuleStopState} of the outermost context without matching any
|
||||||
|
* symbols, {@link Token#EOF} is added to the returned set.
|
||||||
|
* <p/>
|
||||||
|
* If {@code context} is {@code null}, it is treated as
|
||||||
|
* {@link ParserRuleContext#EMPTY}.
|
||||||
|
*
|
||||||
|
* @param stateNumber the ATN state number
|
||||||
|
* @param context the full parse context
|
||||||
|
* @return The set of potentially valid input symbols which could follow the
|
||||||
|
* specified state in the specified context.
|
||||||
|
* @throws IllegalArgumentException if the ATN does not contain a state with
|
||||||
|
* number {@code stateNumber}
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public IntervalSet getExpectedTokens(int stateNumber, @Nullable RuleContext context) {
|
||||||
|
if (stateNumber < 0 || stateNumber >= states.size()) {
|
||||||
|
throw new IllegalArgumentException("Invalid state number.");
|
||||||
|
}
|
||||||
|
|
||||||
|
RuleContext ctx = context;
|
||||||
|
ATNState s = states.get(stateNumber);
|
||||||
|
IntervalSet following = nextTokens(s);
|
||||||
|
if (!following.contains(Token.EPSILON)) {
|
||||||
|
return following;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntervalSet expected = new IntervalSet();
|
||||||
|
expected.addAll(following);
|
||||||
|
expected.remove(Token.EPSILON);
|
||||||
|
while (ctx != null && ctx.invokingState >= 0 && following.contains(Token.EPSILON)) {
|
||||||
|
ATNState invokingState = states.get(ctx.invokingState);
|
||||||
|
RuleTransition rt = (RuleTransition)invokingState.transition(0);
|
||||||
|
following = nextTokens(rt.followState);
|
||||||
|
expected.addAll(following);
|
||||||
|
expected.remove(Token.EPSILON);
|
||||||
|
ctx = ctx.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (following.contains(Token.EPSILON)) {
|
||||||
|
expected.add(Token.EOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
return expected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue