got visitors generated

This commit is contained in:
Terence Parr 2012-02-16 11:04:04 -08:00
parent baf62685ab
commit 4a374dab60
15 changed files with 142 additions and 98 deletions

View File

@ -28,17 +28,11 @@
*/ */
package org.antlr.v4.runtime; package org.antlr.v4.runtime;
import org.antlr.v4.runtime.atn.ATN; import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.atn.ATNState; import org.antlr.v4.runtime.misc.*;
import org.antlr.v4.runtime.misc.NotNull; import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.misc.Nullable;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.List;
/** A rule invocation record for parsing and tree parsing. /** A rule invocation record for parsing and tree parsing.
* *
@ -136,7 +130,7 @@ public class ParserRuleContext<Symbol> extends RuleContext {
public void enterRule(ParseTreeListener<Symbol> listener) { } public void enterRule(ParseTreeListener<Symbol> listener) { }
public void exitRule(ParseTreeListener<Symbol> listener) { } public void exitRule(ParseTreeListener<Symbol> listener) { }
public <T> T dispatch(ParseTreeVisitor<? extends T> visitor) { visitor.visitChildren(this); return null; } public <T> T accept(ParseTreeVisitor<? extends T> visitor) { visitor.visitChildren(this); return null; }
/** Does not set parent link; other add methods do */ /** Does not set parent link; other add methods do */
public void addChild(TerminalNode<Symbol> t) { public void addChild(TerminalNode<Symbol> t) {

View File

@ -1,12 +1,11 @@
package org.antlr.v4.runtime.tree; package org.antlr.v4.runtime.tree;
import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
/** T is return type of visit methods. Use T=Void for no return type. */ /** T is return type of visit methods. Use T=Void for no return type. */
public class ParseTreeVisitor<T> { public class ParseTreeVisitor<T> {
public T visit(ParserRuleContext<?> ctx) { public T visit(ParserRuleContext<?> ctx) {
return ctx.dispatch(this); return ctx.accept(this);
} }
/** Visit all rule, nonleaf children */ /** Visit all rule, nonleaf children */
@ -15,13 +14,8 @@ public class ParseTreeVisitor<T> {
if ( c instanceof ParseTree.RuleNode) { if ( c instanceof ParseTree.RuleNode) {
ParseTree.RuleNode r = (ParseTree.RuleNode)c; ParseTree.RuleNode r = (ParseTree.RuleNode)c;
ParserRuleContext<Symbol> rctx = (ParserRuleContext<Symbol>)r.getRuleContext(); ParserRuleContext<Symbol> rctx = (ParserRuleContext<Symbol>)r.getRuleContext();
rctx.dispatch(this); visit(rctx);
} }
} }
} }
// Don't need to visit tokens. each visit() method deals with it's leaf children
// public T visit(Token t) {
// return null;
// }
} }

View File

