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.ClassHelper;
21 import org.codehaus.groovy.ast.ClassNode;
22 import org.codehaus.groovy.ast.ModuleNode;
23 import org.codehaus.groovy.control.SourceUnit;
24
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 /***
31 * A common base class of AST helper methods which can be shared across the classic and new parsers
32 *
33 * @author Jochen Theodorou
34 * @author James Strachan
35 * @author Bob McWhirter
36 * @author Sam Pullara
37 * @author Chris Poirier
38 * @version $Revision: 1.10 $
39 */
40 public class ASTHelper {
41
42 private static final String[] EMPTY_STRING_ARRAY = new String[0];
43
44 /*** The SourceUnit controlling us */
45 private SourceUnit controller;
46
47 /*** Our ClassLoader, which provides information on external types */
48 private ClassLoader classLoader;
49
50 /*** Our imports, simple name => fully qualified name */
51 private Map imports;
52 protected ModuleNode output;
53
54 /**</package-summary/html">The package name in which the module sits *//package-summary.html">em>* The package name in which the module sits */
55 private String packageName/package-summary.html">ong> String packageName; //
56
57 // TODO should this really be static???
58 protected static HashMap resolutions = new HashMap(); // cleared on build(), to be safe
59
60 private static String NOT_RESOLVED = new String();
61
62 /*** temporarily store the class names that the current modulenode contains */
63 private List newClasses = new ArrayList();
64
65 public ASTHelper(SourceUnit controller, ClassLoader classLoader) {
66 this();
67 this.controller = controller;
68 this.classLoader = classLoader;
69 }
70
71 public ASTHelper() {
72 imports = new HashMap();
73 }
74
75 public String getPackageName() {
76 return</strong> packageName;
77 }
78
79 public void setPackageName(String packageName) {/package-summary.html">ong> void setPackageName(String packageName) {
80 this.packageName = packageName;
81 if (packageName!=null && packageName.length()>0){
82 packageName+='.';
83 }
84 output.setPackageName(packageName);
85 }
86
87
88 /***
89 * Returns our class loader (as supplied on construction).
90 */
91 public ClassLoader getClassLoader() {
92 return classLoader;
93 }
94
95 public void setClassLoader(ClassLoader classLoader) {
96 this.classLoader = classLoader;
97 }
98
99 public SourceUnit getController() {
100 return controller;
101 }
102
103 public void setController(SourceUnit controller) {
104 this.controller = controller;
105 }
106
107 /***
108 * Returns a fully qualified name for any given potential type
109 * name. Returns null if no qualified name could be determined.
110 */
111 /* protected String resolveName(String name, boolean safe) {
112 //
113 // Use our cache of resolutions, if possible
114
115 String resolution = (String) resolutions.get(name);
116 if (NOT_RESOLVED.equals(resolution)) {
117 return (safe ? name : null);
118 }
119 else if (resolution != null) {
120 return (String) resolution;
121 }
122
123 try {
124 getClassLoader().loadClass(name);
125 resolutions.put(name,name);
126 return name;
127 } catch (ClassNotFoundException cnfe){
128 if (cnfe.getCause() instanceof MultipleCompilationErrorsException) {
129 MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) cnfe.getCause();
130 controller.getErrorCollector().addCollectorContents(mcee.getErrorCollector());
131 resolutions.put(name,name);
132 return name;
133 }
134 } catch (NoClassDefFoundError ncdfe) {
135 //fall through
136 }
137
138 do {
139 //
140 // If the type name contains a ".", it's probably fully
141 // qualified, and we don't take it to verification here.
142
143 if (name.indexOf(".") >= 0) {
144 resolution = name;
145 break; // <<< FLOW CONTROL <<<<<<<<<
146 }
147
148
149 //
150 // Otherwise, we'll need the scalar type for checking, and
151 // the postfix for reassembly.
152
153 String scalar = name, postfix = "";
154 while (scalar.endsWith("[]")) {
155 scalar = scalar.substring(0, scalar.length() - 2);
156 postfix += "[]";
157 }
158
159
160 //
161 // Primitive types are all valid...
162
163 if (Types.ofType(Types.lookupKeyword(scalar), Types.PRIMITIVE_TYPE)) {
164 resolution = name;
165 break; // <<< FLOW CONTROL <<<<<<<<<
166 }
167
168
169 //
170 // Next, check our imports and return the qualified name,
171 // if available.
172
173 if (this.imports.containsKey(scalar)) {
174 resolution = ((String) this.imports.get(scalar)) + postfix;
175 break; // <<< FLOW CONTROL <<<<<<<<<
176 }
177
178
179 //
180 // Next, see if our class loader can resolve it in the current package.
181
182 if (packageName != null && packageName.length() > 0) {
183 try {
184 getClassLoader().loadClass(dot(packageName, scalar));
185 resolution = dot(packageName, name);
186
187 break; // <<< FLOW CONTROL <<<<<<<<<
188 } catch (ClassNotFoundException cnfe){
189 if (cnfe.getCause() instanceof CompilationFailedException) {
190 resolution = dot(packageName, name);
191 break;
192 }
193 } catch (NoClassDefFoundError ncdfe) {
194 //fall through
195 }
196 }
197
198 // search the package imports path
199 List packageImports = output.getImportPackages();
200 for (int i = 0; i < packageImports.size(); i++) {
201 String pack = (String) packageImports.get(i);
202 String clsName = pack + name;
203 try {
204 getClassLoader().loadClass(clsName);
205 resolution = clsName;
206 break;
207 } catch (ClassNotFoundException cnfe){
208 if (cnfe.getCause() instanceof CompilationFailedException) {
209 resolution = clsName;
210 break;
211 }
212 } catch (NoClassDefFoundError ncdfe) {
213 //fall through
214 }
215 }
216 if (resolution != null) {
217 break;
218 }
219
220 //
221 // Last chance, check the default imports.
222
223 for (int i = 0; i < DEFAULT_IMPORTS.length; i++) {
224 String qualified = DEFAULT_IMPORTS[i] + scalar;
225 try {
226 getClassLoader().loadClass(qualified);
227
228 resolution = qualified + postfix;
229 break; // <<< FLOW CONTROL <<<<<<<<<
230 } catch (ClassNotFoundException cnfe){
231 if (cnfe.getCause() instanceof CompilationFailedException) {
232 resolution = qualified + postfix;
233 break;
234 }
235 } catch (NoClassDefFoundError ncdfee) {
236 // fall through
237 }
238 }
239
240 }
241 while (false);
242
243
244 //
245 // Cache the solution and return it
246
247 if (resolution == null) {
248 resolutions.put(name, NOT_RESOLVED);
249 return (safe ? name : null);
250 }
251 else {
252 resolutions.put(name, resolution);
253 return resolution;
254 }
255 }
256 */
257
258 /***
259 * Returns two names joined by a dot. If the base name is
260 * empty, returns the name unchanged.
261 */
262 public static String dot(String base, String name) {
263 if (base != null && base.length() > 0) {
264 return base + "." + name;
265 }
266
267 return name;
268 }
269
270 protected void makeModule() {
271 this.newClasses.clear();
272 this.output = new ModuleNode(controller);
273 resolutions.clear();
274 }
275
276 /***
277 * A synonym for <code>dot( base, "" )</code>.
278 */
279 protected String dot(String base) {
280 return dot(base, "");
281 }
282
283 /*protected String resolveNewClassOrName(String name, boolean safe) {
284 if (this.newClasses.contains(name)) {
285 return dot(packageName, name);
286 }
287 else {
288 return resolveName(name, safe);
289 }
290 }*/
291
292 protected void addNewClassName(String name) {
293 this.newClasses.add(name);
294 }
295
296 protected void importClass(ClassNode type, String name, String as) {
297 if (as==null) as=name;
298
299 output.addImport(as, type);
300 imports.put(as, type);
301 }
302
303 protected void importPackageWithStar(String importPackage) {
304 String[] classes = output.addImportPackage( dot(importPackage) );
305 for( int i = 0; i < classes.length; i++ )
306 {
307 imports.put( classes[i], dot(importPackage, classes[i]) );
308 }
309 }
310 }