/*
 * Copyright (C) 2010 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include "JSParser.h"

using namespace JSC;

#include "JSGlobalData.h"
#include "NodeInfo.h"
#include "ASTBuilder.h"
#include <wtf/HashFunctions.h>
#include <utility>

using namespace std;

namespace JSC {
#define fail() do { m_error = true; return 0; } while (0)
#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
#define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
#define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0)
#define matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0)
#define failIfStackOverflow() do { failIfFalse(canRecurse()); } while (0)

// Macros to make the more common TreeBuilder types a little less verbose
#define TreeStatement typename TreeBuilder::Statement
#define TreeExpression typename TreeBuilder::Expression
#define TreeFormalParameterList typename TreeBuilder::FormalParameterList
#define TreeSourceElements typename TreeBuilder::SourceElements
#define TreeClause typename TreeBuilder::Clause
#define TreeClauseList typename TreeBuilder::ClauseList
#define TreeConstDeclList typename TreeBuilder::ConstDeclList
#define TreeArguments typename TreeBuilder::Arguments
#define TreeArgumentsList typename TreeBuilder::ArgumentsList
#define TreeFunctionBody typename TreeBuilder::FunctionBody
#define TreeProperty typename TreeBuilder::Property
#define TreePropertyList typename TreeBuilder::PropertyList

COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);

// This matches v8
static const ptrdiff_t kMaxParserStackUsage = 128 * sizeof(void*) * 1024;

class JSParser {
public:
    JSParser(Lexer*, JSGlobalData*, SourceProvider*);
    bool parseProgram();
private:
    struct AllowInOverride {
        AllowInOverride(JSParser* parser)
            : m_parser(parser)
            , m_oldAllowsIn(parser->m_allowsIn)
        {
            parser->m_allowsIn = true;
        }
        ~AllowInOverride()
        {
            m_parser->m_allowsIn = m_oldAllowsIn;
        }
        JSParser* m_parser;
        bool m_oldAllowsIn;
    };

    const JSToken& token() { return m_token; }
    void next(Lexer::LexType lexType = Lexer::IdentifyReservedWords)
    {
        m_lastLine = token().m_info.line;
        m_lastTokenEnd = token().m_info.endOffset;
        m_lexer->setLastLineNumber(m_lastLine);
        m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexType);
        m_tokenCount++;
    }

    bool consume(JSTokenType expected)
    {
        bool result = m_token.m_type == expected;
        failIfFalse(result);
        next();
        return result;
    }

    bool match(JSTokenType expected)
    {
        return m_token.m_type == expected;
    }

    int tokenStart()
    {
        return token().m_info.startOffset;
    }

    int tokenLine()
    {
        return token().m_info.line;
    }

    int tokenEnd()
    {
        return token().m_info.endOffset;
    }

    template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseBreakStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseContinueStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseReturnStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseThrowStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseWithStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseSwitchStatement(TreeBuilder&);
    template <class TreeBuilder> TreeClauseList parseSwitchClauses(TreeBuilder&);
    template <class TreeBuilder> TreeClause parseSwitchDefaultClause(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseTryStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseDebuggerStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&);
    template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeStatement parseBlockStatement(TreeBuilder&);
    template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
    template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&);
    template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
    template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&);
    template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&, bool& usesArguments);
    template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd);
    template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
    enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
    template <FunctionRequirements, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
    ALWAYS_INLINE int isBinaryOperator(JSTokenType token);
    bool allowAutomaticSemicolon();

    bool autoSemiColon()
    {
        if (token().m_type == SEMICOLON) {
            next();
            return true;
        }
        return allowAutomaticSemicolon();
    }

    bool canRecurse()
    {
        char sample = 0;
        ASSERT(m_endAddress);
        return &sample > m_endAddress;
    }
    
    int lastTokenEnd() const
    {
        return m_lastTokenEnd;
    }

    ParserArena m_arena;
    Lexer* m_lexer;
    char* m_endAddress;
    bool m_error;
    JSGlobalData* m_globalData;
    JSToken m_token;
    bool m_allowsIn;
    int m_tokenCount;
    int m_lastLine;
    int m_lastTokenEnd;
    int m_assignmentCount;
    int m_nonLHSCount;
    bool m_syntaxAlreadyValidated;
};

int jsParse(JSGlobalData* globalData, const SourceCode* source)
{
    JSParser parser(globalData->lexer, globalData, source->provider());
    return parser.parseProgram();
}

JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, SourceProvider* provider)
    : m_lexer(lexer)
    , m_endAddress(0)
    , m_error(false)
    , m_globalData(globalData)
    , m_allowsIn(true)
    , m_tokenCount(0)
    , m_lastLine(0)
    , m_lastTokenEnd(0)
    , m_assignmentCount(0)
    , m_nonLHSCount(0)
    , m_syntaxAlreadyValidated(provider->isValid())
{
    m_endAddress = *(globalData->stackGuards);
    if (!m_endAddress) {
        char sample = 0;
        m_endAddress = &sample - kMaxParserStackUsage;
        *(globalData->stackGuards) = m_endAddress;
    }
    next();
    m_lexer->setLastLineNumber(tokenLine());
}

bool JSParser::parseProgram()
{
    ASTBuilder context(m_globalData, m_lexer);
    SourceElements* sourceElements = parseSourceElements<ASTBuilder>(context);
    if (!sourceElements || !consume(EOFTOK))
        return true;
    m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features(),
                                          m_lastLine, context.numConstants());
    return false;
}

bool JSParser::allowAutomaticSemicolon()
{
    return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
}

template <class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
{
    TreeSourceElements sourceElements = context.createSourceElements();
    while (TreeStatement statement = parseStatement(context))
        context.appendStatement(sourceElements, statement);

    if (m_error)
        fail();
    return sourceElements;
}

template <class TreeBuilder> TreeStatement JSParser::parseVarDeclaration(TreeBuilder& context)
{
    ASSERT(match(VAR));
    int start = tokenLine();
    int end = 0;
    int scratch;
    const Identifier* scratch1 = 0;
    TreeExpression scratch2 = 0;
    int scratch3 = 0;
    TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3);
    failIfTrue(m_error);
    failIfFalse(autoSemiColon());

    return context.createVarStatement(varDecls, start, end);
}

template <class TreeBuilder> TreeStatement JSParser::parseConstDeclaration(TreeBuilder& context)
{
    ASSERT(match(CONSTTOKEN));
    int start = tokenLine();
    int end = 0;
    TreeConstDeclList constDecls = parseConstDeclarationList(context);
    failIfTrue(m_error);
    failIfFalse(autoSemiColon());
    
    return context.createConstStatement(constDecls, start, end);
}

template <class TreeBuilder> TreeStatement JSParser::parseDoWhileStatement(TreeBuilder& context)
{
    ASSERT(match(DO));
    int startLine = tokenLine();
    next();
    TreeStatement statement = parseStatement(context);
    failIfFalse(statement);
    int endLine = tokenLine();
    consumeOrFail(WHILE);
    consumeOrFail(OPENPAREN);
    TreeExpression expr = parseExpression(context);
    failIfFalse(expr);
    consumeOrFail(CLOSEPAREN);
    if (match(SEMICOLON))
        next(); // Always performs automatic semicolon insertion.
    return context.createDoWhileStatement(statement, expr, startLine, endLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseWhileStatement(TreeBuilder& context)
{
    ASSERT(match(WHILE));
    int startLine = tokenLine();
    next();
    consumeOrFail(OPENPAREN);
    TreeExpression expr = parseExpression(context);
    failIfFalse(expr);
    int endLine = tokenLine();
    consumeOrFail(CLOSEPAREN);
    TreeStatement statement = parseStatement(context);
    failIfFalse(statement);
    return context.createWhileStatement(expr, statement, startLine, endLine);
}

template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(TreeBuilder& context, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd)
{
    TreeExpression varDecls = 0;
    do {
        declarations++;
        next();
        matchOrFail(IDENT);

        int varStart = tokenStart();
        identStart = varStart;
        const Identifier* name = token().m_data.ident;
        lastIdent = name;
        next();
        bool hasInitializer = match(EQUAL);
        context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
        if (hasInitializer) {
            int varDivot = tokenStart() + 1;
            initStart = tokenStart();
            next(); // consume '='
            int initialAssignments = m_assignmentCount;
            TreeExpression initializer = parseAssignmentExpression(context);
            initEnd = lastTokenEnd();
            lastInitializer = initializer;
            failIfFalse(initializer);

            TreeExpression node = context.createAssignResolve(*name, initializer, initialAssignments != m_assignmentCount, varStart, varDivot, lastTokenEnd());
            if (!varDecls)
                varDecls = node;
            else
                varDecls = context.combineCommaNodes(varDecls, node);
        }
    } while (match(COMMA));
    return varDecls;
}

template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationList(TreeBuilder& context)
{
    TreeConstDeclList constDecls = 0;
    TreeConstDeclList tail = 0;
    do {
        next();
        matchOrFail(IDENT);
        const Identifier* name = token().m_data.ident;
        next();
        bool hasInitializer = match(EQUAL);
        context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
        TreeExpression initializer = 0;
        if (hasInitializer) {
            next(); // consume '='
            initializer = parseAssignmentExpression(context);
        }
        tail = context.appendConstDecl(tail, name, initializer);
        if (!constDecls)
            constDecls = tail;
    } while (match(COMMA));
    return constDecls;
}

template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuilder& context)
{
    ASSERT(match(FOR));
    int startLine = tokenLine();
    next();
    consumeOrFail(OPENPAREN);
    int nonLHSCount = m_nonLHSCount;
    int declarations = 0;
    int declsStart = 0;
    int declsEnd = 0;
    TreeExpression decls = 0;
    bool hasDeclaration = false;
    if (match(VAR)) {
        /*
         for (var IDENT in expression) statement
         for (var IDENT = expression in expression) statement
         for (var varDeclarationList; expressionOpt; expressionOpt)
         */
        hasDeclaration = true;
        const Identifier* forInTarget = 0;
        TreeExpression forInInitializer = 0;
        m_allowsIn = false;
        int initStart = 0;
        int initEnd = 0;
        decls = parseVarDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd);
        m_allowsIn = true;
        if (m_error)
            fail();

        // Remainder of a standard for loop is handled identically
        if (declarations > 1 || match(SEMICOLON))
            goto standardForLoop;

        // Handle for-in with var declaration
        int inLocation = tokenStart();
        if (!consume(INTOKEN))
            fail();

        TreeExpression expr = parseExpression(context);
        failIfFalse(expr);
        int exprEnd = lastTokenEnd();

        int endLine = tokenLine();
        consumeOrFail(CLOSEPAREN);

        TreeStatement statement = parseStatement(context);
        failIfFalse(statement);

        return context.createForInLoop(forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine);
    }

    if (!match(SEMICOLON)) {
        m_allowsIn = false;
        declsStart = tokenStart();
        decls = parseExpression(context);
        declsEnd = lastTokenEnd();
        m_allowsIn = true;
        failIfFalse(decls);
    }

    if (match(SEMICOLON)) {
    standardForLoop:
        // Standard for loop
        next();
        TreeExpression condition = 0;

        if (!match(SEMICOLON)) {
            condition = parseExpression(context);
            failIfFalse(condition);
        }
        consumeOrFail(SEMICOLON);

        TreeExpression increment = 0;
        if (!match(CLOSEPAREN)) {
            increment = parseExpression(context);
            failIfFalse(increment);
        }
        int endLine = tokenLine();
        consumeOrFail(CLOSEPAREN);
        TreeStatement statement = parseStatement(context);
        failIfFalse(statement);
        return context.createForLoop(decls, condition, increment, statement, hasDeclaration, startLine, endLine);
    }

    // For-in loop
    failIfFalse(nonLHSCount == m_nonLHSCount);
    consumeOrFail(INTOKEN);
    TreeExpression expr = parseExpression(context);
    failIfFalse(expr);
    int exprEnd = lastTokenEnd();
    int endLine = tokenLine();
    consumeOrFail(CLOSEPAREN);
    TreeStatement statement = parseStatement(context);
    failIfFalse(statement);
    
    return context.createForInLoop(decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseBreakStatement(TreeBuilder& context)
{
    ASSERT(match(BREAK));
    int startCol = tokenStart();
    int endCol = tokenEnd();
    int startLine = tokenLine();
    int endLine = tokenLine();
    next();

    if (autoSemiColon())
        return context.createBreakStatement(startCol, endCol, startLine, endLine);
    matchOrFail(IDENT);
    const Identifier* ident = token().m_data.ident;
    endCol = tokenEnd();
    endLine = tokenLine();
    next();
    failIfFalse(autoSemiColon());
    return context.createBreakStatement(ident, startCol, endCol, startLine, endLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(TreeBuilder& context)
{
    ASSERT(match(CONTINUE));
    int startCol = tokenStart();
    int endCol = tokenEnd();
    int startLine = tokenLine();
    int endLine = tokenLine();
    next();

    if (autoSemiColon())
        return context.createContinueStatement(startCol, endCol, startLine, endLine);
    matchOrFail(IDENT);
    const Identifier* ident = token().m_data.ident;
    endCol = tokenEnd();
    endLine = tokenLine();
    next();
    failIfFalse(autoSemiColon());
    return context.createContinueStatement(ident, startCol, endCol, startLine, endLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseReturnStatement(TreeBuilder& context)
{
    ASSERT(match(RETURN));
    int startLine = tokenLine();
    int endLine = startLine;
    int start = tokenStart();
    int end = tokenEnd();
    next();
    // We do the auto semicolon check before attempting to parse an expression
    // as we need to ensure the a line break after the return correctly terminates
    // the statement
    if (match(SEMICOLON))
        endLine  = tokenLine();
    if (autoSemiColon())
        return context.createReturnStatement(0, start, end, startLine, endLine);
    TreeExpression expr = parseExpression(context);
    failIfFalse(expr);
    end = lastTokenEnd();
    if (match(SEMICOLON))
        endLine  = tokenLine();
    failIfFalse(autoSemiColon());
    return context.createReturnStatement(expr, start, end, startLine, endLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseThrowStatement(TreeBuilder& context)
{
    ASSERT(match(THROW));
    int eStart = tokenStart();
    int startLine = tokenLine();
    next();

    TreeExpression expr = parseExpression(context);
    failIfFalse(expr);
    int eEnd = lastTokenEnd();
    int endLine = tokenLine();
    failIfFalse(autoSemiColon());

    return context.createThrowStatement(expr, eStart, eEnd, startLine, endLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuilder& context)
{
    ASSERT(match(WITH));
    int startLine = tokenLine();
    next();
    consumeOrFail(OPENPAREN);
    int start = tokenStart();
    TreeExpression expr = parseExpression(context);
    failIfFalse(expr);
    int end = lastTokenEnd();

    int endLine = tokenLine();
    consumeOrFail(CLOSEPAREN);
    
    TreeStatement statement = parseStatement(context);
    failIfFalse(statement);

    return context.createWithStatement(expr, statement, start, end, startLine, endLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBuilder& context)
{
    ASSERT(match(SWITCH));
    int startLine = tokenLine();
    next();
    consumeOrFail(OPENPAREN);
    TreeExpression expr = parseExpression(context);
    failIfFalse(expr);
    int endLine = tokenLine();
    consumeOrFail(CLOSEPAREN);
    consumeOrFail(OPENBRACE);

    TreeClauseList firstClauses = parseSwitchClauses(context);
    failIfTrue(m_error);

    TreeClause defaultClause = parseSwitchDefaultClause(context);
    failIfTrue(m_error);

    TreeClauseList secondClauses = parseSwitchClauses(context);
    failIfTrue(m_error);
    consumeOrFail(CLOSEBRACE);

    return context.createSwitchStatement(expr, firstClauses, defaultClause, secondClauses, startLine, endLine);

}

template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBuilder& context)
{
    if (!match(CASE))
        return 0;
    next();
    TreeExpression condition = parseExpression(context);
    failIfFalse(condition);
    consumeOrFail(COLON);
    TreeSourceElements statements = parseSourceElements(context);
    failIfFalse(statements);
    TreeClause clause = context.createClause(condition, statements);
    TreeClauseList clauseList = context.createClauseList(clause);
    TreeClauseList tail = clauseList;

    while (match(CASE)) {
        next();
        TreeExpression condition = parseExpression(context);
        failIfFalse(condition);
        consumeOrFail(COLON);
        TreeSourceElements statements = parseSourceElements(context);
        failIfFalse(statements);
        clause = context.createClause(condition, statements);
        tail = context.createClauseList(tail, clause);
    }
    return clauseList;
}

template <class TreeBuilder> TreeClause JSParser::parseSwitchDefaultClause(TreeBuilder& context)
{
    if (!match(DEFAULT))
        return 0;
    next();
    consumeOrFail(COLON);
    TreeSourceElements statements = parseSourceElements(context);
    failIfFalse(statements);
    return context.createClause(0, statements);
}

template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuilder& context)
{
    ASSERT(match(TRY));
    TreeStatement tryBlock = 0;
    const Identifier* ident = &m_globalData->propertyNames->nullIdentifier;
    bool catchHasEval = false;
    TreeStatement catchBlock = 0;
    TreeStatement finallyBlock = 0;
    int firstLine = tokenLine();
    next();
    matchOrFail(OPENBRACE);

    tryBlock = parseBlockStatement(context);
    failIfFalse(tryBlock);
    int lastLine = m_lastLine;

    if (match(CATCH)) {
        next();
        consumeOrFail(OPENPAREN);
        matchOrFail(IDENT);
        ident = token().m_data.ident;
        next();
        consumeOrFail(CLOSEPAREN);
        matchOrFail(OPENBRACE);
        int initialEvalCount = context.evalCount();
        catchBlock = parseBlockStatement(context);
        failIfFalse(catchBlock);
        catchHasEval = initialEvalCount != context.evalCount();
    }

    if (match(FINALLY)) {
        next();
        matchOrFail(OPENBRACE);
        finallyBlock = parseBlockStatement(context);
        failIfFalse(finallyBlock);
    }
    failIfFalse(catchBlock || finallyBlock);
    return context.createTryStatement(tryBlock, ident, catchHasEval, catchBlock, finallyBlock, firstLine, lastLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseDebuggerStatement(TreeBuilder& context)
{
    ASSERT(match(DEBUGGER));
    int startLine = tokenLine();
    int endLine = startLine;
    next();
    if (match(SEMICOLON))
        startLine = tokenLine();
    failIfFalse(autoSemiColon());
    return context.createDebugger(startLine, endLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseBlockStatement(TreeBuilder& context)
{
    ASSERT(match(OPENBRACE));
    int start = tokenLine();
    next();
    if (match(CLOSEBRACE)) {
        next();
        return context.createBlockStatement(0, start, m_lastLine);
    }
    TreeSourceElements subtree = parseSourceElements(context);
    failIfFalse(subtree);
    matchOrFail(CLOSEBRACE);
    next();
    return context.createBlockStatement(subtree, start, m_lastLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context)
{
    failIfStackOverflow();
    switch (token().m_type) {
    case OPENBRACE:
        return parseBlockStatement(context);
    case VAR:
        return parseVarDeclaration(context);
    case CONSTTOKEN:
        return parseConstDeclaration(context);
    case FUNCTION:
        return parseFunctionDeclaration(context);
    case SEMICOLON:
        next();
        return context.createEmptyStatement();
    case IF:
        return parseIfStatement(context);
    case DO:
        return parseDoWhileStatement(context);
    case WHILE:
        return parseWhileStatement(context);
    case FOR:
        return parseForStatement(context);
    case CONTINUE:
        return parseContinueStatement(context);
    case BREAK:
        return parseBreakStatement(context);
    case RETURN:
        return parseReturnStatement(context);
    case WITH:
        return parseWithStatement(context);
    case SWITCH:
        return parseSwitchStatement(context);
    case THROW:
        return parseThrowStatement(context);
    case TRY:
        return parseTryStatement(context);
    case DEBUGGER:
        return parseDebuggerStatement(context);
    case EOFTOK:
    case CASE:
    case CLOSEBRACE:
    case DEFAULT:
        // These tokens imply the end of a set of source elements
        return 0;
    case IDENT:
        return parseExpressionOrLabelStatement(context);
    default:
        return parseExpressionStatement(context);
    }
}

template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParameters(TreeBuilder& context, bool& usesArguments)
{
    matchOrFail(IDENT);
    usesArguments = m_globalData->propertyNames->arguments == *token().m_data.ident;
    TreeFormalParameterList list = context.createFormalParameterList(*token().m_data.ident);
    TreeFormalParameterList tail = list;
    next();
    while (match(COMMA)) {
        next();
        matchOrFail(IDENT);
        const Identifier* ident = token().m_data.ident;
        next();
        usesArguments = usesArguments || m_globalData->propertyNames->arguments == *ident;
        tail = context.createFormalParameterList(tail, *ident);
    }
    return list;
}

template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBuilder& context)
{
    if (match(CLOSEBRACE))
        return context.createFunctionBody();
    typename TreeBuilder::FunctionBodyBuilder bodyBuilder(m_globalData, m_lexer);
    failIfFalse(parseSourceElements(bodyBuilder));
    return context.createFunctionBody();
}

template <JSParser::FunctionRequirements requirements, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
{
    if (match(IDENT)) {
        name = token().m_data.ident;
        next();
    } else if (requirements == FunctionNeedsName)
        return false;
    consumeOrFail(OPENPAREN);
    bool usesArguments = false;
    if (!match(CLOSEPAREN)) {
        parameters = parseFormalParameters(context, usesArguments);
        failIfFalse(parameters);
    }
    consumeOrFail(CLOSEPAREN);
    matchOrFail(OPENBRACE);

    openBracePos = token().m_data.intValue;
    bodyStartLine = tokenLine();
    next();

    body = parseFunctionBody(context);
    failIfFalse(body);
    if (usesArguments)
        context.setUsesArguments(body);

    matchOrFail(CLOSEBRACE);
    closeBracePos = token().m_data.intValue;
    next();
    return true;
}

template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(TreeBuilder& context)
{
    ASSERT(match(FUNCTION));
    next();
    const Identifier* name = 0;
    TreeFormalParameterList parameters = 0;
    TreeFunctionBody body = 0;
    int openBracePos = 0;
    int closeBracePos = 0;
    int bodyStartLine = 0;
    failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine));
    failIfFalse(name);
    return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelStatement(TreeBuilder& context)
{

    /* Expression and Label statements are ambiguous at LL(1), to avoid
     * the cost of having a token buffer to support LL(2) we simply assume
     * we have an expression statement, and then only look for a label if that
     * parse fails.
     */
    int start = tokenStart();
    int startLine = tokenLine();
    const Identifier* ident = token().m_data.ident;
    int currentToken = m_tokenCount;
    TreeExpression expression = parseExpression(context);
    failIfFalse(expression);
    if (autoSemiColon())
        return context.createExprStatement(expression, startLine, m_lastLine);
    failIfFalse(currentToken + 1 == m_tokenCount);
    int end = tokenEnd();
    consumeOrFail(COLON);
    TreeStatement statement = parseStatement(context);
    failIfFalse(statement);
    return context.createLabelStatement(ident, statement, start, end);
}

template <class TreeBuilder> TreeStatement JSParser::parseExpressionStatement(TreeBuilder& context)
{
    int startLine = tokenLine();
    TreeExpression expression = parseExpression(context);
    failIfFalse(expression);
    failIfFalse(autoSemiColon());
    return context.createExprStatement(expression, startLine, m_lastLine);
}

template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilder& context)
{
    ASSERT(match(IF));

    int start = tokenLine();
    next();

    consumeOrFail(OPENPAREN);

    TreeExpression condition = parseExpression(context);
    failIfFalse(condition);
    int end = tokenLine();
    consumeOrFail(CLOSEPAREN);

    TreeStatement trueBlock = parseStatement(context);
    failIfFalse(trueBlock);

    if (!match(ELSE))
        return context.createIfStatement(condition, trueBlock, start, end);
    
    Vector<TreeExpression> exprStack;
    Vector<pair<int, int> > posStack;
    Vector<TreeStatement> statementStack;
    bool trailingElse = false;
    do {
        next();
        if (!match(IF)) {
            TreeStatement block = parseStatement(context);
            failIfFalse(block);
            statementStack.append(block);
            trailingElse = true;
            break;
        }
        int innerStart = tokenLine();
        next();
        
        consumeOrFail(OPENPAREN);
        
        TreeExpression innerCondition = parseExpression(context);
        failIfFalse(innerCondition);
        int innerEnd = tokenLine();
        consumeOrFail(CLOSEPAREN);
        
        TreeStatement innerTrueBlock = parseStatement(context);
        failIfFalse(innerTrueBlock);     
        exprStack.append(innerCondition);
        posStack.append(make_pair(innerStart, innerEnd));
        statementStack.append(innerTrueBlock);
    } while (match(ELSE));

    if (!trailingElse) {
        TreeExpression condition = exprStack.last();
        exprStack.removeLast();
        TreeStatement trueBlock = statementStack.last();
        statementStack.removeLast();
        pair<int, int> pos = posStack.last();
        posStack.removeLast();
        statementStack.append(context.createIfStatement(condition, trueBlock, pos.first, pos.second));
    }

    while (!exprStack.isEmpty()) {
        TreeExpression condition = exprStack.last();
        exprStack.removeLast();
        TreeStatement falseBlock = statementStack.last();
        statementStack.removeLast();
        TreeStatement trueBlock = statementStack.last();
        statementStack.removeLast();
        pair<int, int> pos = posStack.last();
        posStack.removeLast();
        statementStack.append(context.createIfStatement(condition, trueBlock, falseBlock, pos.first, pos.second));
    }
    
    return context.createIfStatement(condition, trueBlock, statementStack.last(), start, end);
}

template <class TreeBuilder> TreeExpression JSParser::parseExpression(TreeBuilder& context)
{
    failIfStackOverflow();
    TreeExpression node = parseAssignmentExpression(context);
    failIfFalse(node);
    if (!match(COMMA))
        return node;
    next();
    m_nonLHSCount++;
    TreeExpression right = parseAssignmentExpression(context);
    failIfFalse(right);
    typename TreeBuilder::Comma commaNode = context.createCommaExpr(node, right);
    while (match(COMMA)) {
        next();
        right = parseAssignmentExpression(context);
        failIfFalse(right);
        context.appendToComma(commaNode, right);
    }
    return commaNode;
}


template <typename TreeBuilder> TreeExpression JSParser::parseAssignmentExpression(TreeBuilder& context)
{
    failIfStackOverflow();
    int start = tokenStart();
    int initialAssignmentCount = m_assignmentCount;
    int initialNonLHSCount = m_nonLHSCount;
    TreeExpression lhs = parseConditionalExpression(context);
    failIfFalse(lhs);
    if (initialNonLHSCount != m_nonLHSCount)
        return lhs;

    int assignmentStack = 0;
    Operator op;
    bool hadAssignment = false;
    while (true) {
        switch (token().m_type) {
        case EQUAL: op = OpEqual; break;
        case PLUSEQUAL: op = OpPlusEq; break;
        case MINUSEQUAL: op = OpMinusEq; break;
        case MULTEQUAL: op = OpMultEq; break;
        case DIVEQUAL: op = OpDivEq; break;
        case LSHIFTEQUAL: op = OpLShift; break;
        case RSHIFTEQUAL: op = OpRShift; break;
        case URSHIFTEQUAL: op = OpURShift; break;
        case ANDEQUAL: op = OpAndEq; break;
        case XOREQUAL: op = OpXOrEq; break;
        case OREQUAL: op = OpOrEq; break;
        case MODEQUAL: op = OpModEq; break;
        default:
            goto end;
        }
        hadAssignment = true;
        context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op);
        start = tokenStart();
        m_assignmentCount++;
        next();
        lhs = parseConditionalExpression(context);
        failIfFalse(lhs);
        if (initialNonLHSCount != m_nonLHSCount)
            break;
    }
end:
    if (hadAssignment)
        m_nonLHSCount++;

    if (!ASTBuilder::CreatesAST)
        return lhs;

    while (assignmentStack)
        lhs = context.createAssignment(assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEnd());

    return lhs;
}

template <class TreeBuilder> TreeExpression JSParser::parseConditionalExpression(TreeBuilder& context)
{
    TreeExpression cond = parseBinaryExpression(context);
    failIfFalse(cond);
    if (!match(QUESTION))
        return cond;
    m_nonLHSCount++;
    next();
    TreeExpression lhs = parseAssignmentExpression(context);
    consumeOrFail(COLON);

    TreeExpression rhs = parseAssignmentExpression(context);
    failIfFalse(rhs);
    return context.createConditionalExpr(cond, lhs, rhs);
}

ALWAYS_INLINE static bool isUnaryOp(JSTokenType token)
{
    return token & UnaryOpTokenFlag;
}

int JSParser::isBinaryOperator(JSTokenType token)
{
    if (m_allowsIn)
        return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift);
    return token & BinaryOpTokenPrecedenceMask;
}

template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(TreeBuilder& context)
{

    int operandStackDepth = 0;
    int operatorStackDepth = 0;
    while (true) {
        int exprStart = tokenStart();
        int initialAssignments = m_assignmentCount;
        TreeExpression current = parseUnaryExpression(context);
        failIfFalse(current);

        context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEnd(), lastTokenEnd(), initialAssignments != m_assignmentCount);
        int precedence = isBinaryOperator(token().m_type);
        if (!precedence)
            break;
        m_nonLHSCount++;
        int operatorToken = token().m_type;
        next();

        while (operatorStackDepth &&  context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) {
            ASSERT(operandStackDepth > 1);

            typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
            typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
            context.shrinkOperandStackBy(operandStackDepth, 2);
            context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs);
            context.operatorStackPop(operatorStackDepth);
        }
        context.operatorStackAppend(operatorStackDepth, operatorToken, precedence);
    }

    while (operatorStackDepth) {
        ASSERT(operandStackDepth > 1);

        typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
        typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
        context.shrinkOperandStackBy(operandStackDepth, 2);
        context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs);
        context.operatorStackPop(operatorStackDepth);
    }
    return context.popOperandStack(operandStackDepth);
}


template <bool complete, class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& context)
{
    bool wasIdent = false;
    switch (token().m_type) {
    namedProperty:
    case IDENT:
        wasIdent = true;
    case STRING: {
        const Identifier* ident = token().m_data.ident;
        next(Lexer::IgnoreReservedWords);
        if (match(COLON)) {
            next();
            TreeExpression node = parseAssignmentExpression(context);
            failIfFalse(node);
            return context.template createProperty<complete>(ident, node, PropertyNode::Constant);
        }
        failIfFalse(wasIdent);
        matchOrFail(IDENT);
        const Identifier* accessorName = 0;
        TreeFormalParameterList parameters = 0;
        TreeFunctionBody body = 0;
        int openBracePos = 0;
        int closeBracePos = 0;
        int bodyStartLine = 0;
        PropertyNode::Type type;
        if (*ident == m_globalData->propertyNames->get)
            type = PropertyNode::Getter;
        else if (*ident == m_globalData->propertyNames->set)
            type = PropertyNode::Setter;
        else
            fail();
        failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine));
        return context.template createGetterOrSetterProperty<complete>(type, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
    }
    case NUMBER: {
        double propertyName = token().m_data.doubleValue;
        next();
        consumeOrFail(COLON);
        TreeExpression node = parseAssignmentExpression(context);
        failIfFalse(node);
        return context.template createProperty<complete>(m_globalData, propertyName, node, PropertyNode::Constant);
    }
    default:
        failIfFalse(token().m_type & KeywordTokenFlag);
        goto namedProperty;
    }
}

template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBuilder& context)
{
    int startOffset = token().m_data.intValue;
    consumeOrFail(OPENBRACE);

    if (match(CLOSEBRACE)) {
        next();
        return context.createObjectLiteral();
    }

    TreeProperty property = parseProperty<false>(context);
    failIfFalse(property);
    if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
        m_lexer->setOffset(startOffset);
        next();
        return parseStrictObjectLiteral(context);
    }
    TreePropertyList propertyList = context.createPropertyList(property);
    TreePropertyList tail = propertyList;
    while (match(COMMA)) {
        next();
        // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
        if (match(CLOSEBRACE))
            break;
        property = parseProperty<false>(context);
        failIfFalse(property);
        if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
            m_lexer->setOffset(startOffset);
            next();
            return parseStrictObjectLiteral(context);
        }
        tail = context.createPropertyList(property, tail);
    }

    consumeOrFail(CLOSEBRACE);

    return context.createObjectLiteral(propertyList);
}

