View Javadoc

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/package-summary.html">Reduction packageDeclaration = null;
250 
251         if( lt() == Types.KEYWORD_PACKAGE )
252         {
253             try
254             {
255                 packageDeclaration = packageDeclaration();
256             }
257 
258             catch (SyntaxException e)
259             {
260                 controller.addError(e);
261                 recover();
262             }
263         }
264 
265         if( packageDeclaration == null )/package-summary.html">strong>( 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 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     publicReduction packageDeclaration() throws SyntaxException, CompilationFailedException/package-summary.html">ong> Reduction packageDeclaration() throws SyntaxException, CompilationFailedException
330     {
331         Reduction packageDeclaration = consume(Types/KEYWORD_PACKAGE)/asReduction( dottedIdentifier() )/package-summary.html">Reduction packageDeclaration = consume(Types.KEYWORD_PACKAGE).asReduction( dottedIdentifier() );
332         endOfStatement( false );
333 
334         return</strong> packageDeclaration;
335     }
336 
337 
338 
339    /***
340     *  Processes an import statement.  Called by <code>module()</code>.
341     *  <p>
342     *  Grammar: <pre>
343     *     importStatement = "import" (all|specific) <eos>
344     *
345     *     all      = package "." (package ".")* "*"
346     *
347     *     specific = (package "." (package ".")*)? classes
348     *     classes  = class ["as" alias] ("," class ["as" alias])*
349     *
350     *     package  = <identifier>
351     *     class    = <identifier>
352     *     alias    = <identifier>
353     *  </pre>
354     *  <p>
355     *  CST: <pre>
356     *     import   = { "import" (package|{}) ({"*"} | clause+) }
357     *
358     *     package  = { "." package <identifier> } | <identifier>
359     *     clause   = { <identifier> <alias>? }
360     *  </pre>
361     */
362 
363     public Reduction importStatement() throws SyntaxException, CompilationFailedException
364     {
365         Reduction importStatement = consume(Types.KEYWORD_IMPORT).asReduction();
366 
367         //
368         // First, process any package name.
369 
370         CSTNode packageNode = null/package-summary.html">CSTNode packageNode = null;
371         if( lt(2) == Types.DOT )
372         {
373             packageNode = consume(Types.IDENTIFIER).asReduction();
374 
375             while( lt(3) == Types.DOT )
376             {
377                 packageNode = consume(Types.DOT).asReduction( packageNode );
378                 packageNode.add( consume(Types.IDENTIFIER) );
379             }
380 
381             consume( Types.DOT );
382         }
383 
384         if( packageNode == null )/package-summary.html">strong>( 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();
1080                     }
1081                 }
1082                 catch( Exception 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 comment ) throws SyntaxException
3591     {
3592         UnexpectedTokenException e = new UnexpectedTokenException( found, expectedTypes, comment );
3593 
3594         if( throwIt )
3595         {
3596             throw e;
3597         }
3598 
3599         return e;
3600     }
3601 
3602 
3603    /***
3604     *  Reports an error by generating and optionally throwing an
3605     *  <code>UnexpectedTokenException</code>.
3606     */
3607 
3608     protected UnexpectedTokenException error( int[] expectedTypes, boolean throwIt, int k, String comment ) throws SyntaxException, CompilationFailedException
3609     {
3610         return error( la(k), expectedTypes, throwIt, comment );
3611     }
3612 
3613 
3614 
3615    /***
3616     *  A synonym for <code>error( expectedTypes, throwIt, k, null )</code>.
3617     */
3618 
3619     protected UnexpectedTokenException error( int[] expectedTypes, boolean throwIt, int k ) throws SyntaxException, CompilationFailedException
3620     {
3621         return error( expectedTypes, throwIt, k, null );
3622     }
3623 
3624 
3625 
3626    /***
3627     *  A synonym for <code>error( expectedTypes, true, 1, null )</code>.
3628     */
3629 
3630     protected void error( int[] expectedTypes ) throws SyntaxException, CompilationFailedException
3631     {
3632         throw error( expectedTypes, false, 1, null );
3633     }
3634 
3635 
3636 
3637    /***
3638     *  A synonym for <code>error( null, true, 1, null )</code>.
3639     */
3640 
3641     protected void error() throws SyntaxException, CompilationFailedException
3642     {
3643         throw error( null, true, 1, null );
3644     }
3645 
3646 
3647 
3648    /***
3649     *  A synonym for <code>error( null, true, 1, comment )</code>.
3650     */
3651 
3652     protected void error( String comment ) throws SyntaxException, CompilationFailedException
3653     {
3654         throw error( null, true, 1, comment );
3655     }
3656 
3657 
3658 
3659    /***
3660     *  A synonym for <code>error( found, null, true, comment )</code>.
3661     */
3662 
3663     protected void error( Token found, String comment ) throws SyntaxException
3664     {
3665         throw error( found, null, true, comment );
3666     }
3667 
3668 
3669 
3670    /***
3671     *  A scalar synonym of <code>error( expectedTypes )</code>.
3672     */
3673 
3674     protected void error( int expectedType ) throws SyntaxException, CompilationFailedException
3675     {
3676         error( new int[] { expectedType } );
3677     }
3678 
3679 
3680 
3681 
3682   //---------------------------------------------------------------------------
3683   // 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 }