replace ctor for single ctx and don't merge wildcards when payloads aren't the same. fixes a unit test.

This commit is contained in:
Terence Parr 2012-10-08 15:26:56 -07:00
parent 55ad7bdb2c
commit ebe633a2cc
7 changed files with 26 additions and 21 deletions

View File

@ -84,7 +84,7 @@ public class ArrayPredictionContext extends PredictionContext {
@Override @Override
public SingletonPredictionContext next() { public SingletonPredictionContext next() {
SingletonPredictionContext ctx = SingletonPredictionContext ctx =
new SingletonPredictionContext(parents[i], invokingStates[i]); SingletonPredictionContext.create(parents[i], invokingStates[i]);
i++; i++;
return ctx; return ctx;
} }
@ -144,8 +144,8 @@ public class ArrayPredictionContext extends PredictionContext {
next = PredictionContext.EMPTY; next = PredictionContext.EMPTY;
} }
else { else {
next = new SingletonPredictionContext(this.parents[i], next = SingletonPredictionContext.create(this.parents[i],
this.invokingStates[i]); this.invokingStates[i]);
} }
boolean rootIsWildcard = fullCtx; boolean rootIsWildcard = fullCtx;
newCtx = merge(newCtx, next, rootIsWildcard, mergeCache); newCtx = merge(newCtx, next, rootIsWildcard, mergeCache);

View File

@ -124,7 +124,7 @@ public class LL1Analyzer {
Transition t = s.transition(i); Transition t = s.transition(i);
if ( t.getClass() == RuleTransition.class ) { if ( t.getClass() == RuleTransition.class ) {
PredictionContext newContext = PredictionContext newContext =
new SingletonPredictionContext(ctx, s.stateNumber); SingletonPredictionContext.create(ctx, s.stateNumber);
_LOOK(t.target, newContext, look, lookBusy, seeThruPreds); _LOOK(t.target, newContext, look, lookBusy, seeThruPreds);
} }
else if ( t instanceof PredicateTransition ) { else if ( t instanceof PredicateTransition ) {

View File

@ -667,7 +667,7 @@ public class LexerATNSimulator extends ATNSimulator {
switch (t.getSerializationType()) { switch (t.getSerializationType()) {
case Transition.RULE: case Transition.RULE:
PredictionContext newContext = PredictionContext newContext =
new SingletonPredictionContext(config.context, p.stateNumber); SingletonPredictionContext.create(config.context, p.stateNumber);
c = new LexerATNConfig(config, t.target, newContext); c = new LexerATNConfig(config, t.target, newContext);
break; break;
case Transition.PREDICATE: case Transition.PREDICATE:

View File

@ -1115,7 +1115,7 @@ public class ParserATNSimulator extends ATNSimulator {
config.state.getClass()==PlusLoopbackState.class ) config.state.getClass()==PlusLoopbackState.class )
{ {
config.context = config.context =
new SingletonPredictionContext(config.context, config.state.stateNumber); SingletonPredictionContext.create(config.context, config.state.stateNumber);
// alter config; it's ok, since all calls to closure pass in a fresh config for us to chase // alter config; it's ok, since all calls to closure pass in a fresh config for us to chase
if ( debug ) System.out.println("Loop back; push "+config.state.stateNumber+", stack="+config.context); if ( debug ) System.out.println("Loop back; push "+config.state.stateNumber+", stack="+config.context);
} }
@ -1286,7 +1286,7 @@ public class ParserATNSimulator extends ATNSimulator {
", ctx="+config.context); ", ctx="+config.context);
} }
PredictionContext newContext = PredictionContext newContext =
new SingletonPredictionContext(config.context, config.state.stateNumber); SingletonPredictionContext.create(config.context, config.state.stateNumber);
return new ATNConfig(config, t.target, newContext); return new ATNConfig(config, t.target, newContext);
} }

View File

