KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > jjs > impl > BuildTypeMap


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.dev.jjs.impl;
17
18 import com.google.gwt.dev.jjs.InternalCompilerException;
19 import com.google.gwt.dev.jjs.SourceInfo;
20 import com.google.gwt.dev.jjs.ast.JClassType;
21 import com.google.gwt.dev.jjs.ast.JField;
22 import com.google.gwt.dev.jjs.ast.JInterfaceType;
23 import com.google.gwt.dev.jjs.ast.JLocal;
24 import com.google.gwt.dev.jjs.ast.JMethod;
25 import com.google.gwt.dev.jjs.ast.JParameter;
26 import com.google.gwt.dev.jjs.ast.JProgram;
27 import com.google.gwt.dev.jjs.ast.JReferenceType;
28 import com.google.gwt.dev.jjs.ast.JType;
29 import com.google.gwt.dev.jjs.ast.js.JsniMethod;
30 import com.google.gwt.dev.js.JsParser;
31 import com.google.gwt.dev.js.JsParserException;
32 import com.google.gwt.dev.js.JsParserException.SourceDetail;
33 import com.google.gwt.dev.js.ast.JsExprStmt;
34 import com.google.gwt.dev.js.ast.JsFunction;
35 import com.google.gwt.dev.js.ast.JsProgram;
36 import com.google.gwt.dev.js.ast.JsStatements;
37
38 import org.eclipse.jdt.internal.compiler.ASTVisitor;
39 import org.eclipse.jdt.internal.compiler.CompilationResult;
40 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
41 import org.eclipse.jdt.internal.compiler.ast.Argument;
42 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
43 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
44 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
45 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
46 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
47 import org.eclipse.jdt.internal.compiler.ast.Statement;
48 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
49 import org.eclipse.jdt.internal.compiler.env.IGenericType;
50 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
51 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
52 import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
53 import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
54 import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
55 import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
56 import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
57 import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
58 import org.eclipse.jdt.internal.compiler.lookup.NestedTypeBinding;
59 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
60 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
61 import org.eclipse.jdt.internal.compiler.lookup.SyntheticArgumentBinding;
62 import org.eclipse.jdt.internal.compiler.problem.ProblemHandler;
63
64 import java.io.IOException JavaDoc;
65 import java.io.StringReader JavaDoc;
66 import java.util.ArrayList JavaDoc;
67 import java.util.HashSet JavaDoc;
68 import java.util.Set JavaDoc;
69
70 /**
71  * This is a Builder for {@link TypeMap}. The whole point of this pass is to
72  * create raw unfinished, unlinked AST nodes for types, methods, fields, and
73  * parameters, and to map the original JDT nodes to these AST nodes. That way
74  * when GenerateJavaDom runs, it just uses the TypeMap output from this Builder
75  * to retrieve whatever referenceable nodes it needs without worrying about
76  * whether they need to be created. Building our AST from JDT starts here.
77  */