template <class TreeBuilder> TreeExpression JSParser::parseStrictObjectLiteral(TreeBuilder& context)
{
    consumeOrFail(OPENBRACE);
    
    if (match(CLOSEBRACE)) {
        next();
        return context.createObjectLiteral();
    }
    
    TreeProperty property = parseProperty<true>(context);
    failIfFalse(property);
    
    typedef HashMap<RefPtr<UString::Rep>, unsigned, IdentifierRepHash> ObjectValidationMap;
    ObjectValidationMap objectValidator;
    // Add the first property
    if (!m_syntaxAlreadyValidated)
        objectValidator.add(context.getName(property).ustring().rep(), context.getType(property));
    
    TreePropertyList propertyList = context.createPropertyList(property);
    TreePropertyList tail = propertyList;
    while (match(COMMA)) {
        next();
        // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
        if (match(CLOSEBRACE))
            break;
        property = parseProperty<true>(context);
        failIfFalse(property);
        if (!m_syntaxAlreadyValidated) {
            std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).ustring().rep(), context.getType(property));
            if (!propertyEntryIter.second) {
                if ((context.getType(property) & propertyEntryIter.first->second) != PropertyNode::Constant) {
                    // Can't have multiple getters or setters with the same name, nor can we define 
                    // a property as both an accessor and a constant value
                    failIfTrue(context.getType(property) & propertyEntryIter.first->second);
                    failIfTrue((context.getType(property) | propertyEntryIter.first->second) & PropertyNode::Constant);
                }
            }
        }
        tail = context.createPropertyList(property, tail);
    }
    
    consumeOrFail(CLOSEBRACE);
    
    return context.createObjectLiteral(propertyList);
}

