Merge pull request #1576 from sharwell/optional-getters
Implement support for optional getters
This commit is contained in:
commit
a17b299cd3
|
@ -21,12 +21,30 @@ import java.util.Deque;
|
|||
import java.util.Map;
|
||||
|
||||
public class ElementFrequenciesVisitor extends GrammarTreeVisitor {
|
||||
/**
|
||||
* This special value means "no set", and is used by {@link #minFrequencies}
|
||||
* to ensure that {@link #combineMin} doesn't merge an empty set (all zeros)
|
||||
* with the results of the first alternative.
|
||||
*/
|
||||
private static final FrequencySet<String> SENTINEL = new FrequencySet<String>();
|
||||
|
||||
final Deque<FrequencySet<String>> frequencies;
|
||||
private final Deque<FrequencySet<String>> minFrequencies;
|
||||
|
||||
public ElementFrequenciesVisitor(TreeNodeStream input) {
|
||||
super(input);
|
||||
frequencies = new ArrayDeque<FrequencySet<String>>();
|
||||
frequencies.push(new FrequencySet<String>());
|
||||
minFrequencies = new ArrayDeque<FrequencySet<String>>();
|
||||
minFrequencies.push(SENTINEL);
|
||||
}
|
||||
|
||||
FrequencySet<String> getMinFrequencies() {
|
||||
assert minFrequencies.size() == 1;
|
||||
assert minFrequencies.peek() != SENTINEL;
|
||||
assert SENTINEL.isEmpty();
|
||||
|
||||
return minFrequencies.peek();
|
||||
}
|
||||
|
||||
/** During code gen, we can assume tree is in good shape */
|
||||
|
@ -61,6 +79,31 @@ public class ElementFrequenciesVisitor extends GrammarTreeVisitor {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a frequency set as the union of two input sets. If an
|
||||
* element is contained in both sets, the value for the output will be
|
||||
* the minimum of the two input values.
|
||||
*
|
||||
* @param a The first set.
|
||||
* @param b The second set. If this set is {@link #SENTINEL}, it is treated
|
||||
* as though no second set were provided.
|
||||
* @return The union of the two sets, with the minimum value chosen
|
||||
* whenever both sets contain the same key.
|
||||
*/
|
||||
protected static FrequencySet<String> combineMin(FrequencySet<String> a, FrequencySet<String> b) {
|
||||
if (b == SENTINEL) {
|
||||
return a;
|
||||
}
|
||||
|
||||
assert a != SENTINEL;
|
||||
FrequencySet<String> result = combineAndClip(a, b, 1);
|
||||
for (Map.Entry<String, MutableInt> entry : result.entrySet()) {
|
||||
entry.getValue().v = Math.min(a.count(entry.getKey()), b.count(entry.getKey()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a frequency set as the union of two input sets, with the
|
||||
* values clipped to a specified maximum value. If an element is
|
||||
|
@ -97,11 +140,13 @@ public class ElementFrequenciesVisitor extends GrammarTreeVisitor {
|
|||
@Override
|
||||
public void tokenRef(TerminalAST ref) {
|
||||
frequencies.peek().add(ref.getText());
|
||||
minFrequencies.peek().add(ref.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ruleRef(GrammarAST ref, ActionAST arg) {
|
||||
frequencies.peek().add(ref.getText());
|
||||
minFrequencies.peek().add(ref.getText());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -111,21 +156,25 @@ public class ElementFrequenciesVisitor extends GrammarTreeVisitor {
|
|||
@Override
|
||||
protected void enterAlternative(AltAST tree) {
|
||||
frequencies.push(new FrequencySet<String>());
|
||||
minFrequencies.push(new FrequencySet<String>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitAlternative(AltAST tree) {
|
||||
frequencies.push(combineMax(frequencies.pop(), frequencies.pop()));
|
||||
minFrequencies.push(combineMin(minFrequencies.pop(), minFrequencies.pop()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enterElement(GrammarAST tree) {
|
||||
frequencies.push(new FrequencySet<String>());
|
||||
minFrequencies.push(new FrequencySet<String>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitElement(GrammarAST tree) {
|
||||
frequencies.push(combineAndClip(frequencies.pop(), frequencies.pop(), 2));
|
||||
minFrequencies.push(combineAndClip(minFrequencies.pop(), minFrequencies.pop(), 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,6 +184,12 @@ public class ElementFrequenciesVisitor extends GrammarTreeVisitor {
|
|||
entry.getValue().v = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (tree.getType() == CLOSURE) {
|
||||
// Everything inside a closure is optional, so the minimum
|
||||
// number of occurrences for all elements is 0.
|
||||
minFrequencies.peek().clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -144,21 +199,25 @@ public class ElementFrequenciesVisitor extends GrammarTreeVisitor {
|
|||
@Override
|
||||
protected void enterLexerAlternative(GrammarAST tree) {
|
||||
frequencies.push(new FrequencySet<String>());
|
||||
minFrequencies.push(new FrequencySet<String>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitLexerAlternative(GrammarAST tree) {
|
||||
frequencies.push(combineMax(frequencies.pop(), frequencies.pop()));
|
||||
minFrequencies.push(combineMin(minFrequencies.pop(), minFrequencies.pop()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enterLexerElement(GrammarAST tree) {
|
||||
frequencies.push(new FrequencySet<String>());
|
||||
minFrequencies.push(new FrequencySet<String>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitLexerElement(GrammarAST tree) {
|
||||
frequencies.push(combineAndClip(frequencies.pop(), frequencies.pop(), 2));
|
||||
minFrequencies.push(combineAndClip(minFrequencies.pop(), minFrequencies.pop(), 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -168,5 +227,11 @@ public class ElementFrequenciesVisitor extends GrammarTreeVisitor {
|
|||
entry.getValue().v = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (tree.getType() == CLOSURE) {
|
||||
// Everything inside a closure is optional, so the minimum
|
||||
// number of occurrences for all elements is 0.
|
||||
minFrequencies.peek().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,14 +171,20 @@ public class RuleFunction extends OutputModelObject {
|
|||
*/
|
||||
public Set<Decl> getDeclsForAllElements(List<AltAST> altASTs) {
|
||||
Set<String> needsList = new HashSet<String>();
|
||||
Set<String> optional = new HashSet<String>();
|
||||
List<GrammarAST> allRefs = new ArrayList<GrammarAST>();
|
||||
for (AltAST ast : altASTs) {
|
||||
IntervalSet reftypes = new IntervalSet(RULE_REF, TOKEN_REF);
|
||||
List<GrammarAST> refs = ast.getNodesWithType(reftypes);
|
||||
allRefs.addAll(refs);
|
||||
FrequencySet<String> altFreq = getElementFrequenciesForAlt(ast);
|
||||
Pair<FrequencySet<String>, FrequencySet<String>> minAndAltFreq = getElementFrequenciesForAlt(ast);
|
||||
FrequencySet<String> minFreq = minAndAltFreq.a;
|
||||
FrequencySet<String> altFreq = minAndAltFreq.b;
|
||||
for (GrammarAST t : refs) {
|
||||
String refLabelName = t.getText();
|
||||
if (minFreq.count(refLabelName) == 0) {
|
||||
optional.add(refLabelName);
|
||||
}
|
||||
if ( altFreq.count(refLabelName)>1 ) {
|
||||
needsList.add(refLabelName);
|
||||
}
|
||||
|
@ -189,31 +195,32 @@ public class RuleFunction extends OutputModelObject {
|
|||
String refLabelName = t.getText();
|
||||
List<Decl> d = getDeclForAltElement(t,
|
||||
refLabelName,
|
||||
needsList.contains(refLabelName));
|
||||
needsList.contains(refLabelName),
|
||||
optional.contains(refLabelName));
|
||||
decls.addAll(d);
|
||||
}
|
||||
return decls;
|
||||
}
|
||||
|
||||
/** Given list of X and r refs in alt, compute how many of each there are */
|
||||
protected FrequencySet<String> getElementFrequenciesForAlt(AltAST ast) {
|
||||
protected Pair<FrequencySet<String>, FrequencySet<String>> getElementFrequenciesForAlt(AltAST ast) {
|
||||
try {
|
||||
ElementFrequenciesVisitor visitor = new ElementFrequenciesVisitor(new CommonTreeNodeStream(new GrammarASTAdaptor(), ast));
|
||||
visitor.outerAlternative();
|
||||
if (visitor.frequencies.size() != 1) {
|
||||
factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR);
|
||||
return new FrequencySet<String>();
|
||||
return new Pair<>(new FrequencySet<String>(), new FrequencySet<String>());
|
||||
}
|
||||
|
||||
return visitor.frequencies.peek();
|
||||
return new Pair<>(visitor.getMinFrequencies(), visitor.frequencies.peek());
|
||||
}
|
||||
catch (RecognitionException ex) {
|
||||
factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, ex);
|
||||
return new FrequencySet<String>();
|
||||
return new Pair<>(new FrequencySet<String>(), new FrequencySet<String>());
|
||||
}
|
||||
}
|
||||
|
||||
public List<Decl> getDeclForAltElement(GrammarAST t, String refLabelName, boolean needList) {
|
||||
public List<Decl> getDeclForAltElement(GrammarAST t, String refLabelName, boolean needList, boolean optional) {
|
||||
List<Decl> decls = new ArrayList<Decl>();
|
||||
if ( t.getType()==RULE_REF ) {
|
||||
Rule rref = factory.getGrammar().getRule(t.getText());
|
||||
|
@ -225,7 +232,7 @@ public class RuleFunction extends OutputModelObject {
|
|||
decls.add( new ContextRuleListIndexedGetterDecl(factory, refLabelName, ctxName) );
|
||||
}
|
||||
else {
|
||||
decls.add( new ContextRuleGetterDecl(factory, refLabelName, ctxName) );
|
||||
decls.add( new ContextRuleGetterDecl(factory, refLabelName, ctxName, optional) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -235,7 +242,7 @@ public class RuleFunction extends OutputModelObject {
|
|||
decls.add( new ContextTokenListIndexedGetterDecl(factory, refLabelName) );
|
||||
}
|
||||
else {
|
||||
decls.add( new ContextTokenGetterDecl(factory, refLabelName) );
|
||||
decls.add( new ContextTokenGetterDecl(factory, refLabelName, optional) );
|
||||
}
|
||||
}
|
||||
return decls;
|
||||
|
|
|
@ -11,8 +11,11 @@ import org.antlr.v4.codegen.OutputModelFactory;
|
|||
/** {@code public XContext X() { }} */
|
||||
public class ContextRuleGetterDecl extends ContextGetterDecl {
|
||||
public String ctxName;
|
||||
public ContextRuleGetterDecl(OutputModelFactory factory, String name, String ctxName) {
|
||||
public boolean optional;
|
||||
|
||||
public ContextRuleGetterDecl(OutputModelFactory factory, String name, String ctxName, boolean optional) {
|
||||
super(factory, name);
|
||||
this.ctxName = ctxName;
|
||||
this.optional = optional;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,10 @@ import org.antlr.v4.codegen.OutputModelFactory;
|
|||
|
||||
/** {@code public Token X() { }} */
|
||||
public class ContextTokenGetterDecl extends ContextGetterDecl {
|
||||
public ContextTokenGetterDecl(OutputModelFactory factory, String name) {
|
||||
public boolean optional;
|
||||
|
||||
public ContextTokenGetterDecl(OutputModelFactory factory, String name, boolean optional) {
|
||||
super(factory, name);
|
||||
this.optional = optional;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue