forked from jasder/antlr
Merge remote-tracking branch 'antlr/master' into non-greedy
This commit is contained in:
commit
a40073a8cc
|
@ -18,8 +18,7 @@ public class ArrayPredictionContext extends PredictionContext {
|
||||||
public final int[] invokingStates;
|
public final int[] invokingStates;
|
||||||
|
|
||||||
public ArrayPredictionContext(SingletonPredictionContext a) {
|
public ArrayPredictionContext(SingletonPredictionContext a) {
|
||||||
this(new PredictionContext[] {a.parent},
|
this(new PredictionContext[] {a.parent}, new int[] {a.invokingState});
|
||||||
new int[] {a==PredictionContext.EMPTY ? EMPTY_FULL_CTX_INVOKING_STATE : a.invokingState});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayPredictionContext(PredictionContext[] parents, int[] invokingStates) {
|
public ArrayPredictionContext(PredictionContext[] parents, int[] invokingStates) {
|
||||||
|
@ -97,7 +96,7 @@ public class ArrayPredictionContext extends PredictionContext {
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return size()==1 &&
|
return size()==1 &&
|
||||||
invokingStates[0]==EmptyPredictionContext.EMPTY_INVOKING_STATE;
|
invokingStates[0]==EMPTY_INVOKING_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -140,7 +139,7 @@ public class ArrayPredictionContext extends PredictionContext {
|
||||||
for (int i = 0; i < this.invokingStates.length; i++) {
|
for (int i = 0; i < this.invokingStates.length; i++) {
|
||||||
if (i == index) continue;
|
if (i == index) continue;
|
||||||
PredictionContext next;
|
PredictionContext next;
|
||||||
if ( this.invokingStates[i] == EMPTY_FULL_CTX_INVOKING_STATE ) {
|
if ( this.invokingStates[i] == EMPTY_INVOKING_STATE ) {
|
||||||
next = PredictionContext.EMPTY;
|
next = PredictionContext.EMPTY;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -179,7 +178,7 @@ public class ArrayPredictionContext extends PredictionContext {
|
||||||
buf.append("[");
|
buf.append("[");
|
||||||
for (int i=0; i<invokingStates.length; i++) {
|
for (int i=0; i<invokingStates.length; i++) {
|
||||||
if ( i>0 ) buf.append(", ");
|
if ( i>0 ) buf.append(", ");
|
||||||
if ( invokingStates[i]==EMPTY_FULL_CTX_INVOKING_STATE ) {
|
if ( invokingStates[i]==EMPTY_INVOKING_STATE ) {
|
||||||
buf.append("$");
|
buf.append("$");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.antlr.v4.runtime.atn;
|
package org.antlr.v4.runtime.atn;
|
||||||
|
|
||||||
public class EmptyPredictionContext extends SingletonPredictionContext {
|
public class EmptyPredictionContext extends SingletonPredictionContext {
|
||||||
public static final int EMPTY_INVOKING_STATE = ATNState.INVALID_STATE_NUMBER - 1;
|
|
||||||
public EmptyPredictionContext() {
|
public EmptyPredictionContext() {
|
||||||
super(null, EMPTY_INVOKING_STATE);
|
super(null, EMPTY_INVOKING_STATE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -576,7 +576,7 @@ public class LexerATNSimulator extends ATNSimulator {
|
||||||
for (SingletonPredictionContext ctx : config.context) {
|
for (SingletonPredictionContext ctx : config.context) {
|
||||||
if ( !ctx.isEmpty() ) {
|
if ( !ctx.isEmpty() ) {
|
||||||
PredictionContext newContext = ctx.parent; // "pop" invoking state
|
PredictionContext newContext = ctx.parent; // "pop" invoking state
|
||||||
if ( ctx.invokingState==PredictionContext.EMPTY_FULL_CTX_INVOKING_STATE ) {
|
if ( ctx.invokingState==PredictionContext.EMPTY_INVOKING_STATE ) {
|
||||||
// we have no context info. Don't pursue but
|
// we have no context info. Don't pursue but
|
||||||
// record a config that indicates how we hit end
|
// record a config that indicates how we hit end
|
||||||
LexerATNConfig c = new LexerATNConfig(config, config.state, ctx);
|
LexerATNConfig c = new LexerATNConfig(config, config.state, ctx);
|
||||||
|
|
|
@ -1104,7 +1104,7 @@ public class ParserATNSimulator extends ATNSimulator {
|
||||||
// run thru all possible stack tops in ctx
|
// run thru all possible stack tops in ctx
|
||||||
if ( config.context!=null && !config.context.isEmpty() ) {
|
if ( config.context!=null && !config.context.isEmpty() ) {
|
||||||
for (SingletonPredictionContext ctx : config.context) {
|
for (SingletonPredictionContext ctx : config.context) {
|
||||||
if ( ctx.invokingState==PredictionContext.EMPTY_FULL_CTX_INVOKING_STATE ) {
|
if ( ctx.invokingState==PredictionContext.EMPTY_INVOKING_STATE ) {
|
||||||
// we have no context info, just chase follow links (if greedy)
|
// we have no context info, just chase follow links (if greedy)
|
||||||
if ( debug ) System.out.println("FALLING off rule "+
|
if ( debug ) System.out.println("FALLING off rule "+
|
||||||
getRuleName(config.state.ruleIndex));
|
getRuleName(config.state.ruleIndex));
|
||||||
|
|
|
@ -22,9 +22,9 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
public static final EmptyPredictionContext EMPTY = new EmptyPredictionContext();
|
public static final EmptyPredictionContext EMPTY = new EmptyPredictionContext();
|
||||||
|
|
||||||
/** Represents $ in an array in full ctx mode, when $ doesn't mean wildcard:
|
/** Represents $ in an array in full ctx mode, when $ doesn't mean wildcard:
|
||||||
* $ + x = [$,x]. Here, $ = EMPTY_FULL_CTX_INVOKING_STATE.
|
* $ + x = [$,x]. Here, $ = EMPTY_INVOKING_STATE.
|
||||||
*/
|
*/
|
||||||
public static final int EMPTY_FULL_CTX_INVOKING_STATE = Integer.MAX_VALUE;
|
public static final int EMPTY_INVOKING_STATE = Integer.MAX_VALUE;
|
||||||
|
|
||||||
public static int globalNodeCount = 0;
|
public static int globalNodeCount = 0;
|
||||||
public final int id = globalNodeCount++;
|
public final int id = globalNodeCount++;
|
||||||
|
@ -231,14 +231,14 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
else {
|
else {
|
||||||
if ( a == EMPTY && b == EMPTY ) return EMPTY; // $ + $ = $
|
if ( a == EMPTY && b == EMPTY ) return EMPTY; // $ + $ = $
|
||||||
if ( a == EMPTY ) { // $ + x = [$,x]
|
if ( a == EMPTY ) { // $ + x = [$,x]
|
||||||
int[] payloads = {b.invokingState, EMPTY_FULL_CTX_INVOKING_STATE};
|
int[] payloads = {b.invokingState, EMPTY_INVOKING_STATE};
|
||||||
PredictionContext[] parents = {b.parent, null};
|
PredictionContext[] parents = {b.parent, null};
|
||||||
PredictionContext joined =
|
PredictionContext joined =
|
||||||
new ArrayPredictionContext(parents, payloads);
|
new ArrayPredictionContext(parents, payloads);
|
||||||
return joined;
|
return joined;
|
||||||
}
|
}
|
||||||
if ( b == EMPTY ) { // x + $ = [$,x] ($ is always first if present)
|
if ( b == EMPTY ) { // x + $ = [$,x] ($ is always first if present)
|
||||||
int[] payloads = {a.invokingState, EMPTY_FULL_CTX_INVOKING_STATE};
|
int[] payloads = {a.invokingState, EMPTY_INVOKING_STATE};
|
||||||
PredictionContext[] parents = {a.parent, null};
|
PredictionContext[] parents = {a.parent, null};
|
||||||
PredictionContext joined =
|
PredictionContext joined =
|
||||||
new ArrayPredictionContext(parents, payloads);
|
new ArrayPredictionContext(parents, payloads);
|
||||||
|
@ -279,7 +279,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
// same payload (stack tops are equal), must yield merged singleton
|
// same payload (stack tops are equal), must yield merged singleton
|
||||||
int payload = a.invokingStates[i];
|
int payload = a.invokingStates[i];
|
||||||
// $+$ = $
|
// $+$ = $
|
||||||
boolean both$ = payload == EMPTY_FULL_CTX_INVOKING_STATE &&
|
boolean both$ = payload == EMPTY_INVOKING_STATE &&
|
||||||
a_parent == null && b_parent == null;
|
a_parent == null && b_parent == null;
|
||||||
boolean ax_ax = (a_parent!=null && b_parent!=null) &&
|
boolean ax_ax = (a_parent!=null && b_parent!=null) &&
|
||||||
a_parent.equals(b_parent); // ax+ax -> ax
|
a_parent.equals(b_parent); // ax+ax -> ax
|
||||||
|
@ -331,7 +331,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
int p = lastSlot; // walk backwards from last index until we find non-null parent
|
int p = lastSlot; // walk backwards from last index until we find non-null parent
|
||||||
while ( p>=0 && mergedParents[p]==null ) { p--; }
|
while ( p>=0 && mergedParents[p]==null ) { p--; }
|
||||||
// p is now last non-null index
|
// p is now last non-null index
|
||||||
assert p>0; // could only happen to be <0 if two arrays with $
|
assert p>=0; // could only happen to be <0 if two arrays with $
|
||||||
if ( p < lastSlot ) {
|
if ( p < lastSlot ) {
|
||||||
int n = p+1; // how many slots we really used in merge
|
int n = p+1; // how many slots we really used in merge
|
||||||
if ( n == 1 ) { // for just one merged element, return singleton top
|
if ( n == 1 ) { // for just one merged element, return singleton top
|
||||||
|
@ -408,7 +408,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (int inv : arr.invokingStates) {
|
for (int inv : arr.invokingStates) {
|
||||||
if ( !first ) buf.append(", ");
|
if ( !first ) buf.append(", ");
|
||||||
if ( inv == EMPTY_FULL_CTX_INVOKING_STATE ) buf.append("$");
|
if ( inv == EMPTY_INVOKING_STATE ) buf.append("$");
|
||||||
else buf.append(inv);
|
else buf.append(inv);
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
@ -610,7 +610,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
|
||||||
String ruleName = recognizer.getRuleNames()[s.ruleIndex];
|
String ruleName = recognizer.getRuleNames()[s.ruleIndex];
|
||||||
localBuffer.append(ruleName);
|
localBuffer.append(ruleName);
|
||||||
}
|
}
|
||||||
else if ( p.getInvokingState(index)!= EMPTY_FULL_CTX_INVOKING_STATE) {
|
else if ( p.getInvokingState(index)!= EMPTY_INVOKING_STATE) {
|
||||||
if ( !p.isEmpty() ) {
|
if ( !p.isEmpty() ) {
|
||||||
if (localBuffer.length() > 1) {
|
if (localBuffer.length() > 1) {
|
||||||
// first char is '[', if more than that this isn't the first rule
|
// first char is '[', if more than that this isn't the first rule
|
||||||
|
|
|
@ -11,14 +11,13 @@ public class SingletonPredictionContext extends PredictionContext {
|
||||||
SingletonPredictionContext(PredictionContext parent, int invokingState) {
|
SingletonPredictionContext(PredictionContext parent, int invokingState) {
|
||||||
super(calculateHashCode(parent!=null ? 31 ^ parent.hashCode() : 1,
|
super(calculateHashCode(parent!=null ? 31 ^ parent.hashCode() : 1,
|
||||||
31 ^ invokingState));
|
31 ^ invokingState));
|
||||||
assert invokingState!=EMPTY_FULL_CTX_INVOKING_STATE &&
|
assert invokingState!=ATNState.INVALID_STATE_NUMBER;
|
||||||
invokingState!=ATNState.INVALID_STATE_NUMBER;
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.invokingState = invokingState;
|
this.invokingState = invokingState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SingletonPredictionContext create(PredictionContext parent, int invokingState) {
|
public static SingletonPredictionContext create(PredictionContext parent, int invokingState) {
|
||||||
if ( invokingState == EMPTY_FULL_CTX_INVOKING_STATE && parent == null ) {
|
if ( invokingState == EMPTY_INVOKING_STATE && parent == null ) {
|
||||||
// someone can pass in the bits of an array ctx that mean $
|
// someone can pass in the bits of an array ctx that mean $
|
||||||
return EMPTY;
|
return EMPTY;
|
||||||
}
|
}
|
||||||
|
@ -92,7 +91,7 @@ public class SingletonPredictionContext extends PredictionContext {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String up = parent!=null ? parent.toString() : "";
|
String up = parent!=null ? parent.toString() : "";
|
||||||
if ( up.length()==0 ) {
|
if ( up.length()==0 ) {
|
||||||
if ( invokingState == EMPTY_FULL_CTX_INVOKING_STATE ) {
|
if ( invokingState == EMPTY_INVOKING_STATE ) {
|
||||||
return "$";
|
return "$";
|
||||||
}
|
}
|
||||||
return String.valueOf(invokingState);
|
return String.valueOf(invokingState);
|
||||||
|
|
|
@ -805,7 +805,7 @@ public class TestGraphNodes extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes.append("<p").append(i).append('>');
|
nodes.append("<p").append(i).append('>');
|
||||||
if (current.getInvokingState(i) == PredictionContext.EMPTY_FULL_CTX_INVOKING_STATE) {
|
if (current.getInvokingState(i) == PredictionContext.EMPTY_INVOKING_STATE) {
|
||||||
nodes.append(rootIsWildcard ? '*' : '$');
|
nodes.append(rootIsWildcard ? '*' : '$');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -820,7 +820,7 @@ public class TestGraphNodes extends TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < current.size(); i++) {
|
for (int i = 0; i < current.size(); i++) {
|
||||||
if (current.getInvokingState(i) == PredictionContext.EMPTY_FULL_CTX_INVOKING_STATE) {
|
if (current.getInvokingState(i) == PredictionContext.EMPTY_INVOKING_STATE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -292,7 +292,7 @@ public class TestParseErrors extends BaseTest {
|
||||||
"WS : [ \\t\\r\\n]+ -> skip;\n";
|
"WS : [ \\t\\r\\n]+ -> skip;\n";
|
||||||
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a.", false);
|
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", "a.", false);
|
||||||
String expecting =
|
String expecting =
|
||||||
"exec stderrVacuum: line 1:1 mismatched input '.' expecting '!'";
|
"line 1:1 mismatched input '.' expecting '!'\n";
|
||||||
String result = stderrDuringParse;
|
String result = stderrDuringParse;
|
||||||
assertEquals(expecting, result);
|
assertEquals(expecting, result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,8 +164,8 @@ public class TestParserExec extends BaseTest {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Related to https://github.com/antlr/antlr4/issues/41. EOF is
|
* This test is meant to detect regressions of bug antlr/antlr4#41.
|
||||||
* not viable after "if x" since EOF not viable after stat.
|
* https://github.com/antlr/antlr4/issues/41
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testOptional() throws Exception {
|
public void testOptional() throws Exception {
|
||||||
|
@ -186,11 +186,11 @@ public class TestParserExec extends BaseTest {
|
||||||
|
|
||||||
found = execParser("T.g4", grammar, "TParser", "TLexer", "stat", "if x", false);
|
found = execParser("T.g4", grammar, "TParser", "TLexer", "stat", "if x", false);
|
||||||
assertEquals("", found);
|
assertEquals("", found);
|
||||||
assertEquals("line 1:4 no viable alternative at input '<EOF>'\n", this.stderrDuringParse);
|
assertNull(this.stderrDuringParse);
|
||||||
|
|
||||||
found = execParser("T.g4", grammar, "TParser", "TLexer", "stat", "if if x else x", false);
|
found = execParser("T.g4", grammar, "TParser", "TLexer", "stat", "if if x else x", false);
|
||||||
assertEquals("", found);
|
assertEquals("", found);
|
||||||
assertEquals("line 1:14 no viable alternative at input '<EOF>'\n", this.stderrDuringParse);
|
assertNull(this.stderrDuringParse);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue