1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.codehaus.groovy.syntax.parser;
47
48 import java.util.HashMap;
49 import java.util.Map;
50 import java.util.List;
51 import java.util.ArrayList;
52
53 import org.codehaus.groovy.ast.ClassNode;
54 import org.codehaus.groovy.ast.InnerClassNode;
55 import org.codehaus.groovy.ast.ConstructorNode;
56 import org.codehaus.groovy.ast.MethodNode;
57 import org.codehaus.groovy.ast.MixinNode;
58 import org.codehaus.groovy.ast.ModuleNode;
59 import org.codehaus.groovy.ast.Parameter;
60 import org.codehaus.groovy.ast.PropertyNode;
61 import org.codehaus.groovy.ast.Type;
62 import org.codehaus.groovy.ast.expr.ArrayExpression;
63 import org.codehaus.groovy.ast.expr.BinaryExpression;
64 import org.codehaus.groovy.ast.expr.BooleanExpression;
65 import org.codehaus.groovy.ast.expr.CastExpression;
66 import org.codehaus.groovy.ast.expr.ClassExpression;
67 import org.codehaus.groovy.ast.expr.ClosureExpression;
68 import org.codehaus.groovy.ast.expr.ConstantExpression;
69 import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
70 import org.codehaus.groovy.ast.expr.Expression;
71 import org.codehaus.groovy.ast.expr.GStringExpression;
72 import org.codehaus.groovy.ast.expr.ListExpression;
73 import org.codehaus.groovy.ast.expr.MapExpression;
74 import org.codehaus.groovy.ast.expr.MethodCallExpression;
75 import org.codehaus.groovy.ast.expr.NegationExpression;
76 import org.codehaus.groovy.ast.expr.NotExpression;
77 import org.codehaus.groovy.ast.expr.PostfixExpression;
78 import org.codehaus.groovy.ast.expr.PrefixExpression;
79 import org.codehaus.groovy.ast.expr.PropertyExpression;
80 import org.codehaus.groovy.ast.expr.RangeExpression;
81 import org.codehaus.groovy.ast.expr.RegexExpression;
82 import org.codehaus.groovy.ast.expr.TernaryExpression;
83 import org.codehaus.groovy.ast.expr.TupleExpression;
84 import org.codehaus.groovy.ast.expr.VariableExpression;
85 import org.codehaus.groovy.ast.stmt.AssertStatement;
86 import org.codehaus.groovy.ast.stmt.BlockStatement;
87 import org.codehaus.groovy.ast.stmt.BreakStatement;
88 import org.codehaus.groovy.ast.stmt.CaseStatement;
89 import org.codehaus.groovy.ast.stmt.CatchStatement;
90 import org.codehaus.groovy.ast.stmt.ContinueStatement;
91 import org.codehaus.groovy.ast.stmt.DoWhileStatement;
92 import org.codehaus.groovy.ast.stmt.EmptyStatement;
93 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
94 import org.codehaus.groovy.ast.stmt.ForStatement;
95 import org.codehaus.groovy.ast.stmt.IfStatement;
96 import org.codehaus.groovy.ast.stmt.ReturnStatement;
97 import org.codehaus.groovy.ast.stmt.Statement;
98 import org.codehaus.groovy.ast.stmt.SwitchStatement;
99 import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
100 import org.codehaus.groovy.ast.stmt.ThrowStatement;
101 import org.codehaus.groovy.ast.stmt.TryCatchStatement;
102 import org.codehaus.groovy.ast.stmt.WhileStatement;
103 import org.codehaus.groovy.control.SourceUnit;
104 import org.codehaus.groovy.syntax.CSTNode;
105 import org.codehaus.groovy.syntax.Token;
106 import org.codehaus.groovy.syntax.Types;
107 import org.codehaus.groovy.syntax.Numbers;
108 import org.codehaus.groovy.GroovyBugError;
109 import org.objectweb.asm.Constants;
110
111
112
113 /***
114 * Builds an Abstract Syntax Tree from the Concrete Syntax Tree produced
115 * by the Parser. The resulting AST is very preliminary, and must still
116 * be validated and massaged before it is ready to be used.
117 * <code>build()</code> is the primary entry point.
118 *
119 * @author James Strachan
120 * @author Bob McWhirter
121 * @author Sam Pullara
122 * @author Chris Poirier
123 */
124
125 public class ASTBuilder
126 {
127
128 private static final String[] EMPTY_STRING_ARRAY = new String[0];
129 private static final String[] DEFAULT_IMPORTS = { "java.lang.", "groovy.lang.", "groovy.util." };
130
131
132
133
134
135
136
137 private SourceUnit controller;
138 private ClassLoader classLoader;
139 private Map imports;
140 private String packageName/package-summary.html">ong> String packageName;
141 private List newClasses = new ArrayList();
142 private ModuleNode output;
143
144
145 /***
146 * Initializes the <code>ASTBuilder</code>.
147 */
148
149 public ASTBuilder( SourceUnit sourceUnit, ClassLoader classLoader )
150 {
151 this.controller = sourceUnit;
152 this.classLoader = classLoader;
153 this.imports = new HashMap();
154 this.packageName = null;
155 }
156
157
158
159 /***
160 * Returns our class loader (as supplied on construction).
161 */
162
163 public ClassLoader getClassLoader()
164 {
165 return this.classLoader;
166 }
167
168
169
170
171
172
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
187
188
189
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
214
215
216 /***
217 * Processes the Reduction produced by Parser.packageDeclaration().
218 */
219
220 protected String packageDeclaration( CSTNode reduction )/package-summary.html">ong> String 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
255
256 String importPackage = makeName( reduction.get(1), null );
257
258
259
260
261
262
263 if( reduction.get(2).isA(Types.STAR) )
264 {
265 String[] 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
275
276 else
277 {
278 for( int i = 2; i < reduction.size(); i++ )
279 {
280 CSTNode clause = reduction.get(i);
281 String name = identifier( clause );
282 String as = (clause.hasChildren() ? identifier(clause.get(1)) : name);
283
284
285
286
287
288
289
290
291
292
293 module.addImport( as, name );
294
295 name = dot( importPackage, name );
296
297
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
343
344 String name = identifier( reduction );
345 this.newClasses.add(name);
346 int modifiers = modifiers( reduction.get(1) );
347 String parent = resolveName( reduction.get(2).get(1) );
348
349
350
351
352
353 CSTNode interfaceReduction = reduction.get(3);
354 String[] interfaces = new String[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
363
364 ClassNode classNode = (
365 context == null
366 ClassNode( dot(packageName, name), modifiers, parent, interfaces, MixinNode/EMPTY_ARRAY )/package-summary.html">? new ClassNode( dot(packageName, name), modifiers, parent, interfaces, MixinNode.EMPTY_ARRAY )
367 InnerClassNode( context, dot(packageName, name), modifiers, parent, interfaces, MixinNode/EMPTY_ARRAY )/package-summary.html">: 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 name = identifier( reduction );
420 int modifiers = modifiers( reduction.get(1) ) | extraModifiers;
421 String 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 className = null;
451 if( classNode != null )
452 {
453 className = classNode.getNameWithoutPackage();
454 }
455
456
457
458
459
460 String name = identifier( reduction );
461 int modifiers = modifiers( reduction.get(1) ) | extraModifiers;
462 String type = resolveName( reduction.get(2) );
463
464 Parameter[] parameters = parameterDeclarations( reduction.get(3) );
465 BlockStatement body = statementBody( reduction.get(5) );
466
467
468
469
470
471 CSTNode clause = reduction.get(4);
472 String[] throwTypes = new String[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
483
484 if( name.length() == 0 )
485 {
486 throw new GroovyBugError( "NOT YET IMPLEMENTED: static initializers" );
487
488
489
490
491
492
493
494
495
496
497 }
498
499
500
501
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
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 identifier = identifier( node );
557 String 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
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624 }
625
626
627
628
629
630
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
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 type = resolveName( element.get(1) );
997 String 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
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
1032
1033 else
1034 {
1035
1036 Type type = typeExpression( header.get(1) );
1037 String 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
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 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
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 text = reduction.getRootText();
1366 String signed = negate ? "-" + text : text;
1367
1368 boolean isInteger = (token.getMeaning() == Types.INTEGER_NUMBER);
1369
1370 try
1371 {
1372 Number number = isInteger ? Numbers.parseInteger(signed) : Numbers.parseDecimal(signed);
1373
1374 return new ConstantExpression( number );
1375 }
1376 catch( NumberFormatException 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 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 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 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 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 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 type = resolveName( reduction.get(1) );
1543
1544
1545
1546
1547
1548 if( reduction.size() == 3 )
1549 {
1550 CSTNode node = reduction.get(2);
1551
1552 VariableExpression name = variableExpression( node, type );
1553
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
1566
1567
1568
1569
1570
1571
1572
1573
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
1590
1591 CSTNode descriptor = reduction.get(1);
1592 Expression context = null;
1593 boolean implicit = false;
1594 String 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
1641
1642 Expression parameters = parameterList( reduction.get(2) );
1643
1644
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 type = resolveName( typeNode );
1699
1700
1701
1702
1703
1704 if( typeNode.getMeaning() == Types.LEFT_SQUARE_BRACKET )
1705 {
1706 CSTNode dimensions = reduction.get(2);
1707
1708
1709
1710
1711
1712
1713
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
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
1743
1744 else
1745 {
1746 if( dimensions.size() > 2 )
1747 {
1748 throw new GroovyBugError( "NOT YET IMPLEMENTED: multidimensional arrays" );
1749
1750
1751
1752
1753
1754
1755 }
1756 else
1757 {
1758 expression = new ArrayExpression( type, expression(dimensions.get(1)) );
1759 }
1760 }
1761 }
1762
1763
1764
1765
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
1904
1905 private static HashMap resolutions = new HashMap();
1906 private static String NOT_RESOLVED = new String();
1907
1908
1909 /***
1910 * Converts a CSTNode representation of a type name back into
1911 * a string.
1912 */
1913
1914 protected String makeName( CSTNode root, String defaultName )
1915 {
1916 if( root == null )
1917 {
1918 return defaultName;
1919 }
1920
1921 String 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 makeName( CSTNode root )
1967 {
1968 return makeName( root, "" );
1969 }
1970
1971
1972
1973 /***
1974 * Returns the text of an identifier.
1975 */
1976
1977 protected String 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 resolveName( String name, boolean safe )
1990 {
1991
1992
1993
1994 String resolution = (String)resolutions.get( name );
1995 if( resolution == NOT_RESOLVED )
1996 {
1997 return (safe ? name : null);
1998 }
1999 else if( resolution != null )
2000 {
2001 return (String)resolution;
2002 }
2003
2004
2005 do
2006 {
2007
2008
2009
2010
2011 if( name.indexOf(".") >= 0 )
2012 {
2013 resolution = name;
2014 break;
2015 }
2016
2017
2018
2019
2020
2021
2022 String scalar = name, postfix = "";
2023 while( scalar.endsWith("[]") )
2024 {
2025 scalar = scalar.substring( 0, scalar.length() - 2 );
2026 postfix += "[]";
2027 }
2028
2029
2030
2031
2032
2033 if( Types.ofType(Types.lookupKeyword(scalar), Types.PRIMITIVE_TYPE) )
2034 {
2035 resolution = name;
2036 break;
2037 }
2038
2039
2040
2041
2042
2043
2044 if( this.imports.containsKey(scalar) )
2045 {
2046 resolution = ((String)this.imports.get(scalar)) + postfix;
2047 break;
2048 }
2049
2050
2051
2052
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;
2062 }
2063 catch( Throwable e )
2064 {
2065
2066 }
2067 }
2068
2069
2070 List packageImports = output.getImportPackages();
2071 for (int i = 0; i < packageImports.size(); i++) {
2072 String pack = (String) packageImports.get(i);
2073 String clsName = pack + name;
2074 try {
2075 getClassLoader().loadClass( clsName );
2076 resolution = clsName;
2077 break;
2078 } catch (Throwable e) {
2079
2080 }
2081 }
2082 if (resolution != null)
2083 break;
2084
2085
2086
2087
2088 for( int i = 0; i < DEFAULT_IMPORTS.length; i++ )
2089 {
2090 try
2091 {
2092 String qualified = DEFAULT_IMPORTS[i] + scalar;
2093 getClassLoader().loadClass( qualified );
2094
2095 resolution = qualified + postfix;
2096 break;
2097 }
2098 catch( Throwable e )
2099 {
2100
2101 }
2102 }
2103
2104 } while( false );
2105
2106
2107
2108
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 resolveName( CSTNode root, boolean safe )
2134 {
2135 String 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 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 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 dot( String base, String 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 dot( String base )
2191 {
2192 return dot( base, "" );
2193 }
2194
2195
2196
2197
2198
2199
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
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
2295
2296
2297 /***
2298 * Throws a <code>ParserException</code>.
2299 */
2300
2301 protected void error( String description, CSTNode node ) throws ParserException
2302 {
2303 throw new ParserException( description, node.getRoot() );
2304 }
2305
2306
2307 }