KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  $Id: Parser.java,v 1.85 2004/07/10 03:31:43 bran Exp $
3
4  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5
6  Redistribution and use of this software and associated documentation
7  ("Software"), with or without modification, are permitted provided
8  that the following conditions are met:
9
10  1. Redistributions of source code must retain copyright
11     statements and notices. Redistributions must also contain a
12     copy of this document.
13
14  2. Redistributions in binary form must reproduce the
15     above copyright notice, this list of conditions and the
16     following disclaimer in the documentation and/or other
17     materials provided with the distribution.
18
19  3. The name "groovy" must not be used to endorse or promote
20     products derived from this Software without prior written
21     permission of The Codehaus. For written permission,
22     please contact info@codehaus.org.
23
24  4. Products derived from this Software may not be called "groovy"
25     nor may "groovy" appear in their names without prior written
26     permission of The Codehaus. "groovy" is a registered
27     trademark of The Codehaus.
28
29  5. Due credit should be given to The Codehaus -
30     http://groovy.codehaus.org/
31
32  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
36  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43  OF THE POSSIBILITY OF SUCH DAMAGE.
44
45  */

46 package org.codehaus.groovy.syntax.parser;
47
48 import 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; // The controller to which we report errors
75
private TokenStream tokenStream = null; // Our token source
76
private int nestCount = 1; // Simplifies tracing of nested calls
77

78
79
80   //---------------------------------------------------------------------------
81
// CONSTRUCTION AND DATA ACCESS
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
// PRODUCTION SUPPORT
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
// PRODUCTIONS: PRIMARY STRUCTURES
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
// First up, the package declaration
246

247         // XXX br: this is where i can do macro processing
248

249         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         if( packageDeclaration == null )
266         {
267             packageDeclaration = Reduction.EMPTY;
268         }
269
270         module.add( packageDeclaration );
271
272
273         //
274
// Next, handle import statements
275

276         Reduction imports = (Reduction)module.add( Reduction.newContainer() );
277         Object JavaDoc 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
// With that taken care of, process everything else.
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
330     {
331         Reduction packageDeclaration = consume(Types.KEYWORD_PACKAGE).asReduction( dottedIdentifier() );
332         endOfStatement( false );
333
334         return 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
// First, process any package name.
369

370         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         if( packageNode == null )
385         {
386             packageNode = Reduction.EMPTY;
387         }
388
389         importStatement.add( packageNode );
390
391
392         //
393
// Then process the class list.
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
// End the statement and return.
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
// If it starts "def", it's a method declaration. Methods
471
// declared this way cannot be abstract. Note that "def"
472
// is required because the return type is not, and it would
473
// be very hard to tell the difference between a function
474
// def and a function invokation with closure...
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             // XXX add my logic here
490
}
491
492         //
493
// If it starts "synchronized(", it's a statement. This check
494
// is necessary because "synchronized" is also a class modifier.
495

496         else if( lt() == Types.KEYWORD_SYNCHRONIZED && lt(2) == Types.LEFT_PARENTHESIS )
497         {
498             result = synchronizedStatement();
499         }
500
501         //
502
// If it starts with a modifier, "class", or "interface",
503
// it's a type declaration.
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
// Otherwise, it's a statement.
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
// Process any extends clause.
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
// Process any implements clause.
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
// Process the declaration body. We currently ignore the abstract keyword.
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
// Process any extends clause.
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
// Process the declaration body. All methods must be abstract.
702
// Static methods are not allowed.
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
// Loop, reading one datatype at a time. On error, attempt
736
// recovery until the end of the clause is found.
737

738             while( limit == 0 || typeList.children() < limit )
739             {
740                 //
741
// Try for a list entry, and correct if missing
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
// Check if we have reached the end point. It is
760
// done at the bottom of the loop to ensure that there
761
// is at least one datatype in the list
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
// As "static" can be both a modifier and a static initializer, we
866
// handle the static initializer first.
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
// Otherwise, it is a property, constructor, method, class, or interface.
882

883         else
884         {
885             Reduction modifiers = modifierList( allowStatic, allowAbstract );
886
887             //
888
// Check for inner types
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
// Otherwise, it is a property, constructor, or method.
902

903             else
904             {
905                 //
906
// Ignore any property keyword, if present (it's deprecated)
907

908                 if( lt() == Types.KEYWORD_PROPERTY )
909                 {
910                     consume();
911                 }
912
913                 //
914
// All processing here is whitespace sensitive, in order
915
// to be consistent with the way "def" functions work (due
916
// to the optionality of the semicolon). One of the
917
// consequences is that the left parenthesis of a
918
// method declaration /must/ appear on the same line.
919

920                 while( lt(true) == Types.NEWLINE)
921                 {
922                     consume( Types.NEWLINE );
923                 }
924
925                 //
926
// We don't yet know about void, so we err on the side of caution
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
// We require abstract if specified on call or the
937
// "abstract" modifier was supplied.
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
// If the next token is an identifier, it could be an untyped
1060
// variable/method name. If it is followed by another identifier,
1061
// we'll assume type. Otherwise, we'll attempt a datatype and
1062
// restore() the stream if there is a problem.
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 JavaDoc();
1080                    }
1081                }
1082                catch( Exception JavaDoc e )
1083                {
1084                    getTokenStream().restore();
1085                    type = Reduction.EMPTY;
1086                }
1087            }
1088        }
1089
1090        //
1091
// If it is a primitive type name, it must be a datatype. If void
1092
// is present but not allowed, it is an error, and we let datatype()
1093
// catch it.
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
// Process the parameter list
1173

1174        consume(Types.LEFT_PARENTHESIS);
1175        method.add( parameterDeclarationList() );
1176        consume(Types.RIGHT_PARENTHESIS);
1177
1178        //
1179
// Process the optional "throws" clause
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
// And the body. If it isn't supposed to be there, report the
1193
// error, but process it anyway, for the point of recovering.
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) ) // TYPE_NAME includes <identifier>, and so does double duty
1247
{
1248
1249            //
1250
// Get the declaration
1251

1252            Reduction parameter = (Reduction)list.add( parameterDeclaration() );
1253
1254            //
1255
// Process any default parameter (it is required on every parameter
1256
// after the first occurrance).
1257

1258            if( expectDefaults || lt() == Types.EQUAL )
1259            {
1260                expectDefaults = true;
1261                consume( Types.EQUAL );
1262
1263                parameter.add( expression() );
1264            }
1265
1266            //
1267
// Check if we are done.
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
// PRODUCTIONS: STATEMENTS
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
// Check for and grab any label for the statement
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
// Process the statement
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
// Bare blocks are no longer generally supported, due to the ambiguity
1640
// with closures. Further, closures and blocks can look identical
1641
// until after parsing, so we process first as a closure expression,
1642
// then, if the expression is a parameter-less, bare closure, rebuild
1643
// it as a block (which generally requires a label). Joy.
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
// It's a closure expression, and must be a statement
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
// Wrap the statement in the label, if necessary.
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
// Process the if clause
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
// If the else clause is present:
1875
// if it is an else if, recurse
1876
// otherwise, build the else node directly.
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
// Process the switch body. Labels can be pretty much anything,
1957
// but we'll duplicate-check for default.
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
// Read the label
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
// Process the statements, if any
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
// Set up the statement with the try clause
2072

2073        Reduction statement = consume(Types.KEYWORD_TRY).asReduction();
2074        statement.add( statementBody(true) );
2075
2076
2077        //
2078
// Process the catch clauses
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
// Process the finally clause, if available.
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
// PRODUCTIONS: LOOP STATEMENTS
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
// The for loop is a little tricky. There are three forms,
2166
// and the first two can't be processed with expression().
2167
// In order to avoid complications, we are going to checkpoint()
2168
// the stream before processing optionalDatatype(), then restore
2169
// it if we need to use expression().
2170
//
2171
// Anyway, after processing the optionalDatatype(), if KEYWORD_IN
2172
// or a COLON is at la(2), it's an each loop. Otherwise, it's the
2173
// standard for loop.
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
// Next up, a single expression is the test clause, followed
2210
// by a semicolon.
2211

2212            header.add( expression() );
2213            consume( Types.SEMICOLON );
2214
2215
2216            //
2217
// Finally, the increment section is a (possibly empty) comma-
2218
// separated list of expressions followed by the RIGHT_PARENTHESIS.
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
// PRODUCTIONS: EXPRESSIONS
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        // int id = nestCount++;
2343
// System.out.println( "ENTERING EXPRESSION " + id );
2344

2345        ExpressionStack stack = new ExpressionStack( this );
2346        CSTNode expression = null;
2347
2348        boolean bareMode = false;
2349
2350        MAIN_LOOP: do
2351        {
2352            //
2353
// Valid at the start of an (sub)expression, a typed variable declaration
2354
// is handled separately. It has the form
2355

2356            //
2357
// In the SHIFT phase, we move stuff onto the stack that can have
2358
// multiple meanings and/or precedence issues, and leave the interpretation
2359
// for a later REDUCE. No lookahead is used. When structures are found that
2360
// have a consistent form, we use LL techniques (the new operator, for instance).
2361

2362            Token next = la(stack);
2363            int type = next.getMeaningAs( EXPRESSION_SHIFT_HANDLERS );
2364
2365            // System.out.println( "expression() status:" );
2366
// System.out.println( stack.toString() );
2367
// System.out.println( "next: " );
2368
// System.out.println( next.toString() );
2369
// System.out.println( la(2).toString() );
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
// Method parameters don't make it here (see REDUCE)...
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
// Method calls don't make it here (see REDUCE). It is
2456
// either a sub-expression or a cast.
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
// All other operators are caught during REDUCE, so if it makes
2517
// it here, it's either the end of the expression, or an error.
2518

2519                    if( stack.size() == 1 && stack.topIsAnExpression() )
2520                    {
2521                        break MAIN_LOOP; // <<< FLOW CONTROL <<<<<<<<<
2522
}
2523                    else
2524                    {
2525                        error();
2526                    }
2527                }
2528
2529
2530            }
2531
2532
2533
2534            //
2535
// In the REDUCE phase, we try to find ways to convert several stack
2536
// elements (and maybe one lookahead token) into a single expression.
2537
// We retry the REDUCE as long as it succeeds. Note that reductions
2538
// are ONLY possible when the top of the stack is an expression.
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
// We reduce at most once per iteration, so we collect info here.
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                // System.out.println( "expression() stack for reduce: " + stack );
2565
// System.out.println( "expression() next token for reduce: " + next );
2566