@ -1,6 +1,3 @@
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
public interface AVisitor<T> { public interface AVisitor<T> {
T visit(AParser.MultContext ctx); T visit(AParser.MultContext ctx);
T visit(AParser.ParensContext ctx); T visit(AParser.ParensContext ctx);

View File

@ -3,7 +3,7 @@ import org.antlr.v4.runtime.*;
public class TestE { public class TestE {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
CharStream input = new ANTLRFileStream(args[0]); CharStream input = new ANTLRFileStream(args[0]);
E lex = new E(input); ELexer lex = new ELexer(input);
CommonTokenStream tokens = new CommonTokenStream(lex); CommonTokenStream tokens = new CommonTokenStream(lex);
tokens.fill(); tokens.fill();
for (Object t : tokens.getTokens()) System.out.println(t); for (Object t : tokens.getTokens()) System.out.println(t);

View File

@ -27,18 +27,14 @@
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
import org.antlr.v4.runtime.ANTLRFileStream; import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTreeVisitor; import org.antlr.v4.runtime.tree.ParseTreeVisitor;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
public class TestVisitor { public class TestVisitor {
public static class MyVisitor extends ParseTreeVisitor<Integer> implements AVisitor<Integer> { public static class MyVisitor extends ParseTreeVisitor<Integer> implements AVisitor<Integer> {
@Override @Override
public Integer visit(AParser.AddContext ctx) { public Integer visit(AParser.AddContext ctx) {
return ctx.e(0).dispatch(this) + ctx.e(1).dispatch(this); return ctx.e(0).accept(this) + ctx.e(1).accept(this);
} }
@Override @Override
@ -48,18 +44,19 @@ public class TestVisitor {
@Override @Override
public Integer visit(AParser.MultContext ctx) { public Integer visit(AParser.MultContext ctx) {
// return ctx.e(0).dispatch(this) * ctx.e(1).dispatch(this); // return ctx.e(0).accept(this) * ctx.e(1).accept(this);
return visit(ctx.e(0)) * visit(ctx.e(1)); return visit(ctx.e(0)) * visit(ctx.e(1));
} }
@Override @Override
public Integer visit(AParser.ParensContext ctx) { public Integer visit(AParser.ParensContext ctx) {
return ctx.e().dispatch(this); return ctx.e().accept(this);
} }
@Override @Override
public Integer visit(AParser.sContext ctx) { public Integer visit(AParser.sContext ctx) {
return ctx.e().dispatch(this); return visit(ctx.e());
//return ctx.e().accept(this);
} }
} }
@ -73,7 +70,7 @@ public class TestVisitor {
MyVisitor visitor = new MyVisitor(); MyVisitor visitor = new MyVisitor();
Integer result = visitor.visit(t); Integer result = visitor.visit(t);
// Integer result = t.dispatch(visitor); // Integer result = t.accept(visitor);
System.out.println("result from tree walk = " + result); System.out.println("result from tree walk = " + result);
} }
} }

View File

@ -56,6 +56,18 @@ public class <file.grammarName>BaseListener implements <file.grammarName>Listene
} }
>> >>
VisitorFile(file, header) ::= <<
<header>
import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.Token;
public interface <file.grammarName>Visitor\<T> {
<file.visitorNames:{lname |
T visit(<file.parserName>.<lname>Context ctx);}; separator="\n">
}
>>
Parser(parser, funcs, atn, sempredFuncs, superclass) ::= << Parser(parser, funcs, atn, sempredFuncs, superclass) ::= <<
<Parser_(ctor="parser_ctor", ...)> <Parser_(ctor="parser_ctor", ...)>
>> >>
@ -571,10 +583,10 @@ public void <if(method.isEnter)>enter<else>exit<endif>Rule(ParseTreeListener\<<I
} }
>> >>
VisitorDispatchMethod() ::= << VisitorDispatchMethod(method) ::= <<
@Override @Override
public \<T> T dispatch(ParseTreeVisitor\<? extends T> visitor) { public \<T> T accept(ParseTreeVisitor\<? extends T> visitor) {
if ( listener instanceof <parser.grammarName>Visitor ) return ((<parser.grammarName>Visitor\<T>)visitor).visit(this); if ( visitor instanceof <parser.grammarName>Visitor ) return ((<parser.grammarName>Visitor\<T>)visitor).visit(this);
else return null; else return null;
} }
>> >>

View File

@ -48,6 +48,7 @@ public class CodeGenPipeline {
gen.writeRecognizer(gen.generateParser()); gen.writeRecognizer(gen.generateParser());
if ( g.tool.gen_listener) { if ( g.tool.gen_listener) {
gen.writeListener(gen.generateListener()); gen.writeListener(gen.generateListener());
gen.writeVisitor(gen.generateVisitor());
gen.writeBlankListener(gen.generateBlankListener()); gen.writeBlankListener(gen.generateBlankListener());
} }
gen.writeHeaderFile(); gen.writeHeaderFile();

View File

@ -33,16 +33,12 @@ import org.antlr.v4.Tool;
import org.antlr.v4.codegen.model.OutputModelObject; import org.antlr.v4.codegen.model.OutputModelObject;
import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.NotNull; import org.antlr.v4.runtime.misc.NotNull;
import org.antlr.v4.tool.ErrorType; import org.antlr.v4.tool.*;
import org.antlr.v4.tool.Grammar;
import org.stringtemplate.v4.*; import org.stringtemplate.v4.*;
import java.io.IOException; import java.io.*;
import java.io.Writer; import java.lang.reflect.*;
import java.lang.reflect.Constructor; import java.util.*;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
/** General controller for code gen. Can instantiate sub generator(s). /** General controller for code gen. Can instantiate sub generator(s).
*/ */
@ -173,6 +169,19 @@ public class CodeGenerator {
return st; return st;
} }
public ST generateVisitor() {
OutputModelFactory factory = new ParserFactory(this);
OutputModelController controller = new OutputModelController(factory);
factory.setController(controller);
OutputModelObject visitorModel = controller.buildVisitorOutputModel();
OutputModelWalker walker = new OutputModelWalker(tool, templates);
ST st = walker.walk(visitorModel);
return st;
}
public ST generateBlankListener() { public ST generateBlankListener() {
OutputModelFactory factory = new ParserFactory(this); OutputModelFactory factory = new ParserFactory(this);
@ -230,6 +239,10 @@ public class CodeGenerator {
target.genFile(g,outputFileST, getBlankListenerFileName()); target.genFile(g,outputFileST, getBlankListenerFileName());
} }
public void writeVisitor(ST outputFileST) {
target.genFile(g,outputFileST, getVisitorFileName());
}
public void writeHeaderFile() { public void writeHeaderFile() {
String fileName = getHeaderFileName(); String fileName = getHeaderFileName();
if ( fileName==null ) return; if ( fileName==null ) return;
@ -309,6 +322,16 @@ public class CodeGenerator {
return listenerName+extST.render(); return listenerName+extST.render();
} }
/** A given grammar T, return the visitor name such as
* TVisitor.java, if we're using the Java target.
*/
public String getVisitorFileName() {
assert g.name != null;
ST extST = templates.getInstanceOf("codeFileExtension");
String listenerName = g.name + "Visitor";
return listenerName+extST.render();
}
/** A given grammar T, return a blank listener implementation /** A given grammar T, return a blank listener implementation
* such as BlankTListener.java, if we're using the Java target. * such as BlankTListener.java, if we're using the Java target.
*/ */

View File

@ -33,22 +33,12 @@ import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo; import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
import org.antlr.v4.codegen.model.*; import org.antlr.v4.codegen.model.*;
import org.antlr.v4.codegen.model.decl.CodeBlock; import org.antlr.v4.codegen.model.decl.CodeBlock;
import org.antlr.v4.parse.ANTLRParser; import org.antlr.v4.parse.*;
import org.antlr.v4.parse.GrammarASTAdaptor; import org.antlr.v4.tool.*;
import org.antlr.v4.tool.Alternative; import org.antlr.v4.tool.ast.*;
import org.antlr.v4.tool.Grammar; import org.stringtemplate.v4.*;
import org.antlr.v4.tool.LeftRecursiveRule;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.tool.ast.BlockAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.PredAST;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Stack;
/** This receives events from SourceGenTriggers.g and asks factory to do work. /** This receives events from SourceGenTriggers.g and asks factory to do work.
* Then runs extensions in order on resulting SrcOps to get final list. * Then runs extensions in order on resulting SrcOps to get final list.
@ -123,6 +113,11 @@ public class OutputModelController {
return new BaseListenerFile(delegate, gen.getBlankListenerFileName()); return new BaseListenerFile(delegate, gen.getBlankListenerFileName());
} }
public OutputModelObject buildVisitorOutputModel() {
CodeGenerator gen = delegate.getGenerator();
return new VisitorFile(delegate, gen.getVisitorFileName());
}
public ParserFile parserFile(String fileName) { public ParserFile parserFile(String fileName) {
ParserFile f = delegate.parserFile(fileName); ParserFile f = delegate.parserFile(fileName);
for (CodeGeneratorExtension ext : extensions) f = ext.parserFile(f); for (CodeGeneratorExtension ext : extensions) f = ext.parserFile(f);

View File

@ -0,0 +1,9 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
public class DispatchMethod extends OutputModelObject {
public DispatchMethod(OutputModelFactory factory) {
super(factory);
}
}

View File

@ -1,20 +1,12 @@
package org.antlr.v4.codegen.model; package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory; import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.misc.Triple;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.AltAST;
import java.util.List; public class ListenerDispatchMethod extends DispatchMethod {
public class ListenerDispatchMethod extends OutputModelObject {
public String listenerName = "Rule";
public boolean isEnter; public boolean isEnter;
public ListenerDispatchMethod(OutputModelFactory factory, Rule r, boolean isEnter) { public ListenerDispatchMethod(OutputModelFactory factory, boolean isEnter) {
super(factory); super(factory);
this.isEnter = isEnter; this.isEnter = isEnter;
List<Triple<Integer,AltAST,String>> label = r.getAltLabels();
if ( label!=null ) listenerName = label.get(0).c;
} }
} }

View File

@ -1,20 +1,9 @@
package org.antlr.v4.codegen.model; package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory; import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.misc.Triple;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.AltAST;
import java.util.List; public class VisitorDispatchMethod extends DispatchMethod {
public VisitorDispatchMethod(OutputModelFactory factory) {
public class VisitorDispatchMethod extends OutputModelObject {
public String listenerName = "Rule";
public boolean isEnter;
public VisitorDispatchMethod(OutputModelFactory factory, Rule r, boolean isEnter) {
super(factory); super(factory);
this.isEnter = isEnter;
List<Triple<Integer,AltAST,String>> label = r.getAltLabels();
if ( label!=null ) listenerName = label.get(0).c;
} }
} }

View File

@ -0,0 +1,37 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.misc.Triple;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.*;
import java.util.*;
public class VisitorFile extends OutputFile {
public String grammarName;
public String parserName;
public Set<String> visitorNames = new HashSet<String>();
@ModelElement public Action header;
public VisitorFile(OutputModelFactory factory, String fileName) {
super(factory, fileName);
Grammar g = factory.getGrammar();
parserName = g.getRecognizerName();
grammarName = g.name;
for (Rule r : g.rules.values()) {
List<Triple<Integer,AltAST,String>> labels = r.getAltLabels();
if ( labels!=null ) {
for (Triple<Integer,AltAST,String> pair : labels) {
visitorNames.add(pair.c);
}
}
else {
// if labels, must label all. no need for generic rule visitor then
visitorNames.add(r.name);
}
}
ActionAST ast = g.namedActions.get("header");
if ( ast!=null ) header = new Action(factory, ast);
}
}

View File

@ -30,6 +30,7 @@
package org.antlr.v4.codegen.model.decl; package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory; import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.VisitorDispatchMethod;
import org.antlr.v4.tool.Rule; import org.antlr.v4.tool.Rule;
/** A StructDecl to handle a -> label on alt */ /** A StructDecl to handle a -> label on alt */
@ -46,6 +47,12 @@ public class AltLabelStructDecl extends StructDecl {
.getInstanceOf("RuleContextNameSuffix").render(); .getInstanceOf("RuleContextNameSuffix").render();
} }
@Override
public void addDispatchMethods(Rule r) {
super.addDispatchMethods(r);
dispatchMethods.add(new VisitorDispatchMethod(factory));
}
@Override @Override
public int hashCode() { public int hashCode() {
return name.hashCode(); return name.hashCode();

View File

@ -30,40 +30,37 @@
package org.antlr.v4.codegen.model.decl; package org.antlr.v4.codegen.model.decl;
import org.antlr.v4.codegen.OutputModelFactory; import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.codegen.model.ModelElement; import org.antlr.v4.codegen.model.*;
import org.antlr.v4.codegen.model.OutputModelObject;
import org.antlr.v4.codegen.model.ListenerDispatchMethod;
import org.antlr.v4.runtime.misc.OrderedHashSet; import org.antlr.v4.runtime.misc.OrderedHashSet;
import org.antlr.v4.tool.Attribute; import org.antlr.v4.tool.*;
import org.antlr.v4.tool.Rule;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.List;
/** This object models the structure holding all of the parameters, /** This object models the structure holding all of the parameters,
* return values, local variables, and labels associated with a rule. * return values, local variables, and labels associated with a rule.
*/ */
public class StructDecl extends Decl { public class StructDecl extends Decl {
public String superClass;
public boolean provideCopyFrom; public boolean provideCopyFrom;
@ModelElement public OrderedHashSet<Decl> attrs = new OrderedHashSet<Decl>(); @ModelElement public OrderedHashSet<Decl> attrs = new OrderedHashSet<Decl>();
@ModelElement public OrderedHashSet<Decl> getters = new OrderedHashSet<Decl>(); @ModelElement public OrderedHashSet<Decl> getters = new OrderedHashSet<Decl>();
@ModelElement public Collection<Attribute> ctorAttrs; @ModelElement public Collection<Attribute> ctorAttrs;
@ModelElement public List<ListenerDispatchMethod> dispatchMethods; @ModelElement public List<? super DispatchMethod> dispatchMethods;
@ModelElement public List<OutputModelObject> interfaces; @ModelElement public List<OutputModelObject> interfaces;
@ModelElement public List<OutputModelObject> extensionMembers; @ModelElement public List<OutputModelObject> extensionMembers;
public StructDecl(OutputModelFactory factory, Rule r) { public StructDecl(OutputModelFactory factory, Rule r) {
super(factory, factory.getGenerator().target.getRuleFunctionContextStructName(r)); super(factory, factory.getGenerator().target.getRuleFunctionContextStructName(r));
addVisitorDispatchMethods(r); addDispatchMethods(r);
provideCopyFrom = r.hasAltSpecificContexts(); provideCopyFrom = r.hasAltSpecificContexts();
} }
public void addVisitorDispatchMethods(Rule r) { public void addDispatchMethods(Rule r) {
dispatchMethods = new ArrayList<ListenerDispatchMethod>(); dispatchMethods = new ArrayList<DispatchMethod>();
dispatchMethods.add(new ListenerDispatchMethod(factory, r, true)); dispatchMethods.add(new ListenerDispatchMethod(factory, true));
dispatchMethods.add(new ListenerDispatchMethod(factory, r, false)); dispatchMethods.add(new ListenerDispatchMethod(factory, false));
if ( !r.hasAltSpecificContexts() ) {
dispatchMethods.add(new VisitorDispatchMethod(factory));
}
} }
public void addDecl(Decl d) { public void addDecl(Decl d) {