@ -53,7 +53,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
parent = PredictionContext.fromRuleContext(outerContext.parent); parent = PredictionContext.fromRuleContext(outerContext.parent);
} }
return new SingletonPredictionContext(parent, outerContext.invokingState); return SingletonPredictionContext.create(parent, outerContext.invokingState);
} }
@Override @Override
@ -123,7 +123,8 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
boolean rootIsWildcard, boolean rootIsWildcard,
DoubleKeyMap<PredictionContext,PredictionContext,PredictionContext> mergeCache) DoubleKeyMap<PredictionContext,PredictionContext,PredictionContext> mergeCache)
{ {
if ( (a==null&&b==null) || a==b || a.equals(b) ) return a; // share same graph if both same // share same graph if both same
if ( (a==null&&b==null) || a==b || (a!=null&&a.equals(b)) ) return a;
if ( a instanceof SingletonPredictionContext && b instanceof SingletonPredictionContext) { if ( a instanceof SingletonPredictionContext && b instanceof SingletonPredictionContext) {
return mergeSingletons((SingletonPredictionContext)a, return mergeSingletons((SingletonPredictionContext)a,
@ -178,17 +179,13 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
// merge parents x and y, giving array node with x,y then remainders // merge parents x and y, giving array node with x,y then remainders
// of those graphs. dup a, a' points at merged array // of those graphs. dup a, a' points at merged array
// new joined parent so create new singleton pointing to it, a' // new joined parent so create new singleton pointing to it, a'
PredictionContext a_ = new SingletonPredictionContext(parent, a.invokingState); PredictionContext a_ = SingletonPredictionContext.create(parent, a.invokingState);
if ( mergeCache!=null ) mergeCache.put(a, b, a_); if ( mergeCache!=null ) mergeCache.put(a, b, a_);
return a_; return a_;
} }
else { // a != b payloads differ else { // a != b payloads differ
// see if we can collapse parents due to $+x parents if local ctx // see if we can collapse parents due to $+x parents if local ctx
PredictionContext singleParent = null; PredictionContext singleParent = null;
if ( rootIsWildcard ) {
if ( a.parent == EMPTY ) singleParent = EMPTY; // $ + b = $
if ( b.parent == EMPTY ) singleParent = EMPTY; // a + $ = $
}
if ( a==b || (a.parent!=null && a.parent.equals(b.parent)) ) { // ax + bx = [a,b]x if ( a==b || (a.parent!=null && a.parent.equals(b.parent)) ) { // ax + bx = [a,b]x
singleParent = a.parent; singleParent = a.parent;
} }
@ -338,8 +335,9 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
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
PredictionContext a_ = new SingletonPredictionContext(mergedParents[0], PredictionContext a_ =
mergedInvokingStates[0]); SingletonPredictionContext.create(mergedParents[0],
mergedInvokingStates[0]);
if ( mergeCache!=null ) mergeCache.put(a,b,a_); if ( mergeCache!=null ) mergeCache.put(a,b,a_);
return a_; return a_;
} }
@ -490,7 +488,7 @@ public abstract class PredictionContext implements Iterable<SingletonPredictionC
updated = EMPTY; updated = EMPTY;
} }
else if (parents.length == 1) { else if (parents.length == 1) {
updated = new SingletonPredictionContext(parents[0], context.getInvokingState(0)); updated = SingletonPredictionContext.create(parents[0], context.getInvokingState(0));
} }
else { else {
ArrayPredictionContext arrayPredictionContext = (ArrayPredictionContext)context; ArrayPredictionContext arrayPredictionContext = (ArrayPredictionContext)context;

View File

@ -8,7 +8,7 @@ public class SingletonPredictionContext extends PredictionContext {
public final PredictionContext parent; public final PredictionContext parent;
public final int invokingState; public final int invokingState;
public 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!=EMPTY_FULL_CTX_INVOKING_STATE &&
@ -17,6 +17,14 @@ public class SingletonPredictionContext extends PredictionContext {
this.invokingState = invokingState; this.invokingState = invokingState;
} }
public static SingletonPredictionContext create(PredictionContext parent, int invokingState) {
if ( invokingState == EMPTY_FULL_CTX_INVOKING_STATE && parent == null ) {
// someone can pass in the bits of an array ctx that mean $
return EMPTY;
}
return new SingletonPredictionContext(parent, invokingState);
}
@Override @Override
public Iterator<SingletonPredictionContext> iterator() { public Iterator<SingletonPredictionContext> iterator() {
final SingletonPredictionContext self = this; final SingletonPredictionContext self = this;

View File

@ -2,7 +2,6 @@ package org.antlr.v4.test;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.antlr.v4.runtime.atn.ArrayPredictionContext; import org.antlr.v4.runtime.atn.ArrayPredictionContext;
import org.antlr.v4.runtime.atn.EmptyPredictionContext;
import org.antlr.v4.runtime.atn.PredictionContext; import org.antlr.v4.runtime.atn.PredictionContext;
import org.antlr.v4.runtime.atn.PredictionContextCache; import org.antlr.v4.runtime.atn.PredictionContextCache;
import org.antlr.v4.runtime.atn.SingletonPredictionContext; import org.antlr.v4.runtime.atn.SingletonPredictionContext;
@ -763,7 +762,7 @@ public class TestGraphNodes extends TestCase {
} }
public SingletonPredictionContext createSingleton(PredictionContext parent, int payload) { public SingletonPredictionContext createSingleton(PredictionContext parent, int payload) {
SingletonPredictionContext a = new SingletonPredictionContext(parent, payload); SingletonPredictionContext a = SingletonPredictionContext.create(parent, payload);
return a; return a;
} }
@ -820,7 +819,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) == EmptyPredictionContext.EMPTY_INVOKING_STATE) { if (current.getInvokingState(i) == PredictionContext.EMPTY_FULL_CTX_INVOKING_STATE) {
continue; continue;
} }