summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/parser/JSParser.cpp
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-09-29 17:32:26 +0100
committerSteve Block <steveblock@google.com>2010-09-29 17:35:08 +0100
commit68513a70bcd92384395513322f1b801e7bf9c729 (patch)
tree161b50f75a5921d61731bb25e730005994fcec85 /JavaScriptCore/parser/JSParser.cpp
parentfd5c6425ce58eb75211be7718d5dee960842a37e (diff)
downloadexternal_webkit-68513a70bcd92384395513322f1b801e7bf9c729.zip
external_webkit-68513a70bcd92384395513322f1b801e7bf9c729.tar.gz
external_webkit-68513a70bcd92384395513322f1b801e7bf9c729.tar.bz2
Merge WebKit at r67908: Initial merge by Git
Change-Id: I43a553e7b3299b28cb6ee8aa035ed70fe342b972
Diffstat (limited to 'JavaScriptCore/parser/JSParser.cpp')
-rw-r--r--JavaScriptCore/parser/JSParser.cpp134
1 files changed, 123 insertions, 11 deletions
diff --git a/JavaScriptCore/parser/JSParser.cpp b/JavaScriptCore/parser/JSParser.cpp
index 820811e..540dc3b 100644
--- a/JavaScriptCore/parser/JSParser.cpp
+++ b/JavaScriptCore/parser/JSParser.cpp
@@ -67,7 +67,7 @@ static const ptrdiff_t kMaxParserStackUsage = 128 * sizeof(void*) * 1024;
class JSParser {
public:
- JSParser(Lexer*, JSGlobalData*, SourceProvider*);
+ JSParser(Lexer*, JSGlobalData*, FunctionParameters*, SourceProvider*);
bool parseProgram();
private:
struct AllowInOverride {
@@ -161,7 +161,7 @@ private:
template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd);
template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
- template <FunctionRequirements, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
+ template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
ALWAYS_INLINE int isBinaryOperator(JSTokenType token);
bool allowAutomaticSemicolon();
@@ -199,15 +199,105 @@ private:
int m_assignmentCount;
int m_nonLHSCount;
bool m_syntaxAlreadyValidated;
+
+ struct Scope {
+ Scope()
+ : m_usesEval(false)
+ , m_needsFullActivation(false)
+ {
+ }
+
+ void declareVariable(const Identifier* ident)
+ {
+ m_declaredVariables.add(ident->ustring().impl());
+ }
+
+ void useVariable(const Identifier* ident, bool isEval)
+ {
+ m_usesEval |= isEval;
+ m_usedVariables.add(ident->ustring().impl());
+ }
+
+ void needsFullActivation() { m_needsFullActivation = true; }
+
+ void 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);
+ }
+ }
+
+ 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);
+ }
+ }
+ private:
+ bool m_usesEval;
+ bool m_needsFullActivation;
+ IdentifierSet m_declaredVariables;
+ IdentifierSet m_usedVariables;
+ IdentifierSet m_closedVariables;
+ };
+
+ typedef Vector<Scope, 10> ScopeStack;
+
+ struct ScopeRef {
+ ScopeRef(ScopeStack* scopeStack, unsigned index)
+ : m_scopeStack(scopeStack)
+ , m_index(index)
+ {
+ }
+ Scope* operator->() { return &m_scopeStack->at(m_index); }
+ unsigned index() const { return m_index; }
+ private:
+ ScopeStack* m_scopeStack;
+ unsigned m_index;
+ };
+
+ ScopeRef currentScope()
+ {
+ return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
+ }
+
+ ScopeRef pushScope()
+ {
+ m_scopeStack.append(Scope());
+ return currentScope();
+ }
+
+ void 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);
+ m_scopeStack.removeLast();
+ }
+
+ ScopeStack m_scopeStack;
};
-int jsParse(JSGlobalData* globalData, const SourceCode* source)
+int jsParse(JSGlobalData* globalData, FunctionParameters* parameters, const SourceCode* source)
{
- JSParser parser(globalData->lexer, globalData, source->provider());
+ JSParser parser(globalData->lexer, globalData, parameters, source->provider());
return parser.parseProgram();
}
-JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, SourceProvider* provider)
+JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, SourceProvider* provider)
: m_lexer(lexer)
, m_endAddress(0)
, m_error(false)
@@ -223,16 +313,24 @@ JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, SourceProvider* provi
m_endAddress = wtfThreadData().approximatedStackStart() - kMaxParserStackUsage;
next();
m_lexer->setLastLineNumber(tokenLine());
+ ScopeRef scope = pushScope();
+ if (parameters) {
+ for (unsigned i = 0; i < parameters->size(); i++)
+ scope->declareVariable(&parameters->at(i));
+ }
}
bool JSParser::parseProgram()
{
ASTBuilder context(m_globalData, m_lexer);
+ ScopeRef scope = currentScope();
SourceElements* sourceElements = parseSourceElements<ASTBuilder>(context);
if (!sourceElements || !consume(EOFTOK))
return true;
+ IdentifierSet capturedVariables;
+ scope->getCapturedVariables(capturedVariables);
m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features(),
- m_lastLine, context.numConstants());
+ m_lastLine, context.numConstants(), capturedVariables);
return false;
}
@@ -327,6 +425,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(Tr
lastIdent = name;
next();
bool hasInitializer = match(EQUAL);
+ currentScope()->declareVariable(name);
context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
if (hasInitializer) {
int varDivot = tokenStart() + 1;
@@ -358,6 +457,7 @@ template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationLi
const Identifier* name = m_token.m_data.ident;
next();
bool hasInitializer = match(EQUAL);
+ currentScope()->declareVariable(name);
context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
TreeExpression initializer = 0;
if (hasInitializer) {
@@ -552,6 +652,7 @@ template <class TreeBuilder> TreeStatement JSParser::parseThrowStatement(TreeBui
template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuilder& context)
{
ASSERT(match(WITH));
+ currentScope()->needsFullActivation();
int startLine = tokenLine();
next();
consumeOrFail(OPENPAREN);
@@ -650,17 +751,21 @@ template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuild
int lastLine = m_lastLine;
if (match(CATCH)) {
+ currentScope()->needsFullActivation();
next();
consumeOrFail(OPENPAREN);
matchOrFail(IDENT);
ident = m_token.m_data.ident;
next();
+ ScopeRef catchScope = pushScope();
+ catchScope->declareVariable(ident);
consumeOrFail(CLOSEPAREN);
matchOrFail(OPENBRACE);
int initialEvalCount = context.evalCount();
catchBlock = parseBlockStatement(context);
failIfFalse(catchBlock);
catchHasEval = initialEvalCount != context.evalCount();
+ popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo);
}
if (match(FINALLY)) {
@@ -757,6 +862,7 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame
{
matchOrFail(IDENT);
usesArguments = m_globalData->propertyNames->arguments == *m_token.m_data.ident;
+ currentScope()->declareVariable(m_token.m_data.ident);
TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
TreeFormalParameterList tail = list;
next();
@@ -764,6 +870,7 @@ template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParame
next();
matchOrFail(IDENT);
const Identifier* ident = m_token.m_data.ident;
+ currentScope()->declareVariable(ident);
next();
usesArguments = usesArguments || m_globalData->propertyNames->arguments == *ident;
tail = context.createFormalParameterList(tail, *ident);
@@ -780,11 +887,14 @@ template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBu
return context.createFunctionBody();
}
-template <JSParser::FunctionRequirements requirements, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
+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();
if (match(IDENT)) {
name = m_token.m_data.ident;
next();
+ if (!nameIsInContainingScope)
+ functionScope->declareVariable(name);
} else if (requirements == FunctionNeedsName)
return false;
consumeOrFail(OPENPAREN);
@@ -804,7 +914,7 @@ template <JSParser::FunctionRequirements requirements, class TreeBuilder> bool J
failIfFalse(body);
if (usesArguments)
context.setUsesArguments(body);
-
+ popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo);
matchOrFail(CLOSEBRACE);
closeBracePos = m_token.m_data.intValue;
next();
@@ -821,8 +931,9 @@ template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(Tr
int openBracePos = 0;
int closeBracePos = 0;
int bodyStartLine = 0;
- failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine));
+ failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
failIfFalse(name);
+ currentScope()->declareVariable(name);
return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
}
@@ -1113,7 +1224,7 @@ template <bool complete, class TreeBuilder> TreeProperty JSParser::parseProperty
type = PropertyNode::Setter;
else
fail();
- failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine));
+ failIfFalse((parseFunctionInfo<FunctionNeedsName, false>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
return context.template createGetterOrSetterProperty<complete>(type, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
}
case NUMBER: {
@@ -1281,6 +1392,7 @@ template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(Tre
int start = tokenStart();
const Identifier* ident = m_token.m_data.ident;
next();
+ currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident);
return context.createResolve(ident, start);
}
case STRING: {
@@ -1364,7 +1476,7 @@ template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(Tree
int closeBracePos = 0;
int bodyStartLine = 0;
next();
- failIfFalse(parseFunctionInfo<FunctionNoRequirements>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine));
+ failIfFalse((parseFunctionInfo<FunctionNoRequirements, false>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
base = context.createFunctionExpr(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
} else
base = parsePrimaryExpression(context);