78 public class BuildTypeMap {
79
80   /**
81    * Creates JNodes for every method, field, initializer, parameter, and local
82    * and memorizes the mapping from the JDT Binding to the corresponding JNode
83    * for each thing created. Note that this pass also 1) sets up the super
84    * type(s) for any member or local types created in BuildTypeMapVisitor (see
85    * the comments there about why it had to be deferred). 2) adds each
86    * user-defined type to a flat list. 3) Creates JNodes for all methods and
87    * variables and memorizes the mapping from the JDT Binding to the
88    * corresponding JNode for each created method and variable. 4) Maps all
89    * synthetic arguments and fields for nested and local classes. 5) Slurps in
90    * JSNI code for native methods as an opaque string.
91    *
92    * Note that methods and fields are not added to their classes here, that
93    * isn't done until {@link GenerateJavaDom}.
94    */

95   private static class BuildDeclMapVisitor extends ASTVisitor {
96
97     private static SourceInfo makeSourceInfo(
98         AbstractMethodDeclaration methodDecl) {
99       CompilationResult compResult = methodDecl.compilationResult;
100       int[] indexes = compResult.lineSeparatorPositions;
101       String JavaDoc fileName = String.valueOf(compResult.fileName);
102       int startLine = ProblemHandler.searchLineNumber(indexes,
103           methodDecl.sourceStart);
104       return new SourceInfo(methodDecl.sourceStart, methodDecl.bodyEnd,
105           startLine, fileName);
106     }
107
108     private static InternalCompilerException translateException(
109         AbstractMethodDeclaration amd, Throwable JavaDoc e) {
110       InternalCompilerException ice;
111       if (e instanceof InternalCompilerException) {
112         ice = (InternalCompilerException) e;
113       } else {
114         ice = new InternalCompilerException("Error building type map", e);
115       }
116       ice.addNode(amd.getClass().getName(), amd.toString(), makeSourceInfo(amd));
117       return ice;
118     }
119
120     private String JavaDoc currentFileName;
121     private int[] currentSeparatorPositions;
122     private final JsParser jsParser = new JsParser();
123     private final JsProgram jsProgram;
124     private JProgram program;
125     private ArrayList JavaDoc/* <TypeDeclaration> */typeDecls = new ArrayList JavaDoc/* <TypeDeclaration> */();
126
127     private final TypeMap typeMap;
128
129     public BuildDeclMapVisitor(TypeMap typeMap, JsProgram jsProgram) {
130       this.typeMap = typeMap;
131       program = this.typeMap.getProgram();
132       this.jsProgram = jsProgram;
133     }
134
135     public TypeDeclaration[] getTypeDeclarataions() {
136       return (TypeDeclaration[]) typeDecls.toArray(new TypeDeclaration[typeDecls.size()]);
137     }
138
139     public boolean visit(Argument argument, BlockScope scope) {
140       try {
141         if (scope == scope.methodScope()) {
142           return true;
143         }
144
145         SourceInfo info = makeSourceInfo(argument);
146         LocalVariableBinding b = argument.binding;
147         JType localType = (JType) typeMap.get(b.type);
148         JMethod enclosingMethod = findEnclosingMethod(scope);
149         JLocal newLocal = program.createLocal(info, argument.name, localType,
150             b.isFinal(), enclosingMethod);
151         typeMap.put(b, newLocal);
152         return true;
153       } catch (Throwable JavaDoc e) {
154         throw translateException(argument, e);
155       }
156     }
157
158     /**
159      * Weird: we used to have JConstructor (and JConstructorCall) in our AST,
160      * but we got rid of them completely and instead model them as instance
161      * methods whose qualifier is a naked no-argument new operation. See
162      * {@link GenerateJavaAST.JavaASTGenerationVisitor#processConstructor(ConstructorDeclaration)}
163      * for details.
164      */

165     public boolean visit(ConstructorDeclaration ctorDecl, ClassScope scope) {
166       try {
167         MethodBinding b = ctorDecl.binding;
168         JClassType enclosingType = (JClassType) typeMap.get(scope.enclosingSourceType());
169         String JavaDoc name = enclosingType.getShortName();
170         SourceInfo info = makeSourceInfo(ctorDecl);
171         JMethod newMethod = program.createMethod(info, name.toCharArray(),
172             enclosingType, enclosingType, false, false, true, b.isPrivate(),
173             false);
174         mapThrownExceptions(newMethod, ctorDecl);
175
176         // user args
177
mapParameters(newMethod, ctorDecl);
178         // original params are now frozen
179

180         int syntheticParamCount = 0;
181         ReferenceBinding declaringClass = b.declaringClass;
182         if (declaringClass.isNestedType() && !declaringClass.isStatic()) {
183           // add synthetic args for outer this and locals
184
NestedTypeBinding nestedBinding = (NestedTypeBinding) declaringClass;
185           Set JavaDoc alreadyNamedVariables = new HashSet JavaDoc();
186           if (nestedBinding.enclosingInstances != null) {
187             for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
188               SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
189               String JavaDoc argName = String.valueOf(arg.name);
190               if (alreadyNamedVariables.contains(argName)) {
191                 argName += "_" + i;
192               }
193               createParameter(arg, argName, newMethod);
194               ++syntheticParamCount;
195               alreadyNamedVariables.add(argName);
196             }
197           }
198
199           if (nestedBinding.outerLocalVariables != null) {
200             for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
201               SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
202               String JavaDoc argName = String.valueOf(arg.name);
203               if (alreadyNamedVariables.contains(argName)) {
204                 argName += "_" + i;
205               }
206               createParameter(arg, argName, newMethod);
207               ++syntheticParamCount;
208               alreadyNamedVariables.add(argName);
209             }
210           }
211         }
212
213         typeMap.put(b, newMethod);
214         return true;
215       } catch (Throwable JavaDoc e) {
216         throw translateException(ctorDecl, e);
217       }
218     }
219
220     public boolean visit(FieldDeclaration fieldDeclaration, MethodScope scope) {
221       try {
222         FieldBinding b = fieldDeclaration.binding;
223         SourceInfo info = makeSourceInfo(fieldDeclaration);
224         JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType());
225         createField(info, b, enclosingType,
226             fieldDeclaration.initialization != null);
227         return true;
228       } catch (Throwable JavaDoc e) {
229         throw translateException(fieldDeclaration, e);
230       }
231     }
232
233     public boolean visit(LocalDeclaration localDeclaration, BlockScope scope) {
234       try {
235         LocalVariableBinding b = localDeclaration.binding;
236         JType localType = (JType) typeMap.get(localDeclaration.type.resolvedType);
237         JMethod enclosingMethod = findEnclosingMethod(scope);
238         SourceInfo info = makeSourceInfo(localDeclaration);
239         JLocal newLocal = program.createLocal(info, localDeclaration.name,
240             localType, b.isFinal(), enclosingMethod);
241         typeMap.put(b, newLocal);
242         return true;
243       } catch (Throwable JavaDoc e) {
244         throw translateException(localDeclaration, e);
245       }
246     }
247
248     public boolean visit(MethodDeclaration methodDeclaration, ClassScope scope) {
249       try {
250         MethodBinding b = methodDeclaration.binding;
251         SourceInfo info = makeSourceInfo(methodDeclaration);
252         JType returnType = (JType) typeMap.get(methodDeclaration.returnType.resolvedType);
253         JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.enclosingSourceType());
254         JMethod newMethod = program.createMethod(info,
255             methodDeclaration.selector, enclosingType, returnType,
256             b.isAbstract(), b.isStatic(), b.isFinal(), b.isPrivate(),
257             b.isNative());
258
259         mapThrownExceptions(newMethod, methodDeclaration);
260         mapParameters(newMethod, methodDeclaration);
261         typeMap.put(b, newMethod);
262
263         if (newMethod.isNative()) {
264           // Handle JSNI block
265
char[] source = methodDeclaration.compilationResult().getCompilationUnit().getContents();
266           String JavaDoc jsniCode = String.valueOf(source, methodDeclaration.bodyStart,
267               methodDeclaration.bodyEnd - methodDeclaration.bodyStart + 1);
268           int startPos = jsniCode.indexOf("/*-{");
269           int endPos = jsniCode.lastIndexOf("}-*/");
270           if (startPos < 0 && endPos < 0) {
271             GenerateJavaAST.reportJsniError(
272                 info,
273                 methodDeclaration,
274                 "Native methods require a JavaScript implementation enclosed with /*-{ and }-*/");
275             return true;
276           }
277           if (startPos < 0) {
278             GenerateJavaAST.reportJsniError(info, methodDeclaration,
279                 "Unable to find start of native block; begin your JavaScript block with: /*-{");
280             return true;
281           }
282           if (endPos < 0) {
283             GenerateJavaAST.reportJsniError(
284                 info,
285                 methodDeclaration,
286                 "Unable to find end of native block; terminate your JavaScript block with: }-*/");
287             return true;
288           }
289
290           startPos += 3; // move up to open brace
291
endPos += 1; // move past close brace
292

293           jsniCode = jsniCode.substring(startPos, endPos);
294
295           // Here we parse it as an anonymous function, but we will give it a
296
// name later when we generate the JavaScript during code generation.
297
//
298
String JavaDoc syntheticFnHeader = "function (";
299           boolean first = true;
300           for (int i = 0; i < newMethod.params.size(); ++i) {
301             JParameter param = (JParameter) newMethod.params.get(i);
302             if (first) {
303               first = false;
304             } else {
305               syntheticFnHeader += ',';
306             }
307             syntheticFnHeader += param.getName();
308           }
309           syntheticFnHeader += ')';
310           StringReader JavaDoc sr = new StringReader JavaDoc(syntheticFnHeader + '\n'
311               + jsniCode);
312           try {
313             // start at -1 to avoid counting our synthetic header
314
// TODO: get the character position start correct
315
JsStatements result = jsParser.parse(jsProgram.getScope(), sr, -1);
316             JsExprStmt jsExprStmt = (JsExprStmt) result.get(0);
317             JsFunction jsFunction = (JsFunction) jsExprStmt.getExpression();
318             ((JsniMethod) newMethod).setFunc(jsFunction);
319           } catch (IOException JavaDoc e) {
320             throw new InternalCompilerException(
321                 "Internal error parsing JSNI in method '" + newMethod
322                     + "' in type '" + enclosingType.getName() + "'", e);
323           } catch (JsParserException e) {
324             /*
325              * count the number of characters to the problem (from the start of
326              * the JSNI code)
327              */

328             SourceDetail detail = e.getSourceDetail();
329             int line = detail.getLine();
330             char[] chars = jsniCode.toCharArray();
331             int i = 0, n = chars.length;
332             while (line > 0) {
333               // CHECKSTYLE_OFF
334
switch (chars[i]) {
335                 case '\r':
336                   // if skip an extra character if this is a CR/LF
337
if (i + 1 < n && chars[i + 1] == '\n') {
338                     ++i;
339                   }
340                   // intentional fall-through
341
case '\n':
342                   --line;
343                   // intentional fall-through
344
default:
345                   ++i;
346               }
347               // CHECKSTYLE_ON
348
}
349
350             // TODO: check this
351
// Map into the original source stream;
352
i += startPos + detail.getLineOffset();
353             info = new SourceInfo(i, i,
354                 info.getStartLine() + detail.getLine(), info.getFileName());
355             GenerateJavaAST.reportJsniError(info, methodDeclaration,
356                 e.getMessage());
357           }
358         }
359
360         return true;
361       } catch (Throwable JavaDoc e) {
362         throw translateException(methodDeclaration, e);
363       }
364     }
365
366     public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
367       return process(localTypeDeclaration);
368     }
369
370     public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
371       return process(memberTypeDeclaration);
372     }
373
374     public boolean visit(TypeDeclaration typeDeclaration,
375         CompilationUnitScope scope) {
376       return process(typeDeclaration);
377     }
378
379     private JField createField(SourceInfo info, FieldBinding binding,
380         JReferenceType enclosingType, boolean hasInitializer) {
381       JType type = (JType) typeMap.get(binding.type);
382       JField field = program.createField(info, binding.name, enclosingType,
383           type, binding.isStatic(), binding.isFinal(), hasInitializer);
384       typeMap.put(binding, field);
385       return field;
386     }
387
388     private JField createField(SyntheticArgumentBinding binding,
389         JReferenceType enclosingType) {
390       JType type = (JType) typeMap.get(binding.type);
391       JField field = program.createField(null, binding.name, enclosingType,
392           type, false, true, true);
393       if (binding.matchingField != null) {
394         typeMap.put(binding.matchingField, field);
395       }
396       typeMap.put(binding, field);
397       return field;
398     }
399
400     private JParameter createParameter(LocalVariableBinding binding,
401         JMethod enclosingMethod) {
402       JType type = (JType) typeMap.get(binding.type);
403       SourceInfo info = makeSourceInfo(binding.declaration);
404       JParameter param = program.createParameter(info, binding.name, type,
405           binding.isFinal(), enclosingMethod);
406       typeMap.put(binding, param);
407       return param;
408     }
409
410     private JParameter createParameter(SyntheticArgumentBinding arg,
411         String JavaDoc argName, JMethod enclosingMethod) {
412       JType type = (JType) typeMap.get(arg.type);
413       JParameter param = program.createParameter(null, argName.toCharArray(),
414           type, true, enclosingMethod);
415       return param;
416     }
417
418     private JMethod findEnclosingMethod(BlockScope scope) {
419       MethodScope methodScope = scope.methodScope();
420       if (methodScope.isInsideInitializer()) {
421         JReferenceType enclosingType = (JReferenceType) typeMap.get(scope.classScope().referenceContext.binding);
422         if (methodScope.isStatic) {
423           // clinit
424
return (JMethod) enclosingType.methods.get(0);
425         } else {
426           // init
427
assert (enclosingType instanceof JClassType);
428           return (JMethod) enclosingType.methods.get(1);
429         }
430       }
431
432       AbstractMethodDeclaration referenceMethod = methodScope.referenceMethod();
433       return (JMethod) typeMap.get(referenceMethod.binding);
434     }
435
436     private SourceInfo makeSourceInfo(Statement stmt) {
437       int startLine = ProblemHandler.searchLineNumber(
438           currentSeparatorPositions, stmt.sourceStart);
439       return new SourceInfo(stmt.sourceStart, stmt.sourceEnd, startLine,
440           currentFileName);
441     }
442
443     private void mapParameters(JMethod method, AbstractMethodDeclaration x) {
444       MethodBinding b = x.binding;
445       int paramCount = (b.parameters != null ? b.parameters.length : 0);
446       if (paramCount > 0) {
447         for (int i = 0, n = x.arguments.length; i < n; ++i) {
448           createParameter(x.arguments[i].binding, method);
449         }
450       }
451       method.freezeParamTypes();
452     }
453
454     private void mapThrownExceptions(JMethod method, AbstractMethodDeclaration x) {
455       MethodBinding b = x.binding;
456       if (b.thrownExceptions != null) {
457         for (int i = 0; i < b.thrownExceptions.length; ++i) {
458           ReferenceBinding refBinding = b.thrownExceptions[i];
459           JClassType thrownException = (JClassType) typeMap.get(refBinding);
460           method.thrownExceptions.add(thrownException);
461         }
462       }
463     }
464
465     /**
466      * Add synthetic fields, setup super types. You'll notice that we DON'T have
467      * any concept of "inner" or "outer" types in our AST. Truth is, we found it
468      * easier to simply model everything as flat classes and emulate the nesting
469      * behavior (and final local access on local classes). It's much closer to
470      * how we'll eventually be generating JavaScript code (code generation is
471      * more straightforward), it makes for fewer kinds of things to worry about
472      * when optimizing (more aggressive optimizations), and it's how Java
473      * actually implements the stuff under the hood anyway.
474      */

