]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - parser/Parser.h
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / parser / Parser.h
index c2a11d665b7913ec5f6431c0636c1a8a6dd6a016..b88f209ce5f0bb618acd7d0052fec5d8c68441a3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ *  Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2011, 2013 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
 #include "Lexer.h"
 #include "Nodes.h"
 #include "ParserArena.h"
+#include "ParserError.h"
 #include "ParserTokens.h"
 #include "SourceProvider.h"
+#include "SourceProviderCache.h"
 #include "SourceProviderCacheItem.h"
 #include <wtf/Forward.h>
 #include <wtf/Noncopyable.h>
@@ -53,33 +55,11 @@ class ExecState;
 class FunctionBodyNode;
 class FunctionParameters;
 class Identifier;
-class JSGlobalData;
+class VM;
 class ProgramNode;
 class SourceCode;
-class UString;
-
-#define fail() do { if (!m_error) updateErrorMessage(); return 0; } while (0)
-#define failWithToken(tok) do { if (!m_error) updateErrorMessage(tok); return 0; } while (0)
-#define failWithMessage(msg) do { if (!m_error) updateErrorMessage(msg); return 0; } while (0)
-#define failWithNameAndMessage(before, name, after) do { if (!m_error) updateErrorWithNameAndMessage(before, name, after); return 0; } while (0)
-#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
-#define failIfFalseWithMessage(cond, msg) do { if (!(cond)) failWithMessage(msg); } while (0)
-#define failIfFalseWithNameAndMessage(cond, before, name, msg) do { if (!(cond)) failWithNameAndMessage(before, name, msg); } while (0)
-#define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
-#define failIfTrueWithMessage(cond, msg) do { if ((cond)) failWithMessage(msg); } while (0)
-#define failIfTrueWithNameAndMessage(cond, before, name, msg) do { if ((cond)) failWithNameAndMessage(before, name, msg); } while (0)
-#define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0)
-#define failIfTrueIfStrictWithMessage(cond, msg) do { if ((cond) && strictMode()) failWithMessage(msg); } while (0)
-#define failIfTrueIfStrictWithNameAndMessage(cond, before, name, after) do { if ((cond) && strictMode()) failWithNameAndMessage(before, name, after); } while (0)
-#define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
-#define failIfFalseIfStrictWithMessage(cond, msg) do { if ((!(cond)) && strictMode()) failWithMessage(msg); } while (0)
-#define failIfFalseIfStrictWithNameAndMessage(cond, before, name, after) do { if ((!(cond)) && strictMode()) failWithNameAndMessage(before, name, after); } while (0)
-#define consumeOrFail(tokenType) do { if (!consume(tokenType)) failWithToken(tokenType); } while (0)
-#define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) failWithToken(tokenType); } while (0)
-#define matchOrFail(tokenType) do { if (!match(tokenType)) failWithToken(tokenType); } while (0)
-#define failIfStackOverflow() do { failIfFalseWithMessage(canRecurse(), "Code nested too deeply."); } while (0)
-
-    // Macros to make the more common TreeBuilder types a little less verbose
+
+// 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
@@ -92,32 +72,22 @@ class UString;
 #define TreeFunctionBody typename TreeBuilder::FunctionBody
 #define TreeProperty typename TreeBuilder::Property
 #define TreePropertyList typename TreeBuilder::PropertyList
+#define TreeDeconstructionPattern typename TreeBuilder::DeconstructionPattern
 
 COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);
 
 enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
 enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
+enum FunctionParseMode { FunctionMode, GetterMode, SetterMode };
+enum DeconstructionKind {
+    DeconstructToVariables,
+    DeconstructToParameters,
+    DeconstructToExpressions
+};
 
 template <typename T> inline bool isEvalNode() { return false; }
 template <> inline bool isEvalNode<EvalNode>() { return true; }
 
