Package macromedia.asc.parser

Source Code of macromedia.asc.parser.Parser

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package macromedia.asc.parser;

import java.io.*;
import java.util.HashSet;
import java.util.ListIterator;
import java.util.BitSet;

import macromedia.asc.semantics.ReferenceValue;
import macromedia.asc.util.*;
import static macromedia.asc.parser.Tokens.*;
import static macromedia.asc.embedding.avmplus.RuntimeConstants.*;
import static macromedia.asc.embedding.avmplus.Features.*;
import static macromedia.asc.embedding.ErrorConstants.*;
import macromedia.asc.embedding.CompilerHandler;
import static macromedia.asc.parser.States.*;

/**
* Parse ECMAScript programs.
*
* @author Jeff Dyer
*/
public final class Parser
{
    private static final boolean debug = false;

    private static final String PUBLIC = "public".intern();
    private static final String PRIVATE = "private".intern();
    private static final String PROTECTED = "protected".intern();
    private static final String ASTERISK = "*".intern();
    private static final String DEFAULT = "default".intern();
    private static final String AS3 = "AS3".intern();
    public static final String CONFIG = "CONFIG".intern();
    private static final String GET = "get".intern();
    private static final String NAMESPACE = "namespace".intern();
    private static final String SET = "set".intern();
    private static final String VEC = "vec".intern();
    private static final String VECTOR = "Vector".intern();
    private static final String __AS3__ = "__AS3__".intern();

    private static final int abbrevIfElse_mode       = ELSE_TOKEN;  // lookahead uses this value. don't change.
    private static final int abbrevDoWhile_mode      = WHILE_TOKEN; // ditto.
    private static final int abbrevFunction_mode     = FUNCTION_TOKEN;
    private static final int abbrev_mode             = LAST_TOKEN - 1;
    private static final int full_mode               = abbrev_mode - 1;
    private static final int allowIn_mode            = full_mode - 1;
    private static final int noIn_mode               = allowIn_mode - 1;
      
    private enum ParseError {
      catch_parameter,
      syntax,
      expression,
      EOS,
      XML
    }
   
    private static int binary_precedence[];
    private static BitSet XMLTokenSet;
    private static BitSet StatementTokenSet;
   
    private void init_BitSets()
    {
 
      if (XMLTokenSet != null)
      return;

      StatementTokenSet = new BitSet(-LAST_TOKEN);
    XMLTokenSet = new BitSet(-LAST_TOKEN);
   
      StatementTokenSet.set(-SUPER_TOKEN);
         StatementTokenSet.set(-LEFTBRACE_TOKEN);
         StatementTokenSet.set(-IF_TOKEN);
         StatementTokenSet.set(-SWITCH_TOKEN);
         StatementTokenSet.set(-DO_TOKEN);
         StatementTokenSet.set(-WHILE_TOKEN);
         StatementTokenSet.set(-FOR_TOKEN);
         StatementTokenSet.set(-WITH_TOKEN);
         StatementTokenSet.set(-CONTINUE_TOKEN);
         StatementTokenSet.set(-BREAK_TOKEN);
         StatementTokenSet.set(-RETURN_TOKEN);
         StatementTokenSet.set(-THROW_TOKEN);
         StatementTokenSet.set(-TRY_TOKEN);
         StatementTokenSet.set(-LEFTBRACKET_TOKEN);
        StatementTokenSet.set(-DOCCOMMENT_TOKEN);
     
    XMLTokenSet.set(-IDENTIFIER_TOKEN);
    XMLTokenSet.set(-ABSTRACT_TOKEN);
    XMLTokenSet.set(-AS_TOKEN);
    XMLTokenSet.set(-BREAK_TOKEN);
    XMLTokenSet.set(-CASE_TOKEN);
    XMLTokenSet.set(-CATCH_TOKEN);
    XMLTokenSet.set(-CLASS_TOKEN);
    XMLTokenSet.set(-CONST_TOKEN);

    XMLTokenSet.set(-CONTINUE_TOKEN);
    XMLTokenSet.set(-DEBUGGER_TOKEN);
    XMLTokenSet.set(-DEFAULT_TOKEN);
    XMLTokenSet.set(-DELETE_TOKEN);

    XMLTokenSet.set(-DO_TOKEN);
    XMLTokenSet.set(-ELSE_TOKEN);
    XMLTokenSet.set(-ENUM_TOKEN);
    XMLTokenSet.set(-EXTENDS_TOKEN);

    XMLTokenSet.set(-FALSE_TOKEN);
    XMLTokenSet.set(-FINAL_TOKEN);
    XMLTokenSet.set(-FINALLY_TOKEN);
    XMLTokenSet.set(-FOR_TOKEN);

    XMLTokenSet.set(-FUNCTION_TOKEN);
    XMLTokenSet.set(-GET_TOKEN);
    XMLTokenSet.set(-GOTO_TOKEN);
    XMLTokenSet.set(-IF_TOKEN);

    XMLTokenSet.set(-IMPLEMENTS_TOKEN);
    XMLTokenSet.set(-IMPORT_TOKEN);
    XMLTokenSet.set(-IN_TOKEN);
    XMLTokenSet.set(-INCLUDE_TOKEN);

    XMLTokenSet.set(-INSTANCEOF_TOKEN);
    XMLTokenSet.set(-INTERFACE_TOKEN);
    XMLTokenSet.set(-IS_TOKEN);
    XMLTokenSet.set(-NAMESPACE_TOKEN);

    XMLTokenSet.set(-CONFIG_TOKEN);
    XMLTokenSet.set(-NATIVE_TOKEN);
    XMLTokenSet.set(-NEW_TOKEN);
    XMLTokenSet.set(-NULL_TOKEN);

    XMLTokenSet.set(-PACKAGE_TOKEN);
    XMLTokenSet.set(-PRIVATE_TOKEN);
    XMLTokenSet.set(-PROTECTED_TOKEN);
    XMLTokenSet.set(-PUBLIC_TOKEN);

    XMLTokenSet.set(-RETURN_TOKEN);
    XMLTokenSet.set(-SET_TOKEN);
    XMLTokenSet.set(-STATIC_TOKEN);
    XMLTokenSet.set(-SUPER_TOKEN);

    XMLTokenSet.set(-SWITCH_TOKEN);
    XMLTokenSet.set(-SYNCHRONIZED_TOKEN);
    XMLTokenSet.set(-THIS_TOKEN);
    XMLTokenSet.set(-THROW_TOKEN);

    XMLTokenSet.set(-THROWS_TOKEN);
    XMLTokenSet.set(-TRANSIENT_TOKEN);
    XMLTokenSet.set(-TRUE_TOKEN);
    XMLTokenSet.set(-TRY_TOKEN);

    XMLTokenSet.set(-TYPEOF_TOKEN);
    XMLTokenSet.set(-USE_TOKEN);
    XMLTokenSet.set(-VAR_TOKEN);
    XMLTokenSet.set(-VOID_TOKEN);

    XMLTokenSet.set(-VOLATILE_TOKEN);
    XMLTokenSet.set(-WHILE_TOKEN);
    XMLTokenSet.set(-WITH_TOKEN);
  }
   
    private final boolean inXMLTokenSet( int id)
    {
      return XMLTokenSet.get(-id);
    }
   
    private final boolean inStatementTokenSet( int id)
    {
      return StatementTokenSet.get(-id);
    }
     
    private void init_binary_precedence()
    {

      if ( binary_precedence != null )
        return;
     
      binary_precedence = new int [-LAST_TOKEN];
     
      binary_precedence[-COMMA_TOKEN] = 1;
      binary_precedence[-ASSIGN_TOKEN] = 2;
       binary_precedence[-BITWISEANDASSIGN_TOKEN] = 2;
       binary_precedence[-BITWISEORASSIGN_TOKEN] = 2;
        binary_precedence[-BITWISEXORASSIGN_TOKEN] = 2;
       binary_precedence[-DIVASSIGN_TOKEN] = 2;
        binary_precedence[-LEFTSHIFTASSIGN_TOKEN] = 2;
       binary_precedence[-LOGICALANDASSIGN_TOKEN] = 2;
        binary_precedence[-LOGICALORASSIGN_TOKEN] = 2;
       binary_precedence[-LOGICALXORASSIGN_TOKEN] = 2;
        binary_precedence[-MINUSASSIGN_TOKEN] = 2;
       binary_precedence[-MULTASSIGN_TOKEN] = 2;
        binary_precedence[-MODULUSASSIGN_TOKEN] = 2;
       binary_precedence[-PLUSASSIGN_TOKEN] = 2;
        binary_precedence[-RIGHTSHIFTASSIGN_TOKEN] = 2;
       binary_precedence[-UNSIGNEDRIGHTSHIFTASSIGN_TOKEN] = 2;
       binary_precedence[-QUESTIONMARK_TOKEN] = 3
       binary_precedence[-LOGICALOR_TOKEN] = 4;
        binary_precedence[-LOGICALAND_TOKEN] = 5;    
       binary_precedence[-BITWISEOR_TOKEN] = 6;
       binary_precedence[-BITWISEXOR_TOKEN] = 7;
        binary_precedence[-BITWISEAND_TOKEN] = 8;
       binary_precedence[-EQUALS_TOKEN] = 9;
       binary_precedence[-NOTEQUALS_TOKEN] = 9;
        binary_precedence[-STRICTEQUALS_TOKEN] = 9;
       binary_precedence[-STRICTNOTEQUALS_TOKEN] = 9;
       binary_precedence[-GREATERTHAN_TOKEN] = 10;
        binary_precedence[-GREATERTHANOREQUALS_TOKEN] = 10;
       binary_precedence[-LESSTHAN_TOKEN] = 10;
       binary_precedence[-LESSTHANOREQUALS_TOKEN] = 10;
        binary_precedence[-INSTANCEOF_TOKEN] = 10;
       binary_precedence[-IS_TOKEN] = 10;
       binary_precedence[-AS_TOKEN] = 10;
        binary_precedence[-IN_TOKEN] = 10;
       binary_precedence[-LEFTSHIFT_TOKEN] = 11;
       binary_precedence[-RIGHTSHIFT_TOKEN] = 11;
        binary_precedence[-UNSIGNEDRIGHTSHIFT_TOKEN] = 11;
       binary_precedence[-MINUS_TOKEN] = 12;
       binary_precedence[-PLUS_TOKEN] = 12;
       binary_precedence[-DIV_TOKEN] = 13;
        binary_precedence[-MODULUS_TOKEN] = 13;
      binary_precedence[-MULT_TOKEN] = 13;
    }

    private int nextToken;
    private Context ctx;
    private NodeFactory nodeFactory;
    private boolean create_doc_info;
    private boolean save_comment_nodes;
    public Scanner scanner;

    private String encoding;
    public ObjectList<Node> comments = new ObjectList<Node>(); // all comments encountered while parsing are placed here, rather than in the parse tree
    public IntList block_kind_stack = new IntList();
    public String current_class_name = null;
    private boolean within_package;
    private boolean parsing_include = false;
    public ObjectList< HashSet<String> > config_namespaces = new ObjectList< HashSet<String> >();

    private void clearUnusedBuffers() {
        comments.clear();
        scanner.clearUnusedBuffers();
        scanner = null;
        comments = null;
    }
   
    /*
     * Log a syntax error and recover
     */

    Node error(int errCode)                                                  { return error(ParseError.syntax, errCode,"","",-1); }
//    private Node error(ParseError kind, int errCode)                           { return error(kind,errCode,"","",-1); }
    private Node error(ParseError kind, int errCode, String arg1)              { return error(kind,errCode,arg1,"",-1); }
    private Node error(ParseError kind, int errCode, String arg1, String arg2) { return error(kind,errCode,arg1,arg2,-1); }
    private Node error(ParseError kind, int errCode, String arg1, String arg2,int pos)
    {
        String origin = this.scanner.input.origin;
        StringBuilder out = new StringBuilder();
       
        if(debug) out.append("[Parser] ");
       
        // Just the arguments for sanities, no message (since they change often)
        if(ContextStatics.useSanityStyleErrors)
        {
            out.append("code=" + errCode + "; arg1=" + arg1 + "; arg2=" + arg2);
        }
        else
        {
            String msg = ctx.shellErrorString(errCode);
            int nextLoc = Context.replaceStringArg(out, msg, 0, arg1);
            nextLoc = Context.replaceStringArg(out, msg, nextLoc, arg2);
            if (nextLoc != -1) // append msg remainder after replacement point, if any
                out.append(msg.substring(nextLoc, msg.length()));
        }

        if( pos < 0 )
        {
            pos = scanner.input.positionOfMark();
        }

        int lineno = scanner.input.getLnNum(pos);
        int column = scanner.input.getColPos(pos);

        if (kind == ParseError.syntax || kind == ParseError.EOS )
        {
            ctx.localizedError(origin, lineno, column, out.toString(), scanner.input.getLineText(pos), errCode);
        }
        else
        {
            ctx.localizedError(origin, lineno, column, out.toString(), "", errCode);
        }
        return null;
    }

    /*
     * skip ahead after an error is detected. this simply goes until the next
     * whitespace or end of input.
     */

    private void skiperror( ParseError e)
    {
      switch (e)
      {
      case catch_parameter:
        while (true)
        {
          getNextToken();
          if (nextToken == RIGHTPAREN_TOKEN || nextToken == EOS_TOKEN)
          {
            break;
          }
        }
        break;
       
      case XML:
      case EOS:
        while (true)
        {
          getNextToken();
          if (nextToken == EOS_TOKEN)
          {
            break;
          }
        }
        break;
       
      case syntax:
      case expression:
        do
        {
          if (nextToken == LEFTPAREN_TOKEN || nextToken == RIGHTPAREN_TOKEN ||
              nextToken == LEFTBRACE_TOKEN || nextToken == RIGHTBRACE_TOKEN ||
              nextToken == LEFTBRACKET_TOKEN || nextToken == RIGHTBRACKET_TOKEN ||
              nextToken == COMMA_TOKEN || nextToken == SEMICOLON_TOKEN ||
              nextToken == EOS_TOKEN)
          {
            break;
          }
          getNextToken();
        }
        while (true);
      break;
     
    }
   
    private void skiperror(int tokenId)
    {
      while (true)
      {
        if (nextToken == tokenId)
        {
          if( tokenId == RIGHTBRACE_TOKEN )
          {
            int size = block_kind_stack.size();
            block_kind_stack.clear();
            for( ; size > 0; --size)
            {
              block_kind_stack.add(ERROR_TOKEN);    // ignore attribute errors since blocks are probably messed up
            }
          }
          break;
        }
        else if( nextToken == EOS_TOKEN )
        {
          break;
        }
        else if( nextToken == SEMICOLON_TOKEN && tokenId != RIGHTBRACE_TOKEN ) // don't stop eating until right brace is found
        {
          break;
        }
        else if( nextToken == LEFTBRACE_TOKEN && tokenId != RIGHTBRACE_TOKEN ) // don't stop eating until right brace is found
        {
          scanner.retract();
          break;
        }
        else if( nextToken == RIGHTBRACE_TOKEN )
        {
          scanner.retract();
          break;
        }
        getNextToken();
      }
    }

  private void init(Context cx, String origin, boolean emit_doc_info, boolean save_comment_nodes, IntList block_kind_stack)
  {
    ctx = cx;
    nextToken = EMPTY_TOKEN;
    create_doc_info = emit_doc_info;
        within_package = false;
    this.save_comment_nodes = save_comment_nodes;
    nodeFactory = cx.getNodeFactory();
    nodeFactory.createDefaultDocComments(emit_doc_info); // for now, always create default comments for uncommented nodes in -doc
    if( block_kind_stack != null )
    {
        this.block_kind_stack.addAll(block_kind_stack);
    }
    else
    {
        this.block_kind_stack.add(EMPTY_TOKEN)// set initial state
    }
    cx.parser = this;
    cx.setOrigin(origin);
    init_binary_precedence();
    init_BitSets();
  }

    public Parser(Context cx, InputStream in, String origin)
    {
        this(cx, in, origin, null);
    }

    public Parser(Context cx, InputStream in, String origin, String encoding)
    {
        init(cx, origin, false, false, null);
        scanner = new Scanner(cx, in, encoding, origin);
        this.encoding = encoding;
    }

    public Parser(Context cx, InputStream in, String origin, boolean emit_doc_info, boolean save_comment_nodes)
    {
        this(cx, in, origin, null, emit_doc_info, save_comment_nodes,null);
    }

    public Parser(Context cx, InputStream in, String origin, String encoding, boolean emit_doc_info, boolean save_comment_nodes)
    {
        this(cx, in, origin, encoding, emit_doc_info, save_comment_nodes,null);
    }

    public Parser(Context cx, InputStream in, String origin, String encoding, boolean emit_doc_info, boolean save_comment_nodes, IntList block_kind_stack)
    {
      init(cx, origin, emit_doc_info, save_comment_nodes, block_kind_stack);
        scanner = new Scanner(cx, in, encoding, origin, save_comment_nodes|emit_doc_info);
        this.encoding = encoding;
    }

    public Parser(Context cx, InputStream in, String origin, String encoding, boolean emit_doc_info, boolean save_comment_nodes, IntList block_kind_stack, boolean is_include)
    {
        this(cx, in, origin,encoding, emit_doc_info, save_comment_nodes, block_kind_stack);
        this.parsing_include = is_include;
    }

  public Parser(Context cx, String in, String origin)
  {
    init(cx, origin, false, false, null);
      scanner = new Scanner(cx, in, origin, false);
  }

  public Parser(Context cx, String in, String origin, boolean emit_doc_info, boolean save_comment_nodes)
  {
      this(cx, in, origin, emit_doc_info, save_comment_nodes,null);
  }

  public Parser(Context cx, String in, String origin, boolean emit_doc_info, boolean save_comment_nodes, IntList block_kind_stack)
  {
    init(cx, origin, emit_doc_info, save_comment_nodes, block_kind_stack);
      scanner = new Scanner(cx, in, origin, save_comment_nodes|emit_doc_info);
  }

    public Parser(Context cx, String in, String origin, boolean emit_doc_info, boolean save_comment_nodes, IntList block_kind_stack, boolean is_include)
    {
        this(cx, in, origin, emit_doc_info, save_comment_nodes, block_kind_stack);
        this.parsing_include = is_include;
    }

    /**
     * This contructor is used by Flex direct AST generation.  It
     * allows Flex to pass in a specialized InputBuffer.
     */
   
    public Parser(Context cx, InputBuffer inputBuffer, String origin, boolean emit_doc_info)
    {
        init(cx, origin, emit_doc_info, false, null);
        scanner = new Scanner(cx, inputBuffer);
    }

    /*
     * shift: -- like match, but we already know the token
     */
   
    private final void shift()
    {
      nextToken = EMPTY_TOKEN;
    }

    /*
     * Match the current input with an expected token. lookahead is managed by
     * setting the state of this.nexttoken to EMPTY_TOKEN after an match is
     * attempted. the next lookahead will initialize it again.
     */
  
    public final int match(int expectedTokenClass)
    {
        int result;
        int lt = lookahead();
  
        if (lt == expectedTokenClass)
        {
          shift();
          return lt;
        }
       
        if (lt == ERROR_TOKEN)
        {
          result = nextToken;
          shift();
          return result;
        }

        if (expectedTokenClass == EOS_TOKEN)
        {
          if (ctx.errorCount() == 0// only if this is the first error.
          {
            error(kError_Parser_ExtraCharsAfterEndOfProgram);
          }
          // otherwise, don't say anything.
          skiperror(EOS_TOKEN);
          result = nextToken;
          shift();
        }
        else
        {
          error(ParseError.EOS, kError_Parser_ExpectedToken,
              Token.getTokenClassName(expectedTokenClass),
              scanner.getCurrentTokenTextOrTypeText(nextToken));
         
          skiperror(expectedTokenClass);

          result = nextToken;
          if (nextToken!=EOS_TOKEN)
          {
            shift();
          }
        }
        return result;
    }

    /*
     * Handle optional semicolon recognition.
     */

    private final boolean lookaheadSemicolon(int mode)
    {
        final int lt = lookahead();
       
        if (lt==SEMICOLON_TOKEN || lt==EOS_TOKEN || lt==RIGHTBRACE_TOKEN || lt==mode || scanner.followsLineTerminator())
        {
          return true;
        }
        return false;
    }

    private final int matchSemicolon(int mode)
    {

        int result = ERROR_TOKEN;
        final int lt = lookahead();

        if (lt==SEMICOLON_TOKEN)
        {
          shift();
            result = SEMICOLON_TOKEN;
        }
        else if (lt==EOS_TOKEN||lt==RIGHTBRACE_TOKEN||scanner.followsLineTerminator())
        {
            result = SEMICOLON_TOKEN;
        }
        else if ((mode == abbrevIfElse_mode || mode == abbrevDoWhile_mode) && lt==mode)
        {
            result = SEMICOLON_TOKEN;
        }
        else if (lt!=ERROR_TOKEN)
        {
            if (mode == abbrevFunction_mode)
            {
                error(kError_Parser_ExpectedLeftBrace);
                skiperror(LEFTBRACE_TOKEN);
            }
            else
            {
                error(ParseError.syntax, kError_Parser_ExpectedSemicolon, scanner.getCurrentTokenTextOrTypeText(nextToken));
                skiperror(SEMICOLON_TOKEN);
            }
        }
        return result;
    }

    /*
     * Match a non-insertable semi-colon. This function looks for
     * a SEMICOLON_TOKEN or other grammatical markers that indicate
     * that the EMPTY_TOKEN is equivalent to a semicolon.
     */

    private final int matchNoninsertableSemicolon(int mode)
    {

        switch ( lookahead() )
        {
        case SEMICOLON_TOKEN:
            shift();
        case EOS_TOKEN:
        case RIGHTBRACE_TOKEN:
            return SEMICOLON_TOKEN;
        }
        if ((mode == abbrevIfElse_mode || mode == abbrevDoWhile_mode) && lookahead()==mode)
        {
            return SEMICOLON_TOKEN;
        }
        else
        {
            error(ParseError.syntax, kError_Parser_ExpectedSemicolon, scanner.getCurrentTokenTextOrTypeText(nextToken));
            skiperror(SEMICOLON_TOKEN);
            return ERROR_TOKEN;
        }
    }

    /*
     * This wrapper to scanner->nextToken filters out all non-doccomment comments from the
     *  scanner output and collects all comments (including doccomments) in the commentTable.
     *  The commentTable can be used by external compiler toolchain tools to detect where
     *  comments are located in the source while walking the parse-tree.
     */
   
    private final void getNextToken()
    {
        int tok = scanner.nexttoken(true);
       
        while(tok == SLASHSLASHCOMMENT_TOKEN || tok == BLOCKCOMMENT_TOKEN || tok == DOCCOMMENT_TOKEN)
        {
          // TODO: figure this out, behavior differs from above comment and is silly.
          // We could also combine adjacent doccomments if it mattered.
         
            if( save_comment_nodes && (!ctx.scriptAssistParsing || tok != DOCCOMMENT_TOKEN))
            {
                Node newComment = nodeFactory.comment(scanner.getCurrentTokenText(), tok, scanner.input.positionOfMark());
                comments.push_back(newComment);
            }

            if (tok == DOCCOMMENT_TOKEN && create_doc_info) // return doccomment tokens if create_doc_info, skip normal comment tokens)
                break;

            tok = scanner.nexttoken(false);
        }
        nextToken = tok;
    }

    /*
     * Change the lookahead token.
     */
   
    private final void changeLookahead(int tok)
    {
        nextToken = tok;
    }

    /*
     * Lookahead (simpler version)
     */

    private final int lookahead()
    {
         if (nextToken == EMPTY_TOKEN)
         {
             getNextToken();
         }
       
        if (debug)
        {
            System.err.println("\t" + Token.getTokenClassName(nextToken));
        }
        return nextToken;
    }
   
    /*
     * Start grammar.
     */

    /*
     * Identifier
     *     'get' | 'set' | 'namespace' | identifier
     */

    private IdentifierNode parseIdentifier()
    {
        if (debug)
        {
            System.err.println("begin parseIdentifier");
        }

        String name = parseIdentifierString();
        IdentifierNode result = nodeFactory.identifier(name, false, scanner.input.positionOfMark());

        if (debug)
        {
            System.err.println("finish parseIdentifier");
        }

        return result;
    }

    public String parseIdentifierString()
    {
        if (debug)
        {
            System.err.println("begin parseIdentifierString");
        }

        String result = null;
        final int lt = lookahead();
       
        switch ( lt )
        {
        case GET_TOKEN:
            shift();
            result = GET;
            break;
           
        case SET_TOKEN:
            shift();
            result = SET;
            break;
           
        case NAMESPACE_TOKEN:
            shift();
            result = NAMESPACE;
            break;
           
        case IDENTIFIER_TOKEN:
          shift();
          result = scanner.getCurrentTokenText().intern();
          break;
           
        default:
          if (IDENTIFIER_TOKEN==match(IDENTIFIER_TOKEN))
          {
            result=scanner.getCurrentTokenText().intern();
          }
          else
          {
            result = "expected identifer";
          }
        }

        if (debug)
        {
            System.err.println("finish parseIdentifierString");
        }

        return result;
    }

    /*
     * PropertyIdentifier:
     *     'default' |'get' | 'set' | 'namespace' | identifier | '*'
     */

    private IdentifierNode parsePropertyIdentifier()
    {
        if (debug)
        {
            System.err.println("begin parsePropertyIdentifier");
        }

        int pos = scanner.input.positionOfMark();
        String name = parsePropertyIdentifierString();
        IdentifierNode result = nodeFactory.identifier(name, false, pos);

        if (debug)
        {
            System.err.println("finish parsePropertyIdentifier");
        }

        return result;
    }

    private String parsePropertyIdentifierString()
    {
        if (debug)
        {
            System.err.println("begin parsePropertyIdentifierString");
        }

        String result = null;
        final int lt = lookahead();
       
        switch(lt)
        {
        case DEFAULT_TOKEN:
            shift();
            result = DEFAULT;
            break;
           
        case GET_TOKEN:
          shift();
            result = GET;
          break;
         
        case SET_TOKEN:
          shift();
            result = SET;
          break;
         
        case NAMESPACE_TOKEN:
          shift();
          result = NAMESPACE;
          break;
           
        case IDENTIFIER_TOKEN:
          shift();
          result = scanner.getCurrentTokenText().intern();
          break;
 
        default:
          if (HAS_WILDCARDSELECTOR && (lt==MULT_TOKEN || lt==MULTASSIGN_TOKEN))
          {
            result = ASTERISK;
            if (lt==MULT_TOKEN)
            {
              shift();
            }
            else
            {
              // for '*=', rewrite it as '*' '='
               changeLookahead(ASSIGN_TOKEN);
            }
          }
          else if (IDENTIFIER_TOKEN==match(IDENTIFIER_TOKEN))
            {
              result=scanner.getCurrentTokenText().intern();
             }
          else
          {
            result = "expected property identifier";
          }
         }

        if (debug)
        {
            System.err.println("finish parsePropertyIdentifier");
        }

        return result;
    }

    /*
     * Qualifier
     *     propertyIdentifier | 'public' | 'private' | 'protected'
     */

    private IdentifierNode parseQualifier()
    {

        if (debug)
        {
            System.err.println("begin parseQualifier");
        }

        IdentifierNode result;

        switch ( lookahead() )
        {
        case PUBLIC_TOKEN:
            shift();
            result = nodeFactory.identifier(PUBLIC,false,scanner.input.positionOfMark());
            break;
           
        case PRIVATE_TOKEN:
            shift();
            result = nodeFactory.identifier(PRIVATE,false,scanner.input.positionOfMark());
            break;
           
        case PROTECTED_TOKEN:
            shift();
            result = nodeFactory.identifier(PROTECTED,false,scanner.input.positionOfMark());
            break;
           
        default:
            result = parsePropertyIdentifier();
        }

        if (debug)
        {
            System.err.println("finish parseQualifier");
        }

        return result;
    }

    /*
     * SimpleQualifiedIdentifier
     *     '@' Brackets
     *     '@'? Qualifier '::' Brackets
     *     '@'? Qualifier '::' PropertyIdentifier
     *     '@'? Qualifier
     *    
     */

    private IdentifierNode parseSimpleQualifiedIdentifier()
    {
        if (debug)
        {
            System.err.println("begin parseSimpleQualifiedIdentifier");
        }

        IdentifierNode result = null;
        IdentifierNode first;
        boolean is_attr = false;
       
        if (HAS_ATTRIBUTEIDENTIFIERS && lookahead()==ATSIGN_TOKEN)
        {
            shift();
            is_attr = true;
        }

        if( is_attr && lookahead()==LEFTBRACKET_TOKEN )   // @[ . expr]
        {
            MemberExpressionNode men = parseBrackets(null);
            GetExpressionNode gen = men.selector instanceof GetExpressionNode ? (GetExpressionNode) men.selector : null;
            result = nodeFactory.qualifiedExpression(null,gen.expr,gen.expr.pos());
        }
        else
        {
            first = parseQualifier();
           
            if (HAS_QUALIFIEDIDENTIFIERS && lookahead()==DOUBLECOLON_TOKEN)
            {
                shift();
                MemberExpressionNode temp = nodeFactory.memberExpression(null,nodeFactory.getExpression(first));
                              
             // ???: Note that this also allows id::[expr] (existence of the @ is not checked)
               
                if( lookahead()==LEFTBRACKET_TOKEN // @ns::[ . expr]
                {
                    MemberExpressionNode men = parseBrackets(null);
                    GetExpressionNode gen = men.selector instanceof GetExpressionNode ? (GetExpressionNode) men.selector : null;
                    result = nodeFactory.qualifiedExpression(temp,gen.expr,gen.expr.pos());
                }
                else
                {
                    QualifiedIdentifierNode qualid = nodeFactory.qualifiedIdentifier(temp,parsePropertyIdentifierString(),scanner.input.positionOfMark());
                    assert config_namespaces.size() > 0;
                    if( config_namespaces.last().contains(first.name) )
                      qualid.is_config_name = true;
                    result = qualid;
                    result.setOrigTypeToken(DOUBLECOLON_TOKEN);
                }
            }
            else
            {
                result = first;
            }
        }

        result.setAttr(is_attr);

        if (debug)
        {
            System.err.println("finish parseSimpleQualifiedIdentifier");
        }

        return result;
    }

    /*
     * ExpressionQualifiedIdentifier
     *     '@'? ParenExpression '::' PropertyIdentifier
     */

    private IdentifierNode parseExpressionQualifiedIdentifier()
    {
        if (debug)
        {
            System.err.println("begin parseExpressionQualifiedIdentifier");
        }

        IdentifierNode result;
        Node first;
        boolean is_attr = false;
       
        if (HAS_ATTRIBUTEIDENTIFIERS && lookahead()==ATSIGN_TOKEN)
        {
            shift();
            is_attr = true;
        }

        first = parseParenExpression();
        match(DOUBLECOLON_TOKEN);
        result = nodeFactory.qualifiedIdentifier(first, parsePropertyIdentifierString(),scanner.input.positionOfMark());
        result.setAttr(is_attr);

        if (debug)
        {
            System.err.println("finish parseExpressionQualifiedIdentifier");
        }

        return result;
    }

    /*
     * QualifiedIdentifier
     *     ExpressionQualifiedIdentifier | SimpleQualifiedIndentifier
     */

    private IdentifierNode parseQualifiedIdentifier()
    {
        if (debug)
        {
            System.err.println("begin parseQualifiedIdentifier");
        }

        IdentifierNode result = (HAS_EXPRESSIONQUALIFIEDIDS && lookahead()==LEFTPAREN_TOKEN)
            ? parseExpressionQualifiedIdentifier()
            : parseSimpleQualifiedIdentifier();

        if (debug)
        {
            System.err.println("finish parseQualifiedIdentifier");
        }

        return result;
    }

    /*
     * PrimaryExpression
     */

    private Node parsePrimaryExpression()
    {
        if (debug)
        {
            System.err.println("begin parsePrimaryExpression");
        }

        Node result;
        final int lt = lookahead();
        int pos = scanner.input.positionOfMark();

        switch ( lt )
        {
        case NULL_TOKEN:
            shift();
            result = nodeFactory.literalNull(pos);
            break;
           
        case TRUE_TOKEN:   
            shift();
            result = nodeFactory.literalBoolean(true,pos);
            break;
           
        case FALSE_TOKEN:
            shift();
            result = nodeFactory.literalBoolean(false,pos);
            break;
           
        case PRIVATE_TOKEN:
            shift();
            result = nodeFactory.identifier(PRIVATE,false,pos);
            break;
           
        case PUBLIC_TOKEN:
            shift();
            result = nodeFactory.identifier(PUBLIC,false,pos);
            break;
           
        case PROTECTED_TOKEN:
            shift();
            result = nodeFactory.identifier(PROTECTED,false,pos);
            break;
       
        case NUMBERLITERAL_TOKEN:
          shift();
            result = nodeFactory.literalNumber(scanner.getCurrentTokenText(),pos);
            break;
           
        case STRINGLITERAL_TOKEN:
        {
            boolean[] is_single_quoted = new boolean[1];
            shift();
            String enclosedText = scanner.getCurrentStringTokenText(is_single_quoted);
            result = nodeFactory.literalString(enclosedText, pos, is_single_quoted[0] );
            break;
        }
       
        case THIS_TOKEN:
            shift();
            result = nodeFactory.thisExpression(pos);
            break;
           
        case LEFTPAREN_TOKEN:
            result = parseParenExpressionList();
            break;
           
        case LEFTBRACKET_TOKEN:
            result = parseArrayLiteral();
            break;
     
        case LEFTBRACE_TOKEN:
            result = parseObjectLiteral();
            break;
           
        case FUNCTION_TOKEN:
        {
            shift();
            IdentifierNode first = null;
            if (lookahead()==IDENTIFIER_TOKEN)
            {
                first = parseIdentifier();
            }
            result = parseFunctionCommon(first);
            break;
        }
 
        case PACKAGE_TOKEN:
            if (within_package)
            {
                error(kError_NestedPackage);
                result = nodeFactory.error(pos, kError_NestedPackage);
            }
            else
            {
                error(ParseError.syntax,kError_Parser_ExpectedPrimaryExprBefore,scanner.getCurrentTokenTextOrTypeText(nextToken));
                result = nodeFactory.error(pos, kError_Parser_ExpectedPrimaryExprBefore);
            }
            skiperror(LEFTBRACE_TOKEN);
            skiperror(RIGHTBRACE_TOKEN);
            break;
           
        case CATCH_TOKEN: case FINALLY_TOKEN: case ELSE_TOKEN:
            error(ParseError.syntax, kError_Parser_ExpectedPrimaryExprBefore,scanner.getCurrentTokenTextOrTypeText(nextToken));
            skiperror(LEFTBRACE_TOKEN);
            skiperror(RIGHTBRACE_TOKEN);
            result = nodeFactory.error(scanner.input.positionOfMark(), kError_Parser_ExpectedPrimaryExprBefore);
            break;
       
        case XMLMARKUP_TOKEN: case LESSTHAN_TOKEN:
            result = (HAS_XMLLITERALS)
                ? parseXMLLiteral()
                : parseTypename();
            break;
           
        case REGEXPLITERAL_TOKEN:
            if (HAS_REGULAREXPRESSIONS)
            {
              shift();
                result = nodeFactory.literalRegExp(scanner.getCurrentTokenText(),pos);
            }
            else
            {
              result = parseTypename();
            }
            break;
           
        default:   
                result = parseTypename();
        }

        if (debug)
        {
            System.err.println("finish parsePrimaryExpression");
        }

        return result;
    }
   
   
    private boolean is_xmllist = false;
   
    private LiteralXMLNode parseXMLLiteral()
    {
        is_xmllist = false;
        LiteralXMLNode result = null;
        Node first;
        int pos = scanner.input.positionOfMark();
       
        if(lookahead()==XMLMARKUP_TOKEN)
        {
          shift();
            first  = nodeFactory.list(null,nodeFactory.literalString(scanner.getCurrentTokenText(),pos));
        }
        else
        {
            scanner.pushState();
            first = parseXMLElement();
            scanner.popState();
        }
       
        if( first != null )
        {
            ListNode list = nodeFactory.list(null,first,pos);
            result = nodeFactory.literalXML(list,is_xmllist,scanner.input.positionOfMark());
        }
        return result;
    }

    /*
     * XMLElement
     *   : '<' '>'  => xmllist=true
     *   | '<' <XMLName> <XMLAttributes> '>' <XMLElement> '</' <XMLName> '>'
     *  | '<' <XMLName> <XMLAttributes> '>' <XMLElement> '</' xmllist? '>'
     *  ;
     */
    Node parseXMLElement()
    {
        Node result;
        boolean is_xmllist = false;

        match(LESSTHAN_TOKEN);
        if(lookahead()==GREATERTHAN_TOKEN)
        {
            is_xmllist = true;
            result = nodeFactory.list(null,nodeFactory.literalString("",0));
        }
        else
        {
            result = nodeFactory.list(null,nodeFactory.literalString("<",0));
            result = parseXMLName(result);
            result = parseXMLAttributes(result);
        }

        if(lookahead()==GREATERTHAN_TOKEN)
        {
            shift();
            if( !is_xmllist )
            {
                result = concatXML(result,nodeFactory.literalString(">",0));
            }
            result = parseXMLElementContent(result);
            if(lookahead()==EOS_TOKEN)
            {
                error(kError_Lexical_NoMatchingTag);
                return nodeFactory.error(scanner.input.positionOfMark(),kError_Lexical_NoMatchingTag);
            }
            match(XMLTAGSTARTEND_TOKEN); // "</"
            if( lookahead()==GREATERTHAN_TOKEN )
            {
                if( !is_xmllist )
                {
                    ctx.error(scanner.input.positionOfMark(),kError_MissingXMLTagName);
                }
            }
            else
            {
                result = concatXML(result,nodeFactory.literalString("</",0));
                result = parseXMLName(result);
                result = concatXML(result,nodeFactory.literalString(">",0));
            }
            match(GREATERTHAN_TOKEN);
        }
        else
        {
            match(XMLTAGENDEND_TOKEN)// "/>"
            result = concatXML(result,nodeFactory.literalString("/>",0));
        }
        this.is_xmllist = is_xmllist;
        return result;
    }

    Node concatXML(Node left, Node right)
    {
      Node tmpLeft = left;
       
      if (left instanceof ListNode && ((ListNode)left).size() == 1)
      {
        tmpLeft = ((ListNode)left).items.first();
      }

      // Concatenate strings
       
      if (tmpLeft instanceof LiteralStringNode && right instanceof LiteralStringNode)
      {
        return nodeFactory.literalString(((LiteralStringNode)tmpLeft).value + ((LiteralStringNode)right).value, left.pos());
      }

      // If the lhs is a + expression with a string literal rhs,
      // and the rhs is a string literal, turn (x+y)+z into x+(y+z)
      if (left instanceof BinaryExpressionNode && right instanceof LiteralStringNode)
      {
        BinaryExpressionNode leftBinary = (BinaryExpressionNode)left;
        if (leftBinary.op == PLUS_TOKEN && leftBinary.rhs instanceof LiteralStringNode)
        {
            return nodeFactory.binaryExpression(PLUS_TOKEN, leftBinary.lhs,
                nodeFactory.literalString(((LiteralStringNode)leftBinary.rhs).value + ((LiteralStringNode)right).value), leftBinary.pos());
        }
      }

      // Couldn't optimize, return ordinary binary expression
      return nodeFactory.binaryExpression(PLUS_TOKEN,left,right);
    }

    /*
     * XMLName
     *   : '{' <ExpressionList> '}'
     *   | XMLNAME
     *   ;
     *
     * XMLNAME: XMLNAMESTART XMLNAMECHAR*
     *
     * XMLNAMECHAR: [A-Z] | [0-9] | ':' | '_' | '.';
     * XMLNAMESTART: [A-z] | '_' | ':';
     */
   
    Node parseXMLName(Node first)
    {
        Node result;
        int lt = lookahead();
       
        if (lt==LEFTBRACE_TOKEN)
        {
            shift();
            scanner.pushState();     // save the state of the scanner
            result = concatXML(first,parseExpressionList(allowIn_mode));
            match(RIGHTBRACE_TOKEN);
            scanner.popState();      // restore the state of the scanner
        }
        else
        {
          // TODO: XMLname recognition is incorrect
          //
          // According to the XML standard, A name starts with
          // A-z_: (+unicode) followed by A-z0-9_:.- (+unicode)
          // ALso our rules allow whitespace, which is fundamentally wrong.
          // Though we're just packing a string really,
          // TODO: Replace all of this with an XML recognizer on the scan level.
         
            if (inXMLTokenSet(lt) || lt == COLON_TOKEN)
            {
              shift();
                result  = concatXML(first,nodeFactory.literalString(scanner.getCurrentTokenTextOrTypeText(lt),scanner.input.positionOfMark()));
            }
            else
            {
                error(ParseError.syntax,kError_ErrorNodeError,"invalid xml name");
                skiperror(ParseError.XML);
                result = nodeFactory.error(scanner.input.positionOfMark(),kError_MissingXMLTagName);
            }
           
            lt = lookahead();
            while( true )
            {
                String separator_text;
               
                if( lt == DOT_TOKEN )
                {  
                    separator_text = ".";
                }
                else if( lt == MINUS_TOKEN )
                {  
                    separator_text = "-";
                }
                else if( lt == COLON_TOKEN )
                {  
                    separator_text = ":";
                }
                else    break;

                shift();
                lt = lookahead();
               
                if (inXMLTokenSet(lt))
                {
                    result = concatXML(result,nodeFactory.literalString(separator_text,0));
                    result = concatXML(result,nodeFactory.literalString(scanner.getCurrentTokenTextOrTypeText(lt),scanner.input.positionOfMark()));
                    shift();
                    lt = lookahead();
                }
                else
                {
                    error(kError_MissingXMLTagName);
                    skiperror(ParseError.XML);
                    result = nodeFactory.error(scanner.input.positionOfMark(),kError_MissingXMLTagName);
                }
            }
        }
        return result;
    }

    Node parseXMLAttributes(Node first)
    {
        Node result = first;
        int lt = lookahead();
       
        while( !(lt==GREATERTHAN_TOKEN||lt==XMLTAGENDEND_TOKEN||lt==EOS_TOKEN) )
        {
            result = concatXML(result,nodeFactory.literalString(" ",0));
            result = parseXMLAttribute(result);
            lt = lookahead();
        }
        return result;
    }

    Node parseXMLAttribute(Node first)
    {
        Node result = parseXMLName(first);
       
        if (lookahead()==ASSIGN_TOKEN)
        {
            shift();

            Node value = null;
            boolean single_quote = false;

            if (lookahead()==STRINGLITERAL_TOKEN)
            {
                boolean[] is_single_quoted = new boolean[1];
                shift();
                String enclosedText = scanner.getCurrentStringTokenText(is_single_quoted);
                value = nodeFactory.literalString( enclosedText, scanner.input.positionOfMark(), is_single_quoted[0] );
                single_quote = is_single_quoted[0];
            }
            else if (lookahead()==LEFTBRACE_TOKEN)
            {
                shift();
                scanner.pushState();     // save the state of the scanner
                Node expr = parseExpressionList(allowIn_mode);
                value = nodeFactory.invoke("[[ToXMLAttrString]]",nodeFactory.argumentList(null,expr),0);
                match(RIGHTBRACE_TOKEN);
                scanner.popState();      // restore the state of the scanner
            }
            else
            {
                error(kError_ParserExpectingLeftBraceOrStringLiteral);
            }

            result = concatXML(result,nodeFactory.literalString(single_quote ? "='" : "=\"",0));

            result = concatXML(result,value);

            result = concatXML(result,nodeFactory.literalString(single_quote ? "'" : "\"",0));
        }

        return result;
    }

    Node parseXMLElementContent(Node first)
    {
        Node result = first;

        // begin xmlelementcontent

        scanner.pushState();

        scanner.state = xmltext_state;
        while( !(lookahead()==XMLTAGSTARTEND_TOKEN || lookahead()==EOS_TOKEN) )  // </
        {
            int lt = lookahead();
           
            if (lt==LEFTBRACE_TOKEN)
            {
                shift();
                scanner.pushState();     // save the state of the scanner
                Node expr = parseExpressionList(allowIn_mode);
                expr = nodeFactory.invoke("[[ToXMLString]]",nodeFactory.argumentList(null,expr),0);
                result = concatXML(result,expr);
                match(RIGHTBRACE_TOKEN);
                scanner.popState();      // restore the state of the scanner
            }
            else if (lt==LESSTHAN_TOKEN)
            {
                scanner.state = start_state;
                result = concatXML(result,parseXMLElement());
            }
            else if (lt==XMLMARKUP_TOKEN)
            {
                result  = concatXML(result,nodeFactory.literalString(scanner.getCurrentTokenTextOrTypeText(match(XMLMARKUP_TOKEN)),scanner.input.positionOfMark()));
            }
            else if (lt==XMLTEXT_TOKEN)
            {
                result  = concatXML(result,nodeFactory.literalString(scanner.getCurrentTokenTextOrTypeText(match(XMLTEXT_TOKEN)),scanner.input.positionOfMark()));
            }
            else
            {
                error(kError_MissingXMLTagName);
                skiperror(RIGHTBRACE_TOKEN);
                scanner.popState();
                return result;
            }
            scanner.state = xmltext_state;
        }
        scanner.popState();
        return result;
    }

/*
XMLElement
    <  XMLTagContent  />
    <  XMLTagContent  >  XMLElementContentopt  <  XMLTagContent  />

XMLTagContent
    XMLTagCharacters XMLTagContentopt
    =  Whitespaceopt  {  Expression  }  XMLTagContentopt
    {  Expression  }  XMLTagContentopt

XMLElementContent
    XMLMarkup  XMLElementContentopt
    XMLText  XMLElementContentopt
    {  Expression  }  XMLElementContentopt
*/

    /*
    public LiteralXMLNode parseXMLLiteral()
    {
        LiteralXMLNode result;
        ListNode first;
        if (lookahead(LESSTHAN_TOKEN))
        {
            match(LESSTHAN_TOKEN);
            first = nodeFactory.list(null, nodeFactory.literalString(scanner.getTokenText(match(XMLPART_TOKEN))));
            scanner.pushState();     // save the state of the scanner
            first = nodeFactory.list(first, parseListExpression(allowIn_mode));
            match(RIGHTBRACE_TOKEN);  // eat the expression escape character
            scanner.popState();      // restore the state of the scanner

            while (lookahead(XMLPART_TOKEN))
            {
                first = nodeFactory.list(first, nodeFactory.literalString(scanner.getTokenText(match(XMLPART_TOKEN))));
                scanner.pushState();
                first = nodeFactory.list(first, parseListExpression(allowIn_mode));
                match(RIGHTBRACE_TOKEN);  // eat the expression escape character
                scanner.popState();
            }
            first = nodeFactory.list(first, nodeFactory.literalString(scanner.getTokenText(match(XMLLITERAL_TOKEN))));
            result = nodeFactory.literalXML(first,scanner.input.positionOfMark());
        }
        else // xml markup
        {
//            first  = nodeFactory.List(0,nodeFactory.literalString(scanner.getTokenText(match(XMLMARKUP_TOKEN))));
//            result = nodeFactory.LiteralXML(first,scanner.input.positionOfMark());
            result = null;
        }
        return result;
    }
    */

    /*
     * ParenExpression
     *     '(' AssignmentExpression ')'
     */

    private Node parseParenExpression()
    {
        if (debug)
        {
            System.err.println("begin parseParenExpression");
        }

        Node result;

        match(LEFTPAREN_TOKEN);
        int mark = scanner.input.positionOfMark();
        result = parseAssignmentExpression(allowIn_mode);
        result.setPosition(mark);
        match(RIGHTPAREN_TOKEN);

        if (debug)
        {
            System.err.println("finish parseParenExpression");
        }

        return result;
    }

    /*
     * ParenExpressionList
     *     '(' ExpressionList ')'
     */

    private ListNode parseParenExpressionList()
    {  
        if (debug)
        {
            System.err.println("begin parseParenListExpression");
        }

        match(LEFTPAREN_TOKEN);
        ListNode result = parseExpressionList(allowIn_mode);
        match(RIGHTPAREN_TOKEN);

        if (debug)
        {
            System.err.println("finish parseParenListExpression");
        }

        return result;
    }

    /*
     * PrimaryExpressionOrExpressionQualifiedIdentifier
     *     ParenExpressionList ('::' Identifier)?
     *     PrimaryExpression
     */

    private Node parsePrimaryExpressionOrExpressionQualifiedIdentifier()
    {

        if (debug)
        {
            System.err.println("begin parsePrimaryExpressionOrExpressionQualifiedIdentifier");
        }

        Node result;

        if (lookahead()==LEFTPAREN_TOKEN)
        {
            ListNode first = parseParenExpressionList();
            result = first;
           
            if (HAS_EXPRESSIONQUALIFIEDIDS && lookahead()==DOUBLECOLON_TOKEN)
            {
                shift();
                if (first == null || first.size() != 1)
                {
                    result = error(kError_Parser_ExpectingASingleExpressionWithinParenthesis);
                    skiperror(ParseError.expression);
                }
                else
                {
                    result = nodeFactory.qualifiedIdentifier(first.items.last(), parseIdentifierString(), scanner.input.positionOfMark());
                    result = nodeFactory.memberExpression(null, nodeFactory.getExpression(result));
                }
            }
        }
        else
        {
            result = parsePrimaryExpression();
        }

        if (debug)
        {
            System.err.println("finish parsePrimaryExpressionOrExpressionQualifiedIdentifier");
        }

        return result;
    }

    /*
     * FunctionCommon:
     *   (<ConstructorSignature>|<FunctionSignature>) (<Block> | Semicolon)
     *
     * If in a class and first is non-null and equal to classname, then this is a constructor
     * else it is a function.
     */

    private FunctionCommonNode parseFunctionCommon(IdentifierNode first)
    {
        if (debug)
        {
            System.err.println("begin parseFunctionCommon");
        }

        FunctionCommonNode result;
        FunctionSignatureNode second;
        StatementListNode third = null;

        boolean saved_has_arguments = nodeFactory.has_arguments;  // for nested functions
        boolean saved_has_rest = nodeFactory.has_rest;  // for nested functions
        boolean saved_has_dxns = nodeFactory.has_dxns;  //

        nodeFactory.has_arguments = false// set by Identifier, captured by FunctionCommon
        nodeFactory.has_rest = false// set by RestParameterNode, captured by FunctionCommon
        nodeFactory.has_dxns = false;

        boolean is_ctor = false;
        if (ctx.statics.es4_nullability && block_kind_stack.last() == CLASS_TOKEN
                && first != null && first.name.equals(current_class_name)) {
            is_ctor = true;
        }

        block_kind_stack.add(FUNCTION_TOKEN);

        second = (is_ctor)
            ? parseConstructorSignature()
            : parseFunctionSignature();

        DefaultXMLNamespaceNode saved_dxns = nodeFactory.dxns;

        //nodeFactory.StartClassDefs();

        if (lookahead()==LEFTBRACE_TOKEN)
        {
            third = parseBlock();

            if (!AVMPLUS)
            {
                third = nodeFactory.statementList(third, nodeFactory.returnStatement(null, scanner.input.positionOfMark()));
            }

            if ( third == null )
            {
                // Function had an empty body.  Create an empty list to represent { }
                third = nodeFactory.statementList(null, null);
            }
        }
        else
        {
            matchSemicolon(abbrevFunction_mode);
        }

        // Append a default return statement with the line number at the position of the } (happens in nodeFactory->FunctionCommon)
        result = nodeFactory.functionCommon(ctx,first,second,third,first!=null?first.pos():second.pos());
        result.default_dxns = nodeFactory.has_dxns?null:saved_dxns;

        nodeFactory.has_arguments = saved_has_arguments;
        nodeFactory.has_rest = saved_has_rest;
        nodeFactory.has_dxns = saved_has_dxns;

        //nodeFactory.FinishClassDefs();
        block_kind_stack.removeLast();

        if (debug)
        {
            System.err.println("finish parseFunctionCommon");
        }

        return result;
    }

    /*
     * ObjectLiteral
     *     '{' LiteralField,* '}'
     */

    private Node parseObjectLiteral()
    {
        if (debug)
        {
            System.err.println("begin parseObjectLiteral");
        }

        Node result;
        ArgumentListNode first = null;

        int pos = scanner.input.positionOfMark();

        match(LEFTBRACE_TOKEN);

        if (lookahead()==RIGHTBRACE_TOKEN)
        {
            shift();
        }
        else
        {
          while(true)
          {
              Node t = parseLiteralField();
             
              if (t!=null)
              {
                first = nodeFactory.argumentList(first,t);
              }
             
              if (lookahead()!=COMMA_TOKEN)
              break;
           
            shift();
          }        
            match(RIGHTBRACE_TOKEN);
        }

        result = nodeFactory.literalObject(first,pos);

        if (debug)
        {
            System.err.println("finish parseObjectLiteral with result = ");
        }

        return result;
    }

    /*
     * LiteralField
     *     FieldOrConfigName (configname & !':'oddity FieldOrConfigName)? ':' AssignmentExpression
     */

    private Node parseLiteralField()
    {
        if (debug)
        {
            System.err.println("begin parseLiteralField");
        }

        Node result;
        Node first;
        Node second;
        ListNode l = null;

        first = parseFieldOrConfigName();
        if( first.isConfigurationName() && lookahead()!=COLON_TOKEN )
        {
          // If we got back a configuration name, then
          // we need to parse the actual name
          // e.g. {... CONFIG::Debug y:val ... }
         
          l = nodeFactory.list(null, first);
          first = parseFieldOrConfigName();
        }
        match(COLON_TOKEN);
       
        second = parseAssignmentExpression(allowIn_mode);
        result = nodeFactory.literalField(first, second);

        if( l != null )
        {
          result = nodeFactory.list(l, result);
        }
       
        if (debug)
        {
            System.err.println("finish parseLiteralField");
        }

        return result;
    }

    /*
     * FieldOrConfigName
     *     string
     *     number
     *     ParenExpression
     *     Identifier ('::' Identifier)?
     */

    private Node parseFieldOrConfigName()
    {

        if (debug)
        {
            System.err.println("begin parseFieldName");
        }

        Node result;
        final int lt = lookahead();
       
        if (HAS_NONIDENTFIELDNAMES && lt==STRINGLITERAL_TOKEN)
        {
            boolean[] is_single_quoted = new boolean[1];
            shift();
            String enclosedText = scanner.getCurrentStringTokenText(is_single_quoted);
            result = nodeFactory.literalString( enclosedText, scanner.input.positionOfMark(), is_single_quoted[0] );
        }
        else if (HAS_NONIDENTFIELDNAMES && lt==NUMBERLITERAL_TOKEN)
        {
          shift();
            result = nodeFactory.literalNumber(scanner.getCurrentTokenText(),scanner.input.positionOfMark());
        }
        else if (HAS_NONIDENTFIELDNAMES && lt==LEFTPAREN_TOKEN)
        {
            result = parseParenExpression();
        }
        else
        {
          IdentifierNode ident = parseIdentifier();
            assert config_namespaces.size() > 0;
            if( config_namespaces.last().contains(ident.name) && lookahead()==DOUBLECOLON_TOKEN)
            {
              shift();
              QualifiedIdentifierNode qualid = nodeFactory.qualifiedIdentifier(ident, parseIdentifierString(),scanner.input.positionOfMark());
              qualid.is_config_name = true;
              result = qualid;
            }
            else
            {
              result = ident;
            }
        }

        if (debug)
        {
            System.err.println("finish parseFieldName");
        }

        return result;
    }

    /*
     * ArrayLiteral
     *     [ ElementList? ]
     */

    private LiteralArrayNode parseArrayLiteral()
    {
        if (debug)
        {
            System.err.println("begin parseArrayLiteral");
        }
   
        LiteralArrayNode result;
        ArgumentListNode initializer_list = null;
        int pos = scanner.input.positionOfMark();

        match(LEFTBRACKET_TOKEN);
        if (RIGHTBRACKET_TOKEN != lookahead())
        {
          initializer_list = parseElementList(true);
        }
        result = nodeFactory.literalArray(initializer_list,pos);
        match(RIGHTBRACKET_TOKEN);

        if (debug)
        {
            System.err.println("finish parseArrayLiteral");
        }
       
        return result;
    }
   
    /*
     * VectorLiteral
     *     '<' TypeExpressionList '>' '[' ElementList ']'
     */
   
    private LiteralVectorNode parseVectorLiteral()
    {
        if (debug)
        {
            System.err.println("begin parseVectorLiteral");
        }
   
        ArgumentListNode initializer_list = null;
        int pos = scanner.input.positionOfMark();
               
        match(LESSTHAN_TOKEN);
        ListNode type_list = parseTypeExpressionList();
        Node vector_type = nodeFactory.applyTypeExpr(nodeFactory.identifier("Vector", false, pos), type_list, pos);
        match(GREATERTHAN_TOKEN);
       
        match(LEFTBRACKET_TOKEN);
        if (RIGHTBRACKET_TOKEN != lookahead())
        {
          initializer_list = parseElementList(false);
        }
        match(RIGHTBRACKET_TOKEN);

        LiteralVectorNode result = nodeFactory.literalVector(vector_type, initializer_list, pos);

        if (debug)
        {
            System.err.println("finish parseVectorLiteral");
        }
       
        return result;
    }

    /*
     * ElementList
     *     LiteralElement,*
     */
    private ArgumentListNode parseElementList(boolean allow_empty)
    {
        if (debug)
        {
            System.err.println("begin parseElementList");
        }

        ArgumentListNode result = null;
       
        while(true)
        {
          Node t = parseLiteralElement(allow_empty);
           
          if( t != null )
            {
                result = nodeFactory.argumentList(result, t);
            }
         
          if (lookahead()!=COMMA_TOKEN)
            break;
       
          shift();
        }

        if (debug)
        {
            System.err.println("finish parseElementList");
        }

        return result;
    }
   
    /*
     * LiteralElement
     *     AssignmentExpression (AssignmentExpression)?
     *     empty
     */

    private Node parseLiteralElement(boolean allow_empty)
    {
        if (debug)
        {
            System.err.println("begin parseLiteralElement");
        }

        Node result;
        Node first;
        int lt = lookahead();
       
        if(lt==COMMA_TOKEN && allow_empty)
        { 
            result = nodeFactory.emptyElement(scanner.input.positionOfMark());
        }
        else if(lt==RIGHTBRACKET_TOKEN)
        {
            result = null;
        }
        else
        {
          first = parseAssignmentExpression(allowIn_mode);
          lt = lookahead();
          if( first.isConfigurationName() && lt!=COMMA_TOKEN && lt!=RIGHTBRACKET_TOKEN )
          {
            // We have an element with a config attr i.e.
            // [..., CONFIG::Debug 4, ...]
            ListNode list = nodeFactory.list(null, first);
            result = nodeFactory.list(list, parseAssignmentExpression(allowIn_mode));
          }
          else
          {
            result = first;
          }
        }

        if (debug)
        {
            System.err.println("finish parseLiteralElement");
        }

        return result;
    }

    /*
     * SuperExpression
     *     'super' ParenExpression?
     */

    private Node parseSuperExpression()
    {
        if (debug)
        {
            System.err.println("begin parseSuperExpression");
        }

        int pos = scanner.input.positionOfMark();
        shift(); //match(SUPER_TOKEN);
        Node first = null;
        if (lookahead()==LEFTPAREN_TOKEN)
        {
            first = parseParenExpression();
        }
        Node result = nodeFactory.superExpression(first,pos);

        if (debug)
        {
            System.err.println("finish parseSuperExpression");
        }

        return result;
    }

   
    /*
     * precedence:
     */
   
    private final int precedence( int token, int mode )
    {
    /*
     * For the context "for ( <dcl|expr> ... IN"
     * We drop the precedence of 'IN' to 0, shutting off operator precedence parsing.
     */
     
      if (token==IN_TOKEN && mode == noIn_mode)
        return 0;
     
      int prec = binary_precedence[-token];
      return prec;
    }
   
    /*
     * BinaryExpression
     *     UnaryExpression (%prec(op) BinaryExpression)?
     */
   
    private Node parseBinaryExpression(int mode, int prec)
    {
      Node result = parseUnaryExpression();
     
      /*
       * Operator precedence parser
       *   refer to Vaughan Pratt, "top down operator precedence parsing"
       * or Dijkstra's shunting yard algorithm, or precedence climbing.
       *
       */
     
      int op = lookahead();
      int p1 = precedence(op,mode);
      int p2 = p1;
      for (; p1 >= prec; p1--)
      {
           while ( p2==p1 )
          {
             shift();
            
             Node t = parseBinaryExpression(mode,p1+1);
            
             // Could fold fully constant expressions here.
            
             result = nodeFactory.binaryExpression(op, result, t);
             op = lookahead();
             p2 = precedence(op,mode);
          }
      }
      return result;
    }
   
    /*
     * PostfixExpression
     */

    private Node parsePostfixExpression()
    {
        if (debug)
        {
            System.err.println("begin parsePostfixExpression");
        }

        Node first;
        Node result;
        int lt = lookahead();

        switch ( lt )
        {
        case PUBLIC_TOKEN: case PRIVATE_TOKEN: case PROTECTED_TOKEN: case DEFAULT_TOKEN:
        case GET_TOKEN: case SET_TOKEN: case IDENTIFIER_TOKEN: case NAMESPACE_TOKEN:
        case MULT_TOKEN: case ATSIGN_TOKEN:
            first = parseAttributeExpression();
            lt = lookahead();
            if ( (lt == PLUSPLUS_TOKEN || lt == MINUSMINUS_TOKEN) && !lookaheadSemicolon(full_mode) )
            {
                first = parsePostfixIncrement(first);
            }
            break;
           
        case NULL_TOKEN: case TRUE_TOKEN: case FALSE_TOKEN: case NUMBERLITERAL_TOKEN:
        case STRINGLITERAL_TOKEN: case THIS_TOKEN: case REGEXPLITERAL_TOKEN: case LEFTPAREN_TOKEN:
        case LEFTBRACKET_TOKEN: case LEFTBRACE_TOKEN: case FUNCTION_TOKEN:
            first = parsePrimaryExpressionOrExpressionQualifiedIdentifier();
            break;
           
        case SUPER_TOKEN:   
            first = parseSuperExpression();
            break;
           
        case NEW_TOKEN:
            first = parseShortNewExpression();
      
            //  LiteralVectorNode shares some syntax
            //  with a new call, but its semantics
            //  are different; it's its own constructor.
           
            if ( ! (first instanceof LiteralVectorNode) )
            {
              if (lookahead()==LEFTPAREN_TOKEN)
              {
                  first = parseArguments(first);
              }
              else
              {
                  first = nodeFactory.callExpression(first, null);
              }
 
              first = nodeFactory.newExpression(first)// translates call to new
              if ( !lookaheadSemicolon(full_mode) && ((lookahead()==PLUSPLUS_TOKEN || lookahead()==MINUSMINUS_TOKEN)))
              {
                  first = parsePostfixIncrement(first);
              }
            }
            break;
           
        default:
            first = parseFullNewSubexpression();
            if (lookahead()==LEFTPAREN_TOKEN)
            {
                first = parseArguments(first);
            }   
        }
        result = parseFullPostfixExpressionPrime(first);

        if (debug)
        {
            System.err.println("finish parsePostfixExpression");
        }

        return result;
    }

    /*
     * PostfixIncrement
     *     <first> ('++'|'--')
     */

    private Node parsePostfixIncrement(Node first)
    {
        if (debug)
        {
            System.err.println("begin parsePostfixIncrement");
        }

        Node result;
        final int lt = lookahead();
       
        if (lt==PLUSPLUS_TOKEN || lt==MINUSMINUS_TOKEN)
        {
          shift();
            result = nodeFactory.postfixExpression(lt, first,scanner.input.positionOfMark());
        }
        else
        {
            result = error(kError_Parser_ExpectingIncrOrDecrOperator);
            skiperror(ParseError.syntax);
        }

        if (debug)
        {
            System.err.println("finish parsePostfixIncrement");
        }

        return result;
    }

    /*
     * FullPostfixExpressionPrime
     *
     *   la == ('.'|'.<'|'{'|'..')   -> <PropertyOperator> <FullPostfixExpressionPrime>
     *  la == '('           -> <Arguments> FullPostfixExpressionPrime>
     *  la == '++' | '--'       -> <PostfixIncrement> <FullPostfixExpression>
     *  -> nil
     * 
     *     PropertyOperator FullPostfixExpressionPrime
     *     Arguments FullPostfixExpressionPrime
     *     FullPostfixExpressionIncrementExpressionSuffix
     *     empty
     */

    private Node parseFullPostfixExpressionPrime(Node first)
    {
        if (debug)
        {
            System.err.println("begin parseFullPostfixExpressionPrime");
        }

        Node result = first;
        final int lt = lookahead();

        if (lt==DOT_TOKEN || lt==LEFTBRACKET_TOKEN || lt==DOTLESSTHAN_TOKEN || (HAS_DESCENDOPERATORS && lt==DOUBLEDOT_TOKEN))
        {
            first = parsePropertyOperator(first);
            result = parseFullPostfixExpressionPrime(first);
        }
        else if (lt==LEFTPAREN_TOKEN)
        {
            first = parseArguments(first);
            result = parseFullPostfixExpressionPrime(first);
        }
        else if ( !lookaheadSemicolon(full_mode) && ((lt==PLUSPLUS_TOKEN || lt==MINUSMINUS_TOKEN)))
        {
            first = parsePostfixIncrement(first);
            result = parseFullPostfixExpressionPrime(first);
        }

        if (debug)
        {
            System.err.println("finish parseFullPostfixExpressionPrime");
        }

        return result;
    }

    /*
     * AttributeExpression
     *    SimpleQualifiedIdentifier
     *    AttributeExpression PropertyOperator
     *    AttributeExpression Arguments
     */

    private Node parseAttributeExpression()
    {
        if (debug)
        {
            System.err.println("begin parseAttributeExpression");
        }

        Node result;
        Node first;

        IdentifierNode ident = parseSimpleQualifiedIdentifier();
    /*
    if( ident.name.equals("*") )
        {
            ctx.error(scanner.input.positionOfMark()-2,kError_InvalidWildcardIdentifier);
        }
    */
        first = nodeFactory.memberExpression(null, nodeFactory.getExpression(ident));
       
        final int lt = lookahead();
       
        if (lt==DOT_TOKEN || lt==LEFTBRACKET_TOKEN || lt==DOUBLEDOT_TOKEN || lt==LEFTPAREN_TOKEN || lt==ATSIGN_TOKEN)   
        {
            result = parseAttributeExpressionPrime(first);
        }
        else
        {
//            MemberExpressionNode memb = first instanceof MemberExpressionNode ? (MemberExpressionNode) first : null;
//            if( memb != null && memb.selector.is_package )
//            {
//                IdentifierNode id = memb.selector.expr instanceof IdentifierNode ? (IdentifierNode) memb.selector.expr : null;
//                if( id != null )
//                {
//                    ctx.error(memb.selector.expr.pos(),kError_IllegalPackageReference, id.name);
//                }
//                memb.selector.is_package = false; // hack, to avoid reporting same error later
//            }
            result = first;
        }

        if (debug)
        {
            System.err.println("finish parseAttributeExpression");
        }

        return result;
    }

    private Node parseAttributeExpressionPrime(Node first)
    {
        if (debug)
        {
            System.err.println("begin parseAttributeExpressionPrime");
        }

        Node result;
        final int lt = lookahead();
       
        if (lt==DOT_TOKEN || lt==DOUBLEDOT_TOKEN || lt==LEFTBRACKET_TOKEN || lt==DOTLESSTHAN_TOKEN)
        {
            result = parseAttributeExpressionPrime(parsePropertyOperator(first));
        }
        else if (lt==LEFTPAREN_TOKEN) // Arguments
        {
/*
            MemberExpressionNode memb = first instanceof MemberExpressionNode ? (MemberExpressionNode) first : null;
            if( memb != null && memb.selector.is_package )
            {
                IdentifierNode ident = memb.selector.expr instanceof IdentifierNode ? (IdentifierNode) memb.selector.expr : null;
                if( ident != null )
                {
                    ctx.error(memb.selector.expr.pos(),kError_IllegalPackageReference, ident.name);
                    memb.selector.is_package = false; // to avoid redundant errors
                }
            }
*/
            result = parseAttributeExpressionPrime(parseArguments(first));
        }
        else  // empty
        {
/*
            MemberExpressionNode memb = first instanceof MemberExpressionNode ? (MemberExpressionNode) first : null;
            if( memb != null && memb.selector.is_package )
            {
                IdentifierNode ident = memb.selector.expr instanceof IdentifierNode ? (IdentifierNode) memb.selector.expr : null;
                if( ident != null )
                {
                    ctx.error(memb.selector.expr.pos(),kError_IllegalPackageReference, ident.name);
                }
            }
*/
            result = first;
        }

        if (debug)
        {
            System.err.println("finish parseAttributeExpressionPrime");
        }

        return result;
    }

    /*
     * FullNewExpression
     *     'new' FullNewSubexpression Arguments
     */

    private Node parseFullNewExpression()
    {
        if (debug)
        {
            System.err.println("begin parseFullNewExpression");
        }

        shift(); //match(NEW_TOKEN);
        Node first = parseFullNewSubexpression();
        Node result = nodeFactory.newExpression(parseArguments(first));

        if (debug)
        {
            System.err.println("finish parseFullNewExpression");
        }

        return result;
    }

    /*
     * FullNewSubexpression
     *     PrimaryExpression FullNewSubexpressionPrime
     *     QualifiedIdentifier FullNewSubexpressionPrime
     *     FullNewExpression FullNewSubexpressionPrime
     *     SuperExpression PropertyOperator FullNewSubexpressionPrime
     */

    private Node parseFullNewSubexpression()
    {
        if (debug)
        {
            System.err.println("begin parseFullNewSubexpression");
        }

        Node result;
        Node first;

        switch ( lookahead() )
        {
        case NEW_TOKEN:
            first = parseFullNewExpression();
            if ( first instanceof LiteralVectorNode )
              result = first;
            else
              result = parseFullNewSubexpressionPrime(first);
            break;
           
        case SUPER_TOKEN:
            first = parseSuperExpression();
            first = parsePropertyOperator(first);
            result = parseFullNewSubexpressionPrime(first);
            break;
           
        case LEFTPAREN_TOKEN:
            first = parsePrimaryExpressionOrExpressionQualifiedIdentifier();
            result = parseFullNewSubexpressionPrime(first);
            break;
           
        case PUBLIC_TOKEN: case PRIVATE_TOKEN: case PROTECTED_TOKEN: case DEFAULT_TOKEN:
        case GET_TOKEN: case SET_TOKEN: case NAMESPACE_TOKEN: case MULT_TOKEN:
        case IDENTIFIER_TOKEN: case ATSIGN_TOKEN:
            first = nodeFactory.memberExpression(null, nodeFactory.getExpression(parseQualifiedIdentifier()));
            result = parseFullNewSubexpressionPrime(first);
            break;
            
        default:
            first = parsePrimaryExpression();
            result = parseFullNewSubexpressionPrime(first);     
        }

        if (debug)
        {
            System.err.println("finish parseFullNewSubexpression");
        }

        return result;
    }

    /*
     * FullNewSubexpressionPrime
     *     PropertyOperator FullNewSubexpressionPrime
     *     empty
     */

    private Node parseFullNewSubexpressionPrime(Node first)
    {
        if (debug)
        {
            System.err.println("begin parseFullNewSubexpressionPrime");
        }

        Node result = first;
        final int lt = lookahead();

        if (lt==DOT_TOKEN || lt==LEFTBRACKET_TOKEN || lt==DOTLESSTHAN_TOKEN ||
            (HAS_DESCENDOPERATORS && lt==DOUBLEDOT_TOKEN) || lt==ATSIGN_TOKEN )
        {
            first = parsePropertyOperator(first);
            result = parseFullNewSubexpressionPrime(first);
        }

        if (debug)
        {
            System.err.println("finish parseFullNewSubexpressionPrime");
        }

        return result;
    }

    /*
     * ShortNewExpression
     *     'new' VectorLiteral
     *     'new' ShortNewSubexpression
     */

    private Node parseShortNewExpression()
    {
        if (debug)
        {
            System.err.println("begin parseShortNewExpression");
        }

        Node result;

        match(NEW_TOKEN);
        if ( LESSTHAN_TOKEN == lookahead() )
        {
          result = parseVectorLiteral();
        }
        else
        {
          result = parseShortNewSubexpression();
        }

        if (debug)
        {
            System.err.println("finish parseShortNewExpression");
        }

        return result;
    }

    /*
     * ShortNewSubexpression
     *     FullNewSubexpression
     *     ShortNewExpression Arguments?
     */

    private Node parseShortNewSubexpression()
    {
        if (debug)
        {
            System.err.println("begin parseShortNewSubexpression");
        }

        Node result;

        // Implement branch into ShortNewExpression
        if (lookahead()==NEW_TOKEN)
        {
            result = parseShortNewExpression();
            if (lookahead()==LEFTPAREN_TOKEN)
            {
                result = parseArguments(result);
            }
            result = nodeFactory.newExpression(result);
        }
        else
        {
            result = parseFullNewSubexpression();
        }

        if (debug)
        {
            System.err.println("finish parseShortNewSubexpression");
        }

        return result;
    }

    /*
     * PropertyOperator
     *     '.' '(' ExpressionList[AllowIn] ')'
     *     '.' QualifiedIdentifier
     *     Brackets
     *     '..' QualifiedIdentifier
     *     '.<' TemplatizedTypeExpression '>'
     */

    private Node parsePropertyOperator(Node first)
    {
        if (debug)
        {
            System.err.println("begin parsePropertyOperator");
        }

        Node result = null;
        int lt = lookahead();
       
        if (lt==DOT_TOKEN)
        {
            shift();
            if (lookahead()==LEFTPAREN_TOKEN)
            {
                shift();
                result = nodeFactory.filterOperator(first,parseExpressionList(allowIn_mode),first.pos());
                match(RIGHTPAREN_TOKEN);
            }
            else
            {
                result = nodeFactory.memberExpression(first, nodeFactory.getExpression(parseQualifiedIdentifier()));
            }
        }
        else if (lt==LEFTBRACKET_TOKEN)
        {
            result = parseBrackets(first);
        }
        else if (lt==DOUBLEDOT_TOKEN)
        {
            shift();
            SelectorNode selector = nodeFactory.getExpression(parseQualifiedIdentifier());
            selector.setMode(DOUBLEDOT_TOKEN);
            result = nodeFactory.memberExpression(first, selector);
        }
        else if (lt==DOTLESSTHAN_TOKEN)
        {
          result = parseTemplatizedTypeExpression(first);
        }

        if (debug)
        {
            System.err.println("finish parsePropertyOperator");
        }

        return result;
    }

    /*
     * Brackets
     *     '[' ArgumentsWithRest[allowIn] ']'
     */

    private MemberExpressionNode parseBrackets(Node first)
    {
        if (debug)
        {
            System.err.println("begin parseBrackets");
        }

        MemberExpressionNode result;
        ArgumentListNode second;

        match(LEFTBRACKET_TOKEN);

        if (lookahead()==RIGHTBRACKET_TOKEN)
        {
            error(kError_Lexical_SyntaxError);
            second = null;
        }
        else
        {
            second = parseArgumentsWithRest(allowIn_mode);
            second.is_bracket_selector = true;
        }

        match(RIGHTBRACKET_TOKEN);
        result = nodeFactory.indexedMemberExpression(first, nodeFactory.getExpression(second));
       
        if (debug)
        {
            System.err.println("finish parseBrackets");
        }

        return result;
    }

    /*
     * Arguments
     *     '(' ArgumentsWithRest[allowIn]* ')'
     */

    private Node parseArguments(Node first)
    {
        if (debug)
        {
            System.err.println("begin parseArguments");
        }

        match(LEFTPAREN_TOKEN);
        ArgumentListNode args = (lookahead()==RIGHTPAREN_TOKEN) ? null : parseArgumentsWithRest(allowIn_mode);
        match(RIGHTPAREN_TOKEN);
       
        Node result = nodeFactory.callExpression(first, args); // Note that a call node is built here.

        if (debug)
        {
            System.err.println("finish parseArguments");
        }

        return result;
    }

    /*
     *  ArgumentsWithRest
     *      ('...'? AssignmentExpression),+
     */

    private ArgumentListNode parseArgumentsWithRest(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseArgumentsWithRest");
        }

       //  (RestExpression | AssignmentExpr),+

        ArgumentListNode result = null;

        while (true)
        {
            Node t = null;

            /*
             * RestOrAssigmentExpression ->
             *     '...' AssignmentExpression[allowIn]
             *     AssignmentExpression[mode]
             */
           
            if (lookahead()==TRIPLEDOT_TOKEN)
            {
                shift(); //match(TRIPLEDOT_TOKEN);
                t = nodeFactory.restExpression(parseAssignmentExpression(allowIn_mode));
            }
            else
            {
              t = parseAssignmentExpression(mode);
            }
           
          if (t!=null)
            result = nodeFactory.argumentList(result, t);
         
          if (lookahead()!=COMMA_TOKEN)
            break;
         
          shift();
        }

        if (debug)
        {
            System.err.println("finish parseArgumentsWithRest with " + ((result != null) ? result.toString() : ""));
        }

        return result;
    }

    /*
     * UnaryExpression
     *     'delete' PostfixExpression
     *     ('typeof' | '++' | '--' | '+' | '~' | '!' ) UnaryExpression
     *     'void' unaryExpression?
     *     '-' (negminlongliteral | UnaryExpression)
     */

    private Node parseUnaryExpression()
    {
        if (debug)
        {
            System.err.println("begin parseUnaryExpression");
        }

        Node result = null;
        int pos;
        final int op = lookahead();
       
        switch ( op )
        {
        case DELETE_TOKEN:
            shift();
            lookahead();
            result = nodeFactory.unaryExpression(op, parsePostfixExpression(),scanner.input.positionOfMark());
            break;
                  
        case TYPEOF_TOKEN:
        case PLUSPLUS_TOKEN:
        case MINUSMINUS_TOKEN:
        case PLUS_TOKEN:
        case BITWISENOT_TOKEN:
        case NOT_TOKEN:   
            shift();
            lookahead();
            result = nodeFactory.unaryExpression(op, parseUnaryExpression(), scanner.input.positionOfMark());
            break;
           
        case VOID_TOKEN:
            shift();
            int la = lookahead();
            pos = scanner.input.positionOfMark();
            result = ( la==COMMA_TOKEN || la==SEMICOLON_TOKEN || la==RIGHTPAREN_TOKEN )
                ? nodeFactory.unaryExpression(op, nodeFactory.literalNumber("0",pos),pos)
                : nodeFactory.unaryExpression(op, parseUnaryExpression(), pos);
            break;
        case MINUS_TOKEN:
            shift();
            if (lookahead()==NEGMINLONGLITERAL_TOKEN)
            {
              shift();
              Node lit = nodeFactory.literalNumber(scanner.getCurrentTokenText(),scanner.input.positionOfMark());
              result = nodeFactory.unaryExpression(op,lit,scanner.input.positionOfMark());
            }
            else
            {
              result = nodeFactory.unaryExpression(op, parseUnaryExpression(), scanner.input.positionOfMark());
            }
            break;

        default:
          result = parsePostfixExpression();
        }

        if (debug)
        {
            System.err.println("finish parseUnaryExpression");
        }

        return result;
    }

    /*
     * ConditionalExpression
     *     BinaryExpression ('?' AssignmentExpression ':' AssignmentExpression)?
     */

    private Node parseConditionalExpression(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseConditionalExpression");
        }

        Node first = parseBinaryExpression(mode,4);
        Node result = first;

        if (lookahead()==QUESTIONMARK_TOKEN)
        {
            shift();
            Node second = parseAssignmentExpression(mode);
            match(COLON_TOKEN);
            Node third = parseAssignmentExpression(mode);
            result = nodeFactory.conditionalExpression(first, second, third);
        }

        if (debug)
        {
            System.err.println("finish parseConditionalExpression with " + ((result != null) ? result.toString() : ""));
        }

        return result;
    }

    /*
     * NonAssignmentExpression
     *     BinaryExpression ('?' NonAssignmentExpression ':' NonAssignmentExpression)?
     */

    private Node parseNonAssignmentExpression(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseNonAssignmentExpression");
        }

        Node first = parseBinaryExpression(mode,4);
        Node result = first;

        if (lookahead()==QUESTIONMARK_TOKEN)
        {
            shift();
            Node second = parseNonAssignmentExpression(mode);
            match(COLON_TOKEN);
            Node third = parseNonAssignmentExpression(mode);
            result = nodeFactory.conditionalExpression(first, second, third);
        }

        if (debug)
        {
            System.err.println("finish parseNonAssignmentExpression with " + ((result != null) ? result.toString() : ""));
        }

        return result;
    }