475     private boolean process(TypeDeclaration typeDeclaration) {
476       CompilationResult compResult = typeDeclaration.compilationResult;
477       currentSeparatorPositions = compResult.lineSeparatorPositions;
478       currentFileName = String.valueOf(compResult.fileName);
479       SourceTypeBinding binding = typeDeclaration.binding;
480       if (binding.constantPoolName() == null) {
481         /*
482          * Weird case: if JDT determines that this local class is totally
483          * uninstantiable, it won't bother allocating a local name.
484          */

485         return false;
486       }
487       JReferenceType type = (JReferenceType) typeMap.get(binding);
488       try {
489         if (binding.isNestedType() && !binding.isStatic()) {
490           // add synthetic fields for outer this and locals
491
assert (type instanceof JClassType);
492           NestedTypeBinding nestedBinding = (NestedTypeBinding) binding;
493           if (nestedBinding.enclosingInstances != null) {
494             for (int i = 0; i < nestedBinding.enclosingInstances.length; ++i) {
495               SyntheticArgumentBinding arg = nestedBinding.enclosingInstances[i];
496               if (arg.matchingField != null) {
497                 createField(arg, type);
498               }
499             }
500           }
501
502           if (nestedBinding.outerLocalVariables != null) {
503             for (int i = 0; i < nestedBinding.outerLocalVariables.length; ++i) {
504               SyntheticArgumentBinding arg = nestedBinding.outerLocalVariables[i];
505               createField(arg, type);
506             }
507           }
508         }
509
510         ReferenceBinding superClassBinding = binding.superclass();
511         if (superClassBinding != null) {
512           assert (binding.superclass().isClass());
513           JClassType superClass = (JClassType) typeMap.get(superClassBinding);
514           type.extnds = superClass;
515         }
516
517         ReferenceBinding[] superInterfaces = binding.superInterfaces();
518         for (int i = 0; i < superInterfaces.length; ++i) {
519           ReferenceBinding superInterfaceBinding = superInterfaces[i];
520           assert (superInterfaceBinding.isInterface());
521           JInterfaceType superInterface = (JInterfaceType) typeMap.get(superInterfaceBinding);
522           type.implments.add(superInterface);
523         }
524         typeDecls.add(typeDeclaration);
525         return true;
526       } catch (InternalCompilerException ice) {
527         ice.addNode(type);
528         throw ice;
529       } catch (Throwable JavaDoc e) {
530         throw new InternalCompilerException(type, "Error building type map", e);
531       }
532     }
533
534     private InternalCompilerException translateException(Statement stmt,
535         Throwable JavaDoc e) {
536       InternalCompilerException ice;
537       if (e instanceof InternalCompilerException) {
538         ice = (InternalCompilerException) e;
539       } else {
540         ice = new InternalCompilerException("Error building type map", e);
541       }
542       ice.addNode(stmt.getClass().getName(), stmt.toString(),
543           makeSourceInfo(stmt));
544       return ice;
545     }
546   }
547
548   /**
549    * Creates JNodes for every type and memorizes the mapping from the JDT
550    * Binding to the corresponding JNode for each created type. Note that since
551    * there could be forward references, it is not possible to set up super types;
552    * it must be done is a subsequent pass.
553    */

