001: /**
002: *
003: * Copyright 2004 James Strachan
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: **/package org.codehaus.groovy.syntax;
018:
019: import org.codehaus.groovy.ast.ClassNode;
020: import org.codehaus.groovy.ast.ModuleNode;
021: import org.codehaus.groovy.control.SourceUnit;
022:
023: import java.util.ArrayList;
024: import java.util.HashMap;
025: import java.util.List;
026: import java.util.Map;
027:
028: /**
029: * A common base class of AST helper methods which can be shared across the classic and new parsers
030: *
031: * @author Jochen Theodorou
032: * @author James Strachan
033: * @author Bob McWhirter
034: * @author Sam Pullara
035: * @author Chris Poirier
036: * @version $Revision: 4032 $
037: */
038: public class ASTHelper {
039:
040: private static final String[] EMPTY_STRING_ARRAY = new String[0];
041:
042: /** The SourceUnit controlling us */
043: private SourceUnit controller;
044:
045: /** Our ClassLoader, which provides information on external types */
046: private ClassLoader classLoader;
047:
048: /** Our imports, simple name => fully qualified name */
049: private Map imports;
050: protected ModuleNode output;
051:
052: /** The package name in which the module sits */
053: private String packageName; //
054:
055: // TODO should this really be static???
056: protected static HashMap resolutions = new HashMap(); // cleared on build(), to be safe
057:
058: private static String NOT_RESOLVED = new String();
059:
060: /** temporarily store the class names that the current modulenode contains */
061: private List newClasses = new ArrayList();
062:
063: public ASTHelper(SourceUnit controller, ClassLoader classLoader) {
064: this ();
065: this .controller = controller;
066: this .classLoader = classLoader;
067: }
068:
069: public ASTHelper() {
070: imports = new HashMap();
071: }
072:
073: public String getPackageName() {
074: return packageName;
075: }
076:
077: public void setPackageName(String packageName) {
078: this .packageName = packageName;
079: if (packageName != null && packageName.length() > 0) {
080: packageName += '.';
081: }
082: output.setPackageName(packageName);
083: }
084:
085: /**
086: * Returns our class loader (as supplied on construction).
087: */
088: public ClassLoader getClassLoader() {
089: return classLoader;
090: }
091:
092: public void setClassLoader(ClassLoader classLoader) {
093: this .classLoader = classLoader;
094: }
095:
096: public SourceUnit getController() {
097: return controller;
098: }
099:
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: /* protected String resolveName(String name, boolean safe) {
109: //
110: // Use our cache of resolutions, if possible
111:
112: String resolution = (String) resolutions.get(name);
113: if (NOT_RESOLVED.equals(resolution)) {
114: return (safe ? name : null);
115: }
116: else if (resolution != null) {
117: return (String) resolution;
118: }
119:
120: try {
121: getClassLoader().loadClass(name);
122: resolutions.put(name,name);
123: return name;
124: } catch (ClassNotFoundException cnfe){
125: if (cnfe.getCause() instanceof MultipleCompilationErrorsException) {
126: MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) cnfe.getCause();
127: controller.getErrorCollector().addCollectorContents(mcee.getErrorCollector());
128: resolutions.put(name,name);
129: return name;
130: }
131: } catch (NoClassDefFoundError 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 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) 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 cnfe){
186: if (cnfe.getCause() instanceof CompilationFailedException) {
187: resolution = dot(packageName, name);
188: break;
189: }
190: } catch (NoClassDefFoundError ncdfe) {
191: //fall through
192: }
193: }
194:
195: // search the package imports path
196: List packageImports = output.getImportPackages();
197: for (int i = 0; i < packageImports.size(); i++) {
198: String pack = (String) packageImports.get(i);
199: String clsName = pack + name;
200: try {
201: getClassLoader().loadClass(clsName);
202: resolution = clsName;
203: break;
204: } catch (ClassNotFoundException cnfe){
205: if (cnfe.getCause() instanceof CompilationFailedException) {
206: resolution = clsName;
207: break;
208: }
209: } catch (NoClassDefFoundError ncdfe) {
210: //fall through
211: }
212: }
213: if (resolution != null) {
214: break;
215: }
216:
217: //
218: // Last chance, check the default imports.
219:
220: for (int i = 0; i < DEFAULT_IMPORTS.length; i++) {
221: String qualified = DEFAULT_IMPORTS[i] + scalar;
222: try {
223: getClassLoader().loadClass(qualified);
224:
225: resolution = qualified + postfix;
226: break; // <<< FLOW CONTROL <<<<<<<<<
227: } catch (ClassNotFoundException cnfe){
228: if (cnfe.getCause() instanceof CompilationFailedException) {
229: resolution = qualified + postfix;
230: break;
231: }
232: } catch (NoClassDefFoundError ncdfee) {
233: // fall through
234: }
235: }
236:
237: }
238: while (false);
239:
240:
241: //
242: // Cache the solution and return it
243:
244: if (resolution == null) {
245: resolutions.put(name, NOT_RESOLVED);
246: return (safe ? name : null);
247: }
248: else {
249: resolutions.put(name, resolution);
250: return resolution;
251: }
252: }
253: */
254:
255: /**
256: * Returns two names joined by a dot. If the base name is
257: * empty, returns the name unchanged.
258: */
259: public static String dot(String base, String name) {
260: if (base != null && base.length() > 0) {
261: return base + "." + name;
262: }
263:
264: return name;
265: }
266:
267: protected void makeModule() {
268: this .newClasses.clear();
269: this .output = new ModuleNode(controller);
270: resolutions.clear();
271: }
272:
273: /**
274: * A synonym for <code>dot( base, "" )</code>.
275: */
276: protected String dot(String base) {
277: return dot(base, "");
278: }
279:
280: /*protected String resolveNewClassOrName(String name, boolean safe) {
281: if (this.newClasses.contains(name)) {
282: return dot(packageName, name);
283: }
284: else {
285: return resolveName(name, safe);
286: }
287: }*/
288:
289: protected void addNewClassName(String name) {
290: this .newClasses.add(name);
291: }
292:
293: protected void importClass(ClassNode type, String name, String as) {
294: if (as == null)
295: as = name;
296:
297: output.addImport(as, type);
298: imports.put(as, type);
299: }
300:
301: protected void importPackageWithStar(String importPackage) {
302: String[] classes = output.addImportPackage(dot(importPackage));
303: for (int i = 0; i < classes.length; i++) {
304: imports.put(classes[i], dot(importPackage, classes[i]));
305: }
306: }
307: }
|