    /*
     * AssignmentExpression(mode)
     *     ConditionalExpression
     *     SuperExpression CompoundAssignmentExpressionSuffix(mode)
     *     PostfixExpression AssignmentExpressionSuffix(mode)
     *
     * AssignmentExpressionSuffix(mode)
     *       CompoundAssignmentExpressionSuffix(mode)
     *       LogicalAssignment AssignmentExpression(mode)
     *       = AssigmentExpression(mode)
     *
     * CompoundAssignmentExpressionSuffix(mode)
     *     CompoundAssignment SuperExpression
     *     CompoundAssignment AssignmentExpression(mode)
     */

    private Node parseAssignmentExpression(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseAssignmentExpression");
        }

        Node first = parseConditionalExpression(mode);
        Node result = parseAssignmentExpressionSuffix(mode, first);

        if (debug)
        {
            System.err.println("finish parseAssignmentExpression with " + ((result != null) ? result.toString() : ""));
        }

        return result;
    }

    private Node parseAssignmentExpressionSuffix(int mode, Node first)
    {

        if (debug)
        {
            System.err.println("begin parseAssignmentExpressionSuffix");
        }

        Node result = first;
        final int lt = lookahead();
       
        switch ( lt )
        {
       
        //TODO: These sorts of special cases could be handled in the scanner.
       
        case LOGICALANDASSIGN_TOKEN: case LOGICALXORASSIGN_TOKEN: case LOGICALORASSIGN_TOKEN:
            if (HAS_LOGICALASSIGNMENT==false)
            {
                break;
            }
        case ASSIGN_TOKEN: case MULTASSIGN_TOKEN: case DIVASSIGN_TOKEN:
        case MODULUSASSIGN_TOKEN: case PLUSASSIGN_TOKEN: case MINUSASSIGN_TOKEN:
        case LEFTSHIFTASSIGN_TOKEN: case RIGHTSHIFTASSIGN_TOKEN: case UNSIGNEDRIGHTSHIFTASSIGN_TOKEN:
        case BITWISEANDASSIGN_TOKEN: case BITWISEXORASSIGN_TOKEN: case BITWISEORASSIGN_TOKEN:
            shift();
            Node third = parseAssignmentExpression(mode);
            result = nodeFactory.assignmentExpression(first, lt, third);
            break;
        }
     
        if (debug)
        {
            System.err.println("finish parseAssignmentExpressionSuffix with " + ((result != null) ? result.toString() : ""));
        }

        return result;
    }

    /*
     * ExpressionList
     *     AssignmentExpression,*
     */

    private ListNode parseExpressionList(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseExpressionList");
        }

        ListNode result = null;
       
        while (true)
        {
          Node t = parseAssignmentExpression(mode);
       
          if (t != null)
            result = nodeFactory.list(result,t);
         
          if (lookahead()!=COMMA_TOKEN)
            break;
         
          shift();
        }

        if (debug)
        {
            System.err.println("finish parseExpressionList with " + ((result != null) ? result.toString() : ""));
        }

        return result;
    }

    private ListNode parseListExpressionPrime(int mode, ListNode list)
    {
      // TODO: ??? this method is only used by Super() call to get the rest of a list packaged up.
      //??? it should be renamed or something. -not a big deal.
        if (debug)
        {
            System.err.println("begin parseListExpressionPrime");
        }

        ListNode result = list;

        // , AssignmentExpression ListExpressionPrime

        while (lookahead()==COMMA_TOKEN)
        {
            shift();
            Node t = parseAssignmentExpression(mode);
            nodeFactory.list(list, t);
        }

        if (debug)
        {
            System.err.println("finish parseListExpressionPrime with " + ((result != null) ? result.toString() : ""));
        }

        return result;
    }

    /*
     * NonAttributeQualifiedExpression:
     *     '(' ExpressionQualifiedIdentifier ')'
     *     SimpleQualifiedIdentifier
     */
   
    private IdentifierNode parseNonAttributeQualifiedExpression()
    {
        if (debug)
        {
            System.err.println("begin parseNonAttributeQualifiedExpression");
        }
       
        IdentifierNode result = (lookahead()==LEFTPAREN_TOKEN)
            ? parseExpressionQualifiedIdentifier()
            : parseSimpleQualifiedIdentifier();

        if (debug)
        {
            System.err.println("finish parseNonAttributeQualifiedExpression");
        }

        return result;
    }

    /*
     * SimpleTypeIdentifier
     *     NonAttributeQualifiedExpression
     *     SimpleTypeIdentifier '.' NonAttributeQualifiedExpression
     */
   
    // TODO: Heck of a misnomer, should be something like member (get (non attribute qualified expr)))+
    // Also odd that everything must have a get AND a member node built over it...
   
    private Node parseSimpleTypeIdentifier()
    {
        if (debug)
        {
            System.err.println("begin parseSimpleTypeIdentifier");
        }
       
        Node result = null;

        while (true)
        {
          Node t = parseNonAttributeQualifiedExpression();
          if (t!=null)
          {
            int pos = t.pos();
            result = nodeFactory.memberExpression(result, nodeFactory.getExpression(t, pos), pos);
          }
         
          if (lookahead()!=DOT_TOKEN)
            break;
         
          shift();
        }
       
        if (debug)
        {
            System.err.println("finish parseSimpleTypeIdentifier");
        }

        return result;
    }

    /*
     * TemplatizedTypeExpression
     *   '.<' TypeExpressionList '>'
     * Complicated by possible follow tokens >>>, >>>=, >>, >>=, >=
     */
   
   private final Node parseTemplatizedTypeExpression(Node first)
   { 
     shift(); // match(DOTLESSTHAN_TOKEN);
     Node result = nodeFactory.applyTypeExpr(first, parseTypeExpressionList(),scanner.input.positionOfMark());

     final int lt = lookahead();

     switch ( lt )
     {
     case UNSIGNEDRIGHTSHIFTASSIGN_TOKEN:  // >>>= to >>=, consume('>')
       changeLookahead(RIGHTSHIFTASSIGN_TOKEN);
       break;
      
     case UNSIGNEDRIGHTSHIFT_TOKEN:  // >>> to >>, consume('>')
       changeLookahead(RIGHTSHIFT_TOKEN);
       break;
    
     case RIGHTSHIFT_TOKEN:  // >> to >, consume('>')
       changeLookahead(GREATERTHAN_TOKEN);
       break;
      
     case RIGHTSHIFTASSIGN_TOKEN:  // >>= to >=, consume('>')
       changeLookahead(GREATERTHANOREQUALS_TOKEN);
       break;
    
     case GREATERTHANOREQUALS_TOKEN:  // >= to =, consume('>')
       changeLookahead(ASSIGN_TOKEN);
       break;
    
     default:
       match(GREATERTHAN_TOKEN);
     }
    
     return result;
   }
  
   /*
    * Typename:
    *     SimpleTypeIdentifier TemplatizedTypeExpression?
    */
  
    private Node parseTypename()
    {
        if (debug)
        {
            System.err.println("begin parseTypeName");
        }

        Node first = parseSimpleTypeIdentifier();
        Node result = first;
       
        if(lookahead()==DOTLESSTHAN_TOKEN)
        {
          result = parseTemplatizedTypeExpression(first);
        }

        if (debug)
        {
            System.err.println("finish parseTypeName");
        }

        return result;
    }
  
    /*
     * TypenameList:
     *     Typename,*
     */
   
    private ListNode parseTypenameList()
    { 
       ListNode result = null;
       
        while (true)
        {
          Node t = parseTypename();
       
          if (t != null)
            result = nodeFactory.list(result,t);
         
          if (lookahead()!=COMMA_TOKEN)
            break;
         
          shift();
        }

        return result;
    }

    /*
     * TypeExpression
     *     "Object"
     *     Typename ('not' | '?')?
     */

    private Node parseTypeExpression(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseTypeExpression");
        }

        Node result;

        if( ctx.dialect(7) && nextToken == IDENTIFIER_TOKEN && scanner.getCurrentTokenText().equals("Object") )
        {
            match(IDENTIFIER_TOKEN);
            result = null// means *
        }
        else
        {
            Node first = parseTypename();
            boolean is_nullable = true;
            boolean is_explicit = false;
            final int lt = lookahead();
           
            if(lt==NOT_TOKEN)
            {
                shift();
                is_nullable = false;
                is_explicit = true;
            }
            else if(lt==QUESTIONMARK_TOKEN)
            {
                shift();
                is_nullable = true;
                is_explicit = true;
            }

            result = nodeFactory.typeExpression(first, is_nullable, is_explicit, -1);
        }

        if (debug)
        {
            System.err.println("finish parseTypeExpression");
        }

        return result;
    }

    /*
     * Statement
     *     SuperStatement
     *     Block
     *     MetaData
     *     IfStatement
     *     SwitchStatement
     *     DoStatement Semicolon
     *     WhileStatement
     *     ForStatement
     *     WithStatement
     *     ContinueStatement Semicolon
     *     BreakStatement Semicolon
     *     ReturnStatement Semicolon
     *     ThrowStatement Semicolon
     *     TryStatement
     *     LabeledStatement
     *     ExpressionStatement Semicolon
     */

    private Node parseStatement(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseStatement");
        }

        Node result;
        final int lt = lookahead();
       
        switch(lt)
        {
        case SUPER_TOKEN:
            result = parseSuperStatement(mode);
            // Moved into parseSuperStatement to allow for AS3 super expressions:
            //     matchSemicolon(mode);
          break;
         
        case LEFTBRACE_TOKEN:
            StatementListNode sln = parseBlock();
            result = sln;
          break;
         
        case LEFTBRACKET_TOKEN:
        case XMLLITERAL_TOKEN:
        case DOCCOMMENT_TOKEN:
          result = parseMetaData();
          break;
         
        case IF_TOKEN:
          result = parseIfStatement(mode);
          break;
           
        case SWITCH_TOKEN:
            result = parseSwitchStatement();
            break;
               
        case DO_TOKEN:
          result = parseDoStatement();
          matchSemicolon(mode);
          break;
               
        case WHILE_TOKEN:
          result = parseWhileStatement(mode);
          break;
               
        case FOR_TOKEN:
          result = parseForStatement(mode);
          break;
               
        case WITH_TOKEN:
          result = parseWithStatement(mode);
          break;
         
        case CONTINUE_TOKEN:
          result = parseContinueStatement();
            matchSemicolon(mode);
            break;
           
        case BREAK_TOKEN:
          result = parseBreakStatement();
            matchSemicolon(mode);
            break;
           
        case RETURN_TOKEN:
          result = parseReturnStatement();
            matchSemicolon(mode);
            break;
           
        case THROW_TOKEN:
            result = parseThrowStatement();
            matchSemicolon(mode);
            break;
           
        case TRY_TOKEN:
            result = parseTryStatement();
            break;
           
        default:
            result = parseLabeledOrExpressionStatement(mode);
            if (!result.isLabeledStatement())
            {
              matchSemicolon(mode);
            }
        }

        if (debug)
        {
            System.err.println("finish parseStatement");
        }

        return result;
    }

    /*
     * Substatement
     *     ';'
     *     VariableDefinition optSemicolon
     *     AnnotatedSubstatementsOrStatement
     */

    private Node parseSubstatement(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseSubstatement");
        }

        Node result;
        int lt = lookahead();
       
        if (lt==SEMICOLON_TOKEN)
        {
            shift();
            result = nodeFactory.emptyStatement();
        }
        else if (lt==VAR_TOKEN)
        {
            result = parseVariableDefinition(null/*attrs*/, mode);
            matchSemicolon(mode);
        }
        else
        {
            result = parseAnnotatedSubstatementsOrStatement(mode);
        }

        if (debug)
        {
            System.err.println("finish parseSubstatement");
        }

        return result;
    }

    /*
     * SuperStatement
     *     'super' '(' Arguments ')' ';'
     *     'super' '(' Arguments[1] ')' FullPostfixExpressionPrime ListExpressionPrime
     *     'super' FullPostfixExpressionPrime ('=' AssignmentExpressionSuffix)? ListExpressionPrime
     */

    private Node parseSuperStatement(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseSuperStatement");
        }

        Node result;

        shift(); //match(SUPER_TOKEN);
        SuperExpressionNode first = nodeFactory.superExpression(null,scanner.input.positionOfMark() );

        if (lookahead()==LEFTPAREN_TOKEN// super statement
        {
            CallExpressionNode call =  (CallExpressionNode) parseArguments(first);
           
            if (lookaheadSemicolon(mode))
            {
                result = nodeFactory.superStatement(call);
                matchSemicolon(mode);
            }
            else // super expression
            {
                if (call == null || call.args == null || call.args.size() != 1)
                {
                    error(kError_Parser_WrongNumberOfSuperArgs);
                }
                else
                {
                  first.expr = call.args.items.get(0);
                }
                Node t = parseFullPostfixExpressionPrime(first);
                result = nodeFactory.expressionStatement(parseListExpressionPrime(mode, nodeFactory.list(null, t)));
                matchSemicolon(mode);
            }
        }
        else if ( lookahead() == DOT_TOKEN || lookahead() == LEFTBRACKET_TOKEN ) // super expression
        {
            Node t = parseFullPostfixExpressionPrime(first);
            if (lookahead()==ASSIGN_TOKEN) // ISSUE: what about compound assignment?
            {
                t = parseAssignmentExpressionSuffix(mode, t);
            }
            result = nodeFactory.expressionStatement(parseListExpressionPrime(mode, nodeFactory.list(null, t)));
            matchSemicolon(mode);
        }
        else
        {
          error(ParseError.EOS, kError_Parser_ExpectedToken,
              Token.getTokenClassName(LEFTPAREN_TOKEN),
              scanner.getCurrentTokenTextOrTypeText(lookahead()));
          result = nodeFactory.error(kError_Parser_ExpectedToken);
          skiperror(SEMICOLON_TOKEN);
        }

        if (debug)
        {
            System.err.println("finish parseSuperStatement");
        }

        return result;
    }

    /*
     * LabeledOrExpressionStatement
     *      ExpressionList (':' Substatement[mode])?
     */

    private Node parseLabeledOrExpressionStatement(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseLabeledOrExpressionStatement");
        }

        Node result;
        ListNode first = parseExpressionList(allowIn_mode);

        if (lookahead()==COLON_TOKEN)
        {
          if (!first.isLabel())
          {
            error(kError_Parser_LabelIsNotIdentifier);
          }
          shift();
          result = nodeFactory.labeledStatement(first, parseSubstatement(mode));
        }
        else
        {
          result = nodeFactory.expressionStatement(first);
          // leave matchSemicolon(mode) for caller
        }

        if (debug)
        {
            System.err.println("finish parseLabeledOrExpressionStatement with " + ((result != null) ? result.toString() : ""));
        }

        return result;
    }

    /*
     * Block
     *     '{' Directives '}'
     */
   
    private StatementListNode parseBlock()
    {
        return parseBlock(null);
    }

    private StatementListNode parseBlock(AttributeListNode first)
    {
        if (debug)
        {
            System.err.println("begin parseBlock");
        }

        match(LEFTBRACE_TOKEN);
        StatementListNode result = parseDirectives(first, null/*stmts*/);
        match(RIGHTBRACE_TOKEN);

        if (debug)
        {
            System.err.println("finish parseBlock");
        }

        return result;
    }

    /*
     * MetaData
     *     Doccomment
     *     XMLLiteral
     *     ArrayLiteral
     */
   
    public MetaDataNode parseMetaData()
    {
        if (debug)
        {
            System.err.println("begin parseMetaData");
        }

        int pos = scanner.input.positionOfMark();
        MetaDataNode result;

        if (lookahead()==DOCCOMMENT_TOKEN)
        {
          shift();
            ListNode list = nodeFactory.list(null,nodeFactory.literalString(scanner.getCurrentTokenText(),pos));
            LiteralXMLNode first = nodeFactory.literalXML(list,false/*is_xmllist*/,pos);
            Node x = nodeFactory.memberExpression(null,nodeFactory.getExpression(first),pos);
            result = nodeFactory.docComment(nodeFactory.literalArray(nodeFactory.argumentList(null,x),pos),pos);
        }
        else if (lookahead()==XMLLITERAL_TOKEN)
        {
            result = nodeFactory.metaData(
                     nodeFactory.literalArray(
                            nodeFactory.argumentList(null,parseXMLLiteral())),pos);
        }
        else
        {
            result = nodeFactory.metaData(parseArrayLiteral(),pos);
        }

        if (debug)
        {
            System.err.println("end parseMetaData");
        }

        return result;
    }

    /*
     * IfStatement
     *     'if' ParenListExpression Statement
     *     'if' ParenListExpression Statement 'else' Statement
     */

    private Node parseIfStatement(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseIfStatement");
        }

        shift(); //match(IF_TOKEN);
       
        ListNode first = parseParenExpressionList();
        Node second = parseSubstatement(abbrevIfElse_mode);
        Node third = null;
       
        if (lookahead()==ELSE_TOKEN)
        {
            shift();
            third = parseSubstatement(mode);
        }

        Node result = nodeFactory.ifStatement(first, second, third);

        if (debug)
        {
            System.err.println("finish parseIfStatement");
        }

        return result;
    }

    /*
     * SwitchStatement
     *     'switch' ParenListExpression '{' CaseStatements '}'
     */

    private Node parseSwitchStatement()
    {
        if (debug)
        {
            System.err.println("begin parseSwitchStatement");
        }

        shift(); //match(SWITCH_TOKEN);
       
        Node first = parseParenExpressionList();
       
        match(LEFTBRACE_TOKEN);
        StatementListNode second = parseCaseStatements();
        match(RIGHTBRACE_TOKEN);

        Node result = nodeFactory.switchStatement(first, second);

        if (debug)
        {
            System.err.println("finish parseSwitchStatement");
        }

        return result;
    }

    /*
     * CaseLabel
     *     'case' ListExpression[allowIn] ':'
     *     'default' ':'
     */

    private Node parseCaseLabel()
    {
        if (debug)
        {
            System.err.println("begin parseCaseLabel");
        }

        Node result = null;
        final int lt = lookahead();
       
        if (lt==CASE_TOKEN)
        {
            shift();
            result = nodeFactory.caseLabel(parseExpressionList(allowIn_mode),scanner.input.positionOfMark());
        }
        else if (lt==DEFAULT_TOKEN)
        {
            shift();
            result = nodeFactory.caseLabel(null,scanner.input.positionOfMark()); // 0 argument means default case.
        }
        else
        {
            error(kError_Parser_ExpectedCaseLabel);
            skiperror(RIGHTBRACE_TOKEN);
        }
        match(COLON_TOKEN);

        if (debug)
        {
            System.err.println("finish parseCaseLabel");
        }

        return result;
    }

    /*
     * CaseStatements
     *     empty
     *     CaseLabel (CaseLabel|Directive)*
     */

    private StatementListNode parseCaseStatements()
    {
        if (debug)
        {
            System.err.println("begin parseCaseStatements");
        }

        StatementListNode result = null;
        int lt = lookahead();

        if (lt!=RIGHTBRACE_TOKEN && lt!=EOS_TOKEN)
        {
            result = nodeFactory.statementList(null, parseCaseLabel()); // force an initial caselabel syntactically ??? more meaningful if we check
           
            for (lt=lookahead(); lt!=RIGHTBRACE_TOKEN && lt!=EOS_TOKEN; lt=lookahead())
            {
                Node t = (lt==CASE_TOKEN || lt==DEFAULT_TOKEN)
                  ? parseCaseLabel()
                    : parseDirective(null, full_mode);
             
              result = nodeFactory.statementList(result, t);
            }
        }
 
        if (debug)
        {
            System.err.println("finish parseCaseStatements");
        }

        return result;
    }

    /*
     * DoStatement
     *     'do' Substatement[abbrevDoWhile] 'while' ParenListExpression
     */

    private Node parseDoStatement()
    {
        if (debug)
        {
            System.err.println("begin parseDoStatement");
        }

        shift(); //match(DO_TOKEN);
        Node first = parseSubstatement(abbrevDoWhile_mode);
        match(WHILE_TOKEN);
        Node result = nodeFactory.doStatement(first, parseParenExpressionList());

        if (debug)
        {
            System.err.println("finish parseDoStatement");
        }

        return result;
    }

    /*
     * WhileStatement
     *     'while' ParenListExpression Substatement
     */

    private Node parseWhileStatement(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseWhileStatement");
        }
       
        shift(); //match(WHILE_TOKEN); 
        Node first = parseParenExpressionList();
        Node second = parseSubstatement(mode);
        Node result = nodeFactory.whileStatement(first, second);

        if (debug)
        {
            System.err.println("finish parseWhileStatement");
        }

        return result;
    }

    /*
     * ForStatement
     *     for ( ForInitializer ; OptionalExpression ; OptionalExpression ) Substatement
     *     for ( ForInBinding 'in' ExpressionList[allowIn] ) Substatement
     *
     * ForInitializer
     *     empty
     *     ExpressionList[noIn]
     *     VariableDefinition[noIn]
     *     //Attributes [no line break] VariableDefinition[noIn]
     *
     * ForInBinding
     *     PostfixExpression
     *     VariableDefinition Kind VariableBinding[noIn]
     *     //Attributes [no line break] VariableDefinition Kind VariableBinding[noIn]
     */

    private Node parseForStatement(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseForStatement");
        }

        Node result;
        boolean is_each = false;
       
        shift(); //match(FOR_TOKEN);

        if(lookahead()==IDENTIFIER_TOKEN)
        {
          shift();
            if( !scanner.getCurrentTokenText().equals("each") )
            {
                error(kError_Parser_ExpectedLeftParen);
            }
            is_each = true;
        }

        match(LEFTPAREN_TOKEN);

        Node first;
        final int lt = lookahead();
       
        if (lt==SEMICOLON_TOKEN)
        {
            first = null;
        }
        else if (lt==CONST_TOKEN || lt==VAR_TOKEN)
        {
            first = parseVariableDefinition(null/*attrs*/, noIn_mode);
        }
        else if( is_each )
        {
            first = nodeFactory.list(null,parsePostfixExpression());
        }
        else
        {
            first = parseExpressionList(noIn_mode);
        }

        Node second;
        if (lookahead()==IN_TOKEN)
        {
            // ISSUE: verify that first is a single expression or variable definition

            if( first instanceof VariableDefinitionNode && ((VariableDefinitionNode)first).list.size() > 1)
            {
                error(kError_ParserInvalidForInInitializer);
            }
            else if( first instanceof ListNode && ((ListNode)first).size() > 1 )
            {
                error(kError_ParserInvalidForInInitializer);
            }
           
            match(IN_TOKEN);
            second = parseExpressionList(allowIn_mode);
            match(RIGHTPAREN_TOKEN);

            int pos = scanner.input.positionOfMark();
            result = nodeFactory.forInStatement(is_each, first, second, parseSubstatement(mode), pos);
        }
        else if(lookahead()==COLON_TOKEN)
        {
            match(IN_TOKEN); //error(ParseError.syntax,kError_Parser_EachWithoutIn);
            skiperror(LEFTBRACE_TOKEN);
            result = parseSubstatement(mode);
        }
        else
        {
            if( is_each )
            {
                error(kError_Parser_EachWithoutIn);
            }

            match(SEMICOLON_TOKEN);
           
            second = (lookahead()==SEMICOLON_TOKEN) ? null : parseExpressionList(allowIn_mode);
            match(SEMICOLON_TOKEN);

            Node third = (lookahead()==RIGHTPAREN_TOKEN) ? null : parseExpressionList(allowIn_mode);
            match(RIGHTPAREN_TOKEN);
           
            int pos = scanner.input.positionOfMark();
            result = nodeFactory.forStatement(first, second, third, parseSubstatement(mode),false/*is_forin*/, pos);
        }
        return result;
    }

    /*
     * WithStatement
     *     'with' ParenListExpression Substatement
     */

    private Node parseWithStatement(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseWithStatement");
        }
       
        int pos = scanner.input.positionOfMark();
        shift(); //match(WITH_TOKEN);
        Node first = parseParenExpressionList();
        Node result = nodeFactory.withStatement(first, parseSubstatement(mode), pos);

        if (debug)
        {
            System.err.println("finish parseWithStatement");
        }

        return result;
    }

    /*
     * ContinueStatement
     *     'continue'
     *     'continue' [no line break] Identifier
     */

    private Node parseContinueStatement()
    {
        if (debug)
        {
            System.err.println("begin parseContinueStatement");
        }

        IdentifierNode first = null;
        shift(); //match(CONTINUE_TOKEN);
       
        if (!lookaheadSemicolon(full_mode))
        {
            first = parseIdentifier();
        }

        Node result = nodeFactory.continueStatement(first, scanner.input.positionOfMark());

        if (debug)
        {
            System.err.println("finish parseContinueStatement");
        }

        return result;
    }

    /*
     * BreakStatement
     *     break
     *     break [no line break] Identifier
     */

    private Node parseBreakStatement()
    {
        if (debug)
        {
            System.err.println("begin parseBreakStatement");
        }

        IdentifierNode first = null;
        shift(); //match(BREAK_TOKEN);
       
        if (!lookaheadSemicolon(full_mode))
        {
            first = parseIdentifier();
        }

        Node result = nodeFactory.breakStatement(first, scanner.input.positionOfMark());

        if (debug)
        {
            System.err.println("finish parseBreakStatement");
        }

        return result;
    }

    /*
     * ReturnStatement
     *     'return' ([no line break] ExpressionList[allowIn])?
     */

    private Node parseReturnStatement()
    {
        if (debug)
        {
            System.err.println("begin parseReturnStatement");
        }

        Node first = null;
        shift(); //match(RETURN_TOKEN);

        // ACTION: check for VirtualSemicolon

        if (!lookaheadSemicolon(full_mode))
        {
            first = parseExpressionList(allowIn_mode);
        }

        Node result = nodeFactory.returnStatement(first, scanner.input.positionOfMark());

        if (debug)
        {
            System.err.println("finish parseReturnStatement");
        }

        return result;
    }

    /*
     * ThrowStatement
     *     'throw' [no line break] ExpressionList[allowIn]
     */

    private Node parseThrowStatement()
    {
        if (debug)
        {
            System.err.println("begin parseThrowStatement");
        }

        Node result;
        int pos = scanner.input.positionOfMark();
        shift(); //match(THROW_TOKEN);
       
        lookahead(); // force read of next token
    
        if (scanner.followsLineTerminator())
        {
            error(ParseError.syntax, kError_Parser_ThrowWithoutExpression,"","",pos);
            result = nodeFactory.throwStatement(null,pos);    // make a dummy node
        }
        else
        {
            result = nodeFactory.throwStatement(parseExpressionList(allowIn_mode),pos);
        }

        if (debug)
        {
            System.err.println("finish parseThrowStatement");
        }

        return result;
    }

    /*
     * TryStatement
     *     'try' Block CatchClauses? FinallyClause?
     */

    private Node parseTryStatement()
    {
        if (debug)
        {
            System.err.println("begin parseTryStatement");
        }

        Node result;
        StatementListNode first;

        shift(); //match(TRY_TOKEN);
        first = parseBlock();
        if (lookahead()==CATCH_TOKEN)
        {
            StatementListNode second = parseCatchClauses();
            if (lookahead()==FINALLY_TOKEN)
            {
                result = nodeFactory.tryStatement(first, second, parseFinallyClause());
            }
            else
            {
                result = nodeFactory.tryStatement(first, second, null);
            }
        }
        else if (lookahead()==FINALLY_TOKEN)
        {
            // finally with no catch clause
            // force feed a default catch clause so finally works
            StatementListNode catchClause =
              nodeFactory.statementList(null,
                          nodeFactory.catchClause(null,
                              nodeFactory.statementList(null,
                                  nodeFactory.throwStatement(null, 0 ))));

            result = nodeFactory.tryStatement(first, catchClause, parseFinallyClause());
        }
        else
        {
            error(kError_Parser_ExpectingCatchOrFinally);
            skiperror(SEMICOLON_TOKEN);
            result = null;
        }

        if (debug)
        {
            System.err.println("finish parseTryStatement");
        }

        return result;
    }

    /*
     * CatchClauses
     *     CatchClause+
     */

    private StatementListNode parseCatchClauses()
    {
        if (debug)
        {
            System.err.println("begin parseCatchClauses");
        }

        StatementListNode result;

        result = nodeFactory.statementList(null, parseCatchClause());
        while (lookahead()==CATCH_TOKEN)
        {
            result = nodeFactory.statementList(result, parseCatchClause());
        }

        if (debug)
        {
            System.err.println("finish parseCatchClauses");
        }

        return result;
    }

    /*
     * CatchClause
     *     'catch' '(' Parameter ')' Block
     */

    private Node parseCatchClause()
    {
        if (debug)
        {
            System.err.println("begin parseCatchClause");
        }

        shift(); //match(CATCH_TOKEN);
       
        match(LEFTPAREN_TOKEN);
        Node first = parseParameter();
        match(RIGHTPAREN_TOKEN);

        Node result = nodeFactory.catchClause(first, parseBlock());

        if (debug)
        {
            System.err.println("finish parseCatchClause");
        }

        return result;
    }

    /*
     * FinallyClause
     *     'finally' Block
     */

    private FinallyClauseNode parseFinallyClause()
    {
        if (debug)
        {
            System.err.println("begin parseFinallyClause");
        }

        shift(); //match(FINALLY_TOKEN);

        // No line break.

        FinallyClauseNode result = nodeFactory.finallyClause(parseBlock());

        if (debug)
        {
            System.err.println("finish parseFinallyClause");
        }

        return result;
    }


    // Directives


    /*
     * Directivew
     *     DefaultXMLNamespaceDirective
     *     EmptyStatement
     *     AnnotatableDirectivew
     *     Pragma Semicolonw
     *     Attributes [no line break] AnnotatableDirectivew
     *     Attributes [no line break] { Directives }
     *     Statementw
     */

    private Node parseDirective(AttributeListNode first, int mode)
    {
        if (debug)
        {
            System.err.println("begin parseDirective");
        }

        Node result = null;

        try
        {
          final int lt = lookahead();
         
            switch ( lt )
            {
            case SEMICOLON_TOKEN:
                matchNoninsertableSemicolon(mode);
                result = nodeFactory.emptyStatement();
                break;
               
            case INTERFACE_TOKEN:
                if (HAS_INTERFACEDEFINITIONS==false)
                {
                  // 'interface' is treated as an identifier on this path.
                    result = parseAnnotatedDirectiveOrStatement(mode);
                    break;
                }
                //fall through
            case VAR_TOKEN: case CONST_TOKEN: case FUNCTION_TOKEN: case CLASS_TOKEN:
            case NAMESPACE_TOKEN: case IMPORT_TOKEN: case INCLUDE_TOKEN: case USE_TOKEN:
                result = parseAnnotatableDirectiveOrPragmaOrInclude(first, mode);
                break;
               
            case DEFAULT_TOKEN: // default xml namespace = <expr>  --pretty cumbersome syntax
            {
                shift();
                if (match(IDENTIFIER_TOKEN)==IDENTIFIER_TOKEN)
                {
                   if( !scanner.getCurrentTokenText().equals("xml") && lookahead()==NAMESPACE_TOKEN)
                     {
                         error(kError_Parser_ExpectedXMLBeforeNameSpace);
                     }
                }
                match(NAMESPACE_TOKEN);
                match(ASSIGN_TOKEN);
                result = nodeFactory.defaultXMLNamespace(parseNonAssignmentExpression(allowIn_mode),0);
                break;
            }
            default:
                result = parseAnnotatedDirectiveOrStatement(mode);
            }

            if (debug)
            {
                System.err.println("finish parseDirective with " + ((result != null) ? result.toString() : ""));
            }

        }
        catch (Exception ex)
        {
          result = null;
          //assert false : ex.getMessage();
            // ex.printStackTrace();
            // System.err.println("\nInternal error: exception caught in parseDirective()");
        }

        return result;
    }

    /*
     *  AnnotatedDirectiveOrStatement
     *   [ true, false, private, public, Identifier ] Attributes [no line break] AnnotatableDirectivew
     *   [ true, false, private, public, Identifier ] Attributes [no line break] { Directives }
     *   Statementw
     */

    private Node parseAnnotatedDirectiveOrStatement(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseDefinition");
        }

        Node result = null;
        int lt = lookahead();

        if (inStatementTokenSet(lt))
        {
            result = parseStatement(mode);
        }
        else
        {
            Node temp;
            if (HAS_SQUAREBRACKETATTRS && lt==LEFTBRACKET_TOKEN)
            {
                shift();
                temp = parseAssignmentExpression(allowIn_mode);
                match(RIGHTBRACKET_TOKEN);
            }
            else
            {
                temp = parseLabeledOrExpressionStatement(mode);
            }
            if (temp.isLabeledStatement())
            {
                    result = temp; // no semi-colon necessary if labeled statement.
            }
            else
           
                String directiveString = scanner.getCurrentTokenTextOrTypeText(nextToken);

                if (lookaheadSemicolon(mode) && !temp.isConfigurationName())
                {
                    // If full mode then cannot be an attribute
                    matchSemicolon(mode);
                   
                    result = temp;

                    if (temp instanceof ExpressionStatementNode)
                    {
                        temp = ((ExpressionStatementNode) temp).expr;
                    }
                   
                    boolean is_attribute_keyword = checkAttribute(temp);
                   
                    if( is_attribute_keyword )
                    {
                        error(ParseError.syntax, kError_Parser_ExpectingAnnotatableDirectiveAfterAttributes, which_attribute(temp), directiveString);
                    }
                }
                else if (temp.isAttribute())
                {
                    // If its an expression statement, then extract the expression
                   
                  ExpressionStatementNode estmt = null;
                  if ( temp instanceof ExpressionStatementNode )
                  {
                    estmt = (ExpressionStatementNode)temp;
                    temp = estmt.expr;
                  }

                    boolean is_attribute_keyword = checkAttribute(temp);
                    AttributeListNode first;
                   
                    switch ( lookahead() )
                    {
                    case TRUE_TOKEN: case FALSE_TOKEN: case PRIVATE_TOKEN: case PUBLIC_TOKEN:
                    case PROTECTED_TOKEN: case IDENTIFIER_TOKEN:
                        first = nodeFactory.attributeList(temp, parseAttributeList());
                        break;
                       
                    default:
                        first = nodeFactory.attributeList(temp, null);
                    }

                    lt = lookahead();
                    switch ( lt )
                    {
                    case VAR_TOKEN: case CONST_TOKEN: case FUNCTION_TOKEN: case CLASS_TOKEN:
                    case NAMESPACE_TOKEN: case IMPORT_TOKEN: case USE_TOKEN: case INTERFACE_TOKEN:
                    case DOCCOMMENT_TOKEN:
                        result = parseAnnotatableDirectiveOrPragmaOrInclude(first, mode);
                        break;
                       
                    default:
                        if ( temp.isConfigurationName() && lt==LEFTBRACE_TOKEN )
                        {
                            result = parseAnnotatableDirectiveOrPragmaOrInclude(first, mode);
                        }
                        else if(lt == PACKAGE_TOKEN)
                        {
                             error(kError_AttributesOnPackage);
                             result = parsePackageDefinition();
                        }
                        else if( is_attribute_keyword || first.size() > 1 )
                        {
                            error(ParseError.syntax, kError_Parser_ExpectingAnnotatableDirectiveAfterAttributes, which_attribute(temp), directiveString);
                            skiperror(SEMICOLON_TOKEN);
                        }
                        else if ( temp.isConfigurationName() )
                        {
                            // Flex gets here when it parses a code fragment like: CONFIG::foo                      
                            result = estmt;
                        }
                        else
                        {
                            // It's not known what code would reach this                                            
                            // state, so this is a best guess at how to                                             
                            // handle it.
                           
                            // Note that asc-tests have an error case e.g. the expression statement "x::y::z;"
                            // that reaches this code, as a result, behavior with/without
                            // this assert enabled differs.
                            // So I shut it off. {pmd 9/28/2008}
                           // assert false : "Unexpected state";
                            result = estmt;
                        }
                    }
                }
                else
                {
                    if (ctx.errorCount() == 0)
                    {
                        matchSemicolon(mode)// don't check if an error has already occured
                    }
                }
            }
        }

        if (debug)
        {
            System.err.println("finish parseDefinition");
        }
        return result;
    }

    /*
     *  AnnotatedSubstatementsOrStatement
     *  lookahead(StatementTokenSet)
     *    ? Statement
     *    : LabeledOrExpressionStatement optSemicolon
     */

    private Node parseAnnotatedSubstatementsOrStatement(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseDefinition");
        }

        Node result = null;
       
        if (inStatementTokenSet(lookahead()))
        {
            result = parseStatement(mode);
        }
        else
        {
          Node t = parseLabeledOrExpressionStatement(mode);
         
          if (t.isLabeledStatement())
          {
            result = t; // following semicolon is optional on labeled statements
            if (lookahead()==SEMICOLON_TOKEN)
            {
              shift();
            }
          }
          else  //must have a semicolon
          {
            if (lookaheadSemicolon(mode))
            {
              // If full mode then cannot be an attribute
              matchSemicolon(mode);
              result = t;
            }
            else if (t.isAttribute())
            {
              error(kError_InvalidAttribute);
            }
            else
            {
              match(SEMICOLON_TOKEN); // force syntax error
            }
          }
        }

        if (debug)
        {
            System.err.println("finish parseDefinition");
        }

        return result;
    }

    /*
     *  AnnotatableDirectiveOrPragmaOrInclude
     *      VariableDefinition optSemicolon
     *      FunctionDefinition
     *      ClassDefinition
     *      InterfaceDefinition
     *      NamespaceDefinition optSemicolon
     *      ImportDirective optSemicolon
     *      UseDirectiveOrPragma optSemicolon
     *      IncludeDirective optSemicolon
     *      Block
     *     
     */

    private Node parseAnnotatableDirectiveOrPragmaOrInclude(AttributeListNode first, int mode)
    {
        if (debug)
        {
            System.err.println("begin parseDefinition");
        }

        Node result = null;
        final int lt = lookahead();
       
        switch ( lt )
        {
        case CONST_TOKEN:
        case VAR_TOKEN:
            result = parseVariableDefinition(first, mode);
            matchSemicolon(mode);
            break;
  
        case FUNCTION_TOKEN:
            result = parseFunctionDefinition(first);
            break;
           
        case CLASS_TOKEN:
            result = parseClassDefinition(first, mode);
            break;
           
        case INTERFACE_TOKEN:
            result = parseInterfaceDefinition(first, mode);
            break;
           
        case NAMESPACE_TOKEN:
            result = parseNamespaceDefinition(first);
            matchSemicolon(mode);
            break;

        case IMPORT_TOKEN:
            result = parseImportDirective(first);
            matchSemicolon(mode);
            break;
           
        case USE_TOKEN:
            result = parseUseDirective(first);
            matchSemicolon(mode);
            break;
           
        case INCLUDE_TOKEN:
            result = parseIncludeDirective();
            matchSemicolon(mode);
            break;
           
        case LEFTBRACE_TOKEN:
          StatementListNode stmts = parseBlock();
          stmts.config_attrs = first;
          result = stmts;
          matchSemicolon(mode);
          break;
       
        default:
            error(kError_Parser_DefinitionOrDirectiveExpected);
            skiperror(SEMICOLON_TOKEN);
            break;
        }

        if (debug)
        {
            System.err.println("finish parseDefinition");
        }
       
        return result;
    }

    /*
     * Directives
     *     Directive*
     */
   
    public StatementListNode parseDirectives(AttributeListNode first, StatementListNode list)
    {
        if (debug)
        {
            System.err.println("begin parseDirectives");
        }

        StatementListNode result = null;
        int lt;

        while ((lt=lookahead())!=RIGHTBRACE_TOKEN && lt!=EOS_TOKEN)
        {
            Node t = parseDirective(first, abbrev_mode);
           
          if (t == null)
          {
            break;
          }
           
          if( t instanceof StatementListNode )
            {
                StatementListNode sln = (StatementListNode) t;     // remove any gratuitous nestings
                if( sln.config_attrs == null && !sln.has_pragma )
                {
                    if( list == null )
                    {
                        list = sln;
                    }
                    else
                    {
                        list.items.addAll(sln.items);
                    }
                }
                else
                {
                  // Can't collapse into one statementlist node if the inner one might be compiled
                  // out due to conditional compilation
                  list = nodeFactory.statementList(list, t);
                }
            }
            else
            {
              list = nodeFactory.statementList(list, t);
            }
        }

        result = list;

        if (debug)
        {
            System.err.println("finish parseDirectives");
        }

        return result;
    }

    /*
     * UseDirective
     *  use 'namespace' NonAssignmentExpression
     *  use 'include' IncludeDirective
     *  use PragmaItemList
     *
     * use: 'use' | '#' ;
     */

    private Node parseUseDirective(AttributeListNode first)
    {
        if (debug)
        {
            System.err.println("begin parseUseDirectiveOrPragma");
        }

        Node result = null;

        shift(); //match(USE_TOKEN);
       
        if (lookahead()==NAMESPACE_TOKEN)
        {
            shift();
            result = nodeFactory.useDirective(first, parseNonAssignmentExpression(allowIn_mode));
        }
        else if (lookahead()==INCLUDE_TOKEN// for AS3 #include
        {
            result = parseIncludeDirective();
        }
        else
        {
            if( ctx.statics.es4_numerics )
                result = nodeFactory.pragma(parsePragmaItemList(allowIn_mode),scanner.input.positionOfMark());
            else
                error(kError_UndefinedNamespace)// Do what we used to do... better than an unlocalized internal error of feature not implemented
        }

        if (debug)
        {
            System.err.println("finish parseUseDirectiveOrPragma");
        }

        return result;
    }

    /*
     * PragmaItem
     *    id (pragma_item_argument)?
     *
     * pragma_item_argument
     *     id|true|false|number|string
     */
   
  private Node parsePragmaItem(int mode)
  {
        Node id;
        Node argument;
       
        if (debug)
        {
            System.err.println("begin parsePragmaItem");
        }

        id = parseIdentifier();
        int lt = lookahead();
        int pos = scanner.input.positionOfMark();
       
        if (lt==COMMA_TOKEN || lookaheadSemicolon(mode))
        {
            argument = null;
        }
        else if (lt==TRUE_TOKEN)
        {
            shift();
            argument = nodeFactory.literalBoolean(true,pos);
        }
        else if (lt==FALSE_TOKEN)
        {
            shift();
            argument = nodeFactory.literalBoolean(false,pos);
        }
        else if (lt==NUMBERLITERAL_TOKEN)
        {
          shift();
            argument = nodeFactory.literalNumber(scanner.getCurrentTokenText(),pos);
        }
        else if (lt==STRINGLITERAL_TOKEN)
        {
            boolean[] is_single_quoted = new boolean[1];
            shift();
            String enclosedText = scanner.getCurrentStringTokenText(is_single_quoted);
            argument = nodeFactory.literalString(enclosedText, pos, is_single_quoted[0] );
        }
        else argument = parseIdentifier();
       
        Node result = nodeFactory.usePragma(id, argument, scanner.input.positionOfMark());

        if (debug)
        {
            System.err.println("finish parsePragmaItem");
        }
        return result;
    }

  /*
   * PragmaItemList
   *     PragmaItem,*
   *
   */
 
    private ListNode parsePragmaItemList(int mode)
    {
        if (debug)
        {
            System.err.println("begin parsePragmaItemList");
        }
        ListNode result = null;
      
        while (true)
        {
          Node t = parsePragmaItem(mode);
          if (t != null)
            result = nodeFactory.list(result,t);
         
          if ( lookahead() != COMMA_TOKEN)
            break;
          shift();
        }

        if (debug)
        {
            System.err.println("finish parsePragmaItemList");
        }
        return result;
    }

    /*
     * IncludeDirective
     *     'include'[no line break] String
     */

    private Node parseIncludeDirective()
    {
        if (debug)
        {
            System.err.println("begin parseIncludeDirective");
        }

        IncludeDirectiveNode result;
        LiteralStringNode first;

        shift(); //match(INCLUDE)

        boolean[] is_single_quoted = new boolean[1];
        String filespec = null;
       
        if (lookahead()==STRINGLITERAL_TOKEN)
        {
          shift();
          filespec = scanner.getCurrentStringTokenText(is_single_quoted).trim();
        }
        else
        {
          match(STRINGLITERAL_TOKEN);
        }
       
        CompilerHandler.FileInclude incl = null;
        if (ctx.handler != null)
        {
            incl = ctx.handler.findFileInclude(ctx.path(), filespec);
        }

      // The input could be an input stream or an in-memory string.
        InputStream in = null;
      String text = null;

        String fixed_filespec = null, parentPath = null;
        if (incl == null)
        {
            filespec = filespec.replace('/', File.separatorChar);

            File inc_file = new File(filespec);
            if (inc_file.isAbsolute())
            {
                // absolute path
                 fixed_filespec = inc_file.getAbsolutePath();
            }
            else
            {
                // must be a relative path
                fixed_filespec = (ctx.path() == null ? "" : ctx.path()) + File.separator + filespec;
            }

            try
            {
              fixed_filespec = new File(fixed_filespec).getCanonicalPath();
            }
            catch (IOException ex)
            {
              fixed_filespec = new File(fixed_filespec).getAbsolutePath();
            }
           
            parentPath = fixed_filespec.substring(0, fixed_filespec.lastIndexOf(File.separator));
          if (!ctx.scriptAssistParsing){
              try
              {
                  in = new BufferedInputStream(new FileInputStream(fixed_filespec));
              }
              catch (FileNotFoundException ex)
              {
                  error(ParseError.syntax, kError_Parser_UnableToOpenFile, fixed_filespec);
                  return null;
              }
          }
        }
        else
        {
            fixed_filespec = incl.fixed_filespec;
            parentPath = incl.parentPath;
            in = incl.in;
          text = incl.text;
        }

        // make sure that we check the include path trail. This is to stop infinite recursion.
        if (ctx.statics.includePaths.contains(fixed_filespec))
        {
            error(ParseError.syntax, kError_Parser_FileIncludesItself, fixed_filespec);
            try { in.close(); } catch (IOException ex) {}
            return null;
        }
        else
        {
            // add the file name to the include path trail.
            ctx.statics.includePaths.push_back(fixed_filespec);
        }

        // To get proper path resolution for included files inside of include directives,
        // temporarily update ctx.pathspec with spec (minus file name) for this file

        String oldCtxPathSpec = ctx.path();
        ctx.setPath(parentPath);

        // Reset to oldCtxPathSpec once we are finished parsing this file

        first  = nodeFactory.literalString(fixed_filespec,scanner.input.positionOfMark(), is_single_quoted[0]);

        ProgramNode second = null;
      if (!ctx.scriptAssistParsing)
      {
        Context cx = new Context(ctx.statics);
        try
        {
          // cx.setEmitter(ctx.getEmitter());
          // cx.statics.nodeFactory = ctx.statics.nodeFactory;
          // cx.statics.global = ctx.statics.global;
          Parser p = null;
          if (in != null)
          {
            p = new Parser(cx, in, fixed_filespec, encoding, create_doc_info, save_comment_nodes,block_kind_stack, true);
            p.config_namespaces = this.config_namespaces;
            second = p.parseProgram();
          }
          else
          {
            p = new Parser(cx, text, fixed_filespec, create_doc_info, save_comment_nodes,block_kind_stack, true);
            p.config_namespaces = this.config_namespaces;
            second = p.parseProgram();
          }
        }
        finally
        {
          ctx.setPath(oldCtxPathSpec);
          // now we can remove the filename...
          ctx.statics.includePaths.removeLast();
          if (in != null)
          {
            try { in.close(); } catch (IOException ex) {}
          }
        }
        result = nodeFactory.includeDirective(cx, first, second);
      }
      else
      {
        result = nodeFactory.includeDirective(ctx, first, second);
      }
     
        if (debug)
        {
            System.err.println("finish parseIncludeDirective");
        }

        return result;
    }

    /*
     * Attributes
     */

    private boolean checkAttribute( Node node )
    {
        int token_id = block_kind_stack.last();
       
        if( token_id != ERROR_TOKEN  && token_id != CLASS_TOKEN  && token_id != INTERFACE_TOKEN)
        {
            if( node.hasAttribute("private") )
            {
                ctx.error(node.pos(), kError_InvalidPrivate);
            }
            else if( node.hasAttribute("protected") )
            {
                ctx.error(node.pos(), kError_InvalidProtected);
            }
            else if( node.hasAttribute("static") )
            {
                ctx.error(node.pos(), kError_InvalidStatic);
            }
            else if( token_id != PACKAGE_TOKEN && token_id != EMPTY_TOKEN && node.hasAttribute("internal") )
            {
                ctx.error(node.pos(), kError_InvalidInternal);
            }
            else if( token_id != PACKAGE_TOKEN && node.hasAttribute("public") )
            {
                ctx.error(node.pos(), kError_InvalidPublic);
            }
        }

        if( node.hasAttribute("prototype") )
        {
            ctx.error(node.pos(),kError_PrototypeIsAnInvalidAttribute);
        }

        return node.hasAttribute("static") ||
                node.hasAttribute("public") ||
                node.hasAttribute("private") ||
                node.hasAttribute("protected") ||
                node.hasAttribute("internal") ||
                node.hasAttribute("native") ||
                node.hasAttribute("final") ||
                node.hasAttribute("override") ||
                node.hasAttribute("prototype");
    }

    private String which_attribute(Node t)
    {
     
        /*
         * empirically derived, fragile code, since tree shapes may differ or change. {pmd}
         */
     
        if (t.isList())
        {
            Node t1 = ((ListNode) t).items.get(0);
            if (t1.isMemberExpression())
            {
                MemberExpressionNode m1 = (MemberExpressionNode) t1;
                IdentifierNode t2 = m1.selector.getIdentifier();
                if (t2 != null)
                    return t2.toIdentifierString();
            }
        }
       
        if (t.hasAttribute("static"))
            return "static";
        if (t.hasAttribute("public"))
            return "public";
        if (t.hasAttribute("private"))
            return "private";
        if (t.hasAttribute("protected"))
            return "protected";
        if (t.hasAttribute("internal"))
            return "internal";
        if (t.hasAttribute("native"))
            return "native";
        if (t.hasAttribute("final"))
            return "final";
        if (t.hasAttribute("override"))
            return "override";
        if (t.hasAttribute("prototype"))
            return "prototype";
        return "<unknown>";
    }
   
    /*
     * AttributeList
     *     attribute,*
     *
     * attribute -> id|'private'|'protected'('::'id)?|'public'('::'id)?|'['arrayliteral']'|'false'|'true'
     */
   
    private AttributeListNode parseAttributeList()
    {
        if (debug)
        {
            System.err.println("begin parseAttributes");
        }
       
        AttributeListNode result = null;

        while (true)
        {
            int lt = lookahead();
            Node t = null;
            int pos = scanner.input.positionOfMark();
           
            switch ( lt )
            {
            case TRUE_TOKEN:
                shift();
                t = nodeFactory.literalBoolean(true, pos);
                break;
               
            case FALSE_TOKEN:
                shift();
                t = nodeFactory.literalBoolean(false, pos);
                break;
               
            case PRIVATE_TOKEN:
                shift();
                t = nodeFactory.identifier(PRIVATE, false, pos);
                if (lookahead()==DOUBLECOLON_TOKEN)
                {
                    shift();
                    t = nodeFactory.qualifiedIdentifier(t, parseIdentifierString(),scanner.input.positionOfMark());
                }
                break;
               
            case PROTECTED_TOKEN:
                shift();
                t = nodeFactory.identifier(PROTECTED, false, pos);
                if (lookahead()==DOUBLECOLON_TOKEN)
                {
                    shift();
                    t = nodeFactory.qualifiedIdentifier(t, parseIdentifierString(),scanner.input.positionOfMark());
                }
                break;
               
            case PUBLIC_TOKEN:
                shift();
                t = nodeFactory.identifier(PUBLIC, false, pos);
                if (lookahead()==DOUBLECOLON_TOKEN)
                {
                    shift();
                    t = nodeFactory.qualifiedIdentifier(t, parseIdentifierString(),scanner.input.positionOfMark());
                }
                break;
               
            case LEFTBRACKET_TOKEN:
                t = parseArrayLiteral();
                break;
           
            case IDENTIFIER_TOKEN:
              t = parseSimpleTypeIdentifier();
              break;
             
            default:
              t = null;
              break;
            }
         
            if (t==nullbreak; // exit
           
          checkAttribute(t);
          result = nodeFactory.attributeList(t,result);
        }

        if (debug)
        {
            System.err.println("finish parseAttributes");
        }

        return result;
    }

    /*
     * ImportDirective
     *     'import' PackageName
     *     'import' Identifier '=' PackageName
     */

    private Node parseImportDirective(AttributeListNode first)
    {
        if (debug)
        {
            System.err.println("begin parseImportDirective");
        }

        PackageNameNode second;
        PackageNameNode third = null;
        int stmtPos = scanner.input.positionOfMark();
       
        shift(); //match(IMPORT_TOKEN);
        second = parsePackageName(true);
        if (lookahead()==ASSIGN_TOKEN)
        {
            // ISSUE: second should be a simple identifier
            third = parsePackageName(true);
        }

        Node result = nodeFactory.importDirective(first, second, third, stmtPos, ctx);

        if (debug)
        {
            System.err.println("finish parseImportDirective");
        }

        return result;
    }

    // Definitions

    /*
     * VariableDefinition
     *     ('const'|'var')? VariableBindingList[mode]
     */

    private Node parseVariableDefinition(AttributeListNode first, int mode)
    {
        if (debug)
        {
            System.err.println("begin parseVariableDefinition");
        }

        int lt = lookahead();
        int kind = VAR_TOKEN;
       
        if (lt==CONST_TOKEN)
        {
          kind = CONST_TOKEN;
          shift();
        }
        else if (lt==VAR_TOKEN)
        {
          shift();
        }
           
        ListNode t = parseVariableBindingList(first, kind, mode);
        Node result = nodeFactory.variableDefinition(first, kind, t);

        if (debug)
        {
            System.err.println("finish parseVariableDefinition");
        }

        return result;
    }

    /*
     * VariableBindingList
     *     VariableBinding,*
     */

    private ListNode parseVariableBindingList(AttributeListNode attrs, int kind, int mode)
    {
        if (debug)
        {
            System.err.println("begin parseVariableBindingList");
        }

        ListNode result = null;
        while (true)
        {
          Node t = parseVariableBinding(attrs, kind, mode);
         
          if ( t != null )
            result = nodeFactory.list(result,t);
         
          if (lookahead()!=COMMA_TOKEN)
            break;
         
          shift();
        }
        if (debug)
        {
            System.err.println("finish parseVariableBindingList");
        }

        return result;
    }

    /*
     * <VariableBinding>
     *     <TypedIdentifier> <VariableInitialization>?
     */

    private Node parseVariableBinding(AttributeListNode attrs, int kind, int mode)
    {
        if (debug)
        {
            System.err.println("begin parseVariableBinding");
        }

        TypedIdentifierNode first = parseTypedIdentifier(mode);
        Node second = parseVariableInitialization(mode);
        Node result = nodeFactory.variableBinding(attrs, kind, first, second);

        if (debug)
        {
            System.err.println("finish parseVariableBinding");
        }

        return result;
    }

    /*
     * <VariableInitialization>
     *     // empty
     *     '=' <AssignmentExpression> -- iff followed by(','|';'|<eol>|[scriptAssistParsing] && 'in')
     *                  
     *  -- on error, IGNORE/throw away the AssignmentExpression.
     */

    private Node parseVariableInitialization(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseVariableInitialization");
        }

        Node result = null;

        if (lookahead()==ASSIGN_TOKEN)
        {
            shift();
            Node t = parseAssignmentExpression(mode);
           
            if (lookahead()==COMMA_TOKEN ||
                lookaheadSemicolon(mode) ||
                (ctx.scriptAssistParsing && lookahead()==IN_TOKEN))
            {
                result = t;
            }
        }
        if (debug)
        {
            System.err.println("finish parseVariableInitialization");
        }

        return result;
    }
     
    /*
     * TypedIdentifier
     *         Identifier (':' ('*' | TypeExpression))?
     */

    private TypedIdentifierNode parseTypedIdentifier(int mode)
    {
        if (debug)
        {
            System.err.println("begin parseTypedIdentifier");
        }

        Node first = parseIdentifier();
        Node second = null;
        boolean no_anno = true;
       
        if (lookahead()==COLON_TOKEN)
        {           
          shift();
            no_anno = false;

          int lt = lookahead();
         
            if (lt==MULT_TOKEN || lt == MULTASSIGN_TOKEN)
            {
                if (lt==MULT_TOKEN)
                {
                  shift();
                }
                else
                {
                  changeLookahead(ASSIGN_TOKEN); // assume that '*=' meant '*' '='
                }
               
                if (ctx.scriptAssistParsing)
                {
                  second = nodeFactory.identifier(ASTERISK, false);
                }
            }
            else if( !errorIfNextTokenIsKeywordInsteadOfTypeExpression()  )
            {
              second = parseTypeExpression(mode);
            }
        }

        TypedIdentifierNode result = nodeFactory.typedIdentifier(first, second);
        result.no_anno = no_anno;

        if (debug)
        {
            System.err.println("finish parseTypedIdentifier");
        }

        return result;
    }

    /*
     * FunctionDefinition
     *     'function' FunctionName FunctionCommon
     */

    private Node parseFunctionDefinition(AttributeListNode first)
    {
        if (debug)
        {
            System.err.println("begin parseFunctionDefinition");
        }

        shift(); //match(FUNCTION_TOKEN);
       
        FunctionNameNode second = parseFunctionName();
        FunctionCommonNode third = parseFunctionCommon(second.identifier);
        Node result = nodeFactory.functionDefinition(ctx, first, second, third);

        if (debug)
        {
            System.err.println("finish parseFunctionDefinition");
        }

        return result;
    }

    /*
     * FunctionName
     *     Identifier
     *     'get' lookahead('(')
     *     'get' Identifier
     *     'set' lookahead('(')
     *     'set' Identifier
     */

    private FunctionNameNode parseFunctionName()
    {
        if (debug)
        {
            System.err.println("begin parseFunctionName");
        }

        FunctionNameNode result;
        int lt = lookahead();
       
        if (lt==GET_TOKEN)
        {
            shift();
            if (lookahead()==LEFTPAREN_TOKEN// function get(...) {...}
            {
                result = nodeFactory.functionName(EMPTY_TOKEN, nodeFactory.identifier(GET,false,scanner.input.positionOfMark()));
            }
            else
            {
                result = nodeFactory.functionName(GET_TOKEN, parseIdentifier());
            }
        }
        else if (lt==SET_TOKEN)
        {
            shift();
            if (lookahead()==LEFTPAREN_TOKEN// function set(...) {...}
            {
                result = nodeFactory.functionName(EMPTY_TOKEN, nodeFactory.identifier(SET,false,scanner.input.positionOfMark()));
            }
            else
            {
                result = nodeFactory.functionName(SET_TOKEN, parseIdentifier());
            }
        }
        else
        {
            result = nodeFactory.functionName(EMPTY_TOKEN, parseIdentifier());
        }

        if (debug)
        {
            System.err.println("finish parseFunctionName");
        }
       
        return result;
    }

    /*
     * ResultSignature
     *     (':' ('*' | 'void' | TypeExpression[allowIn]))?
     */

    private Node parseResultSignature(boolean no_anno[],boolean void_anno[])
    {
        if (debug)
        {
            System.err.println("begin parseResultSignature");
        }

        Node result = null;

        no_anno[0] = true;
        void_anno[0] = false;

        if (lookahead()==COLON_TOKEN)
        {
          no_anno[0] = false;
            shift();
            int lt = lookahead();
           
            if(lt==MULT_TOKEN)
            {
                shift();
                if (ctx.scriptAssistParsing)
                {
                  result = nodeFactory.identifier(ASTERISK,false,scanner.input.positionOfMark());
                }
            }
            else if(lt==MULTASSIGN_TOKEN) // Error, convert to assign for (potentially) better syntax error reporting
            {
                changeLookahead(ASSIGN_TOKEN);
            }
            else if(lt==VOID_TOKEN)
            {
                shift();
                void_anno[0] = true;
            }
            else
            {
                errorIfNextTokenIsKeywordInsteadOfTypeExpression();
                result = parseTypeExpression(allowIn_mode);
            }
        }

        if (debug)
        {
            System.err.println("finish parseResultSignature");
        }

        return result;
    }
   
    /*
     * FunctionSignature
     *     '(' Parameters ')' ResultSignature
     */

    private FunctionSignatureNode parseFunctionSignature()
    {
        if (debug)
        {
            System.err.println("begin parseFunctionSignature");
        }

        FunctionSignatureNode result;
        ParameterListNode first;
        Node second;
        boolean no_anno[] = new boolean[1];
        boolean void_anno[] = new boolean[1];

        match(LEFTPAREN_TOKEN);
        first = parseParameters();
        match(RIGHTPAREN_TOKEN);
       
        second = parseResultSignature(no_anno,void_anno);

        result = nodeFactory.functionSignature(first, second, scanner.input.positionOfMark());
        result.no_anno = no_anno[0];
        result.void_anno = void_anno[0];

        if (debug)
        {
            System.err.println("finish parseFunctionSignature");
        }

        return result;
    }

    /*
     * ConstructorSignature
     *     '(' Parameters ')' ConstructorInitializer
     */

    private FunctionSignatureNode parseConstructorSignature()
    {
        if (debug)
        {
            System.err.println("begin parseConstructorSignature");
        }

        FunctionSignatureNode result;
        ParameterListNode first;
        ListNode second;
        boolean no_anno[] = new boolean[1];
        boolean void_anno[] = new boolean[1];

        match(LEFTPAREN_TOKEN);
        first = parseParameters();
        match(RIGHTPAREN_TOKEN);
       
        second = parseConstructorInitializer(no_anno, void_anno);

        if( void_anno[0] )
        {
            result = nodeFactory.functionSignature(first, null, scanner.input.positionOfMark());
            result.no_anno = false;
            result.void_anno = true;
        }
        else
        {
            result = nodeFactory.constructorSignature(first, second, scanner.input.positionOfMark());
            result.no_anno = true;
            result.void_anno = false;
        }
       
        if (debug) {
            System.err.println("finish parseConstructorSignature");
        }

        return result;
    }

    /*
     * ConstructorInitializer
     *     ':' 'void'
     *     ':' InitializerList (SuperInitializer)?
     */
   
    private ListNode parseConstructorInitializer(boolean no_anno[], boolean void_anno[])
    {
        if (debug)
        {
            System.err.println("begin parseConstructorInitializer");
        }

        ListNode result = null;

        no_anno[0] = true;
        void_anno[0] = false;
       
        if (lookahead()==COLON_TOKEN)
        {
            shift();
            if(lookahead()==VOID_TOKEN)
            {
                // allow :void, since we allowed that in Flex2.0/AS3
                shift();
                no_anno[0] = false;
                void_anno[0] = true;
                return null;
            }
            result = parseInitializerList();
            if(lookahead()==SUPER_TOKEN)
            {
                result = nodeFactory.list(result, parseSuperInitializer() );
            }
        }

        if (debug) {
            System.err.println("finish parseConstructorInitializer");
        }

        return result;
    }

    /*
     * SuperInitializer
     *     'super' Arguments
     */
   
    private Node parseSuperInitializer()
    {
        if (debug)
        {
            System.err.println("begin parseSuperInitializer");
        }
       
        shift(); //match(SUPER_TOKEN);
       
        Node result = null;
        Node first = nodeFactory.superExpression(null, scanner.input.positionOfMark());
        Node n = parseArguments(first);
       
        if ( !( n instanceof CallExpressionNode))
        {
            ctx.internalError("Internal error in parseSuperInitializer()");
        }
       
        result = nodeFactory.superStatement((CallExpressionNode)n);

        if (debug) {
            System.err.println("end parseSuperInitializer");
        }
               
        return result;
    }
    /*
     * InitializerList
     *     Initializer,*
     */
   
    private ListNode parseInitializerList()
    {
      if (debug)
      {
            System.err.println("begin parseInitializerList");
        }

        ListNode result = null;

        while (true)
        {
          if (lookahead()==SUPER_TOKEN)
            break;
       
          Node t = parseInitializer();
         
          if (t!=null)
            result = nodeFactory.list(result, t);
         
          if (lookahead()!=COMMA_TOKEN)
            break;
         
          shift();
        }
       
        if (debug)
        {
            System.err.println("end parseInitializerList");
        }

        return result;
    }

    /*
     * Initializer
     *   Identifier '=' VariableInitialization
     */
   
    private Node parseInitializer()
    {
        if (debug)
        {
            System.err.println("begin parseInitializer");
        }

        Node result = null;

        // Todo: this should be parsePattern();
        Node first = parseIdentifier();
       
        if ( lookahead() != ASSIGN_TOKEN)
        {
            ctx.error(first.pos(), kError_Parser_DefinitionOrDirectiveExpected);
        }
       
        Node second = parseVariableInitialization(allowIn_mode);
       
        result = nodeFactory.assignmentExpression(first, ASSIGN_TOKEN, second);
       
        if (debug)
        {
            System.err.println("end parseInitializer");
        }

        return result;
    }

    /*
     * Parameters
     *         empty
     *         ParameterList
     */

    private ParameterListNode parseParameters()
    {
        if (debug)
        {
            System.err.println("begin parseParameters");
        }

        ParameterListNode result = null;

        if (lookahead()!=RIGHTPAREN_TOKEN)
        {
            result = parseParameterList();
        }

        if (debug)
        {
            System.err.println("finish parseParameters");
        }

        return result;
    }

    /*
     * ParameterList
     *     InitializedParameter,* ('...' RestParameter)?
     *    
     *     InitializedParameter
     *         Parameter | Parameter '=' NonAssignmentExpression
     */

    private ParameterListNode parseParameterList()
    {
        if (debug)
        {
            System.err.println("begin parseParameterList");
        }

        ParameterListNode result = null;

        while (true)
        {
          if (lookahead()==TRIPLEDOT_TOKEN)
          {
            result = nodeFactory.parameterList(result, parseRestParameter());
            break;
          }
         
          ParameterNode t = parseParameter();
          if (lookahead()==ASSIGN_TOKEN)
          {
            shift();
            t.init = parseNonAssignmentExpression(allowIn_mode);
          }
          result = nodeFactory.parameterList(result, t);
         
          if (lookahead()!=COMMA_TOKEN)
            break;
         
          shift();
        }

        if (debug)
        {
            System.err.println("finish parseParameterList");
        }

        return result;
    }

    /*
     * RestParameter
     *     : '...' <Parameter>
     *     ;
     */

    private ParameterNode parseRestParameter()
    {
        if (debug)
        {
            System.err.println("begin parseRestParameter");
        }

        ParameterNode result;
        ParameterNode first = null;

        shift(); //match(TRIPLEDOT_TOKEN);

        final int lt = lookahead();
        if (lt==CONST_TOKEN || lt==IDENTIFIER_TOKEN || lt==GET_TOKEN || lt==SET_TOKEN)
        {
            first = parseParameter();
        }
    
        result = nodeFactory.restParameter(first,scanner.input.positionOfMark());

        if (debug)
        {
            System.err.println("finish parseRestParameter");
        }

        return result;
    }

    /*
     * Parameter
     *     'const'? Identifier (':' TypeSpecification)?
     *
     * TypeSpecification
     *     '*'
     *     '*=' // Note: consume('*'), pushback('='), problem is '*=' token
     *     TypeExpression[allowIn]
     */

    private ParameterNode parseParameter()
    {
        if (debug)
        {
            System.err.println("begin parseParameter");
        }

        Node third = null;
        boolean no_anno = true;

        int first = VAR_TOKEN;
       
        if (HAS_CONSTPARAMETERS && lookahead()==CONST_TOKEN)
        {
          first = CONST_TOKEN;
          shift();
        }
       
        IdentifierNode second = parseIdentifier();
       
        if (lookahead()==COLON_TOKEN)
        {
          no_anno = false;
            shift();
            if(lookahead()==MULT_TOKEN)
            {
                shift();
                second.setOrigTypeToken(MULT_TOKEN);
            }
            else if(lookahead()==MULTASSIGN_TOKEN)
            {
                changeLookahead(ASSIGN_TOKEN)// morph into ordinary looking initializer
                second.setOrigTypeToken(MULTASSIGN_TOKEN);
            }
            else if( !errorIfNextTokenIsKeywordInsteadOfTypeExpression() )
            {
              third = parseTypeExpression(allowIn_mode);
            }
        }

        ParameterNode result = nodeFactory.parameter(first, second, third);
        result.no_anno = no_anno;

        if (debug)
        {
            System.err.println("finish parseParameter");
        }

        return result;
    }

    /**
     * This looks to see if the next token is a reserved keyword, if so then an error is thrown
     * for a keyword being used where we expected a type expression/identifier
     */
   
    private boolean errorIfNextTokenIsKeywordInsteadOfTypeExpression()
    {
      int lt = lookahead();
     
        if (lt == VOID_TOKEN)
        {
            error(ParseError.syntax, kError_Parser_keywordInsteadOfTypeExpr, Token.getTokenClassName(lt));
            match(VOID_TOKEN);
            return true;
        }
        else if (lt != IDENTIFIER_TOKEN && inXMLTokenSet(lt))
        {
            error(ParseError.syntax, kError_Parser_keywordInsteadOfTypeExpr, Token.getTokenClassName(lt));
            lt = lookahead();
            if (inXMLTokenSet(lt))
            {
              shift();
            }
            else
            {
              match(lt);
            }
            return true;
        }
        else if( ctx.dialect(8) && lt == IDENTIFIER_TOKEN && scanner.getCurrentTokenText().equals("Object") )
        {
          error(kError_ColonObjectAnnoOutOfService);
          return true;
        }
        return false;
    }

    /*
     * ClassDefinition:
     *     'class' ClassName Inheritance Block
     */

    private Node parseClassDefinition(AttributeListNode attrs, int mode)
    {
        if (debug)
        {
            System.err.println("begin parseClassDefinition");
        }

        shift(); //match(CLASS_TOKEN);

        if( block_kind_stack.last() != PACKAGE_TOKEN && block_kind_stack.last() != EMPTY_TOKEN )
        {
            error(kError_InvalidClassNesting);
        }

        block_kind_stack.add(CLASS_TOKEN);

        ClassNameNode first = parseClassName();
       
        String temp_class_name = current_class_name;
        current_class_name = first.ident.name;

        if( first.pkgname != null )
        {
          nodeFactory.startPackage(ctx,null,first.pkgname);
        }

        nodeFactory.StartClassDefs();
        InheritanceNode second = parseInheritance();
        StatementListNode third = parseBlock();
       
        if ( third == null )
        {
            // Class had an empty body.  Create an empty list to represent { }
            third = nodeFactory.statementList(null, null);
        }
       
        Node result = nodeFactory.classDefinition(ctx, attrs, first.ident, second, third, first.non_nullable);
        block_kind_stack.removeLast();
        current_class_name = temp_class_name;

        if( first.pkgname != null )
        {
          nodeFactory.finishPackage(ctx,null);
        }

        if (debug)
        {
            System.err.println("finish parseClassDefinition");
        }

        return result;
    }

    /*
     * ClassName
     *      CompoundName (('not'|'?')[es4_nullability])?
     *
     * CompoundName
     *     Identifier
     *     CompoundName '.' Identifier
     */

    private ClassNameNode parseClassName()
    {
        if (debug)
        {
            System.err.println("begin parseClassName");
        }

        ClassNameNode result;
        IdentifierNode first = parseIdentifier();
       
        if (HAS_COMPOUNDCLASSNAMES)
        {  
            PackageIdentifiersNode list = null;

            while (lookahead()==DOT_TOKEN)
            {
                shift();
                list = nodeFactory.packageIdentifiers(list, first, true);
                first = parseIdentifier();
            }

            PackageNameNode pkgname = (list!=null) ? nodeFactory.packageName(list) : null;
            result = nodeFactory.className(pkgname,first);
        }
        else
        {
            result = nodeFactory.className(null, first);
        }

        if( ctx.statics.es4_nullability )
        {
            if(lookahead()==NOT_TOKEN)
            {
                shift();
                result.non_nullable = true;
            }
            else if (lookahead()==QUESTIONMARK_TOKEN)
            {
                shift();
                // do nothing, classes are by default nullable.
            }
        }
       
        if (debug)
        {
            System.err.println("finish parseClassName");
        }

        return result;
    }

    /*
     * Inheritance
     *     ('extends' TypeExpression[allowIn])? ('implements' TypeExpressionList)?
     */

    private InheritanceNode parseInheritance()
    {
        if (debug)
        {
            System.err.println("begin parseInheritance");
        }

        InheritanceNode result = null;
        Node first = null;
        ListNode second = null;

        if (lookahead()==EXTENDS_TOKEN)
        {
            shift();
            first = parseTypename();
        }

        if (lookahead()==IMPLEMENTS_TOKEN)
        {
            shift();
            second = parseTypenameList();
        }

        if (first != null || second != null)
        {
            result = nodeFactory.inheritance(first, second);
        }

        if (debug)
        {
            System.err.println("finish parseInheritance");
        }

        return result;
    }

    /*
     * TypeExpressionList
     *     TypeExpression[allowIn],*
     *
     */

    private ListNode parseTypeExpressionList()
    {
        if (debug)
        {
            System.err.println("begin parseTypeExpressionList");
        }

        ListNode result = null;
        while (true)
        {
          Node t = parseTypeExpression(allowIn_mode);
         
          if ( t != null )
            result = nodeFactory.list(result,t);
         
          if (lookahead()!=COMMA_TOKEN)
            break;
         
          shift();
        }
       
        if (debug)
        {
            System.err.println("finish parseTypeExpressionList");
        }

        return result;
    }

    /*
     * InterfaceDefinition
     *     'interface' ClassName ('extends' TypeNameList)? Block
     */

    private Node parseInterfaceDefinition(AttributeListNode attrs, int mode)
    {
        if (debug)
        {
            System.err.println("begin parseInterfaceDefinition");
        }

        shift(); //match(INTERFACE_TOKEN);

        block_kind_stack.add(INTERFACE_TOKEN);

        ClassNameNode first = parseClassName();

        if( first.pkgname != null )
        {
          nodeFactory.startPackage(ctx,null,first.pkgname);
        }

         // (extends TypeExpressionList)?
       
        ListNode second = null;
        if (lookahead()==EXTENDS_TOKEN)
        {
          shift();
          second = parseTypenameList();
        }
        StatementListNode third  = parseBlock();
        Node result = nodeFactory.interfaceDefinition(ctx, attrs, first.ident, second, third);

        block_kind_stack.removeLast();

        if( first.pkgname != null )
        {
          nodeFactory.finishPackage(ctx,null);
        }

        if (debug)
        {
            System.err.println("finish parseInterfaceDefinition");
        }

        return result;
    }

    /*
     * NamespaceDefinition
     *     'namespace' Identifier ('=' (string|SimpleTypeIdentifier|AssignmentExpression[allowIn]))?
     */

    private NamespaceDefinitionNode parseNamespaceDefinition(AttributeListNode first)
    {
        if (debug)
        {
            System.err.println("begin parseNamespaceDefinition");
        }

        shift(); //match(NAMESPACE_TOKEN);

        IdentifierNode second = parseIdentifier();
        NamespaceDefinitionNode result;
       
        if( first != null && first.items.size() == 1 && first.hasAttribute("config"))
        {  
          /*
             * ConfigNamespaceDefinition
             *     "config" 'namespace' Identifier
             *     --pointless complexity abounds.
             *     Note that the first argument to configNamespaceDefinition below better be null.
             *     Why? Who knows...
             */
         
            result = nodeFactory.configNamespaceDefinition(null, second, -1);

            assert config_namespaces.size() > 0;
            config_namespaces.last().add(result.name.name);
        }
        else
        {
          Node third = null;

          if (lookahead()==ASSIGN_TOKEN)
          {
            shift();
            if( ctx.statics.es4_nullability )
            {
              if(lookahead()==STRINGLITERAL_TOKEN)
              {
                boolean[] is_single_quoted = new boolean[1];
                shift();
                String enclosedText = scanner.getCurrentStringTokenText(is_single_quoted);
                third = nodeFactory.literalString(enclosedText, scanner.input.positionOfMark(), is_single_quoted[0] );
              }
              else
              {
                third = parseSimpleTypeIdentifier();
              }
            }
            else
            {
              third = parseAssignmentExpression(allowIn_mode);
            }
          }
          result = nodeFactory.namespaceDefinition(first, second, third);
        }
       
        if (debug)
        {
            System.err.println("finish parseNamespaceDefinition");
        }

        return result;
    }
   
    public static UseDirectiveNode generateAs3UseDirective(Context ctx)
    {
        NodeFactory nodeFactory = ctx.getNodeFactory();
        IdentifierNode as3Identifier = nodeFactory.identifier(AS3, false);
       
//        Namespaces namespaces = new Namespaces();
//        NamespaceValue namespaceValue = new NamespaceValue();
//        namespaces.add(namespaceValue);     
//        ReferenceValue referenceValue = new ReferenceValue(ctx, null, AS3, namespaces);
       
        ReferenceValue referenceValue = new ReferenceValue(ctx, null, AS3, ctx.AS3Namespace());
        referenceValue.setIsAttributeIdentifier(false);
        as3Identifier.ref = referenceValue;
        return nodeFactory.useDirective(null,nodeFactory.memberExpression(null,nodeFactory.getExpression(as3Identifier)));
    }

    /*
     * PackageDefinition
     *     'package' PackageName? Block
     */
   
    private PackageDefinitionNode parsePackageDefinition()
    {
        if (debug)
        {
            System.err.println("begin parsePackageDefinition");
        }

        if (within_package)
            error(kError_NestedPackage);

        within_package = true;

        // Init the default xml namespace

        nodeFactory.dxns = null;

        block_kind_stack.add(PACKAGE_TOKEN);

        shift(); //match(PACKAGE_TOKEN);

        assert config_namespaces.size() > 0;
        HashSet<String> conf_ns = new HashSet<String>(config_namespaces.last().size());
        conf_ns.addAll(config_namespaces.last());
        config_namespaces.push_back(conf_ns);
       
        PackageNameNode first = null;
        final boolean has_packagename = (lookahead()!=LEFTBRACE_TOKEN);
       
        if (has_packagename==true)
        {
            first = parsePackageName(false);
        }
         
        PackageDefinitionNode result = nodeFactory.startPackage(ctx, null, first);
       
        // Careful, when adding synthetic UseDirectiveNodes they must be created
        // in between calls to start/finishPackage.  Otherwise they won't have their
        // pkgdef ptr set up correctly, and things will go mysteriously awry later.
       
        Node as3UseDirective = generateAs3UseDirective(ctx);
        ObjectList<UseDirectiveNode> useDirectives = null;
       
        if (!ctx.statics.use_namespaces.isEmpty())
        {
          useDirectives = new ObjectList<UseDirectiveNode>();
          for (String u : ctx.statics.use_namespaces)
          {
            useDirectives.add(
                nodeFactory.useDirective(null,
                    nodeFactory.memberExpression(null,
                        nodeFactory.getExpression(
                            nodeFactory.identifier(u)))));
          }
        }
       
        Node importDirective = null;
        if (ctx.statics.es4_vectors)
        {
          PackageIdentifiersNode pin = nodeFactory.packageIdentifiers(null, nodeFactory.identifier(__AS3__, false), true);
          pin = nodeFactory.packageIdentifiers(pin, nodeFactory.identifier(VEC, false), true);
          pin = nodeFactory.packageIdentifiers(pin, nodeFactory.identifier(VECTOR, false), true);
          importDirective = nodeFactory.importDirective(null, nodeFactory.packageName(pin), null, ctx);
        }
       
        result = nodeFactory.finishPackage(ctx, parseBlock());
           
        // General disclaimer: (pmd 5/28/09)
        // This code was refactored, it was very badly written (redundant cut & paste, no comments etc.).
        // I do know that use/import statement ordering matters, I dont know why.
        // Note that earlier add(1,...) end up AFTER following add(1,..) statements
       
        if ((ctx.dialect(10) /*|| ctx.dialect(11)*/) && result != null)
        {
          result.statements.items.add(1,as3UseDirective)// insert after the first statement, which is the starting package definition
        }
           
        // Add importDirective AFTER useDirectives...if there is no packagename...

        if (has_packagename == false && ctx.statics.es4_vectors && result != null)
        {
          result.statements.items.add(1, importDirective);
        }

        if (useDirectives != null && result != null)
        {
          for( UseDirectiveNode u : useDirectives )
          {
            result.statements.items.add(1,u);
          }
        }

        // Or add the importDirective BEFORE, why? who knows...

        if (has_packagename == true && ctx.statics.es4_vectors && result != null)
        {
          result.statements.items.add(1, importDirective);
        }

        block_kind_stack.removeLast();
        config_namespaces.pop_back();
       
        if (debug)
        {
            System.err.println("finish parsePackageDefinition");
        }

        within_package = false;

        return result;
    }

    public StatementListNode parseConfigValues()
    {
        StatementListNode configs = null;
        String config_code = ctx.getConfigVarCode();
       
        if (config_code != null)
        {
            Scanner orig = scanner;
            InputBuffer orig_input = scanner.input;
            int orig_nextToken = nextToken;
           
            scanner = new Scanner(ctx, config_code, "");
            scanner.input.report_pos = false// Don't give position to generated nodes, since they don't have corresponding source

            configs = parseDirectives(null, null);

            scanner = orig;
            scanner.input = orig_input;
            ctx.input = orig_input; // cause the scanner alters this....piss poor design.
            nextToken = orig_nextToken;
        }
        return configs;
    }
   
    /*
     * PackageName
     *      string | PackageIdentifier
     *
     * PackageIdentifier
     *      Identifier
     *     PackageIdentifier '.' propertyIdentifier
     */

    private PackageNameNode parsePackageName(boolean isDefinition)
    {
        if (debug)
        {
            System.err.println("begin parsePackageName");
        }

        PackageNameNode result;

        if (lookahead()==STRINGLITERAL_TOKEN)
        {
            boolean[] is_single_quoted = new boolean[1];
            shift();
            String enclosedText = scanner.getCurrentStringTokenText(is_single_quoted);
            LiteralStringNode first = nodeFactory.literalString(enclosedText, scanner.input.positionOfMark(), is_single_quoted[0]);
            result = nodeFactory.packageName(first);
        }
        else
        {
            PackageIdentifiersNode first = nodeFactory.packageIdentifiers(null, parseIdentifier(), isDefinition);
           
            while (lookahead()==DOT_TOKEN)
            {
                shift();
                first = nodeFactory.packageIdentifiers(first, parsePropertyIdentifier(), isDefinition);
            }
            result = nodeFactory.packageName(first);
        }

        if (debug)
        {
            System.err.println("finish parsePackageName");
        }

        return result;
    }

    /*
     * Program
     *     Directives
     *     PackageDefinition
     *
     * <B>CLEARS unused buffers before returning</B></PRE>
     */
   
    public ProgramNode parseProgram()
    {
        if (debug)
        {
            System.err.println("begin parseProgram");
        }

        StatementListNode first = null;
        StatementListNode second = null;
        StatementListNode configs = null;
       
        if( !parsing_include )
        {
            config_namespaces.push_back(new HashSet<String>());
            config_namespaces.last().add(CONFIG);
            configs = parseConfigValues();
        }

        // Default config namespace
        //config_namespaces.last().add("CONFIG");
       
        while (lookahead()==PACKAGE_TOKEN || lookahead()==DOCCOMMENT_TOKEN)
        {
          // TODO: Obviously, the above line disallows the following checks for LEFTBRACKET or XMLliteral...
         
            MetaDataNode meta=null;
            if (lookahead()==DOCCOMMENT_TOKEN || lookahead()==LEFTBRACKET_TOKEN || lookahead()==XMLLITERAL_TOKEN)
            {
                meta = parseMetaData();
                second = nodeFactory.statementList(second,meta);
            }

            if (lookahead()==PACKAGE_TOKEN)
            {
                PackageDefinitionNode pkgdef = parsePackageDefinition();
                first = nodeFactory.statementList(first, pkgdef );
                if (meta != null)
                {
                    meta.def = pkgdef;
                    pkgdef.addMetaDataNode(meta);
                }
               
                // Merge the package statements with the existing statements
                if (pkgdef != null) // package is NULL if there was an erronously nested package.  Error has already been generated
                {
                    second = nodeFactory.statementList(second,pkgdef.statements);
                }
            }
        }

        second = parseDirectives(null/*attrs*/,second);

        if ( (ctx.dialect(10) /*|| ctx.dialect(11)*/) && !parsing_include && second != null // don't insert a statement for includes because will screw up metadata parsing
        {
            Node udn = generateAs3UseDirective(ctx);
            second.items.add(0,udn);
        }
       
        if (!ctx.statics.use_namespaces.isEmpty() && !parsing_include && second != null)
        {
            for (String useName : ctx.statics.use_namespaces )
            {
                Node udn2 = nodeFactory.useDirective(null,nodeFactory.memberExpression(null,nodeFactory.getExpression(nodeFactory.identifier(useName))));
                second.items.add(0,udn2);
            }
        }
       
        if (ctx.statics.es4_vectors && !parsing_include && second != null)
        {
            PackageIdentifiersNode pin = nodeFactory.packageIdentifiers(null, nodeFactory.identifier(__AS3__, false), true);
            pin = nodeFactory.packageIdentifiers(pin, nodeFactory.identifier(VEC, false), true);
            pin = nodeFactory.packageIdentifiers(pin, nodeFactory.identifier(VECTOR, false), true);
            Node idn = nodeFactory.importDirective(null, nodeFactory.packageName(pin), null, ctx);
            second.items.add(0, idn);
        }
       
        ProgramNode result = nodeFactory.program(ctx,second,scanner.input.positionOfMark());
        match(EOS_TOKEN);

        if (ctx.scriptAssistParsing)
        {
          //the parser comments are needed after the parser is gone
       
          for (ListIterator<Node> it = comments.listIterator(); it.hasNext(); )
        {
          ctx.comments.add(it.next());
        }
        }
       
        clearUnusedBuffers()
       
        if (!parsing_include)
        {
            if (result != null)
            {
              // Add tool chain added values
              if (configs != null)
                result.statements.items.addAll(0, configs.items);
              NamespaceDefinitionNode configdef = nodeFactory.configNamespaceDefinition(null, nodeFactory.identifier(CONFIG, false), -1);
              // Add the default CONFIG namespace
              result.statements.items.add(0, configdef);
            }
            config_namespaces.pop_back();
        }
       
        if (debug)
        {
            System.err.println("finish parseProgram");
        }
       
        return result;
    }
}
TOP

Related Classes of macromedia.asc.parser.Parser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.