Adding ability to supply code as text instead of Trees on some places. jlahoda-tree-builder
authorjlahoda
Mon, 01 Apr 2019 14:46:17 +0200
branchjlahoda-tree-builder
changeset 57298 72d5f7163f12
parent 57297 ad0be596956b
child 57300 c79e191854e4
Adding ability to supply code as text instead of Trees on some places.
src/jdk.compiler/share/classes/com/sun/source/util/TreeBuilder.java
src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java
src/jdk.compiler/share/classes/com/sun/tools/javac/api/TreeBuilderImpl.java
test/langtools/tools/javac/api/ast/ASTBuilder.java
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeBuilder.java	Mon Apr 01 11:44:31 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeBuilder.java	Mon Apr 01 14:46:17 2019 +0200
@@ -58,7 +58,13 @@
     interface Class extends WithModifiers<Class>, WithJavadoc<Class> {
         //setters:
         Class superclass(Consumer<Type> sup);
+        default Class superclass(String sup) {
+            return superclass(t -> t.type(sup));
+        }
         Class superinterface(Consumer<Type> sup);
+        default Class superinterface(String sup) {
+            return superinterface(t -> t.type(sup));
+        }
         //type parameters?
 
         //adders:
@@ -77,6 +83,9 @@
     interface Variable extends WithModifiers<Variable>, WithJavadoc<Variable> {
         //setters:
         Variable init(Consumer<Expression> init);
+        default Variable init(String init) {
+            return init(E -> E.expression(init));
+        }
     }
 
     interface Parameter extends WithModifiers<Parameter> {
@@ -93,7 +102,14 @@
         //TODO: parameter overload type+name?
         Method parameter(Consumer<Type> type, Consumer<Parameter> parameter);
 
-        Method body(Consumer<Block> statements);
+        Method body(Consumer<Block> body);
+
+        /**
+         * Must include the '{' '}'.
+         * @param body
+         * @return 
+         */
+        Method body(String body);
         //throws, default value
     }
 
@@ -119,6 +135,7 @@
         void _int();
         void _float();
         void _void();
+        void type(String type);
     }
 
     interface TypeArguments { //???
@@ -149,6 +166,7 @@
         void select(Consumer<Expression> selected, String name);
         void ident(String qnames);
         void literal(Object value);
+        void expression(String expression);
     }
 
     interface StatementBase<S> {
@@ -158,6 +176,7 @@
         S _return(Consumer<Expression> expr);
         S expr(Consumer<Expression> expr);
         S skip();
+        S statement(String statement);
     }
 
     interface Statement extends StatementBase<Void> {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Mon Apr 01 11:44:31 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Mon Apr 01 14:46:17 2019 +0200
@@ -182,6 +182,7 @@
     private JavaFileManager fileManager;
     private ParserFactory parser;
     private Symtab syms;
+    private com.sun.tools.javac.main.JavaCompiler compiler;
 
     private final Map<Type, Type> extraType2OriginalMap = new WeakHashMap<>();
 
@@ -230,6 +231,7 @@
         docTreeMaker = DocTreeMaker.instance(context);
         parser = ParserFactory.instance(context);
         syms = Symtab.instance(context);
+        compiler = com.sun.tools.javac.main.JavaCompiler.instance(context);
         fileManager = context.get(JavaFileManager.class);
         JavacTask t = context.get(JavacTask.class);
         if (t instanceof JavacTaskImpl)
@@ -1245,6 +1247,6 @@
     }
 
     public TreeBuilder getTreeBuilder() {
-        return new TreeBuilderImpl(treeMaker, names);
+        return new TreeBuilderImpl(compiler, parser, treeMaker, names);
     }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/TreeBuilderImpl.java	Mon Apr 01 11:44:31 2019 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/TreeBuilderImpl.java	Mon Apr 01 14:46:17 2019 +0200
@@ -23,7 +23,11 @@
  * questions.
  */package com.sun.tools.javac.api;
 
+import java.nio.CharBuffer;
 import java.util.function.Consumer;
+import java.util.function.Function;
+
+import javax.tools.JavaFileObject;
 
 import com.sun.source.doctree.DocTree;
 import com.sun.source.tree.CompilationUnitTree;
@@ -34,13 +38,18 @@
 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
 import com.sun.tools.javac.tree.JCTree.JCExpression;
 import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
-import com.sun.tools.javac.tree.JCTree.JCStatement;
 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
 import com.sun.tools.javac.tree.JCTree.Tag;
 
 import com.sun.tools.javac.tree.TreeMaker;
 import com.sun.tools.javac.util.List;
