commit
794e4a0b7b
|
@ -30,7 +30,7 @@
|
|||
package org.antlr.v4.codegen.model;
|
||||
|
||||
import org.antlr.v4.codegen.OutputModelFactory;
|
||||
import org.antlr.v4.runtime.misc.Triple;
|
||||
import org.antlr.v4.runtime.misc.Pair;
|
||||
import org.antlr.v4.tool.Grammar;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
import org.antlr.v4.tool.ast.ActionAST;
|
||||
|
@ -38,6 +38,7 @@ import org.antlr.v4.tool.ast.AltAST;
|
|||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** A model object representing a parse tree listener file.
|
||||
|
@ -57,10 +58,10 @@ public class ListenerFile extends OutputFile {
|
|||
parserName = g.getRecognizerName();
|
||||
grammarName = g.name;
|
||||
for (Rule r : g.rules.values()) {
|
||||
List<Triple<Integer,AltAST,String>> labels = r.getAltLabels();
|
||||
Map<String, List<Pair<Integer,AltAST>>> labels = r.getAltLabels();
|
||||
if ( labels!=null ) {
|
||||
for (Triple<Integer,AltAST,String> pair : labels) {
|
||||
listenerNames.add(pair.c);
|
||||
for (Map.Entry<String, List<Pair<Integer, AltAST>>> pair : labels.entrySet()) {
|
||||
listenerNames.add(pair.getKey());
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -51,7 +51,7 @@ import org.antlr.v4.parse.GrammarTreeVisitor;
|
|||
import org.antlr.v4.runtime.atn.ATNState;
|
||||
import org.antlr.v4.runtime.misc.IntervalSet;
|
||||
import org.antlr.v4.runtime.misc.OrderedHashSet;
|
||||
import org.antlr.v4.runtime.misc.Triple;
|
||||
import org.antlr.v4.runtime.misc.Pair;
|
||||
import org.antlr.v4.tool.Attribute;
|
||||
import org.antlr.v4.tool.ErrorType;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
|
@ -149,17 +149,28 @@ public class RuleFunction extends OutputModelObject {
|
|||
|
||||
// make structs for -> labeled alts, define ctx labels for elements
|
||||
altLabelCtxs = new HashMap<String,AltLabelStructDecl>();
|
||||
List<Triple<Integer,AltAST,String>> labels = r.getAltLabels();
|
||||
Map<String, List<Pair<Integer, AltAST>>> labels = r.getAltLabels();
|
||||
if ( labels!=null ) {
|
||||
for (Triple<Integer,AltAST,String> pair : labels) {
|
||||
Integer altNum = pair.a;
|
||||
AltAST altAST = pair.b;
|
||||
String label = pair.c;
|
||||
altToContext[altNum] = new AltLabelStructDecl(factory, r, altNum, label);
|
||||
altLabelCtxs.put(label, altToContext[altNum]);
|
||||
Set<Decl> decls = getDeclsForAltElements(altAST);
|
||||
// we know which ctx to put in, so do it directly
|
||||
for (Decl d : decls) altToContext[altNum].addDecl(d);
|
||||
for (Map.Entry<String, List<Pair<Integer, AltAST>>> entry : labels.entrySet()) {
|
||||
String label = entry.getKey();
|
||||
List<AltAST> alts = new ArrayList<AltAST>();
|
||||
for (Pair<Integer, AltAST> pair : entry.getValue()) {
|
||||
alts.add(pair.b);
|
||||
}
|
||||
|
||||
Set<Decl> decls = getDeclsForAllElements(alts);
|
||||
for (Pair<Integer, AltAST> pair : entry.getValue()) {
|
||||
Integer altNum = pair.a;
|
||||
altToContext[altNum] = new AltLabelStructDecl(factory, r, altNum, label);
|
||||
if (!altLabelCtxs.containsKey(label)) {
|
||||
altLabelCtxs.put(label, altToContext[altNum]);
|
||||
}
|
||||
|
||||
// we know which ctx to put in, so do it directly
|
||||
for (Decl d : decls) {
|
||||
altToContext[altNum].addDecl(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -223,28 +234,6 @@ public class RuleFunction extends OutputModelObject {
|
|||
}
|
||||
}
|
||||
|
||||
/** Get list of decls for token/rule refs.
|
||||
* Single ref X becomes X() getter
|
||||
* Multiple refs to X becomes List X() method, X(int i) method.
|
||||
* Ref X in a loop then we get List X(), X(int i)
|
||||
*
|
||||
* Does not gen labels for literals like '+', 'begin', ';', ...
|
||||
*/
|
||||
public Set<Decl> getDeclsForAltElements(AltAST altAST) {
|
||||
IntervalSet reftypes = new IntervalSet(RULE_REF,
|
||||
TOKEN_REF);
|
||||
List<GrammarAST> refs = altAST.getNodesWithType(reftypes);
|
||||
Set<Decl> decls = new HashSet<Decl>();
|
||||
FrequencySet<String> freq = getElementFrequenciesForAlt(altAST);
|
||||
for (GrammarAST t : refs) {
|
||||
String refLabelName = t.getText();
|
||||
boolean needList = freq.count(refLabelName)>1;
|
||||
List<Decl> d = getDeclForAltElement(t, refLabelName, needList);
|
||||
decls.addAll(d);
|
||||
}
|
||||
return decls;
|
||||
}
|
||||
|
||||
public List<Decl> getDeclForAltElement(GrammarAST t, String refLabelName, boolean needList) {
|
||||
List<Decl> decls = new ArrayList<Decl>();
|
||||
if ( t.getType()==RULE_REF ) {
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
package org.antlr.v4.codegen.model;
|
||||
|
||||
import org.antlr.v4.codegen.OutputModelFactory;
|
||||
import org.antlr.v4.runtime.misc.Triple;
|
||||
import org.antlr.v4.runtime.misc.Pair;
|
||||
import org.antlr.v4.tool.Grammar;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
import org.antlr.v4.tool.ast.ActionAST;
|
||||
|
@ -38,6 +38,7 @@ import org.antlr.v4.tool.ast.AltAST;
|
|||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class VisitorFile extends OutputFile {
|
||||
|
@ -54,10 +55,10 @@ public class VisitorFile extends OutputFile {
|
|||
parserName = g.getRecognizerName();
|
||||
grammarName = g.name;
|
||||
for (Rule r : g.rules.values()) {
|
||||
List<Triple<Integer,AltAST,String>> labels = r.getAltLabels();
|
||||
Map<String, List<Pair<Integer, AltAST>>> labels = r.getAltLabels();
|
||||
if ( labels!=null ) {
|
||||
for (Triple<Integer,AltAST,String> pair : labels) {
|
||||
visitorNames.add(pair.c);
|
||||
for (Map.Entry<String, List<Pair<Integer, AltAST>>> pair : labels.entrySet()) {
|
||||
visitorNames.add(pair.getKey());
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -33,13 +33,14 @@ package org.antlr.v4.tool;
|
|||
import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
|
||||
import org.antlr.v4.misc.OrderedHashMap;
|
||||
import org.antlr.v4.runtime.misc.Pair;
|
||||
import org.antlr.v4.runtime.misc.Triple;
|
||||
import org.antlr.v4.tool.ast.AltAST;
|
||||
import org.antlr.v4.tool.ast.GrammarAST;
|
||||
import org.antlr.v4.tool.ast.RuleAST;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class LeftRecursiveRule extends Rule {
|
||||
public List<LeftRecursiveRuleAltInfo> recPrimaryAlts;
|
||||
|
@ -84,16 +85,20 @@ public class LeftRecursiveRule extends Rule {
|
|||
|
||||
/** Get -> labels from those alts we deleted for left-recursive rules. */
|
||||
@Override
|
||||
public List<Triple<Integer,AltAST,String>> getAltLabels() {
|
||||
List<Triple<Integer,AltAST,String>> labels = new ArrayList<Triple<Integer,AltAST,String>>();
|
||||
List<Triple<Integer,AltAST,String>> normalAltLabels = super.getAltLabels();
|
||||
if ( normalAltLabels!=null ) labels.addAll(normalAltLabels);
|
||||
public Map<String, List<Pair<Integer, AltAST>>> getAltLabels() {
|
||||
Map<String, List<Pair<Integer, AltAST>>> labels = new HashMap<String, List<Pair<Integer, AltAST>>>();
|
||||
Map<String, List<Pair<Integer, AltAST>>> normalAltLabels = super.getAltLabels();
|
||||
if ( normalAltLabels!=null ) labels.putAll(normalAltLabels);
|
||||
if ( recPrimaryAlts!=null ) {
|
||||
for (LeftRecursiveRuleAltInfo altInfo : recPrimaryAlts) {
|
||||
if (altInfo.altLabel != null) {
|
||||
labels.add(new Triple<Integer, AltAST, String>(altInfo.altNum,
|
||||
altInfo.originalAltAST,
|
||||
altInfo.altLabel));
|
||||
List<Pair<Integer, AltAST>> pairs = labels.get(altInfo.altLabel);
|
||||
if (pairs == null) {
|
||||
pairs = new ArrayList<Pair<Integer, AltAST>>();
|
||||
labels.put(altInfo.altLabel, pairs);
|
||||
}
|
||||
|
||||
pairs.add(new Pair<Integer, AltAST>(altInfo.altNum, altInfo.originalAltAST));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,9 +106,13 @@ public class LeftRecursiveRule extends Rule {
|
|||
for (int i = 0; i < recOpAlts.size(); i++) {
|
||||
LeftRecursiveRuleAltInfo altInfo = recOpAlts.getElement(i);
|
||||
if ( altInfo.altLabel!=null ) {
|
||||
labels.add(new Triple<Integer,AltAST,String>(altInfo.altNum,
|
||||
altInfo.originalAltAST,
|
||||
altInfo.altLabel));
|
||||
List<Pair<Integer, AltAST>> pairs = labels.get(altInfo.altLabel);
|
||||
if (pairs == null) {
|
||||
pairs = new ArrayList<Pair<Integer, AltAST>>();
|
||||
labels.put(altInfo.altLabel, pairs);
|
||||
}
|
||||
|
||||
pairs.add(new Pair<Integer, AltAST>(altInfo.altNum, altInfo.originalAltAST));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
package org.antlr.v4.tool;
|
||||
|
||||
import org.antlr.v4.runtime.misc.Triple;
|
||||
import org.antlr.v4.runtime.misc.Pair;
|
||||
import org.antlr.v4.tool.ast.ActionAST;
|
||||
import org.antlr.v4.tool.ast.AltAST;
|
||||
import org.antlr.v4.tool.ast.GrammarAST;
|
||||
|
@ -205,13 +205,24 @@ public class Rule implements AttributeResolver {
|
|||
return numberOfAlts;
|
||||
}
|
||||
|
||||
/** Get -> labels. */
|
||||
public List<Triple<Integer,AltAST,String>> getAltLabels() {
|
||||
List<Triple<Integer,AltAST,String>> labels = new ArrayList<Triple<Integer,AltAST,String>>();
|
||||
/**
|
||||
* Get {@code #} labels. The keys of the map are the labels applied to outer
|
||||
* alternatives of a lexer rule, and the values are collections of pairs
|
||||
* (alternative number and {@link AltAST}) identifying the alternatives with
|
||||
* this label. Unlabeled alternatives are not included in the result.
|
||||
*/
|
||||
public Map<String, List<Pair<Integer, AltAST>>> getAltLabels() {
|
||||
Map<String, List<Pair<Integer, AltAST>>> labels = new HashMap<String, List<Pair<Integer, AltAST>>>();
|
||||
for (int i=1; i<=numberOfAlts; i++) {
|
||||
GrammarAST altLabel = alt[i].ast.altLabel;
|
||||
if ( altLabel!=null ) {
|
||||
labels.add(new Triple<Integer,AltAST,String>(i,alt[i].ast,altLabel.getText()));
|
||||
List<Pair<Integer, AltAST>> list = labels.get(altLabel.getText());
|
||||
if (list == null) {
|
||||
list = new ArrayList<Pair<Integer, AltAST>>();
|
||||
labels.put(altLabel.getText(), list);
|
||||
}
|
||||
|
||||
list.add(new Pair<Integer, AltAST>(i, alt[i].ast));
|
||||
}
|
||||
}
|
||||
if ( labels.isEmpty() ) return null;
|
||||
|
|
|
@ -339,6 +339,41 @@ public class TestLeftRecursion extends BaseTest {
|
|||
runTests(grammar, tests, "s");
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a regression test for antlr/antlr4#433 "Not all context accessor
|
||||
* methods are generated when an alternative rule label is used for multiple
|
||||
* alternatives".
|
||||
* https://github.com/antlr/antlr4/issues/433
|
||||
*/
|
||||
@Test public void testMultipleAlternativesWithCommonLabel() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
"s : e {System.out.println($e.v);} ;\n" +
|
||||
"\n" +
|
||||
"e returns [int v]\n" +
|
||||
" : e '*' e {$v = ((BinaryContext)$ctx).e(0).v * ((BinaryContext)$ctx).e(1).v;} # binary\n" +
|
||||
" | e '+' e {$v = ((BinaryContext)$ctx).e(0).v + ((BinaryContext)$ctx).e(1).v;} # binary\n" +
|
||||
" | INT {$v = $INT.int;} # anInt\n" +
|
||||
" | '(' e ')' {$v = $e.v;} # parens\n" +
|
||||
" | left=e INC {assert(((UnaryContext)$ctx).INC() != null); $v = $left.v + 1;} # unary\n" +
|
||||
" | left=e DEC {assert(((UnaryContext)$ctx).DEC() != null); $v = $left.v - 1;} # unary\n" +
|
||||
" | ID {$v = 3;} # anID\n" +
|
||||
" ; \n" +
|
||||
"\n" +
|
||||
"ID : 'a'..'z'+ ;\n" +
|
||||
"INT : '0'..'9'+ ;\n" +
|
||||
"INC : '++' ;\n" +
|
||||
"DEC : '--' ;\n" +
|
||||
"WS : (' '|'\\n') -> skip ;\n";
|
||||
String[] tests = {
|
||||
"4", "4",
|
||||
"1+2", "3",
|
||||
"1+2*3", "7",
|
||||
"i++*3", "12",
|
||||
};
|
||||
runTests(grammar, tests, "s");
|
||||
}
|
||||
|
||||
@Test public void testPrefixOpWithActionAndLabel() throws Exception {
|
||||
String grammar =
|
||||
"grammar T;\n" +
|
||||
|
|
Loading…
Reference in New Issue