Commit a89f68c6 authored by marja@chromium.org's avatar marja@chromium.org

Move ParseAssignmentExpression to ParserBase.

R=mstarzinger@chromium.org, mstarzinger
BUG=v8:3126
LOG=N

Committed: https://code.google.com/p/v8/source/detail?r=19908

Review URL: https://codereview.chromium.org/197653002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19920 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent dd28969c
......@@ -437,6 +437,59 @@ bool ParserTraits::IsEvalOrArguments(Handle<String> identifier) const {
}
bool ParserTraits::IsThisProperty(Expression* expression) {
ASSERT(expression != NULL);
Property* property = expression->AsProperty();
return property != NULL &&
property->obj()->AsVariableProxy() != NULL &&
property->obj()->AsVariableProxy()->is_this();
}
void ParserTraits::CheckAssigningFunctionLiteralToProperty(Expression* left,
Expression* right) {
ASSERT(left != NULL);
if (left->AsProperty() != NULL &&
right->AsFunctionLiteral() != NULL) {
right->AsFunctionLiteral()->set_pretenure();
}
}
Expression* ParserTraits::ValidateAssignmentLeftHandSide(
Expression* expression) const {
ASSERT(expression != NULL);
if (!expression->IsValidLeftHandSide()) {
Handle<String> message =
parser_->isolate()->factory()->invalid_lhs_in_assignment_string();
expression = parser_->NewThrowReferenceError(message);
}
return expression;
}
Expression* ParserTraits::MarkExpressionAsLValue(Expression* expression) {
VariableProxy* proxy = expression != NULL
? expression->AsVariableProxy()
: NULL;
if (proxy != NULL) proxy->MarkAsLValue();
return expression;
}
void ParserTraits::CheckStrictModeLValue(Expression* expression,
bool* ok) {
VariableProxy* lhs = expression != NULL
? expression->AsVariableProxy()
: NULL;
if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
parser_->ReportMessage("strict_eval_arguments",
Vector<const char*>::empty());
*ok = false;
}
}
void ParserTraits::ReportMessageAt(Scanner::Location source_location,
const char* message,
Vector<const char*> args) {
......@@ -566,11 +619,6 @@ Literal* ParserTraits::GetLiteralTheHole(
}
Expression* ParserTraits::ParseAssignmentExpression(bool accept_IN, bool* ok) {
return parser_->ParseAssignmentExpression(accept_IN, ok);
}
Expression* ParserTraits::ParseV8Intrinsic(bool* ok) {
return parser_->ParseV8Intrinsic(ok);
}
......@@ -590,6 +638,16 @@ FunctionLiteral* ParserTraits::ParseFunctionLiteral(
}
Expression* ParserTraits::ParseYieldExpression(bool* ok) {
return parser_->ParseYieldExpression(ok);
}
Expression* ParserTraits::ParseConditionalExpression(bool accept_IN, bool* ok) {
return parser_->ParseConditionalExpression(accept_IN, ok);
}
Parser::Parser(CompilationInfo* info)
: ParserBase<ParserTraits>(&scanner_,
info->isolate()->stack_guard()->real_climit(),
......@@ -2877,85 +2935,6 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
}
// Precedence = 2
Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
// AssignmentExpression ::
// ConditionalExpression
// YieldExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression
if (peek() == Token::YIELD && is_generator()) {
return ParseYieldExpression(ok);
}
if (fni_ != NULL) fni_->Enter();
Expression* expression = ParseConditionalExpression(accept_IN, CHECK_OK);
if (!Token::IsAssignmentOp(peek())) {
if (fni_ != NULL) fni_->Leave();
// Parsed conditional expression only (no assignment).
return expression;
}
// Signal a reference error if the expression is an invalid left-hand
// side expression. We could report this as a syntax error here but
// for compatibility with JSC we choose to report the error at
// runtime.
// TODO(ES5): Should change parsing for spec conformance.
if (expression == NULL || !expression->IsValidLeftHandSide()) {
Handle<String> message =
isolate()->factory()->invalid_lhs_in_assignment_string();
expression = NewThrowReferenceError(message);
}
if (strict_mode() == STRICT) {
// Assignment to eval or arguments is disallowed in strict mode.
CheckStrictModeLValue(expression, CHECK_OK);
}
MarkAsLValue(expression);
Token::Value op = Next(); // Get assignment operator.
int pos = position();
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
// TODO(1231235): We try to estimate the set of properties set by
// constructors. We define a new property whenever there is an
// assignment to a property of 'this'. We should probably only add
// properties if we haven't seen them before. Otherwise we'll
// probably overestimate the number of properties.
Property* property = expression ? expression->AsProperty() : NULL;
if (op == Token::ASSIGN &&
property != NULL &&
property->obj()->AsVariableProxy() != NULL &&
property->obj()->AsVariableProxy()->is_this()) {
function_state_->AddProperty();
}
// If we assign a function literal to a property we pretenure the
// literal so it can be added as a constant function property.
if (property != NULL && right->AsFunctionLiteral() != NULL) {
right->AsFunctionLiteral()->set_pretenure();
}
if (fni_ != NULL) {
// Check if the right hand side is a call to avoid inferring a
// name if we're dealing with "a = function(){...}();"-like
// expression.
if ((op == Token::INIT_VAR
|| op == Token::INIT_CONST_LEGACY
|| op == Token::ASSIGN)
&& (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
fni_->Infer();
} else {
fni_->RemoveLastFunction();
}
fni_->Leave();
}
return factory()->NewAssignment(op, expression, right, pos);
}
Expression* Parser::ParseYieldExpression(bool* ok) {
// YieldExpression ::
// 'yield' '*'? AssignmentExpression
......@@ -3184,7 +3163,7 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
// Prefix expression operand in strict mode may not be eval or arguments.
CheckStrictModeLValue(expression, CHECK_OK);
}
MarkAsLValue(expression);
MarkExpressionAsLValue(expression);
return factory()->NewCountOperation(op,
true /* prefix */,
......@@ -3218,7 +3197,7 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
// Postfix expression operand in strict mode may not be eval or arguments.
CheckStrictModeLValue(expression, CHECK_OK);
}
MarkAsLValue(expression);
MarkExpressionAsLValue(expression);
Token::Value next = Next();
expression =
......@@ -3974,31 +3953,6 @@ Literal* Parser::GetLiteralUndefined(int position) {
}
void Parser::MarkAsLValue(Expression* expression) {
VariableProxy* proxy = expression != NULL
? expression->AsVariableProxy()
: NULL;
if (proxy != NULL) proxy->MarkAsLValue();
}
// Checks LHS expression for assignment and prefix/postfix increment/decrement
// in strict mode.
void Parser::CheckStrictModeLValue(Expression* expression,
bool* ok) {
ASSERT(strict_mode() == STRICT);
VariableProxy* lhs = expression != NULL
? expression->AsVariableProxy()
: NULL;
if (lhs != NULL && !lhs->is_this() && IsEvalOrArguments(lhs->name())) {
ReportMessage("strict_eval_arguments", Vector<const char*>::empty());
*ok = false;
}
}
void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) {
Declaration* decl = scope->CheckConflictingVarDeclarations();
if (decl != NULL) {
......
......@@ -452,6 +452,9 @@ class ParserTraits {
// Helper functions for recursive descent.
bool IsEvalOrArguments(Handle<String> identifier) const;
// Returns true if the expression is of type "this.foo".
static bool IsThisProperty(Expression* expression);
static bool IsBoilerplateProperty(ObjectLiteral::Property* property) {
return ObjectLiteral::IsBoilerplateProperty(property);
}
......@@ -460,6 +463,8 @@ class ParserTraits {
return !string.is_null() && string->AsArrayIndex(index);
}
// Functions for encapsulating the differences between parsing and preparsing;
// operations interleaved with the recursive descent.
static void PushLiteralName(FuncNameInferrer* fni, Handle<String> id) {
fni->PushLiteralName(id);
}
......@@ -473,6 +478,25 @@ class ParserTraits {
}
}
// If we assign a function literal to a property we pretenure the
// literal so it can be added as a constant function property.
static void CheckAssigningFunctionLiteralToProperty(Expression* left,
Expression* right);
// Signal a reference error if the expression is an invalid left-hand side
// expression. We could report this as a syntax error but for compatibility
// with JSC we choose to report the error at runtime.
Expression* ValidateAssignmentLeftHandSide(Expression* expression) const;
// Determine if the expression is a variable proxy and mark it as being used
// in an assignment or with a increment/decrement operator. This is currently
// used on for the statically checking assignments to harmony const bindings.
static Expression* MarkExpressionAsLValue(Expression* expression);
// Checks LHS expression for assignment and prefix/postfix increment/decrement
// in strict mode.
void CheckStrictModeLValue(Expression*expression, bool* ok);
// Reporting errors.
void ReportMessageAt(Scanner::Location source_location,
const char* message,
......@@ -523,7 +547,6 @@ class ParserTraits {
}
// Temporary glue; these functions will move to ParserBase.
Expression* ParseAssignmentExpression(bool accept_IN, bool* ok);
Expression* ParseV8Intrinsic(bool* ok);
FunctionLiteral* ParseFunctionLiteral(
Handle<String> name,
......@@ -533,6 +556,8 @@ class ParserTraits {
int function_token_position,
FunctionLiteral::FunctionType type,
bool* ok);
Expression* ParseYieldExpression(bool* ok);
Expression* ParseConditionalExpression(bool accept_IN, bool* ok);
private:
Parser* parser_;
......@@ -675,7 +700,6 @@ class Parser : public ParserBase<ParserTraits> {
// Support for hamony block scoped bindings.
Block* ParseScopedBlock(ZoneStringList* labels, bool* ok);
Expression* ParseAssignmentExpression(bool accept_IN, bool* ok);
Expression* ParseYieldExpression(bool* ok);
Expression* ParseConditionalExpression(bool accept_IN, bool* ok);
Expression* ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
......@@ -711,15 +735,6 @@ class Parser : public ParserBase<ParserTraits> {
// Get odd-ball literals.
Literal* GetLiteralUndefined(int position);
// Determine if the expression is a variable proxy and mark it as being used
// in an assignment or with a increment/decrement operator. This is currently
// used on for the statically checking assignments to harmony const bindings.
void MarkAsLValue(Expression* expression);
// Strict mode validation of LValue expressions
void CheckStrictModeLValue(Expression* expression,
bool* ok);
// For harmony block scoping mode: Check if the scope has conflicting var/let
// declarations from different scopes. It covers for example
//
......
......@@ -55,6 +55,18 @@ int isfinite(double value);
namespace v8 {
namespace internal {
void PreParserTraits::CheckStrictModeLValue(PreParserExpression expression,
bool* ok) {
if (expression.IsIdentifier() &&
expression.AsIdentifier().IsEvalOrArguments()) {
pre_parser_->ReportMessage("strict_eval_arguments",
Vector<const char*>::empty());
*ok = false;
}
}
void PreParserTraits::ReportMessageAt(Scanner::Location location,
const char* message,
Vector<const char*> args) {
......@@ -111,12 +123,6 @@ PreParserExpression PreParserTraits::ExpressionFromString(
}
PreParserExpression PreParserTraits::ParseAssignmentExpression(bool accept_IN,
bool* ok) {
return pre_parser_->ParseAssignmentExpression(accept_IN, ok);
}
PreParserExpression PreParserTraits::ParseV8Intrinsic(bool* ok) {
return pre_parser_->ParseV8Intrinsic(ok);
}
......@@ -136,6 +142,17 @@ PreParserExpression PreParserTraits::ParseFunctionLiteral(
}
PreParserExpression PreParserTraits::ParseYieldExpression(bool* ok) {
return pre_parser_->ParseYieldExpression(ok);
}
PreParserExpression PreParserTraits::ParseConditionalExpression(bool accept_IN,
bool* ok) {
return pre_parser_->ParseConditionalExpression(accept_IN, ok);
}
PreParser::PreParseResult PreParser::PreParseLazyFunction(
StrictMode strict_mode, bool is_generator, ParserRecorder* log) {
log_ = log;
......@@ -827,47 +844,6 @@ PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) {
#undef DUMMY
// Precedence = 2
PreParser::Expression PreParser::ParseAssignmentExpression(bool accept_IN,
bool* ok) {
// AssignmentExpression ::
// ConditionalExpression
// YieldExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression
if (function_state_->is_generator() && peek() == Token::YIELD) {
return ParseYieldExpression(ok);
}
Scanner::Location before = scanner()->peek_location();
Expression expression = ParseConditionalExpression(accept_IN, CHECK_OK);
if (!Token::IsAssignmentOp(peek())) {
// Parsed conditional expression only (no assignment).
return expression;
}
if (strict_mode() == STRICT &&
expression.IsIdentifier() &&
expression.AsIdentifier().IsEvalOrArguments()) {
Scanner::Location after = scanner()->location();
PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
"strict_eval_arguments", NULL);
*ok = false;
return Expression::Default();
}
Token::Value op = Next(); // Get assignment operator.
ParseAssignmentExpression(accept_IN, CHECK_OK);
if ((op == Token::ASSIGN) && expression.IsThisProperty()) {
function_state_->AddProperty();
}
return Expression::Default();
}
// Precedence = 3
PreParser::Expression PreParser::ParseYieldExpression(bool* ok) {
// YieldExpression ::
......@@ -939,15 +915,9 @@ PreParser::Expression PreParser::ParseUnaryExpression(bool* ok) {
return Expression::Default();
} else if (Token::IsCountOp(op)) {
op = Next();
Scanner::Location before = scanner()->peek_location();
Expression expression = ParseUnaryExpression(CHECK_OK);
if (strict_mode() == STRICT &&
expression.IsIdentifier() &&
expression.AsIdentifier().IsEvalOrArguments()) {
Scanner::Location after = scanner()->location();
PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
"strict_eval_arguments", NULL);
*ok = false;
if (strict_mode() == STRICT) {
CheckStrictModeLValue(expression, CHECK_OK);
}
return Expression::Default();
} else {
......@@ -960,18 +930,11 @@ PreParser::Expression PreParser::ParsePostfixExpression(bool* ok) {
// PostfixExpression ::
// LeftHandSideExpression ('++' | '--')?
Scanner::Location before = scanner()->peek_location();
Expression expression = ParseLeftHandSideExpression(CHECK_OK);
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
Token::IsCountOp(peek())) {
if (strict_mode() == STRICT &&
expression.IsIdentifier() &&
expression.AsIdentifier().IsEvalOrArguments()) {
Scanner::Location after = scanner()->location();
PreParserTraits::ReportMessageAt(before.beg_pos, after.end_pos,
"strict_eval_arguments", NULL);
*ok = false;
return Expression::Default();
if (strict_mode() == STRICT) {
CheckStrictModeLValue(expression, CHECK_OK);
}
Next();
return Expression::Default();
......
......@@ -382,6 +382,8 @@ class ParserBase : public Traits {
typename Traits::Type::Expression ParseArrayLiteral(bool* ok);
typename Traits::Type::Expression ParseObjectLiteral(bool* ok);
typename Traits::Type::ExpressionList ParseArguments(bool* ok);
typename Traits::Type::Expression ParseAssignmentExpression(bool accept_IN,
bool* ok);
// Used to detect duplicates in object literals. Each of the values
// kGetterProperty, kSetterProperty and kValueProperty represents
......@@ -564,6 +566,14 @@ class PreParserExpression {
bool IsStrictFunction() { return code_ == kStrictFunctionExpression; }
// Dummy implementation for making expression->AsCall() work (see below).
PreParserExpression* operator->() { return this; }
// These are only used when doing function name inferring, and PreParser
// doesn't do function name inferring.
void* AsCall() const { return NULL; }
void* AsCallNew() const { return NULL; }
private:
// First two/three bits are used as flags.
// Bit 0 and 1 represent identifiers or strings literals, and are
......@@ -683,6 +693,13 @@ class PreParserFactory {
int pos) {
return PreParserExpression::Default();
}
PreParserExpression NewAssignment(Token::Value op,
PreParserExpression left,
PreParserExpression right,
int pos) {
return PreParserExpression::Default();
}
};
......@@ -729,6 +746,11 @@ class PreParserTraits {
return identifier.IsEvalOrArguments();
}
// Returns true if the expression is of type "this.foo".
static bool IsThisProperty(PreParserExpression expression) {
return expression.IsThisProperty();
}
static bool IsBoilerplateProperty(PreParserExpression property) {
// PreParser doesn't count boilerplate properties.
return false;
......@@ -738,6 +760,8 @@ class PreParserTraits {
return false;
}
// Functions for encapsulating the differences between parsing and preparsing;
// operations interleaved with the recursive descent.
static void PushLiteralName(FuncNameInferrer* fni, PreParserIdentifier id) {
// PreParser should not use FuncNameInferrer.
ASSERT(false);
......@@ -746,6 +770,29 @@ class PreParserTraits {
static void CheckFunctionLiteralInsideTopLevelObjectLiteral(
PreParserScope* scope, PreParserExpression value, bool* has_function) {}
static void CheckAssigningFunctionLiteralToProperty(
PreParserExpression left, PreParserExpression right) {}
static PreParserExpression ValidateAssignmentLeftHandSide(
PreParserExpression expression) {
// Parser generates a runtime error here if the left hand side is not valid.
// PreParser doesn't have to.
return expression;
}
static PreParserExpression MarkExpressionAsLValue(
PreParserExpression expression) {
// TODO(marja): To be able to produce the same errors, the preparser needs
// to start tracking which expressions are variables and which are lvalues.
return expression;
}
// Checks LHS expression for assignment and prefix/postfix increment/decrement
// in strict mode.
void CheckStrictModeLValue(PreParserExpression expression, bool* ok);
// Reporting errors.
void ReportMessageAt(Scanner::Location location,
const char* message,
......@@ -815,7 +862,6 @@ class PreParserTraits {
}
// Temporary glue; these functions will move to ParserBase.
PreParserExpression ParseAssignmentExpression(bool accept_IN, bool* ok);
PreParserExpression ParseV8Intrinsic(bool* ok);
PreParserExpression ParseFunctionLiteral(
PreParserIdentifier name,
......@@ -825,6 +871,8 @@ class PreParserTraits {
int function_token_position,
FunctionLiteral::FunctionType type,
bool* ok);
PreParserExpression ParseYieldExpression(bool* ok);
PreParserExpression ParseConditionalExpression(bool accept_IN, bool* ok);
private:
PreParser* pre_parser_;
......@@ -989,8 +1037,6 @@ class PreParser : public ParserBase<PreParserTraits> {
Statement ParseThrowStatement(bool* ok);
Statement ParseTryStatement(bool* ok);
Statement ParseDebuggerStatement(bool* ok);
Expression ParseAssignmentExpression(bool accept_IN, bool* ok);
Expression ParseYieldExpression(bool* ok);
Expression ParseConditionalExpression(bool accept_IN, bool* ok);
Expression ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
......@@ -1537,6 +1583,75 @@ typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
return result;
}
// Precedence = 2
template <class Traits>
typename Traits::Type::Expression ParserBase<Traits>::ParseAssignmentExpression(
bool accept_IN, bool* ok) {
// AssignmentExpression ::
// ConditionalExpression
// YieldExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression
if (peek() == Token::YIELD && is_generator()) {
return this->ParseYieldExpression(ok);
}
if (fni_ != NULL) fni_->Enter();
typename Traits::Type::Expression expression =
this->ParseConditionalExpression(accept_IN, CHECK_OK);
if (!Token::IsAssignmentOp(peek())) {
if (fni_ != NULL) fni_->Leave();
// Parsed conditional expression only (no assignment).
return expression;
}
// Signal a reference error if the expression is an invalid left-hand
// side expression. We could report this as a syntax error here but
// for compatibility with JSC we choose to report the error at
// runtime.
// TODO(ES5): Should change parsing for spec conformance.
expression = this->ValidateAssignmentLeftHandSide(expression);
if (strict_mode() == STRICT) {
// Assignment to eval or arguments is disallowed in strict mode.
this->CheckStrictModeLValue(expression, CHECK_OK);
}
expression = this->MarkExpressionAsLValue(expression);
Token::Value op = Next(); // Get assignment operator.
int pos = position();
typename Traits::Type::Expression right =
this->ParseAssignmentExpression(accept_IN, CHECK_OK);
// TODO(1231235): We try to estimate the set of properties set by
// constructors. We define a new property whenever there is an
// assignment to a property of 'this'. We should probably only add
// properties if we haven't seen them before. Otherwise we'll
// probably overestimate the number of properties.
if (op == Token::ASSIGN && this->IsThisProperty(expression)) {
function_state_->AddProperty();
}
this->CheckAssigningFunctionLiteralToProperty(expression, right);
if (fni_ != NULL) {
// Check if the right hand side is a call to avoid inferring a
// name if we're dealing with "a = function(){...}();"-like
// expression.
if ((op == Token::INIT_VAR
|| op == Token::INIT_CONST_LEGACY
|| op == Token::ASSIGN)
&& (right->AsCall() == NULL && right->AsCallNew() == NULL)) {
fni_->Infer();
} else {
fni_->RemoveLastFunction();
}
fni_->Leave();
}
return factory()->NewAssignment(op, expression, right, pos);
}
#undef CHECK_OK
#undef CHECK_OK_CUSTOM
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment