From a89f68c6cd04aa4bfb367c4a7d7ed356c3509e25 Mon Sep 17 00:00:00 2001 From: "marja@chromium.org" Date: Fri, 14 Mar 2014 09:43:04 +0000 Subject: [PATCH] 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 --- src/parser.cc | 176 ++++++++++++++++++++----------------------------------- src/parser.h | 37 ++++++++---- src/preparser.cc | 91 +++++++++------------------- src/preparser.h | 121 +++++++++++++++++++++++++++++++++++++- 4 files changed, 236 insertions(+), 189 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index bdd9348..e746ed4 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -437,6 +437,59 @@ bool ParserTraits::IsEvalOrArguments(Handle 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 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::empty()); + *ok = false; + } +} + + void ParserTraits::ReportMessageAt(Scanner::Location source_location, const char* message, Vector 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(&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 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::empty()); - *ok = false; - } -} - - void Parser::CheckConflictingVarDeclarations(Scope* scope, bool* ok) { Declaration* decl = scope->CheckConflictingVarDeclarations(); if (decl != NULL) { diff --git a/src/parser.h b/src/parser.h index 073d64b..966dcaa 100644 --- a/src/parser.h +++ b/src/parser.h @@ -452,6 +452,9 @@ class ParserTraits { // Helper functions for recursive descent. bool IsEvalOrArguments(Handle 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 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 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 { // 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 { // 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 // diff --git a/src/preparser.cc b/src/preparser.cc index 652c1ba..6145834 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -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::empty()); + *ok = false; + } +} + + void PreParserTraits::ReportMessageAt(Scanner::Location location, const char* message, Vector 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(); diff --git a/src/preparser.h b/src/preparser.h index 06880d5..48bbfea 100644 --- a/src/preparser.h +++ b/src/preparser.h @@ -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 { 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::ParseArguments( return result; } +// Precedence = 2 +template +typename Traits::Type::Expression ParserBase::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 -- 2.7.4