2567                nextPrecedence = Types.getPrecedence( next.getMeaning(), false );
2568                top1Precedence = Types.getPrecedence( top1.getMeaning(), false );
2569
2570
2571
2572              //---------------------------------------------------------------
2573
// UNUSUAL STUFF FIRST
2574

2575
2576                //
2577
// Not really an operator at all, if top1 is a "(" and next is an ")",
2578
// we should reduce. Extra processing is needed because the "(" is not
2579
// the type of an expression.
2580

2581                if( top1.isA(Types.LEFT_PARENTHESIS) )
2582                {
2583                    if( next.isA(Types.RIGHT_PARENTHESIS) )
2584                    {
2585                        consume();
2586
2587                        //
2588
// To simplify things, cast operators MUST appear on the same line
2589
// as the start of their operands. Without name lookup, we can't
2590
// be sure that even things that look like casts are, but we assume
2591
// they are and let later phases correct, where necessary.
2592

2593                        next = la(true); // XXX the precludes is true for GString. Seems wrong
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; // <<< LOOP CONTROL <<<<<<<<<
2612
}
2613                    else
2614                    {
2615                        skipPatterns = true;
2616                    }
2617                }
2618
2619
2620                //
2621
// Highest precedence: "new". If it is preceeded on the stack by
2622
// a ".", what preceeds the "." is the context for the new, and
2623
// we'll have to do some rewriting.... Note that SHIFT will only
2624
// shift a "new" if it is preceeded by nothing or an operator,
2625
// and it will only shift a "." if it is preceeded by an expression.
2626
// Therefore, we can assume any preceeding "." is an operator.
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; // <<< LOOP CONTROL <<<<<<<<<
2643
}
2644                }
2645
2646
2647                //
2648
// Not unusual, but handled here to simplify precendence handling for
2649
// the rest of the unusual stuff: dereference operators are left-associative.
2650

2651                if( top1.isA(Types.DEREFERENCE_OPERATOR) && !top0.hasChildren() )
2652                {
2653                    stack.reduce( 3, 1, true );
2654
2655                    checkAgain = true;
2656                    continue; // <<< LOOP CONTROL <<<<<<<<<
2657
}
2658
2659
2660
2661                //
2662
// Next precedence, array offsets. Because we allow lists and ranges
2663
// and such inside list expressions, all lists will have been processed
2664
// to a SYNTH_LISTH during SHIFT. Here we do some rewriting, where
2665
// necessary. Empty array offsets are only allowed on types, and we
2666
// run the appropriate conversion in that case.
2667

2668                if( top0.isA(Types.SYNTH_LIST) && top1.isAnExpression() || ExpressionSupport.isAPotentialTypeName(top1, false) )
2669                {
2670                    //
2671
// Empty list is an array type
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
// Okay, we have an array type. We now convert the list and
2686
// expression to an array type, and slurp any further dimensions
2687
// off the lookahead.
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
// One last decision: variable type declaration, or
2702
// cast, or class reference...
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
// Non-empty list is an offset (probably)
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; // <<< LOOP CONTROL <<<<<<<<<
2756

2757                }
2758
2759
2760
2761                //
2762
// Next precedence: typed variable declarations. If the top of stack
2763
// isAPotentialTypeName(), la(true) is an identifier, and la(2) is
2764
// an "=", it's a declaration.
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; // <<< LOOP CONTROL <<<<<<<<<
2772
}
2773
2774
2775                //
2776
// Before getting to method call handling proper, we should check for any
2777
// pending bookkeeping. If the top of stack is a closure and the element
2778
// before it is a method call, the closure is either one of its parameters
2779
// or an error.
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; // <<< LOOP CONTROL <<<<<<<<<
2795
}
2796
2797
2798                //
2799
// Next precedence: method calls and typed declarations. If the top of stack
2800
// isInvokable() and la(stack) is an "(", an "{", or a simple expression, it's
2801
// a method call. We leave the closure for the next SHIFT.
2802