-struct DepthManager {
-    DepthManager(int* depth)
-        : m_originalDepth(*depth)
-        , m_depth(depth)
-    {
-    }
-
-    ~DepthManager()
-    {
-        *m_depth = m_originalDepth;
-    }
-
-private:
-    int m_originalDepth;
-    int* m_depth;
-};
-
 struct ScopeLabelInfo {
     ScopeLabelInfo(StringImpl* ident, bool isLoop)
         : m_ident(ident)
@@ -130,8 +100,8 @@ struct ScopeLabelInfo {
 };
 
 struct Scope {
-    Scope(const JSGlobalData* globalData, bool isFunction, bool strictMode)
-        : m_globalData(globalData)
+    Scope(const VM* vm, bool isFunction, bool strictMode)
+        : m_vm(vm)
         , m_shadowsArguments(false)
         , m_usesEval(false)
         , m_needsFullActivation(false)
@@ -146,7 +116,7 @@ struct Scope {
     }
 
     Scope(const Scope& rhs)
-        : m_globalData(rhs.m_globalData)
+        : m_vm(rhs.m_vm)
         , m_shadowsArguments(rhs.m_shadowsArguments)
         , m_usesEval(rhs.m_usesEval)
         , m_needsFullActivation(rhs.m_needsFullActivation)
@@ -209,14 +179,29 @@ struct Scope {
     bool isFunction() { return m_isFunction; }
     bool isFunctionBoundary() { return m_isFunctionBoundary; }
 
+    void declareCallee(const Identifier* ident)
+    {
+        m_declaredVariables.add(ident->string().impl());
+    }
+
     bool declareVariable(const Identifier* ident)
     {
-        bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
+        bool isValidStrictMode = m_vm->propertyNames->eval != *ident && m_vm->propertyNames->arguments != *ident;
         m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
-        m_declaredVariables.add(ident->ustring().impl());
+        m_declaredVariables.add(ident->string().impl());
         return isValidStrictMode;
     }
 
+    bool hasDeclaredVariable(const Identifier& ident)
+    {
+        return m_declaredVariables.contains(ident.impl());
+    }
+    
+    bool hasDeclaredParameter(const Identifier& ident)
+    {
+        return m_declaredParameters.contains(ident.impl()) || m_declaredVariables.contains(ident.impl());
+    }
+    
     void declareWrite(const Identifier* ident)
     {
         ASSERT(m_strictMode);
@@ -228,18 +213,44 @@ struct Scope {
 
     bool declareParameter(const Identifier* ident)
     {
-        bool isArguments = m_globalData->propertyNames->arguments == *ident;
-        bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).isNewEntry && m_globalData->propertyNames->eval != *ident && !isArguments;
+        bool isArguments = m_vm->propertyNames->arguments == *ident;
+        bool isValidStrictMode = m_declaredVariables.add(ident->string().impl()).isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments;
         m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+        m_declaredParameters.add(ident->string().impl());
+
         if (isArguments)
             m_shadowsArguments = true;
         return isValidStrictMode;
     }
+    
+    enum BindingResult {
+        BindingFailed,
+        StrictBindingFailed,
+        BindingSucceeded
+    };
+    BindingResult declareBoundParameter(const Identifier* ident)
+    {
+        bool isArguments = m_vm->propertyNames->arguments == *ident;
+        bool newEntry = m_declaredVariables.add(ident->string().impl()).isNewEntry;
+        bool isValidStrictMode = newEntry && m_vm->propertyNames->eval != *ident && !isArguments;
+        m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+    
+        if (isArguments)
+            m_shadowsArguments = true;
+        if (!newEntry)
+            return BindingFailed;
+        return isValidStrictMode ? BindingSucceeded : StrictBindingFailed;
+    }
+
+    void getUsedVariables(IdentifierSet& usedVariables)
+    {
+        usedVariables.swap(m_usedVariables);
+    }
 
     void useVariable(const Identifier* ident, bool isEval)
     {
         m_usesEval |= isEval;
-        m_usedVariables.add(ident->ustring().impl());
+        m_usedVariables.add(ident->string().impl());
     }
 
     void setNeedsFullActivation() { m_needsFullActivation = true; }
@@ -268,18 +279,10 @@ struct Scope {
         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)
+    void getCapturedVariables(IdentifierSet& capturedVariables, bool& modifiedParameter)
     {
         if (m_needsFullActivation || m_usesEval) {
+            modifiedParameter = true;
             capturedVariables.swap(m_declaredVariables);
             return;
         }
@@ -288,13 +291,23 @@ struct Scope {
                 continue;
             capturedVariables.add(*ptr);
         }
+        modifiedParameter = false;
+        if (m_declaredParameters.size()) {
+            IdentifierSet::iterator end = m_writtenVariables.end();
+            for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) {
+                if (!m_declaredParameters.contains(*ptr))
+                    continue;
+                modifiedParameter = true;
+                break;
+            }
+        }
     }
     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)
+    void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl>>& vector)
     {
         IdentifierSet::iterator end = capturedVariables.end();
         for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) {
@@ -302,35 +315,32 @@ struct Scope {
                 continue;
             vector.append(*it);
         }
-        vector.shrinkToFit();
     }
 
-    void saveFunctionInfo(SourceProviderCacheItem* info)
+    void fillParametersForSourceProviderCache(SourceProviderCacheItemCreationParameters& parameters)
     {
         ASSERT(m_isFunction);
-        info->usesEval = m_usesEval;
-        info->strictMode = m_strictMode;
-        info->needsFullActivation = m_needsFullActivation;
-        copyCapturedVariablesToVector(m_writtenVariables, info->writtenVariables);
-        copyCapturedVariablesToVector(m_usedVariables, info->usedVariables);
+        parameters.usesEval = m_usesEval;
+        parameters.strictMode = m_strictMode;
+        parameters.needsFullActivation = m_needsFullActivation;
+        copyCapturedVariablesToVector(m_writtenVariables, parameters.writtenVariables);
+        copyCapturedVariablesToVector(m_usedVariables, parameters.usedVariables);
     }
 
-    void restoreFunctionInfo(const SourceProviderCacheItem* info)
+    void restoreFromSourceProviderCache(const SourceProviderCacheItem* info)
     {
         ASSERT(m_isFunction);
         m_usesEval = info->usesEval;
         m_strictMode = info->strictMode;
         m_needsFullActivation = info->needsFullActivation;
-        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]);
+        for (unsigned i = 0; i < info->usedVariablesCount; ++i)
+            m_usedVariables.add(info->usedVariables()[i]);
+        for (unsigned i = 0; i < info->writtenVariablesCount; ++i)
+            m_writtenVariables.add(info->writtenVariables()[i]);
     }
 
 private:
