public:
DECLARE_NODE_TYPE(VariableProxy)
- bool IsValidReferenceExpression() const override { return !is_this(); }
+ bool IsValidReferenceExpression() const override {
+ return !is_this() && !is_new_target();
+ }
bool IsArguments() const { return is_resolved() && var()->is_arguments(); }
bit_field_ = IsResolvedField::update(bit_field_, true);
}
+ bool is_new_target() const { return IsNewTargetField::decode(bit_field_); }
+ void set_is_new_target() {
+ bit_field_ = IsNewTargetField::update(bit_field_, true);
+ }
+
int end_position() const { return end_position_; }
// Bind this proxy to the variable var.
class IsThisField : public BitField8<bool, 0, 1> {};
class IsAssignedField : public BitField8<bool, 1, 1> {};
class IsResolvedField : public BitField8<bool, 2, 1> {};
+ class IsNewTargetField : public BitField8<bool, 3, 1> {};
// Start with 16-bit (or smaller) field, which should get packed together
// with Expression's trailing 16-bit field.
AstNodeFactory* factory,
int pos) {
static const int kNewTargetStringLength = 10;
- return scope->NewUnresolved(
+ auto proxy = scope->NewUnresolved(
factory, parser_->ast_value_factory()->new_target_string(),
Variable::NORMAL, pos, pos + kNewTargetStringLength);
+ proxy->set_is_new_target();
+ return proxy;
}
CHECK_OK);
}
} else {
- Scanner::Location lhs_location = scanner()->peek_location();
+ int lhs_beg_pos = peek_position();
Expression* expression = ParseExpression(false, CHECK_OK);
+ int lhs_end_pos = scanner()->location().end_pos;
ForEachStatement::VisitMode mode;
bool accept_OF = expression->IsVariableProxy();
is_let_identifier_expression =
if (CheckInOrOf(accept_OF, &mode, ok)) {
if (!*ok) return nullptr;
expression = this->CheckAndRewriteReferenceExpression(
- expression, lhs_location, MessageTemplate::kInvalidLhsInFor,
- CHECK_OK);
+ expression, lhs_beg_pos, lhs_end_pos,
+ MessageTemplate::kInvalidLhsInFor, CHECK_OK);
ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, stmt_pos);
return loop;
} else {
- init =
- factory()->NewExpressionStatement(expression, lhs_location.beg_pos);
+ init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
}
}
}
lhs.IsIdentifier() && lhs.AsIdentifier().IsLet();
if (CheckInOrOf(lhs.IsIdentifier(), &mode, ok)) {
if (!*ok) return Statement::Default();
+ // TODO(adamk): Should call CheckAndRewriteReferenceExpression here
+ // to catch early errors if lhs is not a valid reference expression.
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
ParseSubStatement(CHECK_OK);
// left-hand side of assignments). Although ruled out by ECMA as early errors,
// we allow calls for web compatibility and rewrite them to a runtime throw.
ExpressionT CheckAndRewriteReferenceExpression(
- ExpressionT expression, Scanner::Location location,
+ ExpressionT expression, int beg_pos, int end_pos,
MessageTemplate::Template message, bool* ok);
// Used to validate property names in object literals and class literals
// YieldExpression
// LeftHandSideExpression AssignmentOperator AssignmentExpression
- Scanner::Location lhs_location = scanner()->peek_location();
+ int lhs_beg_pos = peek_position();
if (peek() == Token::YIELD && is_generator()) {
return this->ParseYieldExpression(classifier, ok);
BindingPatternUnexpectedToken(classifier);
ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
parenthesized_formals, CHECK_OK);
- Scanner::Location loc(lhs_location.beg_pos, scanner()->location().end_pos);
+ Scanner::Location loc(lhs_beg_pos, scanner()->location().end_pos);
Scope* scope =
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
FormalParametersT parameters(scope);
checkpoint.Restore(¶meters.materialized_literals_count);
- scope->set_start_position(lhs_location.beg_pos);
+ scope->set_start_position(lhs_beg_pos);
Scanner::Location duplicate_loc = Scanner::Location::invalid();
this->ParseArrowFunctionFormalParameterList(¶meters, expression, loc,
&duplicate_loc, CHECK_OK);
}
expression = this->CheckAndRewriteReferenceExpression(
- expression, lhs_location, MessageTemplate::kInvalidLhsInAssignment,
- CHECK_OK);
+ expression, lhs_beg_pos, scanner()->location().end_pos,
+ MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
expression = this->MarkExpressionAsAssigned(expression);
Token::Value op = Next(); // Get assignment operator.
} else if (Token::IsCountOp(op)) {
BindingPatternUnexpectedToken(classifier);
op = Next();
- Scanner::Location lhs_location = scanner()->peek_location();
+ int beg_pos = peek_position();
ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK);
expression = this->CheckAndRewriteReferenceExpression(
- expression, lhs_location, MessageTemplate::kInvalidLhsInPrefixOp,
- CHECK_OK);
+ expression, beg_pos, scanner()->location().end_pos,
+ MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
this->MarkExpressionAsAssigned(expression);
return factory()->NewCountOperation(op,
// PostfixExpression ::
// LeftHandSideExpression ('++' | '--')?
- Scanner::Location lhs_location = scanner()->peek_location();
+ int lhs_beg_pos = peek_position();
ExpressionT expression =
this->ParseLeftHandSideExpression(classifier, CHECK_OK);
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
BindingPatternUnexpectedToken(classifier);
expression = this->CheckAndRewriteReferenceExpression(
- expression, lhs_location, MessageTemplate::kInvalidLhsInPostfixOp,
- CHECK_OK);
+ expression, lhs_beg_pos, scanner()->location().end_pos,
+ MessageTemplate::kInvalidLhsInPostfixOp, CHECK_OK);
expression = this->MarkExpressionAsAssigned(expression);
Token::Value next = Next();
template <typename Traits>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::CheckAndRewriteReferenceExpression(
- ExpressionT expression, Scanner::Location location,
+ ExpressionT expression, int beg_pos, int end_pos,
MessageTemplate::Template message, bool* ok) {
+ Scanner::Location location(beg_pos, end_pos);
if (this->IsIdentifier(expression)) {
if (is_strict(language_mode()) &&
this->IsEvalOrArguments(this->AsIdentifier(expression))) {
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-new-target
+
+function f() { new.target = 5 }
--- /dev/null
+*%(basename)s:7: ReferenceError: Invalid left-hand side in assignment
+function f() { new.target = 5 }
+ ^^^^^^^^^^
+ReferenceError: Invalid left-hand side in assignment
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-new-target
+
+function f() { for (new.target in {}); }
--- /dev/null
+*%(basename)s:7: ReferenceError: Invalid left-hand side in for-loop
+function f() { for (new.target in {}); }
+ ^^^^^^^^^^
+ReferenceError: Invalid left-hand side in for-loop
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-new-target
+
+function f() { new.target++ }
--- /dev/null
+*%(basename)s:7: ReferenceError: Invalid left-hand side expression in postfix operation
+function f() { new.target++ }
+ ^^^^^^^^^^
+ReferenceError: Invalid left-hand side expression in postfix operation
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --harmony-new-target
+
+function f() { ++new.target }
--- /dev/null
+*%(basename)s:7: ReferenceError: Invalid left-hand side expression in prefix operation
+function f() { ++new.target }
+ ^^^^^^^^^^
+ReferenceError: Invalid left-hand side expression in prefix operation
function f6() { with ({'new.target': 42}) return new.target }
assertSame(f6, new f6);
})();
+
+
+(function TestEarlyErrors() {
+ assertThrows(function() { Function("new.target = 42"); }, ReferenceError);
+ assertThrows(function() { Function("var foo = 1; new.target = foo = 42"); }, ReferenceError);
+ assertThrows(function() { Function("var foo = 1; foo = new.target = 42"); }, ReferenceError);
+ assertThrows(function() { Function("new.target--"); }, ReferenceError);
+ assertThrows(function() { Function("--new.target"); }, ReferenceError);
+ assertThrows(function() { Function("(new.target)++"); }, ReferenceError);
+ assertThrows(function() { Function("++(new.target)"); }, ReferenceError);
+ assertThrows(function() { Function("for (new.target of {});"); }, ReferenceError);
+})();