+ Parser();
+ UString parseInner();
+
+ void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*,
+ ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures,
+ int, int, IdentifierSet&);
+
+ // 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());
+ }
+
+ 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());
+ }
+
+ ALWAYS_INLINE bool nextTokenIsColon()
+ {
+ return m_lexer->nextTokenIsColon();
+ }
+
+ ALWAYS_INLINE bool consume(JSTokenType expected, unsigned flags = 0)
+ {
+ bool result = m_token.m_type == expected;
+ if (result)
+ next(flags);
+ return result;
+ }
+
+ ALWAYS_INLINE UString getToken() {
+ SourceProvider* sourceProvider = m_source->provider();
+ return UString(sourceProvider->getRange(tokenStart(), tokenEnd()).impl());
+ }
+
+ ALWAYS_INLINE bool match(JSTokenType expected)
+ {
+ return m_token.m_type == expected;
+ }
+
+ ALWAYS_INLINE int tokenStart()
+ {
+ return m_token.m_info.startOffset;
+ }
+
+ ALWAYS_INLINE int tokenLine()
+ {
+ return m_token.m_info.line;
+ }
+
+ ALWAYS_INLINE int tokenEnd()
+ {
+ return m_token.m_info.endOffset;
+ }
+
+ const char* getTokenName(JSTokenType tok)
+ {
+ 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";
+ }
+
+ ALWAYS_INLINE void updateErrorMessageSpecialCase(JSTokenType expectedToken)
+ {
+ 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;
+ }
+ }
+
+ NEVER_INLINE void updateErrorMessage()
+ {
+ 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());
+ }
+
+ NEVER_INLINE void updateErrorMessage(JSTokenType expectedToken)
+ {
+ 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);
+ }
+ }
+
+ NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, UString name, const char* afterMsg)
+ {
+ m_error = true;
+ String prefix(beforeMsg);
+ String postfix(afterMsg);
+ prefix += " '";
+ prefix += name.impl();
+ prefix += "' ";
+ prefix += postfix;
+ m_errorMessage = prefix.impl();
+ }
+
+ NEVER_INLINE void updateErrorMessage(const char* msg)
+ {
+ m_error = true;
+ m_errorMessage = UString(msg);
+ }
+
+ void startLoop() { currentScope()->startLoop(); }
+ void endLoop() { currentScope()->endLoop(); }
+ void startSwitch() { currentScope()->startSwitch(); }
+ void endSwitch() { currentScope()->endSwitch(); }
+ void setStrictMode() { currentScope()->setStrictMode(); }
+ bool strictMode() { return currentScope()->strictMode(); }
+ bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
+ bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+ bool breakIsValid()
+ {
+ ScopeRef current = currentScope();
+ while (!current->breakIsValid()) {
+ if (!current.hasContainingScope())
+ return false;
+ current = current.containingScope();
+ }
+ return true;
+ }
+ bool continueIsValid()
+ {
+ ScopeRef current = currentScope();
+ while (!current->continueIsValid()) {
+ if (!current.hasContainingScope())
+ return false;
+ current = current.containingScope();
+ }
+ return true;
+ }
+ void pushLabel(const Identifier* label, bool isLoop) { currentScope()->pushLabel(label, isLoop); }
+ void popLabel() { currentScope()->popLabel(); }
+ ScopeLabelInfo* getLabel(const Identifier* label)
+ {
+ ScopeRef current = currentScope();
+ ScopeLabelInfo* result = 0;
+ while (!(result = current->getLabel(label))) {
+ if (!current.hasContainingScope())
+ return 0;
+ current = current.containingScope();
+ }
+ return result;
+ }
+
+ template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
+ template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseBreakStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseContinueStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseReturnStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseThrowStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseWithStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseSwitchStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeClauseList parseSwitchClauses(TreeBuilder&);
+ template <class TreeBuilder> TreeClause parseSwitchDefaultClause(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseTryStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseDebuggerStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeStatement parseBlockStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
+ template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd);
+ template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
+ template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
+ ALWAYS_INLINE int isBinaryOperator(JSTokenType);
+ bool allowAutomaticSemicolon();
+
+ bool autoSemiColon()
+ {
+ if (m_token.m_type == SEMICOLON) {
+ next();
+ return true;
+ }
+ return allowAutomaticSemicolon();
+ }
+
+ bool canRecurse()
+ {
+ return m_stack.recursionCheck();
+ }
+
+ int lastTokenEnd() const
+ {
+ return m_lastTokenEnd;
+ }
+
+ mutable const JSGlobalData* m_globalData;
+ const SourceCode* m_source;
+ ParserArena* m_arena;
+ OwnPtr<LexerType> m_lexer;
+
+ StackBounds m_stack;
+ bool m_error;
+ UString m_errorMessage;
+ JSToken m_token;
+ bool m_allowsIn;
+ int m_lastLine;
+ int m_lastTokenEnd;
+ int m_assignmentCount;
+ int m_nonLHSCount;
+ bool m_syntaxAlreadyValidated;
+ int m_statementDepth;
+ int m_nonTrivialExpressionCount;
+ const Identifier* m_lastIdentifier;
+ SourceProviderCache* m_functionCache;
+ SourceElements* m_sourceElements;
+ ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations;
+ ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+ IdentifierSet m_capturedVariables;
+ CodeFeatures m_features;
+ int m_numConstants;
+
+ struct DepthManager {
+ DepthManager(int* depth)
+ : m_originalDepth(*depth)
+ , m_depth(depth)
+ {
+ }
+
+ ~DepthManager()
+ {
+ *m_depth = m_originalDepth;