-    const JSGlobalData* m_globalData;
+    const VM* m_vm;
     bool m_shadowsArguments : 1;
     bool m_usesEval : 1;
     bool m_needsFullActivation : 1;
@@ -344,6 +354,7 @@ private:
 
     typedef Vector<ScopeLabelInfo, 2> LabelStack;
     OwnPtr<LabelStack> m_labels;
+    IdentifierSet m_declaredParameters;
     IdentifierSet m_declaredVariables;
     IdentifierSet m_usedVariables;
     IdentifierSet m_closedVariables;
@@ -383,11 +394,14 @@ class Parser {
     WTF_MAKE_FAST_ALLOCATED;
 
 public:
-    Parser(JSGlobalData*, const SourceCode&, FunctionParameters*, JSParserStrictness, JSParserMode);
+    Parser(VM*, const SourceCode&, FunctionParameters*, const Identifier&, JSParserStrictness, JSParserMode);
     ~Parser();
 
     template <class ParsedNode>
-    PassRefPtr<ParsedNode> parse(JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, JSObject**);
+    PassRefPtr<ParsedNode> parse(ParserError&, bool needReparsingAdjustment);
+
+    JSTextPosition positionBeforeLastNewline() const { return m_lexer->positionBeforeLastNewline(); }
+    Vector<RefPtr<StringImpl>>&& closedVariables() { return WTF::move(m_closedVariables); }
 
 private:
     struct AllowInOverride {
@@ -440,7 +454,7 @@ private:
             isStrict = m_scopeStack.last().strictMode();
             isFunction = m_scopeStack.last().isFunction();
         }
-        m_scopeStack.append(Scope(m_globalData, isFunction, isStrict));
+        m_scopeStack.append(Scope(m_vm, isFunction, isStrict));
         return currentScope();
     }
     
@@ -475,9 +489,31 @@ private:
         return m_scopeStack[i].declareVariable(ident);
     }
     
+    NEVER_INLINE bool hasDeclaredVariable(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].hasDeclaredVariable(ident);
+    }
+    
+    NEVER_INLINE bool hasDeclaredParameter(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].hasDeclaredParameter(ident);
+    }
+    
     void declareWrite(const Identifier* ident)
     {
-        if (!m_syntaxAlreadyValidated)
+        if (!m_syntaxAlreadyValidated || strictMode())
             m_scopeStack.last().declareWrite(ident);
     }
     
@@ -489,31 +525,33 @@ private:
     }
 
     Parser();
-    UString parseInner();
+    String parseInner();
 
     void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*, 
-                          ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures,
-                          int, int, IdentifierSet&);
+        ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures, int, IdentifierSet&, const Vector<RefPtr<StringImpl>>&&);
 
     // Used to determine type of error to report.
     bool isFunctionBodyNode(ScopeNode*) { return false; }
     bool isFunctionBodyNode(FunctionBodyNode*) { return true; }
 
-
     ALWAYS_INLINE void next(unsigned lexerFlags = 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, lexerFlags, strictMode());