-import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.main.JavaCompiler;
+import com.sun.tools.javac.parser.Parser;
+import com.sun.tools.javac.parser.ParserFactory;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.util.JCDiagnostic;
+import com.sun.tools.javac.util.Log.DiagnosticHandler;
 import com.sun.tools.javac.util.Names;
 
 /**
@@ -49,10 +58,14 @@
  */
 public class TreeBuilderImpl implements TreeBuilder {
 
+    private final JavaCompiler compiler;
+    private final ParserFactory parserFactory;
     private final TreeMaker make;
     private final Names names;
 
-    public TreeBuilderImpl(TreeMaker make, Names names) {
+    public TreeBuilderImpl(JavaCompiler compiler, ParserFactory parserFactory, TreeMaker make, Names names) {
+        this.compiler = compiler;
+        this.parserFactory = parserFactory;
         this.make = make;
         this.names = names;
     }
@@ -193,6 +206,11 @@
             throw new UnsupportedOperationException("Not supported yet.");
         }
 
+        @Override
+        public void type(String typeSpec) {
+            type = parse(typeSpec, Parser::parseType);
+        }
+
     }
 
     private final class TypeArgumentsImpl implements TypeArguments {
@@ -262,6 +280,16 @@
         }
 
         @Override
+        public Method body(String body) {
+            JCStatement parsedBody = parse(body, Parser::parseStatement);
+            if (!parsedBody.hasTag(Tag.BLOCK)) {
+                throw new IllegalArgumentException("Block not provided!");
+            }
+            result.body = (JCBlock) parsedBody;
+            return this;
+        }
+
+        @Override
         public Method modifiers(Consumer<Modifiers> modifiers) {
             throw new UnsupportedOperationException("Not supported yet.");
         }
@@ -371,6 +399,11 @@
             throw new UnsupportedOperationException("Not supported yet.");
         }
 
+        @Override
+        public S statement(String statement) {
+            return addStatement(parse(statement, Parser::parseStatement));
+        }
+
         protected abstract S addStatement(JCStatement stat);
     }
     
@@ -416,6 +449,12 @@
         public void literal(Object value) {
             expr = make.Literal(value);
         }
+
+        @Override
+        public void expression(String expression) {
+            expr = parse(expression, Parser::parseExpression);
+        }
+
     }
 
     private final class QualifiedNameImpl implements QualifiedName {
@@ -477,4 +516,31 @@
 
         return type.type;
     }
+
+    private <T extends JCTree> T parse(String toParse, Function<Parser, T> runParse) {
+        if (toParse == null || toParse.equals(""))
+            throw new IllegalArgumentException();
+        JavaFileObject prev = compiler.log.useSource(null);
+        DiagnosticHandler h = null;
+        try {
+            h = new DiagnosticHandler() {
+                {
+                    install(compiler.log);
+                }
+                @Override
+                public void report(JCDiagnostic err) {
+                    if (err.getKind() == JCDiagnostic.Kind.ERROR) {
+                        throw new IllegalArgumentException("Cannot parse input: " + err.getMessage(null));
+                    }
+                }
+            };
+            CharBuffer buf = CharBuffer.wrap((toParse+"\u0000").toCharArray(), 0, toParse.length());
+            Parser parser = parserFactory.newParser(buf, false, false, false);
+            return runParse.apply(parser);
+        } finally {
+            compiler.log.popDiagnosticHandler(h);
+            compiler.log.useSource(prev);
+        }
+    }
+
 }
--- a/test/langtools/tools/javac/api/ast/ASTBuilder.java	Mon Apr 01 11:44:31 2019 +0200
+++ b/test/langtools/tools/javac/api/ast/ASTBuilder.java	Mon Apr 01 14:46:17 2019 +0200
@@ -79,6 +79,30 @@
                 "        return 1;" +
                 "    }" +
                 "}");
+        runTest("class Test extends java.util.Map<List<String>, Numer> {" +
+                "}",
+                U -> U._class("Test", C -> C.superclass("java.util.Map<List<String>, Numer>")));
+        runTest("class Test {" +
+                "    int i = true ? 0 : 1;" +
+                "}",
+                U -> U._class("Test", C -> C.field("i", Type::_int, F -> F.init("true ? 0 : 1"))));
+        runTest("class Test {" +
+                "    int test(int param) {" +
+                "        if (param == 0) return 0;" +
+                "        else return 1;" +
+                "    }" +
+                "}",
+                U -> U._class("Test", C -> C.method("test", Type::_int, M -> M.parameter(Type::_int, P -> P.name("param")).body("{\n" +
+                "        if (param == 0) return 0;\n" +
+                "        else return 1;\n" +
+                "    }"))));
+        try {
+            runTest("broken",
+                    U -> U._class("Test", C -> C.superclass("java.util.Map<")));
+            throw new AssertionError("The exceptec exception was not thrown.");
+        } catch (IllegalArgumentException ex) {
+            //OK
+        }
     }
 
     private static void runTest(String expectedCode, Consumer<CompilationUnit> actualBuilder) throws Exception {