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