diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/ArrayPredictionContext.java b/runtime/Java/src/org/antlr/v4/runtime/atn/ArrayPredictionContext.java index b9dbea66f..7a0f779db 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/ArrayPredictionContext.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/ArrayPredictionContext.java @@ -71,18 +71,33 @@ public class ArrayPredictionContext extends PredictionContext { return Arrays.binarySearch(invokingStates, invokingState); } - public ArrayPredictionContext trim() { - int i = parents.length-1; - while ( i>=0 && parents[i]==null ) { i--; } - // i is last non-null index - if ( i < parents.length-1 ) { - int n = i+1; - return new ArrayPredictionContext( - Arrays.copyOf(parents, n), - Arrays.copyOf(invokingStates, n) - ); + /** Find invokingState parameter (call it x) in this.invokingStates, + * if present. Call pop on all x's parent(s) and then pull other + * elements from this context and merge into new context. + */ + @Override + public PredictionContext popAll(int invokingState, boolean fullCtx) { + int index = Arrays.binarySearch(this.invokingStates, invokingState); + if ( index < 0 ) { + return this; } - return this; + + PredictionContext newCtx = this.parents[index].popAll(invokingState, fullCtx); + for (int i = 0; i < this.invokingStates.length; i++) { + if (i == index) continue; + PredictionContext next; + if ( this.invokingStates[i] == EMPTY_FULL_CTX_INVOKING_STATE ) { + next = PredictionContext.EMPTY; + } + else { + next = new SingletonPredictionContext(this.parents[i], + this.invokingStates[i]); + } + boolean rootIsWildcard = fullCtx; + newCtx = merge(newCtx, next, rootIsWildcard); + } + + return newCtx; } @Override diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/ParserATNSimulator.java b/runtime/Java/src/org/antlr/v4/runtime/atn/ParserATNSimulator.java index a95c82b9a..d00cc8a63 100755 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/ParserATNSimulator.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/ParserATNSimulator.java @@ -956,19 +956,21 @@ public class ParserATNSimulator extends ATNSimulator { // run thru all possible stack tops in ctx if ( config.context!=null && !config.context.isEmpty() ) { for (SingletonPredictionContext ctx : config.context) { - if ( !ctx.isEmpty() ) { +// if ( !ctx.isEmpty() ) { ATNState invokingState = atn.states.get(ctx.invokingState); RuleTransition rt = (RuleTransition)invokingState.transition(0); ATNState retState = rt.followState; PredictionContext newContext = ctx.parent; // "pop" invoking state - ATNConfig c = new ATNConfig(retState, config.alt, newContext, config.semanticContext); + ATNConfig c = new ATNConfig(retState, config.alt, newContext, + config.semanticContext); // While we have context to pop back from, we may have // gotten that context AFTER having falling off a rule. // Make sure we track that we are now out of context. c.reachesIntoOuterContext = config.reachesIntoOuterContext; assert depth > Integer.MIN_VALUE; - closure(c, configs, closureBusy, collectPredicates, greedy, loopsSimulateTailRecursion, depth - 1); - } + closure(c, configs, closureBusy, collectPredicates, greedy, + loopsSimulateTailRecursion, depth - 1); +// } return; } } @@ -989,16 +991,9 @@ public class ParserATNSimulator extends ATNSimulator { } else if ( config.state.getClass()==LoopEndState.class ) { if ( debug ) System.out.println("Loop end; pop, stack="+config.context); - // run thru all possible stack tops in ctx - for (SingletonPredictionContext ctx : config.context) { - SingletonPredictionContext p = ctx; - LoopEndState end = (LoopEndState) config.state; - // pop all the way back until we don't see the loopback state anymore - while ( !p.isEmpty() && p.invokingState == end.loopBackStateNumber ) { - // TODO: BROKEN. can't figure out how to leave config.context -// p = config.context = config.context.parent; // "pop" - } - } + LoopEndState end = (LoopEndState)config.state; + // pop all the way back until we don't see the loopback state anymore + config.context = config.context.popAll(end.loopBackStateNumber, configs.fullCtx); } } diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/PredictionContext.java b/runtime/Java/src/org/antlr/v4/runtime/atn/PredictionContext.java index 4518c3674..d3cf5fd67 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/PredictionContext.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/PredictionContext.java @@ -15,7 +15,7 @@ import java.util.Map; public abstract class PredictionContext implements Iterable { public static final EmptyPredictionContext EMPTY = new EmptyPredictionContext(); - public static final int EMPTY_FULL_INVOKING_STATE = Integer.MAX_VALUE; + public static final int EMPTY_FULL_CTX_INVOKING_STATE = Integer.MAX_VALUE; public static int globalNodeCount = 0; public final int id = globalNodeCount++; @@ -61,9 +61,14 @@ public abstract class PredictionContext implements Iterable 1) { // first char is '[', if more than that this isn't the first rule @@ -277,14 +282,14 @@ public abstract class PredictionContext implements Iterable=0 && mergedParents[p]==null ) { p--; } + // p is now last non-null index + if ( p < mergedParents.length-1 ) { + int n = p+1; + mergedParents = Arrays.copyOf(mergedParents, n); + mergedInvokingStates = Arrays.copyOf(mergedInvokingStates, n); + } } + ArrayPredictionContext M = + new ArrayPredictionContext(mergedParents, mergedInvokingStates); + // TODO: if we created same array as a or b, return that instead // TODO: make pass over all M parents; merge any equal() ones diff --git a/runtime/Java/src/org/antlr/v4/runtime/atn/SingletonPredictionContext.java b/runtime/Java/src/org/antlr/v4/runtime/atn/SingletonPredictionContext.java index 92afe67a9..7a29fdeaa 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/atn/SingletonPredictionContext.java +++ b/runtime/Java/src/org/antlr/v4/runtime/atn/SingletonPredictionContext.java @@ -50,6 +50,14 @@ public class SingletonPredictionContext extends PredictionContext { return this.invokingState == invokingState ? 0 : -1; } + @Override + public PredictionContext popAll(int invokingState, boolean fullCtx) { + if ( invokingState == this.invokingState ) { + return parent.popAll(invokingState, fullCtx); + } + return this; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/tool/playground/T.g b/tool/playground/T.g index 83e79ba0f..31bea6bda 100644 --- a/tool/playground/T.g +++ b/tool/playground/T.g @@ -1,8 +1,7 @@ grammar T; -s : a a a; +s : a+ ; a : {false}? ID {System.out.println("alt 1");} | {true}? ID {System.out.println("alt 2");} - | INT {System.out.println("alt 3");} ; ID : 'a'..'z'+ ; INT : '0'..'9'+;