void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- ASSERT(expr->target()->IsValidLeftHandSide());
+ ASSERT(expr->target()->IsValidReferenceExpression());
Comment cmnt(masm_, "[ Assignment");
void FullCodeGenerator::EmitAssignment(Expression* expr) {
- ASSERT(expr->IsValidLeftHandSide());
+ ASSERT(expr->IsValidReferenceExpression());
// Left-hand side can only be a property, a global or a (parameter or local)
// slot.
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- ASSERT(expr->expression()->IsValidLeftHandSide());
+ ASSERT(expr->expression()->IsValidReferenceExpression());
Comment cmnt(masm_, "[ CountOperation");
SetSourcePosition(expr->position());
void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- ASSERT(expr->target()->IsValidLeftHandSide());
+ ASSERT(expr->target()->IsValidReferenceExpression());
Comment cmnt(masm_, "[ Assignment");
void FullCodeGenerator::EmitAssignment(Expression* expr) {
- ASSERT(expr->IsValidLeftHandSide());
+ ASSERT(expr->IsValidReferenceExpression());
// Left-hand side can only be a property, a global or a (parameter or local)
// slot.
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- ASSERT(expr->expression()->IsValidLeftHandSide());
+ ASSERT(expr->expression()->IsValidReferenceExpression());
Comment cmnt(masm_, "[ CountOperation");
SetSourcePosition(expr->position());
// Implementation of other node functionality.
-bool Expression::IsSmiLiteral() {
+bool Expression::IsSmiLiteral() const {
return AsLiteral() != NULL && AsLiteral()->value()->IsSmi();
}
-bool Expression::IsStringLiteral() {
+bool Expression::IsStringLiteral() const {
return AsLiteral() != NULL && AsLiteral()->value()->IsString();
}
-bool Expression::IsNullLiteral() {
+bool Expression::IsNullLiteral() const {
return AsLiteral() != NULL && AsLiteral()->value()->IsNull();
}
-bool Expression::IsUndefinedLiteral(Isolate* isolate) {
- VariableProxy* var_proxy = AsVariableProxy();
+bool Expression::IsUndefinedLiteral(Isolate* isolate) const {
+ const VariableProxy* var_proxy = AsVariableProxy();
if (var_proxy == NULL) return false;
Variable* var = var_proxy->var();
// The global identifier "undefined" is immutable. Everything
}
-bool BinaryOperation::ResultOverwriteAllowed() {
+bool BinaryOperation::ResultOverwriteAllowed() const {
switch (op_) {
case Token::COMMA:
case Token::OR:
int position() const { return position_; }
// Type testing & conversion functions overridden by concrete subclasses.
-#define DECLARE_NODE_FUNCTIONS(type) \
- bool Is##type() { return node_type() == AstNode::k##type; } \
- type* As##type() { return Is##type() ? reinterpret_cast<type*>(this) : NULL; }
+#define DECLARE_NODE_FUNCTIONS(type) \
+ bool Is##type() const { return node_type() == AstNode::k##type; } \
+ type* As##type() { \
+ return Is##type() ? reinterpret_cast<type*>(this) : NULL; \
+ } \
+ const type* As##type() const { \
+ return Is##type() ? reinterpret_cast<const type*>(this) : NULL; \
+ }
AST_NODE_LIST(DECLARE_NODE_FUNCTIONS)
#undef DECLARE_NODE_FUNCTIONS
kTest
};
- virtual bool IsValidLeftHandSide() { return false; }
+ virtual bool IsValidReferenceExpression() const { return false; }
// Helpers for ToBoolean conversion.
- virtual bool ToBooleanIsTrue() { return false; }
- virtual bool ToBooleanIsFalse() { return false; }
+ virtual bool ToBooleanIsTrue() const { return false; }
+ virtual bool ToBooleanIsFalse() const { return false; }
// Symbols that cannot be parsed as array indices are considered property
// names. We do not treat symbols that can be array indexes as property
// names because [] for string objects is handled only by keyed ICs.
- virtual bool IsPropertyName() { return false; }
+ virtual bool IsPropertyName() const { return false; }
// True iff the result can be safely overwritten (to avoid allocation).
// False for operations that can return one of their operands.
- virtual bool ResultOverwriteAllowed() { return false; }
+ virtual bool ResultOverwriteAllowed() const { return false; }
// True iff the expression is a literal represented as a smi.
- bool IsSmiLiteral();
+ bool IsSmiLiteral() const;
// True iff the expression is a string literal.
- bool IsStringLiteral();
+ bool IsStringLiteral() const;
// True iff the expression is the null literal.
- bool IsNullLiteral();
+ bool IsNullLiteral() const;
// True if we can prove that the expression is the undefined literal.
- bool IsUndefinedLiteral(Isolate* isolate);
+ bool IsUndefinedLiteral(Isolate* isolate) const;
// Expression type bounds
- Bounds bounds() { return bounds_; }
+ Bounds bounds() const { return bounds_; }
void set_bounds(Bounds bounds) { bounds_ = bounds; }
// Type feedback information for assignments and properties.
public:
DECLARE_NODE_TYPE(Literal)
- virtual bool IsPropertyName() V8_OVERRIDE {
+ virtual bool IsPropertyName() const V8_OVERRIDE {
if (value_->IsInternalizedString()) {
uint32_t ignored;
return !String::cast(*value_)->AsArrayIndex(&ignored);
return Handle<String>::cast(value_);
}
- virtual bool ToBooleanIsTrue() V8_OVERRIDE {
+ virtual bool ToBooleanIsTrue() const V8_OVERRIDE {
return value_->BooleanValue();
}
- virtual bool ToBooleanIsFalse() V8_OVERRIDE {
+ virtual bool ToBooleanIsFalse() const V8_OVERRIDE {
return !value_->BooleanValue();
}
public:
DECLARE_NODE_TYPE(VariableProxy)
- virtual bool IsValidLeftHandSide() V8_OVERRIDE {
- return var_ == NULL ? true : var_->IsValidLeftHandSide();
+ virtual bool IsValidReferenceExpression() const V8_OVERRIDE {
+ return var_ == NULL ? true : var_->IsValidReference();
}
- bool IsVariable(Handle<String> n) {
+ bool IsVariable(Handle<String> n) const {
return !is_this() && name().is_identical_to(n);
}
- bool IsArguments() { return var_ != NULL && var_->is_arguments(); }
+ bool IsArguments() const { return var_ != NULL && var_->is_arguments(); }
- bool IsLValue() {
- return is_lvalue_;
- }
+ bool IsLValue() const { return is_lvalue_; }
Handle<String> name() const { return name_; }
Variable* var() const { return var_; }
public:
DECLARE_NODE_TYPE(Property)
- virtual bool IsValidLeftHandSide() V8_OVERRIDE { return true; }
+ virtual bool IsValidReferenceExpression() const V8_OVERRIDE { return true; }
Expression* obj() const { return obj_; }
Expression* key() const { return key_; }
public:
DECLARE_NODE_TYPE(BinaryOperation)
- virtual bool ResultOverwriteAllowed();
+ virtual bool ResultOverwriteAllowed() const V8_OVERRIDE;
Token::Value op() const { return op_; }
Expression* left() const { return left_; }
V(MakeReferenceError_string, "MakeReferenceError") \
V(MakeSyntaxError_string, "MakeSyntaxError") \
V(MakeTypeError_string, "MakeTypeError") \
- V(illegal_return_string, "illegal_return") \
- V(illegal_break_string, "illegal_break") \
- V(illegal_continue_string, "illegal_continue") \
V(unknown_label_string, "unknown_label") \
- V(redeclaration_string, "redeclaration") \
V(space_string, " ") \
V(exec_string, "exec") \
V(zero_string, "0") \
void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- ASSERT(expr->target()->IsValidLeftHandSide());
+ ASSERT(expr->target()->IsValidReferenceExpression());
Comment cmnt(masm_, "[ Assignment");
void FullCodeGenerator::EmitAssignment(Expression* expr) {
- ASSERT(expr->IsValidLeftHandSide());
+ ASSERT(expr->IsValidReferenceExpression());
// Left-hand side can only be a property, a global or a (parameter or local)
// slot.
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- ASSERT(expr->expression()->IsValidLeftHandSide());
+ ASSERT(expr->expression()->IsValidReferenceExpression());
Comment cmnt(masm_, "[ CountOperation");
SetSourcePosition(expr->position());
// Implementation of Parser
bool ParserTraits::IsEvalOrArguments(Handle<String> identifier) const {
- return identifier.is_identical_to(
- parser_->isolate()->factory()->eval_string()) ||
- identifier.is_identical_to(
- parser_->isolate()->factory()->arguments_string());
+ Factory* factory = parser_->isolate()->factory();
+ return identifier.is_identical_to(factory->eval_string())
+ || identifier.is_identical_to(factory->arguments_string());
}
}
-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;
- }
-}
-
-
bool ParserTraits::ShortcutNumericLiteralBinaryExpression(
Expression** x, Expression* y, Token::Value op, int pos,
AstNodeFactory<AstConstructionVisitor>* factory) {
}
+Expression* ParserTraits::NewThrowReferenceError(
+ const char* message, int pos) {
+ return NewThrowError(
+ parser_->isolate()->factory()->MakeReferenceError_string(),
+ message, HandleVector<Object>(NULL, 0), pos);
+}
+
+
+Expression* ParserTraits::NewThrowSyntaxError(
+ const char* message, Handle<Object> arg, int pos) {
+ int argc = arg.is_null() ? 0 : 1;
+ Vector< Handle<Object> > arguments = HandleVector<Object>(&arg, argc);
+ return NewThrowError(
+ parser_->isolate()->factory()->MakeSyntaxError_string(),
+ message, arguments, pos);
+}
+
+
+Expression* ParserTraits::NewThrowTypeError(
+ const char* message, Handle<Object> arg1, Handle<Object> arg2, int pos) {
+ ASSERT(!arg1.is_null() && !arg2.is_null());
+ Handle<Object> elements[] = { arg1, arg2 };
+ Vector< Handle<Object> > arguments =
+ HandleVector<Object>(elements, ARRAY_SIZE(elements));
+ return NewThrowError(
+ parser_->isolate()->factory()->MakeTypeError_string(),
+ message, arguments, pos);
+}
+
+
+Expression* ParserTraits::NewThrowError(
+ Handle<String> constructor, const char* message,
+ Vector<Handle<Object> > arguments, int pos) {
+ Zone* zone = parser_->zone();
+ Factory* factory = parser_->isolate()->factory();
+ int argc = arguments.length();
+ Handle<FixedArray> elements = factory->NewFixedArray(argc, TENURED);
+ for (int i = 0; i < argc; i++) {
+ Handle<Object> element = arguments[i];
+ if (!element.is_null()) {
+ elements->set(i, *element);
+ }
+ }
+ Handle<JSArray> array =
+ factory->NewJSArrayWithElements(elements, FAST_ELEMENTS, TENURED);
+
+ ZoneList<Expression*>* args = new(zone) ZoneList<Expression*>(2, zone);
+ Handle<String> type = factory->InternalizeUtf8String(message);
+ args->Add(parser_->factory()->NewLiteral(type, pos), zone);
+ args->Add(parser_->factory()->NewLiteral(array, pos), zone);
+ CallRuntime* call_constructor =
+ parser_->factory()->NewCallRuntime(constructor, NULL, args, pos);
+ return parser_->factory()->NewThrow(call_constructor, pos);
+}
+
+
void ParserTraits::ReportMessageAt(Scanner::Location source_location,
const char* message,
Vector<const char*> args,
}
}
Handle<String> result =
- parser_->scanner()->AllocateInternalizedString(parser_->isolate_);
+ parser_->scanner()->AllocateInternalizedString(parser_->isolate());
ASSERT(!result.is_null());
return result;
}
isolate()->factory()->InternalizeOneByteString(
STATIC_ASCII_VECTOR("Variable"));
Expression* expression =
- NewThrowTypeError(isolate()->factory()->redeclaration_string(),
- message_string, name);
+ NewThrowTypeError("redeclaration",
+ message_string, name, declaration->position());
declaration_scope->SetIllegalRedeclaration(expression);
}
}
Scope* declaration_scope = scope_->DeclarationScope();
if (declaration_scope->is_global_scope() ||
declaration_scope->is_eval_scope()) {
- Handle<String> message = isolate()->factory()->illegal_return_string();
Expression* throw_error =
- NewThrowSyntaxError(message, Handle<Object>::null());
+ NewThrowSyntaxError("illegal_return", Handle<Object>::null(), pos);
return factory()->NewExpressionStatement(throw_error, pos);
}
return result;
bool accept_OF = expression->AsVariableProxy();
if (CheckInOrOf(accept_OF, &mode)) {
- if (expression == NULL || !expression->IsValidLeftHandSide()) {
- ReportMessageAt(lhs_location, "invalid_lhs_in_for", true);
- *ok = false;
- return NULL;
- }
+ expression = this->CheckAndRewriteReferenceExpression(
+ expression, lhs_location, "invalid_lhs_in_for", CHECK_OK);
+
ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, pos);
Target target(&this->target_stack_, loop);
}
-Expression* Parser::NewThrowReferenceError(Handle<String> message) {
- return NewThrowError(isolate()->factory()->MakeReferenceError_string(),
- message, HandleVector<Object>(NULL, 0));
-}
-
-
-Expression* Parser::NewThrowSyntaxError(Handle<String> message,
- Handle<Object> first) {
- int argc = first.is_null() ? 0 : 1;
- Vector< Handle<Object> > arguments = HandleVector<Object>(&first, argc);
- return NewThrowError(
- isolate()->factory()->MakeSyntaxError_string(), message, arguments);
-}
-
-
-Expression* Parser::NewThrowTypeError(Handle<String> message,
- Handle<Object> first,
- Handle<Object> second) {
- ASSERT(!first.is_null() && !second.is_null());
- Handle<Object> elements[] = { first, second };
- Vector< Handle<Object> > arguments =
- HandleVector<Object>(elements, ARRAY_SIZE(elements));
- return NewThrowError(
- isolate()->factory()->MakeTypeError_string(), message, arguments);
-}
-
-
-Expression* Parser::NewThrowError(Handle<String> constructor,
- Handle<String> message,
- Vector< Handle<Object> > arguments) {
- int argc = arguments.length();
- Handle<FixedArray> elements = isolate()->factory()->NewFixedArray(argc,
- TENURED);
- for (int i = 0; i < argc; i++) {
- Handle<Object> element = arguments[i];
- if (!element.is_null()) {
- elements->set(i, *element);
- }
- }
- Handle<JSArray> array = isolate()->factory()->NewJSArrayWithElements(
- elements, FAST_ELEMENTS, TENURED);
-
- int pos = position();
- ZoneList<Expression*>* args = new(zone()) ZoneList<Expression*>(2, zone());
- args->Add(factory()->NewLiteral(message, pos), zone());
- args->Add(factory()->NewLiteral(array, pos), zone());
- CallRuntime* call_constructor =
- factory()->NewCallRuntime(constructor, NULL, args, pos);
- return factory()->NewThrow(call_constructor, pos);
-}
-
-
// ----------------------------------------------------------------------------
// Regular expressions
static bool IsIdentifier(Expression* expression);
+ static Handle<String> AsIdentifier(Expression* expression) {
+ ASSERT(IsIdentifier(expression));
+ return expression->AsVariableProxy()->name();
+ }
+
static bool IsBoilerplateProperty(ObjectLiteral::Property* property) {
return ObjectLiteral::IsBoilerplateProperty(property);
}
// 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);
-
// Returns true if we have a binary expression between two numeric
// literals. In that case, *x will be changed to an expression which is the
// computed value.
Expression* expression, Token::Value op, int pos,
AstNodeFactory<AstConstructionVisitor>* factory);
+ // Generate AST node that throws a ReferenceError with the given type.
+ Expression* NewThrowReferenceError(const char* type, int pos);
+
+ // Generate AST node that throws a SyntaxError with the given
+ // type. The first argument may be null (in the handle sense) in
+ // which case no arguments are passed to the constructor.
+ Expression* NewThrowSyntaxError(
+ const char* type, Handle<Object> arg, int pos);
+
+ // Generate AST node that throws a TypeError with the given
+ // type. Both arguments must be non-null (in the handle sense).
+ Expression* NewThrowTypeError(
+ const char* type, Handle<Object> arg1, Handle<Object> arg2, int pos);
+
+ // Generic AST generator for throwing errors from compiled code.
+ Expression* NewThrowError(
+ Handle<String> constructor, const char* type,
+ Vector<Handle<Object> > arguments, int pos);
+
// Reporting errors.
void ReportMessageAt(Scanner::Location source_location,
const char* message,
Handle<String> LookupCachedSymbol(int symbol_id);
- // Generate AST node that throw a ReferenceError with the given type.
- Expression* NewThrowReferenceError(Handle<String> type);
-
- // Generate AST node that throw a SyntaxError with the given
- // type. The first argument may be null (in the handle sense) in
- // which case no arguments are passed to the constructor.
- Expression* NewThrowSyntaxError(Handle<String> type, Handle<Object> first);
-
- // Generate AST node that throw a TypeError with the given
- // type. Both arguments must be non-null (in the handle sense).
- Expression* NewThrowTypeError(Handle<String> type,
- Handle<Object> first,
- Handle<Object> second);
-
- // Generic AST generator for throwing errors from compiled code.
- Expression* NewThrowError(Handle<String> constructor,
- Handle<String> type,
- Vector< Handle<Object> > arguments);
-
PreParser::PreParseResult LazyParseFunctionLiteral(
SingletonLogger* logger);
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,
ExpressionT ParseMemberExpressionContinuation(ExpressionT expression,
bool* ok);
+ // Checks if the expression is a valid reference expression (e.g., on the
+ // 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, const char* message, bool* ok);
+
// Used to detect duplicates in object literals. Each of the values
// kGetterProperty, kSetterProperty and kValueProperty represents
// a type of object literal property. When parsing a property, its
return PreParserExpression(kPropertyExpression);
}
+ static PreParserExpression Call() {
+ return PreParserExpression(kCallExpression);
+ }
+
bool IsIdentifier() { return (code_ & kIdentifierFlag) != 0; }
- // Only works corretly if it is actually an identifier expression.
PreParserIdentifier AsIdentifier() {
+ ASSERT(IsIdentifier());
return PreParserIdentifier(
static_cast<PreParserIdentifier::Type>(code_ >> kIdentifierShift));
}
return code_ == kPropertyExpression || code_ == kThisPropertyExpression;
}
- bool IsValidLeftHandSide() {
+ bool IsCall() { return code_ == kCallExpression; }
+
+ bool IsValidReferenceExpression() {
return IsIdentifier() || IsProperty();
}
// At the moment PreParser doesn't track these expression types.
bool IsFunctionLiteral() const { return false; }
- bool IsCall() const { return false; }
bool IsCallNew() const { return false; }
PreParserExpression AsFunctionLiteral() { return *this; }
// 2 least significant bits for flags.
kThisExpression = 1 << 2,
kThisPropertyExpression = 2 << 2,
- kPropertyExpression = 3 << 2
+ kPropertyExpression = 3 << 2,
+ kCallExpression = 4 << 2
};
explicit PreParserExpression(int expression_code) : code_(expression_code) {}
PreParserExpression NewCall(PreParserExpression expression,
PreParserExpressionList arguments,
int pos) {
- return PreParserExpression::Default();
+ return PreParserExpression::Call();
}
PreParserExpression NewCallNew(PreParserExpression expression,
PreParserExpressionList arguments,
return expression.IsIdentifier();
}
+ static PreParserIdentifier AsIdentifier(PreParserExpression expression) {
+ return expression.AsIdentifier();
+ }
+
static bool IsBoilerplateProperty(PreParserExpression property) {
// PreParser doesn't count boilerplate properties.
return false;
return expression;
}
- // Checks LHS expression for assignment and prefix/postfix increment/decrement
- // in strict mode.
- void CheckStrictModeLValue(PreParserExpression expression, bool* ok);
-
bool ShortcutNumericLiteralBinaryExpression(PreParserExpression* x,
PreParserExpression y,
Token::Value op,
return PreParserExpression::Default();
}
+ PreParserExpression NewThrowReferenceError(const char* type, int pos) {
+ return PreParserExpression::Default();
+ }
+ PreParserExpression NewThrowSyntaxError(
+ const char* type, Handle<Object> arg, int pos) {
+ return PreParserExpression::Default();
+ }
+ PreParserExpression NewThrowTypeError(
+ const char* type, Handle<Object> arg1, Handle<Object> arg2, int pos) {
+ return PreParserExpression::Default();
+ }
+
// Reporting errors.
void ReportMessageAt(Scanner::Location location,
const char* message,
return expression;
}
- if (!expression->IsValidLeftHandSide()) {
- this->ReportMessageAt(lhs_location, "invalid_lhs_in_assignment", true);
- *ok = false;
- return this->EmptyExpression();
- }
-
- if (strict_mode() == STRICT) {
- // Assignment to eval or arguments is disallowed in strict mode.
- this->CheckStrictModeLValue(expression, CHECK_OK);
- }
+ expression = this->CheckAndRewriteReferenceExpression(
+ expression, lhs_location, "invalid_lhs_in_assignment", CHECK_OK);
expression = this->MarkExpressionAsLValue(expression);
Token::Value op = Next(); // Get assignment operator.
} else if (Token::IsCountOp(op)) {
op = Next();
Scanner::Location lhs_location = scanner()->peek_location();
- ExpressionT expression = ParseUnaryExpression(CHECK_OK);
- if (!expression->IsValidLeftHandSide()) {
- ReportMessageAt(lhs_location, "invalid_lhs_in_prefix_op", true);
- *ok = false;
- return this->EmptyExpression();
- }
-
- if (strict_mode() == STRICT) {
- // Prefix expression operand in strict mode may not be eval or arguments.
- this->CheckStrictModeLValue(expression, CHECK_OK);
- }
+ ExpressionT expression = this->ParseUnaryExpression(CHECK_OK);
+ expression = this->CheckAndRewriteReferenceExpression(
+ expression, lhs_location, "invalid_lhs_in_prefix_op", CHECK_OK);
this->MarkExpressionAsLValue(expression);
return factory()->NewCountOperation(op,
ExpressionT expression = this->ParseLeftHandSideExpression(CHECK_OK);
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
Token::IsCountOp(peek())) {
- if (!expression->IsValidLeftHandSide()) {
- ReportMessageAt(lhs_location, "invalid_lhs_in_postfix_op", true);
- *ok = false;
- return this->EmptyExpression();
- }
-
- if (strict_mode() == STRICT) {
- // Postfix expression operand in strict mode may not be eval or arguments.
- this->CheckStrictModeLValue(expression, CHECK_OK);
- }
+ expression = this->CheckAndRewriteReferenceExpression(
+ expression, lhs_location, "invalid_lhs_in_postfix_op", CHECK_OK);
expression = this->MarkExpressionAsLValue(expression);
Token::Value next = Next();
}
+template <typename Traits>
+typename ParserBase<Traits>::ExpressionT
+ParserBase<Traits>::CheckAndRewriteReferenceExpression(
+ ExpressionT expression,
+ Scanner::Location location, const char* message, bool* ok) {
+ if (strict_mode() == STRICT && this->IsIdentifier(expression) &&
+ this->IsEvalOrArguments(this->AsIdentifier(expression))) {
+ this->ReportMessageAt(location, "strict_eval_arguments", false);
+ *ok = false;
+ return this->EmptyExpression();
+ } else if (expression->IsValidReferenceExpression()) {
+ return expression;
+ } else if (expression->IsCall()) {
+ // If it is a call, make it a runtime error for legacy web compatibility.
+ // Rewrite `expr' to `expr[throw ReferenceError]'.
+ int pos = location.beg_pos;
+ ExpressionT error = this->NewThrowReferenceError(message, pos);
+ return factory()->NewProperty(expression, error, pos);
+ } else {
+ this->ReportMessageAt(location, message, true);
+ *ok = false;
+ return this->EmptyExpression();
+ }
+}
+
+
#undef CHECK_OK
#undef CHECK_OK_CUSTOM
Variable::Variable(Scope* scope,
Handle<String> name,
VariableMode mode,
- bool is_valid_LHS,
+ bool is_valid_ref,
Kind kind,
InitializationFlag initialization_flag,
Interface* interface)
index_(-1),
initializer_position_(RelocInfo::kNoPosition),
local_if_not_shadowed_(NULL),
- is_valid_LHS_(is_valid_LHS),
+ is_valid_ref_(is_valid_ref),
force_context_allocation_(false),
is_used_(false),
initialization_flag_(initialization_flag),
Variable(Scope* scope,
Handle<String> name,
VariableMode mode,
- bool is_valid_lhs,
+ bool is_valid_ref,
Kind kind,
InitializationFlag initialization_flag,
Interface* interface = Interface::NewValue());
// Printing support
static const char* Mode2String(VariableMode mode);
- bool IsValidLeftHandSide() { return is_valid_LHS_; }
+ bool IsValidReference() { return is_valid_ref_; }
// The source code for an eval() call may refer to a variable that is
// in an outer scope about which we don't know anything (it may not
// binding scope (exclusive).
Variable* local_if_not_shadowed_;
- // Valid as a LHS? (const and this are not valid LHS, for example)
- bool is_valid_LHS_;
+ // Valid as a reference? (const and this are not valid, for example)
+ bool is_valid_ref_;
// Usage info.
bool force_context_allocation_; // set by variable resolver
void FullCodeGenerator::VisitAssignment(Assignment* expr) {
- ASSERT(expr->target()->IsValidLeftHandSide());
+ ASSERT(expr->target()->IsValidReferenceExpression());
Comment cmnt(masm_, "[ Assignment");
void FullCodeGenerator::EmitAssignment(Expression* expr) {
- ASSERT(expr->IsValidLeftHandSide());
+ ASSERT(expr->IsValidReferenceExpression());
// Left-hand side can only be a property, a global or a (parameter or local)
// slot.
void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
- ASSERT(expr->expression()->IsValidLeftHandSide());
+ ASSERT(expr->expression()->IsValidReferenceExpression());
Comment cmnt(masm_, "[ CountOperation");
SetSourcePosition(expr->position());
"this[foo]",
"new foo()[bar]",
"new foo().bar",
+ "foo()",
+ "foo(bar)",
+ "foo[bar]()",
+ "foo.bar()",
+ "this()",
+ "this.foo()",
+ "this[foo].bar()",
+ "this.foo[foo].bar(this)(bar)[foo]()",
NULL
};
// Bad left hand sides for assigment or prefix / postfix operations.
const char* bad_statement_data_common[] = {
"2",
- "foo()",
+ "new foo",
+ "new foo()",
"null",
"if", // Unexpected token
"{x: 1}", // Unexpected token
assertThrows("12 = 12", ReferenceError);
assertThrows("x++ = 12", ReferenceError);
assertThrows("eval('var x') = 12", ReferenceError);
-assertThrows("if (false) eval('var x') = 12", ReferenceError);
+assertThrows("if (false) 12 = 12", ReferenceError);
+assertDoesNotThrow("if (false) eval('var x') = 12", ReferenceError);
// Pre- and post-fix operations:
assertThrows("12++", ReferenceError);
assertThrows("12--", ReferenceError);
-assertThrows("--12", ReferenceError);
assertThrows("++12", ReferenceError);
+assertThrows("--12", ReferenceError);
assertThrows("++(eval('12'))", ReferenceError);
assertThrows("(eval('12'))++", ReferenceError);
-assertThrows("if (false) ++(eval('12'))", ReferenceError);
-assertThrows("if (false) (eval('12'))++", ReferenceError);
+assertThrows("if (false) 12++", ReferenceError);
+assertThrows("if (false) 12--", ReferenceError);
+assertThrows("if (false) ++12", ReferenceError);
+assertThrows("if (false) --12", ReferenceError);
+assertDoesNotThrow("if (false) ++(eval('12'))", ReferenceError);
+assertDoesNotThrow("if (false) (eval('12'))++", ReferenceError);
// For in:
assertThrows("for (12 in [1]) print(12);", ReferenceError);
assertThrows("for (eval('var x') in [1]) print(12);", ReferenceError);
-assertThrows("if (false) for (eval('0') in [1]) print(12);", ReferenceError);
+assertThrows("if (false) for (12 in [1]) print(12);", ReferenceError);
+assertDoesNotThrow("if (false) for (eval('0') in [1]) print(12);", ReferenceError);
// For:
assertThrows("for (12 = 1;;) print(12);", ReferenceError);
assertThrows("for (eval('var x') = 1;;) print(12);", ReferenceError);
-assertThrows("if (false) for (eval('var x') = 1;;) print(12);", ReferenceError);
+assertThrows("if (false) for (12 = 1;;) print(12);", ReferenceError);
+assertDoesNotThrow("if (false) for (eval('var x') = 1;;) print(12);", ReferenceError);
// Assignments to 'this'.
assertThrows("this = 42", ReferenceError);
assertThrows("++this", ReferenceError);
assertThrows("this--", ReferenceError);
assertThrows("--this", ReferenceError);
+assertThrows("if (false) this = 42", ReferenceError);
+assertThrows("if (false) this++", ReferenceError);
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-FAIL function f() { g()++; } f.toString() should be function f() { g()++; }. Threw exception ReferenceError: Invalid left-hand side expression in postfix operation
-FAIL function f() { g()--; } f.toString() should be function f() { g()--; }. Threw exception ReferenceError: Invalid left-hand side expression in postfix operation
-FAIL function f() { ++g(); } f.toString() should be function f() { ++g(); }. Threw exception ReferenceError: Invalid left-hand side expression in prefix operation
-FAIL function f() { --g(); } f.toString() should be function f() { --g(); }. Threw exception ReferenceError: Invalid left-hand side expression in prefix operation
-FAIL function f() { g() = 1; } f.toString() should be function f() { g() = 1; }. Threw exception ReferenceError: Invalid left-hand side in assignment
-FAIL function f() { g() += 1; } f.toString() should be function f() { g() += 1; }. Threw exception ReferenceError: Invalid left-hand side in assignment
-FAIL g()++ should throw ReferenceError: Postfix ++ operator applied to value that is not a reference.. Threw exception ReferenceError: Invalid left-hand side expression in postfix operation.
-FAIL g()-- should throw ReferenceError: Postfix -- operator applied to value that is not a reference.. Threw exception ReferenceError: Invalid left-hand side expression in postfix operation.
-FAIL ++g() should throw ReferenceError: Prefix ++ operator applied to value that is not a reference.. Threw exception ReferenceError: Invalid left-hand side expression in prefix operation.
-FAIL --g() should throw ReferenceError: Prefix -- operator applied to value that is not a reference.. Threw exception ReferenceError: Invalid left-hand side expression in prefix operation.
-FAIL g() = 1 should throw ReferenceError: Left side of assignment is not a reference.. Threw exception ReferenceError: Invalid left-hand side in assignment.
-FAIL g() += 1 should throw ReferenceError: Left side of assignment is not a reference.. Threw exception ReferenceError: Invalid left-hand side in assignment.
+PASS function f() { g()++; } f.toString() is 'function f() { g()++; }'
+PASS function f() { g()--; } f.toString() is 'function f() { g()--; }'
+PASS function f() { ++g(); } f.toString() is 'function f() { ++g(); }'
+PASS function f() { --g(); } f.toString() is 'function f() { --g(); }'
+PASS function f() { g() = 1; } f.toString() is 'function f() { g() = 1; }'
+PASS function f() { g() += 1; } f.toString() is 'function f() { g() += 1; }'
+PASS Number()++ threw exception ReferenceError: Invalid left-hand side expression in postfix operation.
+PASS Number()-- threw exception ReferenceError: Invalid left-hand side expression in postfix operation.
+PASS ++Number() threw exception ReferenceError: Invalid left-hand side expression in prefix operation.
+PASS --Number() threw exception ReferenceError: Invalid left-hand side expression in prefix operation.
+PASS Number() = 1 threw exception ReferenceError: Invalid left-hand side in assignment.
+PASS Number() += 1 threw exception ReferenceError: Invalid left-hand side in assignment.
PASS successfullyParsed is true
TEST COMPLETE
shouldBe("function f() { --g(); } f.toString()", "'function f() { --g(); }'");
shouldBe("function f() { g() = 1; } f.toString()", "'function f() { g() = 1; }'");
shouldBe("function f() { g() += 1; } f.toString()", "'function f() { g() += 1; }'");
-shouldThrow("g()++", "'ReferenceError: Postfix ++ operator applied to value that is not a reference.'");
-shouldThrow("g()--", "'ReferenceError: Postfix -- operator applied to value that is not a reference.'");
-shouldThrow("++g()", "'ReferenceError: Prefix ++ operator applied to value that is not a reference.'");
-shouldThrow("--g()", "'ReferenceError: Prefix -- operator applied to value that is not a reference.'");
-shouldThrow("g() = 1", "'ReferenceError: Left side of assignment is not a reference.'");
-shouldThrow("g() += 1", "'ReferenceError: Left side of assignment is not a reference.'");
+shouldThrow("Number()++", "'ReferenceError: Invalid left-hand side expression in postfix operation'");
+shouldThrow("Number()--", "'ReferenceError: Invalid left-hand side expression in postfix operation'");
+shouldThrow("++Number()", "'ReferenceError: Invalid left-hand side expression in prefix operation'");
+shouldThrow("--Number()", "'ReferenceError: Invalid left-hand side expression in prefix operation'");
+shouldThrow("Number() = 1", "'ReferenceError: Invalid left-hand side in assignment'");
+shouldThrow("Number() += 1", "'ReferenceError: Invalid left-hand side in assignment'");