KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > syntax > parser > ASTBuilder


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 JavaDoc;
49 import java.util.Map JavaDoc;
50 import java.util.List JavaDoc;
51 import java.util.ArrayList JavaDoc;
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 JavaDoc[] EMPTY_STRING_ARRAY = new String JavaDoc[0];
129     private static final String JavaDoc[] 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 JavaDoc classLoader; // Our ClassLoader, which provides information on external types
139
private Map JavaDoc imports; // Our imports, simple name => fully qualified name
140
private String JavaDoc packageName; // The package name in which the module sits
141
private List JavaDoc newClasses = new ArrayList JavaDoc(); // 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     public ASTBuilder( SourceUnit sourceUnit, ClassLoader JavaDoc classLoader )
150     {
151         this.controller = sourceUnit;
152         this.classLoader = classLoader;
153         this.imports = new HashMap JavaDoc();
154         this.packageName = null;
155     }
156
157
158
159    /**
160     * Returns our class loader (as supplied on construction).
161     */

162
163     public ClassLoader JavaDoc getClassLoader()
164     {
165         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     public ModuleNode build( CSTNode input ) throws ParserException
180     {
181         this.newClasses.clear();
182         this.output = new ModuleNode( controller );
183         resolutions.clear();
184
185         //
186
// input structure:
187
// 1: package
188
// 2: imports
189
// 3+: statements
190

191         packageName = packageDeclaration( input.get(1) );
192         output.setPackageName( packageName );
193
194         importStatements( output, input.get(2) );
195
196         for( int i = 3; i < input.size(); ++i )
197         {
198             topLevelStatement( output, input.get(i) );
199         }
200
201         if( output.isEmpty() )
202         {
203             output.addStatement( new BlockStatement() );
204         }
205
206         return output;
207     }
208
209
210
211
212   //---------------------------------------------------------------------------
213
// DECLARATIONS
214

215
216    /**
217     * Processes the Reduction produced by Parser.packageDeclaration().
218     */

219
220     protected String JavaDoc packageDeclaration( CSTNode reduction )
221     {
222         if( reduction.hasChildren() )
223         {
224             return makeName( reduction.get(1) );
225         }
226
227         return null;
228
229     }
230
231
232
233    /**
234     * Processes the imports Reduction produced by Parser.module().
235     */

236
237     protected void importStatements( ModuleNode module, CSTNode container )
238     {
239         for( int i = 1; i < container.size(); ++i)
240         {
241             importStatement( module, container.get(i) );
242         }
243     }
244
245
246
247    /**
248     * Processes the Reduction produced by Parser.importStatement().
249     */

250
251     protected void importStatement( ModuleNode module, CSTNode reduction )
252     {
253         //
254
// First, get the package name (if supplied).
255

256         String JavaDoc 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         if( reduction.get(2).isA(Types.STAR) )
264         {
265             String JavaDoc[] classes = module.addImportPackage( dot(importPackage) );
266             for( int i = 0; i < classes.length; i++ )
267             {
268                 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             for( int i = 2; i < reduction.size(); i++ )
279             {
280                 CSTNode clause = reduction.get(i);
281                 String JavaDoc name = identifier( clause );
282                 String JavaDoc 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                 module.addImport( as, name ); // unqualified
294

295                 name = dot( importPackage, name );
296
297                 // module.addImport( as, name ); // qualified
298
imports.put( as, name );
299             }
300         }
301     }
302
303
304
305    /**
306     * Processes the Reduction produced by Parser.topLevelStatement().
307     */

308
309     protected void topLevelStatement( ModuleNode module, CSTNode reduction ) throws ParserException
310     {
311         int type = reduction.getMeaning();
312         switch( type )
313         {
314             case Types.SYNTH_CLASS:
315                 module.addClass( classDeclaration(null, reduction) );
316                 break;
317
318             case Types.SYNTH_INTERFACE:
319                 module.addClass( interfaceDeclaration(null, reduction) );
320                 break;
321
322             case Types.SYNTH_METHOD:
323                 module.addMethod( methodDeclaration(null, reduction) );
324                 break;
325
326             default:
327                 module.addStatement( statement(reduction) );
328                 break;
329         }
330
331     }
332
333
334
335    /**
336     * Processes the Reduction produced by Parser.classDeclaration().
337     */

338
339     protected ClassNode classDeclaration( ClassNode context, CSTNode reduction ) throws ParserException
340     {
341         //
342
// Calculate the easy stuff
343

344         String JavaDoc name = identifier( reduction );
345         this.newClasses.add(name);
346         int modifiers = modifiers( reduction.get(1) );
347         String JavaDoc parent = resolveName( reduction.get(2).get(1) );
348
349
350         //
351
// Then process the interface list.
352

353         CSTNode interfaceReduction = reduction.get(3);
354         String JavaDoc[] interfaces = new String JavaDoc[interfaceReduction.children()];
355         for( int i = 1; i < interfaceReduction.size(); i++ )
356         {
357             interfaces[i-1] = resolveName( interfaceReduction.get(i) );
358         }
359
360
361         //
362
// Create the class.
363

364         ClassNode classNode = (
365             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         classNode.setCSTNode( reduction.get(0) );
371         typeBody( classNode, reduction.get(4), 0, 0 );
372         return classNode;
373     }
374
375
376
377    /**
378     * Processes a type body for classDeclaration() and others.
379     */

380
381     protected void typeBody( ClassNode classNode, CSTNode body, int propertyModifiers, int methodModifiers ) throws ParserException
382     {
383         for( int i = 1; i < body.size(); i++ )
384         {
385             CSTNode statement = body.get(i);
386             switch( statement.getMeaning() )
387             {
388                 case Types.SYNTH_PROPERTY:
389                     addPropertyDeclaration( classNode, statement, propertyModifiers );
390                     break;
391
392                 case Types.SYNTH_METHOD:
393                     methodDeclaration( classNode, statement, methodModifiers );
394                     break;
395
396                 case Types.SYNTH_CLASS:
397                     classDeclaration( classNode, statement );
398                     break;
399
400                 case Types.SYNTH_INTERFACE:
401                     interfaceDeclaration( classNode, statement );
402                     break;
403
404                 default:
405                     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     protected void addPropertyDeclaration( ClassNode classNode, CSTNode reduction, int extraModifiers ) throws ParserException
418     {
419         String JavaDoc name = identifier( reduction );
420         int modifiers = modifiers( reduction.get(1) ) | extraModifiers;
421         String JavaDoc type = resolveName( reduction.get(2) );
422
423         Expression value = reduction.size() > 3 ? expression(reduction.get(3)) : null;
424
425         PropertyNode propertyNode = classNode.addProperty( name, modifiers, type, value, null, null );
426         propertyNode.setCSTNode( reduction.get(0) );
427
428     }
429
430
431
432    /**
433     * A synonym for <code>addPropertyDeclaration( classNode, reduction, 0 )</code>.
434     */

435
436     protected void addPropertyDeclaration( ClassNode classNode, CSTNode reduction ) throws ParserException
437     {
438         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     protected MethodNode methodDeclaration( ClassNode classNode, CSTNode reduction, int extraModifiers ) throws ParserException
449     {
450         String JavaDoc className = null;
451         if( classNode != null )
452         {
453             className = classNode.getNameWithoutPackage();
454         }
455
456
457         //
458
// Get the basic method data
459

460         String JavaDoc name = identifier( reduction );
461         int modifiers = modifiers( reduction.get(1) ) | extraModifiers;
462         String JavaDoc type = resolveName( reduction.get(2) );
463
464         Parameter[] parameters = parameterDeclarations( reduction.get(3) );
465         BlockStatement body = statementBody( reduction.get(5) );
466
467
468         //
469
// Process the throws clause
470

471         CSTNode clause = reduction.get(4);
472         String JavaDoc[] throwTypes = new String JavaDoc[clause.children()];
473         for( int i = 1; i < clause.size(); i++ )
474         {
475             throwTypes[i-1] = resolveName( clause.get(i) );
476         }
477
478         if( clause.hasChildren() ) { throw new GroovyBugError( "NOT YET IMPLEMENTED: throws clause" ); }
479
480
481         //
482
// An unnamed method is a static initializer
483

484         if( name.length() == 0 )
485         {
486             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         else if( className != null && name.equals(className) )
504         {
505             ConstructorNode node = new ConstructorNode( modifiers, parameters, body );
506             node.setCSTNode( reduction.get(0) );
507
508             classNode.addConstructor( node );
509             return null;
510         }
511
512
513         //
514
// Anything else is a plain old method
515

516         else
517         {
518             MethodNode method = new MethodNode( name, modifiers, type, parameters, body );
519             method.setCSTNode( reduction.get(0) );
520
521             if( classNode != null )
522             {
523                 classNode.addMethod( method );
524             }
525
526             return method;
527         }
528
529     }
530
531
532
533    /**
534     * A synonym for <code>methodDeclaration( classNode, reduction, 0 )</code>.
535     */

536
537     protected MethodNode methodDeclaration( ClassNode classNode, CSTNode reduction ) throws ParserException
538     {
539         return methodDeclaration( classNode, reduction, 0 );
540     }
541
542
543
544    /**
545     * Processes the Reduction produced by Parser.parameterDeclarationList().
546     */

547
548     protected Parameter[] parameterDeclarations( CSTNode reduction ) throws ParserException
549     {
550         Parameter[] parameters = new Parameter[ reduction.children() ];
551
552         for( int i = 1; i < reduction.size(); i++ )
553         {
554             CSTNode node = reduction.get(i);
555
556             String JavaDoc identifier = identifier( node );
557             String JavaDoc type = resolveName( node.get(1) );
558
559             if( node.size() > 2 )
560             {
561                 parameters[i-1] = new Parameter( type, identifier, expression(node.get(2)) );
562             }
563             else
564             {
565                 parameters[i-1] = new Parameter( type, identifier );
566             }
567         }
568
569         return parameters;
570
571     }
572
573
574
575    /**
576     * Processes the Reduction produced by Parser.interfaceDeclaration().
577     */

578
579     protected ClassNode interfaceDeclaration( ClassNode context, CSTNode reduction ) throws ParserException
580     {
581         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     protected BlockStatement statementBody( CSTNode reduction ) throws ParserException
638     {
639         if( reduction.isEmpty() )
640         {
641             return new BlockStatement();
642         }
643         else if( reduction.getMeaning() == Types.LEFT_CURLY_BRACE )
644         {
645             return statementBlock( reduction );
646         }
647         else
648         {
649             Statement statement = statement( reduction );
650             statement.setCSTNode( reduction );
651
652             BlockStatement block = null;
653             if( statement instanceof BlockStatement )
654             {
655                 block = (BlockStatement)statement;
656             }
657             else
658             {
659                 block = new BlockStatement();
660                 block.addStatement( statement );
661             }
662
663             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     protected BlockStatement statements( CSTNode reduction, int first ) throws ParserException
675     {
676         BlockStatement block = new BlockStatement();
677
678         for( int i = first; i < reduction.size(); i++ )
679         {
680             CSTNode statementReduction = reduction.get(i);
681
682             Statement statement = statement( statementReduction );
683             statement.setCSTNode( statementReduction );
684
685             block.addStatement( statement );
686         }
687
688         return block;
689     }
690
691
692
693    /**
694     * Processes any statement block.
695     */

696
697     protected BlockStatement statementBlock( CSTNode reduction ) throws ParserException
698     {
699         return statements( reduction, 1 );
700     }
701
702
703
704    /**
705     * Processes the Reduction produced by Parser.statement().
706     */

707
708     protected Statement statement( CSTNode reduction ) throws ParserException
709     {
710         Statement statement = null;
711
712         //
713
// Convert the statement
714

715         switch( reduction.getMeaning() )
716         {
717             case Types.KEYWORD_ASSERT:
718             {
719                 statement = assertStatement( reduction );
720                 break;
721             }
722
723             case Types.KEYWORD_BREAK:
724             {
725                 statement = breakStatement( reduction );
726                 break;
727             }
728
729             case Types.KEYWORD_CONTINUE:
730             {
731                 statement = continueStatement( reduction );
732                 break;
733             }
734
735             case Types.KEYWORD_IF:
736             {
737                 statement = ifStatement( reduction );
738                 break;
739             }
740
741             case Types.KEYWORD_RETURN:
742             {
743                 statement = returnStatement( reduction );
744                 break;
745             }
746
747             case Types.KEYWORD_SWITCH:
748             {
749                 statement = switchStatement( reduction );
750                 break;
751             }
752
753             case Types.KEYWORD_SYNCHRONIZED:
754             {
755                 statement = synchronizedStatement( reduction );
756                 break;
757             }
758
759             case Types.KEYWORD_THROW:
760             {
761                 statement = throwStatement( reduction );
762                 break;
763             }
764
765             case Types.KEYWORD_TRY:
766             {
767                 statement = tryStatement( reduction );
768                 break;
769             }
770
771             case Types.KEYWORD_FOR:
772             {
773                 statement = forStatement( reduction );
774                 break;
775             }
776
777             case Types.KEYWORD_WHILE:
778             {
779                 statement = whileStatement( reduction );
780                 break;
781             }
782
783             case Types.KEYWORD_DO:
784             {
785                 statement = doWhileStatement( reduction );
786                 break;
787             }
788
789             case Types.SYNTH_BLOCK:
790             case Types.LEFT_CURLY_BRACE:
791             {
792                 statement = statementBlock( reduction );
793                 break;
794             }
795
796             case Types.SYNTH_LABEL:
797             {
798                 statement = statement( reduction.get(1) );
799                 statement.setStatementLabel( identifier(reduction) );
800                 break;
801             }
802
803             case Types.SYNTH_CLOSURE:
804             default:
805             {
806                 statement = expressionStatement( reduction );
807                 break;
808             }
809
810         }
811
812
813         statement.setCSTNode( reduction );
814         return statement;
815     }
816
817
818
819    /**
820     * Processes the Reduction produced by Parser.assertStatement().
821     */

822
823     protected AssertStatement assertStatement( CSTNode reduction ) throws ParserException
824     {
825         BooleanExpression expression = new BooleanExpression( expression(reduction.get(1)) );
826
827         if( reduction.children() > 1 )
828         {
829             return new AssertStatement( expression, expression(reduction.get(2)) );
830         }
831
832         return new AssertStatement( expression, ConstantExpression.NULL );
833     }
834
835
836
837    /**
838     * Processes the Reduction produced by Parser.breakStatement().
839     */

840
841     protected BreakStatement breakStatement( CSTNode reduction ) throws ParserException
842     {
843         if( reduction.hasChildren() )
844         {
845             return new BreakStatement( reduction.get(1).getRootText() );
846         }
847
848         return new BreakStatement();
849     }
850
851
852
853    /**
854     * Processes the Reduction produced by Parser.continueStatement().
855     */

856
857     protected ContinueStatement continueStatement( CSTNode reduction ) throws ParserException
858     {
859
860         if( reduction.hasChildren() )
861         {
862             return new ContinueStatement( reduction.get(1).getRootText() );
863         }
864
865         return new ContinueStatement();
866     }
867
868
869
870    /**
871     * Processes the Reduction produced by Parser.ifStatement().
872     */

873
874     protected IfStatement ifStatement( CSTNode reduction ) throws ParserException
875     {
876         Expression condition = expression( reduction.get(1) );
877         BlockStatement body = statementBody( reduction.get(2) );
878         Statement elseBlock = EmptyStatement.INSTANCE;
879
880         if( reduction.size() > 3 )
881         {
882             CSTNode elseReduction = reduction.get(3);
883             if( elseReduction.getMeaning() == Types.KEYWORD_IF )
884             {
885                 elseBlock = ifStatement( elseReduction );
886             }
887             else
888             {
889                 elseBlock = statementBody( elseReduction.get(1) );
890             }
891
892         }
893
894         return new IfStatement( new BooleanExpression(condition), body, elseBlock );
895     }
896
897
898
899    /**
900     * Processes the Reduction produced by Parser.returnStatement().
901     */

902
903     protected ReturnStatement returnStatement( CSTNode reduction ) throws ParserException
904     {
905         if( reduction.hasChildren() )
906         {
907             return new ReturnStatement( expression(reduction.get(1)) );
908         }
909
910         return ReturnStatement.RETURN_NULL_OR_VOID;
911     }
912
913
914
915    /**
916     * Processes the Reduction produced by Parser.switchStatement().
917     */

918
919     protected SwitchStatement switchStatement( CSTNode reduction ) throws ParserException
920     {
921         SwitchStatement statement = new SwitchStatement( expression(reduction.get(1)) );
922
923         for( int i = 2; i < reduction.size(); i++ )
924         {
925             CSTNode child = reduction.get(i);
926
927             switch( child.getMeaning() )
928             {
929
930                 case Types.KEYWORD_CASE:
931                     statement.addCase( caseStatement(child) );
932                     break;
933
934                 case Types.KEYWORD_DEFAULT:
935                     statement.setDefaultStatement( statementBlock(child) );
936                     break;
937
938                 default:
939                     throw new GroovyBugError( "invalid something in switch [" + child + "]" );
940             }
941         }
942
943         return statement;
944     }
945
946
947
948    /**
949     * Processes the Reduction produced by Parser.switchStatement() for cases.
950     */

951
952     protected CaseStatement caseStatement( CSTNode reduction ) throws ParserException
953     {
954         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     protected SynchronizedStatement synchronizedStatement( CSTNode reduction ) throws ParserException
964     {
965         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     protected ThrowStatement throwStatement( CSTNode reduction ) throws ParserException
975     {
976         return new ThrowStatement( expression(reduction.get(1)) );
977     }
978
979
980
981    /**
982     * Processes the Reduction produced by Parser.tryStatement().
983     */

984
985     protected TryCatchStatement tryStatement( CSTNode reduction ) throws ParserException
986     {
987         BlockStatement body = statementBody( reduction.get(1) );
988         BlockStatement finallyBlock = statementBody( reduction.get(3) );
989
990         TryCatchStatement statement = new TryCatchStatement( body, finallyBlock );
991
992         CSTNode catches = reduction.get(2);
993         for( int i = 1; i < catches.size(); i++ )
994         {
995             CSTNode element = catches.get(i);
996             String JavaDoc type = resolveName( element.get(1) );
997             String JavaDoc identifier = identifier( element.get(2) );
998
999             statement.addCatch( new CatchStatement(type, identifier, statementBody(element.get(3))) );
1000        }
1001
1002        return statement;
1003    }
1004
1005
1006
1007   /**
1008    * Processes the Reduction produced by Parser.forStatement().
1009    */

1010
1011    protected ForStatement forStatement( CSTNode reduction ) throws ParserException
1012    {
1013        CSTNode header = reduction.get(1);
1014        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        if( header.getMeaning() == Types.UNKNOWN )
1021        {
1022            Expression[] init = expressions( header.get(1) );
1023            Expression test = expression( header.get(2) );
1024            Expression[] incr = expressions( header.get(3) );
1025
1026            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            Type type = typeExpression( header.get(1) );
1037            String JavaDoc identifier = identifier( header.get(2) );
1038            Expression source = expression( header.get(3) );
1039
1040            return new ForStatement( identifier, type, source, body );
1041        }
1042    }
1043
1044
1045
1046   /**
1047    * Processes the Reduction produced by Parser.doWhileStatement().
1048    */

1049
1050    protected DoWhileStatement doWhileStatement( CSTNode reduction ) throws ParserException
1051    {
1052        Expression condition = expression( reduction.get(2) );
1053        BlockStatement body = statementBody( reduction.get(1) );
1054
1055        return new DoWhileStatement( new BooleanExpression(condition), body );
1056    }
1057
1058
1059
1060   /**
1061    * Processes the Reduction produced by Parser.whileStatement().
1062    */

1063
1064    protected WhileStatement whileStatement( CSTNode reduction ) throws ParserException
1065    {
1066        Expression condition = expression( reduction.get(1) );
1067        BlockStatement body = statementBody( reduction.get(2) );
1068
1069        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    protected Statement expressionStatement( CSTNode node ) throws ParserException
1085    {
1086        return new ExpressionStatement( expression(node) );
1087    }
1088
1089
1090
1091   /**
1092    * Processes a series of expression to an Expression[].
1093    */

1094
1095    protected Expression[] expressions( CSTNode reduction ) throws ParserException
1096    {
1097        Expression[] expressions = new Expression[ reduction.children() ];
1098
1099        for( int i = 1; i < reduction.size(); i++ )
1100        {
1101            expressions[i-1] = expression( reduction.get(i) );
1102        }
1103
1104        return expressions;
1105    }
1106
1107
1108
1109   /**
1110    * Processes the CSTNode produced by Parser.expression().
1111    */

1112
1113    protected Expression expression( CSTNode reduction ) throws ParserException
1114    {
1115        Expression expression = null;
1116
1117        int type = reduction.getMeaningAs( EXPRESSION_HANDLERS );
1118        switch( type )
1119        {
1120            case Types.SYNTHETIC:
1121            {
1122                expression = syntheticExpression( reduction );
1123                break;
1124            }
1125
1126            case Types.RANGE_OPERATOR:
1127            {
1128                Expression from = expression( reduction.get(1) );
1129                Expression to = expression( reduction.get(2) );
1130
1131                expression = new RangeExpression( from, to, reduction.getMeaning() == Types.DOT_DOT );
1132                break;
1133            }
1134
1135
1136            case Types.LEFT_SQUARE_BRACKET:
1137            case Types.INFIX_OPERATOR:
1138            {
1139                expression = infixExpression( reduction );
1140                break;
1141            }
1142
1143
1144            case Types.REGEX_PATTERN:
1145            {
1146                expression = new RegexExpression( expression(reduction.get(1)) );
1147                break;
1148            }
1149
1150
1151            case Types.PREFIX_OPERATOR:
1152            {
1153                expression = prefixExpression( reduction );
1154                break;
1155            }
1156
1157
1158            case Types.POSTFIX_OPERATOR:
1159            {
1160                Expression body = expression( reduction.get(1) );
1161                expression = new PostfixExpression( body, reduction.getRoot() );
1162                break;
1163            }
1164
1165
1166            case Types.SIMPLE_EXPRESSION:
1167            {
1168                expression = simpleExpression( reduction );
1169                break;
1170            }
1171
1172
1173            case Types.KEYWORD_NEW:
1174            {
1175                expression = newExpression( reduction );
1176                break;
1177            }
1178
1179            default:
1180                throw new GroovyBugError( "unhandled CST: [" + reduction.toString() + "]" );
1181
1182        }
1183
1184        if( expression == null )
1185        {
1186            throw new GroovyBugError( "expression produced null: [" + reduction.toString() + "]" );
1187        }
1188
1189        expression.setCSTNode( reduction );
1190        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    public Expression infixExpression( CSTNode reduction ) throws ParserException
1214    {
1215        Expression expression;
1216
1217        int type = reduction.getMeaning();
1218        switch( type )
1219        {
1220            case Types.DOT:
1221            case Types.NAVIGATE:
1222            {
1223                String JavaDoc name = reduction.get(2).getRootText();
1224
1225                Expression context = null;
1226                if( name.equals("class") )
1227                {
1228                    CSTNode node = reduction.get(1);
1229                    if( node.isA(Types.LEFT_SQUARE_BRACKET) && node.children() == 1 )
1230                    {
1231                        throw new GroovyBugError( "NOT YET IMPLEMENTED: .class for array types" );
1232                        // context = classExpression( reduction.get(1) );
1233
}
1234                }
1235
1236                if( context == null )
1237                {
1238                    context = expression( reduction.get(1) );
1239                }
1240
1241                expression = new PropertyExpression( context, name, type == Types.NAVIGATE );
1242                break;
1243            }
1244
1245
1246            case Types.KEYWORD_INSTANCEOF:
1247            {
1248                Expression lhs = expression( reduction.get(1) );
1249                Expression rhs = classExpression( reduction.get(2) );
1250                expression = new BinaryExpression( lhs, reduction.getRoot(), rhs );
1251                break;
1252            }
1253
1254
1255            default:
1256            {
1257                Expression lhs = expression( reduction.get(1) );
1258                Expression rhs = expression( reduction.get(2) );
1259                expression = new BinaryExpression( lhs, reduction.getRoot(), rhs );
1260                break;
1261            }
1262        }
1263
1264        return expression;
1265    }
1266
1267
1268
1269   /**
1270    * Processes most prefix operators.
1271    */

1272
1273    public Expression prefixExpression( CSTNode reduction ) throws ParserException
1274    {
1275        Expression expression = null;
1276        CSTNode body = reduction.get(1);
1277
1278        int type = reduction.getMeaning();
1279        switch( type )
1280        {
1281            case Types.PREFIX_MINUS:
1282                if( body.size() == 1 && body.isA(Types.NUMBER) )
1283                {
1284                    expression = numericExpression( body, true );
1285                }
1286                else
1287                {
1288                    expression = new NegationExpression( expression(body) );
1289                }
1290                break;
1291
1292            case Types.PREFIX_PLUS:
1293                expression = expression(body);
1294                break;
1295
1296            case Types.NOT:
1297                expression = new NotExpression( expression(body) );
1298                break;
1299
1300            default:
1301                expression = new PrefixExpression( reduction.getRoot(), expression(body) );
1302                break;
1303        }
1304
1305        return expression;
1306    }
1307
1308
1309
1310   /**
1311    * Processes most simple expressions.
1312    */

1313
1314    public Expression simpleExpression( CSTNode reduction ) throws ParserException
1315    {
1316        Expression expression = null;
1317
1318        int type = reduction.getMeaning();
1319        switch( type )
1320        {
1321            case Types.KEYWORD_NULL:
1322                expression = ConstantExpression.NULL;
1323                break;
1324
1325            case Types.KEYWORD_TRUE:
1326                expression = ConstantExpression.TRUE;
1327                break;
1328
1329            case Types.KEYWORD_FALSE:
1330                expression = ConstantExpression.FALSE;
1331                break;
1332
1333            case Types.STRING:
1334                expression = new ConstantExpression( reduction.getRootText() );
1335                break;
1336
1337            case Types.INTEGER_NUMBER:
1338            case Types.DECIMAL_NUMBER:
1339                expression = numericExpression( reduction, false );
1340                break;
1341
1342            case Types.KEYWORD_SUPER:
1343            case Types.KEYWORD_THIS:
1344                expression = variableExpression( reduction );
1345                break;
1346
1347            case Types.IDENTIFIER:
1348                expression = variableOrClassExpression( reduction );
1349                break;
1350
1351        }
1352
1353        return expression;
1354    }
1355
1356
1357
1358   /**
1359    * Processes numeric literals.
1360    */

1361
1362    public Expression numericExpression( CSTNode reduction, boolean negate ) throws ParserException
1363    {
1364        Token token = reduction.getRoot();
1365        String JavaDoc text = reduction.getRootText();
1366        String JavaDoc signed = negate ? "-" + text : text;
1367
1368        boolean isInteger = (token.getMeaning() == Types.INTEGER_NUMBER);
1369
1370        try
1371        {
1372            Number JavaDoc number = isInteger ? Numbers.parseInteger(signed) : Numbers.parseDecimal(signed);
1373
1374            return new ConstantExpression( number );
1375        }
1376        catch( NumberFormatException JavaDoc e )
1377        {
1378            error( "numeric literal [" + signed + "] invalid or out of range for its type", token );
1379        }
1380
1381        throw new GroovyBugError( "this should never happen" );
1382    }
1383
1384
1385
1386   /**
1387    * Processes most synthetic expressions.
1388    */

1389
1390    public Expression syntheticExpression( CSTNode reduction ) throws ParserException
1391    {
1392        Expression expression = null;
1393
1394        int type = reduction.getMeaning();
1395        switch( type )
1396        {
1397            case Types.SYNTH_TERNARY:
1398            {
1399                BooleanExpression condition = new BooleanExpression( expression(reduction.get(1)) );
1400                Expression trueBranch = expression( reduction.get(2) );
1401                Expression falseBranch = expression( reduction.get(3) );
1402
1403                expression = new TernaryExpression( condition, trueBranch, falseBranch );
1404                break;
1405            }
1406
1407
1408            case Types.SYNTH_CAST:
1409            {
1410                String JavaDoc className = resolveName( reduction.get(1) );
1411                Expression body = expression( reduction.get(2) );
1412
1413                expression = new CastExpression( className, body );
1414                break;
1415            }
1416
1417
1418            case Types.SYNTH_VARIABLE_DECLARATION:
1419            {
1420                expression = variableDeclarationExpression( reduction );
1421                break;
1422            }
1423
1424
1425            case Types.SYNTH_METHOD_CALL:
1426            {
1427                expression = methodCallExpression( reduction );
1428                break;
1429            }
1430
1431
1432            case Types.SYNTH_CLOSURE:
1433            {
1434                expression = closureExpression( reduction );
1435                break;
1436            }
1437
1438
1439            case Types.SYNTH_GSTRING:
1440            {
1441                expression = gstringExpression( reduction );
1442                break;
1443            }
1444
1445
1446            case Types.SYNTH_LIST:
1447            {
1448                expression = listExpression( reduction );
1449                break;
1450            }
1451
1452
1453            case Types.SYNTH_MAP:
1454            {
1455                expression = mapExpression( reduction );
1456                break;
1457            }
1458        }
1459
1460        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    protected Expression variableOrClassExpression( CSTNode reduction ) throws ParserException
1472    {
1473        String JavaDoc className = resolveName( reduction, false );
1474
1475        if( className == null )
1476        {
1477            return variableExpression( reduction );
1478        }
1479        else
1480        {
1481            return new ClassExpression( className );
1482        }
1483    }
1484
1485
1486
1487   /**
1488    * Converts a CSTNode into a ClassExpression.
1489    */

1490
1491    protected ClassExpression classExpression( CSTNode reduction ) throws ParserException
1492    {
1493        String JavaDoc name = resolveName( reduction, true );
1494        return new ClassExpression( name );
1495    }
1496
1497
1498
1499   /**
1500    * Converts a (typically IDENTIFIER) CSTNode to a VariableExpression, if
1501    * valid.
1502    */

1503
1504   protected VariableExpression variableExpression( CSTNode reduction )
1505   {
1506       return new VariableExpression( reduction.getRootText(), null );
1507   }
1508
1509    protected VariableExpression variableExpression( CSTNode reduction, String JavaDoc type )
1510    {
1511        return new VariableExpression( reduction.getRootText(), type );
1512    }
1513
1514
1515
1516   /**
1517    * Converts an (possibly optional) type expression to a Type.
1518    */

1519
1520    protected Type typeExpression( CSTNode reduction )
1521    {
1522        String JavaDoc name = makeName( reduction, null );
1523        if( name == null )
1524        {
1525            return Type.DYNAMIC_TYPE;
1526        }
1527        else
1528        {
1529            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    protected Expression variableDeclarationExpression( CSTNode reduction ) throws ParserException
1541    {
1542        String JavaDoc type = resolveName( reduction.get(1) );
1543
1544
1545        //
1546
// TEMPORARY UNTIL GENERAL SUPPORT IN PLACE
1547

1548        if( reduction.size() == 3 )
1549        {
1550            CSTNode node = reduction.get(2);
1551
1552            VariableExpression name = variableExpression( node, type );
1553            //name.setType( type );
1554

1555            Token symbol = Token.newSymbol( Types.EQUAL, -1, -1 );
1556
1557            return new BinaryExpression( name, symbol, expression(node.get(1)) );
1558        }
1559
1560
1561        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    protected MethodCallExpression methodCallExpression( CSTNode reduction ) throws ParserException
1585    {
1586        MethodCallExpression call = null;
1587
1588        //
1589
// Figure out the name and context of the method call.
1590

1591        CSTNode descriptor = reduction.get(1);
1592        Expression context = null;
1593        boolean implicit = false;
1594        String JavaDoc method = "call";
1595        boolean safe = false;
1596
1597        int type = descriptor.getMeaning();
1598        switch( type )
1599        {
1600            case Types.KEYWORD_SUPER:
1601            {
1602                context = variableExpression( descriptor );
1603                method = identifier( descriptor );
1604                break;
1605            }
1606
1607            case Types.KEYWORD_THIS:
1608            {
1609                context = VariableExpression.THIS_EXPRESSION;
1610                method = identifier( descriptor );
1611                break;
1612            }
1613
1614            case Types.IDENTIFIER:
1615            {
1616                context = VariableExpression.THIS_EXPRESSION;
1617                method = identifier( descriptor );
1618                implicit = true;
1619                break;
1620            }
1621
1622            case Types.DOT:
1623            case Types.NAVIGATE:
1624            {
1625                context = expression( descriptor.get(1) );
1626                method = identifier( descriptor.get(2) );
1627                safe = type == Types.NAVIGATE;
1628                break;
1629            }
1630
1631            default:
1632            {
1633                context = expression( descriptor );
1634                break;
1635            }
1636        }
1637
1638
1639        //
1640
// And build the expression
1641

1642        Expression parameters = parameterList( reduction.get(2) );
1643
1644        // System.out.println( "method call expression: " + context + ", " + method + ", " + parameters + ", " + implicit );
1645

1646        call = new MethodCallExpression( context, method, parameters );
1647        call.setImplicitThis( implicit );
1648        call.setSafe( safe );
1649
1650        return call;
1651    }
1652
1653
1654
1655   /**
1656    * Processes the Reduction produced by Parser.closureExpression().
1657    */

1658
1659    protected ClosureExpression closureExpression( CSTNode reduction ) throws ParserException
1660    {
1661        ClosureExpression expression = null;
1662
1663        Parameter[] parameters = parameterDeclarations( reduction.get(1) );
1664        expression = new ClosureExpression( parameters, statementBlock(reduction.get(2)) );
1665
1666        return expression;
1667    }
1668
1669
1670
1671   /**
1672    * Processes the Reduction produced by Parser.parameterList().
1673    */

1674
1675    protected Expression parameterList( CSTNode reduction ) throws ParserException
1676    {
1677        TupleExpression list = new TupleExpression();
1678
1679        for( int i = 1; i < reduction.size(); i++ )
1680        {
1681            CSTNode node = reduction.get(i);
1682            list.addExpression( expression(node) );
1683        }
1684
1685        return list;
1686    }
1687
1688
1689
1690   /**
1691    * Processes the Reduction produced by Parser.newExpression().
1692    */

1693
1694    protected Expression newExpression( CSTNode reduction ) throws ParserException
1695    {
1696        Expression expression = null;
1697        CSTNode typeNode = reduction.get(1);
1698        String JavaDoc type = resolveName( typeNode );
1699
1700
1701        //
1702
// Array types have dimension and initialization data to handle.
1703

1704        if( typeNode.getMeaning() == Types.LEFT_SQUARE_BRACKET )
1705        {
1706            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            if( typeNode.get(1).getMeaning() == Types.LEFT_SQUARE_BRACKET )
1716            {
1717                throw new GroovyBugError( "NOT YET IMPLEMENTED: multidimensional arrays" );
1718            }
1719            else
1720            {
1721                type = resolveName( typeNode.get(1) );
1722            }
1723
1724
1725            //
1726
// If there are no dimensions, process a tuple initializer
1727

1728            if( dimensions.isEmpty() )
1729            {
1730                CSTNode data = reduction.get(3);
1731
1732                if( data.get(1, true).getMeaning() == Types.SYNTH_TUPLE )
1733                {
1734                    throw new GroovyBugError( "NOT YET IMPLEMENTED: multidimensional arrays" );
1735                }
1736
1737                expression = new ArrayExpression( type, tupleExpression(data).getExpressions() );
1738            }
1739
1740
1741            //
1742
// Otherwise, process the dimensions
1743

1744            else
1745            {
1746                if( dimensions.size() > 2 )
1747                {
1748                    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                    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            Expression parameters = parameterList( reduction.get(2) );
1770
1771            if( reduction.size() > 3 )
1772            {
1773                throw new GroovyBugError( "NOT YET IMPLEMENTED: anonymous classes" );
1774            }
1775
1776            expression = new ConstructorCallExpression( type, parameters );
1777        }
1778
1779        return expression;
1780    }
1781
1782
1783
1784   /**
1785    * Processes the Reduction produced by Parser.newArrayInitializer().
1786    */

1787
1788    protected TupleExpression tupleExpression( CSTNode reduction ) throws ParserException
1789    {
1790        TupleExpression tuple = new TupleExpression();
1791
1792        for( int i = 1; i < reduction.size(); i++ )
1793        {
1794            CSTNode element = reduction.get(i);
1795
1796            if( element.getMeaning() == Types.SYNTH_TUPLE )
1797            {
1798                tuple.addExpression( tupleExpression(element) );
1799            }
1800            else
1801            {
1802                tuple.addExpression( expression(element) );
1803            }
1804        }
1805
1806        return tuple;
1807    }
1808
1809
1810
1811   /**
1812    * Processes the Reduction produced by Parser.gstring().
1813    */

1814
1815    protected Expression gstringExpression( CSTNode reduction ) throws ParserException
1816    {
1817        if( !reduction.hasChildren() )
1818        {
1819            return new ConstantExpression( "" );
1820        }
1821
1822        if( reduction.children() == 1 && reduction.get(1).getMeaning() == Types.STRING )
1823        {
1824            return expression( reduction.get(1) );
1825        }
1826
1827
1828        GStringExpression expression = new GStringExpression( reduction.getRootText() );
1829        boolean lastWasExpression = false;
1830
1831        for( int i = 1; i < reduction.size(); i++ )
1832        {
1833            CSTNode element = reduction.get(i);
1834            if( element.getMeaning() == Types.STRING )
1835            {
1836                ConstantExpression string = new ConstantExpression( element.getRootText() );
1837                string.setCSTNode( element );
1838
1839                expression.addString( string );
1840
1841                lastWasExpression = false;
1842            }
1843            else
1844            {
1845                if( lastWasExpression )
1846                {
1847                    expression.addString( new ConstantExpression("") );
1848                }
1849
1850                lastWasExpression = true;
1851                expression.addValue( element.isEmpty() ? ConstantExpression.NULL : expression(element) );
1852            }
1853        }
1854
1855        return expression;
1856    }
1857
1858
1859
1860   /**
1861    * Processes one of the Reductions produced by Parser.listOrMapExpression().
1862    */

1863
1864    protected ListExpression listExpression( CSTNode reduction ) throws ParserException
1865    {
1866        ListExpression list = new ListExpression();
1867
1868        for( int i = 1; i < reduction.size(); i++ )
1869        {
1870            list.addExpression( expression(reduction.get(i)) );
1871        }
1872
1873        return list;
1874    }
1875
1876
1877
1878   /**
1879    * Processes the other Reduction produced by Parser.listOrMapExpression().
1880    */

1881
1882    protected MapExpression mapExpression( CSTNode reduction ) throws ParserException
1883    {
1884        MapExpression map = new MapExpression();
1885
1886        for( int i = 1; i < reduction.size(); i++ )
1887        {
1888            CSTNode element = reduction.get(i);
1889            Expression key = expression( element.get(1) );
1890            Expression value = expression( element.get(2) );
1891
1892            map.addMapEntryExpression( key, value );
1893        }
1894
1895        return map;
1896    }
1897
1898
1899
1900
1901
1902  //---------------------------------------------------------------------------
1903
// NAMING
1904

1905    private static HashMap JavaDoc resolutions = new HashMap JavaDoc(); // cleared on build(), to be safe
1906
private static String JavaDoc NOT_RESOLVED = new String JavaDoc();
1907
1908
1909   /**
1910    * Converts a CSTNode representation of a type name back into
1911    * a string.
1912    */

1913
1914    protected String JavaDoc makeName( CSTNode root, String JavaDoc defaultName )
1915    {
1916        if( root == null )
1917        {
1918            return defaultName;
1919        }
1920
1921        String JavaDoc name = "";
1922        switch( root.getMeaning() )
1923        {
1924            case Types.LEFT_SQUARE_BRACKET:
1925            {
1926                name = makeName( root.get(1) ) + "[]";
1927                break;
1928            }
1929
1930            case Types.DOT:
1931            {
1932                CSTNode node = root;
1933                while( node.isA(Types.DOT) )
1934                {
1935                    name = "." + node.get(2).getRootText() + name;
1936                    node = node.get(1);
1937                }
1938
1939                name = node.getRootText() + name;
1940                break;
1941            }
1942
1943            case Types.UNKNOWN:
1944            {
1945                name = defaultName;
1946                break;
1947            }
1948
1949            default:
1950            {
1951                name = root.getRootText();
1952                break;
1953            }
1954
1955        }
1956
1957        return name;
1958    }
1959
1960
1961
1962   /**
1963    * A synonym for <code>makeName( root, "java.lang.Object" )</code>.
1964    */

1965
1966    protected String JavaDoc makeName( CSTNode root )
1967    {
1968        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    protected String JavaDoc identifier( CSTNode identifier )
1978    {
1979        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    protected String JavaDoc resolveName( String JavaDoc name, boolean safe )
1990    {
1991        //
1992
// Use our cache of resolutions, if possible
1993

1994        String JavaDoc resolution = (String JavaDoc)resolutions.get( name );
1995        if( resolution == NOT_RESOLVED )
1996        {
1997            return (safe ? name : null);
1998        }
1999        else if( resolution != null )
2000        {
2001            return (String JavaDoc)resolution;
2002        }
2003
2004
2005        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            if( name.indexOf(".") >= 0 )
2012            {
2013                resolution = name;
2014                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            String JavaDoc scalar = name, postfix = "";
2023            while( scalar.endsWith("[]") )
2024            {
2025                scalar = scalar.substring( 0, scalar.length() - 2 );
2026                postfix += "[]";
2027            }
2028
2029
2030            //
2031
// Primitive types are all valid...
2032

2033            if( Types.ofType(Types.lookupKeyword(scalar), Types.PRIMITIVE_TYPE) )
2034            {
2035                resolution = name;
2036                break; // <<< FLOW CONTROL <<<<<<<<<
2037
}
2038
2039
2040            //
2041
// Next, check our imports and return the qualified name,
2042
// if available.
2043

2044            if( this.imports.containsKey(scalar) )
2045            {
2046                resolution = ((String JavaDoc)this.imports.get(scalar)) + postfix;
2047                break; // <<< FLOW CONTROL <<<<<<<<<
2048
}
2049
2050
2051            //
2052
// Next, see if our class loader can resolve it in the current package.
2053

2054            if( packageName != null && packageName.length() > 0 )
2055            {
2056                try
2057                {
2058                    getClassLoader().loadClass( dot(packageName, scalar) );
2059                    resolution = dot(packageName, name);
2060
2061                    break; // <<< FLOW CONTROL <<<<<<<<<
2062
}
2063                catch( Throwable JavaDoc e )
2064                {
2065                    /* ignore */
2066                }
2067            }
2068
2069            // search the package imports path
2070
List JavaDoc packageImports = output.getImportPackages();
2071            for (int i = 0; i < packageImports.size(); i++) {
2072                String JavaDoc pack = (String JavaDoc) packageImports.get(i);
2073                String JavaDoc clsName = pack + name;
2074                try {
2075                    getClassLoader().loadClass( clsName );
2076                    resolution = clsName;
2077                    break;
2078                } catch (Throwable JavaDoc e) {
2079                    //
2080
}
2081            }
2082            if (resolution != null)
2083                break;
2084
2085            //
2086
// Last chance, check the default imports.
2087

2088            for( int i = 0; i < DEFAULT_IMPORTS.length; i++ )
2089            {
2090                try
2091                {
2092                    String JavaDoc qualified = DEFAULT_IMPORTS[i] + scalar;
2093                    getClassLoader().loadClass( qualified );
2094
2095                    resolution = qualified + postfix;
2096                    break; // <<< FLOW CONTROL <<<<<<<<<
2097
}
2098                catch( Throwable JavaDoc e )
2099                {
2100                    /* ignore */
2101                }
2102            }
2103
2104        } while( false );
2105
2106
2107        //
2108
// Cache the solution and return it
2109

2110        if( resolution == null )
2111        {
2112            resolutions.put( name, NOT_RESOLVED );
2113            return (safe ? name : null);
2114        }
2115        else
2116        {
2117            resolutions.put( name, resolution );
2118            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    protected String JavaDoc resolveName( CSTNode root, boolean safe )
2134    {
2135        String JavaDoc name = makeName( root );
2136        if (name.length() == 0)
2137            return "";
2138        if (this.newClasses.contains(name)) {
2139            return dot(packageName, name);
2140        } else {
2141            return resolveName( name, safe );
2142        }
2143    }
2144
2145
2146
2147   /**
2148    * A synonym for <code>resolveName( root, true )</code>.
2149    */

2150
2151    protected String JavaDoc resolveName( CSTNode root )
2152    {
2153        return resolveName( root, true );
2154    }
2155
2156
2157
2158   /**
2159    * Returns true if the specified name is a known type name.
2160    */

2161
2162    protected boolean isDatatype( String JavaDoc name )
2163    {
2164        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    protected String JavaDoc dot( String JavaDoc base, String JavaDoc name )
2175    {
2176        if( base != null && base.length() > 0 )
2177        {
2178            return base + "." + name;
2179        }
2180
2181        return name;
2182    }
2183
2184
2185
2186   /**
2187    * A synonym for <code>dot( base, "" )</code>.
2188    */

2189
2190    protected String JavaDoc dot( String JavaDoc base )
2191    {
2192        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    protected int modifiers( CSTNode list )
2207    {
2208        int modifiers = 0;
2209
2210        for( int i = 1; i < list.size(); ++i )
2211        {
2212            SWITCH: switch( list.get(i).getMeaning() )
2213            {
2214                case Types.KEYWORD_PUBLIC:
2215                {
2216                    modifiers |= Constants.ACC_PUBLIC;
2217                    break SWITCH;
2218                }
2219
2220                case Types.KEYWORD_PROTECTED:
2221                {
2222                    modifiers |= Constants.ACC_PROTECTED;
2223                    break SWITCH;
2224                }
2225
2226                case Types.KEYWORD_PRIVATE:
2227                {
2228                    modifiers |= Constants.ACC_PRIVATE;
2229                    break SWITCH;
2230                }
2231
2232
2233                case Types.KEYWORD_ABSTRACT:
2234                {
2235                    modifiers |= Constants.ACC_ABSTRACT;
2236                    break SWITCH;
2237                }
2238
2239                case Types.KEYWORD_FINAL:
2240                {
2241                    modifiers |= Constants.ACC_FINAL;
2242                    break SWITCH;
2243                }
2244
2245                case Types.KEYWORD_NATIVE:
2246                {
2247                    modifiers |= Constants.ACC_NATIVE;
2248                    break SWITCH;
2249                }
2250
2251                case Types.KEYWORD_TRANSIENT:
2252                {
2253                    modifiers |= Constants.ACC_TRANSIENT;
2254                    break SWITCH;
2255                }
2256
2257                case Types.KEYWORD_VOLATILE:
2258                {
2259                    modifiers |= Constants.ACC_VOLATILE;
2260                    break SWITCH;
2261                }
2262
2263
2264                case Types.KEYWORD_SYNCHRONIZED:
2265                {
2266                    modifiers |= Constants.ACC_SYNCHRONIZED;
2267                    break SWITCH;
2268                }
2269                case Types.KEYWORD_STATIC:
2270                {
2271                    modifiers |= Constants.ACC_STATIC;
2272                    break SWITCH;
2273                }
2274
2275            }
2276        }
2277
2278
2279        //
2280
// If not protected or private we default to public.
2281

2282        if( (modifiers & (Constants.ACC_PROTECTED | Constants.ACC_PRIVATE)) == 0 )
2283        {
2284            modifiers |= Constants.ACC_PUBLIC;
2285        }
2286
2287        return modifiers;
2288    }
2289
2290
2291
2292
2293  //---------------------------------------------------------------------------
2294
// ERROR HANDLING
2295

2296
2297   /**
2298    * Throws a <code>ParserException</code>.
2299    */

2300
2301    protected void error( String JavaDoc description, CSTNode node ) throws ParserException
2302    {
2303        throw new ParserException( description, node.getRoot() );
2304    }
2305
2306
2307}
2308
Popular Tags