summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/parser/JSParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/parser/JSParser.cpp')
-rw-r--r--JavaScriptCore/parser/JSParser.cpp459
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(&parameters->at(i));
+ scope->declareParameter(&parameters->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: