anchor.diff:   *    {(*al,Map m) | m}(0)  ===  [:]
    */
   parameterIdent
  -        :   (   // Spread operator:  {(*y)|y}(1,2,3)  ===  [1,2,3]
  -                        sp:STAR^                                {#sp.setType(SPREAD_ARG);}
  -                |   // Optional-null operator:  {(?x,?y)|[x,y]}(1)  ===  [1,null]
  -                        op:QUESTION^                    {#op.setType(OPTIONAL_ARG);}
  -                )?
  -                IDENT
  -        ;
  +    :   (   // Spread operator:  {(*y)|y}(1,2,3)  ===  [1,2,3]
  +            sp:STAR^                                {#sp.setType(SPREAD_ARG);}
  +        |   // Optional-null operator:  {(?x,?y)|[x,y]}(1)  ===  [1,null]
  +            op:QUESTION^                    {#op.setType(OPTIONAL_ARG);}
  +        )?
  +        IDENT
  +    ;
   
   // Compound statement. This is used in many contexts:
   // Inside a class definition prefixed with "static":
  
positive.code: // Note pernicious case #2:  {xx|1}.  Does this mean add the low-order bit into xx, or return constant 1?
  // In both cases, the bar is "eagerly" taken to be a closure argument delimiter.
  expressionNotBOR
          :   e:expression
                  {require(#e.getType() != BOR,
                                  "expression in block; cannot be of the form a|b",
                                  "enclose the expression parentheses (a|b)");}
          ;
  
  /** A block which is known to be a closure, even if it has no apparent arguments.
   */
  closedBlock
          :       lc:LCURLY^ {#lc.setType(CLOSED_BLOCK);}
                  ( ( nls closureParametersStart ) =>
                          nls closureParameters
                  |
                          implicitParameters  // implicit {it|...} or {?noname|...}
                  )
                  blockBody
                  RCURLY!
          ;
  
  /** A block inside an expression is always assumed to be a closure.
   *  Only blocks which occur directly as substatements are kept open.
   */
  expressionBlock
      	:   closedBlock
      	;
  
  /** An appended block follows a method name or method argument list.
   *  It is optionally labeled.  DECIDE:  A good rule?
   */
  appendedBlock
          :
          /*
              (IDENT COLON nls LCURLY)=>
                  IDENT c:COLON^ {#c.setType(LABELED_ARG);} nls!
                  expressionBlock
          |
          */
                  expressionBlock
          ;
  
  /** A block known to be a closure, but which omits its arguments, is given this placeholder.
   *  A subsequent pass is responsible for deciding if there is an implicit 'it' parameter,
   *  or if the parameter list should be empty.
   */
  implicitParameters
          :   {   #implicitParameters = #(#[IMPLICIT_PARAMETERS,"IMPLICIT_PARAMETERS"]);  }
          ;
  
  /** A sub-block of a block can be either open or closed.
   *  It is closed if and only if there are explicit closure arguments.
  
negative.code:         |   BXOR_ASSIGN^
          |   BOR_ASSIGN^
          |   STAR_STAR_ASSIGN^
          //|   USEROP_13^  //DECIDE: This is how user-define ops would show up.
          )
          nls!
          assignmentExpression
      |
          {#assignmentTail = head;}
          in:INC^ {#in.setType(POST_INC);}
      |
          {#assignmentTail = head;}
          de:DEC^ {#de.setType(POST_DEC);}
      ;
  
  /** A member name (x.y) or element name (x[y]) can serve as a command name,
   *  which may be followed by a list of arguments.
   */
  commandArguments[AST head]
      :   {   #commandArguments = head;
              switch (LA(1)) {
              case PLUS: case MINUS: case INC: case DEC:
              case STAR: case DIV: case MOD:
              case SR: case BSR: case SL:
              case BAND: case BXOR: case BOR: case STAR_STAR:
              require(false,
                  "garbage infix or prefix operator after command name f +x",
                  "parenthesize either the whole expression (f+x) or the command arguments f(+x)");
              }
          }
          expression (options { greedy=true; } : COMMA! nls! expression)*
          // println 2+2 //BAD
          // println(2+2) //OK
          // println (2)+2 //BAD
          // println((2)+2) //OK
          // (println(2)+2) //OK
          // compare (2), 2 //BAD
          // compare( (2), 2 ) //OK
          // foo.bar baz{bat}, bang{boz} //OK?!
          {
              AST headid = getASTFactory().dup(#head);
              headid.setType(METHOD_CALL);
              headid.setText("<command>");
              #commandArguments = #(headid, #commandArguments);
          }
      ;
  
  assignmentOp
      :
      (   ASSIGN^
      |   PLUS_ASSIGN^
      |   MINUS_ASSIGN^
      |   STAR_ASSIGN^
      |   DIV_ASSIGN^
      |   MOD_ASSIGN^
      |   SR_ASSIGN^
      |   BSR_ASSIGN^
      |   SL_ASSIGN^
      |   BAND_ASSIGN^
      |   BXOR_ASSIGN^
      |   BOR_ASSIGN^
      |   STAR_STAR_ASSIGN^
      )
      ;
  
  // expressions
  // Note that most of these expressions follow the pattern
  //   thisLevelExpression :
  //         nextHigherPrecedenceExpression
  //                 (OPERATOR nextHigherPrecedenceExpression)*
  // which is a standard recursive definition for a parsing an expression.
  // The operators in java have the following precedences:
  //      lowest  (15)  = **= *= /= %= += -= <<= >>= >>>= &= ^= |=
  //                      (14)  ?:
  //                      (13)  ||
  //                      (12)  &&
  //                      (11)  |
  //                      (10)  ^
  //                      ( 9)  &
  //                      ( 8)  == != <=>
  //                      ( 7)  < <= > >=
  //                      ( 6)  << >>
  //                      ( 5)  +(binary) -(binary)
  //                      ( 4)  * / %
  //                      ( 3)  ++ -- +(unary) -(unary)
  //                      ( 2)  **(power)
  //                      ( 1)  ~  !  (type)
  //                                []   () (method call)  . (dot -- identifier qualification)
  //                                new   ()  (explicit parenthesis)
  //
  // the last two are not usually on a precedence chart; I put them in
  // to point out that new has a higher precedence than '.', so you
  // can validy use
  //       new Frame().show()
  //
  // Note that the above precedence levels map to the rules below...
  // Once you have a precedence chart, writing the appropriate rules as below
  