template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context)
{
    consumeOrFail(OPENBRACKET);

    int elisions = 0;
    while (match(COMMA)) {
        next();
        elisions++;
    }
    if (match(CLOSEBRACKET)) {
        next();
        return context.createArray(elisions);
    }

    TreeExpression elem = parseAssignmentExpression(context);
    failIfFalse(elem);
    typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem);
    typename TreeBuilder::ElementList tail = elementList;
    elisions = 0;
    while (match(COMMA)) {
        next();
        elisions = 0;

        while (match(COMMA)) {
            next();
            elisions++;
        }

        if (match(CLOSEBRACKET)) {
            next();
            return context.createArray(elisions, elementList);
        }
        TreeExpression elem = parseAssignmentExpression(context);
        failIfFalse(elem);
        tail = context.createElementList(tail, elisions, elem);
    }

    consumeOrFail(CLOSEBRACKET);

    return context.createArray(elementList);
}

template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(TreeBuilder& context)
{
    switch (token().m_type) {
    case OPENBRACE:
        return parseObjectLiteral(context);
    case OPENBRACKET:
        return parseArrayLiteral(context);
    case OPENPAREN: {
        next();
        int oldNonLHSCount = m_nonLHSCount;
        TreeExpression result = parseExpression(context);
        m_nonLHSCount = oldNonLHSCount;
        consumeOrFail(CLOSEPAREN);

        return result;
    }
    case THISTOKEN: {
        next();
        return context.thisExpr();
    }
    case IDENT: {
        int start = tokenStart();
        const Identifier* ident = token().m_data.ident;
        next();
        return context.createResolve(ident, start);
    }
    case STRING: {
        const Identifier* ident = token().m_data.ident;
        next();
        return context.createString(ident);
    }
    case NUMBER: {
        double d = token().m_data.doubleValue;
        next();
        return context.createNumberExpr(d);
    }
    case NULLTOKEN: {
        next();
        return context.createNull();
    }
    case TRUETOKEN: {
        next();
        return context.createBoolean(true);
    }
    case FALSETOKEN: {
        next();
        return context.createBoolean(false);
    }
    case DIVEQUAL:
    case DIVIDE: {
        /* regexp */
        const Identifier* pattern;
        const Identifier* flags;
        if (match(DIVEQUAL))
            failIfFalse(m_lexer->scanRegExp(pattern, flags, '='));
        else
            failIfFalse(m_lexer->scanRegExp(pattern, flags));

        int start = tokenStart();
        next();
        return context.createRegex(*pattern, *flags, start);
    }
    default:
        fail();
    }
}

