X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/1df5f87f1309a8daa30dabdee855f48ae40d14ab..6fe7ccc865dc7d7541b93c5bcaf6368d2c98a174:/parser/JSParser.cpp diff --git a/parser/JSParser.cpp b/parser/JSParser.cpp deleted file mode 100644 index d56155b..0000000 --- a/parser/JSParser.cpp +++ /dev/null @@ -1,2186 +0,0 @@ -/* - * 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 -#include -#include -#include - -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 TreeSourceElements parseSourceElements(TreeBuilder&); - template TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive); - template TreeStatement parseFunctionDeclaration(TreeBuilder&); - template TreeStatement parseVarDeclaration(TreeBuilder&); - template TreeStatement parseConstDeclaration(TreeBuilder&); - template TreeStatement parseDoWhileStatement(TreeBuilder&); - template TreeStatement parseWhileStatement(TreeBuilder&); - template TreeStatement parseForStatement(TreeBuilder&); - template TreeStatement parseBreakStatement(TreeBuilder&); - template TreeStatement parseContinueStatement(TreeBuilder&); - template TreeStatement parseReturnStatement(TreeBuilder&); - template TreeStatement parseThrowStatement(TreeBuilder&); - template TreeStatement parseWithStatement(TreeBuilder&); - template TreeStatement parseSwitchStatement(TreeBuilder&); - template TreeClauseList parseSwitchClauses(TreeBuilder&); - template TreeClause parseSwitchDefaultClause(TreeBuilder&); - template TreeStatement parseTryStatement(TreeBuilder&); - template TreeStatement parseDebuggerStatement(TreeBuilder&); - template TreeStatement parseExpressionStatement(TreeBuilder&); - template TreeStatement parseExpressionOrLabelStatement(TreeBuilder&); - template TreeStatement parseIfStatement(TreeBuilder&); - template ALWAYS_INLINE TreeStatement parseBlockStatement(TreeBuilder&); - template TreeExpression parseExpression(TreeBuilder&); - template TreeExpression parseAssignmentExpression(TreeBuilder&); - template ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&); - template ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&); - template ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&); - template TreeExpression parseMemberExpression(TreeBuilder&); - template ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&); - template ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&); - template ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&); - template ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&); - template ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&); - template ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&); - template ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&); - template ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&); - template ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd); - template ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context); - enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName }; - template 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 >& 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 LabelStack; - OwnPtr m_labels; - IdentifierSet m_declaredVariables; - IdentifierSet m_usedVariables; - IdentifierSet m_closedVariables; - IdentifierSet m_writtenVariables; - }; - - typedef Vector 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(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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 TreeClauseList JSParser::parseSwitchClauses(TreeBuilder& context) -{ - if (!match(CASE)) - return 0; - next(); - TreeExpression condition = parseExpression(context); - failIfFalse(condition); - consumeOrFail(COLON); - TreeSourceElements statements = parseSourceElements(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(context); - failIfFalse(statements); - clause = context.createClause(condition, statements); - tail = context.createClauseList(tail, clause); - } - return clauseList; -} - -template TreeClause JSParser::parseSwitchDefaultClause(TreeBuilder& context) -{ - if (!match(DEFAULT)) - return 0; - next(); - consumeOrFail(COLON); - TreeSourceElements statements = parseSourceElements(context); - failIfFalse(statements); - return context.createClause(0, statements); -} - -template 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 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 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(context); - failIfFalse(subtree); - matchOrFail(CLOSEBRACE); - next(); - return context.createBlockStatement(subtree, start, m_lastLine); -} - -template 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 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 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(bodyBuilder)); - return context.createFunctionBody(strictMode()); -} - -template 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 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 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(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 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 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 TreeStatement JSParser::parseExpressionStatement(TreeBuilder& context) -{ - int startLine = tokenLine(); - TreeExpression expression = parseExpression(context); - failIfFalse(expression); - failIfFalse(autoSemiColon()); - return context.createExprStatement(expression, startLine, m_lastLine); -} - -template 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 exprStack; - Vector > posStack; - Vector 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 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 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 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 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 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 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 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(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(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine))); - return context.template createGetterOrSetterProperty(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(m_globalData, propertyName, node, PropertyNode::Constant); - } - default: - failIfFalse(m_token.m_type & KeywordTokenFlag); - goto namedProperty; - } -} - -template 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(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(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 TreeExpression JSParser::parseStrictObjectLiteral(TreeBuilder& context) -{ - consumeOrFail(OPENBRACE); - - if (match(CLOSEBRACE)) { - next(); - return context.createObjectLiteral(); - } - - TreeProperty property = parseProperty(context); - failIfFalse(property); - - typedef HashMap, 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(context); - failIfFalse(property); - if (!m_syntaxAlreadyValidated) { - std::pair 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 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 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 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 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(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 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 : SimpleClassVectorTraits { - static const bool canInitializeWithMemset = false; // Not all Scope data members initialize to 0. - }; -}