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