]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - parser/JSParser.cpp
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / parser / JSParser.cpp
diff --git a/parser/JSParser.cpp b/parser/JSParser.cpp
new file mode 100644 (file)
index 0000000..d56155b
--- /dev/null
@@ -0,0 +1,2186 @@
+/*
+ * 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 "CodeBlock.h"
+#include "JSGlobalData.h"
+#include "NodeInfo.h"
+#include "ASTBuilder.h"
+#include "SourceProvider.h"
+#include "SourceProviderCacheItem.h"
+#include <wtf/HashFunctions.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/WTFThreadData.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 failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0)
+#define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
+#define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0)
+#define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) 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);
+
+class JSParser {
+public:
+    JSParser(Lexer*, JSGlobalData*, FunctionParameters*, bool isStrictContext, bool isFunction, SourceProvider*);
+    const char* 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;
+    };
+    
+    struct ScopeLabelInfo {
+        ScopeLabelInfo(StringImpl* ident, bool isLoop)
+        : m_ident(ident)
+        , m_isLoop(isLoop)
+        {
+        }
+        StringImpl* m_ident;
+        bool m_isLoop;
+    };
+    
+    ALWAYS_INLINE void next(unsigned lexType = 0)
+    {
+        m_lastLine = m_token.m_info.line;
+        m_lastTokenEnd = m_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, strictMode());
+    }
+    
+    ALWAYS_INLINE void nextExpectIdentifier(unsigned lexType = 0)
+    {
+        m_lastLine = m_token.m_info.line;
+        m_lastTokenEnd = m_token.m_info.endOffset;
+        m_lexer->setLastLineNumber(m_lastLine);
+        m_token.m_type = m_lexer->lexExpectIdentifier(&m_token.m_data, &m_token.m_info, lexType, strictMode());
+    }
+    
+    ALWAYS_INLINE bool nextTokenIsColon()
+    {
+        return m_lexer->nextTokenIsColon();
+    }
+
+    ALWAYS_INLINE bool consume(JSTokenType expected, unsigned flags = 0)
+    {
+        bool result = m_token.m_type == expected;
+        failIfFalse(result);
+        next(flags);
+        return result;
+    }
+
+    ALWAYS_INLINE bool match(JSTokenType expected)
+    {
+        return m_token.m_type == expected;
+    }
+
+    ALWAYS_INLINE int tokenStart()
+    {
+        return m_token.m_info.startOffset;
+    }
+
+    ALWAYS_INLINE int tokenLine()
+    {
+        return m_token.m_info.line;
+    }
+
+    ALWAYS_INLINE int tokenEnd()
+    {
+        return m_token.m_info.endOffset;
+    }
+    
+    void startLoop() { currentScope()->startLoop(); }
+    void endLoop() { currentScope()->endLoop(); }
+    void startSwitch() { currentScope()->startSwitch(); }
+    void endSwitch() { currentScope()->endSwitch(); }
+    void setStrictMode() { currentScope()->setStrictMode(); }
+    bool strictMode() { return currentScope()->strictMode(); }
+    bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
+    bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+    bool breakIsValid()
+    {
+        ScopeRef current = currentScope();
+        while (!current->breakIsValid()) {
+            if (!current.hasContainingScope())
+                return false;
+            current = current.containingScope();
+        }
+        return true;
+    }
+    bool continueIsValid()
+    {
+        ScopeRef current = currentScope();
+        while (!current->continueIsValid()) {
+            if (!current.hasContainingScope())
+                return false;
+            current = current.containingScope();
+        }
+        return true;
+    }
+    void pushLabel(const Identifier* label, bool isLoop) { currentScope()->pushLabel(label, isLoop); }
+    void popLabel() { currentScope()->popLabel(); }
+    ScopeLabelInfo* getLabel(const Identifier* label)
+    {
+        ScopeRef current = currentScope();
+        ScopeLabelInfo* result = 0;
+        while (!(result = current->getLabel(label))) {
+            if (!current.hasContainingScope())
+                return 0;
+            current = current.containingScope();
+        }
+        return result;
+    }
+
+    enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
+    template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
+    template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive);
+    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&);
+    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, bool nameIsInContainingScope, 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 (m_token.m_type == SEMICOLON) {
+            next();
+            return true;
+        }
+        return allowAutomaticSemicolon();
+    }
+
+    bool canRecurse()
+    {
+        return m_stack.recursionCheck();
+    }
+    
+    int lastTokenEnd() const
+    {
+        return m_lastTokenEnd;
+    }
+
+    ParserArena m_arena;
+    Lexer* m_lexer;
+    StackBounds m_stack;
+    bool m_error;
+    const char* m_errorMessage;
+    JSGlobalData* m_globalData;
+    JSToken m_token;
+    bool m_allowsIn;
+    int m_lastLine;
+    int m_lastTokenEnd;
+    int m_assignmentCount;
+    int m_nonLHSCount;
+    bool m_syntaxAlreadyValidated;
+    int m_statementDepth;
+    int m_nonTrivialExpressionCount;
+    const Identifier* m_lastIdentifier;
+
+    struct DepthManager {
+        DepthManager(int* depth)
+            : m_originalDepth(*depth)
+            , m_depth(depth)
+        {
+        }
+        
+        ~DepthManager()
+        {
+            *m_depth = m_originalDepth;
+        }
+        
+    private:
+        int m_originalDepth;
+        int* m_depth;
+    };
+    
+    struct Scope {
+        Scope(JSGlobalData* globalData, bool isFunction, bool strictMode)
+            : m_globalData(globalData)
+            , m_shadowsArguments(false)
+            , m_usesEval(false)
+            , m_needsFullActivation(false)
+            , m_allowsNewDecls(true)
+            , m_strictMode(strictMode)
+            , m_isFunction(isFunction)
+            , m_isFunctionBoundary(false)
+            , m_isValidStrictMode(true)
+            , m_loopDepth(0)
+            , m_switchDepth(0)
+        {
+        }
+
+        Scope(const Scope& rhs)
+            : m_globalData(rhs.m_globalData)
+            , m_shadowsArguments(rhs.m_shadowsArguments)
+            , m_usesEval(rhs.m_usesEval)
+            , m_needsFullActivation(rhs.m_needsFullActivation)
+            , m_allowsNewDecls(rhs.m_allowsNewDecls)
+            , m_strictMode(rhs.m_strictMode)
+            , m_isFunction(rhs.m_isFunction)
+            , m_isFunctionBoundary(rhs.m_isFunctionBoundary)
+            , m_isValidStrictMode(rhs.m_isValidStrictMode)
+            , m_loopDepth(rhs.m_loopDepth)
+            , m_switchDepth(rhs.m_switchDepth)
+        {
+            if (rhs.m_labels) {
+                m_labels = adoptPtr(new LabelStack);
+                
+                typedef LabelStack::const_iterator iterator;
+                iterator end = rhs.m_labels->end();
+                for (iterator it = rhs.m_labels->begin(); it != end; ++it)
+                    m_labels->append(ScopeLabelInfo(it->m_ident, it->m_isLoop));
+            }
+        }
+
+        void startSwitch() { m_switchDepth++; }
+        void endSwitch() { m_switchDepth--; }
+        void startLoop() { m_loopDepth++; }
+        void endLoop() { ASSERT(m_loopDepth); m_loopDepth--; }
+        bool inLoop() { return !!m_loopDepth; }
+        bool breakIsValid() { return m_loopDepth || m_switchDepth; }
+        bool continueIsValid() { return m_loopDepth; }
+
+        void pushLabel(const Identifier* label, bool isLoop)
+        {
+            if (!m_labels)
+                m_labels = adoptPtr(new LabelStack);
+            m_labels->append(ScopeLabelInfo(label->impl(), isLoop));
+        }
+
+        void popLabel()
+        {
+            ASSERT(m_labels);
+            ASSERT(m_labels->size());
+            m_labels->removeLast();
+        }
+
+        ScopeLabelInfo* getLabel(const Identifier* label)
+        {
+            if (!m_labels)
+                return 0;
+            for (int i = m_labels->size(); i > 0; i--) {
+                if (m_labels->at(i - 1).m_ident == label->impl())
+                    return &m_labels->at(i - 1);
+            }
+            return 0;
+        }
+
+        void setIsFunction()
+        {
+            m_isFunction = true;
+            m_isFunctionBoundary = true;
+        }
+        bool isFunction() { return m_isFunction; }
+        bool isFunctionBoundary() { return m_isFunctionBoundary; }
+        
+        bool declareVariable(const Identifier* ident)
+        {
+            bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
+            m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+            m_declaredVariables.add(ident->ustring().impl());
+            return isValidStrictMode;
+        }
+        
+        void declareWrite(const Identifier* ident)
+        {
+            ASSERT(m_strictMode);
+            m_writtenVariables.add(ident->impl());
+        }
+
+        void preventNewDecls() { m_allowsNewDecls = false; }
+        bool allowsNewDecls() const { return m_allowsNewDecls; }
+
+        bool declareParameter(const Identifier* ident)
+        {
+            bool isArguments = m_globalData->propertyNames->arguments == *ident;
+            bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).second && m_globalData->propertyNames->eval != *ident && !isArguments;
+            m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+            if (isArguments)
+                m_shadowsArguments = true;
+            return isValidStrictMode;
+        }
+        
+        void useVariable(const Identifier* ident, bool isEval)
+        {
+            m_usesEval |= isEval;
+            m_usedVariables.add(ident->ustring().impl());
+        }
+        
+        void setNeedsFullActivation() { m_needsFullActivation = true; }
+        
+        bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
+        {
+            if (nestedScope->m_usesEval)
+                m_usesEval = true;
+            IdentifierSet::iterator end = nestedScope->m_usedVariables.end();
+            for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) {
+                if (nestedScope->m_declaredVariables.contains(*ptr))
+                    continue;
+                m_usedVariables.add(*ptr);
+                if (shouldTrackClosedVariables)
+                    m_closedVariables.add(*ptr);
+            }
+            if (nestedScope->m_writtenVariables.size()) {
+                IdentifierSet::iterator end = nestedScope->m_writtenVariables.end();
+                for (IdentifierSet::iterator ptr = nestedScope->m_writtenVariables.begin(); ptr != end; ++ptr) {
+                    if (nestedScope->m_declaredVariables.contains(*ptr))
+                        continue;
+                    m_writtenVariables.add(*ptr);
+                }
+            }
+
+            return true;
+        }
+
+        void getUncapturedWrittenVariables(IdentifierSet& writtenVariables)
+        {
+            IdentifierSet::iterator end = m_writtenVariables.end();
+            for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) {
+                if (!m_declaredVariables.contains(*ptr))
+                    writtenVariables.add(*ptr);
+            }
+        }
+
+        void getCapturedVariables(IdentifierSet& capturedVariables)
+        {
+            if (m_needsFullActivation || m_usesEval) {
+                capturedVariables.swap(m_declaredVariables);
+                return;
+            }
+            for (IdentifierSet::iterator ptr = m_closedVariables.begin(); ptr != m_closedVariables.end(); ++ptr) {
+                if (!m_declaredVariables.contains(*ptr))
+                    continue;
+                capturedVariables.add(*ptr);
+            }
+        }
+        void setStrictMode() { m_strictMode = true; }
+        bool strictMode() const { return m_strictMode; }
+        bool isValidStrictMode() const { return m_isValidStrictMode; }
+        bool shadowsArguments() const { return m_shadowsArguments; }
+        
+        void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl> >& vector)
+        {
+            IdentifierSet::iterator end = capturedVariables.end();
+            for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) {
+                if (m_declaredVariables.contains(*it))
+                    continue;
+                vector.append(*it);
+            }
+            vector.shrinkToFit();
+        }
+
+        void saveFunctionInfo(SourceProviderCacheItem* info)
+        {
+            ASSERT(m_isFunction);
+            info->usesEval = m_usesEval;
+            copyCapturedVariablesToVector(m_writtenVariables, info->writtenVariables);
+            copyCapturedVariablesToVector(m_usedVariables, info->usedVariables);
+        }
+
+        void restoreFunctionInfo(const SourceProviderCacheItem* info)
+        {
+            ASSERT(m_isFunction);
+            m_usesEval = info->usesEval;
+            unsigned size = info->usedVariables.size();
+            for (unsigned i = 0; i < size; ++i)
+                m_usedVariables.add(info->usedVariables[i]);
+            size = info->writtenVariables.size();
+            for (unsigned i = 0; i < size; ++i)
+                m_writtenVariables.add(info->writtenVariables[i]);
+        }
+
+    private:
+        JSGlobalData* m_globalData;
+        bool m_shadowsArguments : 1;
+        bool m_usesEval : 1;
+        bool m_needsFullActivation : 1;
+        bool m_allowsNewDecls : 1;
+        bool m_strictMode : 1;
+        bool m_isFunction : 1;
+        bool m_isFunctionBoundary : 1;
+        bool m_isValidStrictMode : 1;
+        int m_loopDepth;
+        int m_switchDepth;
+
+        typedef Vector<ScopeLabelInfo, 2> LabelStack;
+        OwnPtr<LabelStack> m_labels;
+        IdentifierSet m_declaredVariables;
+        IdentifierSet m_usedVariables;
+        IdentifierSet m_closedVariables;
+        IdentifierSet m_writtenVariables;
+    };
+
+    typedef Vector<Scope, 10> ScopeStack;
+
+    struct ScopeRef {
+        ScopeRef(ScopeStack* scopeStack, unsigned index)
+            : m_scopeStack(scopeStack)
+            , m_index(index)
+        {
+        }
+        Scope* operator->() { return &m_scopeStack->at(m_index); }
+        unsigned index() const { return m_index; }
+
+        bool hasContainingScope()
+        {
+            return m_index && !m_scopeStack->at(m_index).isFunctionBoundary();
+        }
+
+        ScopeRef containingScope()
+        {
+            ASSERT(hasContainingScope());
+            return ScopeRef(m_scopeStack, m_index - 1);
+        }
+
+    private:
+        ScopeStack* m_scopeStack;
+        unsigned m_index;
+    };
+
+    struct AutoPopScopeRef : public ScopeRef {
+        AutoPopScopeRef(JSParser* parser, ScopeRef scope)
+            : ScopeRef(scope)
+            , m_parser(parser)
+        {
+        }
+
+        ~AutoPopScopeRef()
+        {
+            if (m_parser)
+                m_parser->popScope(*this, false);
+        }
+
+        void setPopped()
+        {
+            m_parser = 0;
+        }
+
+    private:
+        JSParser* m_parser;
+    };
+
+    ScopeRef currentScope()
+    {
+        return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
+    }
+    
+    ScopeRef pushScope()
+    {
+        bool isFunction = false;
+        bool isStrict = false;
+        if (!m_scopeStack.isEmpty()) {
+            isStrict = m_scopeStack.last().strictMode();
+            isFunction = m_scopeStack.last().isFunction();
+        }
+        m_scopeStack.append(Scope(m_globalData, isFunction, isStrict));
+        return currentScope();
+    }
+
+    bool popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables)
+    {
+        ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
+        ASSERT(m_scopeStack.size() > 1);
+        bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
+        m_scopeStack.removeLast();
+        return result;
+    }
+
+    bool popScope(ScopeRef& scope, bool shouldTrackClosedVariables)
+    {
+        return popScopeInternal(scope, shouldTrackClosedVariables);
+    }
+
+    bool popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables)
+    {
+        scope.setPopped();
+        return popScopeInternal(scope, shouldTrackClosedVariables);
+    }
+
+    bool declareVariable(const Identifier* ident)
+    {
+        unsigned i = m_scopeStack.size() - 1;
+        ASSERT(i < m_scopeStack.size());
+        while (!m_scopeStack[i].allowsNewDecls()) {
+            i--;
+            ASSERT(i < m_scopeStack.size());
+        }
+        return m_scopeStack[i].declareVariable(ident);
+    }
+    
+    void declareWrite(const Identifier* ident)
+    {
+        if (!m_syntaxAlreadyValidated)
+            m_scopeStack.last().declareWrite(ident);
+    }
+
+    ScopeStack m_scopeStack;
+
+    const SourceProviderCacheItem* findCachedFunctionInfo(int openBracePos) 
+    {
+        return m_functionCache ? m_functionCache->get(openBracePos) : 0;
+    }
+
+    SourceProviderCache* m_functionCache;
+};
+
+const char* jsParse(JSGlobalData* globalData, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, const SourceCode* source)
+{
+    JSParser parser(globalData->lexer, globalData, parameters, strictness == JSParseStrict, parserMode == JSParseFunctionCode, source->provider());
+    return parser.parseProgram();
+}
+
+JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, bool inStrictContext, bool isFunction, SourceProvider* provider)
+    : m_lexer(lexer)
+    , m_stack(globalData->stack())
+    , m_error(false)
+    , m_errorMessage("Parse error")
+    , m_globalData(globalData)
+    , m_allowsIn(true)
+    , m_lastLine(0)
+    , m_lastTokenEnd(0)
+    , m_assignmentCount(0)
+    , m_nonLHSCount(0)
+    , m_syntaxAlreadyValidated(provider->isValid())
+    , m_statementDepth(0)
+    , m_nonTrivialExpressionCount(0)
+    , m_lastIdentifier(0)
+    , m_functionCache(m_lexer->sourceProvider()->cache())
+{
+    ScopeRef scope = pushScope();
+    if (isFunction)
+        scope->setIsFunction();
+    if (inStrictContext)
+        scope->setStrictMode();
+    if (parameters) {
+        for (unsigned i = 0; i < parameters->size(); i++)
+            scope->declareParameter(&parameters->at(i));
+    }
+    next();
+    m_lexer->setLastLineNumber(tokenLine());
+}
+
+const char* JSParser::parseProgram()
+{
+    unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
+    ASTBuilder context(m_globalData, m_lexer);
+    if (m_lexer->isReparsing())
+        m_statementDepth--;
+    ScopeRef scope = currentScope();
+    SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
+    if (!sourceElements || !consume(EOFTOK))
+        return m_errorMessage;
+    IdentifierSet capturedVariables;
+    scope->getCapturedVariables(capturedVariables);
+    CodeFeatures features = context.features();
+    if (scope->strictMode())
+        features |= StrictModeFeature;
+    if (scope->shadowsArguments())
+        features |= ShadowsArgumentsFeature;
+    
+    unsigned functionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
+    if (functionCacheSize != oldFunctionCacheSize)
+        m_lexer->sourceProvider()->notifyCacheSizeChanged(functionCacheSize - oldFunctionCacheSize);
+
+    m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features,
+                                           m_lastLine, context.numConstants(), capturedVariables);
+    return 0;
+}
+
+bool JSParser::allowAutomaticSemicolon()
+{
+    return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
+}
+
+template <JSParser::SourceElementsMode mode, class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
+{
+    TreeSourceElements sourceElements = context.createSourceElements();
+    bool seenNonDirective = false;
+    const Identifier* directive = 0;
+    unsigned startOffset = m_token.m_info.startOffset;
+    unsigned oldLastLineNumber = m_lexer->lastLineNumber();
+    unsigned oldLineNumber = m_lexer->lineNumber();
+    bool hasSetStrict = false;
+    while (TreeStatement statement = parseStatement(context, directive)) {
+        if (mode == CheckForStrictMode && !seenNonDirective) {
+            if (directive) {
+                if (!hasSetStrict && m_globalData->propertyNames->useStrictIdentifier == *directive) {
+                    setStrictMode();
+                    hasSetStrict = true;
+                    failIfFalse(isValidStrictMode());
+                    m_lexer->setOffset(startOffset);
+                    next();
+                    m_lexer->setLastLineNumber(oldLastLineNumber);
+                    m_lexer->setLineNumber(oldLineNumber);
+                    failIfTrue(m_error);
+                    continue;
+                }
+            } else
+                seenNonDirective = true;
+        }
+        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();
+    const Identifier* unused = 0;
+    startLoop();
+    TreeStatement statement = parseStatement(context, unused);
+    endLoop();
+    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);
+    const Identifier* unused = 0;
+    startLoop();
+    TreeStatement statement = parseStatement(context, unused);
+    endLoop();
+    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 = m_token.m_data.ident;
+        lastIdent = name;
+        next();
+        bool hasInitializer = match(EQUAL);
+        failIfFalseIfStrict(declareVariable(name));
+        context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
+        if (hasInitializer) {
+            int varDivot = tokenStart() + 1;
+            initStart = tokenStart();
+            next(TreeBuilder::DontBuildStrings); // 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)
+{
+    failIfTrue(strictMode());
+    TreeConstDeclList constDecls = 0;
+    TreeConstDeclList tail = 0;
+    do {
+        next();
+        matchOrFail(IDENT);
+        const Identifier* name = m_token.m_data.ident;
+        next();
+        bool hasInitializer = match(EQUAL);
+        declareVariable(name);
+        context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
+        TreeExpression initializer = 0;
+        if (hasInitializer) {
+            next(TreeBuilder::DontBuildStrings); // 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 (match(SEMICOLON))
+            goto standardForLoop;
+
+        failIfFalse(declarations == 1);
+
+        // 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);
+
+        const Identifier* unused = 0;
+        startLoop();
+        TreeStatement statement = parseStatement(context, unused);
+        endLoop();
+        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);
+        const Identifier* unused = 0;
+        startLoop();
+        TreeStatement statement = parseStatement(context, unused);
+        endLoop();
+        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);
+    const Identifier* unused = 0;
+    startLoop();
+    TreeStatement statement = parseStatement(context, unused);
+    endLoop();
+    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()) {
+        failIfFalse(breakIsValid());
+        return context.createBreakStatement(startCol, endCol, startLine, endLine);
+    }
+    matchOrFail(IDENT);
+    const Identifier* ident = m_token.m_data.ident;
+    failIfFalse(getLabel(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()) {
+        failIfFalse(continueIsValid());
+        return context.createContinueStatement(startCol, endCol, startLine, endLine);
+    }
+    matchOrFail(IDENT);
+    const Identifier* ident = m_token.m_data.ident;
+    ScopeLabelInfo* label = getLabel(ident);
+    failIfFalse(label);
+    failIfFalse(label->m_isLoop);
+    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));
+    failIfFalse(currentScope()->isFunction());
+    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();
+    
+    failIfTrue(autoSemiColon());
+
+    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));
+    failIfTrue(strictMode());
+    currentScope()->setNeedsFullActivation();
+    int startLine = tokenLine();
+    next();
+    consumeOrFail(OPENPAREN);
+    int start = tokenStart();
+    TreeExpression expr = parseExpression(context);
+    failIfFalse(expr);
+    int end = lastTokenEnd();
+
+    int endLine = tokenLine();
+    consumeOrFail(CLOSEPAREN);
+    const Identifier* unused = 0;
+    TreeStatement statement = parseStatement(context, unused);
+    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);
+    startSwitch();
+    TreeClauseList firstClauses = parseSwitchClauses(context);
+    failIfTrue(m_error);
+
+    TreeClause defaultClause = parseSwitchDefaultClause(context);
+    failIfTrue(m_error);
+
+    TreeClauseList secondClauses = parseSwitchClauses(context);
+    failIfTrue(m_error);
+    endSwitch();
+    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<DontCheckForStrictMode>(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<DontCheckForStrictMode>(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<DontCheckForStrictMode>(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)) {
+        currentScope()->setNeedsFullActivation();
+        next();
+        consumeOrFail(OPENPAREN);
+        matchOrFail(IDENT);
+        ident = m_token.m_data.ident;
+        next();
+        AutoPopScopeRef catchScope(this, pushScope());
+        failIfFalseIfStrict(catchScope->declareVariable(ident));
+        catchScope->preventNewDecls();
+        consumeOrFail(CLOSEPAREN);
+        matchOrFail(OPENBRACE);
+        int initialEvalCount = context.evalCount();
+        catchBlock = parseBlockStatement(context);
+        failIfFalse(catchBlock);
+        catchHasEval = initialEvalCount != context.evalCount();
+        failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo));
+    }
+
+    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<DontCheckForStrictMode>(context);
+    failIfFalse(subtree);
+    matchOrFail(CLOSEBRACE);
+    next();
+    return context.createBlockStatement(subtree, start, m_lastLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context, const Identifier*& directive)
+{
+    DepthManager statementDepth(&m_statementDepth);
+    m_statementDepth++;
+    directive = 0;
+    int nonTrivialExpressionCount = 0;
+    failIfStackOverflow();
+    switch (m_token.m_type) {
+    case OPENBRACE:
+        return parseBlockStatement(context);
+    case VAR:
+        return parseVarDeclaration(context);
+    case CONSTTOKEN:
+        return parseConstDeclaration(context);
+    case FUNCTION:
+        failIfFalseIfStrict(m_statementDepth == 1);
+        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);
+    case STRING:
+        directive = m_token.m_data.ident;
+        nonTrivialExpressionCount = m_nonTrivialExpressionCount;
+    default:
+        TreeStatement exprStatement = parseExpressionStatement(context);
+        if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount)
+            directive = 0;
+        return exprStatement;
+    }
+}
+
+template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParameters(TreeBuilder& context)
+{
+    matchOrFail(IDENT);
+    failIfFalseIfStrict(declareParameter(m_token.m_data.ident));
+    TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
+    TreeFormalParameterList tail = list;
+    next();
+    while (match(COMMA)) {
+        next();
+        matchOrFail(IDENT);
+        const Identifier* ident = m_token.m_data.ident;
+        failIfFalseIfStrict(declareParameter(ident));
+        next();
+        tail = context.createFormalParameterList(tail, *ident);
+    }
+    return list;
+}
+
+template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBuilder& context)
+{
+    if (match(CLOSEBRACE))
+        return context.createFunctionBody(strictMode());
+    DepthManager statementDepth(&m_statementDepth);
+    m_statementDepth = 0;
+    typename TreeBuilder::FunctionBodyBuilder bodyBuilder(m_globalData, m_lexer);
+    failIfFalse(parseSourceElements<CheckForStrictMode>(bodyBuilder));
+    return context.createFunctionBody(strictMode());
+}
+
+template <JSParser::FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
+{
+    AutoPopScopeRef functionScope(this, pushScope());
+    functionScope->setIsFunction();
+    if (match(IDENT)) {
+        name = m_token.m_data.ident;
+        failIfTrue(*name == m_globalData->propertyNames->underscoreProto);
+        next();
+        if (!nameIsInContainingScope)
+            failIfFalseIfStrict(functionScope->declareVariable(name));
+    } else if (requirements == FunctionNeedsName)
+        return false;
+    consumeOrFail(OPENPAREN);
+    if (!match(CLOSEPAREN)) {
+        parameters = parseFormalParameters(context);
+        failIfFalse(parameters);
+    }
+    consumeOrFail(CLOSEPAREN);
+    matchOrFail(OPENBRACE);
+
+    openBracePos = m_token.m_data.intValue;
+    bodyStartLine = tokenLine();
+
+    if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(openBracePos) : 0) {
+        // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
+        body = context.createFunctionBody(strictMode());
+
+        functionScope->restoreFunctionInfo(cachedInfo);
+        failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
+
+        closeBracePos = cachedInfo->closeBracePos;
+        m_token = cachedInfo->closeBraceToken();
+        m_lexer->setOffset(m_token.m_info.endOffset);
+        m_lexer->setLineNumber(m_token.m_info.line);
+
+        next();
+        return true;
+    }
+
+    next();
+
+    body = parseFunctionBody(context);
+    failIfFalse(body);
+    if (functionScope->strictMode() && name) {
+        failIfTrue(m_globalData->propertyNames->arguments == *name);
+        failIfTrue(m_globalData->propertyNames->eval == *name);
+    }
+    closeBracePos = m_token.m_data.intValue;
+    
+    // Cache the tokenizer state and the function scope the first time the function is parsed.
+    // Any future reparsing can then skip the function.
+    static const int minimumFunctionLengthToCache = 64;
+    OwnPtr<SourceProviderCacheItem> newInfo;
+    int functionLength = closeBracePos - openBracePos;
+    if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) {
+        newInfo = adoptPtr(new SourceProviderCacheItem(m_token.m_info.line, closeBracePos));
+        functionScope->saveFunctionInfo(newInfo.get());
+    }
+    
+    failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
+    matchOrFail(CLOSEBRACE);
+
+    if (newInfo) {
+        unsigned approximateByteSize = newInfo->approximateByteSize();
+        m_functionCache->add(openBracePos, newInfo.release(), approximateByteSize);
+    }
+
+    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, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
+    failIfFalse(name);
+    failIfFalseIfStrict(declareVariable(name));
+    return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
+}
+
+struct LabelInfo {
+    LabelInfo(const Identifier* ident, int start, int end)
+        : m_ident(ident)
+        , m_start(start)
+        , m_end(end)
+    {
+    }
+
+    const Identifier* m_ident;
+    int m_start;
+    int m_end;
+};
+
+template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelStatement(TreeBuilder& context)
+{
+
+    /* Expression and Label statements are ambiguous at LL(1), so we have a
+     * special case that looks for a colon as the next character in the input.
+     */
+    Vector<LabelInfo> labels;
+
+    do {
+        int start = tokenStart();
+        int startLine = tokenLine();
+        if (!nextTokenIsColon()) {
+            // If we hit this path we're making a expression statement, which
+            // by definition can't make use of continue/break so we can just
+            // ignore any labels we might have accumulated.
+            TreeExpression expression = parseExpression(context);
+            failIfFalse(expression);
+            failIfFalse(autoSemiColon());
+            return context.createExprStatement(expression, startLine, m_lastLine);
+        }
+        const Identifier* ident = m_token.m_data.ident;
+        int end = tokenEnd();
+        next();
+        consumeOrFail(COLON);
+        if (!m_syntaxAlreadyValidated) {
+            // This is O(N^2) over the current list of consecutive labels, but I
+            // have never seen more than one label in a row in the real world.
+            for (size_t i = 0; i < labels.size(); i++)
+                failIfTrue(ident->impl() == labels[i].m_ident->impl());
+            failIfTrue(getLabel(ident));
+            labels.append(LabelInfo(ident, start, end));
+        }
+    } while (match(IDENT));
+    bool isLoop = false;
+    switch (m_token.m_type) {
+    case FOR:
+    case WHILE:
+    case DO:
+        isLoop = true;
+        break;
+
+    default:
+        break;
+    }
+    const Identifier* unused = 0;
+    if (!m_syntaxAlreadyValidated) {
+        for (size_t i = 0; i < labels.size(); i++)
+            pushLabel(labels[i].m_ident, isLoop);
+    }
+    TreeStatement statement = parseStatement(context, unused);
+    if (!m_syntaxAlreadyValidated) {
+        for (size_t i = 0; i < labels.size(); i++)
+            popLabel();
+    }
+    failIfFalse(statement);
+    for (size_t i = 0; i < labels.size(); i++) {
+        const LabelInfo& info = labels[labels.size() - i - 1];
+        statement = context.createLabelStatement(info.m_ident, statement, info.m_start, info.m_end);
+    }
+    return statement;
+}
+
+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);
+
+    const Identifier* unused = 0;
+    TreeStatement trueBlock = parseStatement(context, unused);
+    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)) {
+            const Identifier* unused = 0;
+            TreeStatement block = parseStatement(context, unused);
+            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);
+        const Identifier* unused = 0;
+        TreeStatement innerTrueBlock = parseStatement(context, unused);
+        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_nonTrivialExpressionCount++;
+    m_nonLHSCount++;
+    TreeExpression right = parseAssignmentExpression(context);
+    failIfFalse(right);
+    typename TreeBuilder::Comma commaNode = context.createCommaExpr(node, right);
+    while (match(COMMA)) {
+        next(TreeBuilder::DontBuildStrings);
+        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 (m_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;
+        }
+        m_nonTrivialExpressionCount++;
+        hadAssignment = true;
+        context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op);
+        start = tokenStart();
+        m_assignmentCount++;
+        next(TreeBuilder::DontBuildStrings);
+        if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) {
+            failIfTrueIfStrict(m_globalData->propertyNames->eval == *m_lastIdentifier);
+            failIfTrueIfStrict(m_globalData->propertyNames->arguments == *m_lastIdentifier);
+            declareWrite(m_lastIdentifier);
+            m_lastIdentifier = 0;
+        }
+        lhs = parseConditionalExpression(context);
+        failIfFalse(lhs);
+        if (initialNonLHSCount != m_nonLHSCount)
+            break;
+    }
+end:
+    if (hadAssignment)
+        m_nonLHSCount++;
+
+    if (!TreeBuilder::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_nonTrivialExpressionCount++;
+    m_nonLHSCount++;
+    next(TreeBuilder::DontBuildStrings);
+    TreeExpression lhs = parseAssignmentExpression(context);
+    consumeOrFailWithFlags(COLON, TreeBuilder::DontBuildStrings);
+
+    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;
+    typename TreeBuilder::BinaryExprContext binaryExprContext(context);
+    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(m_token.m_type);
+        if (!precedence)
+            break;
+        m_nonTrivialExpressionCount++;
+        m_nonLHSCount++;
+        int operatorToken = m_token.m_type;
+        next(TreeBuilder::DontBuildStrings);
+
+        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 (m_token.m_type) {
+    namedProperty:
+    case IDENT:
+        wasIdent = true;
+    case STRING: {
+        const Identifier* ident = m_token.m_data.ident;
+        if (complete || (wasIdent && (*ident == m_globalData->propertyNames->get || *ident == m_globalData->propertyNames->set)))
+            nextExpectIdentifier(Lexer::IgnoreReservedWords);
+        else
+            nextExpectIdentifier(Lexer::IgnoreReservedWords | TreeBuilder::DontBuildKeywords);
+
+        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, false>(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 = m_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(m_token.m_type & KeywordTokenFlag);
+        goto namedProperty;
+    }
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBuilder& context)
+{
+    int startOffset = m_token.m_data.intValue;
+    consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings);
+
+    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(TreeBuilder::DontBuildStrings);
+        // 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<StringImpl>, unsigned, IdentifierRepHash> ObjectValidationMap;
+    ObjectValidationMap objectValidator;
+    // Add the first property
+    if (!m_syntaxAlreadyValidated)
+        objectValidator.add(context.getName(property).impl(), 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).impl(), context.getType(property));
+            if (!propertyEntryIter.second) {
+                failIfTrue(propertyEntryIter.first->second == PropertyNode::Constant);
+                failIfTrue(context.getType(property) == PropertyNode::Constant);
+                failIfTrue(context.getType(property) & propertyEntryIter.first->second);
+                propertyEntryIter.first->second |= context.getType(property);
+            }
+        }
+        tail = context.createPropertyList(property, tail);
+    }
+    
+    consumeOrFail(CLOSEBRACE);
+    
+    return context.createObjectLiteral(propertyList);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context)
+{
+    consumeOrFailWithFlags(OPENBRACKET, TreeBuilder::DontBuildStrings);
+
+    int elisions = 0;
+    while (match(COMMA)) {
+        next(TreeBuilder::DontBuildStrings);
+        elisions++;
+    }
+    if (match(CLOSEBRACKET)) {
+        next(TreeBuilder::DontBuildStrings);
+        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(TreeBuilder::DontBuildStrings);
+        elisions = 0;
+
+        while (match(COMMA)) {
+            next();
+            elisions++;
+        }
+
+        if (match(CLOSEBRACKET)) {
+            next(TreeBuilder::DontBuildStrings);
+            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 (m_token.m_type) {
+    case OPENBRACE:
+        if (strictMode())
+            return parseStrictObjectLiteral(context);
+        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 = m_token.m_data.ident;
+        next();
+        currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident);
+        m_lastIdentifier = ident;
+        return context.createResolve(ident, start);
+    }
+    case STRING: {
+        const Identifier* ident = m_token.m_data.ident;
+        next();
+        return context.createString(ident);
+    }
+    case NUMBER: {
+        double d = m_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();
+        TreeExpression re = context.createRegExp(*pattern, *flags, start);
+        if (!re) {
+            m_errorMessage = Yarr::checkSyntax(pattern->ustring());
+            ASSERT(m_errorMessage);
+            fail();
+        }
+        return re;
+    }
+    default:
+        fail();
+    }
+}
+
+template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& context)
+{
+    consumeOrFailWithFlags(OPENPAREN, TreeBuilder::DontBuildStrings);
+    if (match(CLOSEPAREN)) {
+        next(TreeBuilder::DontBuildStrings);
+        return context.createArguments();
+    }
+    TreeExpression firstArg = parseAssignmentExpression(context);
+    failIfFalse(firstArg);
+
+    TreeArgumentsList argList = context.createArgumentsList(firstArg);
+    TreeArgumentsList tail = argList;
+    while (match(COMMA)) {
+        next(TreeBuilder::DontBuildStrings);
+        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, false>(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 (m_token.m_type) {
+        case OPENBRACKET: {
+            m_nonTrivialExpressionCount++;
+            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: {
+            m_nonTrivialExpressionCount++;
+            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: {
+            m_nonTrivialExpressionCount++;
+            int expressionEnd = lastTokenEnd();
+            nextExpectIdentifier(Lexer::IgnoreReservedWords | TreeBuilder::DontBuildKeywords);
+            matchOrFail(IDENT);
+            base = context.createDotAccess(base, m_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)
+{
+    typename TreeBuilder::UnaryExprContext unaryExprContext(context);
+    AllowInOverride allowInOverride(this);
+    int tokenStackDepth = 0;
+    bool modifiesExpr = false;
+    bool requiresLExpr = false;
+    while (isUnaryOp(m_token.m_type)) {
+        if (strictMode()) {
+            switch (m_token.m_type) {
+            case PLUSPLUS:
+            case MINUSMINUS:
+            case AUTOPLUSPLUS:
+            case AUTOMINUSMINUS:
+                failIfTrue(requiresLExpr);
+                modifiesExpr = true;
+                requiresLExpr = true;
+                break;
+            case DELETETOKEN:
+                failIfTrue(requiresLExpr);
+                requiresLExpr = true;
+                break;
+            default:
+                failIfTrue(requiresLExpr);
+                break;
+            }
+        }
+        m_nonLHSCount++;
+        context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStart());
+        next();
+        m_nonTrivialExpressionCount++;
+    }
+    int subExprStart = tokenStart();
+    TreeExpression expr = parseMemberExpression(context);
+    failIfFalse(expr);
+    bool isEvalOrArguments = false;
+    if (strictMode() && !m_syntaxAlreadyValidated) {
+        if (context.isResolve(expr)) {
+            isEvalOrArguments = *m_lastIdentifier == m_globalData->propertyNames->eval || *m_lastIdentifier == m_globalData->propertyNames->arguments;
+        }
+    }
+    failIfTrueIfStrict(isEvalOrArguments && modifiesExpr);
+    switch (m_token.m_type) {
+    case PLUSPLUS:
+        m_nonTrivialExpressionCount++;
+        m_nonLHSCount++;
+        expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd());
+        m_assignmentCount++;
+        failIfTrueIfStrict(isEvalOrArguments);
+        failIfTrueIfStrict(requiresLExpr);
+        next();
+        break;
+    case MINUSMINUS:
+        m_nonTrivialExpressionCount++;
+        m_nonLHSCount++;
+        expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd());
+        m_assignmentCount++;
+        failIfTrueIfStrict(isEvalOrArguments);
+        failIfTrueIfStrict(requiresLExpr);
+        next();
+        break;
+    default:
+        break;
+    }
+
+    int end = lastTokenEnd();
+
+    if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode()))
+        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:
+            failIfTrueIfStrict(context.isResolve(expr));
+            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;
+}
+
+}
+
+namespace WTF
+{
+    template <> struct VectorTraits<JSC::JSParser::Scope> : SimpleClassVectorTraits {
+        static const bool canInitializeWithMemset = false; // Not all Scope data members initialize to 0.
+    };
+}