template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& context)
{
    consumeOrFail(OPENPAREN);
    if (match(CLOSEPAREN)) {
        next();
        return context.createArguments();
    }
    TreeExpression firstArg = parseAssignmentExpression(context);
    failIfFalse(firstArg);

    TreeArgumentsList argList = context.createArgumentsList(firstArg);
    TreeArgumentsList tail = argList;
    while (match(COMMA)) {
        next();
        TreeExpression arg = parseAssignmentExpression(context);
        failIfFalse(arg);
        tail = context.createArgumentsList(tail, arg);
    }
    consumeOrFail(CLOSEPAREN);
    return context.createArguments(argList);
}

template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(TreeBuilder& context)
{
    TreeExpression base = 0;
    int start = tokenStart();
    int expressionStart = start;
    int newCount = 0;
    while (match(NEW)) {
        next();
        newCount++;
    }
    if (match(FUNCTION)) {
        const Identifier* name = &m_globalData->propertyNames->nullIdentifier;
        TreeFormalParameterList parameters = 0;
        TreeFunctionBody body = 0;
        int openBracePos = 0;
        int closeBracePos = 0;
        int bodyStartLine = 0;
        next();
        failIfFalse(parseFunctionInfo<FunctionNoRequirements>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine));
        base = context.createFunctionExpr(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
    } else
        base = parsePrimaryExpression(context);

    failIfFalse(base);
    while (true) {
        switch (token().m_type) {
        case OPENBRACKET: {
            int expressionEnd = lastTokenEnd();
            next();
            int nonLHSCount = m_nonLHSCount;
            int initialAssignments = m_assignmentCount;
            TreeExpression property = parseExpression(context);
            failIfFalse(property);
            base = context.createBracketAccess(base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd());
            if (!consume(CLOSEBRACKET))
                fail();
            m_nonLHSCount = nonLHSCount;
            break;
        }
        case OPENPAREN: {
            if (newCount) {
                newCount--;
                if (match(OPENPAREN)) {
                    int exprEnd = lastTokenEnd();
                    TreeArguments arguments = parseArguments(context);
                    failIfFalse(arguments);
                    base = context.createNewExpr(base, arguments, start, exprEnd, lastTokenEnd());
                } else
                    base = context.createNewExpr(base, start, lastTokenEnd());               
            } else {
                int nonLHSCount = m_nonLHSCount;
                int expressionEnd = lastTokenEnd();
                TreeArguments arguments = parseArguments(context);
                failIfFalse(arguments);
                base = context.makeFunctionCallNode(base, arguments, expressionStart, expressionEnd, lastTokenEnd());
                m_nonLHSCount = nonLHSCount;
            }
            break;
        }
        case DOT: {
            int expressionEnd = lastTokenEnd();
            next(Lexer::IgnoreReservedWords);
            matchOrFail(IDENT);
            base = context.createDotAccess(base, *token().m_data.ident, expressionStart, expressionEnd, tokenEnd());
            next();
            break;
        }
        default:
            goto endMemberExpression;
        }
    }
endMemberExpression:
    while (newCount--)
        base = context.createNewExpr(base, start, lastTokenEnd());
    return base;
}