554   private static class BuildTypeMapVisitor extends ASTVisitor {
555
556     private static SourceInfo makeSourceInfo(TypeDeclaration typeDecl) {
557       CompilationResult compResult = typeDecl.compilationResult;
558       int[] indexes = compResult.lineSeparatorPositions;
559       String JavaDoc fileName = String.valueOf(compResult.fileName);
560       int startLine = ProblemHandler.searchLineNumber(indexes,
561           typeDecl.sourceStart);
562       return new SourceInfo(typeDecl.sourceStart, typeDecl.bodyEnd, startLine,
563           fileName);
564     }
565
566     private static InternalCompilerException translateException(
567         TypeDeclaration typeDecl, Throwable JavaDoc e) {
568       InternalCompilerException ice;
569       if (e instanceof InternalCompilerException) {
570         ice = (InternalCompilerException) e;
571       } else {
572         ice = new InternalCompilerException("Error building type map", e);
573       }
574       ice.addNode(typeDecl.getClass().getName(), typeDecl.toString(),
575           makeSourceInfo(typeDecl));
576       return ice;
577     }
578
579     private final JProgram program;
580     private final TypeMap typeMap;
581
582     public BuildTypeMapVisitor(TypeMap typeMap) {
583       this.typeMap = typeMap;
584       program = this.typeMap.getProgram();
585     }
586
587     public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope scope) {
588       assert (localTypeDeclaration.kind() != IGenericType.INTERFACE_DECL);
589       return process(localTypeDeclaration);
590     }
591
592     public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope scope) {
593       return process(memberTypeDeclaration);
594     }
595
596     public boolean visit(TypeDeclaration typeDeclaration,
597         CompilationUnitScope scope) {
598       return process(typeDeclaration);
599     }
600
601     private boolean process(TypeDeclaration typeDeclaration) {
602       try {
603         char[][] name = typeDeclaration.binding.compoundName;
604         SourceTypeBinding binding = typeDeclaration.binding;
605         if (binding instanceof LocalTypeBinding) {
606           char[] localName = binding.constantPoolName();
607           if (localName == null) {
608             /*
609              * Weird case: if JDT determines that this local class is totally
610              * uninstantiable, it won't bother allocating a local name.
611              */

612             return false;
613           }
614
615           for (int i = 0, c = localName.length; i < c; ++i) {
616             if (localName[i] == '/') {
617               localName[i] = '.';
618             }
619           }
620           name = new char[1][0];
621           name[0] = localName;
622         }
623
624         SourceInfo info = makeSourceInfo(typeDeclaration);
625         JReferenceType newType;
626         if (binding.isClass()) {
627           newType = program.createClass(info, name, binding.isAbstract(),
628               binding.isFinal());
629         } else if (binding.isInterface()) {
630           newType = program.createInterface(info, name);
631         } else {
632           assert (false);
633           return false;
634         }
635
636         /**
637          * We emulate static initializers and instance initializers as methods.
638          * As in other cases, this gives us: simpler AST, easier to optimize,
639          * more like output JavaScript. Clinit is always in slot 0, init (if it
640          * exists) is always in slot 1.
641          */

642         JMethod clinit = program.createMethod(null, "$clinit".toCharArray(),
643             newType, program.getTypeVoid(), false, true, true, true, false);
644         clinit.freezeParamTypes();
645
646         if (newType instanceof JClassType) {
647           JMethod init = program.createMethod(null, "$init".toCharArray(),
648               newType, program.getTypeVoid(), false, false, true, true, false);
649           init.freezeParamTypes();
650         }
651
652         typeMap.put(binding, newType);
653         return true;
654       } catch (Throwable JavaDoc e) {
655         throw translateException(typeDeclaration, e);
656       }
657     }
658   }
659
660   public static TypeDeclaration[] exec(TypeMap typeMap,
661       CompilationUnitDeclaration[] unitDecls, JsProgram jsProgram) {
662     createPeersForTypes(unitDecls, typeMap);
663     return createPeersForNonTypeDecls(unitDecls, typeMap, jsProgram);
664   }
665
666   private static TypeDeclaration[] createPeersForNonTypeDecls(
667       CompilationUnitDeclaration[] unitDecls, TypeMap typeMap,
668       JsProgram jsProgram) {
669     // Traverse again to create our JNode peers for each method, field,
670
// parameter, and local
671
BuildDeclMapVisitor v2 = new BuildDeclMapVisitor(typeMap, jsProgram);
672     for (int i = 0; i < unitDecls.length; ++i) {
673       unitDecls[i].traverse(v2, unitDecls[i].scope);
674     }
675     return v2.getTypeDeclarataions();
676   }
677
678   private static void createPeersForTypes(
679       CompilationUnitDeclaration[] unitDecls, TypeMap typeMap) {
680     // Traverse once to create our JNode peers for each type
681
BuildTypeMapVisitor v1 = new BuildTypeMapVisitor(typeMap);
682     for (int i = 0; i < unitDecls.length; ++i) {
683       unitDecls[i].traverse(v1, unitDecls[i].scope);
684     }
685   }
686
687 }
688
Popular Tags