+++ /dev/null
-/*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-
-#include "JSParser.h"
-
-using namespace JSC;
-
-#include "CodeBlock.h"
-#include "JSGlobalData.h"
-#include "NodeInfo.h"
-#include "ASTBuilder.h"
-#include "SourceProvider.h"
-#include "SourceProviderCacheItem.h"
-#include <wtf/HashFunctions.h>
-#include <wtf/OwnPtr.h>
-#include <wtf/WTFThreadData.h>
-#include <utility>
-
-using namespace std;
-
-namespace JSC {
-#define fail() do { m_error = true; return 0; } while (0)
-#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
-#define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
-#define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0)
-#define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
-#define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0)
-#define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) fail(); } while (0)
-#define matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0)
-#define failIfStackOverflow() do { failIfFalse(canRecurse()); } while (0)
-
-// 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
-#define TreeSourceElements typename TreeBuilder::SourceElements
-#define TreeClause typename TreeBuilder::Clause
-#define TreeClauseList typename TreeBuilder::ClauseList
-#define TreeConstDeclList typename TreeBuilder::ConstDeclList
-#define TreeArguments typename TreeBuilder::Arguments
-#define TreeArgumentsList typename TreeBuilder::ArgumentsList
-#define TreeFunctionBody typename TreeBuilder::FunctionBody
-#define TreeProperty typename TreeBuilder::Property
-#define TreePropertyList typename TreeBuilder::PropertyList
-
-COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);
-
-class JSParser {
-public:
- JSParser(Lexer*, JSGlobalData*, FunctionParameters*, bool isStrictContext, bool isFunction, SourceProvider*);
- const char* parseProgram();
-private:
- struct AllowInOverride {
- AllowInOverride(JSParser* parser)
- : m_parser(parser)
- , m_oldAllowsIn(parser->m_allowsIn)
- {
- parser->m_allowsIn = true;
- }
- ~AllowInOverride()
- {
- m_parser->m_allowsIn = m_oldAllowsIn;
- }
- JSParser* m_parser;
- bool m_oldAllowsIn;
- };
-
- struct ScopeLabelInfo {
- ScopeLabelInfo(StringImpl* ident, bool isLoop)
- : m_ident(ident)
- , m_isLoop(isLoop)
- {
- }
- StringImpl* m_ident;
- bool m_isLoop;
- };
-
- ALWAYS_INLINE void next(unsigned lexType = 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, lexType, strictMode());
- }
-
- ALWAYS_INLINE void nextExpectIdentifier(unsigned lexType = 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, lexType, 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;
- failIfFalse(result);
- next(flags);
- return result;
- }
-
- 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;
- }
-
- 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;
- }
-
- enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
- template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
- template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive);
- 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);
- enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
- template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
- ALWAYS_INLINE int isBinaryOperator(JSTokenType token);
- 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;
- }
-
- ParserArena m_arena;
- Lexer* m_lexer;
- StackBounds m_stack;
- bool m_error;
- const char* m_errorMessage;
- JSGlobalData* m_globalData;
- 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;
-
- struct DepthManager {
- DepthManager(int* depth)
- : m_originalDepth(*depth)
- , m_depth(depth)
- {
- }
-
- ~DepthManager()
- {
- *m_depth = m_originalDepth;
- }
-
- private:
- int m_originalDepth;
- int* m_depth;
- };
-
- struct Scope {
- Scope(JSGlobalData* globalData, bool isFunction, bool strictMode)
- : m_globalData(globalData)
- , m_shadowsArguments(false)
- , m_usesEval(false)
- , m_needsFullActivation(false)
- , m_allowsNewDecls(true)
- , m_strictMode(strictMode)
- , m_isFunction(isFunction)
- , m_isFunctionBoundary(false)
- , m_isValidStrictMode(true)
- , m_loopDepth(0)
- , m_switchDepth(0)
- {
- }
-
- Scope(const Scope& rhs)
- : m_globalData(rhs.m_globalData)
- , m_shadowsArguments(rhs.m_shadowsArguments)
- , m_usesEval(rhs.m_usesEval)
- , m_needsFullActivation(rhs.m_needsFullActivation)
- , m_allowsNewDecls(rhs.m_allowsNewDecls)
- , m_strictMode(rhs.m_strictMode)
- , m_isFunction(rhs.m_isFunction)
- , m_isFunctionBoundary(rhs.m_isFunctionBoundary)
- , m_isValidStrictMode(rhs.m_isValidStrictMode)
- , m_loopDepth(rhs.m_loopDepth)
- , m_switchDepth(rhs.m_switchDepth)
- {
- if (rhs.m_labels) {
- m_labels = adoptPtr(new LabelStack);
-
- 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));
- }
- }
-
- void startSwitch() { m_switchDepth++; }
- void endSwitch() { m_switchDepth--; }
- void startLoop() { m_loopDepth++; }
- void endLoop() { ASSERT(m_loopDepth); m_loopDepth--; }
- bool inLoop() { return !!m_loopDepth; }
- bool breakIsValid() { return m_loopDepth || m_switchDepth; }
- bool continueIsValid() { return m_loopDepth; }
-
- void pushLabel(const Identifier* label, bool isLoop)
- {
- if (!m_labels)
- m_labels = adoptPtr(new LabelStack);
- m_labels->append(ScopeLabelInfo(label->impl(), isLoop));
- }
-
- void popLabel()
- {
- ASSERT(m_labels);
- ASSERT(m_labels->size());
- m_labels->removeLast();
- }
-
- ScopeLabelInfo* getLabel(const Identifier* label)
- {
- if (!m_labels)
- return 0;
- for (int i = m_labels->size(); i > 0; i--) {
- if (m_labels->at(i - 1).m_ident == label->impl())
- return &m_labels->at(i - 1);
- }
- return 0;
- }
-
- void setIsFunction()
- {
- m_isFunction = true;
- m_isFunctionBoundary = true;
- }
- bool isFunction() { return m_isFunction; }
- bool isFunctionBoundary() { return m_isFunctionBoundary; }
-
- bool declareVariable(const Identifier* ident)
- {
- bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
- m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
- m_declaredVariables.add(ident->ustring().impl());
- return isValidStrictMode;
- }
-
- void declareWrite(const Identifier* ident)
- {
- ASSERT(m_strictMode);
- m_writtenVariables.add(ident->impl());
- }
-
- void preventNewDecls() { m_allowsNewDecls = false; }
- bool allowsNewDecls() const { return m_allowsNewDecls; }
-
- bool declareParameter(const Identifier* ident)
- {
- bool isArguments = m_globalData->propertyNames->arguments == *ident;
- bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).second && m_globalData->propertyNames->eval != *ident && !isArguments;
- m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
- if (isArguments)
- m_shadowsArguments = true;
- return isValidStrictMode;
- }
-
- void useVariable(const Identifier* ident, bool isEval)
- {
- m_usesEval |= isEval;
- m_usedVariables.add(ident->ustring().impl());
- }
-
- void setNeedsFullActivation() { m_needsFullActivation = true; }
-
- bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
- {
- if (nestedScope->m_usesEval)
- m_usesEval = true;
- IdentifierSet::iterator end = nestedScope->m_usedVariables.end();
- for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) {
- if (nestedScope->m_declaredVariables.contains(*ptr))
- continue;
- m_usedVariables.add(*ptr);
- if (shouldTrackClosedVariables)
- m_closedVariables.add(*ptr);
- }
- if (nestedScope->m_writtenVariables.size()) {
- IdentifierSet::iterator end = nestedScope->m_writtenVariables.end();
- for (IdentifierSet::iterator ptr = nestedScope->m_writtenVariables.begin(); ptr != end; ++ptr) {
- if (nestedScope->m_declaredVariables.contains(*ptr))
- continue;
- m_writtenVariables.add(*ptr);
- }
- }
-
- 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)
- {
- if (m_needsFullActivation || m_usesEval) {
- capturedVariables.swap(m_declaredVariables);
- return;
- }
- for (IdentifierSet::iterator ptr = m_closedVariables.begin(); ptr != m_closedVariables.end(); ++ptr) {
- if (!m_declaredVariables.contains(*ptr))
- continue;
- capturedVariables.add(*ptr);
- }
- }
- void setStrictMode() { m_strictMode = true; }
- bool strictMode() const { return m_strictMode; }
- bool isValidStrictMode() const { return m_isValidStrictMode; }
- bool shadowsArguments() const { return m_shadowsArguments; }
-
- void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl> >& vector)
- {
- IdentifierSet::iterator end = capturedVariables.end();
- for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) {
- if (m_declaredVariables.contains(*it))
- continue;
- vector.append(*it);
- }
- vector.shrinkToFit();
- }
-
- void saveFunctionInfo(SourceProviderCacheItem* info)
- {
- ASSERT(m_isFunction);
- info->usesEval = m_usesEval;
- copyCapturedVariablesToVector(m_writtenVariables, info->writtenVariables);
- copyCapturedVariablesToVector(m_usedVariables, info->usedVariables);
- }
-
- void restoreFunctionInfo(const SourceProviderCacheItem* info)
- {
- ASSERT(m_isFunction);
- m_usesEval = info->usesEval;
- 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]);
- }
-
- private:
- JSGlobalData* m_globalData;
- bool m_shadowsArguments : 1;
- bool m_usesEval : 1;
- bool m_needsFullActivation : 1;
- bool m_allowsNewDecls : 1;
- bool m_strictMode : 1;
- bool m_isFunction : 1;
- bool m_isFunctionBoundary : 1;
- bool m_isValidStrictMode : 1;
- int m_loopDepth;
- int m_switchDepth;
-
- typedef Vector<ScopeLabelInfo, 2> LabelStack;
- OwnPtr<LabelStack> m_labels;
- IdentifierSet m_declaredVariables;
- IdentifierSet m_usedVariables;
- IdentifierSet m_closedVariables;
- IdentifierSet m_writtenVariables;
- };
-
- typedef Vector<Scope, 10> ScopeStack;
-
- struct ScopeRef {
- ScopeRef(ScopeStack* scopeStack, unsigned index)
- : m_scopeStack(scopeStack)
- , m_index(index)
- {
- }
- Scope* operator->() { return &m_scopeStack->at(m_index); }
- unsigned index() const { return m_index; }
-
- bool hasContainingScope()
- {
- return m_index && !m_scopeStack->at(m_index).isFunctionBoundary();
- }
-
- ScopeRef containingScope()
- {
- ASSERT(hasContainingScope());
- return ScopeRef(m_scopeStack, m_index - 1);
- }
-
- private:
- ScopeStack* m_scopeStack;
- unsigned m_index;
- };
-
- struct AutoPopScopeRef : public ScopeRef {
- AutoPopScopeRef(JSParser* parser, ScopeRef scope)
- : ScopeRef(scope)
- , m_parser(parser)
- {
- }
-
- ~AutoPopScopeRef()
- {
- if (m_parser)
- m_parser->popScope(*this, false);
- }
-
- void setPopped()
- {
- m_parser = 0;
- }
-
- private:
- JSParser* m_parser;
- };
-
- ScopeRef currentScope()
- {
- return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
- }
-
- ScopeRef pushScope()
- {
- bool isFunction = false;
- bool isStrict = false;
- if (!m_scopeStack.isEmpty()) {
- isStrict = m_scopeStack.last().strictMode();
- isFunction = m_scopeStack.last().isFunction();
- }
- m_scopeStack.append(Scope(m_globalData, isFunction, isStrict));
- return currentScope();
- }
-
- bool popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables)
- {
- ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
- ASSERT(m_scopeStack.size() > 1);
- bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
- m_scopeStack.removeLast();
- return result;
- }
-
- bool popScope(ScopeRef& scope, bool shouldTrackClosedVariables)
- {
- return popScopeInternal(scope, shouldTrackClosedVariables);
- }
-
- bool popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables)
- {
- scope.setPopped();
- return popScopeInternal(scope, shouldTrackClosedVariables);
- }
-
- bool declareVariable(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].declareVariable(ident);
- }
-
- void declareWrite(const Identifier* ident)
- {
- if (!m_syntaxAlreadyValidated)
- m_scopeStack.last().declareWrite(ident);
- }
-
- ScopeStack m_scopeStack;
-
- const SourceProviderCacheItem* findCachedFunctionInfo(int openBracePos)
- {
- return m_functionCache ? m_functionCache->get(openBracePos) : 0;
- }
-
- SourceProviderCache* m_functionCache;
-};
-
-const char* jsParse(JSGlobalData* globalData, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, const SourceCode* source)
-{
- JSParser parser(globalData->lexer, globalData, parameters, strictness == JSParseStrict, parserMode == JSParseFunctionCode, source->provider());
- return parser.parseProgram();
-}
-
-JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, bool inStrictContext, bool isFunction, SourceProvider* provider)
- : m_lexer(lexer)
- , m_stack(globalData->stack())
- , m_error(false)
- , m_errorMessage("Parse error")
- , m_globalData(globalData)
- , m_allowsIn(true)
- , m_lastLine(0)
- , m_lastTokenEnd(0)
- , m_assignmentCount(0)
- , m_nonLHSCount(0)
- , m_syntaxAlreadyValidated(provider->isValid())
- , m_statementDepth(0)
- , m_nonTrivialExpressionCount(0)
- , m_lastIdentifier(0)
- , m_functionCache(m_lexer->sourceProvider()->cache())
-{
- ScopeRef scope = pushScope();
- if (isFunction)
- scope->setIsFunction();
- if (inStrictContext)
- scope->setStrictMode();
- if (parameters) {
- for (unsigned i = 0; i < parameters->size(); i++)
- scope->declareParameter(¶meters->at(i));
- }
- next();
- m_lexer->setLastLineNumber(tokenLine());
-}
-
-const char* JSParser::parseProgram()
-{
- unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
- ASTBuilder context(m_globalData, m_lexer);
- if (m_lexer->isReparsing())
- m_statementDepth--;
- ScopeRef scope = currentScope();
- SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
- if (!sourceElements || !consume(EOFTOK))
- return m_errorMessage;
- IdentifierSet capturedVariables;
- scope->getCapturedVariables(capturedVariables);
- CodeFeatures features = context.features();
- if (scope->strictMode())
- features |= StrictModeFeature;
- if (scope->shadowsArguments())
- features |= ShadowsArgumentsFeature;
-
- unsigned functionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
- if (functionCacheSize != oldFunctionCacheSize)
- m_lexer->sourceProvider()->notifyCacheSizeChanged(functionCacheSize - oldFunctionCacheSize);
-
- m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features,
- m_lastLine, context.numConstants(), capturedVariables);
- return 0;
-}
-
-bool JSParser::allowAutomaticSemicolon()
-{
- return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
-}
-
-template <JSParser::SourceElementsMode mode, class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
-{
- TreeSourceElements sourceElements = context.createSourceElements();
- bool seenNonDirective = false;
- const Identifier* directive = 0;
- unsigned startOffset = m_token.m_info.startOffset;
- unsigned oldLastLineNumber = m_lexer->lastLineNumber();
- unsigned oldLineNumber = m_lexer->lineNumber();
- bool hasSetStrict = false;
- while (TreeStatement statement = parseStatement(context, directive)) {
- if (mode == CheckForStrictMode && !seenNonDirective) {
- if (directive) {
- if (!hasSetStrict && m_globalData->propertyNames->useStrictIdentifier == *directive) {
- setStrictMode();
- hasSetStrict = true;
- failIfFalse(isValidStrictMode());
- m_lexer->setOffset(startOffset);
- next();
- m_lexer->setLastLineNumber(oldLastLineNumber);
- m_lexer->setLineNumber(oldLineNumber);
- failIfTrue(m_error);
- continue;
- }
- } else
- seenNonDirective = true;
- }
- context.appendStatement(sourceElements, statement);
- }
-
- if (m_error)
- fail();
- return sourceElements;
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseVarDeclaration(TreeBuilder& context)
-{
- ASSERT(match(VAR));
- int start = tokenLine();
- int end = 0;
- int scratch;
- const Identifier* scratch1 = 0;
- TreeExpression scratch2 = 0;
- int scratch3 = 0;
- TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3);
- failIfTrue(m_error);
- failIfFalse(autoSemiColon());
-
- return context.createVarStatement(varDecls, start, end);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseConstDeclaration(TreeBuilder& context)
-{
- ASSERT(match(CONSTTOKEN));
- int start = tokenLine();
- int end = 0;
- TreeConstDeclList constDecls = parseConstDeclarationList(context);
- failIfTrue(m_error);
- failIfFalse(autoSemiColon());
-
- return context.createConstStatement(constDecls, start, end);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseDoWhileStatement(TreeBuilder& context)
-{
- ASSERT(match(DO));
- int startLine = tokenLine();
- next();
- const Identifier* unused = 0;
- startLoop();
- TreeStatement statement = parseStatement(context, unused);
- endLoop();
- failIfFalse(statement);
- int endLine = tokenLine();
- consumeOrFail(WHILE);
- consumeOrFail(OPENPAREN);
- TreeExpression expr = parseExpression(context);
- failIfFalse(expr);
- consumeOrFail(CLOSEPAREN);
- if (match(SEMICOLON))
- next(); // Always performs automatic semicolon insertion.
- return context.createDoWhileStatement(statement, expr, startLine, endLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseWhileStatement(TreeBuilder& context)
-{
- ASSERT(match(WHILE));
- int startLine = tokenLine();
- next();
- consumeOrFail(OPENPAREN);
- TreeExpression expr = parseExpression(context);
- failIfFalse(expr);
- int endLine = tokenLine();
- consumeOrFail(CLOSEPAREN);
- const Identifier* unused = 0;
- startLoop();
- TreeStatement statement = parseStatement(context, unused);
- endLoop();
- failIfFalse(statement);
- return context.createWhileStatement(expr, statement, startLine, endLine);
-}
-
-template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(TreeBuilder& context, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd)
-{
- TreeExpression varDecls = 0;
- do {
- declarations++;
- next();
- matchOrFail(IDENT);
-
- int varStart = tokenStart();
- identStart = varStart;
- const Identifier* name = m_token.m_data.ident;
- lastIdent = name;
- next();
- bool hasInitializer = match(EQUAL);
- failIfFalseIfStrict(declareVariable(name));
- context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
- if (hasInitializer) {
- int varDivot = tokenStart() + 1;
- initStart = tokenStart();
- next(TreeBuilder::DontBuildStrings); // consume '='
- int initialAssignments = m_assignmentCount;
- TreeExpression initializer = parseAssignmentExpression(context);
- initEnd = lastTokenEnd();
- lastInitializer = initializer;
- failIfFalse(initializer);
-
- TreeExpression node = context.createAssignResolve(*name, initializer, initialAssignments != m_assignmentCount, varStart, varDivot, lastTokenEnd());
- if (!varDecls)
- varDecls = node;
- else
- varDecls = context.combineCommaNodes(varDecls, node);
- }
- } while (match(COMMA));
- return varDecls;
-}
-
-template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationList(TreeBuilder& context)
-{
- failIfTrue(strictMode());
- TreeConstDeclList constDecls = 0;
- TreeConstDeclList tail = 0;
- do {
- next();
- matchOrFail(IDENT);
- const Identifier* name = m_token.m_data.ident;
- next();
- bool hasInitializer = match(EQUAL);
- declareVariable(name);
- context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
- TreeExpression initializer = 0;
- if (hasInitializer) {
- next(TreeBuilder::DontBuildStrings); // consume '='
- initializer = parseAssignmentExpression(context);
- }
- tail = context.appendConstDecl(tail, name, initializer);
- if (!constDecls)
- constDecls = tail;
- } while (match(COMMA));
- return constDecls;
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuilder& context)
-{
- ASSERT(match(FOR));
- int startLine = tokenLine();
- next();
- consumeOrFail(OPENPAREN);
- int nonLHSCount = m_nonLHSCount;
- int declarations = 0;
- int declsStart = 0;
- int declsEnd = 0;
- TreeExpression decls = 0;
- bool hasDeclaration = false;
- if (match(VAR)) {
- /*
- for (var IDENT in expression) statement
- for (var IDENT = expression in expression) statement
- for (var varDeclarationList; expressionOpt; expressionOpt)
- */
- hasDeclaration = true;
- const Identifier* forInTarget = 0;
- TreeExpression forInInitializer = 0;
- m_allowsIn = false;
- int initStart = 0;
- int initEnd = 0;
- decls = parseVarDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd);
- m_allowsIn = true;
- if (m_error)
- fail();
-
- // Remainder of a standard for loop is handled identically
- if (match(SEMICOLON))
- goto standardForLoop;
-
- failIfFalse(declarations == 1);
-
- // Handle for-in with var declaration
- int inLocation = tokenStart();
- if (!consume(INTOKEN))
- fail();
-
- TreeExpression expr = parseExpression(context);
- failIfFalse(expr);
- int exprEnd = lastTokenEnd();
-
- int endLine = tokenLine();
- consumeOrFail(CLOSEPAREN);
-
- const Identifier* unused = 0;
- startLoop();
- TreeStatement statement = parseStatement(context, unused);
- endLoop();
- failIfFalse(statement);
-
- return context.createForInLoop(forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine);
- }
-
- if (!match(SEMICOLON)) {
- m_allowsIn = false;
- declsStart = tokenStart();
- decls = parseExpression(context);
- declsEnd = lastTokenEnd();
- m_allowsIn = true;
- failIfFalse(decls);
- }
-
- if (match(SEMICOLON)) {
- standardForLoop:
- // Standard for loop
- next();
- TreeExpression condition = 0;
-
- if (!match(SEMICOLON)) {
- condition = parseExpression(context);
- failIfFalse(condition);
- }
- consumeOrFail(SEMICOLON);
-
- TreeExpression increment = 0;
- if (!match(CLOSEPAREN)) {
- increment = parseExpression(context);
- failIfFalse(increment);
- }
- int endLine = tokenLine();
- consumeOrFail(CLOSEPAREN);
- const Identifier* unused = 0;
- startLoop();
- TreeStatement statement = parseStatement(context, unused);
- endLoop();
- failIfFalse(statement);
- return context.createForLoop(decls, condition, increment, statement, hasDeclaration, startLine, endLine);
- }
-
- // For-in loop
- failIfFalse(nonLHSCount == m_nonLHSCount);
- consumeOrFail(INTOKEN);
- TreeExpression expr = parseExpression(context);
- failIfFalse(expr);
- int exprEnd = lastTokenEnd();
- int endLine = tokenLine();
- consumeOrFail(CLOSEPAREN);
- const Identifier* unused = 0;
- startLoop();
- TreeStatement statement = parseStatement(context, unused);
- endLoop();
- failIfFalse(statement);
-
- return context.createForInLoop(decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseBreakStatement(TreeBuilder& context)
-{
- ASSERT(match(BREAK));
- int startCol = tokenStart();
- int endCol = tokenEnd();
- int startLine = tokenLine();
- int endLine = tokenLine();
- next();
-
- if (autoSemiColon()) {
- failIfFalse(breakIsValid());
- return context.createBreakStatement(startCol, endCol, startLine, endLine);
- }
- matchOrFail(IDENT);
- const Identifier* ident = m_token.m_data.ident;
- failIfFalse(getLabel(ident));
- endCol = tokenEnd();
- endLine = tokenLine();
- next();
- failIfFalse(autoSemiColon());
- return context.createBreakStatement(ident, startCol, endCol, startLine, endLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(TreeBuilder& context)
-{
- ASSERT(match(CONTINUE));
- int startCol = tokenStart();
- int endCol = tokenEnd();
- int startLine = tokenLine();
- int endLine = tokenLine();
- next();
-
- if (autoSemiColon()) {
- failIfFalse(continueIsValid());
- return context.createContinueStatement(startCol, endCol, startLine, endLine);
- }
- matchOrFail(IDENT);
- const Identifier* ident = m_token.m_data.ident;
- ScopeLabelInfo* label = getLabel(ident);
- failIfFalse(label);
- failIfFalse(label->m_isLoop);
- endCol = tokenEnd();
- endLine = tokenLine();
- next();
- failIfFalse(autoSemiColon());
- return context.createContinueStatement(ident, startCol, endCol, startLine, endLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseReturnStatement(TreeBuilder& context)
-{
- ASSERT(match(RETURN));
- failIfFalse(currentScope()->isFunction());
- int startLine = tokenLine();
- int endLine = startLine;
- int start = tokenStart();
- int end = tokenEnd();
- next();
- // We do the auto semicolon check before attempting to parse an expression
- // as we need to ensure the a line break after the return correctly terminates
- // the statement
- if (match(SEMICOLON))
- endLine = tokenLine();
- if (autoSemiColon())
- return context.createReturnStatement(0, start, end, startLine, endLine);
- TreeExpression expr = parseExpression(context);
- failIfFalse(expr);
- end = lastTokenEnd();
- if (match(SEMICOLON))
- endLine = tokenLine();
- failIfFalse(autoSemiColon());
- return context.createReturnStatement(expr, start, end, startLine, endLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseThrowStatement(TreeBuilder& context)
-{
- ASSERT(match(THROW));
- int eStart = tokenStart();
- int startLine = tokenLine();
- next();
-
- failIfTrue(autoSemiColon());
-
- TreeExpression expr = parseExpression(context);
- failIfFalse(expr);
- int eEnd = lastTokenEnd();
- int endLine = tokenLine();
- failIfFalse(autoSemiColon());
-
- return context.createThrowStatement(expr, eStart, eEnd, startLine, endLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuilder& context)
-{
- ASSERT(match(WITH));
- failIfTrue(strictMode());
- currentScope()->setNeedsFullActivation();
- int startLine = tokenLine();
- next();
- consumeOrFail(OPENPAREN);
- int start = tokenStart();
- TreeExpression expr = parseExpression(context);
- failIfFalse(expr);
- int end = lastTokenEnd();
-
- int endLine = tokenLine();
- consumeOrFail(CLOSEPAREN);
- const Identifier* unused = 0;
- TreeStatement statement = parseStatement(context, unused);
- failIfFalse(statement);
-
- return context.createWithStatement(expr, statement, start, end, startLine, endLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBuilder& context)
-{
- ASSERT(match(SWITCH));
- int startLine = tokenLine();
- next();
- consumeOrFail(OPENPAREN);
- TreeExpression expr = parseExpression(context);
- failIfFalse(expr);
- int endLine = tokenLine();
- consumeOrFail(CLOSEPAREN);
- consumeOrFail(OPENBRACE);
- startSwitch();
- TreeClauseList firstClauses = parseSwitchClauses(context);
- failIfTrue(m_error);
-
- TreeClause defaultClause = parseSwitchDefaultClause(context);
- failIfTrue(m_error);
-
- TreeClauseList secondClauses = parseSwitchClauses(context);
- failIfTrue(m_error);
- endSwitch();
- consumeOrFail(CLOSEBRACE);
-
- return context.createSwitchStatement(expr, firstClauses, defaultClause, secondClauses, startLine, endLine);
-
-}
-
-template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBuilder& context)
-{
- if (!match(CASE))
- return 0;
- next();
- TreeExpression condition = parseExpression(context);
- failIfFalse(condition);
- consumeOrFail(COLON);
- TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
- failIfFalse(statements);
- TreeClause clause = context.createClause(condition, statements);
- TreeClauseList clauseList = context.createClauseList(clause);
- TreeClauseList tail = clauseList;
-
- while (match(CASE)) {
- next();
- TreeExpression condition = parseExpression(context);
- failIfFalse(condition);
- consumeOrFail(COLON);
- TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
- failIfFalse(statements);
- clause = context.createClause(condition, statements);
- tail = context.createClauseList(tail, clause);
- }
- return clauseList;
-}
-
-template <class TreeBuilder> TreeClause JSParser::parseSwitchDefaultClause(TreeBuilder& context)
-{
- if (!match(DEFAULT))
- return 0;
- next();
- consumeOrFail(COLON);
- TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
- failIfFalse(statements);
- return context.createClause(0, statements);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuilder& context)
-{
- ASSERT(match(TRY));
- TreeStatement tryBlock = 0;
- const Identifier* ident = &m_globalData->propertyNames->nullIdentifier;
- bool catchHasEval = false;
- TreeStatement catchBlock = 0;
- TreeStatement finallyBlock = 0;
- int firstLine = tokenLine();
- next();
- matchOrFail(OPENBRACE);
-
- tryBlock = parseBlockStatement(context);
- failIfFalse(tryBlock);
- int lastLine = m_lastLine;
-
- if (match(CATCH)) {
- currentScope()->setNeedsFullActivation();
- next();
- consumeOrFail(OPENPAREN);
- matchOrFail(IDENT);
- ident = m_token.m_data.ident;
- next();
- AutoPopScopeRef catchScope(this, pushScope());
- failIfFalseIfStrict(catchScope->declareVariable(ident));
- catchScope->preventNewDecls();
- consumeOrFail(CLOSEPAREN);
- matchOrFail(OPENBRACE);
- int initialEvalCount = context.evalCount();
- catchBlock = parseBlockStatement(context);
- failIfFalse(catchBlock);
- catchHasEval = initialEvalCount != context.evalCount();
- failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo));
- }
-
- if (match(FINALLY)) {
- next();
- matchOrFail(OPENBRACE);
- finallyBlock = parseBlockStatement(context);
- failIfFalse(finallyBlock);
- }
- failIfFalse(catchBlock || finallyBlock);
- return context.createTryStatement(tryBlock, ident, catchHasEval, catchBlock, finallyBlock, firstLine, lastLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseDebuggerStatement(TreeBuilder& context)
-{
- ASSERT(match(DEBUGGER));
- int startLine = tokenLine();
- int endLine = startLine;
- next();
- if (match(SEMICOLON))
- startLine = tokenLine();
- failIfFalse(autoSemiColon());
- return context.createDebugger(startLine, endLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseBlockStatement(TreeBuilder& context)
-{
- ASSERT(match(OPENBRACE));
- int start = tokenLine();
- next();
- if (match(CLOSEBRACE)) {
- next();
- return context.createBlockStatement(0, start, m_lastLine);
- }
- TreeSourceElements subtree = parseSourceElements<DontCheckForStrictMode>(context);
- failIfFalse(subtree);
- matchOrFail(CLOSEBRACE);
- next();
- return context.createBlockStatement(subtree, start, m_lastLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context, const Identifier*& directive)
-{
- DepthManager statementDepth(&m_statementDepth);
- m_statementDepth++;
- directive = 0;
- int nonTrivialExpressionCount = 0;
- failIfStackOverflow();
- switch (m_token.m_type) {
- case OPENBRACE:
- return parseBlockStatement(context);
- case VAR:
- return parseVarDeclaration(context);
- case CONSTTOKEN:
- return parseConstDeclaration(context);
- case FUNCTION:
- failIfFalseIfStrict(m_statementDepth == 1);
- return parseFunctionDeclaration(context);
- case SEMICOLON:
- next();
- return context.createEmptyStatement();
- case IF:
- return parseIfStatement(context);
- case DO:
- return parseDoWhileStatement(context);
- case WHILE:
- return parseWhileStatement(context);
- case FOR:
- return parseForStatement(context);
- case CONTINUE:
- return parseContinueStatement(context);
- case BREAK:
- return parseBreakStatement(context);
- case RETURN:
- return parseReturnStatement(context);
- case WITH:
- return parseWithStatement(context);
- case SWITCH:
- return parseSwitchStatement(context);
- case THROW:
- return parseThrowStatement(context);
- case TRY:
- return parseTryStatement(context);
- case DEBUGGER:
- return parseDebuggerStatement(context);
- case EOFTOK:
- case CASE:
- case CLOSEBRACE:
- case DEFAULT:
- // These tokens imply the end of a set of source elements
- return 0;
- case IDENT:
- return parseExpressionOrLabelStatement(context);
- case STRING:
- directive = m_token.m_data.ident;
- nonTrivialExpressionCount = m_nonTrivialExpressionCount;
- default:
- TreeStatement exprStatement = parseExpressionStatement(context);
- if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount)
- directive = 0;
- return exprStatement;
- }
-}
-
-template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParameters(TreeBuilder& context)
-{
- matchOrFail(IDENT);
- failIfFalseIfStrict(declareParameter(m_token.m_data.ident));
- TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
- TreeFormalParameterList tail = list;
- next();
- while (match(COMMA)) {
- next();
- matchOrFail(IDENT);
- const Identifier* ident = m_token.m_data.ident;
- failIfFalseIfStrict(declareParameter(ident));
- next();
- tail = context.createFormalParameterList(tail, *ident);
- }
- return list;
-}
-
-template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBuilder& context)
-{
- if (match(CLOSEBRACE))
- return context.createFunctionBody(strictMode());
- DepthManager statementDepth(&m_statementDepth);
- m_statementDepth = 0;
- typename TreeBuilder::FunctionBodyBuilder bodyBuilder(m_globalData, m_lexer);
- failIfFalse(parseSourceElements<CheckForStrictMode>(bodyBuilder));
- return context.createFunctionBody(strictMode());
-}
-
-template <JSParser::FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
-{
- AutoPopScopeRef functionScope(this, pushScope());
- functionScope->setIsFunction();
- if (match(IDENT)) {
- name = m_token.m_data.ident;
- failIfTrue(*name == m_globalData->propertyNames->underscoreProto);
- next();
- if (!nameIsInContainingScope)
- failIfFalseIfStrict(functionScope->declareVariable(name));
- } else if (requirements == FunctionNeedsName)
- return false;
- consumeOrFail(OPENPAREN);
- if (!match(CLOSEPAREN)) {
- parameters = parseFormalParameters(context);
- failIfFalse(parameters);
- }
- consumeOrFail(CLOSEPAREN);
- matchOrFail(OPENBRACE);
-
- openBracePos = m_token.m_data.intValue;
- bodyStartLine = tokenLine();
-
- if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(openBracePos) : 0) {
- // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
- body = context.createFunctionBody(strictMode());
-
- functionScope->restoreFunctionInfo(cachedInfo);
- failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
-
- closeBracePos = cachedInfo->closeBracePos;
- m_token = cachedInfo->closeBraceToken();
- m_lexer->setOffset(m_token.m_info.endOffset);
- m_lexer->setLineNumber(m_token.m_info.line);
-
- next();
- return true;
- }
-
- next();
-
- body = parseFunctionBody(context);
- failIfFalse(body);
- if (functionScope->strictMode() && name) {
- failIfTrue(m_globalData->propertyNames->arguments == *name);
- failIfTrue(m_globalData->propertyNames->eval == *name);
- }
- closeBracePos = m_token.m_data.intValue;
-
- // Cache the tokenizer state and the function scope the first time the function is parsed.
- // Any future reparsing can then skip the function.
- static const int minimumFunctionLengthToCache = 64;
- OwnPtr<SourceProviderCacheItem> newInfo;
- int functionLength = closeBracePos - openBracePos;
- if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) {
- newInfo = adoptPtr(new SourceProviderCacheItem(m_token.m_info.line, closeBracePos));
- functionScope->saveFunctionInfo(newInfo.get());
- }
-
- failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
- matchOrFail(CLOSEBRACE);
-
- if (newInfo) {
- unsigned approximateByteSize = newInfo->approximateByteSize();
- m_functionCache->add(openBracePos, newInfo.release(), approximateByteSize);
- }
-
- next();
- return true;
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(TreeBuilder& context)
-{
- ASSERT(match(FUNCTION));
- next();
- const Identifier* name = 0;
- TreeFormalParameterList parameters = 0;
- TreeFunctionBody body = 0;
- int openBracePos = 0;
- int closeBracePos = 0;
- int bodyStartLine = 0;
- failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
- failIfFalse(name);
- failIfFalseIfStrict(declareVariable(name));
- return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
-}
-
-struct LabelInfo {
- LabelInfo(const Identifier* ident, int start, int end)
- : m_ident(ident)
- , m_start(start)
- , m_end(end)
- {
- }
-
- const Identifier* m_ident;
- int m_start;
- int m_end;
-};
-
-template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelStatement(TreeBuilder& context)
-{
-
- /* Expression and Label statements are ambiguous at LL(1), so we have a
- * special case that looks for a colon as the next character in the input.
- */
- Vector<LabelInfo> labels;
-
- do {
- int start = tokenStart();
- int startLine = tokenLine();
- if (!nextTokenIsColon()) {
- // If we hit this path we're making a expression statement, which
- // by definition can't make use of continue/break so we can just
- // ignore any labels we might have accumulated.
- TreeExpression expression = parseExpression(context);
- failIfFalse(expression);
- failIfFalse(autoSemiColon());
- return context.createExprStatement(expression, startLine, m_lastLine);
- }
- const Identifier* ident = m_token.m_data.ident;
- int end = tokenEnd();
- next();
- consumeOrFail(COLON);
- if (!m_syntaxAlreadyValidated) {
- // This is O(N^2) over the current list of consecutive labels, but I
- // have never seen more than one label in a row in the real world.
- for (size_t i = 0; i < labels.size(); i++)
- failIfTrue(ident->impl() == labels[i].m_ident->impl());
- failIfTrue(getLabel(ident));
- labels.append(LabelInfo(ident, start, end));
- }
- } while (match(IDENT));
- bool isLoop = false;
- switch (m_token.m_type) {
- case FOR:
- case WHILE:
- case DO:
- isLoop = true;
- break;
-
- default:
- break;
- }
- const Identifier* unused = 0;
- if (!m_syntaxAlreadyValidated) {
- for (size_t i = 0; i < labels.size(); i++)
- pushLabel(labels[i].m_ident, isLoop);
- }
- TreeStatement statement = parseStatement(context, unused);
- if (!m_syntaxAlreadyValidated) {
- for (size_t i = 0; i < labels.size(); i++)
- popLabel();
- }
- failIfFalse(statement);
- for (size_t i = 0; i < labels.size(); i++) {
- const LabelInfo& info = labels[labels.size() - i - 1];
- statement = context.createLabelStatement(info.m_ident, statement, info.m_start, info.m_end);
- }
- return statement;
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseExpressionStatement(TreeBuilder& context)
-{
- int startLine = tokenLine();
- TreeExpression expression = parseExpression(context);
- failIfFalse(expression);
- failIfFalse(autoSemiColon());
- return context.createExprStatement(expression, startLine, m_lastLine);
-}
-
-template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilder& context)
-{
- ASSERT(match(IF));
-
- int start = tokenLine();
- next();
-
- consumeOrFail(OPENPAREN);
-
- TreeExpression condition = parseExpression(context);
- failIfFalse(condition);
- int end = tokenLine();
- consumeOrFail(CLOSEPAREN);
-
- const Identifier* unused = 0;
- TreeStatement trueBlock = parseStatement(context, unused);
- failIfFalse(trueBlock);
-
- if (!match(ELSE))
- return context.createIfStatement(condition, trueBlock, start, end);
-
- Vector<TreeExpression> exprStack;
- Vector<pair<int, int> > posStack;
- Vector<TreeStatement> statementStack;
- bool trailingElse = false;
- do {
- next();
- if (!match(IF)) {
- const Identifier* unused = 0;
- TreeStatement block = parseStatement(context, unused);
- failIfFalse(block);
- statementStack.append(block);
- trailingElse = true;
- break;
- }
- int innerStart = tokenLine();
- next();
-
- consumeOrFail(OPENPAREN);
-
- TreeExpression innerCondition = parseExpression(context);
- failIfFalse(innerCondition);
- int innerEnd = tokenLine();
- consumeOrFail(CLOSEPAREN);
- const Identifier* unused = 0;
- TreeStatement innerTrueBlock = parseStatement(context, unused);
- failIfFalse(innerTrueBlock);
- exprStack.append(innerCondition);
- posStack.append(make_pair(innerStart, innerEnd));
- statementStack.append(innerTrueBlock);
- } while (match(ELSE));
-
- if (!trailingElse) {
- TreeExpression condition = exprStack.last();
- exprStack.removeLast();
- TreeStatement trueBlock = statementStack.last();
- statementStack.removeLast();
- pair<int, int> pos = posStack.last();
- posStack.removeLast();
- statementStack.append(context.createIfStatement(condition, trueBlock, pos.first, pos.second));
- }
-
- while (!exprStack.isEmpty()) {
- TreeExpression condition = exprStack.last();
- exprStack.removeLast();
- TreeStatement falseBlock = statementStack.last();
- statementStack.removeLast();
- TreeStatement trueBlock = statementStack.last();
- statementStack.removeLast();
- pair<int, int> pos = posStack.last();
- posStack.removeLast();
- statementStack.append(context.createIfStatement(condition, trueBlock, falseBlock, pos.first, pos.second));
- }
-
- return context.createIfStatement(condition, trueBlock, statementStack.last(), start, end);
-}
-
-template <class TreeBuilder> TreeExpression JSParser::parseExpression(TreeBuilder& context)
-{
- failIfStackOverflow();
- TreeExpression node = parseAssignmentExpression(context);
- failIfFalse(node);
- if (!match(COMMA))
- return node;
- next();
- m_nonTrivialExpressionCount++;
- m_nonLHSCount++;
- TreeExpression right = parseAssignmentExpression(context);
- failIfFalse(right);
- typename TreeBuilder::Comma commaNode = context.createCommaExpr(node, right);
- while (match(COMMA)) {
- next(TreeBuilder::DontBuildStrings);
- right = parseAssignmentExpression(context);
- failIfFalse(right);
- context.appendToComma(commaNode, right);
- }
- return commaNode;
-}
-
-
-template <typename TreeBuilder> TreeExpression JSParser::parseAssignmentExpression(TreeBuilder& context)
-{
- failIfStackOverflow();
- int start = tokenStart();
- int initialAssignmentCount = m_assignmentCount;
- int initialNonLHSCount = m_nonLHSCount;
- TreeExpression lhs = parseConditionalExpression(context);
- failIfFalse(lhs);
- if (initialNonLHSCount != m_nonLHSCount)
- return lhs;
-
- int assignmentStack = 0;
- Operator op;
- bool hadAssignment = false;
- while (true) {
- switch (m_token.m_type) {
- case EQUAL: op = OpEqual; break;
- case PLUSEQUAL: op = OpPlusEq; break;
- case MINUSEQUAL: op = OpMinusEq; break;
- case MULTEQUAL: op = OpMultEq; break;
- case DIVEQUAL: op = OpDivEq; break;
- case LSHIFTEQUAL: op = OpLShift; break;
- case RSHIFTEQUAL: op = OpRShift; break;
- case URSHIFTEQUAL: op = OpURShift; break;
- case ANDEQUAL: op = OpAndEq; break;
- case XOREQUAL: op = OpXOrEq; break;
- case OREQUAL: op = OpOrEq; break;
- case MODEQUAL: op = OpModEq; break;
- default:
- goto end;
- }
- m_nonTrivialExpressionCount++;
- hadAssignment = true;
- context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op);
- start = tokenStart();
- m_assignmentCount++;
- next(TreeBuilder::DontBuildStrings);
- if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) {
- failIfTrueIfStrict(m_globalData->propertyNames->eval == *m_lastIdentifier);
- failIfTrueIfStrict(m_globalData->propertyNames->arguments == *m_lastIdentifier);
- declareWrite(m_lastIdentifier);
- m_lastIdentifier = 0;
- }
- lhs = parseConditionalExpression(context);
- failIfFalse(lhs);
- if (initialNonLHSCount != m_nonLHSCount)
- break;
- }
-end:
- if (hadAssignment)
- m_nonLHSCount++;
-
- if (!TreeBuilder::CreatesAST)
- return lhs;
-
- while (assignmentStack)
- lhs = context.createAssignment(assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEnd());
-
- return lhs;
-}
-
-template <class TreeBuilder> TreeExpression JSParser::parseConditionalExpression(TreeBuilder& context)
-{
- TreeExpression cond = parseBinaryExpression(context);
- failIfFalse(cond);
- if (!match(QUESTION))
- return cond;
- m_nonTrivialExpressionCount++;
- m_nonLHSCount++;
- next(TreeBuilder::DontBuildStrings);
- TreeExpression lhs = parseAssignmentExpression(context);
- consumeOrFailWithFlags(COLON, TreeBuilder::DontBuildStrings);
-
- TreeExpression rhs = parseAssignmentExpression(context);
- failIfFalse(rhs);
- return context.createConditionalExpr(cond, lhs, rhs);
-}
-
-ALWAYS_INLINE static bool isUnaryOp(JSTokenType token)
-{
- return token & UnaryOpTokenFlag;
-}
-
-int JSParser::isBinaryOperator(JSTokenType token)
-{
- if (m_allowsIn)
- return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift);
- return token & BinaryOpTokenPrecedenceMask;
-}
-
-template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(TreeBuilder& context)
-{
-
- int operandStackDepth = 0;
- int operatorStackDepth = 0;
- typename TreeBuilder::BinaryExprContext binaryExprContext(context);
- while (true) {
- int exprStart = tokenStart();
- int initialAssignments = m_assignmentCount;
- TreeExpression current = parseUnaryExpression(context);
- failIfFalse(current);
-
- context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEnd(), lastTokenEnd(), initialAssignments != m_assignmentCount);
- int precedence = isBinaryOperator(m_token.m_type);
- if (!precedence)
- break;
- m_nonTrivialExpressionCount++;
- m_nonLHSCount++;
- int operatorToken = m_token.m_type;
- next(TreeBuilder::DontBuildStrings);
-
- while (operatorStackDepth && context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) {
- ASSERT(operandStackDepth > 1);
-
- typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
- typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
- context.shrinkOperandStackBy(operandStackDepth, 2);
- context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs);
- context.operatorStackPop(operatorStackDepth);
- }
- context.operatorStackAppend(operatorStackDepth, operatorToken, precedence);
- }
- while (operatorStackDepth) {
- ASSERT(operandStackDepth > 1);
-
- typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
- typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
- context.shrinkOperandStackBy(operandStackDepth, 2);
- context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs);
- context.operatorStackPop(operatorStackDepth);
- }
- return context.popOperandStack(operandStackDepth);
-}
-
-
-template <bool complete, class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& context)
-{
- bool wasIdent = false;
- switch (m_token.m_type) {
- namedProperty:
- case IDENT:
- wasIdent = true;
- case STRING: {
- const Identifier* ident = m_token.m_data.ident;
- if (complete || (wasIdent && (*ident == m_globalData->propertyNames->get || *ident == m_globalData->propertyNames->set)))
- nextExpectIdentifier(Lexer::IgnoreReservedWords);
- else
- nextExpectIdentifier(Lexer::IgnoreReservedWords | TreeBuilder::DontBuildKeywords);
-
- if (match(COLON)) {
- next();
- TreeExpression node = parseAssignmentExpression(context);
- failIfFalse(node);
- return context.template createProperty<complete>(ident, node, PropertyNode::Constant);
- }
- failIfFalse(wasIdent);
- matchOrFail(IDENT);
- const Identifier* accessorName = 0;
- TreeFormalParameterList parameters = 0;
- TreeFunctionBody body = 0;
- int openBracePos = 0;
- int closeBracePos = 0;
- int bodyStartLine = 0;
- PropertyNode::Type type;
- if (*ident == m_globalData->propertyNames->get)
- type = PropertyNode::Getter;
- else if (*ident == m_globalData->propertyNames->set)
- type = PropertyNode::Setter;
- else
- fail();
- failIfFalse((parseFunctionInfo<FunctionNeedsName, false>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
- return context.template createGetterOrSetterProperty<complete>(type, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
- }
- case NUMBER: {
- double propertyName = m_token.m_data.doubleValue;
- next();
- consumeOrFail(COLON);
- TreeExpression node = parseAssignmentExpression(context);
- failIfFalse(node);
- return context.template createProperty<complete>(m_globalData, propertyName, node, PropertyNode::Constant);
- }
- default:
- failIfFalse(m_token.m_type & KeywordTokenFlag);
- goto namedProperty;
- }
-}
-
-template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBuilder& context)
-{
- int startOffset = m_token.m_data.intValue;
- consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings);
-
- if (match(CLOSEBRACE)) {
- next();
- return context.createObjectLiteral();
- }
-
- TreeProperty property = parseProperty<false>(context);
- failIfFalse(property);
- if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
- m_lexer->setOffset(startOffset);
- next();
- return parseStrictObjectLiteral(context);
- }
- TreePropertyList propertyList = context.createPropertyList(property);
- TreePropertyList tail = propertyList;
- while (match(COMMA)) {
- next(TreeBuilder::DontBuildStrings);
- // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
- if (match(CLOSEBRACE))
- break;
- property = parseProperty<false>(context);
- failIfFalse(property);
- if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
- m_lexer->setOffset(startOffset);
- next();
- return parseStrictObjectLiteral(context);
- }
- tail = context.createPropertyList(property, tail);
- }
-
- consumeOrFail(CLOSEBRACE);
-
- return context.createObjectLiteral(propertyList);
-}
-
-template <class TreeBuilder> TreeExpression JSParser::parseStrictObjectLiteral(TreeBuilder& context)
-{
- consumeOrFail(OPENBRACE);
-
- if (match(CLOSEBRACE)) {
- next();
- return context.createObjectLiteral();
- }
-
- TreeProperty property = parseProperty<true>(context);
- failIfFalse(property);
-
- typedef HashMap<RefPtr<StringImpl>, unsigned, IdentifierRepHash> ObjectValidationMap;
- ObjectValidationMap objectValidator;
- // Add the first property
- if (!m_syntaxAlreadyValidated)
- objectValidator.add(context.getName(property).impl(), context.getType(property));
-
- TreePropertyList propertyList = context.createPropertyList(property);
- TreePropertyList tail = propertyList;
- while (match(COMMA)) {
- next();
- // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
- if (match(CLOSEBRACE))
- break;
- property = parseProperty<true>(context);
- failIfFalse(property);
- if (!m_syntaxAlreadyValidated) {
- std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).impl(), context.getType(property));
- if (!propertyEntryIter.second) {
- failIfTrue(propertyEntryIter.first->second == PropertyNode::Constant);
- failIfTrue(context.getType(property) == PropertyNode::Constant);
- failIfTrue(context.getType(property) & propertyEntryIter.first->second);
- propertyEntryIter.first->second |= context.getType(property);
- }
- }
- tail = context.createPropertyList(property, tail);
- }
-
- consumeOrFail(CLOSEBRACE);
-
- return context.createObjectLiteral(propertyList);
-}
-
-template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context)
-{
- consumeOrFailWithFlags(OPENBRACKET, TreeBuilder::DontBuildStrings);
-
- int elisions = 0;
- while (match(COMMA)) {
- next(TreeBuilder::DontBuildStrings);
- elisions++;
- }
- if (match(CLOSEBRACKET)) {
- next(TreeBuilder::DontBuildStrings);
- return context.createArray(elisions);
- }
-
- TreeExpression elem = parseAssignmentExpression(context);
- failIfFalse(elem);
- typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem);
- typename TreeBuilder::ElementList tail = elementList;
- elisions = 0;
- while (match(COMMA)) {
- next(TreeBuilder::DontBuildStrings);
- elisions = 0;
-
- while (match(COMMA)) {
- next();
- elisions++;
- }
-
- if (match(CLOSEBRACKET)) {
- next(TreeBuilder::DontBuildStrings);
- return context.createArray(elisions, elementList);
- }
- TreeExpression elem = parseAssignmentExpression(context);
- failIfFalse(elem);
- tail = context.createElementList(tail, elisions, elem);
- }
-
- consumeOrFail(CLOSEBRACKET);
-
- return context.createArray(elementList);
-}
-
-template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(TreeBuilder& context)
-{
- switch (m_token.m_type) {
- case OPENBRACE:
- if (strictMode())
- return parseStrictObjectLiteral(context);
- return parseObjectLiteral(context);
- case OPENBRACKET:
- return parseArrayLiteral(context);
- case OPENPAREN: {
- next();
- int oldNonLHSCount = m_nonLHSCount;
- TreeExpression result = parseExpression(context);
- m_nonLHSCount = oldNonLHSCount;
- consumeOrFail(CLOSEPAREN);
-
- return result;
- }
- case THISTOKEN: {
- next();
- return context.thisExpr();
- }
- case IDENT: {
- int start = tokenStart();
- const Identifier* ident = m_token.m_data.ident;
- next();
- currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident);
- m_lastIdentifier = ident;
- return context.createResolve(ident, start);
- }
- case STRING: {
- const Identifier* ident = m_token.m_data.ident;
- next();
- return context.createString(ident);
- }
- case NUMBER: {
- double d = m_token.m_data.doubleValue;
- next();
- return context.createNumberExpr(d);
- }
- case NULLTOKEN: {
- next();
- return context.createNull();
- }
- case TRUETOKEN: {
- next();
- return context.createBoolean(true);
- }
- case FALSETOKEN: {
- next();
- return context.createBoolean(false);
- }
- case DIVEQUAL:
- case DIVIDE: {
- /* regexp */
- const Identifier* pattern;
- const Identifier* flags;
- if (match(DIVEQUAL))
- failIfFalse(m_lexer->scanRegExp(pattern, flags, '='));
- else
- failIfFalse(m_lexer->scanRegExp(pattern, flags));
-
- int start = tokenStart();
- next();
- TreeExpression re = context.createRegExp(*pattern, *flags, start);
- if (!re) {
- m_errorMessage = Yarr::checkSyntax(pattern->ustring());
- ASSERT(m_errorMessage);
- fail();
- }
- return re;
- }
- default:
- fail();
- }
-}
-
-template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& context)
-{
- consumeOrFailWithFlags(OPENPAREN, TreeBuilder::DontBuildStrings);
- if (match(CLOSEPAREN)) {
- next(TreeBuilder::DontBuildStrings);
- return context.createArguments();
- }
- TreeExpression firstArg = parseAssignmentExpression(context);
- failIfFalse(firstArg);
-
- TreeArgumentsList argList = context.createArgumentsList(firstArg);
- TreeArgumentsList tail = argList;
- while (match(COMMA)) {
- next(TreeBuilder::DontBuildStrings);
- TreeExpression arg = parseAssignmentExpression(context);
- failIfFalse(arg);
- tail = context.createArgumentsList(tail, arg);
- }
- consumeOrFail(CLOSEPAREN);
- return context.createArguments(argList);
-}
-
-template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(TreeBuilder& context)
-{
- TreeExpression base = 0;
- int start = tokenStart();
- int expressionStart = start;
- int newCount = 0;
- while (match(NEW)) {
- next();
- newCount++;
- }
-
- if (match(FUNCTION)) {
- const Identifier* name = &m_globalData->propertyNames->nullIdentifier;
- TreeFormalParameterList parameters = 0;
- TreeFunctionBody body = 0;
- int openBracePos = 0;
- int closeBracePos = 0;
- int bodyStartLine = 0;
- next();
- failIfFalse((parseFunctionInfo<FunctionNoRequirements, false>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
- base = context.createFunctionExpr(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
- } else
- base = parsePrimaryExpression(context);
-
- failIfFalse(base);
- while (true) {
- switch (m_token.m_type) {
- case OPENBRACKET: {
- m_nonTrivialExpressionCount++;
- int expressionEnd = lastTokenEnd();
- next();
- int nonLHSCount = m_nonLHSCount;
- int initialAssignments = m_assignmentCount;
- TreeExpression property = parseExpression(context);
- failIfFalse(property);
- base = context.createBracketAccess(base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd());
- if (!consume(CLOSEBRACKET))
- fail();
- m_nonLHSCount = nonLHSCount;
- break;
- }
- case OPENPAREN: {
- m_nonTrivialExpressionCount++;
- if (newCount) {
- newCount--;
- if (match(OPENPAREN)) {
- int exprEnd = lastTokenEnd();
- TreeArguments arguments = parseArguments(context);
- failIfFalse(arguments);
- base = context.createNewExpr(base, arguments, start, exprEnd, lastTokenEnd());
- } else
- base = context.createNewExpr(base, start, lastTokenEnd());
- } else {
- int nonLHSCount = m_nonLHSCount;
- int expressionEnd = lastTokenEnd();
- TreeArguments arguments = parseArguments(context);
- failIfFalse(arguments);
- base = context.makeFunctionCallNode(base, arguments, expressionStart, expressionEnd, lastTokenEnd());
- m_nonLHSCount = nonLHSCount;
- }
- break;
- }
- case DOT: {
- m_nonTrivialExpressionCount++;
- int expressionEnd = lastTokenEnd();
- nextExpectIdentifier(Lexer::IgnoreReservedWords | TreeBuilder::DontBuildKeywords);
- matchOrFail(IDENT);
- base = context.createDotAccess(base, m_token.m_data.ident, expressionStart, expressionEnd, tokenEnd());
- next();
- break;
- }
- default:
- goto endMemberExpression;
- }
- }
-endMemberExpression:
- while (newCount--)
- base = context.createNewExpr(base, start, lastTokenEnd());
- return base;
-}
-
-template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeBuilder& context)
-{
- typename TreeBuilder::UnaryExprContext unaryExprContext(context);
- AllowInOverride allowInOverride(this);
- int tokenStackDepth = 0;
- bool modifiesExpr = false;
- bool requiresLExpr = false;
- while (isUnaryOp(m_token.m_type)) {
- if (strictMode()) {
- switch (m_token.m_type) {
- case PLUSPLUS:
- case MINUSMINUS:
- case AUTOPLUSPLUS:
- case AUTOMINUSMINUS:
- failIfTrue(requiresLExpr);
- modifiesExpr = true;
- requiresLExpr = true;
- break;
- case DELETETOKEN:
- failIfTrue(requiresLExpr);
- requiresLExpr = true;
- break;
- default:
- failIfTrue(requiresLExpr);
- break;
- }
- }
- m_nonLHSCount++;
- context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStart());
- next();
- m_nonTrivialExpressionCount++;
- }
- int subExprStart = tokenStart();
- TreeExpression expr = parseMemberExpression(context);
- failIfFalse(expr);
- bool isEvalOrArguments = false;
- if (strictMode() && !m_syntaxAlreadyValidated) {
- if (context.isResolve(expr)) {
- isEvalOrArguments = *m_lastIdentifier == m_globalData->propertyNames->eval || *m_lastIdentifier == m_globalData->propertyNames->arguments;
- }
- }
- failIfTrueIfStrict(isEvalOrArguments && modifiesExpr);
- switch (m_token.m_type) {
- case PLUSPLUS:
- m_nonTrivialExpressionCount++;
- m_nonLHSCount++;
- expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd());
- m_assignmentCount++;
- failIfTrueIfStrict(isEvalOrArguments);
- failIfTrueIfStrict(requiresLExpr);
- next();
- break;
- case MINUSMINUS:
- m_nonTrivialExpressionCount++;
- m_nonLHSCount++;
- expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd());
- m_assignmentCount++;
- failIfTrueIfStrict(isEvalOrArguments);
- failIfTrueIfStrict(requiresLExpr);
- next();
- break;
- default:
- break;
- }
-
- int end = lastTokenEnd();
-
- if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode()))
- return expr;
-
- while (tokenStackDepth) {
- switch (context.unaryTokenStackLastType(tokenStackDepth)) {
- case EXCLAMATION:
- expr = context.createLogicalNot(expr);
- break;
- case TILDE:
- expr = context.makeBitwiseNotNode(expr);
- break;
- case MINUS:
- expr = context.makeNegateNode(expr);
- break;
- case PLUS:
- expr = context.createUnaryPlus(expr);
- break;
- case PLUSPLUS:
- case AUTOPLUSPLUS:
- expr = context.makePrefixNode(expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
- m_assignmentCount++;
- break;
- case MINUSMINUS:
- case AUTOMINUSMINUS:
- expr = context.makePrefixNode(expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
- m_assignmentCount++;
- break;
- case TYPEOF:
- expr = context.makeTypeOfNode(expr);
- break;
- case VOIDTOKEN:
- expr = context.createVoid(expr);
- break;
- case DELETETOKEN:
- failIfTrueIfStrict(context.isResolve(expr));
- expr = context.makeDeleteNode(expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end);
- break;
- default:
- // If we get here something has gone horribly horribly wrong
- CRASH();
- }
- subExprStart = context.unaryTokenStackLastStart(tokenStackDepth);
- context.unaryTokenStackRemoveLast(tokenStackDepth);
- }
- return expr;
-}
-
-}
-
-namespace WTF
-{
- template <> struct VectorTraits<JSC::JSParser::Scope> : SimpleClassVectorTraits {
- static const bool canInitializeWithMemset = false; // Not all Scope data members initialize to 0.
- };
-}