KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > syntax > ASTHelper


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

18 package org.codehaus.groovy.syntax;
19
20 import org.codehaus.groovy.ast.ModuleNode;
21 import org.codehaus.groovy.control.CompilationFailedException;
22 import org.codehaus.groovy.control.SourceUnit;
23 import org.codehaus.groovy.syntax.Types;
24
25 import java.util.ArrayList JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29
30 /**
31  * A common base class of AST helper methods which can be shared across the classic and new parsers
32  *
33  * @author James Strachan
34  * @author Bob McWhirter
35  * @author Sam Pullara
36  * @author Chris Poirier
37  * @version $Revision: 1.6 $
38  */

39 public class ASTHelper {
40
41     private static final String JavaDoc[] EMPTY_STRING_ARRAY = new String JavaDoc[0];
42     private static final String JavaDoc[] DEFAULT_IMPORTS = {"java.lang.", "java.io.", "java.net.", "java.util.", "groovy.lang.", "groovy.util."};
43
44     /** The SourceUnit controlling us */
45     private SourceUnit controller;
46
47     /** Our ClassLoader, which provides information on external types */
48     private ClassLoader JavaDoc classLoader;
49
50     /** Our imports, simple name => fully qualified name */
51     private Map JavaDoc imports;
52     protected ModuleNode output;
53
54     /** The package name in which the module sits */
55     private String JavaDoc packageName; //
56

57     // TODO should this really be static???
58
protected static HashMap JavaDoc resolutions = new HashMap JavaDoc(); // cleared on build(), to be safe
59

60     private static String JavaDoc NOT_RESOLVED = new String JavaDoc();
61
62     /** temporarily store the class names that the current modulenode contains */
63     private List JavaDoc newClasses = new ArrayList JavaDoc();
64
65     public ASTHelper(SourceUnit controller, ClassLoader JavaDoc classLoader) {
66         this();
67         this.controller = controller;
68         this.classLoader = classLoader;
69     }
70
71     public ASTHelper() {
72         imports = new HashMap JavaDoc();
73     }
74
75     public String JavaDoc getPackageName() {
76         return packageName;
77     }
78
79     public void setPackageName(String JavaDoc packageName) {
80         this.packageName = packageName;
81
82         output.setPackageName(packageName);
83     }
84
85
86     /**
87      * Returns our class loader (as supplied on construction).
88      */

89     public ClassLoader JavaDoc getClassLoader() {
90         return classLoader;
91     }
92
93     public void setClassLoader(ClassLoader JavaDoc classLoader) {
94         this.classLoader = classLoader;
95     }
96
97     public SourceUnit getController() {
98         return controller;
99     }
100
101     public void setController(SourceUnit controller) {
102         this.controller = controller;
103     }
104
105     /**
106      * Returns a fully qualified name for any given potential type
107      * name. Returns null if no qualified name could be determined.
108      */

109
110     protected String JavaDoc resolveName(String JavaDoc name, boolean safe) {
111         //
112
// Use our cache of resolutions, if possible
113

114         String JavaDoc resolution = (String JavaDoc) resolutions.get(name);
115         if (NOT_RESOLVED.equals(resolution)) {
116             return (safe ? name : null);
117         }
118         else if (resolution != null) {
119             return (String JavaDoc) resolution;
120         }
121
122         try {
123             getClassLoader().loadClass(name);
124             resolutions.put(name,name);
125             return name;
126         } catch (ClassNotFoundException JavaDoc cnfe){
127             if (cnfe.getCause() instanceof CompilationFailedException) {
128                 resolutions.put(name,name);
129                 return name;
130             }
131         } catch (NoClassDefFoundError JavaDoc ncdfe) {
132             //fall through
133
}
134
135         do {
136             //
137
// If the type name contains a ".", it's probably fully
138
// qualified, and we don't take it to verification here.
139

140             if (name.indexOf(".") >= 0) {
141                 resolution = name;
142                 break; // <<< FLOW CONTROL <<<<<<<<<
143
}
144
145
146             //
147
// Otherwise, we'll need the scalar type for checking, and
148
// the postfix for reassembly.
149

150             String JavaDoc scalar = name, postfix = "";
151             while (scalar.endsWith("[]")) {
152                 scalar = scalar.substring(0, scalar.length() - 2);
153                 postfix += "[]";
154             }
155
156
157             //
158
// Primitive types are all valid...
159

160             if (Types.ofType(Types.lookupKeyword(scalar), Types.PRIMITIVE_TYPE)) {
161                 resolution = name;
162                 break; // <<< FLOW CONTROL <<<<<<<<<
163
}
164
165
166             //
167
// Next, check our imports and return the qualified name,
168
// if available.
169

170             if (this.imports.containsKey(scalar)) {
171                 resolution = ((String JavaDoc) this.imports.get(scalar)) + postfix;
172                 break; // <<< FLOW CONTROL <<<<<<<<<
173
}
174
175
176             //
177
// Next, see if our class loader can resolve it in the current package.
178

179             if (packageName != null && packageName.length() > 0) {
180                 try {
181                     getClassLoader().loadClass(dot(packageName, scalar));
182                     resolution = dot(packageName, name);
183
184                     break; // <<< FLOW CONTROL <<<<<<<<<
185
} catch (ClassNotFoundException JavaDoc cnfe){
186                     if (cnfe.getCause() instanceof CompilationFailedException) {
187                         break;
188                     }
189                 } catch (NoClassDefFoundError JavaDoc ncdfe) {
190                     //fall through
191
}
192             }
193
194             // search the package imports path
195
List JavaDoc packageImports = output.getImportPackages();
196             for (int i = 0; i < packageImports.size(); i++) {
197                 String JavaDoc pack = (String JavaDoc) packageImports.get(i);
198                 String JavaDoc clsName = pack + name;
199                 try {
200                     getClassLoader().loadClass(clsName);
201                     resolution = clsName;
202                     break;
203                 } catch (ClassNotFoundException JavaDoc cnfe){
204                     if (cnfe.getCause() instanceof CompilationFailedException) {
205                         break;
206                     }
207                 } catch (NoClassDefFoundError JavaDoc ncdfe) {
208                     //fall through
209
}
210             }
211             if (resolution != null) {
212                 break;
213             }
214
215             //
216
// Last chance, check the default imports.
217

218             for (int i = 0; i < DEFAULT_IMPORTS.length; i++) {
219                 try {
220                     String JavaDoc qualified = DEFAULT_IMPORTS[i] + scalar;
221                     getClassLoader().loadClass(qualified);
222
223                     resolution = qualified + postfix;
224                     break; // <<< FLOW CONTROL <<<<<<<<<
225
} catch (ClassNotFoundException JavaDoc cnfe){
226                     if (cnfe.getCause() instanceof CompilationFailedException) {
227                         break;
228                     }
229                 } catch (NoClassDefFoundError JavaDoc ncdfee) {
230                     // fall through
231
}
232             }
233
234         }
235         while (false);
236
237
238         //
239
// Cache the solution and return it
240

241         if (resolution == null) {
242             resolutions.put(name, NOT_RESOLVED);
243             return (safe ? name : null);
244         }
245         else {
246             resolutions.put(name, resolution);
247             return resolution;
248         }
249     }
250
251     /**
252      * Returns two names joined by a dot. If the base name is
253      * empty, returns the name unchanged.
254      */

255
256     protected String JavaDoc dot(String JavaDoc base, String JavaDoc name) {
257         if (base != null && base.length() > 0) {
258             return base + "." + name;
259         }
260
261         return name;
262     }
263
264     protected void makeModule() {
265         this.newClasses.clear();
266         this.output = new ModuleNode(controller);
267         resolutions.clear();
268     }
269
270     /**
271      * Returns true if the specified name is a known type name.
272      */

273
274     protected boolean isDatatype(String JavaDoc name) {
275         return resolveName(name, false) != null;
276     }
277
278     /**
279      * A synonym for <code>dot( base, "" )</code>.
280      */

281
282     protected String JavaDoc dot(String JavaDoc base) {
283         return dot(base, "");
284     }
285
286     protected String JavaDoc resolveNewClassOrName(String JavaDoc name, boolean safe) {
287         if (this.newClasses.contains(name)) {
288             return dot(packageName, name);
289         }
290         else {
291             return resolveName(name, safe);
292         }
293     }
294
295     protected void addNewClassName(String JavaDoc name) {
296         this.newClasses.add(name);
297     }
298
299     protected void importClass(String JavaDoc importPackage, String JavaDoc name, String JavaDoc as) {
300         //
301
// There appears to be a bug in the previous code for
302
// single imports, in that the old code passed unqualified
303
// class names to module.addImport(). This hasn't been a
304
// problem apparently because those names are resolved here.
305
// Passing module.addImport() a fully qualified name does
306
// currently causes problems with classgen, possibly because
307
// of name collisions. So, for now, we use the old method...
308

309         if (as==null) as=name;
310         output.addImport( as, name ); // unqualified
311

312         name = dot( importPackage, name );
313
314         // module.addImport( as, name ); // qualified
315
imports.put( as, name );
316     }
317
318     protected void importPackageWithStar(String JavaDoc importPackage) {
319         String JavaDoc[] classes = output.addImportPackage( dot(importPackage) );
320         for( int i = 0; i < classes.length; i++ )
321         {
322             imports.put( classes[i], dot(importPackage, classes[i]) );
323         }
324     }
325 }
326
Popular Tags