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 }