diff --git a/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java b/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java index 531956ede..c3bdc8634 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java +++ b/runtime/Java/src/org/antlr/v4/runtime/ParserRuleContext.java @@ -28,17 +28,11 @@ */ package org.antlr.v4.runtime; -import org.antlr.v4.runtime.atn.ATN; -import org.antlr.v4.runtime.atn.ATNState; -import org.antlr.v4.runtime.misc.NotNull; -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 org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.misc.*; +import org.antlr.v4.runtime.tree.*; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; /** A rule invocation record for parsing and tree parsing. * @@ -136,7 +130,7 @@ public class ParserRuleContext extends RuleContext { public void enterRule(ParseTreeListener listener) { } public void exitRule(ParseTreeListener listener) { } - public T dispatch(ParseTreeVisitor visitor) { visitor.visitChildren(this); return null; } + public T accept(ParseTreeVisitor visitor) { visitor.visitChildren(this); return null; } /** Does not set parent link; other add methods do */ public void addChild(TerminalNode t) { diff --git a/runtime/Java/src/org/antlr/v4/runtime/tree/ParseTreeVisitor.java b/runtime/Java/src/org/antlr/v4/runtime/tree/ParseTreeVisitor.java index 9ad8eabae..c77131a47 100644 --- a/runtime/Java/src/org/antlr/v4/runtime/tree/ParseTreeVisitor.java +++ b/runtime/Java/src/org/antlr/v4/runtime/tree/ParseTreeVisitor.java @@ -1,12 +1,11 @@ package org.antlr.v4.runtime.tree; 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. */ public class ParseTreeVisitor { public T visit(ParserRuleContext ctx) { - return ctx.dispatch(this); + return ctx.accept(this); } /** Visit all rule, nonleaf children */ @@ -15,13 +14,8 @@ public class ParseTreeVisitor { if ( c instanceof ParseTree.RuleNode) { ParseTree.RuleNode r = (ParseTree.RuleNode)c; ParserRuleContext rctx = (ParserRuleContext)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; -// } } diff --git a/tool/playground/AVisitor.java b/tool/playground/AVisitor.java index 358bc5a0f..5badbd275 100644 --- a/tool/playground/AVisitor.java +++ b/tool/playground/AVisitor.java @@ -1,10 +1,7 @@ -import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.Token; - public interface AVisitor { T visit(AParser.MultContext ctx); T visit(AParser.ParensContext ctx); T visit(AParser.sContext ctx); T visit(AParser.AddContext ctx); T visit(AParser.IntContext ctx); -} +} \ No newline at end of file diff --git a/tool/playground/TestE.java b/tool/playground/TestE.java index 02791e0c7..476cbb29f 100644 --- a/tool/playground/TestE.java +++ b/tool/playground/TestE.java @@ -3,7 +3,7 @@ import org.antlr.v4.runtime.*; public class TestE { public static void main(String[] args) throws Exception { CharStream input = new ANTLRFileStream(args[0]); - E lex = new E(input); + ELexer lex = new ELexer(input); CommonTokenStream tokens = new CommonTokenStream(lex); tokens.fill(); for (Object t : tokens.getTokens()) System.out.println(t); diff --git a/tool/playground/TestVisitor.java b/tool/playground/TestVisitor.java index 8d39973de..734e6bc6a 100644 --- a/tool/playground/TestVisitor.java +++ b/tool/playground/TestVisitor.java @@ -27,18 +27,14 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -import org.antlr.v4.runtime.ANTLRFileStream; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.tree.ParseTreeVisitor; -import org.antlr.v4.runtime.tree.ParseTreeWalker; public class TestVisitor { public static class MyVisitor extends ParseTreeVisitor implements AVisitor { @Override 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 @@ -48,18 +44,19 @@ public class TestVisitor { @Override 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)); } @Override public Integer visit(AParser.ParensContext ctx) { - return ctx.e().dispatch(this); + return ctx.e().accept(this); } @Override 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(); Integer result = visitor.visit(t); -// Integer result = t.dispatch(visitor); +// Integer result = t.accept(visitor); System.out.println("result from tree walk = " + result); } } diff --git a/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg b/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg index 32fa834b3..545a72227 100644 --- a/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg +++ b/tool/resources/org/antlr/v4/tool/templates/codegen/Java/Java.stg @@ -56,6 +56,18 @@ public class BaseListener implements Listene } >> +VisitorFile(file, header) ::= << +
+import org.antlr.v4.runtime.tree.*; +import org.antlr.v4.runtime.Token; + +public interface Visitor\ { + .Context ctx);}; separator="\n"> +} +>> + + Parser(parser, funcs, atn, sempredFuncs, superclass) ::= << >> @@ -571,10 +583,10 @@ public void enterexitRule(ParseTreeListener\<> -VisitorDispatchMethod() ::= << +VisitorDispatchMethod(method) ::= << @Override -public \ T dispatch(ParseTreeVisitor\ visitor) { - if ( listener instanceof Visitor ) return ((Visitor\)visitor).visit(this); +public \ T accept(ParseTreeVisitor\ visitor) { + if ( visitor instanceof Visitor ) return ((Visitor\)visitor).visit(this); else return null; } >> diff --git a/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java b/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java index 1c2bc481d..fd08c81c9 100644 --- a/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java +++ b/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java @@ -48,6 +48,7 @@ public class CodeGenPipeline { gen.writeRecognizer(gen.generateParser()); if ( g.tool.gen_listener) { gen.writeListener(gen.generateListener()); + gen.writeVisitor(gen.generateVisitor()); gen.writeBlankListener(gen.generateBlankListener()); } gen.writeHeaderFile(); diff --git a/tool/src/org/antlr/v4/codegen/CodeGenerator.java b/tool/src/org/antlr/v4/codegen/CodeGenerator.java index 76e824aaf..22ff0d310 100644 --- a/tool/src/org/antlr/v4/codegen/CodeGenerator.java +++ b/tool/src/org/antlr/v4/codegen/CodeGenerator.java @@ -33,16 +33,12 @@ import org.antlr.v4.Tool; import org.antlr.v4.codegen.model.OutputModelObject; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.misc.NotNull; -import org.antlr.v4.tool.ErrorType; -import org.antlr.v4.tool.Grammar; +import org.antlr.v4.tool.*; import org.stringtemplate.v4.*; -import java.io.IOException; -import java.io.Writer; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Map; +import java.io.*; +import java.lang.reflect.*; +import java.util.*; /** General controller for code gen. Can instantiate sub generator(s). */ @@ -173,6 +169,19 @@ public class CodeGenerator { 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() { OutputModelFactory factory = new ParserFactory(this); @@ -230,6 +239,10 @@ public class CodeGenerator { target.genFile(g,outputFileST, getBlankListenerFileName()); } + public void writeVisitor(ST outputFileST) { + target.genFile(g,outputFileST, getVisitorFileName()); + } + public void writeHeaderFile() { String fileName = getHeaderFileName(); if ( fileName==null ) return; @@ -309,6 +322,16 @@ public class CodeGenerator { 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 * such as BlankTListener.java, if we're using the Java target. */ diff --git a/tool/src/org/antlr/v4/codegen/OutputModelController.java b/tool/src/org/antlr/v4/codegen/OutputModelController.java index 619267da3..c68613f31 100644 --- a/tool/src/org/antlr/v4/codegen/OutputModelController.java +++ b/tool/src/org/antlr/v4/codegen/OutputModelController.java @@ -33,22 +33,12 @@ import org.antlr.runtime.tree.CommonTreeNodeStream; import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo; import org.antlr.v4.codegen.model.*; import org.antlr.v4.codegen.model.decl.CodeBlock; -import org.antlr.v4.parse.ANTLRParser; -import org.antlr.v4.parse.GrammarASTAdaptor; -import org.antlr.v4.tool.Alternative; -import org.antlr.v4.tool.Grammar; -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 org.antlr.v4.parse.*; +import org.antlr.v4.tool.*; +import org.antlr.v4.tool.ast.*; +import org.stringtemplate.v4.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; +import java.util.*; /** This receives events from SourceGenTriggers.g and asks factory to do work. * 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()); } + public OutputModelObject buildVisitorOutputModel() { + CodeGenerator gen = delegate.getGenerator(); + return new VisitorFile(delegate, gen.getVisitorFileName()); + } + public ParserFile parserFile(String fileName) { ParserFile f = delegate.parserFile(fileName); for (CodeGeneratorExtension ext : extensions) f = ext.parserFile(f); diff --git a/tool/src/org/antlr/v4/codegen/model/DispatchMethod.java b/tool/src/org/antlr/v4/codegen/model/DispatchMethod.java new file mode 100644 index 000000000..799220ab9 --- /dev/null +++ b/tool/src/org/antlr/v4/codegen/model/DispatchMethod.java @@ -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); + } +} diff --git a/tool/src/org/antlr/v4/codegen/model/ListenerDispatchMethod.java b/tool/src/org/antlr/v4/codegen/model/ListenerDispatchMethod.java index 5b241eb01..c35be77ff 100644 --- a/tool/src/org/antlr/v4/codegen/model/ListenerDispatchMethod.java +++ b/tool/src/org/antlr/v4/codegen/model/ListenerDispatchMethod.java @@ -1,20 +1,12 @@ package org.antlr.v4.codegen.model; 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 OutputModelObject { - public String listenerName = "Rule"; +public class ListenerDispatchMethod extends DispatchMethod { public boolean isEnter; - public ListenerDispatchMethod(OutputModelFactory factory, Rule r, boolean isEnter) { + public ListenerDispatchMethod(OutputModelFactory factory, boolean isEnter) { super(factory); this.isEnter = isEnter; - List> label = r.getAltLabels(); - if ( label!=null ) listenerName = label.get(0).c; } } diff --git a/tool/src/org/antlr/v4/codegen/model/VisitorDispatchMethod.java b/tool/src/org/antlr/v4/codegen/model/VisitorDispatchMethod.java index 19c954fd1..71cc671c8 100644 --- a/tool/src/org/antlr/v4/codegen/model/VisitorDispatchMethod.java +++ b/tool/src/org/antlr/v4/codegen/model/VisitorDispatchMethod.java @@ -1,20 +1,9 @@ package org.antlr.v4.codegen.model; 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 OutputModelObject { - public String listenerName = "Rule"; - public boolean isEnter; - - public VisitorDispatchMethod(OutputModelFactory factory, Rule r, boolean isEnter) { +public class VisitorDispatchMethod extends DispatchMethod { + public VisitorDispatchMethod(OutputModelFactory factory) { super(factory); - this.isEnter = isEnter; - List> label = r.getAltLabels(); - if ( label!=null ) listenerName = label.get(0).c; } } diff --git a/tool/src/org/antlr/v4/codegen/model/VisitorFile.java b/tool/src/org/antlr/v4/codegen/model/VisitorFile.java new file mode 100644 index 000000000..ee571c0ae --- /dev/null +++ b/tool/src/org/antlr/v4/codegen/model/VisitorFile.java @@ -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 visitorNames = new HashSet(); + + @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> labels = r.getAltLabels(); + if ( labels!=null ) { + for (Triple 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); + } +} diff --git a/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java index 6fe985471..b027cb1ba 100644 --- a/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java +++ b/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java @@ -30,6 +30,7 @@ package org.antlr.v4.codegen.model.decl; import org.antlr.v4.codegen.OutputModelFactory; +import org.antlr.v4.codegen.model.VisitorDispatchMethod; import org.antlr.v4.tool.Rule; /** A StructDecl to handle a -> label on alt */ @@ -46,6 +47,12 @@ public class AltLabelStructDecl extends StructDecl { .getInstanceOf("RuleContextNameSuffix").render(); } + @Override + public void addDispatchMethods(Rule r) { + super.addDispatchMethods(r); + dispatchMethods.add(new VisitorDispatchMethod(factory)); + } + @Override public int hashCode() { return name.hashCode(); diff --git a/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java index afb9cbdeb..a4ebcfa5a 100644 --- a/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java +++ b/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java @@ -30,40 +30,37 @@ package org.antlr.v4.codegen.model.decl; import org.antlr.v4.codegen.OutputModelFactory; -import org.antlr.v4.codegen.model.ModelElement; -import org.antlr.v4.codegen.model.OutputModelObject; -import org.antlr.v4.codegen.model.ListenerDispatchMethod; +import org.antlr.v4.codegen.model.*; import org.antlr.v4.runtime.misc.OrderedHashSet; -import org.antlr.v4.tool.Attribute; -import org.antlr.v4.tool.Rule; +import org.antlr.v4.tool.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; /** This object models the structure holding all of the parameters, * return values, local variables, and labels associated with a rule. */ public class StructDecl extends Decl { - public String superClass; public boolean provideCopyFrom; @ModelElement public OrderedHashSet attrs = new OrderedHashSet(); @ModelElement public OrderedHashSet getters = new OrderedHashSet(); @ModelElement public Collection ctorAttrs; - @ModelElement public List dispatchMethods; + @ModelElement public List dispatchMethods; @ModelElement public List interfaces; @ModelElement public List extensionMembers; public StructDecl(OutputModelFactory factory, Rule r) { super(factory, factory.getGenerator().target.getRuleFunctionContextStructName(r)); - addVisitorDispatchMethods(r); + addDispatchMethods(r); provideCopyFrom = r.hasAltSpecificContexts(); } - public void addVisitorDispatchMethods(Rule r) { - dispatchMethods = new ArrayList(); - dispatchMethods.add(new ListenerDispatchMethod(factory, r, true)); - dispatchMethods.add(new ListenerDispatchMethod(factory, r, false)); + public void addDispatchMethods(Rule r) { + dispatchMethods = new ArrayList(); + dispatchMethods.add(new ListenerDispatchMethod(factory, true)); + dispatchMethods.add(new ListenerDispatchMethod(factory, false)); + if ( !r.hasAltSpecificContexts() ) { + dispatchMethods.add(new VisitorDispatchMethod(factory)); + } } public void addDecl(Decl d) {