Adding ability to supply code as text instead of Trees on some places.
--- 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 {