Clover coverage report - groovy - 1.0-beta-7
Coverage timestamp: Wed Sep 29 2004 16:55:52 BST
file stats: LOC: 4,012   Methods: 80
NCLOC: 1,868   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
Parser.java 0% 0% 0% 0%
coverage
 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  0
     public Parser( SourceUnit controller, TokenStream tokenStream )
 89   
     {
 90  0
         this.controller  = controller;
 91  0
         this.tokenStream = tokenStream;
 92   
     }
 93   
 
 94   
 
 95   
    /**
 96   
     *  Synonym for module(), the primary entry point.
 97   
     */
 98   
 
 99  0
     public Reduction parse() throws CompilationFailedException
 100   
     {
 101  0
         try
 102   
         {
 103  0
             return module();
 104   
         }
 105   
         catch( SyntaxException e )
 106   
         {
 107  0
             controller.addFatalError( new SyntaxErrorMessage(e) );
 108   
         }
 109   
 
 110  0
         throw new GroovyBugError( "this will never happen" );
 111   
     }
 112   
 
 113   
 
 114   
 
 115   
    /**
 116   
     *  Returns the <code>TokenStream</code> being parsed.
 117   
     */
 118   
 
 119  0
     public TokenStream getTokenStream()
 120   
     {
 121  0
         return this.tokenStream;
 122   
     }
 123   
 
 124   
 
 125   
 
 126   
 
 127   
   //---------------------------------------------------------------------------
 128   
   // PRODUCTION SUPPORT
 129   
 
 130   
 
 131   
    /**
 132   
     *  Eats any optional newlines.
 133   
     */
 134   
 
 135  0
     public void optionalNewlines() throws SyntaxException, CompilationFailedException
 136   
     {
 137  0
         while( lt(false) == Types.NEWLINE)
 138   
         {
 139  0
             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  0
     public void endOfStatement( boolean allowRightCurlyBrace ) throws SyntaxException, CompilationFailedException
 151   
     {
 152  0
         Token next = la( true );
 153   
 
 154  0
         if( next.isA(Types.GENERAL_END_OF_STATEMENT) )
 155   
         {
 156  0
             consume( true );
 157   
         }
 158   
         else
 159   
         {
 160  0
             if( allowRightCurlyBrace )
 161   
             {
 162  0
                 if( !next.isA(Types.RIGHT_CURLY_BRACE) )
 163   
                 {
 164  0
                     error( new int[] { Types.SEMICOLON, Types.NEWLINE, Types.RIGHT_CURLY_BRACE } );
 165   
                 }
 166   
             }
 167   
             else
 168   
             {
 169  0
                 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  0
     public void endOfStatement() throws SyntaxException, CompilationFailedException
 181   
     {
 182  0
         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  0
     public CSTNode dottedIdentifier() throws SyntaxException, CompilationFailedException
 205   
     {
 206  0
         CSTNode identifier = consume(Types.IDENTIFIER);
 207   
 
 208  0
         while (lt() == Types.DOT)
 209   
         {
 210  0
             identifier = consume(Types.DOT).asReduction( identifier, consume(Types.IDENTIFIER) );
 211   
         }
 212   
 
 213  0
         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  0
     public Reduction module() throws SyntaxException, CompilationFailedException
 241   
     {
 242  0
         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  0
         Reduction packageDeclaration = null;
 250   
 
 251  0
         if( lt() == Types.KEYWORD_PACKAGE )
 252   
         {
 253  0
             try
 254   
             {
 255  0
                 packageDeclaration = packageDeclaration();
 256   
             }
 257   
 
 258   
             catch (SyntaxException e)
 259   
             {
 260  0
                 controller.addError(e);
 261  0
                 recover();
 262   
             }
 263   
         }
 264   
 
 265  0
         if( packageDeclaration == null )
 266   
         {
 267  0
             packageDeclaration = Reduction.EMPTY;
 268   
         }
 269   
 
 270  0
         module.add( packageDeclaration );
 271   
 
 272   
 
 273   
         //
 274   
         // Next, handle import statements
 275   
 
 276  0
         Reduction imports = (Reduction)module.add( Reduction.newContainer() );
 277  0
         Object collector;
 278   
 
 279  0
         while( lt() == Types.KEYWORD_IMPORT )
 280   
         {
 281  0
             try
 282   
             {
 283  0
                 imports.add( importStatement() );
 284   
             }
 285   
 
 286   
             catch( SyntaxException e )
 287   
             {
 288  0
                 controller.addError(e);
 289  0
                 recover();
 290   
             }
 291   
         }
 292   
 
 293   
 
 294   
         //
 295   
         // With that taken care of, process everything else.
 296   
 
 297  0
         while( lt() != Types.EOF )
 298   
         {
 299  0
             try
 300   
             {
 301  0
                 module.add( topLevelStatement() );
 302   
             }
 303   
             catch (SyntaxException e)
 304   
             {
 305  0
                 controller.addError(e);
 306  0
                 recover();
 307   
             }
 308   
         }
 309   
 
 310  0
         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  0
     public Reduction packageDeclaration() throws SyntaxException, CompilationFailedException
 330   
     {
 331  0
         Reduction packageDeclaration = consume(Types.KEYWORD_PACKAGE).asReduction( dottedIdentifier() );
 332  0
         endOfStatement( false );
 333   
 
 334  0
         return packageDeclaration;
 335   
     }
 336   
 
 337   
 
 338   
 
 339   
    /**
 340   
     *  Processes an import statement.  Called by <code>module()</code>.
 341   
     *  <p>
 342   
     *  Grammar: <pre>
 343   
     *     importStatement = "import" (all|specific) <eos>
 344   
     *
 345   
     *     all      = package "." (package ".")* "*"
 346   
     *
 347   
     *     specific = (package "." (package ".")*)? classes
 348   
     *     classes  = class ["as" alias] ("," class ["as" alias])*
 349   
     *
 350   
     *     package  = <identifier>
 351   
     *     class    = <identifier>
 352   
     *     alias    = <identifier>
 353   
     *  </pre>
 354   
     *  <p>
 355   
     *  CST: <pre>
 356   
     *     import   = { "import" (package|{}) ({"*"} | clause+) }
 357   
     *
 358   
     *     package  = { "." package <identifier> } | <identifier>
 359   
     *     clause   = { <identifier> <alias>? }
 360   
     *  </pre>
 361   
     */
 362   
 
 363  0
     public Reduction importStatement() throws SyntaxException, CompilationFailedException
 364   
     {
 365  0
         Reduction importStatement = consume(Types.KEYWORD_IMPORT).asReduction();
 366   
 
 367   
         //
 368   
         // First, process any package name.
 369   
 
 370  0
         CSTNode packageNode = null;
 371  0
         if( lt(2) == Types.DOT )
 372   
         {
 373  0
             packageNode = consume(Types.IDENTIFIER).asReduction();
 374   
 
 375  0
             while( lt(3) == Types.DOT )
 376   
             {
 377  0
                 packageNode = consume(Types.DOT).asReduction( packageNode );
 378  0
                 packageNode.add( consume(Types.IDENTIFIER) );
 379   
             }
 380   
 
 381  0
             consume( Types.DOT );
 382   
         }
 383   
 
 384  0
         if( packageNode == null )
 385   
         {
 386  0
             packageNode = Reduction.EMPTY;
 387   
         }
 388   
 
 389  0
         importStatement.add( packageNode );
 390   
 
 391   
 
 392   
         //
 393   
         // Then process the class list.
 394   
 
 395  0
         if( !packageNode.isEmpty() && lt() == Types.STAR )
 396   
         {
 397  0
             importStatement.add( consume(Types.STAR) );
 398   
         }
 399   
         else
 400   
         {
 401  0
            boolean done = false;
 402  0
            while( !done )
 403   
            {
 404  0
                Reduction clause = consume(Types.IDENTIFIER).asReduction();
 405  0
                if( lt() == Types.KEYWORD_AS )
 406   
                {
 407  0
                    consume( Types.KEYWORD_AS );
 408  0
                    clause.add( consume(Types.IDENTIFIER) );
 409   
                }
 410   
 
 411  0
                importStatement.add( clause );
 412   
 
 413  0
                if( lt() == Types.COMMA )
 414   
                {
 415  0
                    consume( Types.COMMA );
 416   
                }
 417   
                else
 418   
                {
 419  0
                    done = true;
 420   
                }
 421   
            }
 422   
 
 423   
         }
 424   
 
 425   
         //
 426   
         // End the statement and return.
 427   
 
 428  0
         endOfStatement( false );
 429  0
         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  0
     public CSTNode topLevelStatement() throws SyntaxException, CompilationFailedException
 466   
     {
 467  0
         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  0
         if (lt() == Types.KEYWORD_DEF)
 477   
         {
 478  0
             consume();
 479   
 
 480  0
             Reduction modifiers  = modifierList( false, false );
 481  0
             CSTNode   type       = optionalDatatype( false, true );
 482  0
             Token     identifier = nameDeclaration( false );
 483   
 
 484  0
             result = methodDeclaration(modifiers, type, identifier, false);
 485   
         }
 486   
 
 487  0
         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  0
         else if( lt() == Types.KEYWORD_SYNCHRONIZED && lt(2) == Types.LEFT_PARENTHESIS )
 497   
         {
 498  0
             result = synchronizedStatement();
 499   
         }
 500   
 
 501   
         //
 502   
         // If it starts with a modifier, "class", or "interface",
 503   
         // it's a type declaration.
 504   
 
 505  0
         else if( la().isA(Types.DECLARATION_MODIFIER) || la().isA(Types.TYPE_DECLARATION) )
 506   
         {
 507  0
             Reduction modifiers = modifierList( true, true );
 508   
 
 509  0
             switch( lt() )
 510   
             {
 511   
                 case Types.KEYWORD_CLASS:
 512   
                 {
 513  0
                     result = classDeclaration( modifiers );
 514  0
                     break;
 515   
                 }
 516   
 
 517   
                 case Types.KEYWORD_INTERFACE:
 518   
                 {
 519  0
                     result = interfaceDeclaration( modifiers );
 520  0
                     break;
 521   
                 }
 522   
 
 523   
                 default:
 524   
                 {
 525  0
                     error( new int[] { Types.KEYWORD_CLASS, Types.KEYWORD_INTERFACE } );
 526  0
                     break;
 527   
                 }
 528   
             }
 529   
         }
 530   
 
 531   
         //
 532   
         // Otherwise, it's a statement.
 533   
 
 534   
         else
 535   
         {
 536  0
             result = statement();
 537   
         }
 538   
 
 539  0
         return result;
 540   
     }
 541   
 
 542   
 
 543   
 
 544   
    /**
 545   
     *  A synomym for <code>topLevelStatement()</code>.
 546   
     */
 547   
 
 548  0
     public CSTNode typeDeclaration() throws SyntaxException, CompilationFailedException
 549   
     {
 550  0
         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  0
     public Reduction modifierList(boolean allowStatic, boolean allowAbstract) throws CompilationFailedException, SyntaxException
 569   
     {
 570  0
         Reduction modifiers = Reduction.newContainer();
 571   
 
 572  0
         while( la().isA(Types.DECLARATION_MODIFIER) )
 573   
         {
 574  0
             if( lt() == Types.KEYWORD_ABSTRACT && !allowAbstract)
 575   
             {
 576  0
                 controller.addError( "keyword 'abstract' not valid in this setting", la() );
 577   
             }
 578  0
             else if (lt() == Types.KEYWORD_STATIC && !allowStatic)
 579   
             {
 580  0
                 controller.addError( "keyword 'static' not valid in this setting", la() );
 581   
             }
 582  0
             modifiers.add( consume() );
 583   
         }
 584   
 
 585  0
         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  0
     public Reduction classDeclaration( Reduction modifiers ) throws SyntaxException, CompilationFailedException
 613   
     {
 614  0
         consume( Types.KEYWORD_CLASS );
 615   
 
 616  0
         Reduction classDeclaration = consume(Types.IDENTIFIER).asReduction( modifiers );
 617  0
         classDeclaration.setMeaning( Types.SYNTH_CLASS );
 618   
 
 619   
 
 620   
         //
 621   
         // Process any extends clause.
 622   
 
 623  0
         try
 624   
         {
 625  0
             classDeclaration.add( typeList(Types.KEYWORD_EXTENDS, true, 1) );
 626   
         }
 627   
         catch (SyntaxException e)
 628   
         {
 629  0
             controller.addError(e);
 630  0
             classDeclaration.add( Reduction.EMPTY );
 631   
         }
 632   
 
 633   
 
 634   
         //
 635   
         // Process any implements clause.
 636   
 
 637  0
         try
 638   
         {
 639  0
             classDeclaration.add( typeList(Types.KEYWORD_IMPLEMENTS, true, 0) );
 640   
         }
 641   
         catch (SyntaxException e)
 642   
         {
 643  0
             controller.addError(e);
 644  0
             classDeclaration.add( Reduction.EMPTY );
 645   
         }
 646   
 
 647   
 
 648   
         //
 649   
         // Process the declaration body.  We currently ignore the abstract keyword.
 650   
 
 651  0
         classDeclaration.add( typeBody(true, true, false) );
 652   
 
 653  0
         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  0
     public Reduction interfaceDeclaration( Reduction modifiers ) throws SyntaxException, CompilationFailedException
 679   
     {
 680  0
         consume( Types.KEYWORD_INTERFACE );
 681   
 
 682  0
         Reduction interfaceDeclaration = consume(Types.IDENTIFIER).asReduction( modifiers, Reduction.EMPTY );
 683  0
         interfaceDeclaration.setMeaning( Types.SYNTH_INTERFACE );
 684   
 
 685   
 
 686   
         //
 687   
         // Process any extends clause.
 688   
 
 689  0
         try
 690   
         {
 691  0
             interfaceDeclaration.add( typeList(Types.KEYWORD_EXTENDS, true, 0) );
 692   
         }
 693   
         catch (SyntaxException e)
 694   
         {
 695  0
             controller.addError(e);
 696  0
             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  0
         interfaceDeclaration.add( typeBody(false, true, true) );
 705  0
         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  0
     public Reduction typeList(int declarator, boolean optional, int limit) throws SyntaxException, CompilationFailedException
 727   
     {
 728  0
         Reduction typeList = null;
 729   
 
 730  0
         if( lt() == declarator )
 731   
         {
 732  0
             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  0
             while( limit == 0 || typeList.children() < limit )
 739   
             {
 740   
                 //
 741   
                 // Try for a list entry, and correct if missing
 742   
 
 743  0
                 try
 744   
                 {
 745  0
                     if( typeList.children() > 0)
 746   
                     {
 747  0
                         consume( Types.COMMA );
 748   
                     }
 749   
 
 750  0
                     typeList.add( datatype(false) );
 751   
                 }
 752   
                 catch (SyntaxException e)
 753   
                 {
 754  0
                     controller.addError(e);
 755  0
                     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  0
                 if( !la().isA(Types.COMMA) )
 764   
                 {
 765  0
                     break;
 766   
                 }
 767   
             }
 768   
         }
 769   
 
 770   
         else
 771   
         {
 772  0
             if (optional)
 773   
             {
 774  0
                 typeList = Reduction.EMPTY;
 775   
             }
 776   
             else
 777   
             {
 778  0
                 error( declarator );
 779   
             }
 780   
         }
 781   
 
 782  0
         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  0
     public Reduction typeBody(boolean allowStatic, boolean allowAbstract, boolean requireAbstract) throws SyntaxException, CompilationFailedException
 802   
     {
 803  0
         Reduction body = Reduction.newContainer();
 804   
 
 805  0
         consume( Types.LEFT_CURLY_BRACE );
 806   
 
 807  0
         while( lt() != Types.EOF && lt() != Types.RIGHT_CURLY_BRACE )
 808   
         {
 809  0
             try
 810   
             {
 811  0
                 body.add( typeBodyStatement(allowStatic, allowAbstract, requireAbstract) );
 812   
             }
 813   
             catch( SyntaxException e )
 814   
             {
 815  0
                 controller.addError(e);
 816  0
                 recover();
 817   
             }
 818   
         }
 819   
 
 820  0
         consume( Types.RIGHT_CURLY_BRACE );
 821   
 
 822  0
         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  0
     public Reduction typeBodyStatement(boolean allowStatic, boolean allowAbstract, boolean requireAbstract) throws SyntaxException, CompilationFailedException
 861   
     {
 862  0
         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  0
         if( lt() == Types.KEYWORD_STATIC && lt(2) == Types.LEFT_CURLY_BRACE )
 869   
         {
 870  0
             if (!allowStatic)
 871   
             {
 872  0
                 controller.addError( "static initializers not valid in this context", la() );
 873   
             }
 874   
 
 875  0
             Reduction modifiers  = modifierList( true, false );
 876  0
             Token     identifier = Token.NULL;
 877  0
             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  0
             Reduction modifiers = modifierList( allowStatic, allowAbstract );
 886   
 
 887   
             //
 888   
             // Check for inner types
 889   
 
 890  0
             if( lt() == Types.KEYWORD_CLASS )
 891   
             {
 892  0
                 statement = classDeclaration( modifiers );
 893   
             }
 894   
 
 895  0
             else if( lt() == Types.KEYWORD_INTERFACE )
 896   
             {
 897  0
                 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  0
                 if( lt() == Types.KEYWORD_PROPERTY )
 909   
                 {
 910  0
                     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  0
                 while( lt(true) == Types.NEWLINE)
 921   
                 {
 922  0
                     consume( Types.NEWLINE );
 923   
                 }
 924   
 
 925   
                 //
 926   
                 // We don't yet know about void, so we err on the side of caution
 927   
 
 928  0
                 CSTNode   type       = optionalDatatype( true, true );
 929  0
                 Token     identifier = nameDeclaration( true );
 930   
 
 931  0
                 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  0
                         boolean methodIsAbstract = requireAbstract;
 940   
 
 941  0
                         if( !methodIsAbstract )
 942   
                         {
 943  0
                             for( int i = 1; i < modifiers.size(); i++ )
 944   
                             {
 945  0
                                 if( modifiers.get(i).getMeaning() == Types.KEYWORD_ABSTRACT )
 946   
                                 {
 947  0
                                     methodIsAbstract = true;
 948  0
                                     break;
 949   
                                 }
 950   
                             }
 951   
                         }
 952   
 
 953  0
                         statement = methodDeclaration( modifiers, type, identifier, methodIsAbstract );
 954  0
                         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  0
                         statement = propertyDeclaration( modifiers, type, identifier );
 963  0
                         break;
 964   
 
 965   
                     default:
 966  0
                         error( new int[] { Types.LEFT_PARENTHESIS, Types.EQUAL, Types.SEMICOLON, Types.NEWLINE, Types.RIGHT_CURLY_BRACE } );
 967   
                 }
 968   
             }
 969   
         }
 970   
 
 971  0
         return statement;
 972   
     }
 973   
 
 974   
 
 975   
 
 976   
    /**
 977   
     *  A synonym for <code>typeBodyStatement( true, true, false )</code>.
 978   
     */
 979   
 
 980  0
     public Reduction bodyStatement() throws SyntaxException, CompilationFailedException
 981   
     {
 982  0
         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  0
     protected Token nameDeclaration( boolean significantNewlines ) throws SyntaxException, CompilationFailedException
 1001   
     {
 1002  0
         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  0
     protected Token nameReference( boolean significantNewlines ) throws SyntaxException, CompilationFailedException
 1021   
     {
 1022   
 
 1023  0
         Token token = la( significantNewlines );
 1024  0
         if( !token.canMean(Types.IDENTIFIER) )
 1025   
         {
 1026  0
             error( Types.IDENTIFIER );
 1027   
         }
 1028   
 
 1029  0
         consume();
 1030  0
         token.setMeaning( Types.IDENTIFIER );
 1031   
 
 1032  0
         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  0
     protected CSTNode optionalDatatype( boolean significantNewlines, boolean allowVoid ) throws SyntaxException, CompilationFailedException
 1054   
     {
 1055  0
         CSTNode type = Reduction.EMPTY;
 1056  0
         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  0
         if( next.isA(Types.IDENTIFIER) )
 1065   
         {
 1066  0
             if( lt(2, significantNewlines) == Types.IDENTIFIER )
 1067   
             {
 1068  0
                 type = datatype( allowVoid );
 1069   
             }
 1070   
             else
 1071   
             {
 1072  0
                 getTokenStream().checkpoint();
 1073   
 
 1074  0
                 try
 1075   
                 {
 1076  0
                     type = datatype( allowVoid );
 1077  0
                     if( lt(significantNewlines) != Types.IDENTIFIER )
 1078   
                     {
 1079  0
                         throw new Exception();
 1080   
                     }
 1081   
                 }
 1082   
                 catch( Exception e )
 1083   
                 {
 1084  0
                     getTokenStream().restore();
 1085  0
                     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  0
         else if( next.isA(Types.PRIMITIVE_TYPE) )
 1096   
         {
 1097  0
             type = datatype( allowVoid );
 1098   
         }
 1099   
 
 1100  0
         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  0
     public Reduction propertyDeclaration( Reduction modifiers, CSTNode type, Token identifier ) throws SyntaxException, CompilationFailedException
 1125   
     {
 1126  0
         Reduction property = identifier.asReduction( modifiers, type );
 1127  0
         property.setMeaning( Types.SYNTH_PROPERTY );
 1128   
 
 1129  0
         if( lt() == Types.EQUAL )
 1130   
         {
 1131  0
             consume();
 1132  0
             property.add( expression() );
 1133   
         }
 1134   
 
 1135  0
         endOfStatement();
 1136  0
         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  0
     public Reduction methodDeclaration( Reduction modifiers, CSTNode type, Token identifier, boolean emptyOnly) throws SyntaxException, CompilationFailedException
 1167   
     {
 1168  0
         Reduction method = identifier.asReduction( modifiers, type );
 1169  0
         method.setMeaning( Types.SYNTH_METHOD );
 1170   
 
 1171   
         //
 1172   
         // Process the parameter list
 1173   
 
 1174  0
         consume(Types.LEFT_PARENTHESIS);
 1175  0
         method.add( parameterDeclarationList() );
 1176  0
         consume(Types.RIGHT_PARENTHESIS);
 1177   
 
 1178   
         //
 1179   
         // Process the optional "throws" clause
 1180   
 
 1181  0
         try
 1182   
         {
 1183  0
             method.add( typeList( Types.KEYWORD_THROWS, true, 0 ) );
 1184   
         }
 1185   
         catch (SyntaxException e)
 1186   
         {
 1187  0
             controller.addError(e);
 1188  0
             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  0
         CSTNode body = null;
 1196   
 
 1197  0
         if( emptyOnly )
 1198   
         {
 1199  0
             if( lt() == Types.LEFT_CURLY_BRACE )
 1200   
             {
 1201  0
                 controller.addError( "abstract and interface methods cannot have a body", la() );
 1202   
             }
 1203   
             else
 1204   
             {
 1205  0
                 body = Reduction.EMPTY;
 1206  0
                 endOfStatement();
 1207   
             }
 1208   
 
 1209   
         }
 1210   
 
 1211  0
         if( body == null )
 1212   
         {
 1213  0
             body = statementBody(true);
 1214   
         }
 1215   
 
 1216  0
         method.add( body );
 1217   
 
 1218   
 
 1219  0
         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  0
     protected Reduction parameterDeclarationList() throws SyntaxException, CompilationFailedException
 1242   
     {
 1243  0
         Reduction list = Reduction.newContainer();
 1244   
 
 1245  0
         boolean expectDefaults = false;
 1246  0
         while( la().isA(Types.TYPE_NAME) )  // TYPE_NAME includes <identifier>, and so does double duty
 1247   
         {
 1248   
 
 1249   
             //
 1250   
             // Get the declaration
 1251   
 
 1252  0
             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  0
             if( expectDefaults || lt() == Types.EQUAL )
 1259   
             {
 1260  0
                 expectDefaults = true;
 1261  0
                 consume( Types.EQUAL );
 1262   
 
 1263  0
                 parameter.add( expression() );
 1264   
             }
 1265   
 
 1266   
             //
 1267   
             // Check if we are done.
 1268   
 
 1269  0
             if( lt() == Types.COMMA )
 1270   
             {
 1271  0
                 consume( Types.COMMA );
 1272   
             }
 1273   
             else
 1274   
             {
 1275  0
                 break;
 1276   
             }
 1277   
         }
 1278   
 
 1279  0
         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  0
     protected Reduction parameterDeclaration() throws SyntaxException, CompilationFailedException
 1299   
     {
 1300  0
         CSTNode   type      = optionalDatatype( false, false );
 1301  0
         Reduction parameter = nameDeclaration( false ).asReduction( type );
 1302  0
         parameter.setMeaning( Types.SYNTH_PARAMETER_DECLARATION );
 1303   
 
 1304  0
         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  0
     protected CSTNode datatype( boolean allowVoid ) throws SyntaxException, CompilationFailedException
 1330   
     {
 1331  0
         CSTNode datatype = scalarDatatype(allowVoid);
 1332   
 
 1333  0
         while( lt(true) == Types.LEFT_SQUARE_BRACKET )
 1334   
         {
 1335  0
             datatype = consume(Types.LEFT_SQUARE_BRACKET).asReduction( datatype );
 1336  0
             consume( Types.RIGHT_SQUARE_BRACKET );
 1337   
         }
 1338   
 
 1339  0
         return datatype;
 1340   
     }
 1341   
 
 1342   
 
 1343   
 
 1344   
    /**
 1345   
     *  A synonym for <code>datatype( true )</code>.
 1346   
     */
 1347   
 
 1348  0
     protected CSTNode datatype() throws SyntaxException, CompilationFailedException
 1349   
     {
 1350  0
         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  0
     protected CSTNode scalarDatatype( boolean allowVoid ) throws SyntaxException, CompilationFailedException
 1371   
     {
 1372  0
         CSTNode datatype = null;
 1373   
 
 1374  0
         if( la().isA(allowVoid ? Types.PRIMITIVE_TYPE : Types.CREATABLE_PRIMITIVE_TYPE) )
 1375   
         {
 1376  0
             datatype = consume();
 1377   
         }
 1378   
         else
 1379   
         {
 1380  0
             datatype = dottedIdentifier();
 1381   
         }
 1382   
 
 1383  0
         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  0
     protected CSTNode statementBody( boolean requireBraces ) throws SyntaxException, CompilationFailedException
 1407   
     {
 1408  0
         CSTNode body = null;
 1409   
 
 1410  0
         if (lt() == Types.LEFT_CURLY_BRACE)
 1411   
         {
 1412  0
             Token brace = consume( Types.LEFT_CURLY_BRACE );
 1413  0
             brace.setMeaning( Types.SYNTH_BLOCK );
 1414   
 
 1415  0
             body = statementsUntilRightCurly();
 1416  0
             body.set( 0, brace );
 1417   
 
 1418  0
             consume( Types.RIGHT_CURLY_BRACE );
 1419   
         }
 1420   
         else
 1421   
         {
 1422  0
             if( requireBraces )
 1423   
             {
 1424  0
                 error( Types.LEFT_CURLY_BRACE );
 1425   
             }
 1426   
             else
 1427   
             {
 1428  0
                body = statement();
 1429   
             }
 1430   
         }
 1431   
 
 1432  0
         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  0
     protected Reduction statementsUntilRightCurly( ) throws SyntaxException, CompilationFailedException
 1450   
     {
 1451  0
         Reduction block = Reduction.newContainer();
 1452   
 
 1453  0
         while( lt() != Types.EOF && lt() != Types.RIGHT_CURLY_BRACE )
 1454   
         {
 1455  0
             try
 1456   
             {
 1457  0
                 block.add( statement() );
 1458   
             }
 1459   
             catch( SyntaxException e )
 1460   
             {
 1461  0
                 controller.addError( e );
 1462  0
                 recover();
 1463   
             }
 1464   
         }
 1465   
 
 1466   
 
 1467  0
         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  0
     protected CSTNode statement( boolean allowUnlabelledBlocks ) throws SyntaxException, CompilationFailedException
 1536   
     {
 1537  0
         CSTNode statement = null;
 1538   
 
 1539   
         //
 1540   
         // Check for and grab any label for the statement
 1541   
 
 1542  0
         CSTNode label = null;
 1543  0
         if( lt() == Types.IDENTIFIER && lt(2) == Types.COLON )
 1544   
         {
 1545  0
             label = consume( Types.IDENTIFIER ).asReduction();
 1546  0
             label.setMeaning( Types.SYNTH_LABEL );
 1547   
 
 1548  0
             consume( Types.COLON );
 1549   
         }
 1550   
 
 1551   
         //
 1552   
         // Process the statement
 1553   
 
 1554  0
         switch( lt() )
 1555   
         {
 1556   
             case Types.KEYWORD_ASSERT:
 1557   
             {
 1558  0
                 statement = assertStatement();
 1559  0
                 break;
 1560   
             }
 1561   
 
 1562   
             case Types.KEYWORD_BREAK:
 1563   
             {
 1564  0
                 statement = breakStatement();
 1565  0
                 break;
 1566   
             }
 1567   
 
 1568   
             case Types.KEYWORD_CONTINUE:
 1569   
             {
 1570  0
                 statement = continueStatement();
 1571  0
                 break;
 1572   
             }
 1573   
 
 1574   
             case Types.KEYWORD_IF:
 1575   
             {
 1576  0
                 statement = ifStatement();
 1577  0
                 break;
 1578   
             }
 1579   
 
 1580   
             case Types.KEYWORD_RETURN:
 1581   
             {
 1582  0
                 statement = returnStatement();
 1583  0
                 break;
 1584   
             }
 1585   
 
 1586   
             case Types.KEYWORD_SWITCH:
 1587   
             {
 1588  0
                 statement = switchStatement();
 1589  0
                 break;
 1590   
             }
 1591   
 
 1592   
             case Types.KEYWORD_SYNCHRONIZED:
 1593   
             {
 1594  0
                 statement = synchronizedStatement();
 1595  0
                 break;
 1596   
             }
 1597   
 
 1598   
             case Types.KEYWORD_THROW:
 1599   
             {
 1600  0
                 statement = throwStatement();
 1601  0
                 break;
 1602   
             }
 1603   
 
 1604   
             case Types.KEYWORD_TRY:
 1605   
             {
 1606  0
                 statement = tryStatement();
 1607  0
                 break;
 1608   
             }
 1609   
 
 1610   
             case Types.KEYWORD_FOR:
 1611   
             {
 1612  0
                 statement = forStatement();
 1613  0
                 break;
 1614   
             }
 1615   
 
 1616   
             case Types.KEYWORD_DO:
 1617   
             {
 1618  0
                 statement = doWhileStatement();
 1619  0
                 break;
 1620   
             }
 1621   
 
 1622   
             case Types.KEYWORD_WHILE:
 1623   
             {
 1624  0
                 statement = whileStatement();
 1625  0
                 break;
 1626   
             }
 1627   
 
 1628   
             case Types.SEMICOLON:
 1629   
             {
 1630  0
                 statement = consume().asReduction();
 1631  0
                 statement.setMeaning( Types.SYNTH_BLOCK );
 1632  0
                 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  0
                 statement = expression();
 1646  0
                 if( statement.isA(Types.SYNTH_CLOSURE) )
 1647   
                 {
 1648  0
                     if( !statement.get(1).hasChildren() )
 1649   
                     {
 1650  0
                         Reduction block = statement.getRoot().asReduction();
 1651  0
                         block.setMeaning( Types.SYNTH_BLOCK );
 1652  0
                         block.addChildrenOf( statement.get(2) );
 1653   
 
 1654  0
                         if( label == null && !allowUnlabelledBlocks )
 1655   
                         {
 1656  0
                             controller.addError( "groovy does not support anonymous blocks; please add a label", statement.getRoot() );
 1657   
                         }
 1658   
 
 1659  0
                         statement = block;
 1660   
                     }
 1661   
                 }
 1662   
                 else
 1663   
                 {
 1664   
                    //
 1665   
                    // It's a closure expression, and must be a statement
 1666   
 
 1667  0
                    endOfStatement();
 1668   
                 }
 1669   
 
 1670  0
                 break;
 1671   
             }
 1672   
 
 1673   
             default:
 1674   
             {
 1675  0
                 try
 1676   
                 {
 1677  0
                     statement = expression();
 1678  0
                     endOfStatement();
 1679   
                 }
 1680   
                 catch (SyntaxException e)
 1681   
                 {
 1682  0
                     controller.addError(e);
 1683  0
                     recover();
 1684   
                 }
 1685   
             }
 1686   
         }
 1687   
 
 1688   
 
 1689   
         //
 1690   
         // Wrap the statement in the label, if necessary.
 1691   
 
 1692  0
         if( label != null )
 1693   
         {
 1694  0
             label.add( statement );
 1695  0
             statement = label;
 1696   
         }
 1697   
 
 1698  0
         return statement;
 1699   
     }
 1700   
 
 1701   
 
 1702   
 
 1703   
    /**
 1704   
     *  Synonym for <code>statement( false )</code>.
 1705   
     */
 1706   
 
 1707  0
     protected CSTNode statement( ) throws SyntaxException, CompilationFailedException
 1708   
     {
 1709  0
         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  0
     protected Reduction assertStatement() throws SyntaxException, CompilationFailedException
 1729   
     {
 1730  0
         Reduction statement = consume( Types.KEYWORD_ASSERT ).asReduction( expression() );
 1731   
 
 1732  0
         if( lt() == Types.COLON )
 1733   
         {
 1734  0
             consume( Types.COLON );
 1735  0
             statement.add( expression() );
 1736   
         }
 1737   
 
 1738  0
         endOfStatement();
 1739   
 
 1740  0
         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  0
     protected Reduction breakStatement() throws SyntaxException, CompilationFailedException
 1761   
     {
 1762  0
         Reduction statement = consume(Types.KEYWORD_BREAK).asReduction();
 1763  0
         if( lt(true) == Types.IDENTIFIER )
 1764   
         {
 1765  0
             statement.add( consume() );
 1766   
         }
 1767   
 
 1768  0
         endOfStatement();
 1769  0
         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  0
     protected Reduction continueStatement() throws SyntaxException, CompilationFailedException
 1791   
     {
 1792  0
         Reduction statement = consume(Types.KEYWORD_CONTINUE).asReduction();
 1793  0
         if( lt(true) == Types.IDENTIFIER )
 1794   
         {
 1795  0
             statement.add( consume() );
 1796   
         }
 1797   
 
 1798  0
         endOfStatement();
 1799  0
         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  0
     protected Reduction throwStatement() throws SyntaxException, CompilationFailedException
 1820   
     {
 1821  0
         Reduction statement = consume(Types.KEYWORD_THROW).asReduction( expression() );
 1822  0
         endOfStatement();
 1823  0
         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  0
     protected Reduction ifStatement() throws SyntaxException, CompilationFailedException
 1850   
     {
 1851   
         //
 1852   
         // Process the if clause
 1853   
 
 1854  0
         Reduction statement = consume(Types.KEYWORD_IF).asReduction();
 1855   
 
 1856  0
         consume( Types.LEFT_PARENTHESIS );
 1857   
 
 1858  0
         try
 1859   
         {
 1860  0
             statement.add( expression() );
 1861   
         }
 1862   
         catch( SyntaxException e )
 1863   
         {
 1864  0
             controller.addError( e );
 1865  0
             recover( Types.RIGHT_PARENTHESIS );
 1866   
         }
 1867   
 
 1868  0
         consume( Types.RIGHT_PARENTHESIS );
 1869   
 
 1870  0
         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  0
         if( lt() == Types.KEYWORD_ELSE )
 1879   
         {
 1880  0
             if( lt(2) == Types.KEYWORD_IF )
 1881   
             {
 1882  0
                 consume( Types.KEYWORD_ELSE );
 1883  0
                 statement.add( ifStatement() );
 1884   
             }
 1885   
             else
 1886   
             {
 1887  0
                 Reduction last = (Reduction)statement.add( consume(Types.KEYWORD_ELSE).asReduction() );
 1888  0
                 last.add( statementBody(false) );
 1889   
             }
 1890   
         }
 1891   
 
 1892  0
         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  0
     protected Reduction returnStatement() throws SyntaxException, CompilationFailedException
 1913   
     {
 1914  0
         Reduction statement = consume(Types.KEYWORD_RETURN).asReduction();
 1915   
 
 1916  0
         if( !la(true).isA(Types.ANY_END_OF_STATEMENT) )
 1917   
         {
 1918  0
             statement.add( expression() );
 1919   
         }
 1920   
 
 1921  0
         endOfStatement();
 1922  0
         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  0
     protected Reduction switchStatement() throws SyntaxException, CompilationFailedException
 1949   
     {
 1950  0
         Reduction statement = consume(Types.KEYWORD_SWITCH).asReduction();
 1951  0
         consume( Types.LEFT_PARENTHESIS );
 1952  0
         statement.add( expression() );
 1953  0
         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  0
         consume( Types.LEFT_CURLY_BRACE );
 1960   
 
 1961  0
         boolean defaultFound = false;
 1962  0
         while( lt() == Types.KEYWORD_CASE || lt() == Types.KEYWORD_DEFAULT )
 1963   
         {
 1964   
             //
 1965   
             // Read the label
 1966   
 
 1967  0
             Reduction caseBlock = null;
 1968  0
             if( lt() == Types.KEYWORD_CASE )
 1969   
             {
 1970  0
                 caseBlock = consume( Types.KEYWORD_CASE ).asReduction( expression() );
 1971   
             }
 1972  0
             else if( lt() == Types.KEYWORD_DEFAULT )
 1973   
             {
 1974  0
                 if( defaultFound )
 1975   
                 {
 1976  0
                     controller.addError( "duplicate default entry in switch", la() );
 1977   
                 }
 1978   
 
 1979  0
                 caseBlock = consume( Types.KEYWORD_DEFAULT ).asReduction();
 1980  0
                 defaultFound = true;
 1981   
             }
 1982   
             else
 1983   
             {
 1984  0
                 error( new int[] { Types.KEYWORD_DEFAULT, Types.KEYWORD_CASE } );
 1985  0
                 recover( Types.SWITCH_ENTRIES );
 1986   
             }
 1987   
 
 1988  0
             consume( Types.COLON );
 1989   
 
 1990   
 
 1991   
             //
 1992   
             // Process the statements, if any
 1993   
 
 1994  0
             boolean first = true;
 1995  0
             while( !la().isA(Types.SWITCH_BLOCK_TERMINATORS) )
 1996   
             {
 1997  0
                 caseBlock.add( statement(first) );
 1998  0
                 first = false;
 1999   
             }
 2000   
 
 2001  0
             statement.add( caseBlock );
 2002   
         }
 2003   
 
 2004  0
         consume( Types.RIGHT_CURLY_BRACE );
 2005   
 
 2006  0
         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  0
     protected Reduction synchronizedStatement() throws SyntaxException, CompilationFailedException
 2027   
     {
 2028  0
         Reduction statement = consume(Types.KEYWORD_SYNCHRONIZED).asReduction();
 2029   
 
 2030  0
         consume( Types.LEFT_PARENTHESIS );
 2031  0
         statement.add( expression() );
 2032  0
         consume( Types.RIGHT_PARENTHESIS );
 2033   
 
 2034  0
         statement.add( statementBody(true) );
 2035   
 
 2036  0
         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  0
     protected Reduction tryStatement() throws SyntaxException, CompilationFailedException
 2068   
     {
 2069   
 
 2070   
         //
 2071   
         // Set up the statement with the try clause
 2072   
 
 2073  0
         Reduction statement = consume(Types.KEYWORD_TRY).asReduction();
 2074  0
         statement.add( statementBody(true) );
 2075   
 
 2076   
 
 2077   
         //
 2078   
         // Process the catch clauses
 2079   
 
 2080  0
         Reduction catches = (Reduction)statement.add( Reduction.newContainer() );
 2081  0
         while( lt() == Types.KEYWORD_CATCH )
 2082   
         {
 2083  0
             try
 2084   
             {
 2085  0
                 Reduction catchBlock = (Reduction)catches.add( consume(Types.KEYWORD_CATCH).asReduction() );
 2086   
 
 2087  0
                 consume( Types.LEFT_PARENTHESIS );
 2088  0
                 try
 2089   
                 {
 2090  0
                     catchBlock.add( datatype(false) );
 2091  0
                     catchBlock.add( nameDeclaration(false) );
 2092   
                 }
 2093   
                 catch( SyntaxException e )
 2094   
                 {
 2095  0
                     controller.addError( e );
 2096  0
                     recover( Types.RIGHT_PARENTHESIS );
 2097   
                 }
 2098  0
                 consume( Types.RIGHT_PARENTHESIS );
 2099   
 
 2100  0
                 catchBlock.add( statementBody(true) );
 2101   
             }
 2102   
             catch( SyntaxException e )
 2103   
             {
 2104  0
                 controller.addError( e );
 2105  0
                 recover();
 2106   
             }
 2107   
         }
 2108   
 
 2109   
         //
 2110   
         // Process the finally clause, if available.
 2111   
 
 2112  0
         if( lt() == Types.KEYWORD_FINALLY )
 2113   
         {
 2114  0
             consume( Types.KEYWORD_FINALLY );
 2115  0
             statement.add( statementBody(true) );
 2116   
         }
 2117   
         else
 2118   
         {
 2119  0
             statement.add( Reduction.EMPTY );
 2120   
         }
 2121   
 
 2122  0
         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  0
     protected Reduction forStatement() throws SyntaxException, CompilationFailedException
 2161   
     {
 2162  0
         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  0
         consume( Types.LEFT_PARENTHESIS );
 2176   
 
 2177  0
         getTokenStream().checkpoint();
 2178   
 
 2179  0
         Reduction header   = null;
 2180  0
         CSTNode   datatype = optionalDatatype( false, false );
 2181   
 
 2182  0
         if( lt(2) == Types.KEYWORD_IN || lt(2) == Types.COLON )
 2183   
         {
 2184  0
             Token name = nameDeclaration( false );
 2185  0
             header = consume().asReduction( datatype, name, expression() );
 2186   
         }
 2187   
         else
 2188   
         {
 2189  0
             getTokenStream().restore();
 2190  0
             header = Reduction.newContainer();
 2191   
 
 2192  0
             Reduction init = Reduction.newContainer();
 2193  0
             while( lt() != Types.SEMICOLON && lt() != Types.EOF )
 2194   
             {
 2195  0
                 init.add( expression() );
 2196   
 
 2197  0
                 if( lt() != Types.SEMICOLON )
 2198   
                 {
 2199  0
                     consume( Types.COMMA );
 2200   
                 }
 2201   
             }
 2202   
 
 2203  0
             consume( Types.SEMICOLON );
 2204   
 
 2205  0
             header.add( init );
 2206   
 
 2207   
 
 2208   
             //
 2209   
             // Next up, a single expression is the test clause, followed
 2210   
             // by a semicolon.
 2211   
 
 2212  0
             header.add( expression() );
 2213  0
             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  0
             Reduction incr = (Reduction)header.add( Reduction.newContainer() );
 2221   
 
 2222  0
             while( lt() != Types.RIGHT_PARENTHESIS && lt() != Types.EOF )
 2223   
             {
 2224  0
                 incr.add( expression() );
 2225   
 
 2226  0
                 if( lt() != Types.RIGHT_PARENTHESIS )
 2227   
                 {
 2228  0
                     consume( Types.COMMA );
 2229   
                 }
 2230   
             }
 2231   
         }
 2232   
 
 2233  0
         consume( Types.RIGHT_PARENTHESIS );
 2234   
 
 2235  0
         statement.add( header );
 2236  0
         statement.add( statementBody(false) );
 2237   
 
 2238  0
         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  0
     protected Reduction doWhileStatement() throws SyntaxException, CompilationFailedException
 2259   
     {
 2260  0
         Reduction statement = consume(Types.KEYWORD_DO).asReduction();
 2261  0
         statement.add( statementBody(false) );
 2262  0
         consume( Types.KEYWORD_WHILE );
 2263   
 
 2264  0
         consume( Types.LEFT_PARENTHESIS );
 2265  0
         try
 2266   
         {
 2267  0
             statement.add( expression() );
 2268   
         }
 2269   
         catch( SyntaxException e )
 2270   
         {
 2271  0
             controller.addError( e );
 2272  0
             recover( Types.RIGHT_PARENTHESIS );
 2273   
         }
 2274  0
         consume( Types.RIGHT_PARENTHESIS );
 2275   
 
 2276  0
         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  0
     protected Reduction whileStatement() throws SyntaxException, CompilationFailedException
 2298   
     {
 2299  0
         Reduction statement = consume(Types.KEYWORD_WHILE).asReduction();
 2300   
 
 2301  0
         consume( Types.LEFT_PARENTHESIS );
 2302   
 
 2303  0
         try
 2304   
         {
 2305  0
             statement.add( expression() );
 2306   
         }
 2307   
         catch( SyntaxException e )
 2308   
         {
 2309  0
             controller.addError( e );
 2310  0
             recover( Types.RIGHT_PARENTHESIS );
 2311   
         }
 2312  0
         consume( Types.RIGHT_PARENTHESIS );
 2313   
 
 2314  0
         statement.add( statementBody(false) );
 2315  0
         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  0
     protected CSTNode expression( ) throws SyntaxException, CompilationFailedException
 2341   
     {
 2342   
         // int id = nestCount++;
 2343   
         // System.out.println( "ENTERING EXPRESSION " + id );
 2344   
 
 2345  0
         ExpressionStack stack = new ExpressionStack( this );
 2346  0
         CSTNode expression = null;
 2347   
 
 2348  0
         boolean bareMode = false;
 2349   
 
 2350  0
         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  0
             Token next = la(stack);
 2363  0
             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  0
             SHIFT: switch( type )
 2372   
             {
 2373   
                 case Types.GSTRING_START:
 2374   
                 {
 2375  0
                     if( stack.topIsAnExpression() )
 2376   
                     {
 2377  0
                         error( "gstring cannot directly follow another expression" );
 2378   
                     }
 2379   
 
 2380  0
                     stack.push( gstring() );
 2381  0
                     break;
 2382   
                 }
 2383   
 
 2384   
 
 2385   
                 case Types.CREATABLE_PRIMITIVE_TYPE:
 2386   
                 {
 2387  0
                     stack.shiftIf( stack.atStartOfExpression(), "type name not valid in this context" );
 2388  0
                     break;
 2389   
                 }
 2390   
 
 2391   
 
 2392   
                 case Types.SIMPLE_EXPRESSION:
 2393   
                 {
 2394   
 
 2395   
                     //
 2396   
                     // Method parameters don't make it here (see REDUCE)...
 2397   
 
 2398  0
                     stack.shiftUnlessTopIsAnExpression( "literal cannot directly follow another expression" );
 2399  0
                     break;
 2400   
                 }
 2401   
 
 2402   
 
 2403   
                 case Types.KEYWORD_IDENTIFIER:
 2404   
                 {
 2405  0
                     if( stack.top().isA(Types.DEREFERENCE_OPERATOR) && stack.topIsAnOperator() )
 2406   
                     {
 2407  0
                         la().setMeaning( Types.IDENTIFIER );
 2408  0
                         stack.shift();
 2409   
                     }
 2410   
                     else
 2411   
                     {
 2412  0
                         error( "not valid as an identifier in this context" );
 2413   
                     }
 2414  0
                     break;
 2415   
                 }
 2416   
 
 2417   
 
 2418   
                 case Types.ASSIGNMENT_OPERATOR:
 2419   
                 {
 2420  0
                     stack.shiftIf( stack.topIsAModifiableExpression(), "left-hand-side of assignment must be modifiable" );
 2421  0
                     break;
 2422   
                 }
 2423   
 
 2424   
 
 2425   
                 case Types.PREFIX_OR_INFIX_OPERATOR:
 2426   
                 {
 2427  0
                     if( stack.topIsAnOperator(0, true) )
 2428   
                     {
 2429  0
                         Types.makePrefix( next, false );
 2430   
                     }
 2431  0
                     stack.shift( );
 2432  0
                     break;
 2433   
                 }
 2434   
 
 2435   
 
 2436   
                 case Types.PREFIX_OPERATOR:
 2437   
                 {
 2438  0
                     Types.makePrefix( next, false );
 2439  0
                     stack.shift( );
 2440  0
                     break;
 2441   
                 }
 2442   
 
 2443   
 
 2444   
                 case Types.QUESTION:
 2445   
                 case Types.INFIX_OPERATOR:
 2446   
                 {
 2447  0
                     stack.shiftIfTopIsAnExpression( "infix operators may only follow expressions" );
 2448  0
                     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  0
                     boolean condition = stack.atStartOfExpression() || (stack.topIsAnOperator() && !stack.top().isA(Types.DEREFERENCE_OPERATOR));
 2459  0
                     stack.shiftIf( condition, "sub-expression not valid at this position" );
 2460  0
                     break;
 2461   
                 }
 2462   
 
 2463   
 
 2464   
 
 2465   
                 case Types.LEFT_CURLY_BRACE:
 2466   
                 {
 2467  0
                     if( stack.atStartOfExpression() || stack.topIsAnOperator() || stack.top().isA(Types.SYNTH_METHOD_CALL) )
 2468   
                     {
 2469  0
                         stack.push( closureExpression() );
 2470   
                     }
 2471   
                     else
 2472   
                     {
 2473  0
                         error( "closure not valid in this context" );
 2474   
                     }
 2475  0
                     break;
 2476   
                 }
 2477   
 
 2478   
 
 2479   
                 case Types.LEFT_SQUARE_BRACKET:
 2480   
                 {
 2481  0
                     boolean isMap = false, insist = false;
 2482  0
                     if( stack.topIsAnExpression() )
 2483   
                     {
 2484  0
                         insist = true;
 2485   
                     }
 2486  0
                     stack.push( listOrMapExpression(isMap, insist) );
 2487  0
                     break;
 2488   
                 }
 2489   
 
 2490   
 
 2491   
                 case Types.KEYWORD_NEW:
 2492   
                 {
 2493  0
                     if( stack.atStartOfExpression() || stack.topIsAnOperator() )
 2494   
                     {
 2495  0
                         stack.push( newExpression() );
 2496   
                     }
 2497   
                     else
 2498   
                     {
 2499  0
                         error( "new can follow the start of an expression or another operator" );
 2500   
                     }
 2501  0
                     break;
 2502   
                 }
 2503   
 
 2504   
 
 2505   
                 case Types.KEYWORD_INSTANCEOF:
 2506   
                 {
 2507  0
                     stack.shiftIf( stack.topIsAnExpression(), "instanceof may only follow an expression" );
 2508  0
                     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  0
                     if( stack.size() == 1 && stack.topIsAnExpression() )
 2520   
                     {
 2521  0
                         break MAIN_LOOP;                          // <<< FLOW CONTROL <<<<<<<<<
 2522   
                     }
 2523   
                     else
 2524   
                     {
 2525  0
                         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  0
             boolean checkAgain = false, skipPatterns = false;
 2541  0
             CSTNode top0 = null, top1 = null, top2 = null;
 2542  0
             int nextPrecedence = 0, top1Precedence = 0;
 2543   
 
 2544  0
             REDUCE: do
 2545   
             {
 2546  0
                 if( !stack.topIsAnExpression() && !ExpressionSupport.isAPotentialTypeName(stack.top(), false) )
 2547   
                 {
 2548  0
                     break;
 2549   
                 }
 2550   
 
 2551   
 
 2552   
                 //
 2553   
                 // We reduce at most once per iteration, so we collect info here.
 2554   
 
 2555  0
                 checkAgain   = false;
 2556  0
                 skipPatterns = false;
 2557   
 
 2558  0
                 top0 = stack.top();
 2559  0
                 top1 = stack.top(1);
 2560  0
                 top2 = stack.top(2);
 2561   
 
 2562  0
                 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  0
                 nextPrecedence = Types.getPrecedence( next.getMeaning(), false );
 2568  0
                 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  0
                 if( top1.isA(Types.LEFT_PARENTHESIS) )
 2582   
                 {
 2583  0
                     if( next.isA(Types.RIGHT_PARENTHESIS) )
 2584   
                     {
 2585  0
                         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  0
                         next = la(true); // XXX the precludes is true for GString. Seems wrong
 2594  0
                         boolean castPrecluded = next.isA(Types.NEWLINE) || next.isA(Types.PRECLUDES_CAST_OPERATOR);
 2595   
 
 2596  0
                         if( ExpressionSupport.isAPotentialTypeName(top0, false) && !castPrecluded )
 2597   
                         {
 2598  0
                             CSTNode   name = stack.pop();
 2599  0
                             Reduction cast = ((Token)stack.pop()).asReduction( name );
 2600  0
                             cast.setMeaning( Types.SYNTH_CAST );
 2601  0
                             stack.push( cast );
 2602   
                         }
 2603   
                         else
 2604   
                         {
 2605  0
                             CSTNode subexpression = stack.pop();
 2606  0
                             stack.pop();
 2607  0
                             stack.push( subexpression );
 2608   
                         }
 2609   
 
 2610  0
                         checkAgain = true;
 2611  0
                         continue;                             // <<< LOOP CONTROL <<<<<<<<<
 2612   
                     }
 2613   
                     else
 2614   
                     {
 2615  0
                         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  0
                 if( top0.isA(Types.KEYWORD_NEW) && !top0.isAnExpression() )
 2629   
                 {
 2630  0
                     top0.markAsExpression();
 2631   
 
 2632  0
                     if( top1.isA(Types.DOT) )
 2633   
                     {
 2634  0
                         CSTNode theNew  = stack.pop();
 2635  0
                         CSTNode theDot  = stack.pop();
 2636  0
                         CSTNode context = stack.pop();
 2637   
 
 2638  0
                         theNew.set( 1, context );
 2639  0
                         stack.push( theNew );
 2640   
 
 2641  0
                         checkAgain = true;
 2642  0
                         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  0
                 if( top1.isA(Types.DEREFERENCE_OPERATOR) && !top0.hasChildren() )
 2652   
                 {
 2653  0
                     stack.reduce( 3, 1, true );
 2654   
 
 2655  0
                     checkAgain = true;
 2656  0
                     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  0
                 if( top0.isA(Types.SYNTH_LIST) && top1.isAnExpression() || ExpressionSupport.isAPotentialTypeName(top1, false) )
 2669   
                 {
 2670   
                     //
 2671   
                     // Empty list is an array type
 2672   
 
 2673  0
                     if( !top0.hasChildren() )
 2674   
                     {
 2675  0
                         boolean typePreceeds   = ExpressionSupport.isAPotentialTypeName(top1, false);
 2676  0
                         boolean potentialCast  = top2.isA(Types.LEFT_PARENTHESIS);
 2677  0
                         boolean potentialDecl  = top2.isA(Types.LEFT_PARENTHESIS) || top2.isA(Types.UNKNOWN);
 2678  0
                         boolean classReference = next.isA(Types.DOT) && la(2).isA(Types.KEYWORD_CLASS);
 2679  0
                         if( !(typePreceeds && (potentialCast || potentialDecl || classReference)) )
 2680   
                         {
 2681  0
                             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  0
                         Reduction array = stack.pop().asReduction();
 2690  0
                         array.setMeaning( Types.LEFT_SQUARE_BRACKET );
 2691  0
                         array.add( stack.pop() );
 2692   
 
 2693  0
                         while( lt(true) == Types.LEFT_SQUARE_BRACKET )
 2694   
                         {
 2695  0
                             array = consume( Types.LEFT_SQUARE_BRACKET ).asReduction( array );
 2696  0
                             consume( Types.RIGHT_SQUARE_BRACKET );
 2697   
                         }
 2698   
 
 2699   
 
 2700   
                         //
 2701   
                         // One last decision: variable type declaration, or
 2702   
                         // cast, or class reference...
 2703   
 
 2704  0
                         if( classReference )
 2705   
                         {
 2706  0
                             CSTNode reference = consume(Types.DOT).asReduction(array, consume(Types.KEYWORD_CLASS));
 2707  0
                             reference.markAsExpression();
 2708  0
                             stack.push( reference );
 2709   
 
 2710   
                         }
 2711  0
                         else if( lt(true) == Types.IDENTIFIER && lt(2) == Types.EQUAL )
 2712   
                         {
 2713  0
                             stack.push( variableDeclarationExpression(array) );
 2714   
                         }
 2715  0
                         else if( stack.top().isA(Types.LEFT_PARENTHESIS) && la(true).isA(Types.RIGHT_PARENTHESIS) )
 2716   
                         {
 2717  0
                             CSTNode cast = ((Token)stack.pop()).asReduction( array );
 2718  0
                             cast.setMeaning( Types.SYNTH_CAST );
 2719  0
                             stack.push( cast );
 2720  0
                             consume( Types.RIGHT_PARENTHESIS );
 2721   
                         }
 2722   
                         else
 2723   
                         {
 2724  0
                             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  0
                         CSTNode list = stack.pop();
 2735  0
                         CSTNode base = stack.pop();
 2736   
 
 2737  0
                         Reduction result = ((Token)list.get(0)).dup().asReduction();
 2738  0
                         result.setMeaning( Types.LEFT_SQUARE_BRACKET );
 2739  0
                         result.add( base );
 2740   
 
 2741  0
                         if( list.children() == 1 )
 2742   
                         {
 2743  0
                             result.add( list.get(1) );
 2744   
                         }
 2745   
                         else
 2746   
                         {
 2747  0
                             result.add( list );
 2748   
                         }
 2749   
 
 2750  0
                         result.markAsExpression();
 2751  0
                         stack.push( result );
 2752   
                     }
 2753   
 
 2754  0
                     checkAgain = true;
 2755  0
                     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  0
                 if( la(true).isA(Types.IDENTIFIER) && lt(2) == Types.EQUALS && ExpressionSupport.isAPotentialTypeName(top0, false) )
 2767   
                 {
 2768  0
                     stack.push( variableDeclarationExpression(stack.pop()) );
 2769   
 
 2770  0
                     checkAgain = true;
 2771  0
                     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  0
                 if( top1.isA(Types.SYNTH_METHOD_CALL) && top0.isA(Types.SYNTH_CLOSURE) )
 2782   
                 {
 2783  0
                     CSTNode parameters = top1.get(2);
 2784   
 
 2785  0
                     int last = parameters.size() - 1;
 2786  0
                     if( last > 0 && parameters.get(last).isA(Types.SYNTH_CLOSURE) )
 2787   
                     {
 2788  0
                         error( "you may only pass one closure to a method implicitly" );
 2789   
                     }
 2790   
 
 2791  0
                     parameters.add( stack.pop() );
 2792   
 
 2793  0
                     checkAgain = true;
 2794  0
                     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  0
                 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  0
                     CSTNode name = stack.pop();
 2808   
 
 2809  0
                     Reduction method = null;
 2810  0
                     switch( next.getMeaning() )
 2811   
                     {
 2812   
                         case Types.LEFT_PARENTHESIS:
 2813  0
                             method = consume().asReduction();
 2814  0
                             method.add( name );
 2815  0
                             method.add( la().isA(Types.RIGHT_PARENTHESIS) ? Reduction.newContainer() : parameterList() );
 2816  0
                             consume( Types.RIGHT_PARENTHESIS );
 2817  0
                             break;
 2818   
 
 2819   
                         case Types.LEFT_CURLY_BRACE:
 2820  0
                             method = Token.newSymbol( Types.LEFT_PARENTHESIS, next.getStartLine(), next.getStartColumn() ).asReduction();
 2821  0
                             method.add( name );
 2822  0
                             method.add( Reduction.newContainer() );
 2823  0
                             break;
 2824   
 
 2825   
                         default:
 2826  0
                             method = Token.newSymbol( Types.LEFT_PARENTHESIS, next.getStartLine(), next.getStartColumn() ).asReduction();
 2827  0
                             method.add( name );
 2828  0
                             method.add( parameterList() );
 2829  0
                             break;
 2830   
                     }
 2831   
 
 2832  0
                     method.setMeaning( Types.SYNTH_METHOD_CALL );
 2833  0
                     method.markAsExpression();
 2834   
 
 2835  0
                     stack.push( method );
 2836   
 
 2837  0
                     if( lt() != Types.LEFT_CURLY_BRACE )
 2838   
                     {
 2839  0
                         checkAgain = true;
 2840   
                     }
 2841   
 
 2842  0
                     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  0
                 if( next.isA(Types.POSTFIX_OPERATOR) && stack.topIsAnExpression() )
 2852   
                 {
 2853  0
                     if( !ExpressionSupport.isAVariable(stack.top()) )
 2854   
                     {
 2855  0
                         error( "increment/decrement operators can only be applied to variables" );
 2856   
                     }
 2857   
 
 2858  0
                     Types.makePostfix( next, true );
 2859   
 
 2860  0
                     stack.shift();
 2861  0
                     stack.reduce( 2, 0, true );
 2862   
 
 2863  0
                     checkAgain = true;
 2864  0
                     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  0
                 if( top1.isA(Types.QUESTION) )
 2876   
                 {
 2877  0
                     boolean reduce = false;
 2878   
 
 2879  0
                     if( la().isA(Types.COLON) )
 2880   
                     {
 2881  0
                         if( top1.hasChildren() )
 2882   
                         {
 2883  0
                             error( "ternary operator can have only three clauses" );
 2884   
                         }
 2885   
 
 2886  0
                         consume();
 2887  0
                         stack.reduce( 3, 1, false );
 2888  0
                         checkAgain = true;
 2889   
                     }
 2890  0
                     else if( Types.getPrecedence(next.getMeaning(), false) < 10 )
 2891   
                     {
 2892  0
                         stack.reduce( 2, 1, false );
 2893  0
                         stack.top().setMeaning( Types.SYNTH_TERNARY );
 2894  0
                         checkAgain = true;
 2895   
                     }
 2896   
 
 2897   
 
 2898  0
                     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  0
                 if( skipPatterns || !ExpressionSupport.isAnOperator(top1, false) )
 2917   
                 {
 2918  0
                     break;                                    // <<< LOOP CONTROL <<<<<<<<<
 2919   
                 }
 2920   
 
 2921   
 
 2922  0
                 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  0
                         if( nextPrecedence < top1Precedence )
 2932   
                         {
 2933  0
                             if( !ExpressionSupport.isAVariable(stack.top()) )
 2934   
                             {
 2935  0
                                 error( "increment/decrement operators can only be applied to variables" );
 2936   
                             }
 2937   
 
 2938  0
                             stack.reduce( 2, 1, true );
 2939  0
                             checkAgain = true;
 2940   
                        }
 2941   
 
 2942  0
                        break;
 2943   
                     }
 2944   
 
 2945   
 
 2946   
                     //
 2947   
                     // All other prefix operators.  They are all right-associative.
 2948   
 
 2949   
                     case Types.PURE_PREFIX_OPERATOR:
 2950   
                     {
 2951  0
                         if( nextPrecedence < top1Precedence )
 2952   
                         {
 2953  0
                             stack.reduce( 2, 1, true );
 2954  0
                             checkAgain = true;
 2955   
                         }
 2956   
 
 2957  0
                         break;
 2958   
                     }
 2959   
 
 2960   
 
 2961   
                     //
 2962   
                     // Handle the assignment operators.  They are all right-associative.
 2963   
 
 2964   
                     case Types.ASSIGNMENT_OPERATOR:
 2965   
                     {
 2966  0
                         if( nextPrecedence < top1Precedence )
 2967   
                         {
 2968  0
                             stack.reduce( 3, 1, true );
 2969  0
                             checkAgain = true;
 2970   
                         }
 2971   
 
 2972  0
                         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  0
                         if( nextPrecedence < top1Precedence )
 2982   
                         {
 2983  0
                             if( !ExpressionSupport.isAPotentialTypeName(top0, false) )
 2984   
                             {
 2985  0
                                 error( "instanceof right-hand side must be a valid type name" );
 2986   
                             }
 2987   
 
 2988  0
                             stack.reduce( 3, 1, true );
 2989  0
                             checkAgain = true;
 2990   
                         }
 2991   
 
 2992  0
                         break;
 2993   
                     }
 2994   
 
 2995   
 
 2996   
                     //
 2997   
                     // Handle all other infix operators.  They are all left-associative.
 2998   
 
 2999   
                     case Types.INFIX_OPERATOR:
 3000   
                     {
 3001  0
                         if( nextPrecedence <= top1Precedence )
 3002   
                         {
 3003  0
                             stack.reduce( 3, 1, true );
 3004  0
                             checkAgain = true;
 3005   
                         }
 3006   
 
 3007  0
                         break;
 3008   
                     }
 3009   
 
 3010   
 
 3011   
                     //
 3012   
                     // Anything else in top1 is an bug.
 3013   
 
 3014   
                     default:
 3015   
                     {
 3016  0
                         throw new GroovyBugError( "found unexpected token during REDUCE [" + top1.getMeaning() + "]" );
 3017   
                     }
 3018   
                 }
 3019   
 
 3020  0
             } while( checkAgain );
 3021   
 
 3022   
         } while( true );
 3023   
 
 3024   
 
 3025  0
         if( stack.size() == 1 && stack.topIsAnExpression() )
 3026   
         {
 3027  0
             expression = stack.pop();
 3028   
         }
 3029   
         else
 3030   
         {
 3031  0
             error( "expression incomplete" );
 3032   
         }
 3033   
 
 3034   
 
 3035   
         // System.out.println( "EXITING EXPRESSION " + id );
 3036  0
         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  0
     protected Reduction variableDeclarationExpression( CSTNode datatype ) throws SyntaxException, CompilationFailedException
 3088   
     {
 3089  0
         Reduction expression = ((Token)datatype.get(0)).dup().asReduction( datatype );  // done for line number on SYNTH
 3090  0
         expression.setMeaning( Types.SYNTH_VARIABLE_DECLARATION );
 3091   
 
 3092  0
         boolean done = false;
 3093  0
         do
 3094   
         {
 3095  0
             try
 3096   
             {
 3097  0
                 Reduction declaration = (Reduction)expression.add( nameDeclaration(false).asReduction() );
 3098  0
                 consume( Types.EQUAL );
 3099  0
                 declaration.add( expression() );
 3100   
             }
 3101   
             catch( SyntaxException e )
 3102   
             {
 3103  0
                 controller.addError( e );
 3104  0
                 recover( Types.ANY_END_OF_STATEMENT );
 3105   
             }
 3106   
 
 3107  0
             if( lt() == Types.COMMA )
 3108   
             {
 3109  0
                 consume( Types.COMMA );
 3110   
             }
 3111   
             else
 3112   
             {
 3113  0
                 done = true;
 3114   
             }
 3115   
 
 3116  0
         } while( !done );
 3117   
 
 3118   
 
 3119  0
         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  0
     protected Reduction gstring() throws SyntaxException, CompilationFailedException
 3139   
     {
 3140   
         // int id = nestCount++;
 3141   
         // System.out.println( "ENTERING GSTRING " + id );
 3142   
 
 3143  0
         Reduction data = Reduction.newContainer();
 3144   
 
 3145  0
         consume( Types.GSTRING_START );
 3146   
 
 3147  0
         while( lt() != Types.GSTRING_END && lt() != Types.EOF )
 3148   
         {
 3149  0
             switch( lt() )
 3150   
             {
 3151   
                 case Types.STRING:
 3152  0
                     data.add( consume() );
 3153  0
                     break;
 3154   
 
 3155   
                 case Types.GSTRING_EXPRESSION_START:
 3156  0
                     consume();
 3157  0
                     data.add( expression() );
 3158  0
                     consume( Types.GSTRING_EXPRESSION_END );
 3159  0
                     break;
 3160   
 
 3161   
                 default:
 3162  0
                     throw new GroovyBugError( "gstring found invalid token: " + la() );
 3163   
             }
 3164   
         }
 3165   
 
 3166  0
         Reduction complete = consume( Types.GSTRING_END ).asReduction();
 3167  0
         complete.addChildrenOf( data );
 3168   
 
 3169  0
         complete.setMeaning( Types.SYNTH_GSTRING );
 3170   
 
 3171   
         // System.out.println( "EXITING GSTRING " + id );
 3172  0
         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  0
     protected Reduction parameterList() throws SyntaxException, CompilationFailedException
 3201   
     {
 3202   
         // int id = nestCount++;
 3203   
         // System.out.println( "ENTERING PARAMETER LIST " + id );
 3204   
 
 3205  0
         Reduction list  = Reduction.newContainer();
 3206  0
         Reduction named = null;
 3207   
 
 3208  0
         boolean done = false;
 3209   
 
 3210  0
         do
 3211   
         {
 3212  0
             if( la().canMean(Types.IDENTIFIER) && la(2).isA(Types.COLON) )
 3213   
             {
 3214  0
                 if( named == null )
 3215   
                 {
 3216  0
                     named = Token.newPlaceholder(Types.SYNTH_MAP).asReduction();
 3217  0
                     list.add( named );
 3218   
                 }
 3219   
 
 3220  0
                 Token name = nameReference(false);
 3221  0
                 name.setMeaning( Types.STRING );
 3222   
 
 3223  0
                 named.add( consume(Types.COLON).asReduction(name, expression()) );
 3224   
             }
 3225   
             else
 3226   
             {
 3227  0
                 list.add( expression() );
 3228   
             }
 3229   
 
 3230   
 
 3231  0
             if( lt() == Types.COMMA )
 3232   
             {
 3233  0
                 consume();
 3234   
             }
 3235   
             else
 3236   
             {
 3237  0
                 done = true;
 3238   
             }
 3239   
 
 3240   
 
 3241  0
         } while( !done );
 3242   
 
 3243   
         // System.out.println( "EXITING PARAMETER LIST " + id );
 3244  0
         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  0
     protected Reduction newExpression() throws SyntaxException, CompilationFailedException
 3274   
     {
 3275   
         // int id = nestCount++;
 3276   
         // System.out.println( "ENTERING NEW " + id );
 3277   
 
 3278  0
         Reduction expression = consume(Types.KEYWORD_NEW).asReduction();
 3279  0
         CSTNode   scalarType = scalarDatatype(false);
 3280   
 
 3281  0
         if( lt(true) == Types.LEFT_SQUARE_BRACKET )
 3282   
         {
 3283   
             //
 3284   
             // First up, figure out the actual type and any
 3285   
             // stated dimensions.
 3286   
 
 3287  0
             boolean   implicit   = (lt(2) == Types.RIGHT_SQUARE_BRACKET);
 3288  0
             Reduction dimensions = implicit ? Reduction.EMPTY : Reduction.newContainer();
 3289  0
             int       count      = 0;
 3290  0
             CSTNode   arrayType  = scalarType;
 3291   
 
 3292  0
             while( lt(true) == Types.LEFT_SQUARE_BRACKET )
 3293   
             {
 3294  0
                 arrayType = consume(Types.LEFT_SQUARE_BRACKET).asReduction( arrayType );
 3295  0
                 count++;
 3296   
 
 3297  0
                 if( !implicit )
 3298   
                 {
 3299  0
                     dimensions.add( expression() );
 3300   
                 }
 3301   
 
 3302  0
                 consume(Types.RIGHT_SQUARE_BRACKET);
 3303   
             }
 3304   
 
 3305  0
             expression.add( arrayType );
 3306  0
             expression.add( dimensions );
 3307   
 
 3308   
             //
 3309   
             // If implicit, there must be initialization data
 3310   
 
 3311  0
             if( implicit )
 3312   
             {
 3313  0
                 expression.add( tupleExpression(0, count) );
 3314   
             }
 3315   
 
 3316   
         }
 3317   
 
 3318   
         else
 3319   
         {
 3320  0
             expression.add( scalarType );
 3321   
 
 3322   
 
 3323   
             //
 3324   
             // Process the constructor call
 3325   
 
 3326  0
             Reduction parameters = null;
 3327   
 
 3328  0
             consume( Types.LEFT_PARENTHESIS );
 3329  0
             parameters = (lt() == Types.RIGHT_PARENTHESIS ? Reduction.newContainer() : parameterList());
 3330  0
             consume( Types.RIGHT_PARENTHESIS );
 3331   
 
 3332  0
             expression.add( parameters );
 3333   
 
 3334   
 
 3335   
             //
 3336   
             // If a "{" follows, it's a class body or a closure...
 3337   
 
 3338  0
             if( lt() == Types.LEFT_CURLY_BRACE )
 3339   
             {
 3340  0
                 if( lt(2) == Types.PIPE || lt(2) == Types.DOUBLE_PIPE )
 3341   
                 {
 3342  0
                     parameters.add( closureExpression() );
 3343   
                 }
 3344   
                 else
 3345   
                 {
 3346  0
                     expression.add( typeBody(true, false, false) );
 3347   
                 }
 3348   
             }
 3349   
         }
 3350   
 
 3351   
         // System.out.println( "EXITING NEW " + id );
 3352  0
         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  0
     protected Reduction tupleExpression( int level, int depth ) throws SyntaxException, CompilationFailedException
 3372   
     {
 3373  0
         Reduction data = consume(Types.LEFT_CURLY_BRACE).asReduction();
 3374  0
         data.setMeaning( Types.SYNTH_TUPLE );
 3375   
 
 3376  0
         if( lt() != Types.RIGHT_CURLY_BRACE )
 3377   
         {
 3378  0
             int    child = level + 1;
 3379  0
             boolean leaf = (child == depth);
 3380   
 
 3381  0
             do
 3382   
             {
 3383  0
                 data.add( leaf ? expression() : tupleExpression(child, depth) );
 3384   
 
 3385  0
             } while( lt() == Types.COMMA && (consume() != null) );
 3386   
         }
 3387   
 
 3388  0
         consume( Types.RIGHT_CURLY_BRACE );
 3389   
 
 3390  0
         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  0
     protected Reduction closureExpression( ) throws SyntaxException, CompilationFailedException
 3414   
     {
 3415   
         // int id = nestCount++;
 3416   
         // System.out.println( "ENTERING CLOSURE EXPRESSION " + id );
 3417   
 
 3418  0
         Reduction closure = consume(Types.LEFT_CURLY_BRACE).asReduction();
 3419  0
         closure.setMeaning( Types.SYNTH_CLOSURE );
 3420  0
         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  0
         if( !specified )
 3432   
         {
 3433  0
             getTokenStream().checkpoint();
 3434  0
             CSTNode type = optionalDatatype( true, false );
 3435  0
             if( lt() == Types.IDENTIFIER && (lt(2) == Types.PIPE || lt(2) == Types.COMMA) )
 3436   
             {
 3437  0
                 specified = true;
 3438   
             }
 3439   
 
 3440  0
             getTokenStream().restore();
 3441   
         }
 3442   
 
 3443   
 
 3444   
         //
 3445   
         // If the parameter list is specified, process it.
 3446   
 
 3447  0
         if( specified )
 3448   
         {
 3449  0
             if( lt() == Types.DOUBLE_PIPE )
 3450   
             {
 3451  0
                 consume( Types.DOUBLE_PIPE );
 3452  0
                 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  0
                 if( lt() == Types.PIPE )
 3461   
                 {
 3462  0
                     consume(Types.PIPE);
 3463   
                 }
 3464   
 
 3465  0
                 closure.add( parameterDeclarationList() );
 3466  0
                 consume(Types.PIPE);
 3467   
             }
 3468   
         }
 3469   
         else
 3470   
         {
 3471  0
             closure.add( Reduction.newContainer() );
 3472   
         }
 3473   
 
 3474   
 
 3475   
         //
 3476   
         // Finally, process the statements.
 3477   
 
 3478  0
         closure.add( statementsUntilRightCurly() );
 3479  0
         consume( Types.RIGHT_CURLY_BRACE );
 3480   
 
 3481   
         // System.out.println( "EXITING CLOSURE EXPRESSION " + id );
 3482  0
         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  0
     protected Reduction listOrMapExpression( boolean isMap, boolean insist ) throws SyntaxException, CompilationFailedException
 3509   
     {
 3510  0
         Reduction expression = consume(Types.LEFT_SQUARE_BRACKET).asReduction();
 3511  0
         expression.setMeaning( Types.SYNTH_LIST );
 3512   
 
 3513  0
         if( lt() == Types.COLON )
 3514   
         {
 3515  0
             if( !isMap && insist )
 3516   
             {
 3517  0
                 error( "expected list" );
 3518   
             }
 3519   
 
 3520  0
             isMap = true;
 3521  0
             expression.setMeaning( Types.SYNTH_MAP );
 3522  0
             consume();
 3523  0
             if( lt() != Types.RIGHT_SQUARE_BRACKET )
 3524   
             {
 3525  0
                 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  0
         boolean done = (lt() == Types.RIGHT_SQUARE_BRACKET);
 3536   
 
 3537  0
         while( !done )
 3538   
         {
 3539  0
             CSTNode element = expression();
 3540   
 
 3541  0
             if( !insist )
 3542   
             {
 3543  0
                 insist = true;
 3544  0
                 if( lt() == Types.COLON )
 3545   
                 {
 3546  0
                     isMap = true;
 3547  0
                     expression.setMeaning(Types.SYNTH_MAP);
 3548   
                 }
 3549   
             }
 3550   
 
 3551  0
             if( isMap )
 3552   
             {
 3553  0
                 element = consume(Types.COLON).asReduction( element, expression() );
 3554   
             }
 3555   
 
 3556  0
             expression.add( element );
 3557   
 
 3558  0
             if( lt() == Types.COMMA ) { consume(); } else { done = true; }
 3559   
         }
 3560   
 
 3561  0
         consume(Types.RIGHT_SQUARE_BRACKET);
 3562   
 
 3563  0
         return expression;
 3564   
     }
 3565   
 
 3566   
 
 3567   
 
 3568   
    /**
 3569   
     *  Synonym for <code>listOrMapExpression( false, false )</code>.
 3570   
     */
 3571   
 
 3572  0
     protected Reduction listOrMapExpression( ) throws SyntaxException, CompilationFailedException
 3573   
     {
 3574  0
         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  0
     protected UnexpectedTokenException error( Token found, int[] expectedTypes, boolean throwIt, String comment ) throws SyntaxException
 3591   
     {
 3592  0
         UnexpectedTokenException e = new UnexpectedTokenException( found, expectedTypes, comment );
 3593   
 
 3594  0
         if( throwIt )
 3595   
         {
 3596  0
             throw e;
 3597   
         }
 3598   
 
 3599  0
         return e;
 3600   
     }
 3601   
 
 3602   
 
 3603   
    /**
 3604   
     *  Reports an error by generating and optionally throwing an
 3605   
     *  <code>UnexpectedTokenException</code>.
 3606   
     */
 3607   
 
 3608  0
     protected UnexpectedTokenException error( int[] expectedTypes, boolean throwIt, int k, String comment ) throws SyntaxException, CompilationFailedException
 3609   
     {
 3610  0
         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  0
     protected UnexpectedTokenException error( int[] expectedTypes, boolean throwIt, int k ) throws SyntaxException, CompilationFailedException
 3620   
     {
 3621  0
         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  0
     protected void error( int[] expectedTypes ) throws SyntaxException, CompilationFailedException
 3631   
     {
 3632  0
         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  0
     protected void error() throws SyntaxException, CompilationFailedException
 3642   
     {
 3643  0
         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  0
     protected void error( String comment ) throws SyntaxException, CompilationFailedException
 3653   
     {
 3654  0
         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  0
     protected void error( Token found, String comment ) throws SyntaxException
 3664   
     {
 3665  0
         throw error( found, null, true, comment );
 3666   
     }
 3667   
 
 3668   
 
 3669   
 
 3670   
    /**
 3671   
     *  A scalar synonym of <code>error( expectedTypes )</code>.
 3672   
     */
 3673   
 
 3674  0
     protected void error( int expectedType ) throws SyntaxException, CompilationFailedException
 3675   
     {
 3676  0
         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  0
     public void recover( int[] safe, boolean ignoreNewlines ) throws SyntaxException, CompilationFailedException
 3693   
     {
 3694  0
         Token leading = la( ignoreNewlines );
 3695   
 
 3696  0
         while( true )
 3697   
         {
 3698  0
             Token next = la( ignoreNewlines );
 3699  0
             if( next.isA(Types.EOF) || next.isOneOf(safe) )
 3700   
             {
 3701  0
                 break;
 3702   
             }
 3703   
             else
 3704   
             {
 3705  0
                 consume( ignoreNewlines );
 3706   
             }
 3707   
         }
 3708   
 
 3709  0
         if( la(ignoreNewlines) == leading )
 3710   
         {
 3711  0
             consume( ignoreNewlines );
 3712   
         }
 3713   
     }
 3714   
 
 3715   
 
 3716   
 
 3717   
    /**
 3718   
     *  A scalar version of <code>recover( int[], boolean )</code>.
 3719   
     */
 3720   
 
 3721  0
     public void recover( int safe, boolean ignoreNewlines ) throws SyntaxException, CompilationFailedException
 3722   
     {
 3723  0
         Token leading = la( ignoreNewlines );
 3724   
 
 3725  0
         while( true )
 3726   
         {
 3727  0
             Token next = la( ignoreNewlines );
 3728  0
             if( next.isA(Types.EOF) || next.isA(safe) )
 3729   
             {
 3730  0
                 break;
 3731   
             }
 3732   
             else
 3733   
             {
 3734  0
                 consume( ignoreNewlines );
 3735   
             }
 3736   
         }
 3737   
 
 3738  0
         if( la(ignoreNewlines) == leading )
 3739   
         {
 3740  0
             consume( ignoreNewlines );
 3741   
         }
 3742   
     }
 3743   
 
 3744   
 
 3745   
 
 3746   
    /**
 3747   
     *  A synonym for <code>recover( safe, false )</code>.
 3748   
     */
 3749   
 
 3750  0
     public void recover( int[] safe ) throws SyntaxException, CompilationFailedException
 3751   
     {
 3752  0
         recover( safe, false );
 3753   
     }
 3754   
 
 3755   
 
 3756   
 
 3757   
    /**
 3758   
     *  A synonm for the scalar <code>recover( safe, false )</code>.
 3759   
     */
 3760   
 
 3761  0
     public void recover( int safe ) throws SyntaxException, CompilationFailedException
 3762   
     {
 3763  0
         recover( safe, false );
 3764   
     }
 3765   
 
 3766   
 
 3767   
 
 3768   
    /**
 3769   
     *  A synonym for <code>recover( Types.ANY_END_OF_STATMENT, true )</code>.
 3770   
     */
 3771   
 
 3772  0
     public void recover( ) throws SyntaxException, CompilationFailedException
 3773   
     {
 3774  0
         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  0
     protected Token la( int k, boolean significantNewlines ) throws SyntaxException, CompilationFailedException
 3791   
     {
 3792  0
         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  0
         try
 3801   
         {
 3802  0
             int streamK = 1;
 3803  0
             while( k > 0 && token.getMeaning() != Types.EOF )
 3804   
             {
 3805  0
                 token = getTokenStream().la( streamK );
 3806  0
                 streamK += 1;
 3807   
 
 3808  0
                 if( token == null  )
 3809   
                 {
 3810  0
                     token = Token.EOF;
 3811   
                 }
 3812  0
                 else if( token.getMeaning() == Types.NEWLINE )
 3813   
                 {
 3814  0
                     if( significantNewlines )
 3815   
                     {
 3816  0
                         k -= 1;
 3817   
                     }
 3818   
                 }
 3819   
                 else
 3820   
                 {
 3821  0
                     k -= 1;
 3822   
                 }
 3823   
             }
 3824   
         }
 3825   
         catch( ReadException e )
 3826   
         {
 3827  0
             controller.addFatalError( new SimpleMessage(e.getMessage()) );
 3828   
         }
 3829   
 
 3830  0
         return token;
 3831   
     }
 3832   
 
 3833   
 
 3834   
 
 3835   
    /**
 3836   
     *  Synonym for <code>la( k, false )</code>.
 3837   
     */
 3838   
 
 3839  0
     protected Token la( int k ) throws SyntaxException, CompilationFailedException
 3840   
     {
 3841  0
         return la( k, false );
 3842   
     }
 3843   
 
 3844   
 
 3845   
 
 3846   
    /**
 3847   
     *  Synonym for <code>la( 1, significantNewlines )</code>.
 3848   
     */
 3849   
 
 3850  0
     protected Token la( boolean significantNewlines ) throws SyntaxException, CompilationFailedException
 3851   
     {
 3852  0
         return la( 1, significantNewlines );
 3853   
     }
 3854   
 
 3855   
 
 3856   
 
 3857   
    /**
 3858   
     * Synonym for <code>la( 1, false )</code>.
 3859   
     */
 3860   
 
 3861  0
     protected Token la() throws SyntaxException, CompilationFailedException
 3862   
     {
 3863  0
         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  0
     protected Token la( ExpressionStack stack ) throws SyntaxException, CompilationFailedException
 3875   
     {
 3876  0
         Token next = la();
 3877   
 
 3878  0
         if( stack.canComplete() && next.isA(Types.UNSAFE_OVER_NEWLINES) )
 3879   
         {
 3880  0
             if( la(true).getMeaning() == Types.NEWLINE )
 3881   
             {
 3882  0
                 next = la(true);
 3883   
             }
 3884   
         }
 3885   
 
 3886  0
         return next;
 3887   
     }
 3888   
 
 3889   
 
 3890   
 
 3891   
 
 3892   
    /**
 3893   
     *  Returns the meaning of the <code>la( k, significantNewlines )</code> token.
 3894   
     */
 3895   
 
 3896  0
     protected int lt( int k, boolean significantNewlines ) throws SyntaxException, CompilationFailedException
 3897   
     {
 3898  0
         return la(k, significantNewlines).getMeaning();
 3899   
     }
 3900   
 
 3901   
 
 3902   
 
 3903   
    /**
 3904   
     *  Returns the meaning of the <code>la( k )</code> token.
 3905   
     */
 3906   
 
 3907  0
     protected int lt( int k ) throws SyntaxException, CompilationFailedException
 3908   
     {
 3909  0
         return la(k).getMeaning();
 3910   
     }
 3911   
 
 3912   
 
 3913   
 
 3914   
    /**
 3915   
     *  Returns the meaning of the <code>la( significantNewlines )</code> token.
 3916   
     */
 3917   
 
 3918  0
     protected int lt( boolean significantNewlines ) throws SyntaxException, CompilationFailedException
 3919   
     {
 3920  0
         return la(significantNewlines).getMeaning();
 3921   
     }
 3922   
 
 3923   
 
 3924   
 
 3925   
    /**
 3926   
     *  Returns the meaning of the <code>la()</code> token.
 3927   
     */
 3928   
 
 3929  0
     protected int lt() throws SyntaxException, CompilationFailedException
 3930   
     {
 3931  0
         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  0
     protected Token consume( int type, boolean significantNewlines ) throws SyntaxException, CompilationFailedException
 3949   
     {
 3950  0
         try
 3951   
         {
 3952  0
             if( !la(significantNewlines).isA(type) )
 3953   
             {
 3954  0
                 error( type );
 3955   
             }
 3956   
 
 3957  0
             if( !significantNewlines )
 3958   
             {
 3959  0
                 while( lt(true) == Types.NEWLINE )
 3960   
                 {
 3961  0
                     getTokenStream().consume(Types.NEWLINE);
 3962   
                 }
 3963   
             }
 3964   
 
 3965  0
             return getTokenStream().consume(type);
 3966   
         }
 3967   
         catch( ReadException e )
 3968   
         {
 3969  0
             controller.addFatalError( new SimpleMessage(e.getMessage()) );
 3970   
         }
 3971   
 
 3972  0
         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  0
     protected Token consume( int type ) throws SyntaxException, CompilationFailedException
 3983   
     {
 3984  0
         return consume( type, type == Types.NEWLINE );
 3985   
     }
 3986   
 
 3987   
 
 3988   
 
 3989   
    /**
 3990   
     *  A synonym for <code>consume( Types.ANY, false )</code>.
 3991   
     */
 3992   
 
 3993  0
     protected Token consume() throws SyntaxException, CompilationFailedException
 3994   
     {
 3995  0
         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  0
     protected Token consume( boolean significantNewlines ) throws SyntaxException, CompilationFailedException
 4007   
     {
 4008  0
         return consume( lt(significantNewlines), significantNewlines );
 4009   
     }
 4010   
 
 4011   
 }
 4012