X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/93a3786624b2768d89bfa27e46598dc64e2fb70a..ed1e77d3adeb83d26fd1dfb16dd84cabdcefd250:/parser/Parser.h diff --git a/parser/Parser.h b/parser/Parser.h index ff30f1e..a0e5ce7 100644 --- a/parser/Parser.h +++ b/parser/Parser.h @@ -31,13 +31,13 @@ #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; @@ -70,43 +70,43 @@ class SourceCode; #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 { @@ -115,6 +115,8 @@ struct Scope { , m_shadowsArguments(false) , m_usesEval(false) , m_needsFullActivation(false) + , m_hasDirectSuper(false) + , m_needsSuperBinding(false) , m_allowsNewDecls(true) , m_strictMode(strictMode) , m_isFunction(isFunction) @@ -130,6 +132,8 @@ struct Scope { , 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) @@ -139,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 }); } } @@ -159,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() @@ -175,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; @@ -191,17 +195,27 @@ struct Scope { void declareCallee(const Identifier* ident) { - m_declaredVariables.add(ident->string().impl()); + m_declaredVariables.add(ident->impl()); } bool declareVariable(const Identifier* ident) { bool isValidStrictMode = m_vm->propertyNames->eval != *ident && m_vm->propertyNames->arguments != *ident; m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; - m_declaredVariables.add(ident->string().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); @@ -214,21 +228,61 @@ struct Scope { bool declareParameter(const Identifier* ident) { bool isArguments = m_vm->propertyNames->arguments == *ident; - bool isValidStrictMode = m_declaredVariables.add(ident->string().impl()).isNewEntry && m_vm->propertyNames->eval != *ident && !isArguments; + 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->string().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) @@ -253,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) { @@ -273,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) { @@ -316,6 +376,8 @@ private: 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; @@ -325,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; @@ -365,11 +428,18 @@ class Parser { WTF_MAKE_FAST_ALLOCATED; public: - Parser(VM*, const SourceCode&, FunctionParameters*, const Identifier&, JSParserStrictness, JSParserMode); + Parser( + VM*, const SourceCode&, FunctionParameters*, const Identifier&, + JSParserBuiltinMode, JSParserStrictMode, JSParserCodeType, + ConstructorKind defaultConstructorKind = ConstructorKind::None, ThisTDZMode = ThisTDZMode::CheckIfNeeded); ~Parser(); template - PassRefPtr parse(ParserError&); + 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 { @@ -457,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); } @@ -473,9 +565,8 @@ private: Parser(); 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; } @@ -483,20 +574,22 @@ private: ALWAYS_INLINE void next(unsigned lexerFlags = 0) { - m_lastLine = m_token.m_location.line; - m_lastTokenEnd = m_token.m_location.endOffset; - m_lastTokenLineStart = m_token.m_location.lineStartOffset; - m_lexer->setLastLineNumber(m_lastLine); - m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_location, 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_location.line; - m_lastTokenEnd = m_token.m_location.endOffset; - m_lastTokenLineStart = m_token.m_location.lineStartOffset; - m_lexer->setLastLineNumber(m_lastLine); - m_token.m_type = m_lexer->lexExpectIdentifier(&m_token.m_data, &m_token.m_location, 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() @@ -511,10 +604,11 @@ private: next(flags); return result; } - + + void printUnexpectedTokenText(WTF::PrintStream&); ALWAYS_INLINE String getToken() { SourceProvider* sourceProvider = m_source->provider(); - return sourceProvider->getRange(tokenStart(), tokenEnd()); + return sourceProvider->getRange(tokenStart(), tokenEndPosition().offset); } ALWAYS_INLINE bool match(JSTokenType expected) @@ -522,11 +616,62 @@ private: return m_token.m_type == expected; } + ALWAYS_INLINE bool isofToken() + { + return m_token.m_type == IDENT && *m_token.m_data.ident == m_vm->propertyNames->of; + } + +#if ENABLE(ES6_ARROWFUNCTION_SYNTAX) + ALWAYS_INLINE bool isEndOfArrowFunction() + { + return match(SEMICOLON) || match(COMMA) || match(CLOSEPAREN) || match(CLOSEBRACE) || match(CLOSEBRACKET) || match(EOFTOK) || m_lexer->prevTerminator(); + } + + ALWAYS_INLINE bool isArrowFunctionParamters() + { + 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 + ALWAYS_INLINE unsigned tokenStart() { return m_token.m_location.startOffset; } + ALWAYS_INLINE const JSTextPosition& tokenStartPosition() + { + return m_token.m_startPosition; + } + ALWAYS_INLINE int tokenLine() { return m_token.m_location.line; @@ -537,9 +682,9 @@ private: return tokenStart() - tokenLineStart(); } - ALWAYS_INLINE unsigned tokenEnd() + ALWAYS_INLINE const JSTextPosition& tokenEndPosition() { - return m_token.m_location.endOffset; + return m_token.m_endPosition; } ALWAYS_INLINE unsigned tokenLineStart() @@ -552,281 +697,23 @@ private: return m_token.m_location; } - const char* getTokenName(JSTokenType tok) + void setErrorMessage(const String& message) { - 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 UNTERMINATED_IDENTIFIER_ESCAPE_ERRORTOK: - case UNTERMINATED_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK: - case UNTERMINATED_MULTILINE_COMMENT_ERRORTOK: - case UNTERMINATED_NUMERIC_LITERAL_ERRORTOK: - case UNTERMINATED_STRING_LITERAL_ERRORTOK: - case INVALID_IDENTIFIER_ESCAPE_ERRORTOK: - case INVALID_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK: - case INVALID_NUMERIC_LITERAL_ERRORTOK: - case INVALID_OCTAL_NUMBER_ERRORTOK: - case INVALID_STRING_LITERAL_ERRORTOK: - case ERRORTOK: - case EOFTOK: - return 0; - case LastUntaggedToken: - break; - } - RELEASE_ASSERT_NOT_REACHED(); - return "internal error"; - } - - ALWAYS_INLINE void updateErrorMessageSpecialCase(JSTokenType expectedToken) - { - switch (expectedToken) { - case RESERVED_IF_STRICT: - m_errorMessage = "Use of reserved word '" + getToken() + "' in strict mode"; - return; - case RESERVED: - m_errorMessage = "Use of reserved word '" + getToken() + '\''; - return; - case NUMBER: - m_errorMessage = "Unexpected number '" + getToken() + '\''; - return; - case IDENT: - m_errorMessage = "Expected an identifier but found '" + getToken() + "' instead"; - return; - case STRING: - m_errorMessage = "Unexpected string " + getToken(); - return; - - case UNTERMINATED_IDENTIFIER_ESCAPE_ERRORTOK: - case UNTERMINATED_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK: - m_errorMessage = "Incomplete unicode escape in identifier: '" + getToken() + '\''; - return; - case UNTERMINATED_MULTILINE_COMMENT_ERRORTOK: - m_errorMessage = "Unterminated multiline comment"; - return; - case UNTERMINATED_NUMERIC_LITERAL_ERRORTOK: - m_errorMessage = "Unterminated numeric literal '" + getToken() + '\''; - return; - case UNTERMINATED_STRING_LITERAL_ERRORTOK: - m_errorMessage = "Unterminated string literal '" + getToken() + '\''; - return; - case INVALID_IDENTIFIER_ESCAPE_ERRORTOK: - m_errorMessage = "Invalid escape in identifier: '" + getToken() + '\''; - return; - case INVALID_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK: - m_errorMessage = "Invalid unicode escape in identifier: '" + getToken() + '\''; - return; - case INVALID_NUMERIC_LITERAL_ERRORTOK: - m_errorMessage = "Invalid numeric literal: '" + getToken() + '\''; - return; - case INVALID_OCTAL_NUMBER_ERRORTOK: - m_errorMessage = "Invalid use of octal: '" + getToken() + '\''; - return; - case INVALID_STRING_LITERAL_ERRORTOK: - m_errorMessage = "Invalid string literal: '" + getToken() + '\''; - return; - case ERRORTOK: - m_errorMessage = "Unrecognized token '" + getToken() + '\''; - return; - case EOFTOK: - m_errorMessage = ASCIILiteral("Unexpected EOF"); - return; - case RETURN: - m_errorMessage = ASCIILiteral("Return statements are only valid inside functions"); - return; - default: - RELEASE_ASSERT_NOT_REACHED(); - m_errorMessage = ASCIILiteral("internal error"); - return; - } + m_errorMessage = message; } - NEVER_INLINE void updateErrorMessage() - { - const char* name = getTokenName(m_token.m_type); - if (!name) - updateErrorMessageSpecialCase(m_token.m_type); - else - m_errorMessage = String::format("Unexpected token '%s'", name); - ASSERT(!m_errorMessage.isNull()); - } + 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 updateErrorMessage(JSTokenType expectedToken) + NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMessage, const String& name, const char* afterMessage) { - const char* name = getTokenName(expectedToken); - if (name) - m_errorMessage = String::format("Expected token '%s'", name); - else { - if (!getTokenName(m_token.m_type)) - updateErrorMessageSpecialCase(m_token.m_type); - else - updateErrorMessageSpecialCase(expectedToken); - } - ASSERT(!m_errorMessage.isNull()); - } - - NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, String name, const char* afterMsg) - { - m_errorMessage = makeString(beforeMsg, " '", name, "' ", afterMsg); + m_errorMessage = makeString(beforeMessage, " '", name, "' ", afterMessage); } NEVER_INLINE void updateErrorMessage(const char* msg) @@ -844,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(); @@ -877,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&); @@ -899,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&); @@ -909,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&, unsigned& openBraceOffset, unsigned& closeBraceOffset, int& bodyStartLine, unsigned& bodyStartColumn); + 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(); @@ -929,56 +850,106 @@ private: return allowAutomaticSemicolon(); } + +#if ENABLE(ES6_ARROWFUNCTION_SYNTAX) + void setEndOfStatement() + { + m_lexer->setTokenPosition(&m_token); + } +#endif + bool canRecurse() { - return m_stack.isSafeToRecurse(); + return m_vm->isSafeToRecurse(); } - int lastTokenEnd() const + const JSTextPosition& lastTokenEndPosition() const { - return m_lastTokenEnd; + return m_lastTokenEndPosition; } - unsigned lastTokenLine() const + bool hasError() const { - return m_lastLine; + return !m_errorMessage.isNull(); } - unsigned lastTokenLineStart() const + 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) { - return m_lastTokenLineStart; + m_errorMessage = String(); + m_lexer->setOffset(savePoint.startOffset, savePoint.oldLineStartOffset); + next(); + m_lexer->setLastLineNumber(savePoint.oldLastLineNumber); + m_lexer->setLineNumber(savePoint.oldLineNumber); } - bool hasError() const + struct ParserState { + int assignmentCount; + int nonLHSCount; + int nonTrivialExpressionCount; + }; + + ALWAYS_INLINE ParserState saveState() { - return !m_errorMessage.isNull(); + 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_hasStackOverflow; String m_errorMessage; JSToken m_token; bool m_allowsIn; - unsigned m_lastLine; - int m_lastTokenEnd; - unsigned m_lastTokenLine; - unsigned m_lastTokenLineStart; + JSTextPosition m_lastTokenEndPosition; int m_assignmentCount; int m_nonLHSCount; bool m_syntaxAlreadyValidated; int m_statementDepth; int m_nonTrivialExpressionCount; const Identifier* m_lastIdentifier; + 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; @@ -1003,7 +974,7 @@ private: template template -PassRefPtr Parser::parse(ParserError& error) +std::unique_ptr Parser::parse(ParserError& error) { int errLine; String errMsg; @@ -1017,7 +988,8 @@ PassRefPtr Parser::parse(ParserError& error) errMsg = String(); JSTokenLocation startLocation(tokenLocation()); - unsigned startColumn = m_source->startColumn(); + ASSERT(m_source->startColumn() > 0); + unsigned startColumn = m_source->startColumn() - 1; String parseError = parseInner(); @@ -1033,24 +1005,27 @@ PassRefPtr Parser::parse(ParserError& error) m_sourceElements = 0; } - RefPtr result; + std::unique_ptr result; if (m_sourceElements) { JSTokenLocation endLocation; - endLocation.line = m_lexer->lastLineNumber(); + endLocation.line = m_lexer->lineNumber(); endLocation.lineStartOffset = m_lexer->currentLineStartOffset(); endLocation.startOffset = m_lexer->currentOffset(); - result = ParsedNode::create(m_vm, + 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, m_lexer->currentOffset(), m_lexer->currentLineStartOffset()); + 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 @@ -1074,23 +1049,39 @@ PassRefPtr Parser::parse(ParserError& error) } } - m_arena->reset(); - - return result.release(); + return result; } template -PassRefPtr parse(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode, ParserError& error) +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()->source().isNull()); if (source.provider()->source().is8Bit()) { - Parser< Lexer > parser(vm, source, parameters, name, strictness, parserMode); - return parser.parse(error); + 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(vm, source, parameters, name, strictness, parserMode); - return parser.parse(error); + 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