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 org.codehaus.groovy.GroovyBugError;
49 import org.codehaus.groovy.control.CompilationFailedException;
50 import org.codehaus.groovy.control.SourceUnit;
51 import org.codehaus.groovy.control.messages.SimpleMessage;
52 import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
53 import org.codehaus.groovy.syntax.CSTNode;
54 import org.codehaus.groovy.syntax.ReadException;
55 import org.codehaus.groovy.syntax.Reduction;
56 import org.codehaus.groovy.syntax.SyntaxException;
57 import org.codehaus.groovy.syntax.Token;
58 import org.codehaus.groovy.syntax.TokenStream;
59 import org.codehaus.groovy.syntax.Types;
60
61 /***
62 * Reads the source text and produces a Concrete Syntax Tree. Exceptions
63 * are collected during processing, and parsing will continue for while
64 * possible, in order to report as many problems as possible.
65 * <code>module()</code> is the primary entry point.
66 *
67 * @author Bob McWhirter
68 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
69 * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
70 */
71
72 public class Parser
73 {
74 private SourceUnit controller = null;
75 private TokenStream tokenStream = null;
76 private int nestCount = 1;
77
78
79
80
81
82
83 /***
84 * Sets the <code>Parser</code> to process a <code>TokenStream</code>,
85 * under control of the specified <code>SourceUnit</code>.
86 */
87
88 public Parser( SourceUnit controller, TokenStream tokenStream )
89 {
90 this.controller = controller;
91 this.tokenStream = tokenStream;
92 }
93
94
95 /***
96 * Synonym for module(), the primary entry point.
97 */
98
99 public Reduction parse() throws CompilationFailedException
100 {
101 try
102 {
103 return module();
104 }
105 catch( SyntaxException e )
106 {
107 controller.addFatalError( new SyntaxErrorMessage(e) );
108 }
109
110 throw new GroovyBugError( "this will never happen" );
111 }
112
113
114
115 /***
116 * Returns the <code>TokenStream</code> being parsed.
117 */
118
119 public TokenStream getTokenStream()
120 {
121 return this.tokenStream;
122 }
123
124
125
126
127
128
129
130
131 /***
132 * Eats any optional newlines.
133 */
134
135 public void optionalNewlines() throws SyntaxException, CompilationFailedException
136 {
137 while( lt(false) == Types.NEWLINE)
138 {
139 consume( Types.NEWLINE );
140 }
141 }
142
143
144
145 /***
146 * Eats a required end-of-statement (semicolon or newline) from the stream.
147 * Throws an <code>UnexpectedTokenException</code> if anything else is found.
148 */
149
150 public void endOfStatement( boolean allowRightCurlyBrace ) throws SyntaxException, CompilationFailedException
151 {
152 Token next = la( true );
153
154 if( next.isA(Types.GENERAL_END_OF_STATEMENT) )
155 {
156 consume( true );
157 }
158 else
159 {
160 if( allowRightCurlyBrace )
161 {
162 if( !next.isA(Types.RIGHT_CURLY_BRACE) )
163 {
164 error( new int[] { Types.SEMICOLON, Types.NEWLINE, Types.RIGHT_CURLY_BRACE } );
165 }
166 }
167 else
168 {
169 error( new int[] { Types.SEMICOLON, Types.NEWLINE } );
170 }
171 }
172 }
173
174
175
176 /***
177 * A synonym for <code>endOfStatement( true )</code>.
178 */
179
180 public void endOfStatement() throws SyntaxException, CompilationFailedException
181 {
182 endOfStatement( true );
183 }
184
185
186
187
188
189
190
191
192 /***
193 * Processes a dotted identifer. Used all over the place.
194 * <p>
195 * Grammar: <pre>
196 * dottedIdentifier = <identifier> ("." <identifier>)*
197 * </pre>
198 * <p>
199 * CST: <pre>
200 * dotted = { "." dotted <identifier> } | <identifier>
201 * </pre>
202 */
203
204 public CSTNode dottedIdentifier() throws SyntaxException, CompilationFailedException
205 {
206 CSTNode identifier = consume(Types.IDENTIFIER);
207
208 while (lt() == Types.DOT)
209 {
210 identifier = consume(Types.DOT).asReduction( identifier, consume(Types.IDENTIFIER) );
211 }
212
213 return identifier;
214 }
215
216
217
218 /***
219 * The primary file-level parsing entry point. The returned CST
220 * represents the content in a single class file. Collects most
221 * exceptions and attempts to continue.
222 * <p>
223 * Grammar: <pre>
224 * module = [packageStatement]
225 * (usingStatement)*
226 * (topLevelStatement)*
227 * <eof>
228 * </pre>
229 * <p>
230 * CST: <pre>
231 * module = { <null> package imports (topLevelStatement)* }
232 *
233 * package see packageDeclaration()
234 * imports see importStatement()
235 * topLevelStatement see topLevelStatement()
236 * </pre>
237 *
238 */
239
240 public Reduction module() throws SyntaxException, CompilationFailedException
241 {
242 Reduction module = Reduction.newContainer();
243
244
245
246
247
248
249 Reduction packageDeclaration = null/package-summary.html">Reduction packageDeclaration = null;
250
251 if( lt() == Types.KEYWORD_PACKAGE )
252 {
253 try
254 {
255 packageDeclaration = packageDeclaration();
256 }
257
258 catch (SyntaxException e)
259 {
260 controller.addError(e);
261 recover();
262 }
263 }
264
265 ifstrong>( packageDeclaration == null )
266 {
267 packageDeclaration = Reduction.EMPTY;
268 }
269
270 module.add( packageDeclaration );
271
272
273
274
275
276 Reduction imports = (Reduction)module.add( Reduction.newContainer() );
277 Object collector;
278
279 while( lt() == Types.KEYWORD_IMPORT )
280 {
281 try
282 {
283 imports.add( importStatement() );
284 }
285
286 catch( SyntaxException e )
287 {
288 controller.addError(e);
289 recover();
290 }
291 }
292
293
294
295
296
297 while( lt() != Types.EOF )
298 {
299 try
300 {
301 module.add( topLevelStatement() );
302 }
303 catch (SyntaxException e)
304 {
305 controller.addError(e);
306 recover();
307 }
308 }
309
310 return module;
311 }
312
313
314
315 /***
316 * Processes a package declaration. Called by <code>module()</code>.
317 * <p>
318 * Grammar: <pre>
319 * packageDeclaration = "package" dottedIdentifier <eos>
320 * </pre>
321 * <p>
322 * CST: <pre>
323 * package = { "package" dottedIdentifier }
324 *
325 * see dottedIdentifier()
326 * </pre>
327 */
328
329 public Reduction packageDeclaration() throws SyntaxException, CompilationFailedException/package-summary.html">ong> Reduction packageDeclaration() throws SyntaxException, CompilationFailedException
330 {
331 Reduction packageDeclaration = consume(Types/KEYWORD_PACKAGE)/asReduction( dottedIdentifier() )/package-summary.html">Reduction packageDeclaration = consume(Types.KEYWORD_PACKAGE).asReduction( dottedIdentifier() );
332 endOfStatement( false );
333
334 return</strong> packageDeclaration;
335 }
336
337
338
339 /***
340 * Processes an import statement. Called by <code>module()</code>.
341 * <p>
342 * Grammar: <pre>
343 * importStatement = "import" (all|specific) <eos>
344 *
345 * all = package "." (package ".")* "*"
346 *
347 * specific = (package "." (package ".")*)? classes
348 * classes = class ["as" alias] ("," class ["as" alias])*
349 *
350 * package = <identifier>
351 * class = <identifier>
352 * alias = <identifier>
353 * </pre>
354 * <p>
355 * CST: <pre>
356 * import = { "import" (package|{}) ({"*"} | clause+) }
357 *
358 * package = { "." package <identifier> } | <identifier>
359 * clause = { <identifier> <alias>? }
360 * </pre>
361 */
362
363 public Reduction importStatement() throws SyntaxException, CompilationFailedException
364 {
365 Reduction importStatement = consume(Types.KEYWORD_IMPORT).asReduction();
366
367
368
369
370 CSTNode packageNode = null/package-summary.html">CSTNode packageNode = null;
371 if( lt(2) == Types.DOT )
372 {
373 packageNode = consume(Types.IDENTIFIER).asReduction();
374
375 while( lt(3) == Types.DOT )
376 {
377 packageNode = consume(Types.DOT).asReduction( packageNode );
378 packageNode.add( consume(Types.IDENTIFIER) );
379 }
380
381 consume( Types.DOT );
382 }
383
384 ifstrong>( packageNode == null )
385 {
386 packageNode = Reduction.EMPTY;
387 }
388
389 importStatement.add( packageNode );
390
391
392
393
394
395 if( !packageNode.isEmpty() && lt() == Types.STAR )
396 {
397 importStatement.add( consume(Types.STAR) );
398 }
399 else
400 {
401 boolean done = false;
402 while( !done )
403 {
404 Reduction clause = consume(Types.IDENTIFIER).asReduction();
405 if( lt() == Types.KEYWORD_AS )
406 {
407 consume( Types.KEYWORD_AS );
408 clause.add( consume(Types.IDENTIFIER) );
409 }
410
411 importStatement.add( clause );
412
413 if( lt() == Types.COMMA )
414 {
415 consume( Types.COMMA );
416 }
417 else
418 {
419 done = true;
420 }
421 }
422
423 }
424
425
426
427
428 endOfStatement( false );
429 return importStatement;
430 }
431
432
433
434 /***
435 * Processes a top level statement (classes, interfaces, unattached methods, and
436 * unattached code). Called by <code>module()</code>.
437 * <p>
438 * Grammar: <pre>
439 * topLevelStatement
440 * = methodDeclaration
441 * | typeDeclaration
442 * | statement
443 *
444 * typeDeclaration = classDeclaration | interfaceDeclaration
445 * </pre>
446 * <p>
447 * Recognition: <pre>
448 * "def" => methodDeclaration
449 * "synchronized" "(" => synchronizedStatement
450 * modifierList "class" => classDeclaration
451 * modifierList "interface" => interfaceDeclaration
452 * modifierList => <error>
453 * * => statement
454 * </pre>
455 * <p>
456 * CST: <pre>
457 * see methodDeclaration()
458 * see classDeclaration()
459 * see interfaceDeclaration()
460 * see statement()
461 * see synchronizedStatement()
462 * </pre>
463 */
464
465 public CSTNode topLevelStatement() throws SyntaxException, CompilationFailedException
466 {
467 CSTNode result = null;
468
469
470
471
472
473
474
475
476 if (lt() == Types.KEYWORD_DEF)
477 {
478 consume();
479
480 Reduction modifiers = modifierList( false, false );
481 CSTNode type = optionalDatatype( false, true );
482 Token identifier = nameDeclaration( false );
483
484 result = methodDeclaration(modifiers, type, identifier, false);
485 }
486
487 else if (lt() == Types.KEYWORD_DEFMACRO)
488 {
489
490 }
491
492
493
494
495
496 else if( lt() == Types.KEYWORD_SYNCHRONIZED && lt(2) == Types.LEFT_PARENTHESIS )
497 {
498 result = synchronizedStatement();
499 }
500
501
502
503
504
505 else if( la().isA(Types.DECLARATION_MODIFIER) || la().isA(Types.TYPE_DECLARATION) )
506 {
507 Reduction modifiers = modifierList( true, true );
508
509 switch( lt() )
510 {
511 case Types.KEYWORD_CLASS:
512 {
513 result = classDeclaration( modifiers );
514 break;
515 }
516
517 case Types.KEYWORD_INTERFACE:
518 {
519 result = interfaceDeclaration( modifiers );
520 break;
521 }
522
523 default:
524 {
525 error( new int[] { Types.KEYWORD_CLASS, Types.KEYWORD_INTERFACE } );
526 break;
527 }
528 }
529 }
530
531
532
533
534 else
535 {
536 result = statement();
537 }
538
539 return result;
540 }
541
542
543
544 /***
545 * A synomym for <code>topLevelStatement()</code>.
546 */
547
548 public CSTNode typeDeclaration() throws SyntaxException, CompilationFailedException
549 {
550 return topLevelStatement();
551 }
552
553
554
555 /***
556 * Processes the modifiers list that can appear on top- and class-level
557 * method and class-level variable names (public, private, abstract, etc.).
558 * <p>
559 * Grammar: <pre>
560 * modifierList = <modifier>*
561 * </pre>
562 * <p>
563 * CST: <pre>
564 * modifiers = { <null> <modifier>* }
565 * </pre>
566 */
567
568 public Reduction modifierList(boolean allowStatic, boolean allowAbstract) throws CompilationFailedException, SyntaxException
569 {
570 Reduction modifiers = Reduction.newContainer();
571
572 while( la().isA(Types.DECLARATION_MODIFIER) )
573 {
574 if( lt() == Types.KEYWORD_ABSTRACT && !allowAbstract)
575 {
576 controller.addError( "keyword 'abstract' not valid in this setting", la() );
577 }
578 else if (lt() == Types.KEYWORD_STATIC && !allowStatic)
579 {
580 controller.addError( "keyword 'static' not valid in this setting", la() );
581 }
582 modifiers.add( consume() );
583 }
584
585 return modifiers;
586 }
587
588
589
590 /***
591 * Processes a class declaration. Caller has already processed the declaration
592 * modifiers, and passes them in.
593 * <p>
594 * Grammar: <pre>
595 * classDeclaration = <modifier>* "class" <identifier>
596 * ["extends" datatype]
597 * ["implements" datatype (, datatype)*]
598 * typeBody
599 * </pre>
600 * <p>
601 * CST: <pre>
602 * class = { <identifier>:SYNTH_CLASS modifiers extends implements body }
603 * extends = { "extends" datatype } | {}
604 * implements = { "implements" datatype* } | {}
605 *
606 * modifiers see modifierList()
607 * datatype see datatype()
608 * body see typeBody()
609 * </pre>
610 */
611
612 public Reduction classDeclaration( Reduction modifiers ) throws SyntaxException, CompilationFailedException
613 {
614 consume( Types.KEYWORD_CLASS );
615
616 Reduction classDeclaration = consume(Types.IDENTIFIER).asReduction( modifiers );
617 classDeclaration.setMeaning( Types.SYNTH_CLASS );
618
619
620
621
622
623 try
624 {
625 classDeclaration.add( typeList(Types.KEYWORD_EXTENDS, true, 1) );
626 }
627 catch (SyntaxException e)
628 {
629 controller.addError(e);
630 classDeclaration.add( Reduction.EMPTY );
631 }
632
633
634
635
636
637 try
638 {
639 classDeclaration.add( typeList(Types.KEYWORD_IMPLEMENTS, true, 0) );
640 }
641 catch (SyntaxException e)
642 {
643 controller.addError(e);
644 classDeclaration.add( Reduction.EMPTY );
645 }
646
647
648
649
650
651 classDeclaration.add( typeBody(true, true, false) );
652
653 return classDeclaration;
654 }
655
656
657
658 /***
659 * Processes a interface declaration. Caller has already processed the
660 * declaration modifiers, and passes them in.
661 * <p>
662 * Grammar: <pre>
663 * interfaceDeclaration = <modifier>* "interface" <identifier>
664 * ["extends" typeList]
665 * typeBody
666 * </pre>
667 * <p>
668 * CST: <pre>
669 * interface = { <identifier>:SYNTH_INTERFACE modifiers {} extends body }
670 * extends = { "extends" datatype* } | {}
671 *
672 * modifiers see modifierList()
673 * datatype see datatype()
674 * body see typeBody()
675 * </pre>
676 */
677
678 public Reduction interfaceDeclaration( Reduction modifiers ) throws SyntaxException, CompilationFailedException
679 {
680 consume( Types.KEYWORD_INTERFACE );
681
682 Reduction interfaceDeclaration = consume(Types.IDENTIFIER).asReduction( modifiers, Reduction.EMPTY );
683 interfaceDeclaration.setMeaning( Types.SYNTH_INTERFACE );
684
685
686
687
688
689 try
690 {
691 interfaceDeclaration.add( typeList(Types.KEYWORD_EXTENDS, true, 0) );
692 }
693 catch (SyntaxException e)
694 {
695 controller.addError(e);
696 interfaceDeclaration.add( Reduction.EMPTY );
697 }
698
699
700
701
702
703
704 interfaceDeclaration.add( typeBody(false, true, true) );
705 return interfaceDeclaration;
706 }
707
708
709
710 /***
711 * Processes a type list, like the ones that occur after "extends" or
712 * implements. If the list is optional, the returned CSTNode will
713 * be empty.
714 * <p>
715 * Grammar: <pre>
716 * typeList = <declarator> datatype (, datatype)*
717 * </pre>
718 * <p>
719 * CST: <pre>
720 * typeList = { <declarator> datatype+ } | {}
721 *
722 * datatype see datatype()
723 * </pre>
724 */
725
726 public Reduction typeList(int declarator, boolean optional, int limit) throws SyntaxException, CompilationFailedException
727 {
728 Reduction typeList = null;
729
730 if( lt() == declarator )
731 {
732 typeList = consume(declarator).asReduction();
733
734
735
736
737
738 while( limit == 0 || typeList.children() < limit )
739 {
740
741
742
743 try
744 {
745 if( typeList.children() > 0)
746 {
747 consume( Types.COMMA );
748 }
749
750 typeList.add( datatype(false) );
751 }
752 catch (SyntaxException e)
753 {
754 controller.addError(e);
755 recover( Types.TYPE_LIST_TERMINATORS );
756 }
757
758
759
760
761
762
763 if( !la().isA(Types.COMMA) )
764 {
765 break;
766 }
767 }
768 }
769
770 else
771 {
772 if (optional)
773 {
774 typeList = Reduction.EMPTY;
775 }
776 else
777 {
778 error( declarator );
779 }
780 }
781
782 return typeList;
783 }
784
785
786
787 /***
788 * Processes the body of an interface or class.
789 * <p>
790 * Grammar: <pre>
791 * typeBody = "{" typeBodyStatement* "}"
792 * </pre>
793 * <p>
794 * CST: <pre>
795 * body = { <null> typeBodyStatement* }
796 *
797 * typeBodyStatement see typeBodyStatement()
798 * </pre>
799 */
800
801 public Reduction typeBody(boolean allowStatic, boolean allowAbstract, boolean requireAbstract) throws SyntaxException, CompilationFailedException
802 {
803 Reduction body = Reduction.newContainer();
804
805 consume( Types.LEFT_CURLY_BRACE );
806
807 while( lt() != Types.EOF && lt() != Types.RIGHT_CURLY_BRACE )
808 {
809 try
810 {
811 body.add( typeBodyStatement(allowStatic, allowAbstract, requireAbstract) );
812 }
813 catch( SyntaxException e )
814 {
815 controller.addError(e);
816 recover();
817 }
818 }
819
820 consume( Types.RIGHT_CURLY_BRACE );
821
822 return body;
823 }
824
825
826
827 /***
828 * Processes a single entry in the the body of an interface or class.
829 * Valid objects are constructors, methods, properties, static initializers,
830 * and inner classes or interfaces.
831 * <p>
832 * Grammar: <pre>
833 * typeBodyStatement
834 * = staticInitializer
835 * | classDeclaration
836 * | interfaceDeclaration
837 * | propertyDeclaration
838 * | methodDeclaration
839 *
840 * staticInitializer = ("static" "{" statement* "}")
841 * </pre>
842 * <p>
843 * Recognition: <pre>
844 * "static" "{" => staticInitializer
845 * modifierList "class" => classDeclaration
846 * modifierList "interface" => interfaceDeclaration
847 * modifierList ["property"] optionalDatatype identifier "(" => methodDeclaration
848 * modifierList ["property"] optionalDatatype identifier ("="|";"|"\n"|"}" => propertyDeclaration
849 * * => <error>
850 * </pre>
851 * <p>
852 * CST: <pre>
853 * see classDeclaration()
854 * see interfaceDeclaration()
855 * see methodDeclaration()
856 * see propertyDeclaration()
857 * </pre>
858 */
859
860 public Reduction typeBodyStatement(boolean allowStatic, boolean allowAbstract, boolean requireAbstract) throws SyntaxException, CompilationFailedException
861 {
862 Reduction statement = null;
863
864
865
866
867
868 if( lt() == Types.KEYWORD_STATIC && lt(2) == Types.LEFT_CURLY_BRACE )
869 {
870 if (!allowStatic)
871 {
872 controller.addError( "static initializers not valid in this context", la() );
873 }
874
875 Reduction modifiers = modifierList( true, false );
876 Token identifier = Token.NULL;
877 statement = methodDeclaration( modifiers, Reduction.EMPTY, identifier, false );
878 }
879
880
881
882
883 else
884 {
885 Reduction modifiers = modifierList( allowStatic, allowAbstract );
886
887
888
889
890 if( lt() == Types.KEYWORD_CLASS )
891 {
892 statement = classDeclaration( modifiers );
893 }
894
895 else if( lt() == Types.KEYWORD_INTERFACE )
896 {
897 statement = interfaceDeclaration( modifiers );
898 }
899
900
901
902
903 else
904 {
905
906
907
908 if( lt() == Types.KEYWORD_PROPERTY )
909 {
910 consume();
911 }
912
913
914
915
916
917
918
919
920 while( lt(true) == Types.NEWLINE)
921 {
922 consume( Types.NEWLINE );
923 }
924
925
926
927
928 CSTNode type = optionalDatatype( true, true );
929 Token identifier = nameDeclaration( true );
930
931 switch( lt(true) )
932 {
933 case Types.LEFT_PARENTHESIS :
934 {
935
936
937
938
939 boolean methodIsAbstract = requireAbstract;
940
941 if( !methodIsAbstract )
942 {
943 for( int i = 1; i < modifiers.size(); i++ )
944 {
945 if( modifiers.get(i).getMeaning() == Types.KEYWORD_ABSTRACT )
946 {
947 methodIsAbstract = true;
948 break;
949 }
950 }
951 }
952
953 statement = methodDeclaration( modifiers, type, identifier, methodIsAbstract );
954 break;
955 }
956
957 case Types.EQUAL:
958 case Types.SEMICOLON:
959 case Types.NEWLINE:
960 case Types.RIGHT_CURLY_BRACE:
961 case Types.EOF:
962 statement = propertyDeclaration( modifiers, type, identifier );
963 break;
964
965 default:
966 error( new int[] { Types.LEFT_PARENTHESIS, Types.EQUAL, Types.SEMICOLON, Types.NEWLINE, Types.RIGHT_CURLY_BRACE } );
967 }
968 }
969 }
970
971 return statement;
972 }
973
974
975
976 /***
977 * A synonym for <code>typeBodyStatement( true, true, false )</code>.
978 */
979
980 public Reduction bodyStatement() throws SyntaxException, CompilationFailedException
981 {
982 return typeBodyStatement( true, true, false );
983 }
984
985
986
987 /***
988 * Processes a name that is valid for declarations. Newlines can be made
989 * significant, if required for disambiguation.
990 * <p>
991 * Grammar: <pre>
992 * nameDeclaration = <identifier>
993 * </pre>
994 * <p>
995 * CST: <pre>
996 * name = <identifier>
997 * </pre>
998 */
999
1000 protected Token nameDeclaration( boolean significantNewlines ) throws SyntaxException, CompilationFailedException
1001 {
1002 return consume( Types.IDENTIFIER, significantNewlines );
1003 }
1004
1005
1006
1007 /***
1008 * Processes a reference to a declared name. Newlines can be made significant,
1009 * if required for disambiguation.
1010 * <p>
1011 * Grammar: <pre>
1012 * nameReference = <identifier> | <various keywords>
1013 * </pre>
1014 * <p>
1015 * CST: <pre>
1016 * name = <identifier>
1017 * </pre>
1018 */
1019
1020 protected Token nameReference( boolean significantNewlines ) throws SyntaxException, CompilationFailedException
1021 {
1022
1023 Token token = la( significantNewlines );
1024 if( !token.canMean(Types.IDENTIFIER) )
1025 {
1026 error( Types.IDENTIFIER );
1027 }
1028
1029 consume();
1030 token.setMeaning( Types.IDENTIFIER );
1031
1032 return token;
1033
1034 }
1035
1036
1037
1038 /***
1039 * Processes an optional data type marker (for a parameter, method return type,
1040 * etc.). Newlines can be made significant, if required for disambiguation.
1041 * <p>
1042 * Grammar: <pre>
1043 * optionalDatatype = datatype? (?=<identifier>)
1044 * </pre>h
1045 * <p>
1046 * CST: <pre>
1047 * result = datatype | {}
1048 *
1049 * see datatype()
1050 * </pre>
1051 */
1052
1053 protected CSTNode optionalDatatype( boolean significantNewlines, boolean allowVoid ) throws SyntaxException, CompilationFailedException
1054 {
1055 CSTNode type = Reduction.EMPTY;
1056 Token next = la(significantNewlines);
1057
1058
1059
1060
1061
1062
1063
1064 if( next.isA(Types.IDENTIFIER) )
1065 {
1066 if( lt(2, significantNewlines) == Types.IDENTIFIER )
1067 {
1068 type = datatype( allowVoid );
1069 }
1070 else
1071 {
1072 getTokenStream().checkpoint();
1073
1074 try
1075 {
1076 type = datatype( allowVoid );
1077 if( lt(significantNewlines) != Types.IDENTIFIER )
1078 {
1079 throw new Exception();
1080 }
1081 }
1082 catch( Exception e )
1083 {
1084 getTokenStream().restore();
1085 type = Reduction.EMPTY;
1086 }
1087 }
1088 }
1089
1090
1091
1092
1093
1094
1095 else if( next.isA(Types.PRIMITIVE_TYPE) )
1096 {
1097 type = datatype( allowVoid );
1098 }
1099
1100 return type;
1101 }
1102
1103
1104
1105
1106 /***
1107 * Processes a class/interface property, including the optional initialization
1108 * clause. The modifiers, type, and identifier have already been identified
1109 * by the caller, and are passed in.
1110 * <p>
1111 * Grammar: <pre>
1112 * propertyDeclaration = (modifierList optionalDatatype nameDeclaration ["=" expression]) <eos>
1113 * </pre>
1114 * <p>
1115 * CST: <pre>
1116 * property = { <identifier>:SYNTH_PROPERTY modifierList optionalDatatype expression? }
1117 *
1118 * see modifierList()
1119 * see optionalDatatype()
1120 * see expression()
1121 * </pre>
1122 */
1123
1124 public Reduction propertyDeclaration( Reduction modifiers, CSTNode type, Token identifier ) throws SyntaxException, CompilationFailedException
1125 {
1126 Reduction property = identifier.asReduction( modifiers, type );
1127 property.setMeaning( Types.SYNTH_PROPERTY );
1128
1129 if( lt() == Types.EQUAL )
1130 {
1131 consume();
1132 property.add( expression() );
1133 }
1134
1135 endOfStatement();
1136 return property;
1137 }
1138
1139
1140
1141 /***
1142 * Processes a class/interface method. The modifiers, type, and identifier have
1143 * already been identified by the caller, and are passed in. If <code>emptyOnly</code>
1144 * is set, no method body will be allowed.
1145 * <p>
1146 * Grammar: <pre>
1147 * methodDeclaration = modifierList optionalDatatype identifier
1148 * "(" parameterDeclarationList ")"
1149 * [ "throws" typeList ]
1150 * ( statementBody | <eos> )
1151 * </pre>
1152 * <p>
1153 * CST: <pre>
1154 * method = { <identifier>:SYNTH_METHOD modifierList optionalDatatype
1155 * parameterDeclarationList throwsClause statementBody }
1156 *
1157 * throwsClause = { "throws" datatype+ } | {}
1158 *
1159 * see modifierList()
1160 * see optionalDatatype()
1161 * see parameterDeclarationList()
1162 * see statementBody()
1163 * </pre>
1164 */
1165
1166 public Reduction methodDeclaration( Reduction modifiers, CSTNode type, Token identifier, boolean emptyOnly) throws SyntaxException, CompilationFailedException
1167 {
1168 Reduction method = identifier.asReduction( modifiers, type );
1169 method.setMeaning( Types.SYNTH_METHOD );
1170
1171
1172
1173
1174 consume(Types.LEFT_PARENTHESIS);
1175 method.add( parameterDeclarationList() );
1176 consume(Types.RIGHT_PARENTHESIS);
1177
1178
1179
1180
1181 try
1182 {
1183 method.add( typeList( Types.KEYWORD_THROWS, true, 0 ) );
1184 }
1185 catch (SyntaxException e)
1186 {
1187 controller.addError(e);
1188 method.add( Reduction.EMPTY );
1189 }
1190
1191
1192
1193
1194
1195 CSTNode body = null;
1196
1197 if( emptyOnly )
1198 {
1199 if( lt() == Types.LEFT_CURLY_BRACE )
1200 {
1201 controller.addError( "abstract and interface methods cannot have a body", la() );
1202 }
1203 else
1204 {
1205 body = Reduction.EMPTY;
1206 endOfStatement();
1207 }
1208
1209 }
1210
1211 if( body == null )
1212 {
1213 body = statementBody(true);
1214 }
1215
1216 method.add( body );
1217
1218
1219 return method;
1220 }
1221
1222
1223
1224 /***
1225 * Processes a parameter declaration list, which can occur on methods and closures.
1226 * It loops as long as it finds a comma as the next token.
1227 * <p>
1228 * Grammar: <pre>
1229 * parameterDeclarationList
1230 * = (parameterDeclaration ("," parameterDeclaration)* ("," parameterDeclaration "=" expression)* )?
1231 * | (parameterDeclaration "=" expression ("," parameterDeclaration "=" expression)* )?
1232 * </pre>
1233 * <p>
1234 * CST: <pre>
1235 * parameters = { <null> parameter* }
1236 * parameter = { <identifier>:SYNTH_PARAMETER_DECLARATION optionalDatatype default? }
1237 * default = expression
1238 * </pre>
1239 */
1240
1241 protected Reduction parameterDeclarationList() throws SyntaxException, CompilationFailedException
1242 {
1243 Reduction list = Reduction.newContainer();
1244
1245 boolean expectDefaults = false;
1246 while( la().isA(Types.TYPE_NAME) )
1247 {
1248
1249
1250
1251
1252 Reduction parameter = (Reduction)list.add( parameterDeclaration() );
1253
1254
1255
1256
1257
1258 if( expectDefaults || lt() == Types.EQUAL )
1259 {
1260 expectDefaults = true;
1261 consume( Types.EQUAL );
1262
1263 parameter.add( expression() );
1264 }
1265
1266
1267
1268
1269 if( lt() == Types.COMMA )
1270 {
1271 consume( Types.COMMA );
1272 }
1273 else
1274 {
1275 break;
1276 }
1277 }
1278
1279 return list;
1280 }
1281
1282
1283
1284 /***
1285 * Processes a single parameter declaration, which can occur on methods and closures.
1286 * <p>
1287 * Grammar: <pre>
1288 * parameterDeclaration = optionalDatatype nameDeclaration
1289 * </pre>
1290 * <p>
1291 * CST: <pre>
1292 * parameter = { <identifier>:SYNTH_PARAMETER_DECLARATION optionalDatatype }
1293 *
1294 * see optionalDatatype()
1295 * </pre>
1296 */
1297
1298 protected Reduction parameterDeclaration() throws SyntaxException, CompilationFailedException
1299 {
1300 CSTNode type = optionalDatatype( false, false );
1301 Reduction parameter = nameDeclaration( false ).asReduction( type );
1302 parameter.setMeaning( Types.SYNTH_PARAMETER_DECLARATION );
1303
1304 return parameter;
1305 }
1306
1307
1308
1309 /***
1310 * Processes a datatype specification. For reasons of disambiguation,
1311 * the array marker ([]) must never be on a separate line from the
1312 * base datatype.
1313 * <p>
1314 * Grammar: <pre>
1315 * datatype = scalarDatatype ( "[" "]" )*
1316 *
1317 * scalarDatatype = dottedIdentifier | "void" | "int" | ...
1318 * </pre>
1319 * <p>
1320 * CST: <pre>
1321 * datatype = { "[" datatype } | scalar
1322 * scalar = dottedIdentifier | primitive
1323 * primitive = "void" | "int" | ...
1324 *
1325 * see dottedIdentifier()
1326 * </pre>
1327 */
1328
1329 protected CSTNode datatype( boolean allowVoid ) throws SyntaxException, CompilationFailedException
1330 {
1331 CSTNode datatype = scalarDatatype(allowVoid);
1332
1333 while( lt(true) == Types.LEFT_SQUARE_BRACKET )
1334 {
1335 datatype = consume(Types.LEFT_SQUARE_BRACKET).asReduction( datatype );
1336 consume( Types.RIGHT_SQUARE_BRACKET );
1337 }
1338
1339 return datatype;
1340 }
1341
1342
1343
1344 /***
1345 * A synonym for <code>datatype( true )</code>.
1346 */
1347
1348 protected CSTNode datatype() throws SyntaxException, CompilationFailedException
1349 {
1350 return datatype(true);
1351 }
1352
1353
1354
1355 /***
1356 * Processes a scalar datatype specification.
1357 * <p>
1358 * Grammar: <pre>
1359 * scalarDatatype = dottedIdentifier | "void" | "int" | ...
1360 * </pre>
1361 * <p>
1362 * CST: <pre>
1363 * scalar = dottedIdentifier | primitive
1364 * primitive = "void" | "int" | ...
1365 *
1366 * see dottedIdentifier()
1367 * </pre>
1368 */
1369
1370 protected CSTNode scalarDatatype( boolean allowVoid ) throws SyntaxException, CompilationFailedException
1371 {
1372 CSTNode datatype = null;
1373
1374 if( la().isA(allowVoid ? Types.PRIMITIVE_TYPE : Types.CREATABLE_PRIMITIVE_TYPE) )
1375 {
1376 datatype = consume();
1377 }
1378 else
1379 {
1380 datatype = dottedIdentifier();
1381 }
1382
1383 return datatype;
1384 }
1385
1386
1387
1388 /***
1389 * Processes the body of a complex statement (like "if", "for", etc.).
1390 * Set <code>requireBraces</code> if the body must not be just a single
1391 * statement.
1392 * <p>
1393 * Grammar: <pre>
1394 * statementBody = ("{" statement* "}")
1395 * | statement
1396 * </pre>
1397 * <p>
1398 * CST: <pre>
1399 * complex = { "{" statement* }
1400 * simple = statement
1401 *
1402 * see statement()
1403 * </pre>
1404 */
1405
1406 protected CSTNode statementBody( boolean requireBraces ) throws SyntaxException, CompilationFailedException
1407 {
1408 CSTNode body = null;
1409
1410 if (lt() == Types.LEFT_CURLY_BRACE)
1411 {
1412 Token brace = consume( Types.LEFT_CURLY_BRACE );
1413 brace.setMeaning( Types.SYNTH_BLOCK );
1414
1415 body = statementsUntilRightCurly();
1416 body.set( 0, brace );
1417
1418 consume( Types.RIGHT_CURLY_BRACE );
1419 }
1420 else
1421 {
1422 if( requireBraces )
1423 {
1424 error( Types.LEFT_CURLY_BRACE );
1425 }
1426 else
1427 {
1428 body = statement();
1429 }
1430 }
1431
1432 return body;
1433 }
1434
1435
1436
1437 /***
1438 * Reads statements until a "}" is met.
1439 * <p>
1440 * Grammar: <pre>
1441 * statementsUntilRightCurly = statement* (?= "}")
1442 * </pre>
1443 * <p>
1444 * CST: <pre>
1445 * statements = { <null> statement* }
1446 * </pre>
1447 */
1448
1449 protected Reduction statementsUntilRightCurly( ) throws SyntaxException, CompilationFailedException
1450 {
1451 Reduction block = Reduction.newContainer();
1452
1453 while( lt() != Types.EOF && lt() != Types.RIGHT_CURLY_BRACE )
1454 {
1455 try
1456 {
1457 block.add( statement() );
1458 }
1459 catch( SyntaxException e )
1460 {
1461 controller.addError( e );
1462 recover();
1463 }
1464 }
1465
1466
1467 return block;
1468 }
1469
1470
1471
1472
1473
1474
1475
1476 /***
1477 * Processes a single statement. Statements include: loop constructs, branch
1478 * constructs, flow control constructs, exception constructs, expressions of
1479 * a variety of types, and pretty much anything you can put inside a method.
1480 * <p>
1481 * Grammar: <pre>
1482 * statement = (label ":")? bareStatement
1483 * bareStatement = (emptyStatement|basicStatement|blockStatement)
1484 *
1485 * basicStatement = forStatement
1486 * | whileStatement
1487 * | doStatement
1488 * | continueStatement
1489 * | breakStatement
1490 * | ifStatement
1491 * | tryStatement
1492 * | throwStatement
1493 * | synchronizedStatement
1494 * | switchStatement
1495 * | returnStatement
1496 * | assertStatement
1497 * | expression <eos>
1498 *
1499 * label = <identifier>
1500 * blockStatement = "{" statement* "}"
1501 * emptyStatement = ";"
1502 * </pre>
1503 * <p>
1504 * Recognition: <pre>
1505 * ";" => emptyStatement
1506 * <keyword> => <keyword>Statement
1507 * "{" => expression, then:
1508 * if it is a closureExpression and has no parameters => blockStatement
1509 *
1510 * * => expression
1511 * </pre>
1512 * <p>
1513 * CST: <pre>
1514 * labelled = { <identifier>:SYNTH_LABEL bareStatement }
1515 * bareStatement = emptyStatement | blockStatement | basicStatement
1516 * emptyStatement = { "{" }
1517 * blockStatement = { "{" statement* }
1518 *
1519 * see forStatement()
1520 * see whileStatement()
1521 * see doStatement()
1522 * see continueStatement()
1523 * see breakStatement()
1524 * see ifStatement()
1525 * see tryStatement()
1526 * see throwStatement()
1527 * see synchronizedStatement()
1528 * see switchStatement()
1529 * see returnStatement()
1530 * see assertStatement()
1531 * see expression()
1532 * </pre>
1533 */
1534
1535 protected CSTNode statement( boolean allowUnlabelledBlocks ) throws SyntaxException, CompilationFailedException
1536 {
1537 CSTNode statement = null;
1538
1539
1540
1541
1542 CSTNode label = null;
1543 if( lt() == Types.IDENTIFIER && lt(2) == Types.COLON )
1544 {
1545 label = consume( Types.IDENTIFIER ).asReduction();
1546 label.setMeaning( Types.SYNTH_LABEL );
1547
1548 consume( Types.COLON );
1549 }
1550
1551
1552
1553
1554 switch( lt() )
1555 {
1556 case Types.KEYWORD_ASSERT:
1557 {
1558 statement = assertStatement();
1559 break;
1560 }
1561
1562 case Types.KEYWORD_BREAK:
1563 {
1564 statement = breakStatement();
1565 break;
1566 }
1567
1568 case Types.KEYWORD_CONTINUE:
1569 {
1570 statement = continueStatement();
1571 break;
1572 }
1573
1574 case Types.KEYWORD_IF:
1575 {
1576 statement = ifStatement();
1577 break;
1578 }
1579
1580 case Types.KEYWORD_RETURN:
1581 {
1582 statement = returnStatement();
1583 break;
1584 }
1585
1586 case Types.KEYWORD_SWITCH:
1587 {
1588 statement = switchStatement();
1589 break;
1590 }
1591
1592 case Types.KEYWORD_SYNCHRONIZED:
1593 {
1594 statement = synchronizedStatement();
1595 break;
1596 }
1597
1598 case Types.KEYWORD_THROW:
1599 {
1600 statement = throwStatement();
1601 break;
1602 }
1603
1604 case Types.KEYWORD_TRY:
1605 {
1606 statement = tryStatement();
1607 break;
1608 }
1609
1610 case Types.KEYWORD_FOR:
1611 {
1612 statement = forStatement();
1613 break;
1614 }
1615
1616 case Types.KEYWORD_DO:
1617 {
1618 statement = doWhileStatement();
1619 break;
1620 }
1621
1622 case Types.KEYWORD_WHILE:
1623 {
1624 statement = whileStatement();
1625 break;
1626 }
1627
1628 case Types.SEMICOLON:
1629 {
1630 statement = consume().asReduction();
1631 statement.setMeaning( Types.SYNTH_BLOCK );
1632 break;
1633 }
1634
1635 case Types.LEFT_CURLY_BRACE:
1636 {
1637
1638
1639
1640
1641
1642
1643
1644
1645 statement = expression();
1646 if( statement.isA(Types.SYNTH_CLOSURE) )
1647 {
1648 if( !statement.get(1).hasChildren() )
1649 {
1650 Reduction block = statement.getRoot().asReduction();
1651 block.setMeaning( Types.SYNTH_BLOCK );
1652 block.addChildrenOf( statement.get(2) );
1653
1654 if( label == null && !allowUnlabelledBlocks )
1655 {
1656 controller.addError( "groovy does not support anonymous blocks; please add a label", statement.getRoot() );
1657 }
1658
1659 statement = block;
1660 }
1661 }
1662 else
1663 {
1664
1665
1666
1667 endOfStatement();
1668 }
1669
1670 break;
1671 }
1672
1673 default:
1674 {
1675 try
1676 {
1677 statement = expression();
1678 endOfStatement();
1679 }
1680 catch (SyntaxException e)
1681 {
1682 controller.addError(e);
1683 recover();
1684 }
1685 }
1686 }
1687
1688
1689
1690
1691
1692 if( label != null )
1693 {
1694 label.add( statement );
1695 statement = label;
1696 }
1697
1698 return statement;
1699 }
1700
1701
1702
1703 /***
1704 * Synonym for <code>statement( false )</code>.
1705 */
1706
1707 protected CSTNode statement( ) throws SyntaxException, CompilationFailedException
1708 {
1709 return statement( false );
1710 }
1711
1712
1713
1714 /***
1715 * Processes an assert statement.
1716 * <p>
1717 * Grammar: <pre>
1718 * assertStatement = "assert" expression (":" expression) <eos>
1719 * </pre>
1720 * <p>
1721 * CST: <pre>
1722 * assert = { "assert" expression expression? }
1723 *
1724 * see expression()
1725 * </pre>
1726 */
1727
1728 protected Reduction assertStatement() throws SyntaxException, CompilationFailedException
1729 {
1730 Reduction statement = consume( Types.KEYWORD_ASSERT ).asReduction( expression() );
1731
1732 if( lt() == Types.COLON )
1733 {
1734 consume( Types.COLON );
1735 statement.add( expression() );
1736 }
1737
1738 endOfStatement();
1739
1740 return statement;
1741 }
1742
1743
1744
1745 /***
1746 * Processes a break statement. We require the label on the same line.
1747 * <p>
1748 * Grammar: <pre>
1749 * breakStatement = "break" label? <eos>
1750 *
1751 * label = <identifier>
1752 * </pre>
1753 * <p>
1754 * CST: <pre>
1755 * statement = { "break" label? }
1756 * label = <identifier>
1757 * </pre>
1758 */
1759
1760 protected Reduction breakStatement() throws SyntaxException, CompilationFailedException
1761 {
1762 Reduction statement = consume(Types.KEYWORD_BREAK).asReduction();
1763 if( lt(true) == Types.IDENTIFIER )
1764 {
1765 statement.add( consume() );
1766 }
1767
1768 endOfStatement();
1769 return statement;
1770
1771 }
1772
1773
1774
1775 /***
1776 * Processes a continue statement. We require the label on the same line.
1777 * <p>
1778 * Grammar: <pre>
1779 * continueStatement = "continue" label? <eos>
1780 *
1781 * label = <identifier>
1782 * </pre>
1783 * <p>
1784 * CST: <pre>
1785 * statement = { "continue" label? }
1786 * label = <identifier>
1787 * </pre>
1788 */
1789
1790 protected Reduction continueStatement() throws SyntaxException, CompilationFailedException
1791 {
1792 Reduction statement = consume(Types.KEYWORD_CONTINUE).asReduction();
1793 if( lt(true) == Types.IDENTIFIER )
1794 {
1795 statement.add( consume() );
1796 }
1797
1798 endOfStatement();
1799 return statement;
1800
1801 }
1802
1803
1804
1805 /***
1806 * Processes a throw statement.
1807 * <p>
1808 * Grammar: <pre>
1809 * throwStatement = "throw" expression <eos>
1810 * </pre>
1811 * <p>
1812 * CST: <pre>
1813 * statement = { "throw" expression }
1814 *
1815 * see expression()
1816 * </pre>
1817 */
1818
1819 protected Reduction throwStatement() throws SyntaxException, CompilationFailedException
1820 {
1821 Reduction statement = consume(Types.KEYWORD_THROW).asReduction( expression() );
1822 endOfStatement();
1823 return statement;
1824
1825 }
1826
1827
1828
1829 /***
1830 * Processes an if statement.
1831 * <p>
1832 * Grammar: <pre>
1833 * ifStatement = ifClause elseIfClause* elseClause?
1834 *
1835 * ifClause = "if" "(" expression ")" statementBody
1836 * elseIfClause = "else" "if" "(" expression ")" statementBody
1837 * elseClause = "else" statementBody
1838 * </pre>
1839 * <p>
1840 * CST: <pre>
1841 * if = { "if" expression statementBody else? }
1842 * else = if | { "else" statementBody }
1843 *
1844 * see expression()
1845 * see statementBody()
1846 * </pre>
1847 */
1848
1849 protected Reduction ifStatement() throws SyntaxException, CompilationFailedException
1850 {
1851
1852
1853
1854 Reduction statement = consume(Types.KEYWORD_IF).asReduction();
1855
1856 consume( Types.LEFT_PARENTHESIS );
1857
1858 try
1859 {
1860 statement.add( expression() );
1861 }
1862 catch( SyntaxException e )
1863 {
1864 controller.addError( e );
1865 recover( Types.RIGHT_PARENTHESIS );
1866 }
1867
1868 consume( Types.RIGHT_PARENTHESIS );
1869
1870 statement.add( statementBody(false) );
1871
1872
1873
1874
1875
1876
1877
1878 if( lt() == Types.KEYWORD_ELSE )
1879 {
1880 if( lt(2) == Types.KEYWORD_IF )
1881 {
1882 consume( Types.KEYWORD_ELSE );
1883 statement.add( ifStatement() );
1884 }
1885 else
1886 {
1887 Reduction last = (Reduction)statement.add( consume(Types.KEYWORD_ELSE).asReduction() );
1888 last.add( statementBody(false) );
1889 }
1890 }
1891
1892 return statement;
1893 }
1894
1895
1896
1897 /***
1898 * Processes a return statement. Any expression must start on the same line
1899 * as the "return".
1900 * <p>
1901 * Grammar: <pre>
1902 * returnStatement = "return" expression? <eos>
1903 * </pre>
1904 * <p>
1905 * CST: <pre>
1906 * statement = { "return" expression? }
1907 *
1908 * see expression()
1909 * </pre>
1910 */
1911
1912 protected Reduction returnStatement() throws SyntaxException, CompilationFailedException
1913 {
1914 Reduction statement = consume(Types.KEYWORD_RETURN).asReduction();
1915
1916 if( !la(true).isA(Types.ANY_END_OF_STATEMENT) )
1917 {
1918 statement.add( expression() );
1919 }
1920
1921 endOfStatement();
1922 return statement;
1923
1924 }
1925
1926
1927
1928 /***
1929 * Processes a switch statement.
1930 * <p>
1931 * Grammar: <pre>
1932 * switchStatment = "switch" "(" expression ")" "{" switchBody "}"
1933 *
1934 * switchBody = caseSet*
1935 * caseSet = (("case" expression ":")+ | ("default" ":")) statement+
1936 * </pre>
1937 * <p>
1938 * CST: <pre>
1939 * switch = { "switch" expression case* }
1940 * case = { "case" expression statement* }
1941 * | { "default" statement* }
1942 *
1943 * see expression()
1944 * see statement()
1945 * </pre>
1946 */
1947
1948 protected Reduction switchStatement() throws SyntaxException, CompilationFailedException
1949 {
1950 Reduction statement = consume(Types.KEYWORD_SWITCH).asReduction();
1951 consume( Types.LEFT_PARENTHESIS );
1952 statement.add( expression() );
1953 consume( Types.RIGHT_PARENTHESIS );
1954
1955
1956
1957
1958
1959 consume( Types.LEFT_CURLY_BRACE );
1960
1961 boolean defaultFound = false;
1962 while( lt() == Types.KEYWORD_CASE || lt() == Types.KEYWORD_DEFAULT )
1963 {
1964
1965
1966
1967 Reduction caseBlock = null;
1968 if( lt() == Types.KEYWORD_CASE )
1969 {
1970 caseBlock = consume( Types.KEYWORD_CASE ).asReduction( expression() );
1971 }
1972 else if( lt() == Types.KEYWORD_DEFAULT )
1973 {
1974 if( defaultFound )
1975 {
1976 controller.addError( "duplicate default entry in switch", la() );
1977 }
1978
1979 caseBlock = consume( Types.KEYWORD_DEFAULT ).asReduction();
1980 defaultFound = true;
1981 }
1982 else
1983 {
1984 error( new int[] { Types.KEYWORD_DEFAULT, Types.KEYWORD_CASE } );
1985 recover( Types.SWITCH_ENTRIES );
1986 }
1987
1988 consume( Types.COLON );
1989
1990
1991
1992
1993
1994 boolean first = true;
1995 while( !la().isA(Types.SWITCH_BLOCK_TERMINATORS) )
1996 {
1997 caseBlock.add( statement(first) );
1998 first = false;
1999 }
2000
2001 statement.add( caseBlock );
2002 }
2003
2004 consume( Types.RIGHT_CURLY_BRACE );
2005
2006 return statement;
2007 }
2008
2009
2010
2011 /***
2012 * Processes a synchronized statement.
2013 * <p>
2014 * Grammar: <pre>
2015 * synchronizedStatement = "synchronized" "(" expression ")" statementBody
2016 * </pre>
2017 * <p>
2018 * CST: <pre>
2019 * statement = { "synchronized" expression statementBody }
2020 *
2021 * see expression()
2022 * see statementBody()
2023 * </pre>
2024 */
2025
2026 protected Reduction synchronizedStatement() throws SyntaxException, CompilationFailedException
2027 {
2028 Reduction statement = consume(Types.KEYWORD_SYNCHRONIZED).asReduction();
2029
2030 consume( Types.LEFT_PARENTHESIS );
2031 statement.add( expression() );
2032 consume( Types.RIGHT_PARENTHESIS );
2033
2034 statement.add( statementBody(true) );
2035
2036 return statement;
2037
2038 }
2039
2040
2041
2042 /***
2043 * Processes a try statement.
2044 * <p>
2045 * Grammar: <pre>
2046 * tryStatement = "try" statementBody catchClause* finallyClause?
2047 *
2048 * catchClause = "catch" "(" datatype identifier ")" statementBody
2049 * finallyClause = "finally" statementBody
2050 * </pre>
2051 * <p>
2052 * CST: <pre>
2053 * try = { "try" statementBody catches finally }
2054 *
2055 * catches = { <null> catch* }
2056 *
2057 * catch = { "catch" datatype <identifier> statementBody }
2058 *
2059 * finally = {} | statementBody
2060 *
2061 * see datatype()
2062 * see identifier()
2063 * see statementBody()
2064 * </pre>
2065 */
2066
2067 protected Reduction tryStatement() throws SyntaxException, CompilationFailedException
2068 {
2069
2070
2071
2072
2073 Reduction statement = consume(Types.KEYWORD_TRY).asReduction();
2074 statement.add( statementBody(true) );
2075
2076
2077
2078
2079
2080 Reduction catches = (Reduction)statement.add( Reduction.newContainer() );
2081 while( lt() == Types.KEYWORD_CATCH )
2082 {
2083 try
2084 {
2085 Reduction catchBlock = (Reduction)catches.add( consume(Types.KEYWORD_CATCH).asReduction() );
2086
2087 consume( Types.LEFT_PARENTHESIS );
2088 try
2089 {
2090 catchBlock.add( datatype(false) );
2091 catchBlock.add( nameDeclaration(false) );
2092 }
2093 catch( SyntaxException e )
2094 {
2095 controller.addError( e );
2096 recover( Types.RIGHT_PARENTHESIS );
2097 }
2098 consume( Types.RIGHT_PARENTHESIS );
2099
2100 catchBlock.add( statementBody(true) );
2101 }
2102 catch( SyntaxException e )
2103 {
2104 controller.addError( e );
2105 recover();
2106 }
2107 }
2108
2109
2110
2111
2112 if( lt() == Types.KEYWORD_FINALLY )
2113 {
2114 consume( Types.KEYWORD_FINALLY );
2115 statement.add( statementBody(true) );
2116 }
2117 else
2118 {
2119 statement.add( Reduction.EMPTY );
2120 }
2121
2122 return statement;
2123 }
2124
2125
2126
2127
2128
2129
2130
2131 /***
2132 * Processes a for statement.
2133 * <p>
2134 * Grammar: <pre>
2135 * forStatement = "for" "(" normal | each ")" statementBody
2136 *
2137 * normal = multi ";" expression ";" multi
2138 * multi = (expression ["," expression]*)
2139 *
2140 * each = optionalDatatype nameDeclaration ("in"|":") expression
2141 * </pre>
2142 * <p>
2143 * CST: <pre>
2144 * for = { "for" header statementBody }
2145 *
2146 * header = normal | each
2147 * each = { ("in"|":") optionalDatatype nameDeclaration expression }
2148 *
2149 * normal = { <null> init test incr }
2150 * init = { <null> expression* }
2151 * test = expression
2152 * incr = { <null> expression* }
2153 *
2154 * see expression()
2155 * see nameDeclaration()
2156 * see statementBody()
2157 * </pre>
2158 */
2159
2160 protected Reduction forStatement() throws SyntaxException, CompilationFailedException
2161 {
2162 Reduction statement = consume( Types.KEYWORD_FOR ).asReduction();
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175 consume( Types.LEFT_PARENTHESIS );
2176
2177 getTokenStream().checkpoint();
2178
2179 Reduction header = null;
2180 CSTNode datatype = optionalDatatype( false, false );
2181
2182 if( lt(2) == Types.KEYWORD_IN || lt(2) == Types.COLON )
2183 {
2184 Token name = nameDeclaration( false );
2185 header = consume().asReduction( datatype, name, expression() );
2186 }
2187 else
2188 {
2189 getTokenStream().restore();
2190 header = Reduction.newContainer();
2191
2192 Reduction init = Reduction.newContainer();
2193 while( lt() != Types.SEMICOLON && lt() != Types.EOF )
2194 {
2195 init.add( expression() );
2196
2197 if( lt() != Types.SEMICOLON )
2198 {
2199 consume( Types.COMMA );
2200 }
2201 }
2202
2203 consume( Types.SEMICOLON );
2204
2205 header.add( init );
2206
2207
2208
2209
2210
2211
2212 header.add( expression() );
2213 consume( Types.SEMICOLON );
2214
2215
2216
2217
2218
2219
2220 Reduction incr = (Reduction)header.add( Reduction.newContainer() );
2221
2222 while( lt() != Types.RIGHT_PARENTHESIS && lt() != Types.EOF )
2223 {
2224 incr.add( expression() );
2225
2226 if( lt() != Types.RIGHT_PARENTHESIS )
2227 {
2228 consume( Types.COMMA );
2229 }
2230 }
2231 }
2232
2233 consume( Types.RIGHT_PARENTHESIS );
2234
2235 statement.add( header );
2236 statement.add( statementBody(false) );
2237
2238 return statement;
2239 }
2240
2241
2242
2243 /***
2244 * Processes a do ... while statement.
2245 * <p>
2246 * Grammar: <pre>
2247 * doWhileStatement = "do" statementBody "while" "(" expression ")" <eos>
2248 * </pre>
2249 * <p>
2250 * CST: <pre>
2251 * do = { "do" statementBody expression }
2252 *
2253 * see expression()
2254 * see statementBody()
2255 * </pre>
2256 */
2257
2258 protected Reduction doWhileStatement() throws SyntaxException, CompilationFailedException
2259 {
2260 Reduction statement = consume(Types.KEYWORD_DO).asReduction();
2261 statement.add( statementBody(false) );
2262 consume( Types.KEYWORD_WHILE );
2263
2264 consume( Types.LEFT_PARENTHESIS );
2265 try
2266 {
2267 statement.add( expression() );
2268 }
2269 catch( SyntaxException e )
2270 {
2271 controller.addError( e );
2272 recover( Types.RIGHT_PARENTHESIS );
2273 }
2274 consume( Types.RIGHT_PARENTHESIS );
2275
2276 return statement;
2277
2278 }
2279
2280
2281
2282 /***
2283 * Processes a while statement.
2284 * <p>
2285 * Grammar: <pre>
2286 * whileStatement = "while" "(" expression ")" statementBody
2287 * </pre>
2288 * <p>
2289 * CST: <pre>
2290 * while = { "while" expression statementBody }
2291 *
2292 * see expression()
2293 * see statementBody()
2294 * </pre>
2295 */
2296
2297 protected Reduction whileStatement() throws SyntaxException, CompilationFailedException
2298 {
2299 Reduction statement = consume(Types.KEYWORD_WHILE).asReduction();
2300
2301 consume( Types.LEFT_PARENTHESIS );
2302
2303 try
2304 {
2305 statement.add( expression() );
2306 }
2307 catch( SyntaxException e )
2308 {
2309 controller.addError( e );
2310 recover( Types.RIGHT_PARENTHESIS );
2311 }
2312 consume( Types.RIGHT_PARENTHESIS );
2313
2314 statement.add( statementBody(false) );
2315 return statement;
2316
2317 }
2318
2319
2320
2321
2322
2323
2324
2325
2326 /***
2327 * Processes a single (sub-)expression into a CSTNode. No assumption is
2328 * made about what follows the expression.
2329 * <p>
2330 * Note that the expression parser is rather stupid, in that it cannot
2331 * resolve names. Therefore it is little more than a pre-filter, removing
2332 * statements that can't possibly be right, but leaving everything that
2333 * might be right for semantic analysis by the <code>Analyzer</code> (which
2334 * has access to the symbol table. There was some thought given to eliminating
2335 * the CSTs and going right to ASTs, but that option was rejected because
2336 * inner classes mean that class name resolution won't work before parsing
2337 * is complete.
2338 */
2339
2340 protected CSTNode expression( ) throws SyntaxException, CompilationFailedException
2341 {
2342
2343
2344
2345 ExpressionStack stack = new ExpressionStack( this );
2346 CSTNode expression = null;
2347
2348 boolean bareMode = false;
2349
2350 MAIN_LOOP: do
2351 {
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362 Token next = la(stack);
2363 int type = next.getMeaningAs( EXPRESSION_SHIFT_HANDLERS );
2364
2365
2366
2367
2368
2369
2370
2371 SHIFT: switch( type )
2372 {
2373 case Types.GSTRING_START:
2374 {
2375 if( stack.topIsAnExpression() )
2376 {
2377 error( "gstring cannot directly follow another expression" );
2378 }
2379
2380 stack.push( gstring() );
2381 break;
2382 }
2383
2384
2385 case Types.CREATABLE_PRIMITIVE_TYPE:
2386 {
2387 stack.shiftIf( stack.atStartOfExpression(), "type name not valid in this context" );
2388 break;
2389 }
2390
2391
2392 case Types.SIMPLE_EXPRESSION:
2393 {
2394
2395
2396
2397
2398 stack.shiftUnlessTopIsAnExpression( "literal cannot directly follow another expression" );
2399 break;
2400 }
2401
2402
2403 case Types.KEYWORD_IDENTIFIER:
2404 {
2405 if( stack.top().isA(Types.DEREFERENCE_OPERATOR) && stack.topIsAnOperator() )
2406 {
2407 la().setMeaning( Types.IDENTIFIER );
2408 stack.shift();
2409 }
2410 else
2411 {
2412 error( "not valid as an identifier in this context" );
2413 }
2414 break;
2415 }
2416
2417
2418 case Types.ASSIGNMENT_OPERATOR:
2419 {
2420 stack.shiftIf( stack.topIsAModifiableExpression(), "left-hand-side of assignment must be modifiable" );
2421 break;
2422 }
2423
2424
2425 case Types.PREFIX_OR_INFIX_OPERATOR:
2426 {
2427 if( stack.topIsAnOperator(0, true) )
2428 {
2429 Types.makePrefix( next, false );
2430 }
2431 stack.shift( );
2432 break;
2433 }
2434
2435
2436 case Types.PREFIX_OPERATOR:
2437 {
2438 Types.makePrefix( next, false );
2439 stack.shift( );
2440 break;
2441 }
2442
2443
2444 case Types.QUESTION:
2445 case Types.INFIX_OPERATOR:
2446 {
2447 stack.shiftIfTopIsAnExpression( "infix operators may only follow expressions" );
2448 break;
2449 }
2450
2451
2452 case Types.LEFT_PARENTHESIS:
2453 {
2454
2455
2456
2457
2458 boolean condition = stack.atStartOfExpression() || (stack.topIsAnOperator() && !stack.top().isA(Types.DEREFERENCE_OPERATOR));
2459 stack.shiftIf( condition, "sub-expression not valid at this position" );
2460 break;
2461 }
2462
2463
2464
2465 case Types.LEFT_CURLY_BRACE:
2466 {
2467 if( stack.atStartOfExpression() || stack.topIsAnOperator() || stack.top().isA(Types.SYNTH_METHOD_CALL) )
2468 {
2469 stack.push( closureExpression() );
2470 }
2471 else
2472 {
2473 error( "closure not valid in this context" );
2474 }
2475 break;
2476 }
2477
2478
2479 case Types.LEFT_SQUARE_BRACKET:
2480 {
2481 boolean isMap = false, insist = false;
2482 if( stack.topIsAnExpression() )
2483 {
2484 insist = true;
2485 }
2486 stack.push( listOrMapExpression(isMap, insist) );
2487 break;
2488 }
2489
2490
2491 case Types.KEYWORD_NEW:
2492 {
2493 if( stack.atStartOfExpression() || stack.topIsAnOperator() )
2494 {
2495 stack.push( newExpression() );
2496 }
2497 else
2498 {
2499 error( "new can follow the start of an expression or another operator" );
2500 }
2501 break;
2502 }
2503
2504
2505 case Types.KEYWORD_INSTANCEOF:
2506 {
2507 stack.shiftIf( stack.topIsAnExpression(), "instanceof may only follow an expression" );
2508 break;
2509 }
2510
2511
2512 default:
2513 {
2514
2515
2516
2517
2518
2519 if( stack.size() == 1 && stack.topIsAnExpression() )
2520 {
2521 break MAIN_LOOP;
2522 }
2523 else
2524 {
2525 error();
2526 }
2527 }
2528
2529
2530 }
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540 boolean checkAgain = false, skipPatterns = false;
2541 CSTNode top0 = null, top1 = null, top2 = null;
2542 int nextPrecedence = 0, top1Precedence = 0;
2543
2544 REDUCE: do
2545 {
2546 if( !stack.topIsAnExpression() && !ExpressionSupport.isAPotentialTypeName(stack.top(), false) )
2547 {
2548 break;
2549 }
2550
2551
2552
2553
2554
2555 checkAgain = false;
2556 skipPatterns = false;
2557
2558 top0 = stack.top();
2559 top1 = stack.top(1);
2560 top2 = stack.top(2);
2561
2562 next = la( stack );
2563
2564
2565
2566
2567 nextPrecedence = Types.getPrecedence( next.getMeaning(), false );
2568 top1Precedence = Types.getPrecedence( top1.getMeaning(), false );
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581 if( top1.isA(Types.LEFT_PARENTHESIS) )
2582 {
2583 if( next.isA(Types.RIGHT_PARENTHESIS) )
2584 {
2585 consume();
2586
2587
2588
2589
2590
2591
2592
2593 next = la(true);
2594 boolean castPrecluded = next.isA(Types.NEWLINE) || next.isA(Types.PRECLUDES_CAST_OPERATOR);
2595
2596 if( ExpressionSupport.isAPotentialTypeName(top0, false) && !castPrecluded )
2597 {
2598 CSTNode name = stack.pop();
2599 Reduction cast = ((Token)stack.pop()).asReduction( name );
2600 cast.setMeaning( Types.SYNTH_CAST );
2601 stack.push( cast );
2602 }
2603 else
2604 {
2605 CSTNode subexpression = stack.pop();
2606 stack.pop();
2607 stack.push( subexpression );
2608 }
2609
2610 checkAgain = true;
2611 continue;
2612 }
2613 else
2614 {
2615 skipPatterns = true;
2616 }
2617 }
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628 if( top0.isA(Types.KEYWORD_NEW) && !top0.isAnExpression() )
2629 {
2630 top0.markAsExpression();
2631
2632 if( top1.isA(Types.DOT) )
2633 {
2634 CSTNode theNew = stack.pop();
2635 CSTNode theDot = stack.pop();
2636 CSTNode context = stack.pop();
2637
2638 theNew.set( 1, context );
2639 stack.push( theNew );
2640
2641 checkAgain = true;
2642 continue;
2643 }
2644 }
2645
2646
2647
2648
2649
2650
2651 if( top1.isA(Types.DEREFERENCE_OPERATOR) && !top0.hasChildren() )
2652 {
2653 stack.reduce( 3, 1, true );
2654
2655 checkAgain = true;
2656 continue;
2657 }
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668 if( top0.isA(Types.SYNTH_LIST) && top1.isAnExpression() || ExpressionSupport.isAPotentialTypeName(top1, false) )
2669 {
2670
2671
2672
2673 if( !top0.hasChildren() )
2674 {
2675 boolean typePreceeds = ExpressionSupport.isAPotentialTypeName(top1, false);
2676 boolean potentialCast = top2.isA(Types.LEFT_PARENTHESIS);
2677 boolean potentialDecl = top2.isA(Types.LEFT_PARENTHESIS) || top2.isA(Types.UNKNOWN);
2678 boolean classReference = next.isA(Types.DOT) && la(2).isA(Types.KEYWORD_CLASS);
2679 if( !(typePreceeds && (potentialCast || potentialDecl || classReference)) )
2680 {
2681 error( "empty square brackets are only valid on type names" );
2682 }
2683
2684
2685
2686
2687
2688
2689 Reduction array = stack.pop().asReduction();
2690 array.setMeaning( Types.LEFT_SQUARE_BRACKET );
2691 array.add( stack.pop() );
2692
2693 while( lt(true) == Types.LEFT_SQUARE_BRACKET )
2694 {
2695 array = consume( Types.LEFT_SQUARE_BRACKET ).asReduction( array );
2696 consume( Types.RIGHT_SQUARE_BRACKET );
2697 }
2698
2699
2700
2701
2702
2703
2704 if( classReference )
2705 {
2706 CSTNode reference = consume(Types.DOT).asReduction(array, consume(Types.KEYWORD_CLASS));
2707 reference.markAsExpression();
2708 stack.push( reference );
2709
2710 }
2711 else if( lt(true) == Types.IDENTIFIER && lt(2) == Types.EQUAL )
2712 {
2713 stack.push( variableDeclarationExpression(array) );
2714 }
2715 else if( stack.top().isA(Types.LEFT_PARENTHESIS) && la(true).isA(Types.RIGHT_PARENTHESIS) )
2716 {
2717 CSTNode cast = ((Token)stack.pop()).asReduction( array );
2718 cast.setMeaning( Types.SYNTH_CAST );
2719 stack.push( cast );
2720 consume( Types.RIGHT_PARENTHESIS );
2721 }
2722 else
2723 {
2724 error( "found array type where none expected" );
2725 }
2726 }
2727
2728
2729
2730
2731
2732 else
2733 {
2734 CSTNode list = stack.pop();
2735 CSTNode base = stack.pop();
2736
2737 Reduction result = ((Token)list.get(0)).dup().asReduction();
2738 result.setMeaning( Types.LEFT_SQUARE_BRACKET );
2739 result.add( base );
2740
2741 if( list.children() == 1 )
2742 {
2743 result.add( list.get(1) );
2744 }
2745 else
2746 {
2747 result.add( list );
2748 }
2749
2750 result.markAsExpression();
2751 stack.push( result );
2752 }
2753
2754 checkAgain = true;
2755 continue;
2756
2757 }
2758
2759
2760
2761
2762
2763
2764
2765
2766 if( la(true).isA(Types.IDENTIFIER) && lt(2) == Types.EQUALS && ExpressionSupport.isAPotentialTypeName(top0, false) )
2767 {
2768 stack.push( variableDeclarationExpression(stack.pop()) );
2769
2770 checkAgain = true;
2771 continue;
2772 }
2773
2774
2775
2776
2777
2778
2779
2780
2781 if( top1.isA(Types.SYNTH_METHOD_CALL) && top0.isA(Types.SYNTH_CLOSURE) )
2782 {
2783 CSTNode parameters = top1.get(2);
2784
2785 int last = parameters.size() - 1;
2786 if( last > 0 && parameters.get(last).isA(Types.SYNTH_CLOSURE) )
2787 {
2788 error( "you may only pass one closure to a method implicitly" );
2789 }
2790
2791 parameters.add( stack.pop() );
2792
2793 checkAgain = true;
2794 continue;
2795 }
2796
2797
2798
2799
2800
2801
2802
2803 if( ExpressionSupport.isInvokable(top0) && (next.isA(Types.LEFT_CURLY_BRACE) || la(true).isA(Types.METHOD_CALL_STARTERS)) )
2804 {
2805
2806
2807 CSTNode name = stack.pop();
2808
2809 Reduction method = null;
2810 switch( next.getMeaning() )
2811 {
2812 case Types.LEFT_PARENTHESIS:
2813 method = consume().asReduction();
2814 method.add( name );
2815 method.add( la().isA(Types.RIGHT_PARENTHESIS) ? Reduction.newContainer() : parameterList() );
2816 consume( Types.RIGHT_PARENTHESIS );
2817 break;
2818
2819 case Types.LEFT_CURLY_BRACE:
2820 method = Token.newSymbol( Types.LEFT_PARENTHESIS, next.getStartLine(), next.getStartColumn() ).asReduction();
2821 method.add( name );
2822 method.add( Reduction.newContainer() );
2823 break;
2824
2825 default:
2826 method = Token.newSymbol( Types.LEFT_PARENTHESIS, next.getStartLine(), next.getStartColumn() ).asReduction();
2827 method.add( name );
2828 method.add( parameterList() );
2829 break;
2830 }
2831
2832 method.setMeaning( Types.SYNTH_METHOD_CALL );
2833 method.markAsExpression();
2834
2835 stack.push( method );
2836
2837 if( lt() != Types.LEFT_CURLY_BRACE )
2838 {
2839 checkAgain = true;
2840 }
2841
2842 continue;
2843 }
2844
2845
2846
2847
2848
2849
2850
2851 if( next.isA(Types.POSTFIX_OPERATOR) && stack.topIsAnExpression() )
2852 {
2853 if( !ExpressionSupport.isAVariable(stack.top()) )
2854 {
2855 error( "increment/decrement operators can only be applied to variables" );
2856 }
2857
2858 Types.makePostfix( next, true );
2859
2860 stack.shift();
2861 stack.reduce( 2, 0, true );
2862
2863 checkAgain = true;
2864 continue;
2865 }
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875 if( top1.isA(Types.QUESTION) )
2876 {
2877 boolean reduce = false;
2878
2879 if( la().isA(Types.COLON) )
2880 {
2881 if( top1.hasChildren() )
2882 {
2883 error( "ternary operator can have only three clauses" );
2884 }
2885
2886 consume();
2887 stack.reduce( 3, 1, false );
2888 checkAgain = true;
2889 }
2890 else if( Types.getPrecedence(next.getMeaning(), false) < 10 )
2891 {
2892 stack.reduce( 2, 1, false );
2893 stack.top().setMeaning( Types.SYNTH_TERNARY );
2894 checkAgain = true;
2895 }
2896
2897
2898 continue;
2899 }
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916 if( skipPatterns || !ExpressionSupport.isAnOperator(top1, false) )
2917 {
2918 break;
2919 }
2920
2921
2922 switch( top1.getMeaningAs(EXPRESSION_REDUCE_HANDLERS) )
2923 {
2924
2925
2926
2927
2928 case Types.PREFIX_PLUS_PLUS:
2929 case Types.PREFIX_MINUS_MINUS:
2930 {
2931 if( nextPrecedence < top1Precedence )
2932 {
2933 if( !ExpressionSupport.isAVariable(stack.top()) )
2934 {
2935 error( "increment/decrement operators can only be applied to variables" );
2936 }
2937
2938 stack.reduce( 2, 1, true );
2939 checkAgain = true;
2940 }
2941
2942 break;
2943 }
2944
2945
2946
2947
2948
2949 case Types.PURE_PREFIX_OPERATOR:
2950 {
2951 if( nextPrecedence < top1Precedence )
2952 {
2953 stack.reduce( 2, 1, true );
2954 checkAgain = true;
2955 }
2956
2957 break;
2958 }
2959
2960
2961
2962
2963
2964 case Types.ASSIGNMENT_OPERATOR:
2965 {
2966 if( nextPrecedence < top1Precedence )
2967 {
2968 stack.reduce( 3, 1, true );
2969 checkAgain = true;
2970 }
2971
2972 break;
2973 }
2974
2975
2976
2977
2978
2979 case Types.KEYWORD_INSTANCEOF:
2980 {
2981 if( nextPrecedence < top1Precedence )
2982 {
2983 if( !ExpressionSupport.isAPotentialTypeName(top0, false) )
2984 {
2985 error( "instanceof right-hand side must be a valid type name" );
2986 }
2987
2988 stack.reduce( 3, 1, true );
2989 checkAgain = true;
2990 }
2991
2992 break;
2993 }
2994
2995
2996
2997
2998
2999 case Types.INFIX_OPERATOR:
3000 {
3001 if( nextPrecedence <= top1Precedence )
3002 {
3003 stack.reduce( 3, 1, true );
3004 checkAgain = true;
3005 }
3006
3007 break;
3008 }
3009
3010
3011
3012
3013
3014 default:
3015 {
3016 throw new GroovyBugError( "found unexpected token during REDUCE [" + top1.getMeaning() + "]" );
3017 }
3018 }
3019
3020 } while( checkAgain );
3021
3022 } while( true );
3023
3024
3025 if( stack.size() == 1 && stack.topIsAnExpression() )
3026 {
3027 expression = stack.pop();
3028 }
3029 else
3030 {
3031 error( "expression incomplete" );
3032 }
3033
3034
3035
3036 return expression;
3037 }
3038
3039
3040 private static final int EXPRESSION_SHIFT_HANDLERS[] = {
3041 Types.GSTRING_START
3042 , Types.CREATABLE_PRIMITIVE_TYPE
3043 , Types.SIMPLE_EXPRESSION
3044 , Types.KEYWORD_IDENTIFIER
3045 , Types.ASSIGNMENT_OPERATOR
3046 , Types.PREFIX_OR_INFIX_OPERATOR
3047 , Types.PREFIX_OPERATOR
3048 , Types.QUESTION
3049 , Types.INFIX_OPERATOR
3050 , Types.LEFT_PARENTHESIS
3051 , Types.LEFT_CURLY_BRACE
3052 , Types.LEFT_SQUARE_BRACKET
3053 , Types.KEYWORD_NEW
3054 , Types.KEYWORD_INSTANCEOF
3055 };
3056
3057 private static final int EXPRESSION_REDUCE_HANDLERS[] = {
3058 Types.PREFIX_PLUS_PLUS
3059 , Types.PREFIX_MINUS_MINUS
3060 , Types.PURE_PREFIX_OPERATOR
3061 , Types.ASSIGNMENT_OPERATOR
3062 , Types.KEYWORD_INSTANCEOF
3063 , Types.INFIX_OPERATOR
3064 };
3065
3066
3067
3068 /***
3069 * Processes a typed variable declaration. Without the type, it's a
3070 * assignment expression instead (no comma support). The datatype
3071 * has already been identified and is passed in.
3072 * <p>
3073 * Grammar: <pre>
3074 * variableDeclarationExpression
3075 * = datatype (nameDeclaration "=" expression)
3076 * ("," nameDeclaration "=" expression)*
3077 * </pre>
3078 * <p>
3079 * CST: <pre>
3080 * statement = { :<SYNTH_VARIABLE_DECLARATION> datatype declaration+ }
3081 * declaration = { <identifier> expression }
3082 *
3083 * see expression()
3084 * </pre>
3085 */
3086
3087 protected Reduction variableDeclarationExpression( CSTNode datatype ) throws SyntaxException, CompilationFailedException
3088 {
3089 Reduction expression = ((Token)datatype.get(0)).dup().asReduction( datatype );
3090 expression.setMeaning( Types.SYNTH_VARIABLE_DECLARATION );
3091
3092 boolean done = false;
3093 do
3094 {
3095 try
3096 {
3097 Reduction declaration = (Reduction)expression.add( nameDeclaration(false).asReduction() );
3098 consume( Types.EQUAL );
3099 declaration.add( expression() );
3100 }
3101 catch( SyntaxException e )
3102 {
3103 controller.addError( e );
3104 recover( Types.ANY_END_OF_STATEMENT );
3105 }
3106
3107 if( lt() == Types.COMMA )
3108 {
3109 consume( Types.COMMA );
3110 }
3111 else
3112 {
3113 done = true;
3114 }
3115
3116 } while( !done );
3117
3118
3119 return expression;
3120 }
3121
3122
3123
3124 /***
3125 * Processes a GString.
3126 * <p>
3127 * Grammar: <pre>
3128 * gstring = (<text>? "$" "{" expression "}" <text>?)*
3129 * </pre>
3130 * <p>
3131 * CST: <pre>
3132 * gstring = { <full-text>:SYNTH_GSTRING (segment|expression)* }
3133 *
3134 * see expression()
3135 * </pre>
3136 */
3137
3138 protected Reduction gstring() throws SyntaxException, CompilationFailedException
3139 {
3140
3141
3142
3143 Reduction data = Reduction.newContainer();
3144
3145 consume( Types.GSTRING_START );
3146
3147 while( lt() != Types.GSTRING_END && lt() != Types.EOF )
3148 {
3149 switch( lt() )
3150 {
3151 case Types.STRING:
3152 data.add( consume() );
3153 break;
3154
3155 case Types.GSTRING_EXPRESSION_START:
3156 consume();
3157 data.add( expression() );
3158 consume( Types.GSTRING_EXPRESSION_END );
3159 break;
3160
3161 default:
3162 throw new GroovyBugError( "gstring found invalid token: " + la() );
3163 }
3164 }
3165
3166 Reduction complete = consume( Types.GSTRING_END ).asReduction();
3167 complete.addChildrenOf( data );
3168
3169 complete.setMeaning( Types.SYNTH_GSTRING );
3170
3171
3172 return complete;
3173 }
3174
3175
3176
3177
3178 /***
3179 * Processes a NON-EMPTY parameter list, as supplied on either a method invokation or
3180 * a closure invokation. Reads parameters until something that doesn't belong
3181 * is found.
3182 * <p>
3183 * Grammar: <pre>
3184 * parameterList = (regular "," named) | named
3185 * regular = parameter ("," parameter)*
3186 * named = nameReference ":" parameter ("," nameReference ":" parameter)*
3187 *
3188 * parameter = expression
3189 * </pre>
3190 * <p>
3191 * CST: <pre>
3192 * parameterList = { <null> regular* named* }
3193 * regular = expression
3194 * named = { ":" <identifier> expression }
3195 *
3196 * see expression()
3197 * </pre>
3198 */
3199
3200 protected Reduction parameterList() throws SyntaxException, CompilationFailedException
3201 {
3202
3203
3204
3205 Reduction list = Reduction.newContainer();
3206 Reduction named = null;
3207
3208 boolean done = false;
3209
3210 do
3211 {
3212 if( la().canMean(Types.IDENTIFIER) && la(2).isA(Types.COLON) )
3213 {
3214 if( named == null )
3215 {
3216 named = Token.newPlaceholder(Types.SYNTH_MAP).asReduction();
3217 list.add( named );
3218 }
3219
3220 Token name = nameReference(false);
3221 name.setMeaning( Types.STRING );
3222
3223 named.add( consume(Types.COLON).asReduction(name, expression()) );
3224 }
3225 else
3226 {
3227 list.add( expression() );
3228 }
3229
3230
3231 if( lt() == Types.COMMA )
3232 {
3233 consume();
3234 }
3235 else
3236 {
3237 done = true;
3238 }
3239
3240
3241 } while( !done );
3242
3243
3244 return list;
3245 }
3246
3247
3248
3249 /***
3250 * Processes a "new" expression. Handles optional constructors, array
3251 * initializations, closure arguments, and anonymous classes. In order
3252 * to support anonymous classes, anonymous closures are not allowed.
3253 * <p>
3254 * Grammar: <pre>
3255 * newExpression = "new" scalarDatatype (array|init)?
3256 * array = ( "[" expression "]" )+ | ( ("[" "]")+ newArrayInitializer )
3257 * init = "(" parameterList? ")" (typeBody | closureExpression)?
3258 * </pre>
3259 * <p>
3260 * CST: <pre>
3261 * new = { "new" arrayType dimensions newArrayInitializer? }
3262 * | { "new" scalarDataype (parameterList|{<null>}) typeBody? }
3263 *
3264 * arrayType = { "{" (arrayType | scalarDatatype) }
3265 * dimensions = { <null> expression+ } | {}
3266 *
3267 * see expression()
3268 * see scalarDatatype()
3269 * see typeBody()
3270 * </pre>
3271 */
3272
3273 protected Reduction newExpression() throws SyntaxException, CompilationFailedException
3274 {
3275
3276
3277
3278 Reduction expression = consume(Types.KEYWORD_NEW).asReduction();
3279 CSTNode scalarType = scalarDatatype(false);
3280
3281 if( lt(true) == Types.LEFT_SQUARE_BRACKET )
3282 {
3283
3284
3285
3286
3287 boolean implicit = (lt(2) == Types.RIGHT_SQUARE_BRACKET);
3288 Reduction dimensions = implicit ? Reduction.EMPTY : Reduction.newContainer();
3289 int count = 0;
3290 CSTNode arrayType = scalarType;
3291
3292 while( lt(true) == Types.LEFT_SQUARE_BRACKET )
3293 {
3294 arrayType = consume(Types.LEFT_SQUARE_BRACKET).asReduction( arrayType );
3295 count++;
3296
3297 if( !implicit )
3298 {
3299 dimensions.add( expression() );
3300 }
3301
3302 consume(Types.RIGHT_SQUARE_BRACKET);
3303 }
3304
3305 expression.add( arrayType );
3306 expression.add( dimensions );
3307
3308
3309
3310
3311 if( implicit )
3312 {
3313 expression.add( tupleExpression(0, count) );
3314 }
3315
3316 }
3317
3318 else
3319 {
3320 expression.add( scalarType );
3321
3322
3323
3324
3325
3326 Reduction parameters = null;
3327
3328 consume( Types.LEFT_PARENTHESIS );
3329 parameters = (lt() == Types.RIGHT_PARENTHESIS ? Reduction.newContainer() : parameterList());
3330 consume( Types.RIGHT_PARENTHESIS );
3331
3332 expression.add( parameters );
3333
3334
3335
3336
3337
3338 if( lt() == Types.LEFT_CURLY_BRACE )
3339 {
3340 if( lt(2) == Types.PIPE || lt(2) == Types.DOUBLE_PIPE )
3341 {
3342 parameters.add( closureExpression() );
3343 }
3344 else
3345 {
3346 expression.add( typeBody(true, false, false) );
3347 }
3348 }
3349 }
3350
3351
3352 return expression;
3353 }
3354
3355
3356
3357 /***
3358 * Processes a "new" array initializer expression.
3359 * <p>
3360 * Grammar: <pre>
3361 * tupleExpression = "{" (tupleExpression | (expression ("," expression))? "}"
3362 * </pre>
3363 * <p>
3364 * CST: <pre>
3365 * initializer = { "{":SYNTH_TUPLE (initializer*|expression*) }
3366 *
3367 * see expression()
3368 * </pre>
3369 */
3370
3371 protected Reduction tupleExpression( int level, int depth ) throws SyntaxException, CompilationFailedException
3372 {
3373 Reduction data = consume(Types.LEFT_CURLY_BRACE).asReduction();
3374 data.setMeaning( Types.SYNTH_TUPLE );
3375
3376 if( lt() != Types.RIGHT_CURLY_BRACE )
3377 {
3378 int child = level + 1;
3379 boolean leaf = (child == depth);
3380
3381 do
3382 {
3383 data.add( leaf ? expression() : tupleExpression(child, depth) );
3384
3385 } while( lt() == Types.COMMA && (consume() != null) );
3386 }
3387
3388 consume( Types.RIGHT_CURLY_BRACE );
3389
3390 return data;
3391 }
3392
3393
3394
3395 /***
3396 * Processes a closure expression.
3397 * <p>
3398 * Grammar: <pre>
3399 * closureExpression = "{" parameters statement* "}"
3400 * parameters = ("|" parameterDeclarationList "|")?
3401 * </pre>
3402 * <p>
3403 * CST: <pre>
3404 * initializer = { "{":SYNTH_CLOSURE parameters statements }
3405 * parameters = parameterDeclarationList | { <null> }
3406 * statements = { <null> statement* }
3407 *
3408 * see parameterDeclarationList()
3409 * see statement()
3410 * </pre>
3411 */
3412
3413 protected Reduction closureExpression( ) throws SyntaxException, CompilationFailedException
3414 {
3415
3416
3417
3418 Reduction closure = consume(Types.LEFT_CURLY_BRACE).asReduction();
3419 closure.setMeaning( Types.SYNTH_CLOSURE );
3420 boolean specified = (lt() == Types.PIPE) || (lt() == Types.DOUBLE_PIPE);
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431 if( !specified )
3432 {
3433 getTokenStream().checkpoint();
3434 CSTNode type = optionalDatatype( true, false );
3435 if( lt() == Types.IDENTIFIER && (lt(2) == Types.PIPE || lt(2) == Types.COMMA) )
3436 {
3437 specified = true;
3438 }
3439
3440 getTokenStream().restore();
3441 }
3442
3443
3444
3445
3446
3447 if( specified )
3448 {
3449 if( lt() == Types.DOUBLE_PIPE )
3450 {
3451 consume( Types.DOUBLE_PIPE );
3452 closure.add( Reduction.newContainer() );
3453 }
3454 else
3455 {
3456
3457
3458
3459
3460 if( lt() == Types.PIPE )
3461 {
3462 consume(Types.PIPE);
3463 }
3464
3465 closure.add( parameterDeclarationList() );
3466 consume(Types.PIPE);
3467 }
3468 }
3469 else
3470 {
3471 closure.add( Reduction.newContainer() );
3472 }
3473
3474
3475
3476
3477
3478 closure.add( statementsUntilRightCurly() );
3479 consume( Types.RIGHT_CURLY_BRACE );
3480
3481
3482 return closure;
3483 }
3484
3485
3486
3487 /***
3488 * Processes a list or map expression.
3489 * <p>
3490 * Grammar: <pre>
3491 * listOrMapExpression = list | map
3492 *
3493 * list = "[" (expression ("," expression)*)? "]"
3494 *
3495 * map = "[" (":" | mapping+) "]"
3496 * mapping = expression ":" expression
3497 * </pre>
3498 * <p>
3499 * CST: <pre>
3500 * list = { "[":SYNTH_LIST expression* }
3501 * map = { "[":SYNTH_MAP mapping* }
3502 * mapping = { ":" expression expression }
3503 *
3504 * see expression()
3505 * </pre>
3506 */
3507
3508 protected Reduction listOrMapExpression( boolean isMap, boolean insist ) throws SyntaxException, CompilationFailedException
3509 {
3510 Reduction expression = consume(Types.LEFT_SQUARE_BRACKET).asReduction();
3511 expression.setMeaning( Types.SYNTH_LIST );
3512
3513 if( lt() == Types.COLON )
3514 {
3515 if( !isMap && insist )
3516 {
3517 error( "expected list" );
3518 }
3519
3520 isMap = true;
3521 expression.setMeaning( Types.SYNTH_MAP );
3522 consume();
3523 if( lt() != Types.RIGHT_SQUARE_BRACKET )
3524 {
3525 error( "expected empty map" );
3526 }
3527 }
3528
3529
3530
3531
3532
3533
3534
3535 boolean done = (lt() == Types.RIGHT_SQUARE_BRACKET);
3536
3537 while( !done )
3538 {
3539 CSTNode element = expression();
3540
3541 if( !insist )
3542 {
3543 insist = true;
3544 if( lt() == Types.COLON )
3545 {
3546 isMap = true;
3547 expression.setMeaning(Types.SYNTH_MAP);
3548 }
3549 }
3550
3551 if( isMap )
3552 {
3553 element = consume(Types.COLON).asReduction( element, expression() );
3554 }
3555
3556 expression.add( element );
3557
3558 if( lt() == Types.COMMA ) { consume(); } else { done = true; }
3559 }
3560
3561 consume(Types.RIGHT_SQUARE_BRACKET);
3562
3563 return expression;
3564 }
3565
3566
3567
3568 /***
3569 * Synonym for <code>listOrMapExpression( false, false )</code>.
3570 */
3571
3572 protected Reduction listOrMapExpression( ) throws SyntaxException, CompilationFailedException
3573 {
3574 return listOrMapExpression( false, false );
3575 }
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586 /***
3587 * Reports an error assembled from parts.
3588 */
3589
3590 protected UnexpectedTokenException error( Token found, int[] expectedTypes, boolean throwIt, String comment ) throws SyntaxException
3591 {
3592 UnexpectedTokenException e = new UnexpectedTokenException( found, expectedTypes, comment );
3593
3594 if( throwIt )
3595 {
3596 throw e;
3597 }
3598
3599 return e;
3600 }
3601
3602
3603 /***
3604 * Reports an error by generating and optionally throwing an
3605 * <code>UnexpectedTokenException</code>.
3606 */
3607
3608 protected UnexpectedTokenException error( int[] expectedTypes, boolean throwIt, int k, String comment ) throws SyntaxException, CompilationFailedException
3609 {
3610 return error( la(k), expectedTypes, throwIt, comment );
3611 }
3612
3613
3614
3615 /***
3616 * A synonym for <code>error( expectedTypes, throwIt, k, null )</code>.
3617 */
3618
3619 protected UnexpectedTokenException error( int[] expectedTypes, boolean throwIt, int k ) throws SyntaxException, CompilationFailedException
3620 {
3621 return error( expectedTypes, throwIt, k, null );
3622 }
3623
3624
3625
3626 /***
3627 * A synonym for <code>error( expectedTypes, true, 1, null )</code>.
3628 */
3629
3630 protected void error( int[] expectedTypes ) throws SyntaxException, CompilationFailedException
3631 {
3632 throw error( expectedTypes, false, 1, null );
3633 }
3634
3635
3636
3637 /***
3638 * A synonym for <code>error( null, true, 1, null )</code>.
3639 */
3640
3641 protected void error() throws SyntaxException, CompilationFailedException
3642 {
3643 throw error( null, true, 1, null );
3644 }
3645
3646
3647
3648 /***
3649 * A synonym for <code>error( null, true, 1, comment )</code>.
3650 */
3651
3652 protected void error( String comment ) throws SyntaxException, CompilationFailedException
3653 {
3654 throw error( null, true, 1, comment );
3655 }
3656
3657
3658
3659 /***
3660 * A synonym for <code>error( found, null, true, comment )</code>.
3661 */
3662
3663 protected void error( Token found, String comment ) throws SyntaxException
3664 {
3665 throw error( found, null, true, comment );
3666 }
3667
3668
3669
3670 /***
3671 * A scalar synonym of <code>error( expectedTypes )</code>.
3672 */
3673
3674 protected void error( int expectedType ) throws SyntaxException, CompilationFailedException
3675 {
3676 error( new int[] { expectedType } );
3677 }
3678
3679
3680
3681
3682
3683
3684
3685
3686 /***
3687 * Attempts to recover from an error by discarding input until a
3688 * known token is found. It further guarantees that /at least/
3689 * one token will be eaten.
3690 */
3691
3692 public void recover( int[] safe, boolean ignoreNewlines ) throws SyntaxException, CompilationFailedException
3693 {
3694 Token leading = la( ignoreNewlines );
3695
3696 while( true )
3697 {
3698 Token next = la( ignoreNewlines );
3699 if( next.isA(Types.EOF) || next.isOneOf(safe) )
3700 {
3701 break;
3702 }
3703 else
3704 {
3705 consume( ignoreNewlines );
3706 }
3707 }
3708
3709 if( la(ignoreNewlines) == leading )
3710 {
3711 consume( ignoreNewlines );
3712 }
3713 }
3714
3715
3716
3717 /***
3718 * A scalar version of <code>recover( int[], boolean )</code>.
3719 */
3720
3721 public void recover( int safe, boolean ignoreNewlines ) throws SyntaxException, CompilationFailedException
3722 {
3723 Token leading = la( ignoreNewlines );
3724
3725 while( true )
3726 {
3727 Token next = la( ignoreNewlines );
3728 if( next.isA(Types.EOF) || next.isA(safe) )
3729 {
3730 break;
3731 }
3732 else
3733 {
3734 consume( ignoreNewlines );
3735 }
3736 }
3737
3738 if( la(ignoreNewlines) == leading )
3739 {
3740 consume( ignoreNewlines );
3741 }
3742 }
3743
3744
3745
3746 /***
3747 * A synonym for <code>recover( safe, false )</code>.
3748 */
3749
3750 public void recover( int[] safe ) throws SyntaxException, CompilationFailedException
3751 {
3752 recover( safe, false );
3753 }
3754
3755
3756
3757 /***
3758 * A synonm for the scalar <code>recover( safe, false )</code>.
3759 */
3760
3761 public void recover( int safe ) throws SyntaxException, CompilationFailedException
3762 {
3763 recover( safe, false );
3764 }
3765
3766
3767
3768 /***
3769 * A synonym for <code>recover( Types.ANY_END_OF_STATMENT, true )</code>.
3770 */
3771
3772 public void recover( ) throws SyntaxException, CompilationFailedException
3773 {
3774 recover( Types.ANY_END_OF_STATEMENT, true );
3775 }
3776
3777
3778
3779
3780
3781
3782
3783
3784 /***
3785 * Returns (without consuming) the next kth token in the underlying
3786 * token stream. You can make newlines significant as needed.
3787 * Returns Token.EOF on end of stream. k is counted from 1.
3788 */
3789
3790 protected Token la( int k, boolean significantNewlines ) throws SyntaxException, CompilationFailedException
3791 {
3792 Token token = Token.NULL;
3793
3794
3795
3796
3797
3798
3799
3800 try
3801 {
3802 int streamK = 1;
3803 while( k > 0 && token.getMeaning() != Types.EOF )
3804 {
3805 token = getTokenStream().la( streamK );
3806 streamK += 1;
3807
3808 if( token == null )
3809 {
3810 token = Token.EOF;
3811 }
3812 else if( token.getMeaning() == Types.NEWLINE )
3813 {
3814 if( significantNewlines )
3815 {
3816 k -= 1;
3817 }
3818 }
3819 else
3820 {
3821 k -= 1;
3822 }
3823 }
3824 }
3825 catch( ReadException e )
3826 {
3827 controller.addFatalError( new SimpleMessage(e.getMessage()) );
3828 }
3829
3830 return token;
3831 }
3832
3833
3834
3835 /***
3836 * Synonym for <code>la( k, false )</code>.
3837 */
3838
3839 protected Token la( int k ) throws SyntaxException, CompilationFailedException
3840 {
3841 return la( k, false );
3842 }
3843
3844
3845
3846 /***
3847 * Synonym for <code>la( 1, significantNewlines )</code>.
3848 */
3849
3850 protected Token la( boolean significantNewlines ) throws SyntaxException, CompilationFailedException
3851 {
3852 return la( 1, significantNewlines );
3853 }
3854
3855
3856
3857 /***
3858 * Synonym for <code>la( 1, false )</code>.
3859 */
3860
3861 protected Token la() throws SyntaxException, CompilationFailedException
3862 {
3863 return la( 1, false );
3864 }
3865
3866
3867
3868 /***
3869 * Special <code>la()</code> used by the expression parser. It will get the next token
3870 * in the current statement. If the next token is past a line boundary and might be
3871 * the start of the next statement, it won't cross the line to get it.
3872 */
3873
3874 protected Token la( ExpressionStack stack ) throws SyntaxException, CompilationFailedException
3875 {
3876 Token next = la();
3877
3878 if( stack.canComplete() && next.isA(Types.UNSAFE_OVER_NEWLINES) )
3879 {
3880 if( la(true).getMeaning() == Types.NEWLINE )
3881 {
3882 next = la(true);
3883 }
3884 }
3885
3886 return next;
3887 }
3888
3889
3890
3891
3892 /***
3893 * Returns the meaning of the <code>la( k, significantNewlines )</code> token.
3894 */
3895
3896 protected int lt( int k, boolean significantNewlines ) throws SyntaxException, CompilationFailedException
3897 {
3898 return la(k, significantNewlines).getMeaning();
3899 }
3900
3901
3902
3903 /***
3904 * Returns the meaning of the <code>la( k )</code> token.
3905 */
3906
3907 protected int lt( int k ) throws SyntaxException, CompilationFailedException
3908 {
3909 return la(k).getMeaning();
3910 }
3911
3912
3913
3914 /***
3915 * Returns the meaning of the <code>la( significantNewlines )</code> token.
3916 */
3917
3918 protected int lt( boolean significantNewlines ) throws SyntaxException, CompilationFailedException
3919 {
3920 return la(significantNewlines).getMeaning();
3921 }
3922
3923
3924
3925 /***
3926 * Returns the meaning of the <code>la()</code> token.
3927 */
3928
3929 protected int lt() throws SyntaxException, CompilationFailedException
3930 {
3931 return la().getMeaning();
3932 }
3933
3934
3935
3936
3937
3938
3939
3940
3941 /***
3942 * Consumes (and returns) the next token if it is of the specified type.
3943 * If <code>significantNewlines</code> is set, newlines will not automatically
3944 * be consumed; otherwise they will. Throws <code>UnexpectedTokenException</code>
3945 * if the type doesn't match.
3946 */
3947
3948 protected Token consume( int type, boolean significantNewlines ) throws SyntaxException, CompilationFailedException
3949 {
3950 try
3951 {
3952 if( !la(significantNewlines).isA(type) )
3953 {
3954 error( type );
3955 }
3956
3957 if( !significantNewlines )
3958 {
3959 while( lt(true) == Types.NEWLINE )
3960 {
3961 getTokenStream().consume(Types.NEWLINE);
3962 }
3963 }
3964
3965 return getTokenStream().consume(type);
3966 }
3967 catch( ReadException e )
3968 {
3969 controller.addFatalError( new SimpleMessage(e.getMessage()) );
3970 }
3971
3972 throw new GroovyBugError( "this should never happen" );
3973 }
3974
3975
3976
3977 /***
3978 * A synonym for <code>consume( type, false )</code>. If type is Types.NEWLINE,
3979 * equivalent to <code>consume( Types.NEWLINE, true )</code>.
3980 */
3981
3982 protected Token consume( int type ) throws SyntaxException, CompilationFailedException
3983 {
3984 return consume( type, type == Types.NEWLINE );
3985 }
3986
3987
3988
3989 /***
3990 * A synonym for <code>consume( Types.ANY, false )</code>.
3991 */
3992
3993 protected Token consume() throws SyntaxException, CompilationFailedException
3994 {
3995 return consume( lt(), false );
3996 }
3997
3998
3999
4000 /***
4001 * A synonym for <code>consume( Types.ANY, significantNewlines )</code>.
4002 * If you pass true, it will consume exactly the next token from the
4003 * stream.
4004 */
4005
4006 protected Token consume( boolean significantNewlines ) throws SyntaxException, CompilationFailedException
4007 {
4008 return consume( lt(significantNewlines), significantNewlines );
4009 }
4010
4011 }