View Javadoc

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