44 import com.sun.source.util.TreeBuilder; |
48 import com.sun.source.util.TreeBuilder; |
45 import com.sun.source.util.TreeBuilder.*; |
49 import com.sun.source.util.TreeBuilder.*; |
46 import com.sun.source.util.Trees; |
50 import com.sun.source.util.Trees; |
47 import com.sun.source.util.TreeScanner; |
51 import com.sun.source.util.TreeScanner; |
48 |
52 |
|
53 import javax.tools.StandardLocation; |
|
54 |
|
55 import com.sun.source.tree.ClassTree; |
|
56 import com.sun.source.tree.IdentifierTree; |
|
57 import com.sun.source.tree.MemberReferenceTree; |
|
58 import com.sun.source.tree.MemberSelectTree; |
|
59 import com.sun.source.tree.MethodTree; |
|
60 import com.sun.source.tree.VariableTree; |
|
61 import toolbox.ToolBox.MemoryFileManager; |
|
62 |
49 public class ASTBuilder { |
63 public class ASTBuilder { |
50 |
64 |
51 public static void main(String[] args) throws Exception { |
65 public static void main(String[] args) throws Exception { |
52 runTest("class Test {" + |
66 runTest("class Test {" + |
53 " int x;" + |
67 " int x;" + |
54 "}", |
68 "}", |
55 U -> U._class("Test", C -> C.field("x", Type::_int))); |
69 U -> U._class("Test", C -> C.field("x", Type::_int))); |
|
70 runTest("class Test {" + |
|
71 " int x1 = 2;" + |
|
72 " int x2 = 2 + x1;" + |
|
73 "}"); |
56 } |
74 } |
57 |
75 |
58 private static void runTest(String expectedCode, Consumer<CompilationUnit> actualBuilder) throws Exception { |
76 private static void runTest(String expectedCode, Consumer<CompilationUnit> actualBuilder) throws Exception { |
59 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); |
77 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); |
60 assert tool != null; |
78 assert tool != null; |
61 |
79 |
62 JavacTask expecteTask = (JavacTask) tool.getTask(null, null, null, |
80 JavacTask expectedTask = (JavacTask) tool.getTask(null, null, null, |
63 null, null, Arrays.asList(new MyFileObject(expectedCode))); |
81 null, null, Arrays.asList(new MyFileObject(expectedCode))); |
64 String expectedDump = dumpTree(expecteTask.parse().iterator().next()); |
82 String expectedDump = dumpTree(expectedTask.parse().iterator().next()); |
65 |
83 |
66 JavacTask ct = (JavacTask) tool.getTask(null, null, null, |
84 JavacTask ct = (JavacTask) tool.getTask(null, null, null, |
67 null, null, Arrays.asList(new MyFileObject(""))); |
85 null, null, Arrays.asList(new MyFileObject(""))); |
68 ct.parse(); //init javac |
86 ct.parse(); //init javac |
69 Trees t = Trees.instance(ct); |
87 Trees t = Trees.instance(ct); |
74 |
92 |
75 String actualDump = dumpTree(cut); |
93 String actualDump = dumpTree(cut); |
76 |
94 |
77 if (!actualDump.equals(expectedDump)) { |
95 if (!actualDump.equals(expectedDump)) { |
78 throw new AssertionError("Expected and actual dump differ. Expected: " + expectedDump + "; actual: " + actualDump); |
96 throw new AssertionError("Expected and actual dump differ. Expected: " + expectedDump + "; actual: " + actualDump); |
|
97 } |
|
98 } |
|
99 |
|
100 private static void runTest(String expectedCode) throws Exception { |
|
101 final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); |
|
102 assert tool != null; |
|
103 |
|
104 JavacTask expectedTask = (JavacTask) tool.getTask(null, null, null, |
|
105 null, null, Arrays.asList(new MyFileObject(expectedCode))); |
|
106 CompilationUnitTree expectedCUT = expectedTask.parse().iterator().next(); |
|
107 String builderCode = CodeBuilder.buildCodeToGenerate(expectedCUT, "builder"); |
|
108 System.err.println("builderCode:"); |
|
109 System.err.println(builderCode); |
|
110 String expectedCodeGen = "import com.sun.source.tree.*; import com.sun.source.util.*; public class CodeGen { public static CompilationUnitTree build(TreeBuilder builder) { return " + builderCode + "; } }"; |
|
111 String expectedDump = dumpTree(expectedCUT); |
|
112 |
|
113 try (MemoryFileManager mfm = new MemoryFileManager(tool.getStandardFileManager(null, null, null))) { |
|
114 Boolean res = tool.getTask(null, mfm, null, |
|
115 null, null, Arrays.asList(new MyFileObject(expectedCodeGen))) |
|
116 .call(); |
|
117 if (!res) { |
|
118 throw new IllegalStateException("Could not compile the generated code!"); |
|
119 } |
|
120 |
|
121 ClassLoader codeCL = new ClassLoader(ASTBuilder.class.getClassLoader()) { |
|
122 @Override |
|
123 protected java.lang.Class<?> findClass(String name) throws ClassNotFoundException { |
|
124 byte[] bytecode = mfm.getFileBytes(StandardLocation.CLASS_OUTPUT, name); |
|
125 if (bytecode != null) { |
|
126 return defineClass(name, bytecode, 0, bytecode.length); |
|
127 } |
|
128 return super.findClass(name); |
|
129 } |
|
130 }; |
|
131 |
|
132 JavacTask ct = (JavacTask) tool.getTask(null, null, null, |
|
133 null, null, Arrays.asList(new MyFileObject(""))); |
|
134 ct.parse(); //init javac |
|
135 Trees t = Trees.instance(ct); |
|
136 |
|
137 TreeBuilder builder = t.getTreeBuilder(); |
|
138 |
|
139 java.lang.Class<?> codeGen = codeCL.loadClass("CodeGen"); |
|
140 CompilationUnitTree cut = (CompilationUnitTree) codeGen.getDeclaredMethod("build", TreeBuilder.class).invoke(null, builder); |
|
141 String actualDump = dumpTree(cut); |
|
142 |
|
143 if (!actualDump.equals(expectedDump)) { |
|
144 throw new AssertionError("Expected and actual dump differ. Expected: " + expectedDump + "; actual: " + actualDump); |
|
145 } |
79 } |
146 } |
80 } |
147 } |
81 |
148 |
82 static String dumpTree(Tree t) { |
149 static String dumpTree(Tree t) { |
83 StringBuilder result = new StringBuilder(); |
150 StringBuilder result = new StringBuilder(); |
108 result.append("("); |
175 result.append("("); |
109 super.scan(nodes, p); |
176 super.scan(nodes, p); |
110 result.append(")"); |
177 result.append(")"); |
111 return null; |
178 return null; |
112 } |
179 } |
|
180 @Override |
|
181 public Void visitIdentifier(IdentifierTree node, Void p) { |
|
182 result.append(node.getName()); |
|
183 return super.visitIdentifier(node, p); |
|
184 } |
|
185 @Override |
|
186 public Void visitMemberSelect(MemberSelectTree node, Void p) { |
|
187 result.append(node.getIdentifier()); |
|
188 return super.visitMemberSelect(node, p); |
|
189 } |
|
190 @Override |
|
191 public Void visitMemberReference(MemberReferenceTree node, Void p) { |
|
192 result.append(node.getName()); |
|
193 return super.visitMemberReference(node, p); |
|
194 } |
|
195 @Override |
|
196 public Void visitClass(ClassTree node, Void p) { |
|
197 result.append(node.getSimpleName()); |
|
198 return super.visitClass(node, p); |
|
199 } |
|
200 @Override |
|
201 public Void visitMethod(MethodTree node, Void p) { |
|
202 result.append(node.getName()); |
|
203 return super.visitMethod(node, p); |
|
204 } |
|
205 @Override |
|
206 public Void visitVariable(VariableTree node, Void p) { |
|
207 result.append(node.getName()); |
|
208 return super.visitVariable(node, p); |
|
209 } |
113 }.scan(t, null); |
210 }.scan(t, null); |
114 return result.toString(); |
211 return result.toString(); |
115 } |
212 } |
116 |
213 |
117 static class MyFileObject extends SimpleJavaFileObject { |
214 static class MyFileObject extends SimpleJavaFileObject { |