+ ALWAYS_INLINE bool consume(JSTokenType expected, unsigned flags = 0)
+ {
+ bool result = m_token.m_type == expected;
+ if (result)
+ next(flags);
+ return result;
+ }
+
+ void printUnexpectedTokenText(WTF::PrintStream&);
+ ALWAYS_INLINE String getToken() {
+ SourceProvider* sourceProvider = m_source->provider();
+ return sourceProvider->getRange(tokenStart(), tokenEndPosition().offset);
+ }
+
+ ALWAYS_INLINE bool match(JSTokenType expected)
+ {
+ 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;
+ }
+
+ ALWAYS_INLINE int tokenColumn()
+ {
+ return tokenStart() - tokenLineStart();
+ }
+
+ ALWAYS_INLINE const JSTextPosition& tokenEndPosition()
+ {
+ return m_token.m_endPosition;
+ }
+
+ ALWAYS_INLINE unsigned tokenLineStart()
+ {
+ 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 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* beforeMessage, const String& name, const char* afterMessage)
+ {
+ m_errorMessage = makeString(beforeMessage, " '", name, "' ", afterMessage);
+ }
+
+ NEVER_INLINE void updateErrorMessage(const char* msg)
+ {
+ ASSERT(msg);
+ m_errorMessage = String(msg);
+ ASSERT(!m_errorMessage.isNull());
+ }
+
+ void startLoop() { currentScope()->startLoop(); }
+ void endLoop() { currentScope()->endLoop(); }
+ void startSwitch() { currentScope()->startSwitch(); }
+ void endSwitch() { currentScope()->endSwitch(); }
+ void setStrictMode() { currentScope()->setStrictMode(); }
+ bool strictMode() { return currentScope()->strictMode(); }
+ bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
+ bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+ Scope::BindingResult declareBoundParameter(const Identifier* ident) { return currentScope()->declareBoundParameter(ident); }
+ bool breakIsValid()
+ {
+ ScopeRef current = currentScope();
+ while (!current->breakIsValid()) {
+ if (!current.hasContainingScope())
+ return false;
+ current = current.containingScope();
+ }
+ return true;
+ }
+ bool continueIsValid()
+ {
+ ScopeRef current = currentScope();
+ while (!current->continueIsValid()) {
+ if (!current.hasContainingScope())
+ return false;
+ current = current.containingScope();
+ }
+ return true;
+ }
+ void pushLabel(const Identifier* label, bool isLoop) { currentScope()->pushLabel(label, isLoop); }
+ void popLabel() { currentScope()->popLabel(); }
+ ScopeLabelInfo* getLabel(const Identifier* label)
+ {
+ ScopeRef current = currentScope();
+ ScopeLabelInfo* result = 0;
+ while (!(result = current->getLabel(label))) {
+ if (!current.hasContainingScope())
+ return 0;
+ current = current.containingScope();
+ }
+ return result;
+ }
+
+ template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&, SourceElementsMode, FunctionParseType);
+ template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength);
+ template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
+#if ENABLE(ES6_CLASS_SYNTAX)
+ template <class TreeBuilder> TreeStatement parseClassDeclaration(TreeBuilder&);
+#endif
+ template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseBreakStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseContinueStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseReturnStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseThrowStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseWithStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseSwitchStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeClauseList parseSwitchClauses(TreeBuilder&);
+ template <class TreeBuilder> TreeClause parseSwitchDefaultClause(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseTryStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseDebuggerStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseBlockStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
+ template <class TreeBuilder> 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> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName);
+ template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind = ConstructorKind::None, SuperBinding = SuperBinding::NotNeeded);
+ template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, int functionKeywordStart, int functionNameStart, int parametersStart, ConstructorKind, FunctionParseType);
+ template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&);
+ enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext };
+ template <class TreeBuilder> TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext);
+ template <class TreeBuilder> NEVER_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder&);
+
+#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
+ template <class TreeBuilder> TreeStatement parseArrowFunctionSingleExpressionBody(TreeBuilder&, FunctionParseType);
+ template <class TreeBuilder> TreeExpression parseArrowFunctionExpression(TreeBuilder&);
+#endif
+
+ template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern createBindingPattern(TreeBuilder&, DestructuringKind, const Identifier&, int depth, JSToken);
+ template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern parseDestructuringPattern(TreeBuilder&, DestructuringKind, int depth = 0);
+ template <class TreeBuilder> NEVER_INLINE TreeDestructuringPattern tryParseDestructuringPatternExpression(TreeBuilder&);
+ template <class TreeBuilder> NEVER_INLINE TreeExpression parseDefaultValueForDestructuringPattern(TreeBuilder&);
+
+ template <class TreeBuilder> NEVER_INLINE bool parseFunctionInfo(TreeBuilder&, FunctionRequirements, FunctionParseMode, bool nameIsInContainingScope, ConstructorKind, SuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>&, FunctionParseType);
+
+ template <class TreeBuilder> NEVER_INLINE int parseFunctionParameters(TreeBuilder&, FunctionParseMode, ParserFunctionInfo<TreeBuilder>&);
+
+#if ENABLE(ES6_CLASS_SYNTAX)
+ template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionRequirements, ParserClassInfo<TreeBuilder>&);
+#endif
+
+#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
+ template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateString parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode, bool& elementIsTail);
+ template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateLiteral parseTemplateLiteral(TreeBuilder&, typename LexerType::RawStringsBuildMode);
+#endif
+
+ template <class TreeBuilder> ALWAYS_INLINE bool shouldCheckPropertyForUnderscoreProtoDuplicate(TreeBuilder&, const TreeProperty&);
+
+ ALWAYS_INLINE int isBinaryOperator(JSTokenType);
+ bool allowAutomaticSemicolon();
+
+ bool autoSemiColon()
+ {
+ if (m_token.m_type == SEMICOLON) {
+ next();
+ return true;
+ }
+ return allowAutomaticSemicolon();
+ }
+
+
+#if ENABLE(ES6_ARROWFUNCTION_SYNTAX)
+ void setEndOfStatement()
+ {
+ m_lexer->setTokenPosition(&m_token);
+ }
+#endif
+
+ bool canRecurse()
+ {
+ return m_vm->isSafeToRecurse();
+ }
+
+ const JSTextPosition& lastTokenEndPosition() const
+ {
+ return m_lastTokenEndPosition;
+ }
+
+ 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_parserArena;
+ std::unique_ptr<LexerType> m_lexer;
+
+ bool m_hasStackOverflow;
+ String m_errorMessage;
+ JSToken m_token;
+ bool m_allowsIn;
+ 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<SourceProviderCache> m_functionCache;
+ SourceElements* m_sourceElements;
+ bool m_parsingBuiltin;
+ ConstructorKind m_defaultConstructorKind;
+ ThisTDZMode m_thisTDZMode;
+ DeclarationStacks::VarStack m_varDeclarations;
+ DeclarationStacks::FunctionStack m_funcDeclarations;
+ IdentifierSet m_capturedVariables;
+ Vector<RefPtr<UniquedStringImpl>> m_closedVariables;
+ CodeFeatures m_features;
+ int m_numConstants;
+
+ struct DepthManager {
+ DepthManager(int* depth)
+ : m_originalDepth(*depth)
+ , m_depth(depth)
+ {
+ }
+
+ ~DepthManager()
+ {
+ *m_depth = m_originalDepth;
+ }
+
+ private:
+ int m_originalDepth;
+ int* m_depth;
+ };
+};
+
+
+template <typename LexerType>
+template <class ParsedNode>
+std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error)
+{
+ int errLine;
+ String errMsg;
+
+ if (ParsedNode::scopeIsFunction)
+ m_lexer->setIsReparsing();
+
+ m_sourceElements = 0;
+
+ errLine = -1;
+ errMsg = String();
+
+ JSTokenLocation startLocation(tokenLocation());
+ ASSERT(m_source->startColumn() > 0);
+ unsigned startColumn = m_source->startColumn() - 1;
+
+ String parseError = parseInner();
+
+ int lineNumber = m_lexer->lineNumber();
+ bool lexError = m_lexer->sawError();
+ String lexErrorMessage = lexError ? m_lexer->getErrorMessage() : String();
+ ASSERT(lexErrorMessage.isNull() != lexError);
+ m_lexer->clear();
+
+ if (!parseError.isNull() || lexError) {
+ errLine = lineNumber;
+ errMsg = !lexErrorMessage.isNull() ? lexErrorMessage : parseError;