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.parser;
19
20 import org.codehaus.groovy.ast.ModuleNode;
21 import org.codehaus.groovy.control.SourceUnit;
22 import org.codehaus.groovy.syntax.Types;
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 James Strachan
33 * @author Bob McWhirter
34 * @author Sam Pullara
35 * @author Chris Poirier
36 * @version $Revision: 1.3 $
37 */
38 public class ASTHelper {
39
40 private static final String[] EMPTY_STRING_ARRAY = new String[0];
41 private static final String[] DEFAULT_IMPORTS = {"java.lang.", "groovy.lang.", "groovy.util."};
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
57 protected static HashMap resolutions = new HashMap();
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
81 output.setPackageName(packageName);
82 }
83
84
85 /***
86 * Returns our class loader (as supplied on construction).
87 */
88 public ClassLoader getClassLoader() {
89 return classLoader;
90 }
91
92 public void setClassLoader(ClassLoader classLoader) {
93 this.classLoader = classLoader;
94 }
95
96 public SourceUnit getController() {
97 return controller;
98 }
99
100 public void setController(SourceUnit controller) {
101 this.controller = controller;
102 }
103
104 /***
105 * Returns a fully qualified name for any given potential type
106 * name. Returns null if no qualified name could be determined.
107 */
108
109 protected String resolveName(String name, boolean safe) {
110
111
112
113 String resolution = (String) resolutions.get(name);
114 if (NOT_RESOLVED.equals(resolution)) {
115 return (safe ? name : null);
116 }
117 else if (resolution != null) {
118 return (String) resolution;
119 }
120
121
122 do {
123
124
125
126
127 if (name.indexOf(".") >= 0) {
128 resolution = name;
129 break;
130 }
131
132
133
134
135
136
137 String scalar = name, postfix = "";
138 while (scalar.endsWith("[]")) {
139 scalar = scalar.substring(0, scalar.length() - 2);
140 postfix += "[]";
141 }
142
143
144
145
146
147 if (Types.ofType(Types.lookupKeyword(scalar), Types.PRIMITIVE_TYPE)) {
148 resolution = name;
149 break;
150 }
151
152
153
154
155
156
157 if (this.imports.containsKey(scalar)) {
158 resolution = ((String) this.imports.get(scalar)) + postfix;
159 break;
160 }
161
162
163
164
165
166 if (packageName != null && packageName.length() > 0) {
167 try {
168 getClassLoader().loadClass(dot(packageName, scalar));
169 resolution = dot(packageName, name);
170
171 break;
172 }
173 catch (Throwable e) {
174
175 }
176 }
177
178
179 List packageImports = output.getImportPackages();
180 for (int i = 0; i < packageImports.size(); i++) {
181 String pack = (String) packageImports.get(i);
182 String clsName = pack + name;
183 try {
184 getClassLoader().loadClass(clsName);
185 resolution = clsName;
186 break;
187 }
188 catch (Throwable e) {
189
190 }
191 }
192 if (resolution != null) {
193 break;
194 }
195
196
197
198
199 for (int i = 0; i < DEFAULT_IMPORTS.length; i++) {
200 try {
201 String qualified = DEFAULT_IMPORTS[i] + scalar;
202 getClassLoader().loadClass(qualified);
203
204 resolution = qualified + postfix;
205 break;
206 }
207 catch (Throwable e) {
208
209 }
210 }
211
212 }
213 while (false);
214
215
216
217
218
219 if (resolution == null) {
220 resolutions.put(name, NOT_RESOLVED);
221 return (safe ? name : null);
222 }
223 else {
224 resolutions.put(name, resolution);
225 return resolution;
226 }
227 }
228
229 /***
230 * Returns two names joined by a dot. If the base name is
231 * empty, returns the name unchanged.
232 */
233
234 protected String dot(String base, String name) {
235 if (base != null && base.length() > 0) {
236 return base + "." + name;
237 }
238
239 return name;
240 }
241
242 protected void makeModule() {
243 this.newClasses.clear();
244 this.output = new ModuleNode(controller);
245 resolutions.clear();
246 }
247
248 /***
249 * Returns true if the specified name is a known type name.
250 */
251
252 protected boolean isDatatype(String name) {
253 return resolveName(name, false) != null;
254 }
255
256 /***
257 * A synonym for <code>dot( base, "" )</code>.
258 */
259
260 protected String dot(String base) {
261 return dot(base, "");
262 }
263
264 protected String resolveNewClassOrName(String name, boolean safe) {
265 if (this.newClasses.contains(name)) {
266 return dot(packageName, name);
267 }
268 else {
269 return resolveName(name, safe);
270 }
271 }
272
273 protected void addNewClassName(String name) {
274 this.newClasses.add(name);
275 }
276
277 protected void importClass(String importPackage, String name, String as) {
278
279
280
281
282
283
284
285
286
287 output.addImport( as, name );
288
289 name = dot( importPackage, name );
290
291
292 imports.put( as, name );
293 }
294
295 protected void importPackageWithStar(String importPackage) {
296 String[] classes = output.addImportPackage( dot(importPackage) );
297 for( int i = 0; i < classes.length; i++ )
298 {
299 imports.put( classes[i], dot(importPackage, classes[i]) );
300 }
301 }
302 }