1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
|
23 | |
|
24 | |
|
25 | |
|
26 | |
package com.sun.tools.javafx.comp; |
27 | |
|
28 | |
import com.sun.javafx.api.JavafxBindStatus; |
29 | |
import com.sun.javafx.api.tree.TypeTree; |
30 | |
import com.sun.tools.javac.code.Flags; |
31 | |
import com.sun.tools.javac.code.Type; |
32 | |
import static com.sun.tools.javac.code.Flags.*; |
33 | |
import com.sun.tools.javac.tree.JCTree; |
34 | |
import com.sun.tools.javac.tree.JCTree.*; |
35 | |
import com.sun.tools.javac.util.Context; |
36 | |
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; |
37 | |
import com.sun.tools.javac.util.List; |
38 | |
import com.sun.tools.javac.util.ListBuffer; |
39 | |
import com.sun.tools.javac.util.Log; |
40 | |
import com.sun.tools.javac.util.Name; |
41 | |
import com.sun.tools.javac.util.Name.Table; |
42 | |
import com.sun.tools.javafx.code.JavafxSymtab; |
43 | |
import com.sun.tools.javafx.tree.*; |
44 | |
import static com.sun.tools.javafx.tree.JavafxTag.*; |
45 | |
import com.sun.tools.javafx.util.MsgSym; |
46 | |
|
47 | |
import java.net.URI; |
48 | |
import java.util.HashSet; |
49 | |
import java.util.Map; |
50 | |
import java.util.Set; |
51 | |
import javax.tools.FileObject; |
52 | |
|
53 | 21802 | public class JavafxModuleBuilder { |
54 | 12 | protected static final Context.Key<JavafxModuleBuilder> javafxModuleBuilderKey = |
55 | |
new Context.Key<JavafxModuleBuilder>(); |
56 | |
|
57 | |
private final JavafxDefs defs; |
58 | |
private Table names; |
59 | |
private JavafxTreeMaker make; |
60 | |
private Log log; |
61 | |
private JavafxSymtab syms; |
62 | |
private Set<Name> topLevelNamesSet; |
63 | |
private Name pseudoFile; |
64 | |
private Name pseudoDir; |
65 | |
private Name commandLineArgs; |
66 | |
|
67 | 12 | private static final boolean debugBadPositions = Boolean.getBoolean("JavafxModuleBuilder.debugBadPositions"); |
68 | |
|
69 | |
public static JavafxModuleBuilder instance(Context context) { |
70 | 399 | JavafxModuleBuilder instance = context.get(javafxModuleBuilderKey); |
71 | 399 | if (instance == null) |
72 | 399 | instance = new JavafxModuleBuilder(context); |
73 | 399 | return instance; |
74 | |
} |
75 | |
|
76 | 399 | protected JavafxModuleBuilder(Context context) { |
77 | 399 | defs = JavafxDefs.instance(context); |
78 | 399 | names = Table.instance(context); |
79 | 399 | make = (JavafxTreeMaker)JavafxTreeMaker.instance(context); |
80 | 399 | log = Log.instance(context); |
81 | 399 | syms = (JavafxSymtab)JavafxSymtab.instance(context); |
82 | 399 | pseudoFile = names.fromString("__FILE__"); |
83 | 399 | pseudoDir = names.fromString("__DIR__"); |
84 | 399 | commandLineArgs = names.fromString("__ARGS__"); |
85 | 399 | } |
86 | |
|
87 | |
public void preProcessJfxTopLevel(JCCompilationUnit module) { |
88 | 385 | Name moduleClassName = moduleName(module); |
89 | |
|
90 | 385 | if (debugBadPositions) { |
91 | 0 | checkForBadPositions(module); |
92 | |
} |
93 | |
|
94 | 385 | ListBuffer<JCTree> moduleClassDefs = new ListBuffer<JCTree>(); |
95 | 385 | ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>(); |
96 | |
|
97 | |
|
98 | 385 | final boolean[] usesFile = new boolean[1]; |
99 | 385 | final boolean[] usesDir = new boolean[1]; |
100 | 385 | final DiagnosticPosition[] diagPos = new DiagnosticPosition[1]; |
101 | 385 | new JavafxTreeScanner() { |
102 | |
@Override |
103 | |
public void visitIdent(JCIdent id) { |
104 | 10901 | super.visitIdent(id); |
105 | 10901 | if (id.name.equals(pseudoFile)) { |
106 | 2 | usesFile[0] = true; |
107 | 2 | markPosition(id); |
108 | |
} |
109 | 10901 | if (id.name.equals(pseudoDir)) { |
110 | 2 | usesDir[0] = true; |
111 | 2 | markPosition(id); |
112 | |
} |
113 | 10901 | } |
114 | |
void markPosition(JCTree tree) { |
115 | 4 | if (diagPos[0] == null) { |
116 | 3 | diagPos[0] = tree.pos(); |
117 | |
} |
118 | 4 | } |
119 | |
}.scan(module.defs); |
120 | 385 | addPseudoVariables(diagPos[0], moduleClassName, module, moduleClassDefs, usesFile[0], usesDir[0]); |
121 | |
|
122 | |
|
123 | 385 | ListBuffer<JCTree> topLevelDefs = new ListBuffer<JCTree>(); |
124 | 385 | JFXClassDeclaration moduleClass = null; |
125 | 385 | JCExpression value = null; |
126 | 385 | for (JCTree tree : module.defs) { |
127 | 3500 | if (value != null) { |
128 | 1504 | stats.append( make.at(value).Exec(value) ); |
129 | 1504 | value = null; |
130 | |
} |
131 | 3500 | switch (tree.getTag()) { |
132 | |
case IMPORT: |
133 | 409 | topLevelDefs.append(tree); |
134 | 409 | break; |
135 | |
case CLASS_DEF: { |
136 | 325 | JFXClassDeclaration decl = (JFXClassDeclaration)tree; |
137 | 325 | Name name = decl.getName(); |
138 | 325 | checkName(tree.pos, name); |
139 | 325 | if (name == moduleClassName) { |
140 | 60 | moduleClass = decl; |
141 | |
} else { |
142 | 265 | decl.mods.flags |= STATIC; |
143 | 265 | moduleClassDefs.append(tree); |
144 | |
} |
145 | 265 | break; |
146 | |
} |
147 | |
case FUNCTION_DEF: { |
148 | 125 | JFXFunctionDefinition decl = |
149 | |
(JFXFunctionDefinition)tree; |
150 | 125 | decl.mods.flags |= STATIC; |
151 | 125 | Name name = decl.name; |
152 | 125 | checkName(tree.pos, name); |
153 | 125 | moduleClassDefs.append(tree); |
154 | |
|
155 | 125 | break; |
156 | |
} |
157 | |
case VAR_DEF: { |
158 | 816 | JFXVar decl = (JFXVar) tree; |
159 | |
|
160 | |
|
161 | 816 | checkName(tree.pos, decl.getName()); |
162 | 816 | stats.append(decl); |
163 | 816 | break; |
164 | |
} |
165 | |
default: |
166 | 1825 | if (tree instanceof JCExpression) { |
167 | 1751 | value = (JCExpression)tree; |
168 | |
} else { |
169 | 74 | stats.append((JCStatement)tree); |
170 | |
} |
171 | 3500 | break; |
172 | |
} |
173 | |
} |
174 | |
|
175 | |
|
176 | 385 | JFXFunctionDefinition runMethod = makeRunFunction(defs.runMethodName, stats.toList(), value, syms.objectType); |
177 | 385 | moduleClassDefs.prepend(runMethod); |
178 | |
|
179 | 385 | if (moduleClass == null) { |
180 | 325 | moduleClass = make.ClassDeclaration( |
181 | |
make.Modifiers(PUBLIC), |
182 | |
moduleClassName, |
183 | |
List.<JCExpression>nil(), |
184 | |
moduleClassDefs.toList()); |
185 | |
} else { |
186 | 60 | moduleClass.appendToMembers(moduleClassDefs); |
187 | |
} |
188 | 385 | moduleClass.isModuleClass = true; |
189 | 385 | moduleClass.runMethod = runMethod; |
190 | |
|
191 | 385 | topLevelDefs.append(moduleClass); |
192 | |
|
193 | 385 | module.defs = topLevelDefs.toList(); |
194 | |
|
195 | 385 | topLevelNamesSet = null; |
196 | 385 | } |
197 | |
|
198 | |
private void addPseudoVariables(DiagnosticPosition diagPos, Name moduleClassName, JCCompilationUnit module, |
199 | |
ListBuffer<JCTree> stats, boolean usesFile, boolean usesDir) { |
200 | 385 | if (usesFile || usesDir) { |
201 | |
|
202 | 3 | JCExpression moduleClassFQN = module.pid != null ? |
203 | |
make.at(diagPos).Select(module.pid, moduleClassName) : make.at(diagPos).Ident(moduleClassName); |
204 | 3 | JCExpression getFile = make.at(diagPos).Identifier("com.sun.javafx.runtime.Util.get__FILE__"); |
205 | 3 | JCExpression forName = make.at(diagPos).Identifier("java.lang.Class.forName"); |
206 | 3 | List<JCExpression> args = List.<JCExpression>of(make.at(diagPos).Literal(moduleClassFQN.toString())); |
207 | 3 | JCExpression loaderCall = make.at(diagPos).Apply(List.<JCExpression>nil(), forName, args); |
208 | 3 | args = List.<JCExpression>of(loaderCall); |
209 | 3 | JCExpression getFileURL = make.at(diagPos).Apply(List.<JCExpression>nil(), getFile, args); |
210 | 3 | JCStatement fileVar = |
211 | |
make.at(diagPos).Var(pseudoFile, getURLType(diagPos), |
212 | |
make.at(diagPos).Modifiers(Flags.FINAL|Flags.STATIC), |
213 | |
false, getFileURL, JavafxBindStatus.UNBOUND, null); |
214 | |
|
215 | |
|
216 | 3 | if (usesDir) { |
217 | 2 | JCExpression getDir = make.at(diagPos).Identifier("com.sun.javafx.runtime.Util.get__DIR__"); |
218 | 2 | args = List.<JCExpression>of(make.at(diagPos).Ident(pseudoFile)); |
219 | 2 | JCExpression getDirURL = make.at(diagPos).Apply(List.<JCExpression>nil(), getDir, args); |
220 | 2 | stats.prepend( |
221 | |
make.at(diagPos).Var(pseudoDir, getURLType(diagPos), |
222 | |
make.at(diagPos).Modifiers(Flags.FINAL|Flags.STATIC), |
223 | |
false, getDirURL, JavafxBindStatus.UNBOUND, null)); |
224 | |
} |
225 | |
|
226 | 3 | stats.prepend(fileVar); |
227 | |
} |
228 | 385 | } |
229 | |
|
230 | |
private JFXType getURLType(DiagnosticPosition diagPos) { |
231 | 5 | JCExpression urlFQN = make.at(diagPos).Identifier("java.net.URL"); |
232 | 5 | return make.at(diagPos).TypeClass(urlFQN, TypeTree.Cardinality.SINGLETON); |
233 | |
} |
234 | |
|
235 | |
private JFXFunctionDefinition makeRunFunction(Name name, List<JCStatement> stats, JCExpression value, Type returnType) { |
236 | 385 | JFXVar mainArgs = make.Param(commandLineArgs, |
237 | |
make.TypeClass(make.Ident(Name.fromString(names, "String")), TypeTree.Cardinality.ANY)); |
238 | 385 | List<JFXVar> argsVarList = List.<JFXVar>of(mainArgs); |
239 | 385 | return makeMethod(name, stats, value, returnType, argsVarList); |
240 | |
} |
241 | |
|
242 | |
private JFXFunctionDefinition makeMethod(Name name, List<JCStatement> stats, JCExpression value, Type returnType, List<JFXVar> param) { |
243 | 385 | JFXBlockExpression body = make.BlockExpression(0, stats, value); |
244 | 385 | JCExpression rettree = make.Type(returnType); |
245 | |
|
246 | 385 | rettree.type = returnType; |
247 | 385 | return make.FunctionDefinition( |
248 | |
make.Modifiers(PUBLIC | STATIC | SYNTHETIC), |
249 | |
name, |
250 | |
make.TypeClass(rettree, JFXType.Cardinality.SINGLETON), |
251 | |
param, |
252 | |
body); |
253 | |
} |
254 | |
|
255 | |
private Name moduleName(JCCompilationUnit tree) { |
256 | 385 | String fileObjName = null; |
257 | |
|
258 | 385 | FileObject fo = tree.getSourceFile(); |
259 | 385 | URI uri = fo.toUri(); |
260 | 385 | String path = uri.getPath(); |
261 | 385 | int i = path.lastIndexOf('/') + 1; |
262 | 385 | fileObjName = path.substring(i); |
263 | 385 | int lastDotIdx = fileObjName.lastIndexOf('.'); |
264 | 385 | if (lastDotIdx != -1) { |
265 | 385 | fileObjName = fileObjName.substring(0, lastDotIdx); |
266 | |
} |
267 | |
|
268 | 385 | return Name.fromString(names, fileObjName); |
269 | |
} |
270 | |
|
271 | |
private void checkName(int pos, Name name) { |
272 | 1266 | if (topLevelNamesSet == null) { |
273 | 352 | topLevelNamesSet = new HashSet<Name>(); |
274 | |
|
275 | |
|
276 | 352 | topLevelNamesSet.add(pseudoFile); |
277 | 352 | topLevelNamesSet.add(pseudoDir); |
278 | 352 | topLevelNamesSet.add(commandLineArgs); |
279 | |
} |
280 | |
|
281 | 1266 | if (topLevelNamesSet.contains(name)) { |
282 | 0 | log.error(pos, MsgSym.MESSAGE_JAVAFX_DUPLICATE_MODULE_MEMBER, name.toString()); |
283 | |
} |
284 | |
|
285 | 1266 | topLevelNamesSet.add(name); |
286 | 1266 | } |
287 | |
|
288 | |
private void checkForBadPositions(JCCompilationUnit testTree) { |
289 | 0 | final Map<JCTree, Integer> endPositions = testTree.endPositions; |
290 | 0 | new JavafxTreeScanner() { |
291 | |
|
292 | |
@Override |
293 | |
public void scan(JCTree tree) { |
294 | 0 | super.scan(tree); |
295 | |
|
296 | |
|
297 | |
|
298 | 0 | if (tree instanceof JCModifiers) { |
299 | 0 | JCModifiers mods = (JCModifiers)tree; |
300 | 0 | if (mods.getAnnotations().isEmpty() && |
301 | |
mods.getFlags().isEmpty() || |
302 | |
(mods.flags & Flags.SYNTHETIC) > 0) |
303 | 0 | return; |
304 | |
} |
305 | |
|
306 | |
|
307 | 0 | if (tree instanceof JFXTypeUnknown) |
308 | 0 | return; |
309 | |
|
310 | 0 | if (tree != null) { |
311 | 0 | if (tree.pos <= 0) { |
312 | 0 | String where = tree.getClass().getSimpleName(); |
313 | |
try { |
314 | 0 | where = where + ": " + tree.toString(); |
315 | 0 | } catch (Throwable exc) { |
316 | |
|
317 | 0 | } |
318 | 0 | System.err.println("Position of " + |
319 | |
tree.pos + |
320 | |
" in ---" + |
321 | |
where); |
322 | |
} |
323 | 0 | if (tree.getEndPosition(endPositions) <= 0) { |
324 | 0 | String where = tree.getClass().getSimpleName(); |
325 | |
try { |
326 | 0 | where = where + ": " + tree.toString(); |
327 | 0 | } catch (Throwable exc) { |
328 | |
|
329 | 0 | } |
330 | 0 | System.err.println("End position of " + |
331 | |
tree.getEndPosition(endPositions) + |
332 | |
" in ---" + |
333 | |
where); |
334 | |
} |
335 | |
} |
336 | 0 | } |
337 | |
}.scan(testTree); |
338 | 0 | } |
339 | |
|
340 | |
} |