diff options
Diffstat (limited to 'JavaScriptCore/parser/JSParser.cpp')
-rw-r--r-- | JavaScriptCore/parser/JSParser.cpp | 459 |
1 files changed, 391 insertions, 68 deletions
diff --git a/JavaScriptCore/parser/JSParser.cpp b/JavaScriptCore/parser/JSParser.cpp index 0e526ac..0338210 100644 --- a/JavaScriptCore/parser/JSParser.cpp +++ b/JavaScriptCore/parser/JSParser.cpp @@ -29,6 +29,7 @@ using namespace JSC; +#include "CodeBlock.h" #include "JSGlobalData.h" #include "NodeInfo.h" #include "ASTBuilder.h" @@ -42,6 +43,8 @@ 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 matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0) #define failIfStackOverflow() do { failIfFalse(canRecurse()); } while (0) @@ -67,8 +70,8 @@ static const ptrdiff_t kMaxParserStackUsage = 128 * sizeof(void*) * 1024; class JSParser { public: - JSParser(Lexer*, JSGlobalData*, FunctionParameters*, SourceProvider*); - bool parseProgram(); + JSParser(Lexer*, JSGlobalData*, FunctionParameters*, bool isStrictContext, bool isFunction, SourceProvider*); + bool parseProgram(JSGlobalObject*); private: struct AllowInOverride { AllowInOverride(JSParser* parser) @@ -90,7 +93,7 @@ private: 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); + m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexType, strictMode()); m_tokenCount++; } @@ -121,9 +124,23 @@ private: { return m_token.m_info.endOffset; } - - template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&); - template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&); + + 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() { return currentScope()->breakIsValid(); } + void pushLabel(const Identifier* label) { currentScope()->pushLabel(label); } + void popLabel() { currentScope()->popLabel(); } + bool hasLabel(const Identifier* label) { return currentScope()->hasLabel(label); } + + 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&); @@ -199,32 +216,118 @@ private: 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() - : m_usesEval(false) + Scope(JSGlobalData* globalData, bool isFunction, bool strictMode) + : m_globalData(globalData) + , m_usesEval(false) , m_needsFullActivation(false) , m_allowsNewDecls(true) + , m_strictMode(strictMode) + , m_isFunction(isFunction) + , m_isValidStrictMode(true) + , m_loopDepth(0) + , m_switchDepth(0) + , m_labels(0) + { + } + + 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; } + + void pushLabel(const Identifier* label) + { + if (!m_labels) + m_labels = new LabelStack; + m_labels->append(label->impl()); + } + + void popLabel() { + ASSERT(m_labels); + ASSERT(m_labels->size()); + m_labels->removeLast(); } + + bool hasLabel(const Identifier* label) + { + if (!m_labels) + return false; + for (int i = m_labels->size(); i > 0; i--) { + if (m_labels->at(i - 1) == label->impl()) + return true; + } + return false; + } + + void setIsFunction() { m_isFunction = true; } + bool isFunction() { return m_isFunction; } - void declareVariable(const Identifier* ident) + 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()); + } + + bool deleteProperty(const Identifier* ident) + { + if (m_declaredVariables.contains(ident->impl())) + return false; + m_deletedVariables.add(ident->impl()); + return true; } void preventNewDecls() { m_allowsNewDecls = false; } bool allowsNewDecls() const { return m_allowsNewDecls; } + bool declareParameter(const Identifier* ident) + { + bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).second && m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident; + m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode; + return isValidStrictMode; + } + void useVariable(const Identifier* ident, bool isEval) { m_usesEval |= isEval; m_usedVariables.add(ident->ustring().impl()); } - void needsFullActivation() { m_needsFullActivation = true; } + void setNeedsFullActivation() { m_needsFullActivation = true; } - void collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables) + bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables) { if (nestedScope->m_usesEval) m_usesEval = true; @@ -236,6 +339,45 @@ private: 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); + } + } + if (nestedScope->m_deletedVariables.size()) { + IdentifierSet::iterator end = nestedScope->m_deletedVariables.end(); + for (IdentifierSet::iterator ptr = nestedScope->m_deletedVariables.begin(); ptr != end; ++ptr) { + if (nestedScope->m_declaredVariables.contains(*ptr)) + return false; + if (m_declaredVariables.contains(*ptr)) + return false; + m_deletedVariables.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); + } + } + + bool getDeletedVariables(IdentifierSet& deletedVariables) + { + IdentifierSet::iterator end = m_deletedVariables.end(); + for (IdentifierSet::iterator ptr = m_deletedVariables.begin(); ptr != end; ++ptr) { + if (m_declaredVariables.contains(*ptr)) + return false; + } + deletedVariables.swap(m_deletedVariables); + return true; } void getCapturedVariables(IdentifierSet& capturedVariables) @@ -250,13 +392,27 @@ private: capturedVariables.add(*ptr); } } + void setStrictMode() { m_strictMode = true; } + bool strictMode() const { return m_strictMode; } + bool isValidStrictMode() const { return m_isValidStrictMode; } + private: - bool m_usesEval; - bool m_needsFullActivation; - bool m_allowsNewDecls; + JSGlobalData* m_globalData; + bool m_usesEval : 1; + bool m_needsFullActivation : 1; + bool m_allowsNewDecls : 1; + bool m_strictMode : 1; + bool m_isFunction : 1; + bool m_isValidStrictMode : 1; + int m_loopDepth; + int m_switchDepth; + typedef Vector<StringImpl*, 2> LabelStack; + LabelStack* m_labels; IdentifierSet m_declaredVariables; IdentifierSet m_usedVariables; IdentifierSet m_closedVariables; + IdentifierSet m_writtenVariables; + IdentifierSet m_deletedVariables; }; typedef Vector<Scope, 10> ScopeStack; @@ -281,19 +437,26 @@ private: ScopeRef pushScope() { - m_scopeStack.append(Scope()); + 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(); } - void popScope(ScopeRef scope, bool shouldTrackClosedVariables) + bool popScope(ScopeRef scope, bool shouldTrackClosedVariables) { ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1); ASSERT(m_scopeStack.size() > 1); - m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables); + bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables); m_scopeStack.removeLast(); + return result; } - void declareVariable(const Identifier* ident) + bool declareVariable(const Identifier* ident) { unsigned i = m_scopeStack.size() - 1; ASSERT(i < m_scopeStack.size()); @@ -301,19 +464,32 @@ private: i--; ASSERT(i < m_scopeStack.size()); } - m_scopeStack[i].declareVariable(ident); + return m_scopeStack[i].declareVariable(ident); + } + + void declareWrite(const Identifier* ident) + { + if (!m_syntaxAlreadyValidated) + m_scopeStack.last().declareWrite(ident); } + bool deleteProperty(const Identifier* ident) + { + if (!m_syntaxAlreadyValidated) + return m_scopeStack.last().deleteProperty(ident); + return true; + } + ScopeStack m_scopeStack; }; -int jsParse(JSGlobalData* globalData, FunctionParameters* parameters, const SourceCode* source) +int jsParse(JSGlobalObject* lexicalGlobalObject, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, const SourceCode* source) { - JSParser parser(globalData->lexer, globalData, parameters, source->provider()); - return parser.parseProgram(); + JSParser parser(lexicalGlobalObject->globalData()->lexer, lexicalGlobalObject->globalData(), parameters, strictness == JSParseStrict, parserMode == JSParseFunctionCode, source->provider()); + return parser.parseProgram(lexicalGlobalObject); } -JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, SourceProvider* provider) +JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, bool inStrictContext, bool isFunction, SourceProvider* provider) : m_lexer(lexer) , m_endAddress(0) , m_error(false) @@ -325,28 +501,48 @@ JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* p , m_assignmentCount(0) , m_nonLHSCount(0) , m_syntaxAlreadyValidated(provider->isValid()) + , m_statementDepth(0) + , m_nonTrivialExpressionCount(0) + , m_lastIdentifier(0) { m_endAddress = wtfThreadData().approximatedStackStart() - kMaxParserStackUsage; - next(); - m_lexer->setLastLineNumber(tokenLine()); ScopeRef scope = pushScope(); + if (isFunction) + scope->setIsFunction(); + if (inStrictContext) + scope->setStrictMode(); if (parameters) { for (unsigned i = 0; i < parameters->size(); i++) - scope->declareVariable(¶meters->at(i)); + scope->declareParameter(¶meters->at(i)); } + next(); + m_lexer->setLastLineNumber(tokenLine()); } -bool JSParser::parseProgram() +bool JSParser::parseProgram(JSGlobalObject* lexicalGlobalObject) { ASTBuilder context(m_globalData, m_lexer); + if (m_lexer->isReparsing()) + m_statementDepth--; ScopeRef scope = currentScope(); - SourceElements* sourceElements = parseSourceElements<ASTBuilder>(context); + SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context); if (!sourceElements || !consume(EOFTOK)) return true; + if (!m_syntaxAlreadyValidated) { + IdentifierSet deletedVariables; + if (!scope->getDeletedVariables(deletedVariables)) + return true; + IdentifierSet::const_iterator end = deletedVariables.end(); + SymbolTable& globalEnvRecord = lexicalGlobalObject->symbolTable(); + for (IdentifierSet::const_iterator ptr = deletedVariables.begin(); ptr != end; ++ptr) { + if (!globalEnvRecord.get(*ptr).isNull()) + return true; + } + } IdentifierSet capturedVariables; scope->getCapturedVariables(capturedVariables); - m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features(), - m_lastLine, context.numConstants(), capturedVariables); + m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features() | (scope->strictMode() ? StrictModeFeature : 0), + m_lastLine, context.numConstants(), capturedVariables); return false; } @@ -355,11 +551,30 @@ bool JSParser::allowAutomaticSemicolon() return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator(); } -template <class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context) +template <JSParser::SourceElementsMode mode, class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context) { TreeSourceElements sourceElements = context.createSourceElements(); - while (TreeStatement statement = parseStatement(context)) + bool seenNonDirective = false; + const Identifier* directive = 0; + unsigned startOffset = m_token.m_info.startOffset; + 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(); + failIfTrue(m_error); + continue; + } + } else + seenNonDirective = true; + } context.appendStatement(sourceElements, statement); + } if (m_error) fail(); @@ -399,7 +614,10 @@ template <class TreeBuilder> TreeStatement JSParser::parseDoWhileStatement(TreeB ASSERT(match(DO)); int startLine = tokenLine(); next(); - TreeStatement statement = parseStatement(context); + const Identifier* unused = 0; + startLoop(); + TreeStatement statement = parseStatement(context, unused); + endLoop(); failIfFalse(statement); int endLine = tokenLine(); consumeOrFail(WHILE); @@ -422,7 +640,10 @@ template <class TreeBuilder> TreeStatement JSParser::parseWhileStatement(TreeBui failIfFalse(expr); int endLine = tokenLine(); consumeOrFail(CLOSEPAREN); - TreeStatement statement = parseStatement(context); + const Identifier* unused = 0; + startLoop(); + TreeStatement statement = parseStatement(context, unused); + endLoop(); failIfFalse(statement); return context.createWhileStatement(expr, statement, startLine, endLine); } @@ -441,7 +662,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(Tr lastIdent = name; next(); bool hasInitializer = match(EQUAL); - declareVariable(name); + failIfFalseIfStrict(declareVariable(name)); context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0); if (hasInitializer) { int varDivot = tokenStart() + 1; @@ -465,6 +686,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(Tr template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationList(TreeBuilder& context) { + failIfTrue(strictMode()); TreeConstDeclList constDecls = 0; TreeConstDeclList tail = 0; do { @@ -532,7 +754,10 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild int endLine = tokenLine(); consumeOrFail(CLOSEPAREN); - TreeStatement statement = parseStatement(context); + 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); @@ -566,7 +791,10 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild } int endLine = tokenLine(); consumeOrFail(CLOSEPAREN); - TreeStatement statement = parseStatement(context); + const Identifier* unused = 0; + startLoop(); + TreeStatement statement = parseStatement(context, unused); + endLoop(); failIfFalse(statement); return context.createForLoop(decls, condition, increment, statement, hasDeclaration, startLine, endLine); } @@ -579,7 +807,10 @@ template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuild int exprEnd = lastTokenEnd(); int endLine = tokenLine(); consumeOrFail(CLOSEPAREN); - TreeStatement statement = parseStatement(context); + const Identifier* unused = 0; + startLoop(); + TreeStatement statement = parseStatement(context, unused); + endLoop(); failIfFalse(statement); return context.createForInLoop(decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine); @@ -594,10 +825,13 @@ template <class TreeBuilder> TreeStatement JSParser::parseBreakStatement(TreeBui int endLine = tokenLine(); next(); - if (autoSemiColon()) + if (autoSemiColon()) { + failIfFalseIfStrict(breakIsValid()); return context.createBreakStatement(startCol, endCol, startLine, endLine); + } matchOrFail(IDENT); const Identifier* ident = m_token.m_data.ident; + failIfFalseIfStrict(hasLabel(ident)); endCol = tokenEnd(); endLine = tokenLine(); next(); @@ -614,10 +848,13 @@ template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(Tree int endLine = tokenLine(); next(); - if (autoSemiColon()) + if (autoSemiColon()) { + failIfFalseIfStrict(breakIsValid()); return context.createContinueStatement(startCol, endCol, startLine, endLine); + } matchOrFail(IDENT); const Identifier* ident = m_token.m_data.ident; + failIfFalseIfStrict(hasLabel(ident)); endCol = tokenEnd(); endLine = tokenLine(); next(); @@ -628,6 +865,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(Tree template <class TreeBuilder> TreeStatement JSParser::parseReturnStatement(TreeBuilder& context) { ASSERT(match(RETURN)); + failIfFalseIfStrict(currentScope()->isFunction()); int startLine = tokenLine(); int endLine = startLine; int start = tokenStart(); @@ -655,6 +893,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseThrowStatement(TreeBui int eStart = tokenStart(); int startLine = tokenLine(); next(); + + failIfTrue(autoSemiColon()); TreeExpression expr = parseExpression(context); failIfFalse(expr); @@ -668,7 +908,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseThrowStatement(TreeBui template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuilder& context) { ASSERT(match(WITH)); - currentScope()->needsFullActivation(); + failIfTrue(strictMode()); + currentScope()->setNeedsFullActivation(); int startLine = tokenLine(); next(); consumeOrFail(OPENPAREN); @@ -679,8 +920,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuil int endLine = tokenLine(); consumeOrFail(CLOSEPAREN); - - TreeStatement statement = parseStatement(context); + const Identifier* unused = 0; + TreeStatement statement = parseStatement(context, unused); failIfFalse(statement); return context.createWithStatement(expr, statement, start, end, startLine, endLine); @@ -697,7 +938,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBu int endLine = tokenLine(); consumeOrFail(CLOSEPAREN); consumeOrFail(OPENBRACE); - + startSwitch(); TreeClauseList firstClauses = parseSwitchClauses(context); failIfTrue(m_error); @@ -706,6 +947,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBu TreeClauseList secondClauses = parseSwitchClauses(context); failIfTrue(m_error); + endSwitch(); consumeOrFail(CLOSEBRACE); return context.createSwitchStatement(expr, firstClauses, defaultClause, secondClauses, startLine, endLine); @@ -720,7 +962,7 @@ template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBui TreeExpression condition = parseExpression(context); failIfFalse(condition); consumeOrFail(COLON); - TreeSourceElements statements = parseSourceElements(context); + TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context); failIfFalse(statements); TreeClause clause = context.createClause(condition, statements); TreeClauseList clauseList = context.createClauseList(clause); @@ -731,7 +973,7 @@ template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBui TreeExpression condition = parseExpression(context); failIfFalse(condition); consumeOrFail(COLON); - TreeSourceElements statements = parseSourceElements(context); + TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context); failIfFalse(statements); clause = context.createClause(condition, statements); tail = context.createClauseList(tail, clause); @@ -745,7 +987,7 @@ template <class TreeBuilder> TreeClause JSParser::parseSwitchDefaultClause(TreeB return 0; next(); consumeOrFail(COLON); - TreeSourceElements statements = parseSourceElements(context); + TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context); failIfFalse(statements); return context.createClause(0, statements); } @@ -767,14 +1009,14 @@ template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuild int lastLine = m_lastLine; if (match(CATCH)) { - currentScope()->needsFullActivation(); + currentScope()->setNeedsFullActivation(); next(); consumeOrFail(OPENPAREN); matchOrFail(IDENT); ident = m_token.m_data.ident; next(); ScopeRef catchScope = pushScope(); - catchScope->declareVariable(ident); + failIfFalseIfStrict(catchScope->declareVariable(ident)); catchScope->preventNewDecls(); consumeOrFail(CLOSEPAREN); matchOrFail(OPENBRACE); @@ -782,7 +1024,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuild catchBlock = parseBlockStatement(context); failIfFalse(catchBlock); catchHasEval = initialEvalCount != context.evalCount(); - popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo); + failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo)); } if (match(FINALLY)) { @@ -816,15 +1058,19 @@ template <class TreeBuilder> TreeStatement JSParser::parseBlockStatement(TreeBui next(); return context.createBlockStatement(0, start, m_lastLine); } - TreeSourceElements subtree = parseSourceElements(context); + 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) +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: @@ -834,6 +1080,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& case CONSTTOKEN: return parseConstDeclaration(context); case FUNCTION: + failIfFalseIfStrict(m_statementDepth == 1); return parseFunctionDeclaration(context); case SEMICOLON: next(); @@ -870,8 +1117,14 @@ template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& return 0; case IDENT: return parseExpressionOrLabelStatement(context); + case STRING: + directive = m_token.m_data.ident; + nonTrivialExpressionCount = m_nonTrivialExpressionCount; default: - return parseExpressionStatement(context); + TreeStatement exprStatement = parseExpressionStatement(context); + if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount) + directive = 0; + return exprStatement; } } @@ -879,7 +1132,7 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame { matchOrFail(IDENT); usesArguments = m_globalData->propertyNames->arguments == *m_token.m_data.ident; - declareVariable(m_token.m_data.ident); + failIfFalseIfStrict(declareParameter(m_token.m_data.ident)); TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident); TreeFormalParameterList tail = list; next(); @@ -887,7 +1140,8 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame next(); matchOrFail(IDENT); const Identifier* ident = m_token.m_data.ident; - declareVariable(ident); + usesArguments |= m_globalData->propertyNames->arguments == *m_token.m_data.ident; + failIfFalseIfStrict(declareParameter(ident)); next(); usesArguments = usesArguments || m_globalData->propertyNames->arguments == *ident; tail = context.createFormalParameterList(tail, *ident); @@ -898,20 +1152,23 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBuilder& context) { if (match(CLOSEBRACE)) - return context.createFunctionBody(); + 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(); + 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) { ScopeRef functionScope = pushScope(); + functionScope->setIsFunction(); if (match(IDENT)) { name = m_token.m_data.ident; next(); if (!nameIsInContainingScope) - functionScope->declareVariable(name); + failIfFalseIfStrict(functionScope->declareVariable(name)); } else if (requirements == FunctionNeedsName) return false; consumeOrFail(OPENPAREN); @@ -931,7 +1188,11 @@ template <JSParser::FunctionRequirements requirements, bool nameIsInContainingSc failIfFalse(body); if (usesArguments) context.setUsesArguments(body); - popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo); + if (functionScope->strictMode() && name) { + failIfTrue(m_globalData->propertyNames->arguments == *name); + failIfTrue(m_globalData->propertyNames->eval == *name); + } + failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo)); matchOrFail(CLOSEBRACE); closeBracePos = m_token.m_data.intValue; next(); @@ -950,7 +1211,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(Tr int bodyStartLine = 0; failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine))); failIfFalse(name); - declareVariable(name); + failIfFalseIfStrict(declareVariable(name)); return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine); } @@ -973,7 +1234,12 @@ template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelState failIfFalse(currentToken + 1 == m_tokenCount); int end = tokenEnd(); consumeOrFail(COLON); - TreeStatement statement = parseStatement(context); + const Identifier* unused = 0; + if (strictMode() && !m_syntaxAlreadyValidated) + pushLabel(ident); + TreeStatement statement = parseStatement(context, unused); + if (strictMode() && !m_syntaxAlreadyValidated) + popLabel(); failIfFalse(statement); return context.createLabelStatement(ident, statement, start, end); } @@ -1001,7 +1267,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilde int end = tokenLine(); consumeOrFail(CLOSEPAREN); - TreeStatement trueBlock = parseStatement(context); + const Identifier* unused = 0; + TreeStatement trueBlock = parseStatement(context, unused); failIfFalse(trueBlock); if (!match(ELSE)) @@ -1014,7 +1281,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilde do { next(); if (!match(IF)) { - TreeStatement block = parseStatement(context); + const Identifier* unused = 0; + TreeStatement block = parseStatement(context, unused); failIfFalse(block); statementStack.append(block); trailingElse = true; @@ -1029,8 +1297,8 @@ template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilde failIfFalse(innerCondition); int innerEnd = tokenLine(); consumeOrFail(CLOSEPAREN); - - TreeStatement innerTrueBlock = parseStatement(context); + const Identifier* unused = 0; + TreeStatement innerTrueBlock = parseStatement(context, unused); failIfFalse(innerTrueBlock); exprStack.append(innerCondition); posStack.append(make_pair(innerStart, innerEnd)); @@ -1070,6 +1338,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseExpression(TreeBuilde if (!match(COMMA)) return node; next(); + m_nonTrivialExpressionCount++; m_nonLHSCount++; TreeExpression right = parseAssignmentExpression(context); failIfFalse(right); @@ -1115,11 +1384,17 @@ template <typename TreeBuilder> TreeExpression JSParser::parseAssignmentExpressi default: goto end; } + m_nonTrivialExpressionCount++; hadAssignment = true; context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op); start = tokenStart(); m_assignmentCount++; next(); + if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) { + failIfTrueIfStrict(m_globalData->propertyNames->eval == *m_lastIdentifier); + declareWrite(m_lastIdentifier); + m_lastIdentifier = 0; + } lhs = parseConditionalExpression(context); failIfFalse(lhs); if (initialNonLHSCount != m_nonLHSCount) @@ -1144,6 +1419,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseConditionalExpression failIfFalse(cond); if (!match(QUESTION)) return cond; + m_nonTrivialExpressionCount++; m_nonLHSCount++; next(); TreeExpression lhs = parseAssignmentExpression(context); @@ -1181,6 +1457,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(Tree int precedence = isBinaryOperator(m_token.m_type); if (!precedence) break; + m_nonTrivialExpressionCount++; m_nonLHSCount++; int operatorToken = m_token.m_type; next(); @@ -1196,7 +1473,6 @@ template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(Tree } context.operatorStackAppend(operatorStackDepth, operatorToken, precedence); } - while (operatorStackDepth) { ASSERT(operandStackDepth > 1); @@ -1327,6 +1603,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseStrictObjectLiteral(T if (!m_syntaxAlreadyValidated) { std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).impl(), context.getType(property)); if (!propertyEntryIter.second) { + failIfTrue(strictMode()); if ((context.getType(property) & propertyEntryIter.first->second) != PropertyNode::Constant) { // Can't have multiple getters or setters with the same name, nor can we define // a property as both an accessor and a constant value @@ -1389,6 +1666,8 @@ template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(Tre { switch (m_token.m_type) { case OPENBRACE: + if (strictMode()) + return parseStrictObjectLiteral(context); return parseObjectLiteral(context); case OPENBRACKET: return parseArrayLiteral(context); @@ -1410,6 +1689,7 @@ template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(Tre 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: { @@ -1485,6 +1765,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree next(); newCount++; } + if (match(FUNCTION)) { const Identifier* name = &m_globalData->propertyNames->nullIdentifier; TreeFormalParameterList parameters = 0; @@ -1502,6 +1783,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree while (true) { switch (m_token.m_type) { case OPENBRACKET: { + m_nonTrivialExpressionCount++; int expressionEnd = lastTokenEnd(); next(); int nonLHSCount = m_nonLHSCount; @@ -1515,6 +1797,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree break; } case OPENPAREN: { + m_nonTrivialExpressionCount++; if (newCount) { newCount--; if (match(OPENPAREN)) { @@ -1535,6 +1818,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree break; } case DOT: { + m_nonTrivialExpressionCount++; int expressionEnd = lastTokenEnd(); next(Lexer::IgnoreReservedWords); matchOrFail(IDENT); @@ -1556,25 +1840,62 @@ template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeB { 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_globalData->propertyNames->eval == *m_lastIdentifier; + if (!isEvalOrArguments && currentScope()->isFunction()) + isEvalOrArguments = m_globalData->propertyNames->arguments == *m_lastIdentifier; + } + } + 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: @@ -1583,7 +1904,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeB int end = lastTokenEnd(); - if (!TreeBuilder::CreatesAST) + if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode())) return expr; while (tokenStackDepth) { @@ -1617,6 +1938,8 @@ template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeB expr = context.createVoid(expr); break; case DELETETOKEN: + if (strictMode() && context.isResolve(expr)) + failIfFalse(deleteProperty(m_lastIdentifier)); expr = context.makeDeleteNode(expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end); break; default: |