Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make test suite deterministic. #195

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tool/src/main/java/org/antlr/analysis/DFAState.java
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ public Set<Integer> getAltSet() {

public Set<? extends SemanticContext> getGatedSyntacticPredicatesInNFAConfigurations() {
int numConfigs = nfaConfigurations.size();
Set<SemanticContext> synpreds = new HashSet<SemanticContext>();
Set<SemanticContext> synpreds = new LinkedHashSet<SemanticContext>();
for (int i = 0; i < numConfigs; i++) {
NFAConfiguration configuration = nfaConfigurations.get(i);
SemanticContext gatedPredExpr =
Expand Down
36 changes: 18 additions & 18 deletions tool/src/main/java/org/antlr/analysis/DecisionProbe.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,44 +79,44 @@ public class DecisionProbe {
* Note that from the DFA state, you can ask for
* which alts are nondeterministic.
*/
protected Set<DFAState> statesWithSyntacticallyAmbiguousAltsSet = new HashSet<DFAState>();
protected Set<DFAState> statesWithSyntacticallyAmbiguousAltsSet = new LinkedHashSet<DFAState>();

/** Track just like stateToSyntacticallyAmbiguousAltsMap, but only
* for nondeterminisms that arise in the Tokens rule such as keyword vs
* ID rule. The state maps to the list of Tokens rule alts that are
* in conflict.
*/
protected Map<DFAState, Set<Integer>> stateToSyntacticallyAmbiguousTokensRuleAltsMap =
new HashMap<DFAState, Set<Integer>>();
new LinkedHashMap<DFAState, Set<Integer>>();

/** Was a syntactic ambiguity resolved with predicates? Any DFA
* state that predicts more than one alternative, must be resolved
* with predicates or it should be reported to the user.
*/
protected Set<DFAState> statesResolvedWithSemanticPredicatesSet = new HashSet<DFAState>();
protected Set<DFAState> statesResolvedWithSemanticPredicatesSet = new LinkedHashSet<DFAState>();

/** Track the predicates for each alt per DFA state;
* more than one DFA state might have syntactically ambig alt prediction.
* Maps DFA state to another map, mapping alt number to a
* SemanticContext (pred(s) to execute to resolve syntactic ambiguity).
*/
protected Map<DFAState, Map<Integer,SemanticContext>> stateToAltSetWithSemanticPredicatesMap =
new HashMap<DFAState, Map<Integer,SemanticContext>>();
new LinkedHashMap<DFAState, Map<Integer,SemanticContext>>();

/** Tracks alts insufficiently covered.
* For example, p1||true gets reduced to true and so leaves
* whole alt uncovered. This maps DFA state to the set of alts
*/
protected Map<DFAState,Map<Integer, Set<Token>>> stateToIncompletelyCoveredAltsMap =
new HashMap<DFAState,Map<Integer, Set<Token>>>();
new LinkedHashMap<DFAState,Map<Integer, Set<Token>>>();

/** The set of states w/o emanating edges and w/o resolving sem preds. */
protected Set<DFAState> danglingStates = new HashSet<DFAState>();
protected Set<DFAState> danglingStates = new LinkedHashSet<DFAState>();

/** The overall list of alts within the decision that have at least one
* conflicting input sequence.
*/
protected Set<Integer> altsWithProblem = new HashSet<Integer>();
protected Set<Integer> altsWithProblem = new LinkedHashSet<Integer>();

/** If decision with &gt; 1 alt has recursion in &gt; 1 alt, it's (likely) nonregular
* lookahead. The decision cannot be made with a DFA.
Expand All @@ -137,7 +137,7 @@ public class DecisionProbe {
/** Left recursion discovered. The proposed new NFAConfiguration
* is recorded for the associated DFA state.
protected Map<Integer,List<NFAConfiguration>> stateToLeftRecursiveConfigurationsMap =
new HashMap<Integer,List<NFAConfiguration>>();
new LinkedHashMap<Integer,List<NFAConfiguration>>();
*/

/** Did ANTLR have to terminate early on the analysis of this decision? */
Expand Down Expand Up @@ -297,7 +297,7 @@ public void removeRecursiveOverflowState(DFAState d) {
*/
public List<Label> getSampleNonDeterministicInputSequence(DFAState targetState) {
Set<DFAState> dfaStates = getDFAPathStatesToTarget(targetState);
statesVisitedDuringSampleSequence = new HashSet<Integer>();
statesVisitedDuringSampleSequence = new LinkedHashSet<Integer>();
List<Label> labels = new ArrayList<Label>(); // may access ith element; use array
if ( dfa==null || dfa.startState==null ) {
return labels;
Expand Down Expand Up @@ -372,7 +372,7 @@ public List<? extends NFAState> getNFAPathStatesForAlt(int firstAlt,
path.add(isolatedAltStart);

// add the actual path now
statesVisitedAtInputDepth = new HashSet<String>();
statesVisitedAtInputDepth = new LinkedHashSet<String>();
getNFAPath(isolatedAltStart,
0,
labels,
Expand Down Expand Up @@ -532,9 +532,9 @@ protected void issueRecursionWarnings() {
// Goal: create a map from alt to map<target,List<callsites>>
// Map<Map<String target, List<NFAState call sites>>
Map<Integer, Map<String, Set<NFAState>>> altToTargetToCallSitesMap =
new HashMap<Integer, Map<String, Set<NFAState>>>();
new LinkedHashMap<Integer, Map<String, Set<NFAState>>>();
// track a single problem DFA state for each alt
Map<Integer, DFAState> altToDFAState = new HashMap<Integer, DFAState>();
Map<Integer, DFAState> altToDFAState = new LinkedHashMap<Integer, DFAState>();
computeAltToProblemMaps(dfaStatesWithRecursionProblems,
stateToRecursionOverflowConfigurationsMap,
altToTargetToCallSitesMap, // output param
Expand Down Expand Up @@ -576,13 +576,13 @@ private void computeAltToProblemMaps(Set<Integer> dfaStatesUnaliased,
Map<String, Set<NFAState>> targetToCallSiteMap =
altToTargetToCallSitesMap.get(altI);
if ( targetToCallSiteMap==null ) {
targetToCallSiteMap = new HashMap<String, Set<NFAState>>();
targetToCallSiteMap = new LinkedHashMap<String, Set<NFAState>>();
altToTargetToCallSitesMap.put(altI, targetToCallSiteMap);
}
Set<NFAState> callSites =
targetToCallSiteMap.get(targetRule);
if ( callSites==null ) {
callSites = new HashSet<NFAState>();
callSites = new LinkedHashSet<NFAState>();
targetToCallSiteMap.put(targetRule, callSites);
}
callSites.add(ruleInvocationState);
Expand All @@ -596,7 +596,7 @@ private void computeAltToProblemMaps(Set<Integer> dfaStatesUnaliased,
}

private Set<Integer> getUnaliasedDFAStateSet(Set<Integer> dfaStatesWithRecursionProblems) {
Set<Integer> dfaStatesUnaliased = new HashSet<Integer>();
Set<Integer> dfaStatesUnaliased = new LinkedHashSet<Integer>();
for (Integer stateI : dfaStatesWithRecursionProblems) {
DFAState d = dfa.getState(stateI);
dfaStatesUnaliased.add(Utils.integer(d.stateNumber));
Expand Down Expand Up @@ -684,7 +684,7 @@ public void reportNondeterminismResolvedWithSemanticPredicate(DFAState d) {
* in d as resolved.
*/
public void reportAltPredicateContext(DFAState d, Map<Integer, ? extends SemanticContext> altPredicateContext) {
Map<Integer, SemanticContext> copy = new HashMap<Integer, SemanticContext>();
Map<Integer, SemanticContext> copy = new LinkedHashMap<Integer, SemanticContext>();
copy.putAll(altPredicateContext);
stateToAltSetWithSemanticPredicatesMap.put(d,copy);
}
Expand Down Expand Up @@ -745,8 +745,8 @@ protected boolean reachesState(DFAState startState,
}

protected Set<DFAState> getDFAPathStatesToTarget(DFAState targetState) {
Set<DFAState> dfaStates = new HashSet<DFAState>();
stateReachable = new HashMap<Integer, Integer>();
Set<DFAState> dfaStates = new LinkedHashSet<DFAState>();
stateReachable = new LinkedHashMap<Integer, Integer>();
if ( dfa==null || dfa.startState==null ) {
return dfaStates;
}
Expand Down
8 changes: 4 additions & 4 deletions tool/src/main/java/org/antlr/analysis/NFAToDFAConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ protected void findNewDFAStatesAndAddDFATransitions(DFAState d) {
*/

int numberOfEdgesEmanating = 0;
Map<Integer, Transition> targetToLabelMap = new HashMap<Integer, Transition>();
Map<Integer, Transition> targetToLabelMap = new LinkedHashMap<Integer, Transition>();
// for each label that could possibly emanate from NFAStates of d
int numLabels = 0;
if ( labels!=null ) {
Expand Down Expand Up @@ -1487,10 +1487,10 @@ protected Map<Integer, SemanticContext> getPredicatesPerNonDeterministicAlt(DFAS
{
// map alt to combined SemanticContext
Map<Integer, SemanticContext> altToPredicateContextMap =
new HashMap<Integer, SemanticContext>();
new LinkedHashMap<Integer, SemanticContext>();
// init the alt to predicate set map
Map<Integer, OrderedHashSet<SemanticContext>> altToSetOfContextsMap =
new HashMap<Integer, OrderedHashSet<SemanticContext>>();
new LinkedHashMap<Integer, OrderedHashSet<SemanticContext>>();
for (Integer altI : nondeterministicAlts) {
altToSetOfContextsMap.put(altI, new OrderedHashSet<SemanticContext>());
}
Expand All @@ -1504,7 +1504,7 @@ protected Map<Integer, SemanticContext> getPredicatesPerNonDeterministicAlt(DFAS
// for each configuration, create a unique set of predicates
// Also, track the alts with at least one uncovered configuration
// (one w/o a predicate); tracks tautologies like p1||true
Map<Integer, Set<Token>> altToLocationsReachableWithoutPredicate = new HashMap<Integer, Set<Token>>();
Map<Integer, Set<Token>> altToLocationsReachableWithoutPredicate = new LinkedHashMap<Integer, Set<Token>>();
Set<Integer> nondetAltsWithUncoveredConfiguration = new HashSet<Integer>();
//System.out.println("configs="+d.nfaConfigurations);
//System.out.println("configs with preds?"+d.atLeastOneConfigurationHasAPredicate);
Expand Down
19 changes: 12 additions & 7 deletions tool/src/main/java/org/antlr/analysis/SemanticContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ public abstract ST genExpr(CodeGenerator generator,
public void trackUseOfSyntacticPredicates(Grammar g) {
}

@Override
public abstract int hashCode();
@Override
public abstract String toString();

public static class Predicate extends SemanticContext {
/** The AST node in tree created from the grammar holding the predicate */
public GrammarAST predicateAST;
Expand Down Expand Up @@ -304,7 +309,7 @@ public String toString() {
}

public static abstract class CommutativePredicate extends SemanticContext {
protected final Set<SemanticContext> operands = new HashSet<SemanticContext>();
protected final Set<SemanticContext> operands = new LinkedHashSet<SemanticContext>();
protected int hashcode;

public CommutativePredicate(SemanticContext a, SemanticContext b) {
Expand Down Expand Up @@ -733,10 +738,10 @@ public static SemanticContext[] factorAnd(SemanticContext a, SemanticContext b)
return new SemanticContext[] { new TruePredicate(), EMPTY_SEMANTIC_CONTEXT, EMPTY_SEMANTIC_CONTEXT };
}

HashSet<SemanticContext> opsA = new HashSet<SemanticContext>(getAndOperands(a));
HashSet<SemanticContext> opsB = new HashSet<SemanticContext>(getAndOperands(b));
HashSet<SemanticContext> opsA = new LinkedHashSet<SemanticContext>(getAndOperands(a));
HashSet<SemanticContext> opsB = new LinkedHashSet<SemanticContext>(getAndOperands(b));

HashSet<SemanticContext> result = new HashSet<SemanticContext>(opsA);
HashSet<SemanticContext> result = new LinkedHashSet<SemanticContext>(opsA);
result.retainAll(opsB);
if (result.isEmpty())
return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };
Expand Down Expand Up @@ -766,10 +771,10 @@ else if (opsB.size() == 1)
// Factor so (a || b) == (result || a || b)
public static SemanticContext[] factorOr(SemanticContext a, SemanticContext b)
{
HashSet<SemanticContext> opsA = new HashSet<SemanticContext>(getOrOperands(a));
HashSet<SemanticContext> opsB = new HashSet<SemanticContext>(getOrOperands(b));
HashSet<SemanticContext> opsA = new LinkedHashSet<SemanticContext>(getOrOperands(a));
HashSet<SemanticContext> opsB = new LinkedHashSet<SemanticContext>(getOrOperands(b));

HashSet<SemanticContext> result = new HashSet<SemanticContext>(opsA);
HashSet<SemanticContext> result = new LinkedHashSet<SemanticContext>(opsA);
result.retainAll(opsB);
if (result.isEmpty())
return new SemanticContext[] { EMPTY_SEMANTIC_CONTEXT, a, b };
Expand Down
9 changes: 9 additions & 0 deletions tool/src/main/java/org/antlr/misc/BitSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,15 @@ public int size() {
return deg;
}

@Override
public int hashCode() {
int hashCode = 0;
for (int i=0; i < this.bits.length; i++) {
hashCode ^= this.bits[i];
}
return hashCode;
}

@Override
public boolean equals(Object other) {
if ( other == null || !(other instanceof BitSet) ) {
Expand Down
4 changes: 3 additions & 1 deletion tool/src/main/java/org/antlr/misc/Graph.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,12 @@ public void addEdge(Node<T> n) {

@Override
public String toString() { return payload.toString(); }
@Override
public int hashCode() { return payload.hashCode(); }
}

/** Map from node payload to node containing it */
protected Map<T,Node<T>> nodes = new HashMap<T,Node<T>>();
protected Map<T,Node<T>> nodes = new LinkedHashMap<T,Node<T>>();

public void addEdge(T a, T b) {
//System.out.println("add edge "+a+" to "+b);
Expand Down
5 changes: 5 additions & 0 deletions tool/src/main/java/org/antlr/misc/Interval.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public static Interval create(int a, int b) {
return cache[a];
}

@Override
public int hashCode() {
return this.a + 7*this.b;
}

@Override
public boolean equals(Object o) {
if ( o==null ) {
Expand Down
7 changes: 7 additions & 0 deletions tool/src/main/java/org/antlr/misc/IntervalSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,13 @@ public boolean equals(Object obj) {
return this.intervals.equals(other.intervals);
}

@Override
public int hashCode() {
// Since the intervals are sorted and disjoint, we can use the
// hashcode of the list as the hashcode of the set.
return this.intervals.hashCode();
}

@Override
public String toString() {
return toString(null);
Expand Down
28 changes: 14 additions & 14 deletions tool/src/test/java/org/antlr/test/TestSemanticPredicates.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public TestSemanticPredicates() {
"a : {p1}? {p1a}? A | {p2}? A ;");
String expecting =
".s0-A->.s1\n" +
".s1-{(p1a&&p1)}?->:s2=>1\n" +
".s1-{(p1&&p1a)}?->:s2=>1\n" +
".s1-{p2}?->:s3=>2\n";
checkDecision(g, 1, expecting, null, null, null, null, null, 0, false);
}
Expand All @@ -135,7 +135,7 @@ public void testOrPredicates() throws Exception {
"b : {p1}? A | {p1a}? A ;");
String expecting =
".s0-A->.s1\n" +
".s1-{(p1a||p1)}?->:s2=>1\n" +
".s1-{(p1||p1a)}?->:s2=>1\n" +
".s1-{p2}?->:s3=>2\n";
checkDecision(g, 1, expecting, null, null, null, null, null, 0, false);
}
Expand Down Expand Up @@ -312,7 +312,7 @@ public void testOrPredicates() throws Exception {
".s0-A->.s1\n" +
".s1-B->:s2=>1\n" +
".s1-C->:s3=>2\n" +
".s1-{!((p3||p2))}?->:s5=>4\n" +
".s1-{!((p2||p3))}?->:s5=>4\n" +
".s1-{p2}?->:s4=>3\n" +
".s1-{p3}?->:s6=>5\n";
checkDecision(g, 1, expecting, null, null, null, null, null, 0, false);
Expand Down Expand Up @@ -445,10 +445,10 @@ public void testGatedPred() throws Exception {
"B : {p}? => 'a' ;\n" +
"C : {q}? => ('a'|'b')+ ;");
String expecting =
".s0-'a'&&{(q||p)}?->.s1\n" +
".s0-'a'&&{(p||q)}?->.s1\n" +
".s0-'b'&&{q}?->:s4=>2\n" +
".s1-'a'..'b'&&{q}?->:s4=>2\n" +
".s1-<EOT>&&{(q||p)}?->.s2\n" +
".s1-<EOT>&&{(p||q)}?->.s2\n" +
".s2-{p}?->:s3=>1\n" +
".s2-{q}?->:s4=>2\n";
checkDecision(g, 2, expecting, null, null, null, null, null, 0, false);
Expand All @@ -475,12 +475,12 @@ public void testGatedPredInCyclicDFA() throws Exception {
"A : {p}?=> ('a')+ 'x' ;\n" +
"B : {q}?=> ('a'|'b')+ 'x' ;");
String expecting =
".s0-'a'&&{(q||p)}?->.s1\n" +
".s0-'a'&&{(p||q)}?->.s1\n" +
".s0-'b'&&{q}?->:s5=>2\n" +
".s1-'a'&&{(q||p)}?->.s1\n" +
".s1-'a'&&{(p||q)}?->.s1\n" +
".s1-'b'&&{q}?->:s5=>2\n" +
".s1-'x'&&{(q||p)}?->.s2\n" +
".s2-<EOT>&&{(q||p)}?->.s3\n" +
".s1-'x'&&{(p||q)}?->.s2\n" +
".s2-<EOT>&&{(p||q)}?->.s3\n" +
".s3-{p}?->:s4=>1\n" +
".s3-{q}?->:s5=>2\n";
checkDecision(g, 3, expecting, null, null, null, null, null, 0, false);
Expand Down Expand Up @@ -533,7 +533,7 @@ public void testGatedPredInCyclicDFA() throws Exception {
" ;\n");
String expecting =
".s0-B->.s1\n" +
".s0-C&&{(r&&q)}?->:s3=>2\n" +
".s0-C&&{(q&&r)}?->:s3=>2\n" +
".s1-{p}?->:s2=>1\n" +
".s1-{q}?->:s3=>2\n";
checkDecision(g, 1, expecting, null, null, null, null, null, 0, false);
Expand All @@ -550,8 +550,8 @@ public void testGatedPredInCyclicDFA() throws Exception {
" ;\n");
String expecting =
".s0-B->.s1\n" +
".s0-C&&{(r&&q)}?->:s3=>2\n" +
".s1-{(s&&q)}?->:s3=>2\n" +
".s0-C&&{(q&&r)}?->:s3=>2\n" +
".s1-{(q&&s)}?->:s3=>2\n" +
".s1-{p}?->:s2=>1\n";
checkDecision(g, 1, expecting, null, null, null, null, null, 0, false);
}
Expand Down Expand Up @@ -734,7 +734,7 @@ public void testUniquePredicateOR() throws Exception {
" ;\n");
String expecting =
".s0-X->.s1\n" +
".s1-{((b||a)&&c)}?->:s2=>1\n" +
".s1-{(c&&(a||b))}?->:s2=>1\n" +
".s1-{c}?->:s3=>2\n";
int[] unreachableAlts = null;
int[] nonDetAlts = null;
Expand All @@ -761,7 +761,7 @@ public void testSemanticContextPreventsEarlyTerminationOfClosure() throws Except
String expecting =
".s0-ID->.s1\n" +
".s1-SEMI->.s2\n" +
".s2-{(for||do||while)}?->:s3=>1\n" +
".s2-{(while||do||for)}?->:s3=>1\n" +
".s2-{true}?->:s4=>2\n";
checkDecision(g, 1, expecting, null, null, null, null, null, 0, false);
}
Expand Down
Loading