forked from jasder/antlr
Consistent handling of element options applied to alternatives (fixes #542)
This commit is contained in:
parent
8f08802716
commit
6eeafacb88
|
@ -285,6 +285,12 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
|
|||
GrammarAST alt = (GrammarAST)blk.getChildren().get(i);
|
||||
Tree first = alt.getChild(0);
|
||||
if ( first==null ) continue;
|
||||
if (first.getType() == ELEMENT_OPTIONS) {
|
||||
first = alt.getChild(1);
|
||||
if (first == null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ( first.getType()==RULE_REF && first.getText().equals(ruleName) ) return true;
|
||||
Tree rref = first.getChild(1);
|
||||
if ( rref!=null && rref.getType()==RULE_REF && rref.getText().equals(ruleName) ) return true;
|
||||
|
|
|
@ -769,8 +769,8 @@ public class ParserATNFactory implements ATNFactory {
|
|||
for (Object alt : block.getChildren()) {
|
||||
if ( !(alt instanceof AltAST) ) continue;
|
||||
AltAST altAST = (AltAST)alt;
|
||||
if ( altAST.getChildCount()==1 ) {
|
||||
Tree e = altAST.getChild(0);
|
||||
if ( altAST.getChildCount()==1 || (altAST.getChildCount() == 2 && altAST.getChild(0).getType() == ANTLRParser.ELEMENT_OPTIONS) ) {
|
||||
Tree e = altAST.getChild(altAST.getChildCount() - 1);
|
||||
if ( e.getType()==ANTLRParser.WILDCARD ) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -99,9 +99,9 @@ alt[boolean outerMost] returns [CodeBlockForAlt altCodeBlock, List<SrcOp> ops]
|
|||
$altCodeBlock.ops = $ops = elems;
|
||||
controller.setCurrentBlock($altCodeBlock);
|
||||
}
|
||||
^( ALT ( element {if ($element.omos!=null) elems.addAll($element.omos);} )+ )
|
||||
^( ALT elementOptions? ( element {if ($element.omos!=null) elems.addAll($element.omos);} )+ )
|
||||
|
||||
| ^(ALT EPSILON)
|
||||
| ^(ALT elementOptions? EPSILON)
|
||||
{$altCodeBlock = controller.epsilon(controller.getCurrentOuterMostAlt(), outerMost);}
|
||||
;
|
||||
|
||||
|
|
|
@ -658,10 +658,11 @@ alternative
|
|||
paraphrases.pop();
|
||||
Grammar.setNodeOptions($tree, $o.tree);
|
||||
}
|
||||
: o=elementOptions?
|
||||
e+=element+ -> ^(ALT<AltAST> elementOptions? $e+)
|
||||
| -> ^(ALT<AltAST> EPSILON) // empty alt
|
||||
;
|
||||
: o=elementOptions?
|
||||
( e+=element+ -> ^(ALT<AltAST> elementOptions? $e+)
|
||||
| -> ^(ALT<AltAST> elementOptions? EPSILON) // empty alt
|
||||
)
|
||||
;
|
||||
|
||||
element
|
||||
@init {
|
||||
|
|
|
@ -104,8 +104,8 @@ alternative returns [ATNFactory.Handle p]
|
|||
@init {List<ATNFactory.Handle> els = new ArrayList<ATNFactory.Handle>();}
|
||||
: ^(LEXER_ALT_ACTION a=alternative lexerCommands)
|
||||
{$p = factory.lexerAltCommands($a.p,$lexerCommands.p);}
|
||||
| ^(ALT EPSILON) {$p = factory.epsilon($EPSILON);}
|
||||
| ^(ALT (e=element {els.add($e.p);})+) {$p = factory.alt(els);}
|
||||
| ^(ALT elementOptions? EPSILON) {$p = factory.epsilon($EPSILON);}
|
||||
| ^(ALT elementOptions? (e=element {els.add($e.p);})+) {$p = factory.alt(els);}
|
||||
;
|
||||
|
||||
lexerCommands returns [ATNFactory.Handle p]
|
||||
|
@ -200,3 +200,15 @@ terminal returns [ATNFactory.Handle p]
|
|||
| ^(TOKEN_REF .) {$p = factory.tokenRef((TerminalAST)$start);}
|
||||
| TOKEN_REF {$p = factory.tokenRef((TerminalAST)$start);}
|
||||
;
|
||||
|
||||
elementOptions
|
||||
: ^(ELEMENT_OPTIONS elementOption*)
|
||||
;
|
||||
|
||||
elementOption
|
||||
: ID
|
||||
| ^(ASSIGN ID ID)
|
||||
| ^(ASSIGN ID STRING_LITERAL)
|
||||
| ^(ASSIGN ID ACTION)
|
||||
| ^(ASSIGN ID INT)
|
||||
;
|
||||
|
|
|
@ -95,10 +95,10 @@ boolean inLexer = Grammar.isTokenName(currentRuleName);
|
|||
GrammarTransformPipeline.setGrammarPtr(g, $tree);
|
||||
}
|
||||
: {inContext("RULE")}? // top-level: rule block and > 1 alt
|
||||
^(BLOCK ^(alt=ALT {((AltAST)$alt).altLabel==null}? setElement[inLexer]) ( ^(ALT setElement[inLexer]) )+)
|
||||
^(BLOCK ^(alt=ALT elementOptions? {((AltAST)$alt).altLabel==null}? setElement[inLexer]) ( ^(ALT elementOptions? setElement[inLexer]) )+)
|
||||
-> ^(BLOCK<BlockAST>[$BLOCK.token] ^(ALT<AltAST>[$BLOCK.token,"ALT"] ^(SET[$BLOCK.token, "SET"] setElement+)))
|
||||
| {!inContext("RULE")}? // if not rule block and > 1 alt
|
||||
^(BLOCK ^(ALT setElement[inLexer]) ( ^(ALT setElement[inLexer]) )+)
|
||||
^(BLOCK ^(ALT elementOptions? setElement[inLexer]) ( ^(ALT elementOptions? setElement[inLexer]) )+)
|
||||
-> ^(SET[$BLOCK.token, "SET"] setElement+)
|
||||
;
|
||||
|
||||
|
|
|
@ -767,7 +767,7 @@ alternative
|
|||
exitAlternative((AltAST)$start);
|
||||
}
|
||||
: ^(ALT elementOptions? element+)
|
||||
| ^(ALT EPSILON)
|
||||
| ^(ALT elementOptions? EPSILON)
|
||||
;
|
||||
|
||||
lexerCommand
|
||||
|
|
|
@ -139,7 +139,7 @@ suffix
|
|||
;
|
||||
|
||||
nonLeftRecur
|
||||
: ^(ALT element+) // no assoc for these; ignore if <assoc=...> present
|
||||
: ^(ALT elementOptions? element+)
|
||||
;
|
||||
|
||||
recurse
|
||||
|
|
|
@ -152,6 +152,36 @@ public class TestLeftRecursion extends BaseTest {
|
|||
runTests(grammar, tests, "s");
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a regression test for antlr/antlr4#542 "First alternative cannot
|
||||
* be right-associative".
|
||||
* https://github.com/antlr/antlr4/issues/542
|
||||
*/
|
||||
@Test public void testTernaryExprExplicitAssociativity() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"s @after {System.out.println($ctx.toStringTree(this));} : e EOF ;\n" + // must indicate EOF can follow or 'a<EOF>' won't match
|
||||
"e :<assoc=right> e '*' e" +
|
||||
" |<assoc=right> e '+' e" +
|
||||
" |<assoc=right> e '?' e ':' e" +
|
||||
" |<assoc=right> e '=' e" +
|
||||
" | ID" +
|
||||
" ;\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"WS : (' '|'\\n') -> skip ;\n";
|
||||
String[] tests = {
|
||||
"a", "(s (e a) <EOF>)",
|
||||
"a+b", "(s (e (e a) + (e b)) <EOF>)",
|
||||
"a*b", "(s (e (e a) * (e b)) <EOF>)",
|
||||
"a?b:c", "(s (e (e a) ? (e b) : (e c)) <EOF>)",
|
||||
"a=b=c", "(s (e (e a) = (e (e b) = (e c))) <EOF>)",
|
||||
"a?b+c:d", "(s (e (e a) ? (e (e b) + (e c)) : (e d)) <EOF>)",
|
||||
"a?b=c:d", "(s (e (e a) ? (e (e b) = (e c)) : (e d)) <EOF>)",
|
||||
"a? b?c:d : e", "(s (e (e a) ? (e (e b) ? (e c) : (e d)) : (e e)) <EOF>)",
|
||||
"a?b: c?d:e", "(s (e (e a) ? (e b) : (e (e c) ? (e d) : (e e))) <EOF>)",
|
||||
};
|
||||
runTests(grammar, tests, "s");
|
||||
}
|
||||
|
||||
@Test public void testExpressions() throws Exception {
|
||||
String grammar =
|
||||
|
|
Loading…
Reference in New Issue