+        int lastLine = m_token.m_location.line;
+        int lastTokenEnd = m_token.m_location.endOffset;
+        int lastTokenLineStart = m_token.m_location.lineStartOffset;
+        m_lastTokenEndPosition = JSTextPosition(lastLine, lastTokenEnd, lastTokenLineStart);
+        m_lexer->setLastLineNumber(lastLine);
+        m_token.m_type = m_lexer->lex(&m_token, lexerFlags, strictMode());
     }
 
     ALWAYS_INLINE void nextExpectIdentifier(unsigned lexerFlags = 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, lexerFlags, strictMode());
+        int lastLine = m_token.m_location.line;
+        int lastTokenEnd = m_token.m_location.endOffset;
+        int lastTokenLineStart = m_token.m_location.lineStartOffset;
+        m_lastTokenEndPosition = JSTextPosition(lastLine, lastTokenEnd, lastTokenLineStart);
+        m_lexer->setLastLineNumber(lastLine);
+        m_token.m_type = m_lexer->lexExpectIdentifier(&m_token, lexerFlags, strictMode());
     }
 
     ALWAYS_INLINE bool nextTokenIsColon()
@@ -528,10 +566,11 @@ private:
             next(flags);
         return result;
     }
-    
-    ALWAYS_INLINE UString getToken() {
+
+    void printUnexpectedTokenText(WTF::PrintStream&);
+    ALWAYS_INLINE String getToken() {
         SourceProvider* sourceProvider = m_source->provider();
-        return UString(sourceProvider->getRange(tokenStart(), tokenEnd()).impl());
+        return sourceProvider->getRange(tokenStart(), tokenEndPosition().offset);
     }
     
     ALWAYS_INLINE bool match(JSTokenType expected)
@@ -539,288 +578,70 @@ private:
         return m_token.m_type == expected;
     }
     
-    ALWAYS_INLINE int tokenStart()
+    ALWAYS_INLINE bool isofToken()
     {
-        return m_token.m_info.startOffset;
+        return m_token.m_type == IDENT && *m_token.m_data.ident == m_vm->propertyNames->of;
     }
     
-    ALWAYS_INLINE int tokenLine()
+    ALWAYS_INLINE unsigned tokenStart()
     {
-        return m_token.m_info.line;
+        return m_token.m_location.startOffset;
     }
     
-    ALWAYS_INLINE int tokenEnd()
+    ALWAYS_INLINE const JSTextPosition& tokenStartPosition()
     {
-        return m_token.m_info.endOffset;
+        return m_token.m_startPosition;
     }
-    
-    const char* getTokenName(JSTokenType tok) 
+
+    ALWAYS_INLINE int tokenLine()
     {
-        switch (tok) {
-        case NULLTOKEN: 
-            return "null";
-        case TRUETOKEN:
-            return "true";
-        case FALSETOKEN: 
-            return "false";
-        case BREAK: 
-            return "break";
-        case CASE: 
-            return "case";
-        case DEFAULT: 
-            return "default";
-        case FOR: 
-            return "for";
-        case NEW: 
-            return "new";
-        case VAR: 
-            return "var";
-        case CONSTTOKEN: 
-            return "const";
-        case CONTINUE: 
-            return "continue";
-        case FUNCTION: 
-            return "function";
-        case IF: 
-            return "if";
-        case THISTOKEN: 
-            return "this";
-        case DO: 
-            return "do";
-        case WHILE: 
-            return "while";
-        case SWITCH: 
-            return "switch";
-        case WITH: 
-            return "with";
-        case THROW: 
-            return "throw";
-        case TRY: 
-            return "try";
-        case CATCH: 
-            return "catch";
-        case FINALLY: 
-            return "finally";
-        case DEBUGGER: 
-            return "debugger";
-        case ELSE: 
-            return "else";
-        case OPENBRACE: 
-            return "{";
-        case CLOSEBRACE: 
-            return "}";
-        case OPENPAREN: 
-            return "(";
-        case CLOSEPAREN: 
-            return ")";
-        case OPENBRACKET: 
-            return "[";
-        case CLOSEBRACKET: 
-            return "]";
-        case COMMA: 
-            return ",";
-        case QUESTION: 
-            return "?";
-        case SEMICOLON: 
-            return ";";
-        case COLON: 
-            return ":";
-        case DOT: 
-            return ".";
-        case EQUAL: 
-            return "=";
-        case PLUSEQUAL: 
-            return "+=";
-        case MINUSEQUAL: 
-            return "-=";
-        case MULTEQUAL: 
-            return "*=";
-        case DIVEQUAL: 
-            return "/=";
-        case LSHIFTEQUAL: 
-            return "<<=";
-        case RSHIFTEQUAL: 
-            return ">>=";
-        case URSHIFTEQUAL: 
-            return ">>>=";
-        case ANDEQUAL: 
-            return "&=";
-        case MODEQUAL: 
-            return "%=";
-        case XOREQUAL: 
-            return "^=";
-        case OREQUAL: 
-            return "|=";
-        case AUTOPLUSPLUS: 
-        case PLUSPLUS: 
-            return "++";
-        case AUTOMINUSMINUS: 
-        case MINUSMINUS: 
-            return "--";
-        case EXCLAMATION: 
-            return "!";
-        case TILDE: 
-            return "~";
-        case TYPEOF: 
-            return "typeof";
-        case VOIDTOKEN: 
-            return "void";
-        case DELETETOKEN: 
-            return "delete";
-        case OR: 
-            return "||";
-        case AND: 
-            return "&&";
-        case BITOR: 
-            return "|";
-        case BITXOR: 
-            return "^";
-        case BITAND: 
-            return "&";
-        case EQEQ: 
-            return "==";
-        case NE: 
-            return "!=";
-        case STREQ: 
-            return "===";
-        case STRNEQ: 
-            return "!==";
-        case LT: 
-            return "<";
-        case GT: 
-            return ">";
-        case LE: 
-            return "<=";
-        case GE: 
-            return ">=";
-        case INSTANCEOF: 
-            return "instanceof";
-        case INTOKEN: 
-            return "in";
-        case LSHIFT: 
-            return "<<";
-        case RSHIFT: 
-            return ">>";
-        case URSHIFT: 
-            return ">>>";
-        case PLUS: 
-            return "+";
-        case MINUS: 
-            return "-";
-        case TIMES: 
-            return "*";
-        case DIVIDE: 
-            return "/";
-        case MOD: 
-            return "%";
-        case RETURN: 
-        case RESERVED_IF_STRICT:
-        case RESERVED: 
-        case NUMBER:
-        case IDENT: 
-        case STRING: 
-        case ERRORTOK:
-        case EOFTOK: 
-            return 0;
-        case LastUntaggedToken: 
-            break;
-        }
-        ASSERT_NOT_REACHED();
-        return "internal error";
+        return m_token.m_location.line;
     }
     
