getting more unit tests in

[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 8924]
This commit is contained in:
parrt 2011-07-29 14:05:19 -08:00
parent 4b5cd3a9ba
commit b90b073450
3 changed files with 286 additions and 2 deletions

View File

@ -501,7 +501,9 @@ public class ParserATNSimulator extends ATNSimulator {
", using context="+ctx); ", using context="+ctx);
} }
int fromRuleIndex = config.state.ruleIndex; int fromRuleIndex = config.state.ruleIndex;
if ( argIndex>=0 ) { if ( argIndex>=0 && ctx!=null ) {
// we have an argument and we know its context or it's not depedent
/*
// we're forced to exec args, even if dependent on _localctx. // we're forced to exec args, even if dependent on _localctx.
// If no actual context to use, create dummy context to use // If no actual context to use, create dummy context to use
// for arg eval only. // for arg eval only.
@ -509,11 +511,14 @@ public class ParserATNSimulator extends ATNSimulator {
// get dummy context for fromRuleIndex // get dummy context for fromRuleIndex
ctx = parser.newContext(null, config.state.stateNumber, fromRuleIndex); ctx = parser.newContext(null, config.state.stateNumber, fromRuleIndex);
} }
*/
newContext = parser.newContext(ctx, t.target.stateNumber, newContext = parser.newContext(ctx, t.target.stateNumber,
fromRuleIndex, fromRuleIndex,
argIndex); argIndex);
} }
else { else {
// there is no argument or there is a dependent arg but
// we are unable to identify the proper context
newContext = parser.newContext(ctx, t.target.stateNumber, targetRuleIndex); newContext = parser.newContext(ctx, t.target.stateNumber, targetRuleIndex);
} }

View File

@ -34,7 +34,7 @@ public class TestU {
ULexer t = new ULexer(new ANTLRFileStream(args[0])); ULexer t = new ULexer(new ANTLRFileStream(args[0]));
CommonTokenStream tokens = new CommonTokenStream(t); CommonTokenStream tokens = new CommonTokenStream(t);
UParser p = new UParser(tokens); UParser p = new UParser(tokens);
ParserRuleContext ret = p.a(33); ParserRuleContext ret = p.s();
// System.out.println(((Tree)ret.tree).toStringTree()); // System.out.println(((Tree)ret.tree).toStringTree());
} }
} }

View File

