got it generating getters, labels correctly. now to impl getters

This commit is contained in:
Terence Parr 2012-02-14 13:58:48 -08:00
parent 6c2beb530d
commit a6786743d4
14 changed files with 266 additions and 79 deletions

View File

@ -485,15 +485,20 @@ NonLocalAttrRef(s) ::= "((<s.ruleName>Context)getInvokingContext(<s.ruleIndex>
SetNonLocalAttr(s, rhsChunks) ::=
"((<s.ruleName>Context)getInvokingContext(<s.ruleIndex>)).<s.name> = <rhsChunks>;"
AddToLabelList(a) ::= "_localctx.<a.listName>.add(<labelref(a.label)>);"
AddToLabelList(a) ::= "<ctx(a.label)>.<a.listName>.add(<labelref(a.label)>);"
TokenDecl(t) ::= "Token <t.name>"
TokenDecl(t) ::= "public Token <t.name>;"
TokenTypeDecl(t) ::= "int <t.name>;"
TokenListDecl(t) ::= "List\<Token> <t.name> = new ArrayList\<Token>()"
RuleContextDecl(r) ::= "<r.ctxName> <r.name>"
RuleContextListDecl(rdecl) ::= "List\<<rdecl.ctxName>> <rdecl.name> = new ArrayList\<<rdecl.ctxName>>()"
TokenListDecl(t) ::= "public List\<Token> <t.name> = new ArrayList\<Token>();"
RuleContextDecl(r) ::= "public <r.ctxName> <r.name>;"
RuleContextListDecl(rdecl) ::= "public List\<<rdecl.ctxName>> <rdecl.name> = new ArrayList\<<rdecl.ctxName>>();"
ContextGetterDecl(g) ::= "public <g.decl> get<t.name>() { }"
ContextTokenGetterDecl(t) ::= "public Token <t.name>() { return null; }"
ContextTokenListGetterDecl(t) ::= "public List\<Token> <t.name>() { return null; }"
ContextTokenListIndexedGetterDecl(t) ::= "public Token <t.name>(int i) { return null; }"
ContextRuleGetterDecl(r) ::= "public <r.ctxName> <r.name>() { return null; }"
ContextRuleListGetterDecl(r) ::= "public List\<<r.ctxName>> <r.name>() { return null; }"
ContextRuleListIndexedGetterDecl(r) ::= "public <r.ctxName> <r.name>(int i) { return null; }"
LexerRuleContext() ::= "RuleContext"
@ -502,18 +507,19 @@ LexerRuleContext() ::= "RuleContext"
*/
RuleContextNameSuffix() ::= "Context"
ImplicitTokenLabel(tokenName) ::= "_<tokenName>"
ImplicitRuleLabel(ruleName) ::= "_<ruleName>"
ImplicitTokenLabel(tokenName) ::= "<tokenName>"
ImplicitRuleLabel(ruleName) ::= "<ruleName>"
ImplicitSetLabel(id) ::= "_tset<id>"
ListLabelName(label) ::= "<label>"
CaptureNextToken(d) ::= "<d.varName> = _input.LT(1);"
CaptureNextTokenType(d) ::= "<d.varName> = _input.LA(1);"
StructDecl(s,attrs,visitorDispatchMethods,interfaces,extensionMembers,
StructDecl(s,attrs,getters,visitorDispatchMethods,interfaces,extensionMembers,
superClass={ParserRuleContext\<<InputSymbolType()>>}) ::= <<
public static class <s.name> extends <superClass><if(interfaces)> implements <interfaces; separator=", "><endif> {
<attrs:{a | public <a>;}; separator="\n">
<attrs:{a | <a>}; separator="\n">
<getters:{g | <g>}; separator="\n">
<if(s.ctorAttrs)>public <s.name>(ParserRuleContext\<<InputSymbolType()>\> parent, int state) { super(parent, state); }<endif>
public <s.name>(ParserRuleContext\<<InputSymbolType()>\> parent, int state<s.ctorAttrs:{a | , <a>}>) {
super(parent, state);
@ -531,9 +537,10 @@ public static class <s.name> extends <superClass><if(interfaces)> implements <in
}
>>
AltLabelStructDecl(s,attrs,visitorDispatchMethods) ::= <<
AltLabelStructDecl(s,attrs,getters,visitorDispatchMethods) ::= <<
public static class <s.name> extends <currentRule.name>Context {
<attrs:{a | public <a.decl> get<a.name>() {\}}; separator="\n">
<attrs:{a | <a>}; separator="\n">
<getters:{g | <g>}; separator="\n">
public <s.name>(<currentRule.name>Context ctx) { copyFrom(ctx); }
<visitorDispatchMethods; separator="\n">
}
@ -546,7 +553,7 @@ public void <if(method.isEnter)>enter<else>exit<endif>Rule(ParseTreeListener\<<I
}
>>
AttributeDecl(d) ::= "<d.decl>"
AttributeDecl(d) ::= "public <d.decl>;"
/** If we don't know location of label def x, use this template */
labelref(x) ::= "<if(!x.isLocal)>((<x.ctx.name>)_localctx).<endif><x.name>"

View File

@ -203,13 +203,13 @@ public class LeftRecursiveRuleTransformer {
LeftRecursiveRuleAltInfo altInfo = r.recPrimaryAlts.get(i);
altInfo.altAST = (AltAST)primaryBlk.getChild(i);
altInfo.altAST.leftRecursiveAltInfo = altInfo;
System.out.println(altInfo.altAST.toStringTree());
// System.out.println(altInfo.altAST.toStringTree());
}
for (int i = 0; i < r.recOpAlts.size(); i++) {
LeftRecursiveRuleAltInfo altInfo = r.recOpAlts.getElement(i);
altInfo.altAST = (AltAST)opsBlk.getChild(i);
altInfo.altAST.leftRecursiveAltInfo = altInfo;
System.out.println(altInfo.altAST.toStringTree());
// System.out.println(altInfo.altAST.toStringTree());
}
}

View File

@ -31,12 +31,21 @@ package org.antlr.v4.codegen;
import org.antlr.v4.analysis.AnalysisPipeline;
import org.antlr.v4.codegen.model.*;
import org.antlr.v4.codegen.model.decl.*;
import org.antlr.v4.codegen.model.decl.Decl;
import org.antlr.v4.codegen.model.decl.RuleContextDecl;
import org.antlr.v4.codegen.model.decl.TokenDecl;
import org.antlr.v4.codegen.model.decl.TokenListDecl;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.atn.DecisionState;
import org.antlr.v4.runtime.atn.PlusBlockStartState;
import org.antlr.v4.runtime.atn.StarLoopEntryState;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.*;
import org.antlr.v4.tool.Alternative;
import org.antlr.v4.tool.LeftRecursiveRule;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.BlockAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.TerminalAST;
import java.util.List;
@ -83,7 +92,7 @@ public class ParserFactory extends DefaultOutputModelFactory {
InvokeRule invokeOp = new InvokeRule(this, ID, label);
// If no manual label and action refs as token/rule not label, we need to define implicit label
if ( controller.needsImplicitLabel(ID, invokeOp) ) defineImplicitLabel(ID, invokeOp);
AddToLabelList listLabelOp = getListLabelIfPresent(invokeOp, label);
AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(invokeOp, label);
return list(invokeOp, listLabelOp);
}
@ -91,22 +100,29 @@ public class ParserFactory extends DefaultOutputModelFactory {
LabeledOp matchOp = new MatchToken(this, (TerminalAST) ID);
if ( labelAST!=null ) {
String label = labelAST.getText();
RuleFunction rf = getCurrentRuleFunction();
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
// add Token _X and List<Token> X decls
defineImplicitLabel(ID, matchOp); // adds _X
TokenListDecl l = getTokenListLabelDecl(label);
getCurrentRuleFunction().addContextDecl(ID.getAltLabel(), l);
rf.addContextDecl(ID.getAltLabel(), l);
}
else {
Decl d = getTokenLabelDecl(label);
((MatchToken) matchOp).labels.add(d);
rf.addContextDecl(ID.getAltLabel(), d);
}
// String label = labelAST.getText();
Decl d = getTokenLabelDecl(label);
((MatchToken)matchOp).labels.add(d);
getCurrentRuleFunction().addContextDecl(ID.getAltLabel(), d);
if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
TokenListDecl l = getTokenListLabelDecl(label);
getCurrentRuleFunction().addContextDecl(ID.getAltLabel(), l);
}
// Decl d = getTokenLabelDecl(label);
// ((MatchToken)matchOp).labels.add(d);
// getCurrentRuleFunction().addContextDecl(ID.getAltLabel(), d);
// if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
// TokenListDecl l = getTokenListLabelDecl(label);
// getCurrentRuleFunction().addContextDecl(ID.getAltLabel(), l);
// }
}
if ( controller.needsImplicitLabel(ID, matchOp) ) defineImplicitLabel(ID, matchOp);
AddToLabelList listLabelOp = getListLabelIfPresent(matchOp, labelAST);
AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(matchOp, labelAST);
return list(matchOp, listLabelOp);
}
@ -134,7 +150,7 @@ public class ParserFactory extends DefaultOutputModelFactory {
}
}
if ( controller.needsImplicitLabel(setAST, matchOp) ) defineImplicitLabel(setAST, matchOp);
AddToLabelList listLabelOp = getListLabelIfPresent(matchOp, labelAST);
AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(matchOp, labelAST);
return list(matchOp, listLabelOp);
}
@ -153,7 +169,7 @@ public class ParserFactory extends DefaultOutputModelFactory {
}
}
if ( controller.needsImplicitLabel(ast, wild) ) defineImplicitLabel(ast, wild);
AddToLabelList listLabelOp = getListLabelIfPresent(wild, labelAST);
AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(wild, labelAST);
return list(wild, listLabelOp);
}
@ -289,7 +305,7 @@ public class ParserFactory extends DefaultOutputModelFactory {
getCurrentRuleFunction().addContextDecl(ast.getAltLabel(), d);
}
public AddToLabelList getListLabelIfPresent(LabeledOp op, GrammarAST label) {
public AddToLabelList getAddToListOpIfListLabelPresent(LabeledOp op, GrammarAST label) {
AddToLabelList labelOp = null;
if ( label!=null && label.parent.getType()==ANTLRParser.PLUS_ASSIGN ) {
String listLabel = gen.target.getListLabel(label.getText());

View File

@ -88,11 +88,9 @@ public class RuleFunction extends OutputModelObject {
if ( !factory.getGrammar().tool.no_auto_element_labels ) {
List<Alternative> altsNoLabels = r.getUnlabeledAlts();
if ( altsNoLabels!=null ) {
for (Alternative alt : altsNoLabels) {
List<Decl> decls = getLabelsForAltElements(alt.ast);
Set<Decl> decls = getDeclsForAllElements(altsNoLabels);
// we know to put in rule ctx, so do it directly
for (Decl d : decls) ruleCtx.addDecl(d);
}
for (Decl d : decls) ruleCtx.addDecl(d);
}
}
@ -107,7 +105,7 @@ public class RuleFunction extends OutputModelObject {
altToContext[altNum] = new AltLabelStructDecl(factory, r, altNum, label);
altLabelCtxs.put(label, altToContext[altNum]);
if ( !factory.getGrammar().tool.no_auto_element_labels ) {
List<Decl> decls = getLabelsForAltElements(altAST);
Set<Decl> decls = getDeclsForAltElements(altAST);
// we know which ctx to put in, so do it directly
for (Decl d : decls) altToContext[altNum].addDecl(d);
}
@ -142,45 +140,86 @@ public class RuleFunction extends OutputModelObject {
}
}
/** for all alts, find which ref X or r in way which needs List
Must see across alts. If any alt needs X or r as list, then
define as list.
*/
public Set<Decl> getDeclsForAllElements(List<Alternative> alts) {
Set<String> needsList = new HashSet<String>();
List<GrammarAST> allRefs = new ArrayList<GrammarAST>();
for (Alternative a :alts) {
IntervalSet reftypes = new IntervalSet(RULE_REF, TOKEN_REF);
List<GrammarAST> refs = a.ast.getNodesWithType(reftypes);
FrequencySet<String> altFreq = new FrequencySet<String>();
for (GrammarAST t : refs) {
String refLabelName = t.getText();
altFreq.add(refLabelName);
allRefs.add(t);
}
for (GrammarAST t : refs) {
String refLabelName = t.getText();
if ( altFreq.count(t.getText())>1 ) needsList.add(refLabelName);
}
}
Set<Decl> decls = new HashSet<Decl>();
for (GrammarAST t : allRefs) {
String refLabelName = t.getText();
List<Decl> d = getDeclForAltElement(t,
refLabelName,
needsList.contains(refLabelName));
decls.addAll(d);
}
return decls;
}
/** Get list of decls for token/rule refs.
* Single ref X becomes label X
* Multiple refs to X become X1, X2, ...
* Ref X in a loop then is part of List
* 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 List<Decl> getLabelsForAltElements(AltAST altAST) {
List<Decl> decls = new ArrayList<Decl>();
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 = new FrequencySet<String>();
for (GrammarAST t : refs) freq.add(t.getText());
for (GrammarAST t : refs) {
freq.add(t.getText());
}
// track which ref for X we are at so we can gen X1 if necessary
FrequencySet<String> counter = new FrequencySet<String>();
for (GrammarAST t : refs) {
boolean inLoop = t.hasAncestor(CLOSURE) || t.hasAncestor(POSITIVE_CLOSURE);
// System.out.println(altAST.toStringTree()+" "+t+" inLoop? "+inLoop);
Decl d;
String refLabelName = t.getText();
if ( !inLoop && freq.count(refLabelName)>1 ) {
counter.add(refLabelName);
refLabelName = refLabelName+counter.count(refLabelName);
}
if ( t.getType()==RULE_REF ) {
Rule rref = factory.getGrammar().getRule(t.getText());
String ctxName = factory.getGenerator().target
.getRuleFunctionContextStructName(rref);
if ( inLoop ) d = new RuleContextListDecl(factory, refLabelName, ctxName);
else d = new RuleContextDecl(factory, refLabelName, ctxName);
boolean inLoop = t.hasAncestor(CLOSURE) || t.hasAncestor(POSITIVE_CLOSURE);
boolean multipleRefs = freq.count(refLabelName)>1;
boolean needList = inLoop || multipleRefs;
// System.out.println(altAST.toStringTree()+" "+t+" inLoop? "+inLoop);
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 ) {
Rule rref = factory.getGrammar().getRule(t.getText());
String ctxName = factory.getGenerator().target
.getRuleFunctionContextStructName(rref);
if ( needList ) {
decls.add( new ContextRuleListGetterDecl(factory, refLabelName, ctxName) );
decls.add( new ContextRuleListIndexedGetterDecl(factory, refLabelName, ctxName) );
}
else {
if ( inLoop ) d = new TokenListDecl(factory, refLabelName);
else d = new TokenDecl(factory, refLabelName);
decls.add( new ContextRuleGetterDecl(factory, refLabelName, ctxName) );
}
}
else {
if ( needList ) {
decls.add( new ContextTokenListGetterDecl(factory, refLabelName) );
decls.add( new ContextTokenListIndexedGetterDecl(factory, refLabelName) );
}
else {
decls.add( new ContextTokenGetterDecl(factory, refLabelName) );
}
decls.add(d);
}
return decls;
}

View File

@ -2,9 +2,34 @@ package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
/** public Token getID() { } */
public class ContextGetterDecl extends Decl {
public ContextGetterDecl(OutputModelFactory factory, String name, String decl) {
super(factory, name, decl);
public abstract class ContextGetterDecl extends Decl {
public ContextGetterDecl(OutputModelFactory factory, String name) {
super(factory, name);
}
/** Not used for output; just used to distinguish between decl types
* to avoid dups.
*/
public String getArgType() { return ""; }; // assume no args
@Override
public int hashCode() {
return name.hashCode() + getArgType().hashCode();
}
/** Make sure that a getter does not equal a label. X() and X are ok.
* OTOH, treat X() with two diff return values as the same. Treat
* two X() with diff args as different.
*/
@Override
public boolean equals(Object obj) {
if ( obj==null ) return false;
// A() and label A are different
if ( !(obj instanceof ContextGetterDecl) ) return false;
if ( this==obj ) return true;
if ( this.hashCode() != obj.hashCode() ) return false;
return
name.equals(((Decl) obj).name) &&
getArgType().equals(((ContextGetterDecl) obj).getArgType());
}
}

View File

@ -0,0 +1,12 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
/** public XContext X() { } */
public class ContextRuleGetterDecl extends ContextGetterDecl {
public String ctxName;
public ContextRuleGetterDecl(OutputModelFactory factory, String name, String ctxName) {
super(factory, name);
this.ctxName = ctxName;
}
}

View File

@ -0,0 +1,14 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
/** public List<XContext> X() { }
* public XContext X(int i) { }
*/
public class ContextRuleListGetterDecl extends ContextGetterDecl {
public String ctxName;
public ContextRuleListGetterDecl(OutputModelFactory factory, String name, String ctxName) {
super(factory, name);
this.ctxName = ctxName;
}
}

View File

@ -0,0 +1,14 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
public class ContextRuleListIndexedGetterDecl extends ContextRuleListGetterDecl {
public ContextRuleListIndexedGetterDecl(OutputModelFactory factory, String name, String ctxName) {
super(factory, name, ctxName);
}
@Override
public String getArgType() {
return "int";
}
}

View File

@ -0,0 +1,10 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
/** public Token X() { } */
public class ContextTokenGetterDecl extends ContextGetterDecl {
public ContextTokenGetterDecl(OutputModelFactory factory, String name) {
super(factory, name);
}
}

View File

@ -0,0 +1,12 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
/** public List<Token> X() { }
* public Token X(int i) { }
*/
public class ContextTokenListGetterDecl extends ContextGetterDecl {
public ContextTokenListGetterDecl(OutputModelFactory factory, String name) {
super(factory, name);
}
}

View File

@ -0,0 +1,14 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
public class ContextTokenListIndexedGetterDecl extends ContextTokenListGetterDecl {
public ContextTokenListIndexedGetterDecl(OutputModelFactory factory, String name) {
super(factory, name);
}
@Override
public String getArgType() {
return "int";
}
}

View File

@ -54,8 +54,14 @@ public class Decl extends SrcOp {
return name.hashCode();
}
/** If same name, can't redefine, unless it's a getter */
@Override
public boolean equals(Object obj) {
return name.equals(((Decl)obj).name);
if ( obj==null ) return false;
// A() and label A are different
if ( obj instanceof ContextGetterDecl ) return false;
if ( this==obj ) return true;
if ( this.hashCode() != obj.hashCode() ) return false;
return name.equals(((Decl) obj).name);
}
}

View File

@ -30,11 +30,16 @@
package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.*;
import org.antlr.v4.codegen.model.ModelElement;
import org.antlr.v4.codegen.model.OutputModelObject;
import org.antlr.v4.codegen.model.VisitorDispatchMethod;
import org.antlr.v4.runtime.misc.OrderedHashSet;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.Attribute;
import org.antlr.v4.tool.Rule;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/** This object models the structure holding all of the parameters,
* return values, local variables, and labels associated with a rule.
@ -43,6 +48,7 @@ public class StructDecl extends Decl {
public String superClass;
public boolean provideCopyFrom;
@ModelElement public OrderedHashSet<Decl> attrs = new OrderedHashSet<Decl>();
@ModelElement public OrderedHashSet<Decl> getters = new OrderedHashSet<Decl>();
@ModelElement public Collection<Attribute> ctorAttrs;
@ModelElement public List<VisitorDispatchMethod> visitorDispatchMethods;
@ModelElement public List<OutputModelObject> interfaces;
@ -60,7 +66,11 @@ public class StructDecl extends Decl {
visitorDispatchMethods.add(new VisitorDispatchMethod(factory, r, false));
}
public void addDecl(Decl d) { attrs.add(d); d.ctx = this; }
public void addDecl(Decl d) {
d.ctx = this;
if ( d instanceof ContextGetterDecl ) getters.add(d);
else attrs.add(d);
}
public void addDecl(Attribute a) {
addDecl(new AttributeDecl(factory, a.name, a.decl));

View File

@ -29,14 +29,22 @@
package org.antlr.v4.tool.ast;
import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.v4.parse.*;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.runtime.tree.Tree;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.tool.Grammar;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
public class GrammarAST extends CommonTree {
/** For error msgs, nice to know which grammar this AST lives in */
@ -115,8 +123,8 @@ public class GrammarAST extends CommonTree {
public String getAltLabel() {
List ancestors = this.getAncestors();
if ( ancestors==null ) return null;
for (Object o : ancestors) {
GrammarAST p = (GrammarAST)o;
for (int i=ancestors.size()-1; i>=0; i--) {
GrammarAST p = (GrammarAST)ancestors.get(i);
if ( p.getType()== ANTLRParser.ALT ) {
AltAST a = (AltAST)p;
if ( a.altLabel!=null ) return a.altLabel.getText();