2803                if( ExpressionSupport.isInvokable(top0) && (next.isA(Types.LEFT_CURLY_BRACE) || la(true).isA(Types.METHOD_CALL_STARTERS)) )
2804                {
2805                    // System.out.println( "making a method call of " + top0 );
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; // <<< LOOP CONTROL <<<<<<<<<
2843
}
2844
2845
2846                //
2847
// Handle postfix operators next. We have to check for acceptable
2848
// precedence before doing it. All the higher precedence reductions
2849
// have already been checked.
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; // <<< LOOP CONTROL <<<<<<<<<
2865
}
2866
2867
2868                //
2869
// The ternary operator will be seen twice. The first reduction is
2870
// infix when there is a ":" on lookahed. The second reduction is
2871
// prefix when there is a lower-precedence operator on lookahed.
2872
// The ternary operator is right-associative. Note that
2873
// Types.getPrecedence() on a ternary operator returns 10.
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; // <<< LOOP CONTROL <<<<<<<<<
2899
}
2900
2901
2902
2903
2904              //---------------------------------------------------------------
2905
// PATTERN STUFF SECOND
2906

2907
2908                //
2909
// Note that because of the loop control above, we get here only if none
2910
// of the above options matched.
2911
//
2912
// So, everything else we handle generically: top1 will be an operator, and
2913
// will be reduced or not with top0 and possibly top2, depending on the
2914
// cardinality and associativity of the operator, and the type of la().
2915

2916                if( skipPatterns || !ExpressionSupport.isAnOperator(top1, false) )
2917                {
2918                    break; // <<< LOOP CONTROL <<<<<<<<<
2919
}
2920
2921
2922                switch( top1.getMeaningAs(EXPRESSION_REDUCE_HANDLERS) )
2923                {
2924                    //
2925
// Prefix increment/decrement operators aren't always valid, so we
2926
// handle the separately from the other prefix operators.
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
// All other prefix operators. They are all right-associative.
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
// Handle the assignment operators. They are all right-associative.
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
// Handle the instenceof keyword. The rhs has to be a potential type.
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
// Handle all other infix operators. They are all left-associative.
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
// Anything else in top1 is an bug.
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        // System.out.println( "EXITING EXPRESSION " + id );
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 ); // done for line number on SYNTH
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        // int id = nestCount++;
3141
// System.out.println( "ENTERING GSTRING " + id );
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        // System.out.println( "EXITING GSTRING " + id );
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        // int id = nestCount++;
3203
// System.out.println( "ENTERING PARAMETER LIST " + id );
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        // System.out.println( "EXITING PARAMETER LIST " + id );
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        // int id = nestCount++;
3276
// System.out.println( "ENTERING NEW " + id );
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
// First up, figure out the actual type and any
3285
// stated dimensions.
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
// If implicit, there must be initialization data
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
// Process the constructor call
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
// If a "{" follows, it's a class body or a closure...
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        // System.out.println( "EXITING NEW " + id );
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        // int id = nestCount++;
3416
// System.out.println( "ENTERING CLOSURE EXPRESSION " + id );
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
// DEPRECATED: the old syntax for parameters had a | only
3424
// at the end of the parameter list. The new syntax has
3425
// two pipes or none. For now, we attempt to support the
3426
// old syntax. It can mistake a variable declaration
3427
// for a parameter declaration, though, so it may cause more
3428
// trouble than it's worth. This if() and the one below
3429
// (also marked) should be removed before v1.0.
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
// If the parameter list is specified, process it.
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
// DEPRECATED: further support for note above, this consume()
3458
// should not be conditional after the above code is removed.
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
// Finally, process the statements.
3477

3478        closure.add( statementsUntilRightCurly() );
3479        consume( Types.RIGHT_CURLY_BRACE );
3480
3481        // System.out.println( "EXITING CLOSURE EXPRESSION " + id );
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
// Process the data. On the first one, check if we are
3532
// processing a map. We assume not going in, as the empty
3533
// map isn't relevant...
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
// ERROR REPORTING
3584

3585
3586   /**
3587    * Reports an error assembled from parts.
3588    */

3589
3590    protected UnexpectedTokenException error( Token found, int[] expectedTypes, boolean throwIt, String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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
// ERROR RECOVERY
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
// TOKEN LOOKAHEAD
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
// Count down on k while counting up on streamK.
3796
// NOTE: k starting at less than 1 is a mistake...
3797
// This routine will reliably NOT return Token.NULL
3798
// /unless/ it is actually in the stream.
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
// TOKEN CONSUMPTION
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}
4012
Popular Tags