template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeBuilder& context)
{
    AllowInOverride allowInOverride(this);
    int tokenStackDepth = 0;
    while (isUnaryOp(token().m_type)) {
        m_nonLHSCount++;
        context.appendUnaryToken(tokenStackDepth, token().m_type, tokenStart());
        next();
    }
    int subExprStart = tokenStart();
    TreeExpression expr = parseMemberExpression(context);
    failIfFalse(expr);
    switch (token().m_type) {
    case PLUSPLUS:
        m_nonLHSCount++;
        expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd());
        m_assignmentCount++;
        next();
        break;
    case MINUSMINUS:
        m_nonLHSCount++;
        expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd());
        m_assignmentCount++;
        next();
        break;
    default:
        break;
    }

    int end = lastTokenEnd();

    if (!TreeBuilder::CreatesAST)
        return expr;

    while (tokenStackDepth) {
        switch (context.unaryTokenStackLastType(tokenStackDepth)) {
        case EXCLAMATION:
            expr = context.createLogicalNot(expr);
            break;
        case TILDE:
            expr = context.makeBitwiseNotNode(expr);
            break;
        case MINUS:
            expr = context.makeNegateNode(expr);
            break;
        case PLUS:
            expr = context.createUnaryPlus(expr);
            break;
        case PLUSPLUS:
        case AUTOPLUSPLUS:
            expr = context.makePrefixNode(expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
            m_assignmentCount++;
            break;
        case MINUSMINUS:
        case AUTOMINUSMINUS:
            expr = context.makePrefixNode(expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
            m_assignmentCount++;
            break;
        case TYPEOF:
            expr = context.makeTypeOfNode(expr);
            break;
        case VOIDTOKEN:
            expr = context.createVoid(expr);
            break;
        case DELETETOKEN:
            expr = context.makeDeleteNode(expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end);
            break;
        default:
            // If we get here something has gone horribly horribly wrong
            CRASH();
        }
        subExprStart = context.unaryTokenStackLastStart(tokenStackDepth);
        context.unaryTokenStackRemoveLast(tokenStackDepth);
    }
    return expr;
}

}