-    ALWAYS_INLINE void updateErrorMessageSpecialCase(JSTokenType expectedToken) 
+    ALWAYS_INLINE int tokenColumn()
     {
-        String errorMessage;
-        switch (expectedToken) {
-        case RESERVED_IF_STRICT:
-            errorMessage = "Use of reserved word '";
-            errorMessage += getToken().impl();
-            errorMessage += "' in strict mode";
-            m_errorMessage = errorMessage.impl();
-            return;
-        case RESERVED:
-            errorMessage = "Use of reserved word '";
-            errorMessage += getToken().impl();
-            errorMessage += "'";
-            m_errorMessage = errorMessage.impl();
-            return;
-        case NUMBER: 
-            errorMessage = "Unexpected number '";
-            errorMessage += getToken().impl();
-            errorMessage += "'";
-            m_errorMessage = errorMessage.impl();
-            return;
-        case IDENT: 
-            errorMessage = "Expected an identifier but found '";
-            errorMessage += getToken().impl();
-            errorMessage += "' instead";
-            m_errorMessage = errorMessage.impl();
-            return;
-        case STRING: 
-            errorMessage = "Unexpected string ";
-            errorMessage += getToken().impl();
-            m_errorMessage = errorMessage.impl();
-            return;
-        case ERRORTOK: 
-            errorMessage = "Unrecognized token '";
-            errorMessage += getToken().impl();
-            errorMessage += "'";
-            m_errorMessage = errorMessage.impl();
-            return;
-        case EOFTOK:  
-            m_errorMessage = "Unexpected EOF";
-            return;
-        case RETURN:
-            m_errorMessage = "Return statements are only valid inside functions";
-            return;
-        default:
-            ASSERT_NOT_REACHED();
-            m_errorMessage = "internal error";
-            return;
-        }
+        return tokenStart() - tokenLineStart();
+    }
+
+    ALWAYS_INLINE const JSTextPosition& tokenEndPosition()
+    {
+        return m_token.m_endPosition;
     }
     
-    NEVER_INLINE void updateErrorMessage() 
+    ALWAYS_INLINE unsigned tokenLineStart()
     {
-        m_error = true;
-        const char* name = getTokenName(m_token.m_type);
-        if (!name) 
-            updateErrorMessageSpecialCase(m_token.m_type);
-        else 
-            m_errorMessage = UString(String::format("Unexpected token '%s'", name).impl());
+        return m_token.m_location.lineStartOffset;
     }
     
-    NEVER_INLINE void updateErrorMessage(JSTokenType expectedToken) 
+    ALWAYS_INLINE const JSTokenLocation& tokenLocation()
     {
-        m_error = true;
-        const char* name = getTokenName(expectedToken);
-        if (name)
-            m_errorMessage = UString(String::format("Expected token '%s'", name).impl());
-        else {
-            if (!getTokenName(m_token.m_type))
-                updateErrorMessageSpecialCase(m_token.m_type);
-            else
-                updateErrorMessageSpecialCase(expectedToken);
-        } 
+        return m_token.m_location;
     }
+
+    void setErrorMessage(String msg)
+    {
+        m_errorMessage = msg;
+    }
+    
+    NEVER_INLINE void logError(bool);
+    template <typename A> NEVER_INLINE void logError(bool, const A&);
+    template <typename A, typename B> NEVER_INLINE void logError(bool, const A&, const B&);
+    template <typename A, typename B, typename C> NEVER_INLINE void logError(bool, const A&, const B&, const C&);
+    template <typename A, typename B, typename C, typename D> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&);
+    template <typename A, typename B, typename C, typename D, typename E> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&);
+    template <typename A, typename B, typename C, typename D, typename E, typename F> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&, const F&);
+    template <typename A, typename B, typename C, typename D, typename E, typename F, typename G> NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&, const F&, const G&);
     
-    NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, UString name, const char* afterMsg) 
+    NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, String name, const char* afterMsg)
     {
-        m_error = true;
-        String prefix(beforeMsg);
-        String postfix(afterMsg);
-        prefix += " '";
-        prefix += name.impl();
-        prefix += "' ";
-        prefix += postfix;
-        m_errorMessage = prefix.impl();
+        m_errorMessage = makeString(beforeMsg, " '", name, "' ", afterMsg);
     }
     
-    NEVER_INLINE void updateErrorMessage(const char* msg) 
-    {   
-        m_error = true;
-        m_errorMessage = UString(msg);
+    NEVER_INLINE void updateErrorMessage(const char* msg)
+    {
+        ASSERT(msg);
+        m_errorMessage = String(msg);
+        ASSERT(!m_errorMessage.isNull());
     }
     
     void startLoop() { currentScope()->startLoop(); }
@@ -831,6 +652,7 @@ private:
     bool strictMode() { return currentScope()->strictMode(); }
     bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
     bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+    Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); }
     bool breakIsValid()
     {
         ScopeRef current = currentScope();
@@ -865,7 +687,7 @@ private:
         return result;
     }
     
-    template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
+    template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode);
     template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
     template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
     template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
@@ -886,7 +708,7 @@ private:
     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> TreeStatement parseBlockStatement(TreeBuilder&);
     template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
     template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);
     template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
@@ -896,14 +718,19 @@ private:
     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> NEVER_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
+    enum SpreadMode { AllowSpread, DontAllowSpread };
+    template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&, SpreadMode);
+    template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict);
     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);
-    template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
+    template <class TreeBuilder> TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, TreeDeconstructionPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd);
+    template <class TreeBuilder> NEVER_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder&);
+
+    template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern createBindingPattern(TreeBuilder&, DeconstructionKind, const Identifier&, int depth);
+    template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern parseDeconstructionPattern(TreeBuilder&, DeconstructionKind, int depth = 0);
+    template <class TreeBuilder> NEVER_INLINE TreeDeconstructionPattern tryParseDeconstructionPatternExpression(TreeBuilder&);
+    template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, FunctionParseMode, bool nameIsInContainingScope, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, unsigned& openBraceOffset, unsigned& closeBraceOffset, int& bodyStartLine, unsigned& bodyStartColumn);
     ALWAYS_INLINE int isBinaryOperator(JSTokenType);
     bool allowAutomaticSemicolon();
     
@@ -918,37 +745,94 @@ private:
     
     bool canRecurse()
     {
-        return m_stack.recursionCheck();
+        return m_vm->isSafeToRecurse();
     }
     
-    int lastTokenEnd() const
+    const JSTextPosition& lastTokenEndPosition() const
     {
-        return m_lastTokenEnd;
+        return m_lastTokenEndPosition;
     }
 
