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 **/ 018 package org.codehaus.groovy.syntax; 019 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 James Strachan 032 * @author Bob McWhirter 033 * @author Sam Pullara 034 * @author Chris Poirier 035 * @version $Revision: 1.9 $ 036 */ 037 public class ASTHelper { 038 039 private static final String[] EMPTY_STRING_ARRAY = new String[0]; 040 041 /** The SourceUnit controlling us */ 042 private SourceUnit controller; 043 044 /** Our ClassLoader, which provides information on external types */ 045 private ClassLoader classLoader; 046 047 /** Our imports, simple name => fully qualified name */ 048 private Map imports; 049 protected ModuleNode output; 050 051 /** The package name in which the module sits */ 052 private String packageName; // 053 054 // TODO should this really be static??? 055 protected static HashMap resolutions = new HashMap(); // cleared on build(), to be safe 056 057 private static String NOT_RESOLVED = new String(); 058 059 /** temporarily store the class names that the current modulenode contains */ 060 private List newClasses = new ArrayList(); 061 062 public ASTHelper(SourceUnit controller, ClassLoader classLoader) { 063 this(); 064 this.controller = controller; 065 this.classLoader = classLoader; 066 } 067 068 public ASTHelper() { 069 imports = new HashMap(); 070 } 071 072 public String getPackageName() { 073 return packageName; 074 } 075 076 public void setPackageName(String packageName) { 077 this.packageName = packageName; 078 if (packageName!=null && packageName.length()>0){ 079 packageName+='.'; 080 } 081 output.setPackageName(packageName); 082 } 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(String importPackage, String name, String as) { 294 if (as==null) as=name; 295 296 name = dot( importPackage, name ); 297 298 output.addImport( as, name ); 299 imports.put( as, name ); 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 }