@ -117,4 +117,283 @@ public class TestSemPredEvalParser extends BaseTest {
assertEquals(expecting, found); assertEquals(expecting, found);
} }
/**
* The ATN simulator ignores the unforced action but sees the forced
* actions at the start of both alternatives. Further, during closure,
* it sees the 2nd forced action s1b in the 1st alternative. Once parsing
* begins, it executes the "parse" action as well as the forced actions
* in the 1st alternative.
*/
@Test public void testForcedAction() throws Exception {
String grammar =
"grammar T;\n" +
"@members {" +
"void f(Object s) {System.out.println(s);}\n" +
"}\n" +
"s : {f(\"parse\");} {{f(\"s1a\");}} ID {{f(\"s1b\");}} | {{f(\"s2\");}} ID ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {skip();} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer", "s",
"x x y", false);
String expecting =
"s1a\n" +
"s2\n" +
"s1b\n" +
"parse\n" +
"s1a\n" +
"s1b\n";
assertEquals(expecting, found);
}
/** To distinguish the alternatives of rule e, we compute FOLLOW(e),
* which includes all tokens that can be matched following all
* references to e. In this case, it sees two forced actions after
* references to e that it must execute.
*/
@Test public void testForcedActionInGlobalFOLLOW() throws Exception {
String grammar =
"grammar T;\n" +
"@members {" +
"void f(Object s) {System.out.println(s);}\n" +
"}\n" +
"s : e {{f(\"s1\");}} {f(\"alt 1\");} '!' ;\n" +
"t : e {{f(\"t1\");}} ID ;\n" +
"e : ID | ;\n" + // non-LL(1) so we use ATN
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {skip();} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer", "s",
"a!", false);
String expecting =
"s1\n" + // do s1, t1 once during s0 computation from epsilon edge in e
"t1\n" +
"s1\n" + // do them again during closure after passing ID in e
"t1\n" +
"s1\n" + // now we are parsing
"alt 1\n";
assertEquals(expecting, found);
}
/**
* Actions that depend on local scope information such as local
* variables and arguments are executed if we are sure we have the
* right RuleContext object. Have the correct context for any rule
* that we invoke during ATN simulation (unless we fall off the edge
* of the initial rule into the outer context. see other unit
* tests). In this case, the forced actions are accessing the
* argument of the surrounding rule so everything is okay.
*/
@Test public void testForcedDepedentActionInContext() throws Exception {
String grammar =
"grammar T;\n" +
"@members {" +
"void f(Object s) {System.out.println(s);}\n" +
"}\n" +
"s : a[99] ;\n" +
"a[int i] : {f(\"parse\");} {{f($i);}} ID {{f(\"s1b\");}} | {{f($i+1);}} ID ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {skip();} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer", "s",
"x x y", false);
String expecting =
"99\n" +
"100\n" +
"s1b\n" +
"parse\n" +
"99\n" +
"s1b\n";
assertEquals(expecting, found);
}
/** In this case, we also know what the context is for $i. During
* ATN simulation, rule a invokes rule b which creates the correct context.
*/
@Test public void testForcedDepedentActionInContext2() throws Exception {
String grammar =
"grammar T;\n" +
"@members {" +
"void f(Object s) {System.out.println(s);}\n" +
"}\n" +
"s : a ;\n" +
"a : {f(\"parse\");} b {{f(\"s1b\");}} | b ;\n" +
"b returns [int i=32] : {{f($i);}} ID ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {skip();} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer", "s",
"x x y", false);
String expecting =
"32\n" +
"32\n" +
"s1b\n" +
"parse\n" +
"32\n" +
"s1b\n";
assertEquals(expecting, found);
}
/** We must execute all arguments for rules that we invoked during ATN
* simulation. In this case, the evaluation of the arguments is clearly
* okay because the arguments are not dependent on local context.
*/
@Test public void testArgEval() throws Exception {
String grammar =
"grammar T;\n" +
"@members {" +
"void f(Object s) {System.out.println(s);}\n" +
"}\n" +
"s : {f(\"parse\");} b[1] {{f(\"s1b\");}} | b[2] ;\n" +
"b[int i] : {{f($i);}} ID ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {skip();} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer", "s",
"x x y", false);
String expecting =
"1\n" +
"2\n" +
"s1b\n" +
"parse\n" +
"1\n" +
"s1b\n";
assertEquals(expecting, found);
}
/** The arguments to rule b access $i, which makes it dependent upon
* the local context. It's okay, because we are in the proper spot.
*/
@Test public void testDepedentArgEval() throws Exception {
String grammar =
"grammar T;\n" +
"@members {" +
"void f(Object s) {System.out.println(s);}\n" +
"}\n" +
"s : a[1] ;\n" +
"a[int i] : {f(\"parse\");} b[$i] {{f(\"s1b\");}} | b[$i+1] ;\n" +
"b[int i] : {{f($i);}} ID ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {skip();} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer", "s",
"x x y", false);
String expecting =
"1\n" +
"2\n" +
"s1b\n" +
"parse\n" +
"1\n" +
"s1b\n";
assertEquals(expecting, found);
}
/** The call chain is s a e but since e is optional, we invoke the
* global follow of e. This runs into the foo rule invocations, both of
* which have parameters that are dependent upon the local context.
* Because we can never be sure if we are in the proper context (without
* using full LL(*) context parsing), we can't ever execute dependent
* actions encountered during global follows. We create an uninitialized
* foo_ctx object for use while chasing edges in foo.
*/
@Test public void testDepedentArgEvalInGlobalFOLLOW() throws Exception {
String grammar =
"grammar T;\n" +
"@members {" +
"int f(int s) {System.out.println(s); return s;}\n" +
"}\n" +
"s : a[1] ;\n" +
"a[int i] : e foo[f($i)] ;\n" +
"b[int i] : e foo[f($i+1)] ;\n" +
"e : ID | ;\n" +
"foo[int k] : ID ';' ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {skip();} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer", "s",
"x y;", false);
String expecting =
"1\n"; // f($i) executed only during real parse during call to foo.
assertEquals(expecting, found);
}
@Test public void testForcedDepedentActionInGlobalFOLLOW() throws Exception {
String grammar =
"grammar T;\n" +
"@members {" +
"int f(int s) {System.out.println(s); return s;}\n" +
"}\n" +
"s : a[1] ;\n" +
"a[int i] : e {{f($i);}} ID '!' ;\n" +
"b[int i] : e {{f($i+1);}} ID '?' ;\n" +
"e : ID | ;\n" +
"foo[int k] : ID ';' ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {skip();} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer", "s",
"x y !", false);
String expecting =
"1\n";
assertEquals(expecting, found);
}
@Test public void testPredsInGlobalFOLLOW() throws Exception {
String grammar =
"grammar T;\n" +
"@members {" +
"void f(Object s) {System.out.println(s);}\n" +
"}\n" +
"s : e {{f(\"s1\");}} {f(\"alt 1\");} '!' ;\n" +
"t : e {{f(\"t1\");}} ID ;\n" +
"e : ID | ;\n" + // non-LL(1) so we use ATN
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {skip();} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer", "s",
"a!", false);
String expecting =
"s1\n" + // do s1, t1 once during s0 computation from epsilon edge in e
"t1\n" +
"s1\n" + // do them again during closure after passing ID in e
"t1\n" +
"s1\n" + // now we are parsing
"alt 1\n";
assertEquals(expecting, found);
}
@Test public void testDepedentPredsInGlobalFOLLOW() throws Exception {
String grammar =
"grammar T;\n" +
"@members {" +
"int f(int s) {System.out.println(s); return s;}\n" +
"}\n" +
"s : a[1] ;\n" +
"a[int i] : e {{f($i);}} ID '!' ;\n" +
"b[int i] : e {{f($i+1);}} ID '?' ;\n" +
"e : ID | ;\n" +
"foo[int k] : ID ';' ;\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+;\n" +
"WS : (' '|'\\n') {skip();} ;\n";
String found = execParser("T.g", grammar, "TParser", "TLexer", "s",
"x y !", false);
String expecting =
"1\n";
assertEquals(expecting, found);
}
// "boolean p(boolean v) {System.out.println(\"eval=\"+v); return v;}\n" +
} }