-    mutable const JSGlobalData* m_globalData;
+    bool hasError() const
+    {
+        return !m_errorMessage.isNull();
+    }
+
+    struct SavePoint {
+        int startOffset;
+        unsigned oldLineStartOffset;
+        unsigned oldLastLineNumber;
+        unsigned oldLineNumber;
+    };
+    
+    ALWAYS_INLINE SavePoint createSavePoint()
+    {
+        ASSERT(!hasError());
+        SavePoint result;
+        result.startOffset = m_token.m_location.startOffset;
+        result.oldLineStartOffset = m_token.m_location.lineStartOffset;
+        result.oldLastLineNumber = m_lexer->lastLineNumber();
+        result.oldLineNumber = m_lexer->lineNumber();
+        return result;
+    }
+    
+    ALWAYS_INLINE void restoreSavePoint(const SavePoint& savePoint)
+    {
+        m_errorMessage = String();
+        m_lexer->setOffset(savePoint.startOffset, savePoint.oldLineStartOffset);
+        next();
+        m_lexer->setLastLineNumber(savePoint.oldLastLineNumber);
+        m_lexer->setLineNumber(savePoint.oldLineNumber);
+    }
+
+    struct ParserState {
+        int assignmentCount;
+        int nonLHSCount;
+        int nonTrivialExpressionCount;
+    };
+
+    ALWAYS_INLINE ParserState saveState()
+    {
+        ParserState result;
+        result.assignmentCount = m_assignmentCount;
+        result.nonLHSCount = m_nonLHSCount;
+        result.nonTrivialExpressionCount = m_nonTrivialExpressionCount;
+        return result;
+    }
+    
+    ALWAYS_INLINE void restoreState(const ParserState& state)
+    {
+        m_assignmentCount = state.assignmentCount;
+        m_nonLHSCount = state.nonLHSCount;
+        m_nonTrivialExpressionCount = state.nonTrivialExpressionCount;
+        
+    }
+    
+
+    VM* m_vm;
     const SourceCode* m_source;
     ParserArena* m_arena;
     OwnPtr<LexerType> m_lexer;
     
-    StackBounds m_stack;
-    bool m_error;
-    UString m_errorMessage;
+    bool m_hasStackOverflow;
+    String m_errorMessage;
     JSToken m_token;
     bool m_allowsIn;
-    int m_lastLine;
-    int m_lastTokenEnd;
+    JSTextPosition m_lastTokenEndPosition;
     int m_assignmentCount;
     int m_nonLHSCount;
     bool m_syntaxAlreadyValidated;
     int m_statementDepth;
     int m_nonTrivialExpressionCount;
     const Identifier* m_lastIdentifier;
-    SourceProviderCache* m_functionCache;
+    const Identifier* m_lastFunctionName;
+    RefPtr<SourceProviderCache> m_functionCache;
     SourceElements* m_sourceElements;
+    bool m_parsingBuiltin;
     ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations;
     ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
     IdentifierSet m_capturedVariables;
+    Vector<RefPtr<StringImpl>> m_closedVariables;
     CodeFeatures m_features;
     int m_numConstants;
     
@@ -970,28 +854,31 @@ private:
     };
 };
 
+
 template <typename LexerType>
 template <class ParsedNode>
-PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, JSObject** exception)
+PassRefPtr<ParsedNode> Parser<LexerType>::parse(ParserError& error, bool needReparsingAdjustment)
 {
-    ASSERT(lexicalGlobalObject);
-    ASSERT(exception && !*exception);
     int errLine;
-    UString errMsg;
+    String errMsg;
 
-    if (ParsedNode::scopeIsFunction)
+    if (ParsedNode::scopeIsFunction && needReparsingAdjustment)
         m_lexer->setIsReparsing();
 
     m_sourceElements = 0;
 
     errLine = -1;
-    errMsg = UString();
+    errMsg = String();
+
+    JSTokenLocation startLocation(tokenLocation());
+    ASSERT(m_source->startColumn() > 0);
+    unsigned startColumn = m_source->startColumn() - 1;
 
-    UString parseError = parseInner();
+    String parseError = parseInner();
 
     int lineNumber = m_lexer->lineNumber();
     bool lexError = m_lexer->sawError();
-    UString lexErrorMessage = lexError ? m_lexer->getErrorMessage() : UString();
+    String lexErrorMessage = lexError ? m_lexer->getErrorMessage() : String();
     ASSERT(lexErrorMessage.isNull() != lexError);
     m_lexer->clear();
 
@@ -1003,8 +890,16 @@ PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObj
 
     RefPtr<ParsedNode> result;
     if (m_sourceElements) {
-        result = ParsedNode::create(&lexicalGlobalObject->globalData(),
-                                    m_lexer->lastLineNumber(),
+        JSTokenLocation endLocation;
+        endLocation.line = m_lexer->lineNumber();
+        endLocation.lineStartOffset = m_lexer->currentLineStartOffset();
+        endLocation.startOffset = m_lexer->currentOffset();
+        unsigned endColumn = endLocation.startOffset - endLocation.lineStartOffset;
+        result = ParsedNode::create(m_vm,
+                                    startLocation,
+                                    endLocation,
+                                    startColumn,
+                                    endColumn,
                                     m_sourceElements,
                                     m_varDeclarations ? &m_varDeclarations->data : 0,
                                     m_funcDeclarations ? &m_funcDeclarations->data : 0,
@@ -1012,44 +907,60 @@ PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObj
                                     *m_source,
                                     m_features,
                                     m_numConstants);
-        result->setLoc(m_source->firstLine(), m_lastLine);
-    } else if (lexicalGlobalObject) {
+        result->setLoc(m_source->firstLine(), m_lexer->lineNumber(), m_lexer->currentOffset(), m_lexer->currentLineStartOffset());
+    } else {
         // We can never see a syntax error when reparsing a function, since we should have
         // reported the error when parsing the containing program or eval code. So if we're
         // parsing a function body node, we assume that what actually happened here is that
         // we ran out of stack while parsing. If we see an error while parsing eval or program
         // code we assume that it was a syntax error since running out of stack is much less
         // likely, and we are currently unable to distinguish between the two cases.
-        if (isFunctionBodyNode(static_cast<ParsedNode*>(0)))
-            *exception = createStackOverflowError(lexicalGlobalObject);
-        else if (isEvalNode<ParsedNode>())
-            *exception = createSyntaxError(lexicalGlobalObject, errMsg);
-        else
-            *exception = addErrorInfo(lexicalGlobalObject->globalExec(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, *m_source);
+        if (isFunctionBodyNode(static_cast<ParsedNode*>(0)) || m_hasStackOverflow)
+            error = ParserError(ParserError::StackOverflow, ParserError::SyntaxErrorNone, m_token);
+        else {
+            ParserError::SyntaxErrorType errorType = ParserError::SyntaxErrorIrrecoverable;
+            if (m_token.m_type == EOFTOK)
+                errorType = ParserError::SyntaxErrorRecoverable;
+            else if (m_token.m_type & UnterminatedErrorTokenFlag)
+                errorType = ParserError::SyntaxErrorUnterminatedLiteral;
+            
+            if (isEvalNode<ParsedNode>())
+                error = ParserError(ParserError::EvalError, errorType, m_token, errMsg, errLine);
+            else
+                error = ParserError(ParserError::SyntaxError, errorType, m_token, errMsg, errLine);
+        }
     }
 
-    if (debugger && !ParsedNode::scopeIsFunction)
-        debugger->sourceParsed(debuggerExecState, m_source->provider(), errLine, errMsg);
-
     m_arena->reset();
 
     return result.release();
 }
 
 template <class ParsedNode>
-PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, Debugger* debugger, ExecState* execState, JSObject** exception)
+PassRefPtr<ParsedNode> parse(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode, ParserError& error, JSTextPosition* positionBeforeLastNewline = 0, bool needReparsingAdjustment = false)
 {
     SamplingRegion samplingRegion("Parsing");
 
-    ASSERT(source.provider()->data());
-
-    if (source.provider()->data()->is8Bit()) {
-        Parser< Lexer<LChar> > parser(globalData, source, parameters, strictness, parserMode);
-        return parser.parse<ParsedNode>(lexicalGlobalObject, debugger, execState, exception);
+    ASSERT(!source.provider()->source().isNull());
+    if (source.provider()->source().is8Bit()) {
+        Parser<Lexer<LChar>> parser(vm, source, parameters, name, strictness, parserMode);
+        RefPtr<ParsedNode> result = parser.parse<ParsedNode>(error, needReparsingAdjustment);
+        if (positionBeforeLastNewline)
+            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
+        if (strictness == JSParseBuiltin) {
+            if (!result)
+                WTF::dataLog("Error compiling builtin: ", error.m_message, "\n");
+            RELEASE_ASSERT(result);
+            result->setClosedVariables(parser.closedVariables());
+        }
+        return result.release();
     }
-    Parser< Lexer<UChar> > parser(globalData, source, parameters, strictness, parserMode);
-    return parser.parse<ParsedNode>(lexicalGlobalObject, debugger, execState, exception);
+    Parser<Lexer<UChar>> parser(vm, source, parameters, name, strictness, parserMode);
+    RefPtr<ParsedNode> result = parser.parse<ParsedNode>(error, needReparsingAdjustment);
+    if (positionBeforeLastNewline)
+        *positionBeforeLastNewline = parser.positionBeforeLastNewline();
+    return result.release();
 }
 
-} // namespace 
+} // namespace
 #endif