View Javadoc

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      privateong> 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      publicong> 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 }