forked from jasder/antlr
ANTLR4 generated incorrect code to access return value of recursive rule
Incorrect code was generated for $e.v in a rule like this one: e returns [int v] ::= INT {$v = $INT.int;} | '(' e ')' {$v = $e.v;} ; After parsing "(99)" the result would have v == 0 instead of 99.
This commit is contained in:
parent
3d8f81a63e
commit
ab8d17472f
|
@ -30,6 +30,7 @@
|
|||
package org.antlr.v4.test.runtime.java;
|
||||
|
||||
import org.antlr.v4.Tool;
|
||||
import org.antlr.v4.analysis.AnalysisPipeline;
|
||||
import org.antlr.v4.automata.ATNFactory;
|
||||
import org.antlr.v4.automata.ATNPrinter;
|
||||
import org.antlr.v4.automata.LexerATNFactory;
|
||||
|
@ -913,6 +914,9 @@ public class BaseJavaTest implements RuntimeTestSupport {
|
|||
if ( g.isLexer() ) factory = new LexerATNFactory((LexerGrammar)g);
|
||||
g.atn = factory.createATN();
|
||||
|
||||
AnalysisPipeline anal = new AnalysisPipeline(g);
|
||||
anal.process();
|
||||
|
||||
CodeGenerator gen = new CodeGenerator(g);
|
||||
ST outputFileST = gen.generateParser(false);
|
||||
String output = outputFileST.render();
|
||||
|
|
|
@ -176,6 +176,45 @@ public class TestActionTranslation extends BaseJavaTest {
|
|||
testActions(attributeTemplate, "inline", action, expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regression test for issue #1295
|
||||
* $e.v yields incorrect value 0 in "e returns [int v] : '1' {$v = 1;} | '(' e ')' {$v = $e.v;} ;"
|
||||
* https://github.com/antlr/antlr4/issues/1295
|
||||
*/
|
||||
@Test public void testRuleRefsRecursive() throws Exception {
|
||||
String recursiveTemplate =
|
||||
"recursiveTemplate(inline) ::= <<\n" +
|
||||
"parser grammar A;\n"+
|
||||
"e returns [int v]\n" +
|
||||
" : INT {$v = $INT.int;}\n" +
|
||||
" | '(' e ')' {\n" +
|
||||
" #inline#<inline>#end-inline#\n" +
|
||||
" }\n" +
|
||||
" ;\n" +
|
||||
">>";
|
||||
String leftRecursiveTemplate =
|
||||
"recursiveTemplate(inline) ::= <<\n" +
|
||||
"parser grammar A;\n"+
|
||||
"e returns [int v]\n" +
|
||||
" : a=e op=('*'|'/') b=e {$v = eval($a.v, $op.type, $b.v);}\n" +
|
||||
" | INT {$v = $INT.int;}\n" +
|
||||
" | '(' e ')' {\n" +
|
||||
" #inline#<inline>#end-inline#\n" +
|
||||
" }\n" +
|
||||
" ;\n" +
|
||||
">>";
|
||||
// ref to value returned from recursive call to rule
|
||||
String action = "$v = $e.v;";
|
||||
String expected = "((EContext)_localctx).v = ((EContext)_localctx).e.v;";
|
||||
testActions(recursiveTemplate, "inline", action, expected);
|
||||
testActions(leftRecursiveTemplate, "inline", action, expected);
|
||||
// ref to predefined attribute obtained from recursive call to rule
|
||||
action = "$v = $e.text.length();";
|
||||
expected = "((EContext)_localctx).v = (((EContext)_localctx).e!=null?_input.getText(((EContext)_localctx).e.start,((EContext)_localctx).e.stop):null).length();";
|
||||
testActions(recursiveTemplate, "inline", action, expected);
|
||||
testActions(leftRecursiveTemplate, "inline", action, expected);
|
||||
}
|
||||
|
||||
@Test public void testRefToTextAttributeForCurrentRule() throws Exception {
|
||||
String action = "$ctx.text; $text";
|
||||
|
||||
|
|
|
@ -214,23 +214,10 @@ public class ActionTranslator implements ActionSplitterListener {
|
|||
switch ( a.dict.type ) {
|
||||
case ARG: chunks.add(new ArgRef(nodeContext,y.getText())); break; // has to be current rule
|
||||
case RET:
|
||||
if ( factory.getCurrentRuleFunction()!=null &&
|
||||
factory.getCurrentRuleFunction().name.equals(x.getText()) )
|
||||
{
|
||||
chunks.add(new RetValueRef(rf.ruleCtx, y.getText())); break;
|
||||
}
|
||||
else {
|
||||
chunks.add(new QRetValueRef(nodeContext, getRuleLabel(x.getText()), y.getText())); break;
|
||||
}
|
||||
chunks.add(new QRetValueRef(nodeContext, getRuleLabel(x.getText()), y.getText()));
|
||||
break;
|
||||
case PREDEFINED_RULE:
|
||||
if ( factory.getCurrentRuleFunction()!=null &&
|
||||
factory.getCurrentRuleFunction().name.equals(x.getText()) )
|
||||
{
|
||||
chunks.add(getRulePropertyRef(y));
|
||||
}
|
||||
else {
|
||||
chunks.add(getRulePropertyRef(x, y));
|
||||
}
|
||||
chunks.add(getRulePropertyRef(x, y));
|
||||
break;
|
||||
case TOKEN:
|
||||
chunks.add(getTokenPropertyRef(x, y));
|
||||
|
|
Loading…
Reference in New Issue