Clover coverage report - groovy - 1.0-beta-6
Coverage timestamp: Thu Jul 15 2004 13:18:22 BST
file stats: LOC: 2,308   Methods: 65
NCLOC: 1,273   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
ASTBuilder.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  $Id: ASTBuilder.java,v 1.105 2004/07/10 03:31:43 bran Exp $
 3   
 
 4   
  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
 5   
 
 6   
  Redistribution and use of this software and associated documentation
 7   
  ("Software"), with or without modification, are permitted provided
 8   
  that the following conditions are met:
 9   
 
 10   
  1. Redistributions of source code must retain copyright
 11   
     statements and notices.  Redistributions must also contain a
 12   
     copy of this document.
 13   
 
 14   
  2. Redistributions in binary form must reproduce the
 15   
     above copyright notice, this list of conditions and the
 16   
     following disclaimer in the documentation and/or other
 17   
     materials provided with the distribution.
 18   
 
 19   
  3. The name "groovy" must not be used to endorse or promote
 20   
     products derived from this Software without prior written
 21   
     permission of The Codehaus.  For written permission,
 22   
     please contact info@codehaus.org.
 23   
 
 24   
  4. Products derived from this Software may not be called "groovy"
 25   
     nor may "groovy" appear in their names without prior written
 26   
     permission of The Codehaus. "groovy" is a registered
 27   
     trademark of The Codehaus.
 28   
 
 29   
  5. Due credit should be given to The Codehaus -
 30   
     http://groovy.codehaus.org/
 31   
 
 32   
  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
 33   
  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
 34   
  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 35   
  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
 36   
  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 37   
  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 38   
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 39   
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 40   
  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 41   
  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 42   
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 43   
  OF THE POSSIBILITY OF SUCH DAMAGE.
 44   
 
 45   
  */
 46   
 package org.codehaus.groovy.syntax.parser;
 47   
 
 48   
 import java.util.HashMap;
 49   
 import java.util.Map;
 50   
 import java.util.List;
 51   
 import java.util.ArrayList;
 52   
 
 53   
 import org.codehaus.groovy.ast.ClassNode;
 54   
 import org.codehaus.groovy.ast.InnerClassNode;
 55   
 import org.codehaus.groovy.ast.ConstructorNode;
 56   
 import org.codehaus.groovy.ast.MethodNode;
 57   
 import org.codehaus.groovy.ast.MixinNode;
 58   
 import org.codehaus.groovy.ast.ModuleNode;
 59   
 import org.codehaus.groovy.ast.Parameter;
 60   
 import org.codehaus.groovy.ast.PropertyNode;
 61   
 import org.codehaus.groovy.ast.Type;
 62   
 import org.codehaus.groovy.ast.expr.ArrayExpression;
 63   
 import org.codehaus.groovy.ast.expr.BinaryExpression;
 64   
 import org.codehaus.groovy.ast.expr.BooleanExpression;
 65   
 import org.codehaus.groovy.ast.expr.CastExpression;
 66   
 import org.codehaus.groovy.ast.expr.ClassExpression;
 67   
 import org.codehaus.groovy.ast.expr.ClosureExpression;
 68   
 import org.codehaus.groovy.ast.expr.ConstantExpression;
 69   
 import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
 70   
 import org.codehaus.groovy.ast.expr.Expression;
 71   
 import org.codehaus.groovy.ast.expr.GStringExpression;
 72   
 import org.codehaus.groovy.ast.expr.ListExpression;
 73   
 import org.codehaus.groovy.ast.expr.MapExpression;
 74   
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 75   
 import org.codehaus.groovy.ast.expr.NegationExpression;
 76   
 import org.codehaus.groovy.ast.expr.NotExpression;
 77   
 import org.codehaus.groovy.ast.expr.PostfixExpression;
 78   
 import org.codehaus.groovy.ast.expr.PrefixExpression;
 79   
 import org.codehaus.groovy.ast.expr.PropertyExpression;
 80   
 import org.codehaus.groovy.ast.expr.RangeExpression;
 81   
 import org.codehaus.groovy.ast.expr.RegexExpression;
 82   
 import org.codehaus.groovy.ast.expr.TernaryExpression;
 83   
 import org.codehaus.groovy.ast.expr.TupleExpression;
 84   
 import org.codehaus.groovy.ast.expr.VariableExpression;
 85   
 import org.codehaus.groovy.ast.stmt.AssertStatement;
 86   
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 87   
 import org.codehaus.groovy.ast.stmt.BreakStatement;
 88   
 import org.codehaus.groovy.ast.stmt.CaseStatement;
 89   
 import org.codehaus.groovy.ast.stmt.CatchStatement;
 90   
 import org.codehaus.groovy.ast.stmt.ContinueStatement;
 91   
 import org.codehaus.groovy.ast.stmt.DoWhileStatement;
 92   
 import org.codehaus.groovy.ast.stmt.EmptyStatement;
 93   
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 94   
 import org.codehaus.groovy.ast.stmt.ForStatement;
 95   
 import org.codehaus.groovy.ast.stmt.IfStatement;
 96   
 import org.codehaus.groovy.ast.stmt.ReturnStatement;
 97   
 import org.codehaus.groovy.ast.stmt.Statement;
 98   
 import org.codehaus.groovy.ast.stmt.SwitchStatement;
 99   
 import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
 100   
 import org.codehaus.groovy.ast.stmt.ThrowStatement;
 101   
 import org.codehaus.groovy.ast.stmt.TryCatchStatement;
 102   
 import org.codehaus.groovy.ast.stmt.WhileStatement;
 103   
 import org.codehaus.groovy.control.SourceUnit;
 104   
 import org.codehaus.groovy.syntax.CSTNode;
 105   
 import org.codehaus.groovy.syntax.Token;
 106   
 import org.codehaus.groovy.syntax.Types;
 107   
 import org.codehaus.groovy.syntax.Numbers;
 108   
 import org.codehaus.groovy.GroovyBugError;
 109   
 import org.objectweb.asm.Constants;
 110   
 
 111   
 
 112   
 
 113   
 /**
 114   
  *  Builds an Abstract Syntax Tree from the Concrete Syntax Tree produced
 115   
  *  by the Parser.  The resulting AST is very preliminary, and must still
 116   
  *  be validated and massaged before it is ready to be used.
 117   
  *  <code>build()</code> is the primary entry point.
 118   
  *
 119   
  *  @author James Strachan
 120   
  *  @author Bob McWhirter
 121   
  *  @author Sam Pullara
 122   
  *  @author Chris Poirier
 123   
  */
 124   
 
 125   
 public class ASTBuilder
 126   
 {
 127   
 
 128   
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 129   
     private static final String[] DEFAULT_IMPORTS    = { "java.lang.", "groovy.lang.", "groovy.util." };
 130   
 
 131   
 
 132   
 
 133   
   //---------------------------------------------------------------------------
 134   
   // INITIALIZATION AND MEMBER ACCESS
 135   
 
 136   
 
 137   
     private SourceUnit  controller;    // The SourceUnit controlling us
 138   
     private ClassLoader classLoader;   // Our ClassLoader, which provides information on external types
 139   
     private Map         imports;       // Our imports, simple name => fully qualified name
 140   
     private String      packageName;   // The package name in which the module sits
 141   
     private List newClasses = new ArrayList(); // temporarily store the class names that the current modulenode contains
 142   
     private ModuleNode output;
 143   
 
 144   
 
 145   
     /**
 146   
     *  Initializes the <code>ASTBuilder</code>.
 147   
     */
 148   
 
 149  0
     public ASTBuilder( SourceUnit sourceUnit, ClassLoader classLoader )
 150   
     {
 151  0
         this.controller  = sourceUnit;
 152  0
         this.classLoader = classLoader;
 153  0
         this.imports     = new HashMap();
 154  0
         this.packageName = null;
 155   
     }
 156   
 
 157   
 
 158   
 
 159   
    /**
 160   
     *  Returns our class loader (as supplied on construction).
 161   
     */
 162   
 
 163  0
     public ClassLoader getClassLoader()
 164   
     {
 165  0
         return this.classLoader;
 166   
     }
 167   
 
 168   
 
 169   
 
 170   
 
 171   
   //---------------------------------------------------------------------------
 172   
   // ENTRY POINT
 173   
 
 174   
 
 175   
    /**
 176   
     *  Builds an AST ModuleNode from a Parser.module() Reduction.
 177   
     */
 178   
 
 179  0
     public ModuleNode build( CSTNode input ) throws ParserException
 180   
     {
 181  0
         this.newClasses.clear();
 182  0
         this.output = new ModuleNode( controller );
 183  0
         resolutions.clear();
 184   
 
 185   
         //
 186   
         // input structure:
 187   
         //    1: package
 188   
         //    2: imports
 189   
         //   3+: statements
 190   
 
 191  0
         packageName = packageDeclaration( input.get(1) );
 192  0
         output.setPackageName( packageName );
 193   
 
 194  0
         importStatements( output, input.get(2) );
 195   
 
 196  0
         for( int i = 3; i < input.size(); ++i )
 197   
         {
 198  0
             topLevelStatement( output, input.get(i) );
 199   
         }
 200   
 
 201  0
         if( output.isEmpty() )
 202   
         {
 203  0
             output.addStatement( new BlockStatement() );
 204   
         }
 205   
 
 206  0
         return output;
 207   
     }
 208   
 
 209   
 
 210   
 
 211   
 
 212   
   //---------------------------------------------------------------------------
 213   
   // DECLARATIONS
 214   
 
 215   
 
 216   
    /**
 217   
     *  Processes the Reduction produced by Parser.packageDeclaration().
 218   
     */
 219   
 
 220  0
     protected String packageDeclaration( CSTNode reduction )
 221   
     {
 222  0
         if( reduction.hasChildren() )
 223   
         {
 224  0
             return makeName( reduction.get(1) );
 225   
         }
 226   
 
 227  0
         return null;
 228   
 
 229   
     }
 230   
 
 231   
 
 232   
 
 233   
    /**
 234   
     *  Processes the imports Reduction produced by Parser.module().
 235   
     */
 236   
 
 237  0
     protected void importStatements( ModuleNode module, CSTNode container )
 238   
     {
 239  0
         for( int i = 1; i < container.size(); ++i)
 240   
         {
 241  0
             importStatement( module, container.get(i) );
 242   
         }
 243   
     }
 244   
 
 245   
 
 246   
 
 247   
    /**
 248   
     *  Processes the Reduction produced by Parser.importStatement().
 249   
     */
 250   
 
 251  0
     protected void importStatement( ModuleNode module, CSTNode reduction )
 252   
     {
 253   
         //
 254   
         // First, get the package name (if supplied).
 255   
 
 256  0
         String importPackage = makeName( reduction.get(1), null );
 257   
 
 258   
 
 259   
 
 260   
         //
 261   
         // If the first clause is Types.STAR, it's a package import.
 262   
 
 263  0
         if( reduction.get(2).isA(Types.STAR) )
 264   
         {
 265  0
             String[] classes = module.addImportPackage( dot(importPackage) );
 266  0
             for( int i = 0; i < classes.length; i++ )
 267   
             {
 268  0
                 imports.put( classes[i], dot(importPackage, classes[i]) );
 269   
             }
 270   
         }
 271   
 
 272   
 
 273   
         //
 274   
         // Otherwise, it's a series of specific imports.
 275   
 
 276   
         else
 277   
         {
 278  0
             for( int i = 2; i < reduction.size(); i++ )
 279   
             {
 280  0
                 CSTNode clause = reduction.get(i);
 281  0
                 String  name   = identifier( clause );
 282  0
                 String  as     = (clause.hasChildren() ? identifier(clause.get(1)) : name);
 283   
 
 284   
                 //
 285   
                 // There appears to be a bug in the previous code for
 286   
                 // single imports, in that the old code passed unqualified
 287   
                 // class names to module.addImport().  This hasn't been a
 288   
                 // problem apparently because those names are resolved here.
 289   
                 // Passing module.addImport() a fully qualified name does
 290   
                 // currently causes problems with classgen, possibly because
 291   
                 // of name collisions.  So, for now, we use the old method...
 292   
 
 293  0
                 module.addImport( as, name );  // unqualified
 294   
 
 295  0
                 name = dot( importPackage, name );
 296   
 
 297   
                 // module.addImport( as, name );  // qualified
 298  0
                 imports.put( as, name );
 299   
             }
 300   
         }
 301   
     }
 302   
 
 303   
 
 304   
 
 305   
    /**
 306   
     *  Processes the Reduction produced by Parser.topLevelStatement().
 307   
     */
 308   
 
 309  0
     protected void topLevelStatement( ModuleNode module, CSTNode reduction ) throws ParserException
 310   
     {
 311  0
         int type = reduction.getMeaning();
 312  0
         switch( type )
 313   
         {
 314   
             case Types.SYNTH_CLASS:
 315  0
                 module.addClass( classDeclaration(null, reduction) );
 316  0
                 break;
 317   
 
 318   
             case Types.SYNTH_INTERFACE:
 319  0
                 module.addClass( interfaceDeclaration(null, reduction) );
 320  0
                 break;
 321   
 
 322   
             case Types.SYNTH_METHOD:
 323  0
                 module.addMethod( methodDeclaration(null, reduction) );
 324  0
                 break;
 325   
 
 326   
             default:
 327  0
                 module.addStatement( statement(reduction) );
 328  0
                 break;
 329   
         }
 330   
 
 331   
     }
 332   
 
 333   
 
 334   
 
 335   
    /**
 336   
     *  Processes the Reduction produced by Parser.classDeclaration().
 337   
     */
 338   
 
 339  0
     protected ClassNode classDeclaration( ClassNode context, CSTNode reduction ) throws ParserException
 340   
     {
 341   
         //
 342   
         // Calculate the easy stuff
 343   
 
 344  0
         String   name = identifier( reduction );
 345  0
         this.newClasses.add(name);
 346  0
         int modifiers = modifiers( reduction.get(1) );
 347  0
         String parent = resolveName( reduction.get(2).get(1) );
 348   
 
 349   
 
 350   
         //
 351   
         // Then process the interface list.
 352   
 
 353  0
         CSTNode  interfaceReduction = reduction.get(3);
 354  0
         String[] interfaces = new String[interfaceReduction.children()];
 355  0
         for( int i = 1; i < interfaceReduction.size(); i++ )
 356   
         {
 357  0
             interfaces[i-1] = resolveName( interfaceReduction.get(i) );
 358   
         }
 359   
 
 360   
 
 361   
         //
 362   
         // Create the class.
 363   
 
 364  0
         ClassNode classNode = (
 365  0
             context == null
 366   
                 ? new ClassNode(               dot(packageName, name), modifiers, parent, interfaces, MixinNode.EMPTY_ARRAY )
 367   
                 : new InnerClassNode( context, dot(packageName, name), modifiers, parent, interfaces, MixinNode.EMPTY_ARRAY )
 368   
         );
 369   
 
 370  0
         classNode.setCSTNode( reduction.get(0) );
 371  0
         typeBody( classNode, reduction.get(4), 0, 0 );
 372  0
         return classNode;
 373   
     }
 374   
 
 375   
 
 376   
 
 377   
    /**
 378   
     *  Processes a type body for classDeclaration() and others.
 379   
     */
 380   
 
 381  0
     protected void typeBody( ClassNode classNode, CSTNode body, int propertyModifiers, int methodModifiers ) throws ParserException
 382   
     {
 383  0
         for( int i = 1; i < body.size(); i++ )
 384   
         {
 385  0
             CSTNode statement = body.get(i);
 386  0
             switch( statement.getMeaning() )
 387   
             {
 388   
                 case Types.SYNTH_PROPERTY:
 389  0
                     addPropertyDeclaration( classNode, statement, propertyModifiers );
 390  0
                     break;
 391   
 
 392   
                 case Types.SYNTH_METHOD:
 393  0
                     methodDeclaration( classNode, statement, methodModifiers );
 394  0
                     break;
 395   
 
 396   
                 case Types.SYNTH_CLASS:
 397  0
                     classDeclaration( classNode, statement );
 398  0
                     break;
 399   
 
 400   
                 case Types.SYNTH_INTERFACE:
 401  0
                     interfaceDeclaration( classNode, statement );
 402  0
                     break;
 403   
 
 404   
                 default:
 405  0
                     throw new GroovyBugError( "unrecognized type body statement [" + statement.toString() + "]" );
 406   
             }
 407   
         }
 408   
     }
 409   
 
 410   
 
 411   
 
 412   
    /**
 413   
     *  Processes the Reduction produced by Parser.propertyDeclaration().
 414   
     *  Adds the property to the supplied class.
 415   
     */
 416   
 
 417  0
     protected void addPropertyDeclaration( ClassNode classNode, CSTNode reduction, int extraModifiers ) throws ParserException
 418   
     {
 419  0
         String   name = identifier( reduction );
 420  0
         int modifiers = modifiers( reduction.get(1) ) | extraModifiers;
 421  0
         String   type = resolveName( reduction.get(2) );
 422   
 
 423  0
         Expression value = reduction.size() > 3 ? expression(reduction.get(3)) : null;
 424   
 
 425  0
         PropertyNode propertyNode = classNode.addProperty( name, modifiers, type, value, null, null );
 426  0
         propertyNode.setCSTNode( reduction.get(0) );
 427   
 
 428   
     }
 429   
 
 430   
 
 431   
 
 432   
    /**
 433   
     *  A synonym for <code>addPropertyDeclaration( classNode, reduction, 0 )</code>.
 434   
     */
 435   
 
 436  0
     protected void addPropertyDeclaration( ClassNode classNode, CSTNode reduction ) throws ParserException
 437   
     {
 438  0
         addPropertyDeclaration( classNode, reduction, 0 );
 439   
     }
 440   
 
 441   
 
 442   
 
 443   
    /**
 444   
     *  Processes the Reduction produced by Parser.methodDeclaration().
 445   
     *  Adds the method to the supplied class.
 446   
     */
 447   
 
 448  0
     protected MethodNode methodDeclaration( ClassNode classNode, CSTNode reduction, int extraModifiers ) throws ParserException
 449   
     {
 450  0
         String className = null;
 451  0
         if( classNode != null  )
 452   
         {
 453  0
             className = classNode.getNameWithoutPackage();
 454   
         }
 455   
 
 456   
 
 457   
         //
 458   
         // Get the basic method data
 459   
 
 460  0
         String   name = identifier( reduction );
 461  0
         int modifiers = modifiers( reduction.get(1) ) | extraModifiers;
 462  0
         String   type = resolveName( reduction.get(2) );
 463   
 
 464  0
         Parameter[] parameters = parameterDeclarations( reduction.get(3) );
 465  0
         BlockStatement    body = statementBody( reduction.get(5) );
 466   
 
 467   
 
 468   
         //
 469   
         // Process the throws clause
 470   
 
 471  0
         CSTNode  clause     = reduction.get(4);
 472  0
         String[] throwTypes = new String[clause.children()];
 473  0
         for( int i = 1; i < clause.size(); i++ )
 474   
         {
 475  0
             throwTypes[i-1] = resolveName( clause.get(i) );
 476   
         }
 477   
 
 478  0
         if( clause.hasChildren() ) { throw new GroovyBugError( "NOT YET IMPLEMENTED: throws clause" ); }
 479   
 
 480   
 
 481   
         //
 482   
         // An unnamed method is a static initializer
 483   
 
 484  0
         if( name.length() == 0 )
 485   
         {
 486  0
             throw new GroovyBugError( "NOT YET IMPLEMENTED: static initializers" );
 487   
 
 488   
             /*
 489   
 
 490   
             ConstructorNode node = new ConstructorNode( modifiers | Constants.ACC_STATIC, parameters, body );
 491   
             node.setCSTNode( reduction.get(0) );
 492   
 
 493   
             classNode.addConstructor( node );
 494   
             return null;
 495   
 
 496   
             */
 497   
         }
 498   
 
 499   
 
 500   
         //
 501   
         // A method with the class name is a constructor
 502   
 
 503  0
         else if( className != null && name.equals(className) )
 504   
         {
 505  0
             ConstructorNode node = new ConstructorNode( modifiers, parameters, body );
 506  0
             node.setCSTNode( reduction.get(0) );
 507   
 
 508  0
             classNode.addConstructor( node );
 509  0
             return null;
 510   
         }
 511   
 
 512   
 
 513   
         //
 514   
         // Anything else is a plain old method
 515   
 
 516   
         else
 517   
         {
 518  0
             MethodNode method = new MethodNode( name, modifiers, type, parameters, body );
 519  0
             method.setCSTNode( reduction.get(0) );
 520   
 
 521  0
             if( classNode != null )
 522   
             {
 523  0
                 classNode.addMethod( method );
 524   
             }
 525   
 
 526  0
             return method;
 527   
         }
 528   
 
 529   
     }
 530   
 
 531   
 
 532   
 
 533   
    /**
 534   
     *  A synonym for <code>methodDeclaration( classNode, reduction, 0 )</code>.
 535   
     */
 536   
 
 537  0
     protected MethodNode methodDeclaration( ClassNode classNode, CSTNode reduction ) throws ParserException
 538   
     {
 539  0
         return methodDeclaration( classNode, reduction, 0 );
 540   
     }
 541   
 
 542   
 
 543   
 
 544   
    /**
 545   
     *  Processes the Reduction produced by Parser.parameterDeclarationList().
 546   
     */
 547   
 
 548  0
     protected Parameter[] parameterDeclarations( CSTNode reduction ) throws ParserException
 549   
     {
 550  0
         Parameter[] parameters = new Parameter[ reduction.children() ];
 551   
 
 552  0
         for( int i = 1; i < reduction.size(); i++ )
 553   
         {
 554  0
             CSTNode node = reduction.get(i);
 555   
 
 556  0
             String identifier = identifier( node );
 557  0
             String type       = resolveName( node.get(1) );
 558   
 
 559  0
             if( node.size() > 2 )
 560   
             {
 561  0
                 parameters[i-1] = new Parameter( type, identifier, expression(node.get(2)) );
 562   
             }
 563   
             else
 564   
             {
 565  0
                 parameters[i-1] = new Parameter( type, identifier );
 566   
             }
 567   
         }
 568   
 
 569  0
         return parameters;
 570   
 
 571   
     }
 572   
 
 573   
 
 574   
 
 575   
    /**
 576   
     * Processes the Reduction produced by Parser.interfaceDeclaration().
 577   
     */
 578   
 
 579  0
     protected ClassNode interfaceDeclaration( ClassNode context, CSTNode reduction ) throws ParserException
 580   
     {
 581  0
         throw new GroovyBugError( "NOT YET IMPLEMENTED: interfaces" );
 582   
 
 583   
         /*
 584   
 
 585   
         //
 586   
         // Calculate the easy stuff
 587   
 
 588   
         String   name = identifier( reduction );
 589   
         int modifiers = modifiers( reduction.get(1) ) | Constants.ACC_ABSTRACT | Constants.ACC_STATIC;
 590   
         String parent = null;
 591   
 
 592   
 
 593   
         //
 594   
         // Then process the interface list.
 595   
 
 596   
         CSTNode  interfaceReduction = reduction.get(3);
 597   
         String[] interfaces = new String[interfaceReduction.children()];
 598   
         for( int i = 1; i < interfaceReduction.size(); i++ )
 599   
         {
 600   
             interfaces[i-1] = resolveName( interfaceReduction.get(i) );
 601   
         }
 602   
 
 603   
 
 604   
         //
 605   
         // Create the interface.
 606   
 
 607   
         ClassNode classNode = (
 608   
             context == null
 609   
                 ? new ClassNode(               dot(packageName, name), modifiers, parent, interfaces, MixinNode.EMPTY_ARRAY )
 610   
                 : new InnerClassNode( context, dot(packageName, name), modifiers, parent, interfaces, MixinNode.EMPTY_ARRAY )
 611   
         );
 612   
 
 613   
         classNode.setCSTNode( reduction.get(0) );
 614   
 
 615   
         int propertyModifiers = Constants.ACC_STATIC | Constants.ACC_FINAL | Constants.ACC_PUBLIC;
 616   
         int methodModifiers   = Constants.ACC_ABSTRACT;
 617   
 
 618   
         typeBody( classNode, reduction.get(4), propertyModifiers, methodModifiers );
 619   
 
 620   
 
 621   
         return classNode;
 622   
 
 623   
         */
 624   
     }
 625   
 
 626   
 
 627   
 
 628   
 
 629   
   //---------------------------------------------------------------------------
 630   
   // STATEMENTS
 631   
 
 632   
 
 633   
    /**
 634   
     *  Processes the Reduction that results from Parser.statementBody().
 635   
     */
 636   
 
 637  0
     protected BlockStatement statementBody( CSTNode reduction ) throws ParserException
 638   
     {
 639  0
         if( reduction.isEmpty() )
 640   
         {
 641  0
             return new BlockStatement();
 642   
         }
 643  0
         else if( reduction.getMeaning() == Types.LEFT_CURLY_BRACE )
 644   
         {
 645  0
             return statementBlock( reduction );
 646   
         }
 647   
         else
 648   
         {
 649  0
             Statement statement = statement( reduction );
 650  0
             statement.setCSTNode( reduction );
 651   
 
 652  0
             BlockStatement block = null;
 653  0
             if( statement instanceof BlockStatement )
 654   
             {
 655  0
                 block = (BlockStatement)statement;
 656   
             }
 657   
             else
 658   
             {
 659  0
                 block = new BlockStatement();
 660  0
                 block.addStatement( statement );
 661   
             }
 662   
 
 663  0
             return block;
 664   
         }
 665   
     }
 666   
 
 667   
 
 668   
 
 669   
    /**
 670   
     *  Processes any series of statements, starting at the specified offset
 671   
     *  and running to the end of the CSTNode.
 672   
     */
 673   
 
 674  0
     protected BlockStatement statements( CSTNode reduction, int first ) throws ParserException
 675   
     {
 676  0
         BlockStatement block = new BlockStatement();
 677   
 
 678  0
         for( int i = first; i < reduction.size(); i++ )
 679   
         {
 680  0
             CSTNode statementReduction = reduction.get(i);
 681   
 
 682  0
             Statement statement = statement( statementReduction );
 683  0
             statement.setCSTNode( statementReduction );
 684   
 
 685  0
             block.addStatement( statement );
 686   
         }
 687   
 
 688  0
         return block;
 689   
     }
 690   
 
 691   
 
 692   
 
 693   
    /**
 694   
     *  Processes any statement block.
 695   
     */
 696   
 
 697  0
     protected BlockStatement statementBlock( CSTNode reduction ) throws ParserException
 698   
     {
 699  0
         return statements( reduction, 1 );
 700   
     }
 701   
 
 702   
 
 703   
 
 704   
    /**
 705   
     *  Processes the Reduction produced by Parser.statement().
 706   
     */
 707   
 
 708  0
     protected Statement statement( CSTNode reduction ) throws ParserException
 709   
     {
 710  0
         Statement statement = null;
 711   
 
 712   
         //
 713   
         // Convert the statement
 714   
 
 715  0
         switch( reduction.getMeaning() )
 716   
         {
 717   
             case Types.KEYWORD_ASSERT:
 718   
             {
 719  0
                 statement = assertStatement( reduction );
 720  0
                 break;
 721   
             }
 722   
 
 723   
             case Types.KEYWORD_BREAK:
 724   
             {
 725  0
                 statement = breakStatement( reduction );
 726  0
                 break;
 727   
             }
 728   
 
 729   
             case Types.KEYWORD_CONTINUE:
 730   
             {
 731  0
                 statement = continueStatement( reduction );
 732  0
                 break;
 733   
             }
 734   
 
 735   
             case Types.KEYWORD_IF:
 736   
             {
 737  0
                 statement = ifStatement( reduction );
 738  0
                 break;
 739   
             }
 740   
 
 741   
             case Types.KEYWORD_RETURN:
 742   
             {
 743  0
                 statement = returnStatement( reduction );
 744  0
                 break;
 745   
             }
 746   
 
 747   
             case Types.KEYWORD_SWITCH:
 748   
             {
 749  0
                 statement = switchStatement( reduction );
 750  0
                 break;
 751   
             }
 752   
 
 753   
             case Types.KEYWORD_SYNCHRONIZED:
 754   
             {
 755  0
                 statement = synchronizedStatement( reduction );
 756  0
                 break;
 757   
             }
 758   
 
 759   
             case Types.KEYWORD_THROW:
 760   
             {
 761  0
                 statement = throwStatement( reduction );
 762  0
                 break;
 763   
             }
 764   
 
 765   
             case Types.KEYWORD_TRY:
 766   
             {
 767  0
                 statement = tryStatement( reduction );
 768  0
                 break;
 769   
             }
 770   
 
 771   
             case Types.KEYWORD_FOR:
 772   
             {
 773  0
                 statement = forStatement( reduction );
 774  0
                 break;
 775   
             }
 776   
 
 777   
             case Types.KEYWORD_WHILE:
 778   
             {
 779  0
                 statement = whileStatement( reduction );
 780  0
                 break;
 781   
             }
 782   
 
 783   
             case Types.KEYWORD_DO:
 784   
             {
 785  0
                 statement = doWhileStatement( reduction );
 786  0
                 break;
 787   
             }
 788   
 
 789   
             case Types.SYNTH_BLOCK:
 790   
             case Types.LEFT_CURLY_BRACE:
 791   
             {
 792  0
                 statement = statementBlock( reduction );
 793  0
                 break;
 794   
             }
 795   
 
 796   
             case Types.SYNTH_LABEL:
 797   
             {
 798  0
                 statement = statement( reduction.get(1) );
 799  0
                 statement.setStatementLabel( identifier(reduction) );
 800  0
                 break;
 801   
             }
 802   
 
 803   
             case Types.SYNTH_CLOSURE:
 804   
             default:
 805   
             {
 806  0
                 statement = expressionStatement( reduction );
 807  0
                 break;
 808   
             }
 809   
 
 810   
         }
 811   
 
 812   
 
 813  0
         statement.setCSTNode( reduction );
 814  0
         return statement;
 815   
     }
 816   
 
 817   
 
 818   
 
 819   
    /**
 820   
     *  Processes the Reduction produced by Parser.assertStatement().
 821   
     */
 822   
 
 823  0
     protected AssertStatement assertStatement( CSTNode reduction ) throws ParserException
 824   
     {
 825  0
         BooleanExpression expression = new BooleanExpression( expression(reduction.get(1)) );
 826   
 
 827  0
         if( reduction.children() > 1 )
 828   
         {
 829  0
             return new AssertStatement( expression, expression(reduction.get(2)) );
 830   
         }
 831   
 
 832  0
         return new AssertStatement( expression, ConstantExpression.NULL );
 833   
     }
 834   
 
 835   
 
 836   
 
 837   
    /**
 838   
     *  Processes the Reduction produced by Parser.breakStatement().
 839   
     */
 840   
 
 841  0
     protected BreakStatement breakStatement( CSTNode reduction ) throws ParserException
 842   
     {
 843  0
         if( reduction.hasChildren() )
 844   
         {
 845  0
             return new BreakStatement( reduction.get(1).getRootText() );
 846   
         }
 847   
 
 848  0
         return new BreakStatement();
 849   
     }
 850   
 
 851   
 
 852   
 
 853   
    /**
 854   
     *  Processes the Reduction produced by Parser.continueStatement().
 855   
     */
 856   
 
 857  0
     protected ContinueStatement continueStatement( CSTNode reduction ) throws ParserException
 858   
     {
 859   
 
 860  0
         if( reduction.hasChildren() )
 861   
         {
 862  0
             return new ContinueStatement( reduction.get(1).getRootText() );
 863   
         }
 864   
 
 865  0
         return new ContinueStatement();
 866   
     }
 867   
 
 868   
 
 869   
 
 870   
    /**
 871   
     *  Processes the Reduction produced by Parser.ifStatement().
 872   
     */
 873   
 
 874  0
     protected IfStatement ifStatement( CSTNode reduction ) throws ParserException
 875   
     {
 876  0
         Expression condition = expression( reduction.get(1) );
 877  0
         BlockStatement  body = statementBody( reduction.get(2) );
 878  0
         Statement  elseBlock = EmptyStatement.INSTANCE;
 879   
 
 880  0
         if( reduction.size() > 3 )
 881   
         {
 882  0
             CSTNode elseReduction = reduction.get(3);
 883  0
             if( elseReduction.getMeaning() == Types.KEYWORD_IF )
 884   
             {
 885  0
                 elseBlock = ifStatement( elseReduction );
 886   
             }
 887   
             else
 888   
             {
 889  0
                 elseBlock = statementBody( elseReduction.get(1) );
 890   
             }
 891   
 
 892   
         }
 893   
 
 894  0
         return new IfStatement( new BooleanExpression(condition), body, elseBlock );
 895   
     }
 896   
 
 897   
 
 898   
 
 899   
    /**
 900   
     *  Processes the Reduction produced by Parser.returnStatement().
 901   
     */
 902   
 
 903  0
     protected ReturnStatement returnStatement( CSTNode reduction ) throws ParserException
 904   
     {
 905  0
         if( reduction.hasChildren() )
 906   
         {
 907  0
             return new ReturnStatement( expression(reduction.get(1)) );
 908   
         }
 909   
 
 910  0
         return ReturnStatement.RETURN_NULL_OR_VOID;
 911   
     }
 912   
 
 913   
 
 914   
 
 915   
    /**
 916   
     *  Processes the Reduction produced by Parser.switchStatement().
 917   
     */
 918   
 
 919  0
     protected SwitchStatement switchStatement( CSTNode reduction ) throws ParserException
 920   
     {
 921  0
         SwitchStatement statement = new SwitchStatement( expression(reduction.get(1)) );
 922   
 
 923  0
         for( int i = 2; i < reduction.size(); i++ )
 924   
         {
 925  0
             CSTNode child = reduction.get(i);
 926   
 
 927  0
             switch( child.getMeaning() )
 928   
             {
 929   
 
 930   
                 case Types.KEYWORD_CASE:
 931  0
                     statement.addCase( caseStatement(child) );
 932  0
                     break;
 933   
 
 934   
                 case Types.KEYWORD_DEFAULT:
 935  0
                     statement.setDefaultStatement( statementBlock(child) );
 936  0
                     break;
 937   
 
 938   
                 default:
 939  0
                     throw new GroovyBugError( "invalid something in switch [" + child + "]" );
 940   
             }
 941   
         }
 942   
 
 943  0
         return statement;
 944   
     }
 945   
 
 946   
 
 947   
 
 948   
    /**
 949   
     *  Processes the Reduction produced by Parser.switchStatement() for cases.
 950   
     */
 951   
 
 952  0
     protected CaseStatement caseStatement( CSTNode reduction ) throws ParserException
 953   
     {
 954  0
         return new CaseStatement( expression(reduction.get(1)), statements(reduction, 2) );
 955   
     }
 956   
 
 957   
 
 958   
 
 959   
    /**
 960   
     *  Processes the Reduction produced by Parser.synchronizedStatement().
 961   
     */
 962   
 
 963  0
     protected SynchronizedStatement synchronizedStatement( CSTNode reduction ) throws ParserException
 964   
     {
 965  0
         return new SynchronizedStatement( expression(reduction.get(1)), statementBody(reduction.get(2)) );
 966   
     }
 967   
 
 968   
 
 969   
 
 970   
    /**
 971   
     *  Processes the Reduction produced by Parser.throwStatement().
 972   
     */
 973   
 
 974  0
     protected ThrowStatement throwStatement( CSTNode reduction ) throws ParserException
 975   
     {
 976  0
         return new ThrowStatement( expression(reduction.get(1)) );
 977   
     }
 978   
 
 979   
 
 980   
 
 981   
    /**
 982   
     *  Processes the Reduction produced by Parser.tryStatement().
 983   
     */
 984   
 
 985  0
     protected TryCatchStatement tryStatement( CSTNode reduction ) throws ParserException
 986   
     {
 987  0
         BlockStatement         body = statementBody( reduction.get(1) );
 988  0
         BlockStatement finallyBlock = statementBody( reduction.get(3) );
 989   
 
 990  0
         TryCatchStatement statement = new TryCatchStatement( body, finallyBlock );
 991   
 
 992  0
         CSTNode catches = reduction.get(2);
 993  0
         for( int i = 1; i < catches.size(); i++ )
 994   
         {
 995  0
             CSTNode   element = catches.get(i);
 996  0
             String       type = resolveName( element.get(1) );
 997  0
             String identifier = identifier( element.get(2) );
 998   
 
 999  0
             statement.addCatch( new CatchStatement(type, identifier, statementBody(element.get(3))) );
 1000   
         }
 1001   
 
 1002  0
         return statement;
 1003   
     }
 1004   
 
 1005   
 
 1006   
 
 1007   
    /**
 1008   
     *  Processes the Reduction produced by Parser.forStatement().
 1009   
     */
 1010   
 
 1011  0
     protected ForStatement forStatement( CSTNode reduction ) throws ParserException
 1012   
     {
 1013  0
         CSTNode header = reduction.get(1);
 1014  0
         Statement body = statementBody( reduction.get(2) );
 1015   
 
 1016   
 
 1017   
         //
 1018   
         // If the header has type Types.UNKNOWN, it's a standard for loop.
 1019   
 
 1020  0
         if( header.getMeaning() == Types.UNKNOWN )
 1021   
         {
 1022  0
             Expression[] init = expressions( header.get(1) );
 1023  0
             Expression   test = expression(  header.get(2) );
 1024  0
             Expression[] incr = expressions( header.get(3) );
 1025   
 
 1026  0
             throw new GroovyBugError( "NOT YET IMPLEMENTED: standard for loop" );
 1027   
         }
 1028   
 
 1029   
 
 1030   
         //
 1031   
         // Otherwise, it's a for each loop.
 1032   
 
 1033   
         else
 1034   
         {
 1035   
 
 1036  0
             Type         type = typeExpression( header.get(1) );
 1037  0
             String identifier = identifier(  header.get(2) );
 1038  0
             Expression source = expression(  header.get(3) );
 1039   
 
 1040  0
             return new ForStatement( identifier, type, source, body );
 1041   
         }
 1042   
     }
 1043   
 
 1044   
 
 1045   
 
 1046   
    /**
 1047   
     *  Processes the Reduction produced by Parser.doWhileStatement().
 1048   
     */
 1049   
 
 1050  0
     protected DoWhileStatement doWhileStatement( CSTNode reduction ) throws ParserException
 1051   
     {
 1052  0
         Expression condition = expression( reduction.get(2) );
 1053  0
         BlockStatement  body = statementBody( reduction.get(1) );
 1054   
 
 1055  0
         return new DoWhileStatement( new BooleanExpression(condition), body );
 1056   
     }
 1057   
 
 1058   
 
 1059   
 
 1060   
    /**
 1061   
     *  Processes the Reduction produced by Parser.whileStatement().
 1062   
     */
 1063   
 
 1064  0
     protected WhileStatement whileStatement( CSTNode reduction ) throws ParserException
 1065   
     {
 1066  0
         Expression condition = expression( reduction.get(1) );
 1067  0
         BlockStatement  body = statementBody( reduction.get(2) );
 1068   
 
 1069  0
         return new WhileStatement( new BooleanExpression(condition), body );
 1070   
 
 1071   
     }
 1072   
 
 1073   
 
 1074   
 
 1075   
 
 1076   
   //---------------------------------------------------------------------------
 1077   
   // EXPRESSIONS
 1078   
 
 1079   
 
 1080   
    /**
 1081   
     *  Processes any expression that forms a complete statement.
 1082   
     */
 1083   
 
 1084  0
     protected Statement expressionStatement( CSTNode node ) throws ParserException
 1085   
     {
 1086  0
         return new ExpressionStatement( expression(node) );
 1087   
     }
 1088   
 
 1089   
 
 1090   
 
 1091   
    /**
 1092   
     *  Processes a series of expression to an Expression[].
 1093   
     */
 1094   
 
 1095  0
     protected Expression[] expressions( CSTNode reduction ) throws ParserException
 1096   
     {
 1097  0
         Expression[] expressions = new Expression[ reduction.children() ];
 1098   
 
 1099  0
         for( int i = 1; i < reduction.size(); i++ )
 1100   
         {
 1101  0
             expressions[i-1] = expression( reduction.get(i) );
 1102   
         }
 1103   
 
 1104  0
         return expressions;
 1105   
     }
 1106   
 
 1107   
 
 1108   
 
 1109   
    /**
 1110   
     *  Processes the CSTNode produced by Parser.expression().
 1111   
     */
 1112   
 
 1113  0
     protected Expression expression( CSTNode reduction ) throws ParserException
 1114   
     {
 1115  0
         Expression expression = null;
 1116   
 
 1117  0
         int type = reduction.getMeaningAs( EXPRESSION_HANDLERS );
 1118  0
         switch( type )
 1119   
         {
 1120   
             case Types.SYNTHETIC:
 1121   
             {
 1122  0
                 expression = syntheticExpression( reduction );
 1123  0
                 break;
 1124   
             }
 1125   
 
 1126   
             case Types.RANGE_OPERATOR:
 1127   
             {
 1128  0
                 Expression from = expression( reduction.get(1) );
 1129  0
                 Expression   to = expression( reduction.get(2) );
 1130   
 
 1131  0
                 expression = new RangeExpression( from, to, reduction.getMeaning() == Types.DOT_DOT );
 1132  0
                 break;
 1133   
             }
 1134   
 
 1135   
 
 1136   
             case Types.LEFT_SQUARE_BRACKET:
 1137   
             case Types.INFIX_OPERATOR:
 1138   
             {
 1139  0
                 expression = infixExpression( reduction );
 1140  0
                 break;
 1141   
             }
 1142   
 
 1143   
 
 1144   
             case Types.REGEX_PATTERN:
 1145   
             {
 1146  0
                 expression = new RegexExpression( expression(reduction.get(1)) );
 1147  0
                 break;
 1148   
             }
 1149   
 
 1150   
 
 1151   
             case Types.PREFIX_OPERATOR:
 1152   
             {
 1153  0
                 expression = prefixExpression( reduction );
 1154  0
                 break;
 1155   
             }
 1156   
 
 1157   
 
 1158   
             case Types.POSTFIX_OPERATOR:
 1159   
             {
 1160  0
                 Expression body = expression( reduction.get(1) );
 1161  0
                 expression = new PostfixExpression( body, reduction.getRoot() );
 1162  0
                 break;
 1163   
             }
 1164   
 
 1165   
 
 1166   
             case Types.SIMPLE_EXPRESSION:
 1167   
             {
 1168  0
                 expression = simpleExpression( reduction );
 1169  0
                 break;
 1170   
             }
 1171   
 
 1172   
 
 1173   
             case Types.KEYWORD_NEW:
 1174   
             {
 1175  0
                 expression = newExpression( reduction );
 1176  0
                 break;
 1177   
             }
 1178   
 
 1179   
             default:
 1180  0
                 throw new GroovyBugError( "unhandled CST: [" + reduction.toString() + "]" );
 1181   
 
 1182   
         }
 1183   
 
 1184  0
         if( expression == null )
 1185   
         {
 1186  0
             throw new GroovyBugError( "expression produced null: [" + reduction.toString() + "]" );
 1187   
         }
 1188   
 
 1189  0
         expression.setCSTNode( reduction );
 1190  0
         return expression;
 1191   
     }
 1192   
 
 1193   
 
 1194   
     public static final int[] EXPRESSION_HANDLERS = {
 1195   
           Types.SYNTHETIC
 1196   
         , Types.RANGE_OPERATOR
 1197   
         , Types.LEFT_SQUARE_BRACKET
 1198   
         , Types.INFIX_OPERATOR
 1199   
         , Types.REGEX_PATTERN
 1200   
         , Types.PREFIX_OPERATOR
 1201   
         , Types.POSTFIX_OPERATOR
 1202   
         , Types.SIMPLE_EXPRESSION
 1203   
         , Types.KEYWORD_NEW
 1204   
     };
 1205   
 
 1206   
 
 1207   
 
 1208   
 
 1209   
    /**
 1210   
     *  Processes most infix operators.
 1211   
     */
 1212   
 
 1213  0
     public Expression infixExpression( CSTNode reduction ) throws ParserException
 1214   
     {
 1215  0
         Expression expression;
 1216   
 
 1217  0
         int type = reduction.getMeaning();
 1218  0
         switch( type )
 1219   
         {
 1220   
             case Types.DOT:
 1221   
             case Types.NAVIGATE:
 1222   
             {
 1223  0
                 String name = reduction.get(2).getRootText();
 1224   
 
 1225  0
                 Expression context = null;
 1226  0
                 if( name.equals("class") )
 1227   
                 {
 1228  0
                     CSTNode node = reduction.get(1);
 1229  0
                     if( node.isA(Types.LEFT_SQUARE_BRACKET) && node.children() == 1 )
 1230   
                     {
 1231  0
                         throw new GroovyBugError( "NOT YET IMPLEMENTED: .class for array types" );
 1232   
                         // context = classExpression( reduction.get(1) );
 1233   
                     }
 1234   
                 }
 1235   
 
 1236  0
                 if( context == null )
 1237   
                 {
 1238  0
                     context = expression( reduction.get(1) );
 1239   
                 }
 1240   
 
 1241  0
                 expression = new PropertyExpression( context, name, type == Types.NAVIGATE );
 1242  0
                 break;
 1243   
             }
 1244   
 
 1245   
 
 1246   
             case Types.KEYWORD_INSTANCEOF:
 1247   
             {
 1248  0
                 Expression   lhs = expression(  reduction.get(1) );
 1249  0
                 Expression   rhs = classExpression( reduction.get(2) );
 1250  0
                 expression = new BinaryExpression( lhs, reduction.getRoot(), rhs );
 1251  0
                 break;
 1252   
             }
 1253   
 
 1254   
 
 1255   
             default:
 1256   
             {
 1257  0
                 Expression lhs = expression( reduction.get(1) );
 1258  0
                 Expression rhs = expression( reduction.get(2) );
 1259  0
                 expression = new BinaryExpression( lhs, reduction.getRoot(), rhs );
 1260  0
                 break;
 1261   
             }
 1262   
         }
 1263   
 
 1264  0
         return expression;
 1265   
     }
 1266   
 
 1267   
 
 1268   
 
 1269   
    /**
 1270   
     *  Processes most prefix operators.
 1271   
     */
 1272   
 
 1273  0
     public Expression prefixExpression( CSTNode reduction ) throws ParserException
 1274   
     {
 1275  0
         Expression expression = null;
 1276  0
         CSTNode    body       = reduction.get(1);
 1277   
 
 1278  0
         int type = reduction.getMeaning();
 1279  0
         switch( type )
 1280   
         {
 1281   
             case Types.PREFIX_MINUS:
 1282  0
                 if( body.size() == 1 && body.isA(Types.NUMBER) )
 1283   
                 {
 1284  0
                     expression = numericExpression( body, true );
 1285   
                 }
 1286   
                 else
 1287   
                 {
 1288  0
                     expression = new NegationExpression( expression(body) );
 1289   
                 }
 1290  0
                 break;
 1291   
 
 1292   
             case Types.PREFIX_PLUS:
 1293  0
                 expression = expression(body);
 1294  0
                 break;
 1295   
 
 1296   
             case Types.NOT:
 1297  0
                 expression = new NotExpression( expression(body) );
 1298  0
                 break;
 1299   
 
 1300   
             default:
 1301  0
                 expression = new PrefixExpression( reduction.getRoot(), expression(body) );
 1302  0
                 break;
 1303   
         }
 1304   
 
 1305  0
         return expression;
 1306   
     }
 1307   
 
 1308   
 
 1309   
 
 1310   
    /**
 1311   
     *  Processes most simple expressions.
 1312   
     */
 1313   
 
 1314  0
     public Expression simpleExpression( CSTNode reduction ) throws ParserException
 1315   
     {
 1316  0
         Expression expression = null;
 1317   
 
 1318  0
         int type = reduction.getMeaning();
 1319  0
         switch( type )
 1320   
         {
 1321   
             case Types.KEYWORD_NULL:
 1322  0
                 expression = ConstantExpression.NULL;
 1323  0
                 break;
 1324   
 
 1325   
             case Types.KEYWORD_TRUE:
 1326  0
                 expression = ConstantExpression.TRUE;
 1327  0
                 break;
 1328   
 
 1329   
             case Types.KEYWORD_FALSE:
 1330  0
                 expression = ConstantExpression.FALSE;
 1331  0
                 break;
 1332   
 
 1333   
             case Types.STRING:
 1334  0
                 expression = new ConstantExpression( reduction.getRootText() );
 1335  0
                 break;
 1336   
 
 1337   
             case Types.INTEGER_NUMBER:
 1338   
             case Types.DECIMAL_NUMBER:
 1339  0
                 expression = numericExpression( reduction, false );
 1340  0
                 break;
 1341   
 
 1342   
             case Types.KEYWORD_SUPER:
 1343   
             case Types.KEYWORD_THIS:
 1344  0
                 expression = variableExpression( reduction );
 1345  0
                 break;
 1346   
 
 1347   
             case Types.IDENTIFIER:
 1348  0
                 expression = variableOrClassExpression( reduction );
 1349  0
                 break;
 1350   
 
 1351   
         }
 1352   
 
 1353  0
         return expression;
 1354   
     }
 1355   
 
 1356   
 
 1357   
 
 1358   
    /**
 1359   
     *  Processes numeric literals.
 1360   
     */
 1361   
 
 1362  0
     public Expression numericExpression( CSTNode reduction, boolean negate ) throws ParserException
 1363   
     {
 1364  0
         Token  token  = reduction.getRoot();
 1365  0
         String text   = reduction.getRootText();
 1366  0
         String signed = negate ? "-" + text : text;
 1367   
 
 1368  0
         boolean isInteger = (token.getMeaning() == Types.INTEGER_NUMBER);
 1369   
 
 1370  0
         try
 1371   
         {
 1372  0
             Number number = isInteger ? Numbers.parseInteger(signed) : Numbers.parseDecimal(signed);
 1373   
 
 1374  0
             return new ConstantExpression( number );
 1375   
         }
 1376   
         catch( NumberFormatException e )
 1377   
         {
 1378  0
             error( "numeric literal [" + signed + "] invalid or out of range for its type", token );
 1379   
         }
 1380   
 
 1381  0
         throw new GroovyBugError( "this should never happen" );
 1382   
     }
 1383   
 
 1384   
 
 1385   
 
 1386   
    /**
 1387   
     *  Processes most synthetic expressions.
 1388   
     */
 1389   
 
 1390  0
     public Expression syntheticExpression( CSTNode reduction ) throws ParserException
 1391   
     {
 1392  0
         Expression expression = null;
 1393   
 
 1394  0
         int type = reduction.getMeaning();
 1395  0
         switch( type )
 1396   
         {
 1397   
             case Types.SYNTH_TERNARY:
 1398   
             {
 1399  0
                 BooleanExpression condition   = new BooleanExpression( expression(reduction.get(1)) );
 1400  0
                 Expression        trueBranch  = expression( reduction.get(2) );
 1401  0
                 Expression        falseBranch = expression( reduction.get(3) );
 1402   
 
 1403  0
                 expression = new TernaryExpression( condition, trueBranch, falseBranch );
 1404  0
                 break;
 1405   
             }
 1406   
 
 1407   
 
 1408   
             case Types.SYNTH_CAST:
 1409   
             {
 1410  0
                 String className = resolveName( reduction.get(1) );
 1411  0
                 Expression  body = expression(  reduction.get(2) );
 1412   
 
 1413  0
                 expression = new CastExpression( className, body );
 1414  0
                 break;
 1415   
             }
 1416   
 
 1417   
 
 1418   
             case Types.SYNTH_VARIABLE_DECLARATION:
 1419   
             {
 1420  0
                 expression = variableDeclarationExpression( reduction );
 1421  0
                 break;
 1422   
             }
 1423   
 
 1424   
 
 1425   
             case Types.SYNTH_METHOD_CALL:
 1426   
             {
 1427  0
                 expression = methodCallExpression( reduction );
 1428  0
                 break;
 1429   
             }
 1430   
 
 1431   
 
 1432   
             case Types.SYNTH_CLOSURE:
 1433   
             {
 1434  0
                 expression = closureExpression( reduction );
 1435  0
                 break;
 1436   
             }
 1437   
 
 1438   
 
 1439   
             case Types.SYNTH_GSTRING:
 1440   
             {
 1441  0
                 expression = gstringExpression( reduction );
 1442  0
                 break;
 1443   
             }
 1444   
 
 1445   
 
 1446   
             case Types.SYNTH_LIST:
 1447   
             {
 1448  0
                 expression = listExpression( reduction );
 1449  0
                 break;
 1450   
             }
 1451   
 
 1452   
 
 1453   
             case Types.SYNTH_MAP:
 1454   
             {
 1455  0
                 expression = mapExpression( reduction );
 1456  0
                 break;
 1457   
             }
 1458   
         }
 1459   
 
 1460  0
         return expression;
 1461   
     }
 1462   
 
 1463   
 
 1464   
 
 1465   
 
 1466   
    /**
 1467   
     *  Converts a (typically IDENTIFIER) CSTNode to a ClassExpression, if valid,
 1468   
     *  or a VariableExpression otherwise.
 1469   
     */
 1470   
 
 1471  0
     protected Expression variableOrClassExpression( CSTNode reduction ) throws ParserException
 1472   
     {
 1473  0
         String className = resolveName( reduction, false );
 1474   
 
 1475  0
         if( className == null )
 1476   
         {
 1477  0
             return variableExpression( reduction );
 1478   
         }
 1479   
         else
 1480   
         {
 1481  0
             return new ClassExpression( className );
 1482   
         }
 1483   
     }
 1484   
 
 1485   
 
 1486   
 
 1487   
    /**
 1488   
     *  Converts a CSTNode into a ClassExpression.
 1489   
     */
 1490   
 
 1491  0
     protected ClassExpression classExpression( CSTNode reduction ) throws ParserException
 1492   
     {
 1493  0
         String name = resolveName( reduction, true );
 1494  0
         return new ClassExpression( name );
 1495   
     }
 1496   
 
 1497   
 
 1498   
 
 1499   
    /**
 1500   
     *  Converts a (typically IDENTIFIER) CSTNode to a VariableExpression, if
 1501   
     *  valid.
 1502   
     */
 1503   
 
 1504  0
    protected VariableExpression variableExpression( CSTNode reduction )
 1505   
    {
 1506  0
        return new VariableExpression( reduction.getRootText(), null );
 1507   
    }
 1508   
 
 1509  0
     protected VariableExpression variableExpression( CSTNode reduction, String type )
 1510   
     {
 1511  0
         return new VariableExpression( reduction.getRootText(), type );
 1512   
     }
 1513   
 
 1514   
 
 1515   
 
 1516   
    /**
 1517   
     *  Converts an (possibly optional) type expression to a Type.
 1518   
     */
 1519   
 
 1520  0
     protected Type typeExpression( CSTNode reduction )
 1521   
     {
 1522  0
         String name = makeName( reduction, null );
 1523  0
         if( name == null )
 1524   
         {
 1525  0
             return Type.DYNAMIC_TYPE;
 1526   
         }
 1527   
         else
 1528   
         {
 1529  0
             return new Type( resolveName(name, true) );
 1530   
         }
 1531   
     }
 1532   
 
 1533   
 
 1534   
 
 1535   
    /**
 1536   
     *  Processes the Reduction produced by parsing a typed variable
 1537   
     *  declaration.
 1538   
     */
 1539   
 
 1540  0
     protected Expression variableDeclarationExpression( CSTNode reduction ) throws ParserException
 1541   
     {
 1542  0
         String type = resolveName( reduction.get(1) );
 1543   
 
 1544   
 
 1545   
         //
 1546   
         // TEMPORARY UNTIL GENERAL SUPPORT IN PLACE
 1547   
 
 1548  0
         if( reduction.size() == 3 )
 1549   
         {
 1550  0
             CSTNode node = reduction.get(2);
 1551   
 
 1552  0
             VariableExpression name = variableExpression( node, type );
 1553   
             //name.setType( type );
 1554   
 
 1555  0
             Token symbol = Token.newSymbol( Types.EQUAL, -1, -1 );
 1556   
 
 1557  0
             return new BinaryExpression( name, symbol, expression(node.get(1)) );
 1558   
         }
 1559   
 
 1560   
 
 1561  0
         throw new GroovyBugError( "NOT YET IMPLEMENTED: generalized variable declarations" );
 1562   
 
 1563   
         /*
 1564   
 
 1565   
         VariableDeclarationExpression expression = new VariableDeclarationExpression( type );
 1566   
 
 1567   
         for( i = 2; i < reduction.size(); i++ )
 1568   
         {
 1569   
             CSTNode node = reduction.get(i);
 1570   
             declaration.add( node.get(0), expression(node.get(1)) );
 1571   
         }
 1572   
 
 1573   
         return expression;
 1574   
 
 1575   
         */
 1576   
     }
 1577   
 
 1578   
 
 1579   
 
 1580   
    /**
 1581   
     *  Processes a SYNTH_METHOD_CALL Reduction produced by Parser.expression().
 1582   
     */
 1583   
 
 1584  0
     protected MethodCallExpression methodCallExpression( CSTNode reduction ) throws ParserException
 1585   
     {
 1586  0
         MethodCallExpression call = null;
 1587   
 
 1588   
         //
 1589   
         // Figure out the name and context of the method call.
 1590   
 
 1591  0
         CSTNode descriptor = reduction.get(1);
 1592  0
         Expression context = null;
 1593  0
         boolean   implicit = false;
 1594  0
         String      method = "call";
 1595  0
         boolean       safe = false;
 1596   
 
 1597  0
         int type = descriptor.getMeaning();
 1598  0
         switch( type )
 1599   
         {
 1600   
             case Types.KEYWORD_SUPER:
 1601   
             {
 1602  0
                 context  = variableExpression( descriptor );
 1603  0
                 method   = identifier( descriptor );
 1604  0
                 break;
 1605   
             }
 1606   
 
 1607   
             case Types.KEYWORD_THIS:
 1608   
             {
 1609  0
                 context  = VariableExpression.THIS_EXPRESSION;
 1610  0
                 method   = identifier( descriptor );
 1611  0
                 break;
 1612   
             }
 1613   
 
 1614   
             case Types.IDENTIFIER:
 1615   
             {
 1616  0
                 context  = VariableExpression.THIS_EXPRESSION;
 1617  0
                 method   = identifier( descriptor );
 1618  0
                 implicit = true;
 1619  0
                 break;
 1620   
             }
 1621   
 
 1622   
             case Types.DOT:
 1623   
             case Types.NAVIGATE:
 1624   
             {
 1625  0
                 context = expression( descriptor.get(1) );
 1626  0
                 method  = identifier( descriptor.get(2) );
 1627  0
                 safe    = type == Types.NAVIGATE;
 1628  0
                 break;
 1629   
             }
 1630   
 
 1631   
             default:
 1632   
             {
 1633  0
                 context = expression( descriptor );
 1634  0
                 break;
 1635   
             }
 1636   
         }
 1637   
 
 1638   
 
 1639   
         //
 1640   
         // And build the expression
 1641   
 
 1642  0
         Expression parameters = parameterList( reduction.get(2) );
 1643   
 
 1644   
         // System.out.println( "method call expression: " + context + ", " + method + ", " + parameters + ", " + implicit );
 1645   
 
 1646  0
         call = new MethodCallExpression( context, method, parameters );
 1647  0
         call.setImplicitThis( implicit );
 1648  0
         call.setSafe( safe );
 1649   
 
 1650  0
         return call;
 1651   
     }
 1652   
 
 1653   
 
 1654   
 
 1655   
    /**
 1656   
     *  Processes the Reduction produced by Parser.closureExpression().
 1657   
     */
 1658   
 
 1659  0
     protected ClosureExpression closureExpression( CSTNode reduction ) throws ParserException
 1660   
     {
 1661  0
         ClosureExpression expression = null;
 1662   
 
 1663  0
         Parameter[] parameters = parameterDeclarations( reduction.get(1) );
 1664  0
         expression = new ClosureExpression( parameters, statementBlock(reduction.get(2)) );
 1665   
 
 1666  0
         return expression;
 1667   
     }
 1668   
 
 1669   
 
 1670   
 
 1671   
    /**
 1672   
     *  Processes the Reduction produced by Parser.parameterList().
 1673   
     */
 1674   
 
 1675  0
     protected Expression parameterList( CSTNode reduction ) throws ParserException
 1676   
     {
 1677  0
         TupleExpression list = new TupleExpression();
 1678   
 
 1679  0
         for( int i = 1; i < reduction.size(); i++ )
 1680   
         {
 1681  0
             CSTNode node = reduction.get(i);
 1682  0
             list.addExpression( expression(node) );
 1683   
         }
 1684   
 
 1685  0
         return list;
 1686   
     }
 1687   
 
 1688   
 
 1689   
 
 1690   
    /**
 1691   
     *  Processes the Reduction produced by Parser.newExpression().
 1692   
     */
 1693   
 
 1694  0
     protected Expression newExpression( CSTNode reduction ) throws ParserException
 1695   
     {
 1696  0
         Expression expression = null;
 1697  0
         CSTNode      typeNode = reduction.get(1);
 1698  0
         String           type = resolveName( typeNode );
 1699   
 
 1700   
 
 1701   
         //
 1702   
         // Array types have dimension and initialization data to handle.
 1703   
 
 1704  0
         if( typeNode.getMeaning() == Types.LEFT_SQUARE_BRACKET )
 1705   
         {
 1706  0
             CSTNode dimensions = reduction.get(2);
 1707   
 
 1708   
             //
 1709   
             // BUG: at present, ArrayExpression expects a scalar type and
 1710   
             // does not support multi-dimensional arrays.  In future, the
 1711   
             // the latter will need to change, and that may require the
 1712   
             // former to change, as well.  For now, we calculate the scalar
 1713   
             // type and error for multiple dimensions.
 1714   
 
 1715  0
             if( typeNode.get(1).getMeaning() == Types.LEFT_SQUARE_BRACKET )
 1716   
             {
 1717  0
                 throw new GroovyBugError( "NOT YET IMPLEMENTED: multidimensional arrays" );
 1718   
             }
 1719   
             else
 1720   
             {
 1721  0
                 type = resolveName( typeNode.get(1) );
 1722   
             }
 1723   
 
 1724   
 
 1725   
             //
 1726   
             // If there are no dimensions, process a tuple initializer
 1727   
 
 1728  0
             if( dimensions.isEmpty() )
 1729   
             {
 1730  0
                 CSTNode data = reduction.get(3);
 1731   
 
 1732  0
                 if( data.get(1, true).getMeaning() == Types.SYNTH_TUPLE )
 1733   
                 {
 1734  0
                     throw new GroovyBugError( "NOT YET IMPLEMENTED: multidimensional arrays" );
 1735   
                 }
 1736   
 
 1737  0
                 expression = new ArrayExpression( type, tupleExpression(data).getExpressions() );
 1738   
             }
 1739   
 
 1740   
 
 1741   
             //
 1742   
             // Otherwise, process the dimensions
 1743   
 
 1744   
             else
 1745   
             {
 1746  0
                 if( dimensions.size() > 2 )
 1747   
                 {
 1748  0
                     throw new GroovyBugError( "NOT YET IMPLEMENTED: multidimensional arrays" );
 1749   
 
 1750   
                     /*
 1751   
 
 1752   
                     expression = new ArrayExpression( type, tupleExpression(dimensions) );
 1753   
 
 1754   
                     */
 1755   
                 }
 1756   
                 else
 1757   
                 {
 1758  0
                     expression = new ArrayExpression( type, expression(dimensions.get(1)) );
 1759   
                 }
 1760   
             }
 1761   
         }
 1762   
 
 1763   
 
 1764   
         //
 1765   
         // Scalar types have a constructor parameter list and possibly a type body
 1766   
 
 1767   
         else
 1768   
         {
 1769  0
             Expression parameters = parameterList( reduction.get(2) );
 1770   
 
 1771  0
             if( reduction.size() > 3 )
 1772   
             {
 1773  0
                 throw new GroovyBugError( "NOT YET IMPLEMENTED: anonymous classes" );
 1774   
             }
 1775   
 
 1776  0
             expression = new ConstructorCallExpression( type, parameters );
 1777   
         }
 1778   
 
 1779  0
         return expression;
 1780   
     }
 1781   
 
 1782   
 
 1783   
 
 1784   
    /**
 1785   
     *  Processes the Reduction produced by Parser.newArrayInitializer().
 1786   
     */
 1787   
 
 1788  0
     protected TupleExpression tupleExpression( CSTNode reduction ) throws ParserException
 1789   
     {
 1790  0
         TupleExpression tuple = new TupleExpression();
 1791   
 
 1792  0
         for( int i = 1; i < reduction.size(); i++ )
 1793   
         {
 1794  0
             CSTNode element = reduction.get(i);
 1795   
 
 1796  0
             if( element.getMeaning() == Types.SYNTH_TUPLE )
 1797   
             {
 1798  0
                 tuple.addExpression( tupleExpression(element) );
 1799   
             }
 1800   
             else
 1801   
             {
 1802  0
                 tuple.addExpression( expression(element) );
 1803   
             }
 1804   
         }
 1805   
 
 1806  0
         return tuple;
 1807   
     }
 1808   
 
 1809   
 
 1810   
 
 1811   
    /**
 1812   
     *  Processes the Reduction produced by Parser.gstring().
 1813   
     */
 1814   
 
 1815  0
     protected Expression gstringExpression( CSTNode reduction ) throws ParserException
 1816   
     {
 1817  0
         if( !reduction.hasChildren() )
 1818   
         {
 1819  0
             return new ConstantExpression( "" );
 1820   
         }
 1821   
 
 1822  0
         if( reduction.children() == 1 && reduction.get(1).getMeaning() == Types.STRING )
 1823   
         {
 1824  0
             return expression( reduction.get(1) );
 1825   
         }
 1826   
 
 1827   
 
 1828  0
         GStringExpression expression = new GStringExpression( reduction.getRootText() );
 1829  0
         boolean lastWasExpression = false;
 1830   
 
 1831  0
         for( int i = 1; i < reduction.size(); i++ )
 1832   
         {
 1833  0
             CSTNode element = reduction.get(i);
 1834  0
             if( element.getMeaning() == Types.STRING )
 1835   
             {
 1836  0
                 ConstantExpression string = new ConstantExpression( element.getRootText() );
 1837  0
                 string.setCSTNode( element );
 1838   
 
 1839  0
                 expression.addString( string );
 1840   
 
 1841  0
                 lastWasExpression = false;
 1842   
             }
 1843   
             else
 1844   
             {
 1845  0
                 if( lastWasExpression )
 1846   
                 {
 1847  0
                     expression.addString( new ConstantExpression("") );
 1848   
                 }
 1849   
 
 1850  0
                 lastWasExpression = true;
 1851  0
                 expression.addValue( element.isEmpty() ? ConstantExpression.NULL : expression(element) );
 1852   
             }
 1853   
         }
 1854   
 
 1855  0
         return expression;
 1856   
     }
 1857   
 
 1858   
 
 1859   
 
 1860   
    /**
 1861   
     *  Processes one of the Reductions produced by Parser.listOrMapExpression().
 1862   
     */
 1863   
 
 1864  0
     protected ListExpression listExpression( CSTNode reduction ) throws ParserException
 1865   
     {
 1866  0
         ListExpression list = new ListExpression();
 1867   
 
 1868  0
         for( int i = 1; i < reduction.size(); i++ )
 1869   
         {
 1870  0
             list.addExpression( expression(reduction.get(i)) );
 1871   
         }
 1872   
 
 1873  0
         return list;
 1874   
     }
 1875   
 
 1876   
 
 1877   
 
 1878   
    /**
 1879   
     *  Processes the other Reduction produced by Parser.listOrMapExpression().
 1880   
     */
 1881   
 
 1882  0
     protected MapExpression mapExpression( CSTNode reduction ) throws ParserException
 1883   
     {
 1884  0
         MapExpression map = new MapExpression();
 1885   
 
 1886  0
         for( int i = 1; i < reduction.size(); i++ )
 1887   
         {
 1888  0
             CSTNode  element = reduction.get(i);
 1889  0
             Expression   key = expression( element.get(1) );
 1890  0
             Expression value = expression( element.get(2) );
 1891   
 
 1892  0
             map.addMapEntryExpression( key, value );
 1893   
         }
 1894   
 
 1895  0
         return map;
 1896   
     }
 1897   
 
 1898   
 
 1899   
 
 1900   
 
 1901   
 
 1902   
   //---------------------------------------------------------------------------
 1903   
   // NAMING
 1904   
 
 1905   
     private static HashMap resolutions = new HashMap();  // cleared on build(), to be safe
 1906   
     private static String NOT_RESOLVED = new String();
 1907   
 
 1908   
 
 1909   
    /**
 1910   
     *  Converts a CSTNode representation of a type name back into
 1911   
     *  a string.
 1912   
     */
 1913   
 
 1914  0
     protected String makeName( CSTNode root, String defaultName )
 1915   
     {
 1916  0
         if( root == null )
 1917   
         {
 1918  0
             return defaultName;
 1919   
         }
 1920   
 
 1921  0
         String name = "";
 1922  0
         switch( root.getMeaning() )
 1923   
         {
 1924   
             case Types.LEFT_SQUARE_BRACKET:
 1925   
             {
 1926  0
                 name = makeName( root.get(1) ) + "[]";
 1927  0
                 break;
 1928   
             }
 1929   
 
 1930   
             case Types.DOT:
 1931   
             {
 1932  0
                 CSTNode node = root;
 1933  0
                 while( node.isA(Types.DOT) )
 1934   
                 {
 1935  0
                     name = "." + node.get(2).getRootText() + name;
 1936  0
                     node = node.get(1);
 1937   
                 }
 1938   
 
 1939  0
                 name = node.getRootText() + name;
 1940  0
                 break;
 1941   
             }
 1942   
 
 1943   
             case Types.UNKNOWN:
 1944   
             {
 1945  0
                 name = defaultName;
 1946  0
                 break;
 1947   
             }
 1948   
 
 1949   
             default:
 1950   
             {
 1951  0
                 name = root.getRootText();
 1952  0
                 break;
 1953   
             }
 1954   
 
 1955   
         }
 1956   
 
 1957  0
         return name;
 1958   
     }
 1959   
 
 1960   
 
 1961   
 
 1962   
    /**
 1963   
     *  A synonym for <code>makeName( root, "java.lang.Object" )</code>.
 1964   
     */
 1965   
 
 1966  0
     protected String makeName( CSTNode root )
 1967   
     {
 1968  0
         return makeName( root, "" ); // br: the default name. was "java.lang.Object"
 1969   
     }
 1970   
 
 1971   
 
 1972   
 
 1973   
    /**
 1974   
     *  Returns the text of an identifier.
 1975   
     */
 1976   
 
 1977  0
     protected String identifier( CSTNode identifier )
 1978   
     {
 1979  0
         return identifier.getRootText();
 1980   
     }
 1981   
 
 1982   
 
 1983   
 
 1984   
    /**
 1985   
     *  Returns a fully qualified name for any given potential type
 1986   
     *  name.  Returns null if no qualified name could be determined.
 1987   
     */
 1988   
 
 1989  0
     protected String resolveName( String name, boolean safe )
 1990   
     {
 1991   
         //
 1992   
         // Use our cache of resolutions, if possible
 1993   
 
 1994  0
         String resolution = (String)resolutions.get( name );
 1995  0
         if( resolution == NOT_RESOLVED )
 1996   
         {
 1997  0
             return (safe ? name : null);
 1998   
         }
 1999  0
         else if( resolution != null )
 2000   
         {
 2001  0
             return (String)resolution;
 2002   
         }
 2003   
 
 2004   
 
 2005  0
         do
 2006   
         {
 2007   
             //
 2008   
             // If the type name contains a ".", it's probably fully
 2009   
             // qualified, and we don't take it to verification here.
 2010   
 
 2011  0
             if( name.indexOf(".") >= 0 )
 2012   
             {
 2013  0
                 resolution = name;
 2014  0
                 break;                                            // <<< FLOW CONTROL <<<<<<<<<
 2015   
             }
 2016   
 
 2017   
 
 2018   
             //
 2019   
             // Otherwise, we'll need the scalar type for checking, and
 2020   
             // the postfix for reassembly.
 2021   
 
 2022  0
             String scalar = name, postfix = "";
 2023  0
             while( scalar.endsWith("[]") )
 2024   
             {
 2025  0
                 scalar = scalar.substring( 0, scalar.length() - 2 );
 2026  0
                 postfix += "[]";
 2027   
             }
 2028   
 
 2029   
 
 2030   
             //
 2031   
             // Primitive types are all valid...
 2032   
 
 2033  0
             if( Types.ofType(Types.lookupKeyword(scalar), Types.PRIMITIVE_TYPE) )
 2034   
             {
 2035  0
                 resolution = name;
 2036  0
                 break;                                            // <<< FLOW CONTROL <<<<<<<<<
 2037   
             }
 2038   
 
 2039   
 
 2040   
             //
 2041   
             // Next, check our imports and return the qualified name,
 2042   
             // if available.
 2043   
 
 2044  0
             if( this.imports.containsKey(scalar) )
 2045   
             {
 2046  0
                 resolution = ((String)this.imports.get(scalar)) + postfix;
 2047  0
                 break;                                            // <<< FLOW CONTROL <<<<<<<<<
 2048   
             }
 2049   
 
 2050   
 
 2051   
             //
 2052   
             // Next, see if our class loader can resolve it in the current package.
 2053   
 
 2054  0
             if( packageName != null && packageName.length() > 0 )
 2055   
             {
 2056  0
                 try
 2057   
                 {
 2058  0
                     getClassLoader().loadClass( dot(packageName, scalar) );
 2059  0
                     resolution = dot(packageName, name);
 2060   
 
 2061  0
                     break;                                        // <<< FLOW CONTROL <<<<<<<<<
 2062   
                 }
 2063   
                 catch( Throwable e )
 2064   
                 {
 2065   
                     /* ignore */
 2066   
                 }
 2067   
             }
 2068   
 
 2069   
             // search the package imports path
 2070  0
             List packageImports = output.getImportPackages();
 2071  0
             for (int i = 0; i < packageImports.size(); i++) {
 2072  0
                 String pack = (String) packageImports.get(i);
 2073  0
                 String clsName = pack + name;
 2074  0
                 try {
 2075  0
                     getClassLoader().loadClass( clsName );
 2076  0
                     resolution  = clsName;
 2077  0
                     break;
 2078   
                 } catch (Throwable e) {
 2079   
                     //
 2080   
                 }
 2081   
             }
 2082  0
             if (resolution != null)
 2083  0
                 break;
 2084   
 
 2085   
             //
 2086   
             // Last chance, check the default imports.
 2087   
 
 2088  0
             for( int i = 0; i < DEFAULT_IMPORTS.length; i++ )
 2089   
             {
 2090  0
                 try
 2091   
                 {
 2092  0
                     String qualified = DEFAULT_IMPORTS[i] + scalar;
 2093  0
                     getClassLoader().loadClass( qualified );
 2094   
 
 2095  0
                     resolution = qualified + postfix;
 2096  0
                     break;                                        // <<< FLOW CONTROL <<<<<<<<<
 2097   
                 }
 2098   
                 catch( Throwable e )
 2099   
                 {
 2100   
                     /* ignore */
 2101   
                 }
 2102   
             }
 2103   
 
 2104   
         } while( false );
 2105   
 
 2106   
 
 2107   
         //
 2108   
         // Cache the solution and return it
 2109   
 
 2110  0
         if( resolution == null )
 2111   
         {
 2112  0
             resolutions.put( name, NOT_RESOLVED );
 2113  0
             return (safe ? name : null);
 2114   
         }
 2115   
         else
 2116   
         {
 2117  0
             resolutions.put( name, resolution );
 2118  0
             return resolution;
 2119   
         }
 2120   
     }
 2121   
 
 2122   
 
 2123   
 
 2124   
    /**
 2125   
     *  Builds a name from a CSTNode, then resolves it.  Returns the resolved name
 2126   
     *  if available, or null, unless safe is set, in which case the built name
 2127   
     *  is returned instead of null.
 2128   
     *
 2129   
     *  @todo we should actually remove all resolving code from the ASTBuilder and
 2130   
     *        move it into the verifier / analyser
 2131   
     */
 2132   
 
 2133  0
     protected String resolveName( CSTNode root, boolean safe )
 2134   
     {
 2135  0
         String name = makeName( root );
 2136  0
         if (name.length() == 0)
 2137  0
             return "";
 2138  0
         if (this.newClasses.contains(name)) {
 2139  0
             return dot(packageName, name);
 2140   
         } else {
 2141  0
             return resolveName( name, safe );
 2142   
         }
 2143   
     }
 2144   
 
 2145   
 
 2146   
 
 2147   
    /**
 2148   
     *  A synonym for <code>resolveName( root, true )</code>.
 2149   
     */
 2150   
 
 2151  0
     protected String resolveName( CSTNode root )
 2152   
     {
 2153  0
         return resolveName( root, true );
 2154   
     }
 2155   
 
 2156   
 
 2157   
 
 2158   
    /**
 2159   
     *  Returns true if the specified name is a known type name.
 2160   
     */
 2161   
 
 2162  0
     protected boolean isDatatype( String name )
 2163   
     {
 2164  0
         return resolveName( name, false ) != null;
 2165   
     }
 2166   
 
 2167   
 
 2168   
 
 2169   
    /**
 2170   
     *  Returns two names joined by a dot.  If the base name is
 2171   
     *  empty, returns the name unchanged.
 2172   
     */
 2173   
 
 2174  0
     protected String dot( String base, String name )
 2175   
     {
 2176  0
         if( base != null && base.length() > 0 )
 2177   
         {
 2178  0
             return base + "." + name;
 2179   
         }
 2180   
 
 2181  0
         return name;
 2182   
     }
 2183   
 
 2184   
 
 2185   
 
 2186   
    /**
 2187   
     *  A synonym for <code>dot( base, "" )</code>.
 2188   
     */
 2189   
 
 2190  0
     protected String dot( String base )
 2191   
     {
 2192  0
         return dot( base, "" );
 2193   
     }
 2194   
 
 2195   
 
 2196   
 
 2197   
 
 2198   
   //---------------------------------------------------------------------------
 2199   
   // ASM SUPPORT
 2200   
 
 2201   
 
 2202   
    /**
 2203   
     *  Returns the ASM Constant bits for the specified modifiers.
 2204   
     */
 2205   
 
 2206  0
     protected int modifiers( CSTNode list )
 2207   
     {
 2208  0
         int modifiers = 0;
 2209   
 
 2210  0
         for( int i = 1; i < list.size(); ++i )
 2211   
         {
 2212  0
             SWITCH: switch( list.get(i).getMeaning() )
 2213   
             {
 2214   
                 case Types.KEYWORD_PUBLIC:
 2215   
                 {
 2216  0
                     modifiers |= Constants.ACC_PUBLIC;
 2217  0
                     break SWITCH;
 2218   
                 }
 2219   
 
 2220   
                 case Types.KEYWORD_PROTECTED:
 2221   
                 {
 2222  0
                     modifiers |= Constants.ACC_PROTECTED;
 2223  0
                     break SWITCH;
 2224   
                 }
 2225   
 
 2226   
                 case Types.KEYWORD_PRIVATE:
 2227   
                 {
 2228  0
                     modifiers |= Constants.ACC_PRIVATE;
 2229  0
                     break SWITCH;
 2230   
                 }
 2231   
 
 2232   
 
 2233   
                 case Types.KEYWORD_ABSTRACT:
 2234   
                 {
 2235  0
                     modifiers |= Constants.ACC_ABSTRACT;
 2236  0
                     break SWITCH;
 2237   
                 }
 2238   
 
 2239   
                 case Types.KEYWORD_FINAL:
 2240   
                 {
 2241  0
                     modifiers |= Constants.ACC_FINAL;
 2242  0
                     break SWITCH;
 2243   
                 }
 2244   
 
 2245   
                 case Types.KEYWORD_NATIVE:
 2246   
                 {
 2247  0
                     modifiers |= Constants.ACC_NATIVE;
 2248  0
                     break SWITCH;
 2249   
                 }
 2250   
 
 2251   
                 case Types.KEYWORD_TRANSIENT:
 2252   
                 {
 2253  0
                     modifiers |= Constants.ACC_TRANSIENT;
 2254  0
                     break SWITCH;
 2255   
                 }
 2256   
 
 2257   
                 case Types.KEYWORD_VOLATILE:
 2258   
                 {
 2259  0
                     modifiers |= Constants.ACC_VOLATILE;
 2260  0
                     break SWITCH;
 2261   
                 }
 2262   
 
 2263   
 
 2264   
                 case Types.KEYWORD_SYNCHRONIZED:
 2265   
                 {
 2266  0
                     modifiers |= Constants.ACC_SYNCHRONIZED;
 2267  0
                     break SWITCH;
 2268   
                 }
 2269   
                 case Types.KEYWORD_STATIC:
 2270   
                 {
 2271  0
                     modifiers |= Constants.ACC_STATIC;
 2272  0
                     break SWITCH;
 2273   
                 }
 2274   
 
 2275   
             }
 2276   
         }
 2277   
 
 2278   
 
 2279   
         //
 2280   
         // If not protected or private we default to public.
 2281   
 
 2282  0
         if( (modifiers & (Constants.ACC_PROTECTED | Constants.ACC_PRIVATE)) == 0 )
 2283   
         {
 2284  0
             modifiers |= Constants.ACC_PUBLIC;
 2285   
         }
 2286   
 
 2287  0
         return modifiers;
 2288   
     }
 2289   
 
 2290   
 
 2291   
 
 2292   
 
 2293   
   //---------------------------------------------------------------------------
 2294   
   // ERROR HANDLING
 2295   
 
 2296   
 
 2297   
    /**
 2298   
     *  Throws a <code>ParserException</code>.
 2299   
     */
 2300   
 
 2301  0
     protected void error( String description, CSTNode node ) throws ParserException
 2302   
     {
 2303  0
         throw new ParserException( description, node.getRoot() );
 2304   
     }
 2305   
 
 2306   
 
 2307   
 }
 2308