X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174..ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250:/parser/Parser.h diff --git a/parser/Parser.h b/parser/Parser.h index c2a11d6..a0e5ce7 100644 --- a/parser/Parser.h +++ b/parser/Parser.h @@ -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 @@ -30,12 +30,14 @@ #include "Lexer.h" #include "Nodes.h" #include "ParserArena.h" +#include "ParserError.h" +#include "ParserFunctionInfo.h" #include "ParserTokens.h" #include "SourceProvider.h" +#include "SourceProviderCache.h" #include "SourceProviderCacheItem.h" #include #include -#include #include namespace JSC { struct Scope; @@ -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 @@ -90,51 +70,53 @@ class UString; #define TreeArguments typename TreeBuilder::Arguments #define TreeArgumentsList typename TreeBuilder::ArgumentsList #define TreeFunctionBody typename TreeBuilder::FunctionBody +#if ENABLE(ES6_CLASS_SYNTAX) +#define TreeClassExpression typename TreeBuilder::ClassExpression +#endif #define TreeProperty typename TreeBuilder::Property #define TreePropertyList typename TreeBuilder::PropertyList +#define TreeDestructuringPattern typename TreeBuilder::DestructuringPattern COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens); enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode }; +#if ENABLE(ES6_ARROWFUNCTION_SYNTAX) +enum FunctionParseType { StandardFunctionParseType, ArrowFunctionParseType }; +#else +enum FunctionParseType { StandardFunctionParseType}; +#endif enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName }; +enum FunctionParseMode { + FunctionMode, + GetterMode, + SetterMode, + MethodMode, +#if ENABLE(ES6_ARROWFUNCTION_SYNTAX) + ArrowFunctionMode +#endif +}; +enum DestructuringKind { + DestructureToVariables, + DestructureToParameters, + DestructureToExpressions +}; template inline bool isEvalNode() { return false; } template <> inline bool isEvalNode() { 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) - , m_isLoop(isLoop) - { - } - - StringImpl* m_ident; - bool m_isLoop; + UniquedStringImpl* uid; + bool isLoop; }; 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) + , m_hasDirectSuper(false) + , m_needsSuperBinding(false) , m_allowsNewDecls(true) , m_strictMode(strictMode) , m_isFunction(isFunction) @@ -146,10 +128,12 @@ 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) + , m_hasDirectSuper(rhs.m_hasDirectSuper) + , m_needsSuperBinding(rhs.m_needsSuperBinding) , m_allowsNewDecls(rhs.m_allowsNewDecls) , m_strictMode(rhs.m_strictMode) , m_isFunction(rhs.m_isFunction) @@ -159,12 +143,12 @@ struct Scope { , m_switchDepth(rhs.m_switchDepth) { if (rhs.m_labels) { - m_labels = adoptPtr(new LabelStack); + m_labels = std::make_unique(); 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)); + m_labels->append(ScopeLabelInfo { it->uid, it->isLoop }); } } @@ -179,8 +163,8 @@ struct Scope { void pushLabel(const Identifier* label, bool isLoop) { if (!m_labels) - m_labels = adoptPtr(new LabelStack); - m_labels->append(ScopeLabelInfo(label->impl(), isLoop)); + m_labels = std::make_unique(); + m_labels->append(ScopeLabelInfo { label->impl(), isLoop }); } void popLabel() @@ -195,7 +179,7 @@ struct Scope { if (!m_labels) return 0; for (int i = m_labels->size(); i > 0; i--) { - if (m_labels->at(i - 1).m_ident == label->impl()) + if (m_labels->at(i - 1).uid == label->impl()) return &m_labels->at(i - 1); } return 0; @@ -209,14 +193,29 @@ struct Scope { bool isFunction() { return m_isFunction; } bool isFunctionBoundary() { return m_isFunctionBoundary; } + void declareCallee(const Identifier* ident) + { + m_declaredVariables.add(ident->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->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,22 +227,62 @@ 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->impl()).isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments; m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; + m_declaredParameters.add(ident->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->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->impl()); } void setNeedsFullActivation() { m_needsFullActivation = true; } +#if ENABLE(ES6_CLASS_SYNTAX) + bool hasDirectSuper() { return m_hasDirectSuper; } +#else + bool hasDirectSuper() { return false; } +#endif + void setHasDirectSuper() { m_hasDirectSuper = true; } + +#if ENABLE(ES6_CLASS_SYNTAX) + bool needsSuperBinding() { return m_needsSuperBinding; } +#else + bool needsSuperBinding() { return false; } +#endif + void setNeedsSuperBinding() { m_needsSuperBinding = true; } + bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables) { if (nestedScope->m_usesEval) @@ -268,19 +307,11 @@ 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, bool& modifiedArguments) { if (m_needsFullActivation || m_usesEval) { - capturedVariables.swap(m_declaredVariables); + modifiedParameter = true; + capturedVariables = m_declaredVariables; return; } for (IdentifierSet::iterator ptr = m_closedVariables.begin(); ptr != m_closedVariables.end(); ++ptr) { @@ -288,13 +319,27 @@ struct Scope { continue; capturedVariables.add(*ptr); } + modifiedParameter = false; + if (shadowsArguments()) + modifiedArguments = true; + if (m_declaredParameters.size()) { + IdentifierSet::iterator end = m_writtenVariables.end(); + for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) { + if (*ptr == m_vm->propertyNames->arguments.impl()) + modifiedArguments = true; + 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 >& vector) + void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector>& vector) { IdentifierSet::iterator end = capturedVariables.end(); for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) { @@ -302,38 +347,37 @@ 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; + bool m_hasDirectSuper : 1; + bool m_needsSuperBinding : 1; bool m_allowsNewDecls : 1; bool m_strictMode : 1; bool m_isFunction : 1; @@ -343,7 +387,8 @@ private: int m_switchDepth; typedef Vector LabelStack; - OwnPtr m_labels; + std::unique_ptr m_labels; + IdentifierSet m_declaredParameters; IdentifierSet m_declaredVariables; IdentifierSet m_usedVariables; IdentifierSet m_closedVariables; @@ -383,11 +428,18 @@ class Parser { WTF_MAKE_FAST_ALLOCATED; public: - Parser(JSGlobalData*, const SourceCode&, FunctionParameters*, JSParserStrictness, JSParserMode); + Parser( + VM*, const SourceCode&, FunctionParameters*, const Identifier&, + JSParserBuiltinMode, JSParserStrictMode, JSParserCodeType, + ConstructorKind defaultConstructorKind = ConstructorKind::None, ThisTDZMode = ThisTDZMode::CheckIfNeeded); ~Parser(); template - PassRefPtr parse(JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, JSObject**); + std::unique_ptr parse(ParserError&); + + JSTextPosition positionBeforeLastNewline() const { return m_lexer->positionBeforeLastNewline(); } + JSTokenLocation locationBeforeLastToken() const { return m_lexer->lastTokenLocation(); } + Vector>&& closedVariables() { return WTF::move(m_closedVariables); } private: struct AllowInOverride { @@ -440,7 +492,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 +527,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 +563,33 @@ private: } Parser(); - UString parseInner(); + String parseInner(); - void didFinishParsing(SourceElements*, ParserArenaData*, - ParserArenaData*, CodeFeatures, - int, int, IdentifierSet&); + void didFinishParsing(SourceElements*, DeclarationStacks::VarStack&, + DeclarationStacks::FunctionStack&, CodeFeatures, int, IdentifierSet&, const Vector>&&); // 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 +604,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 +616,111 @@ 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() +#if ENABLE(ES6_ARROWFUNCTION_SYNTAX) + ALWAYS_INLINE bool isEndOfArrowFunction() { - return m_token.m_info.line; + return match(SEMICOLON) || match(COMMA) || match(CLOSEPAREN) || match(CLOSEBRACE) || match(CLOSEBRACKET) || match(EOFTOK) || m_lexer->prevTerminator(); } - ALWAYS_INLINE int tokenEnd() + ALWAYS_INLINE bool isArrowFunctionParamters() { - return m_token.m_info.endOffset; + bool isArrowFunction = false; + + if (match(EOFTOK)) + return isArrowFunction; + + SavePoint saveArrowFunctionPoint = createSavePoint(); + + if (consume(OPENPAREN)) { + bool isArrowFunctionParamters = true; + + while (consume(IDENT)) { + if (consume(COMMA)) { + if (!match(IDENT)) { + isArrowFunctionParamters = false; + break; + } + } else + break; + } + + if (isArrowFunctionParamters) { + if (consume(CLOSEPAREN) && match(ARROWFUNCTION)) + isArrowFunction = true; + } + } else if (consume(IDENT) && match(ARROWFUNCTION)) + isArrowFunction = true; + + restoreSavePoint(saveArrowFunctionPoint); + + return isArrowFunction; } +#endif - const char* getTokenName(JSTokenType tok) + ALWAYS_INLINE unsigned tokenStart() { - 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.startOffset; } - ALWAYS_INLINE void updateErrorMessageSpecialCase(JSTokenType expectedToken) + ALWAYS_INLINE const JSTextPosition& tokenStartPosition() { - 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 m_token.m_startPosition; + } + + ALWAYS_INLINE int tokenLine() + { + return m_token.m_location.line; } - NEVER_INLINE void updateErrorMessage() + ALWAYS_INLINE int tokenColumn() { - 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 tokenStart() - tokenLineStart(); + } + + ALWAYS_INLINE const JSTextPosition& tokenEndPosition() + { + return m_token.m_endPosition; } - NEVER_INLINE void updateErrorMessage(JSTokenType expectedToken) + ALWAYS_INLINE unsigned tokenLineStart() { - 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.lineStartOffset; + } + + ALWAYS_INLINE const JSTokenLocation& tokenLocation() + { + return m_token.m_location; + } + + void setErrorMessage(const String& message) + { + m_errorMessage = message; } - NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, UString name, const char* afterMsg) + NEVER_INLINE void logError(bool); + template NEVER_INLINE void logError(bool, const A&); + template NEVER_INLINE void logError(bool, const A&, const B&); + template NEVER_INLINE void logError(bool, const A&, const B&, const C&); + template NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&); + template NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&); + template NEVER_INLINE void logError(bool, const A&, const B&, const C&, const D&, const E&, const F&); + template 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* beforeMessage, const String& name, const char* afterMessage) { - m_error = true; - String prefix(beforeMsg); - String postfix(afterMsg); - prefix += " '"; - prefix += name.impl(); - prefix += "' "; - prefix += postfix; - m_errorMessage = prefix.impl(); + m_errorMessage = makeString(beforeMessage, " '", name, "' ", afterMessage); } - 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 +731,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(); @@ -864,9 +765,13 @@ private: } return result; } - - template TreeSourceElements parseSourceElements(TreeBuilder&); + + template TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode, FunctionParseType); + template TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength); template TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0); +#if ENABLE(ES6_CLASS_SYNTAX) + template TreeStatement parseClassDeclaration(TreeBuilder&); +#endif template TreeStatement parseFunctionDeclaration(TreeBuilder&); template TreeStatement parseVarDeclaration(TreeBuilder&); template TreeStatement parseConstDeclaration(TreeBuilder&); @@ -886,7 +791,7 @@ private: template TreeStatement parseExpressionStatement(TreeBuilder&); template TreeStatement parseExpressionOrLabelStatement(TreeBuilder&); template TreeStatement parseIfStatement(TreeBuilder&); - template ALWAYS_INLINE TreeStatement parseBlockStatement(TreeBuilder&); + template TreeStatement parseBlockStatement(TreeBuilder&); template TreeExpression parseExpression(TreeBuilder&); template TreeExpression parseAssignmentExpression(TreeBuilder&); template ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&); @@ -896,14 +801,43 @@ private: template ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&); template ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&); template ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&); - template ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&); - template ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&); - template ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&); - template ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&); + template NEVER_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&); + enum SpreadMode { AllowSpread, DontAllowSpread }; + template ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&, SpreadMode); + template TreeProperty parseProperty(TreeBuilder&, bool strict); + template TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName); + template TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind = ConstructorKind::None, SuperBinding = SuperBinding::NotNeeded); + template ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, FunctionParseType); template ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&); - template ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd); - template ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context); - template bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine); + enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext }; + template TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext); + template NEVER_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder&); + +#if ENABLE(ES6_ARROWFUNCTION_SYNTAX) + template TreeStatement parseArrowFunctionSingleExpressionBody(TreeBuilder&, FunctionParseType); + template TreeExpression parseArrowFunctionExpression(TreeBuilder&); +#endif + + template NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, const Identifier&, int depth, JSToken); + template NEVER_INLINE TreeDestructuringPattern parseDestructuringPattern(TreeBuilder&, DestructuringKind, int depth = 0); + template NEVER_INLINE TreeDestructuringPattern tryParseDestructuringPatternExpression(TreeBuilder&); + template NEVER_INLINE TreeExpression parseDefaultValueForDestructuringPattern(TreeBuilder&); + + template NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, FunctionParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo&, FunctionParseType); + + template NEVER_INLINE int parseFunctionParameters(TreeBuilder&, FunctionParseMode, ParserFunctionInfo&); + +#if ENABLE(ES6_CLASS_SYNTAX) + template NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionRequirements, ParserClassInfo&); +#endif + +#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) + template NEVER_INLINE typename TreeBuilder::TemplateString parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode, bool& elementIsTail); + template NEVER_INLINE typename TreeBuilder::TemplateLiteral parseTemplateLiteral(TreeBuilder&, typename LexerType::RawStringsBuildMode); +#endif + + template ALWAYS_INLINE bool shouldCheckPropertyForUnderscoreProtoDuplicate(TreeBuilder&, const TreeProperty&); + ALWAYS_INLINE int isBinaryOperator(JSTokenType); bool allowAutomaticSemicolon(); @@ -916,39 +850,106 @@ private: return allowAutomaticSemicolon(); } + +#if ENABLE(ES6_ARROWFUNCTION_SYNTAX) + void setEndOfStatement() + { + m_lexer->setTokenPosition(&m_token); + } +#endif + bool canRecurse() { - return m_stack.recursionCheck(); + return m_vm->isSafeToRecurse(); } - int lastTokenEnd() const + const JSTextPosition& lastTokenEndPosition() const + { + return m_lastTokenEndPosition; + } + + bool hasError() const { - return m_lastTokenEnd; + return !m_errorMessage.isNull(); } - mutable const JSGlobalData* m_globalData; + 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 m_lexer; + ParserArena m_parserArena; + std::unique_ptr 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 m_functionCache; SourceElements* m_sourceElements; - ParserArenaData* m_varDeclarations; - ParserArenaData* m_funcDeclarations; + bool m_parsingBuiltin; + ConstructorKind m_defaultConstructorKind; + ThisTDZMode m_thisTDZMode; + DeclarationStacks::VarStack m_varDeclarations; + DeclarationStacks::FunctionStack m_funcDeclarations; IdentifierSet m_capturedVariables; + Vector> m_closedVariables; CodeFeatures m_features; int m_numConstants; @@ -970,14 +971,13 @@ private: }; }; + template template -PassRefPtr Parser::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, JSObject** exception) +std::unique_ptr Parser::parse(ParserError& error) { - ASSERT(lexicalGlobalObject); - ASSERT(exception && !*exception); int errLine; - UString errMsg; + String errMsg; if (ParsedNode::scopeIsFunction) m_lexer->setIsReparsing(); @@ -985,13 +985,17 @@ PassRefPtr Parser::parse(JSGlobalObject* lexicalGlobalObj 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(); @@ -1001,55 +1005,84 @@ PassRefPtr Parser::parse(JSGlobalObject* lexicalGlobalObj m_sourceElements = 0; } - RefPtr result; + std::unique_ptr 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 = std::make_unique(m_parserArena, + startLocation, + endLocation, + startColumn, + endColumn, m_sourceElements, - m_varDeclarations ? &m_varDeclarations->data : 0, - m_funcDeclarations ? &m_funcDeclarations->data : 0, + m_varDeclarations, + m_funcDeclarations, m_capturedVariables, *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()); + result->setEndOffset(m_lexer->currentOffset()); + } 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(0))) - *exception = createStackOverflowError(lexicalGlobalObject); - else if (isEvalNode()) - *exception = createSyntaxError(lexicalGlobalObject, errMsg); - else - *exception = addErrorInfo(lexicalGlobalObject->globalExec(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, *m_source); + if (isFunctionBodyNode(static_cast(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()) + 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(); + return result; } template -PassRefPtr parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, Debugger* debugger, ExecState* execState, JSObject** exception) +std::unique_ptr parse( + VM* vm, const SourceCode& source, FunctionParameters* parameters, + const Identifier& name, JSParserBuiltinMode builtinMode, + JSParserStrictMode strictMode, JSParserCodeType codeType, + ParserError& error, JSTextPosition* positionBeforeLastNewline = 0, + ConstructorKind defaultConstructorKind = ConstructorKind::None, ThisTDZMode thisTDZMode = ThisTDZMode::CheckIfNeeded) { SamplingRegion samplingRegion("Parsing"); - ASSERT(source.provider()->data()); - - if (source.provider()->data()->is8Bit()) { - Parser< Lexer > parser(globalData, source, parameters, strictness, parserMode); - return parser.parse(lexicalGlobalObject, debugger, execState, exception); + ASSERT(!source.provider()->source().isNull()); + if (source.provider()->source().is8Bit()) { + Parser> parser(vm, source, parameters, name, builtinMode, strictMode, codeType, defaultConstructorKind, thisTDZMode); + std::unique_ptr result = parser.parse(error); + if (positionBeforeLastNewline) + *positionBeforeLastNewline = parser.positionBeforeLastNewline(); + if (builtinMode == JSParserBuiltinMode::Builtin) { + if (!result) + WTF::dataLog("Error compiling builtin: ", error.message(), "\n"); + RELEASE_ASSERT(result); + result->setClosedVariables(parser.closedVariables()); + } + return result; } - Parser< Lexer > parser(globalData, source, parameters, strictness, parserMode); - return parser.parse(lexicalGlobalObject, debugger, execState, exception); + ASSERT_WITH_MESSAGE(defaultConstructorKind == ConstructorKind::None, "BuiltinExecutables::createDefaultConstructor should always use a 8-bit string"); + Parser> parser(vm, source, parameters, name, builtinMode, strictMode, codeType, defaultConstructorKind, thisTDZMode); + std::unique_ptr result = parser.parse(error); + if (positionBeforeLastNewline) + *positionBeforeLastNewline = parser.positionBeforeLastNewline(); + return result; } -} // namespace +} // namespace #endif