Two changes, one a refactoring and one that affects V8's JS semantics.
1. Change the AST node type CallNew to be a subclass of Expression rather than Call. It's not really a call but it just happens to have the same fields. 2. Change our error reporting for invalid left-hand sides in for-in statements, pre- and postfix count expressions, and assignments. Before we signaled a syntax error at compile time *unless* the LHS was a function call or 'new' expression, in which case we signaled a reference error at runtime. Now we signal a reference error at runtime in all cases. This matches the JSC behavior in Safari 4. Review URL: http://codereview.chromium.org/249039 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2994 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
b1a5bf4c5d
commit
fb038bf146
21
src/ast.h
21
src/ast.h
@ -954,12 +954,8 @@ class Property: public Expression {
|
||||
|
||||
class Call: public Expression {
|
||||
public:
|
||||
Call(Expression* expression,
|
||||
ZoneList<Expression*>* arguments,
|
||||
int pos)
|
||||
: expression_(expression),
|
||||
arguments_(arguments),
|
||||
pos_(pos) { }
|
||||
Call(Expression* expression, ZoneList<Expression*>* arguments, int pos)
|
||||
: expression_(expression), arguments_(arguments), pos_(pos) { }
|
||||
|
||||
virtual void Accept(AstVisitor* v);
|
||||
|
||||
@ -981,12 +977,21 @@ class Call: public Expression {
|
||||
};
|
||||
|
||||
|
||||
class CallNew: public Call {
|
||||
class CallNew: public Expression {
|
||||
public:
|
||||
CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos)
|
||||
: Call(expression, arguments, pos) { }
|
||||
: expression_(expression), arguments_(arguments), pos_(pos) { }
|
||||
|
||||
virtual void Accept(AstVisitor* v);
|
||||
|
||||
Expression* expression() const { return expression_; }
|
||||
ZoneList<Expression*>* arguments() const { return arguments_; }
|
||||
int position() { return pos_; }
|
||||
|
||||
private:
|
||||
Expression* expression_;
|
||||
ZoneList<Expression*>* arguments_;
|
||||
int pos_;
|
||||
};
|
||||
|
||||
|
||||
|
123
src/parser.cc
123
src/parser.cc
@ -2660,25 +2660,13 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
||||
} else {
|
||||
Expression* expression = ParseExpression(false, CHECK_OK);
|
||||
if (peek() == Token::IN) {
|
||||
// Report syntax error if the expression is an invalid
|
||||
// left-hand side 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.
|
||||
if (expression == NULL || !expression->IsValidLeftHandSide()) {
|
||||
if (expression != NULL && expression->AsCall() != NULL) {
|
||||
// According to ECMA-262 host function calls are permitted to
|
||||
// return references. This cannot happen in our system so we
|
||||
// will always get an error. We could report this as a syntax
|
||||
// error here but for compatibility with KJS and SpiderMonkey we
|
||||
// choose to report the error at runtime.
|
||||
Handle<String> type = Factory::invalid_lhs_in_for_in_symbol();
|
||||
expression = NewThrowReferenceError(type);
|
||||
} else {
|
||||
// Invalid left hand side expressions that are not function
|
||||
// calls are reported as syntax errors at compile time.
|
||||
ReportMessage("invalid_lhs_in_for_in",
|
||||
Vector<const char*>::empty());
|
||||
*ok = false;
|
||||
return NULL;
|
||||
}
|
||||
Handle<String> type = Factory::invalid_lhs_in_for_in_symbol();
|
||||
expression = NewThrowReferenceError(type);
|
||||
}
|
||||
ForInStatement* loop = NEW(ForInStatement(labels));
|
||||
Target target(this, loop);
|
||||
@ -2755,30 +2743,15 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
|
||||
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.
|
||||
if (expression == NULL || !expression->IsValidLeftHandSide()) {
|
||||
if (expression != NULL && expression->AsCall() != NULL) {
|
||||
// According to ECMA-262 host function calls are permitted to
|
||||
// return references. This cannot happen in our system so we
|
||||
// will always get an error. We could report this as a syntax
|
||||
// error here but for compatibility with KJS and SpiderMonkey we
|
||||
// choose to report the error at runtime.
|
||||
Handle<String> type = Factory::invalid_lhs_in_assignment_symbol();
|
||||
expression = NewThrowReferenceError(type);
|
||||
} else {
|
||||
// Invalid left hand side expressions that are not function
|
||||
// calls are reported as syntax errors at compile time.
|
||||
//
|
||||
// NOTE: KJS sometimes delay the error reporting to runtime. If
|
||||
// we want to be completely compatible we should do the same.
|
||||
// For example: "(x++) = 42" gives a reference error at runtime
|
||||
// with KJS whereas we report a syntax error at compile time.
|
||||
ReportMessage("invalid_lhs_in_assignment", Vector<const char*>::empty());
|
||||
*ok = false;
|
||||
return NULL;
|
||||
}
|
||||
Handle<String> type = Factory::invalid_lhs_in_assignment_symbol();
|
||||
expression = NewThrowReferenceError(type);
|
||||
}
|
||||
|
||||
|
||||
Token::Value op = Next(); // Get assignment operator.
|
||||
int pos = scanner().location().beg_pos;
|
||||
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
|
||||
@ -2951,45 +2924,37 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
|
||||
Token::Value op = peek();
|
||||
if (Token::IsUnaryOp(op)) {
|
||||
op = Next();
|
||||
Expression* x = ParseUnaryExpression(CHECK_OK);
|
||||
Expression* expression = ParseUnaryExpression(CHECK_OK);
|
||||
|
||||
// Compute some expressions involving only number literals.
|
||||
if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber()) {
|
||||
double x_val = x->AsLiteral()->handle()->Number();
|
||||
if (expression != NULL && expression->AsLiteral() &&
|
||||
expression->AsLiteral()->handle()->IsNumber()) {
|
||||
double value = expression->AsLiteral()->handle()->Number();
|
||||
switch (op) {
|
||||
case Token::ADD:
|
||||
return x;
|
||||
return expression;
|
||||
case Token::SUB:
|
||||
return NewNumberLiteral(-x_val);
|
||||
return NewNumberLiteral(-value);
|
||||
case Token::BIT_NOT:
|
||||
return NewNumberLiteral(~DoubleToInt32(x_val));
|
||||
return NewNumberLiteral(~DoubleToInt32(value));
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return NEW(UnaryOperation(op, x));
|
||||
return NEW(UnaryOperation(op, expression));
|
||||
|
||||
} else if (Token::IsCountOp(op)) {
|
||||
op = Next();
|
||||
Expression* x = ParseUnaryExpression(CHECK_OK);
|
||||
if (x == NULL || !x->IsValidLeftHandSide()) {
|
||||
if (x != NULL && x->AsCall() != NULL) {
|
||||
// According to ECMA-262 host function calls are permitted to
|
||||
// return references. This cannot happen in our system so we
|
||||
// will always get an error. We could report this as a syntax
|
||||
// error here but for compatibility with KJS and SpiderMonkey we
|
||||
// choose to report the error at runtime.
|
||||
Handle<String> type = Factory::invalid_lhs_in_prefix_op_symbol();
|
||||
x = NewThrowReferenceError(type);
|
||||
} else {
|
||||
// Invalid left hand side expressions that are not function
|
||||
// calls are reported as syntax errors at compile time.
|
||||
ReportMessage("invalid_lhs_in_prefix_op", Vector<const char*>::empty());
|
||||
*ok = false;
|
||||
return NULL;
|
||||
}
|
||||
Expression* expression = ParseUnaryExpression(CHECK_OK);
|
||||
// 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.
|
||||
if (expression == NULL || !expression->IsValidLeftHandSide()) {
|
||||
Handle<String> type = Factory::invalid_lhs_in_prefix_op_symbol();
|
||||
expression = NewThrowReferenceError(type);
|
||||
}
|
||||
return NEW(CountOperation(true /* prefix */, op, x));
|
||||
return NEW(CountOperation(true /* prefix */, op, expression));
|
||||
|
||||
} else {
|
||||
return ParsePostfixExpression(ok);
|
||||
@ -3001,30 +2966,20 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
|
||||
// PostfixExpression ::
|
||||
// LeftHandSideExpression ('++' | '--')?
|
||||
|
||||
Expression* result = ParseLeftHandSideExpression(CHECK_OK);
|
||||
Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
|
||||
if (!scanner_.has_line_terminator_before_next() && Token::IsCountOp(peek())) {
|
||||
if (result == NULL || !result->IsValidLeftHandSide()) {
|
||||
if (result != NULL && result->AsCall() != NULL) {
|
||||
// According to ECMA-262 host function calls are permitted to
|
||||
// return references. This cannot happen in our system so we
|
||||
// will always get an error. We could report this as a syntax
|
||||
// error here but for compatibility with KJS and SpiderMonkey we
|
||||
// choose to report the error at runtime.
|
||||
Handle<String> type = Factory::invalid_lhs_in_postfix_op_symbol();
|
||||
result = NewThrowReferenceError(type);
|
||||
} else {
|
||||
// Invalid left hand side expressions that are not function
|
||||
// calls are reported as syntax errors at compile time.
|
||||
ReportMessage("invalid_lhs_in_postfix_op",
|
||||
Vector<const char*>::empty());
|
||||
*ok = false;
|
||||
return NULL;
|
||||
}
|
||||
// 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.
|
||||
if (expression == NULL || !expression->IsValidLeftHandSide()) {
|
||||
Handle<String> type = Factory::invalid_lhs_in_postfix_op_symbol();
|
||||
expression = NewThrowReferenceError(type);
|
||||
}
|
||||
Token::Value next = Next();
|
||||
result = NEW(CountOperation(false /* postfix */, next, result));
|
||||
expression = NEW(CountOperation(false /* postfix */, next, expression));
|
||||
}
|
||||
return result;
|
||||
return expression;
|
||||
}
|
||||
|
||||
|
||||
|
@ -44,44 +44,12 @@ class UsageComputer: public AstVisitor {
|
||||
public:
|
||||
static bool Traverse(AstNode* node);
|
||||
|
||||
void VisitBlock(Block* node);
|
||||
void VisitDeclaration(Declaration* node);
|
||||
void VisitExpressionStatement(ExpressionStatement* node);
|
||||
void VisitEmptyStatement(EmptyStatement* node);
|
||||
void VisitIfStatement(IfStatement* node);
|
||||
void VisitContinueStatement(ContinueStatement* node);
|
||||
void VisitBreakStatement(BreakStatement* node);
|
||||
void VisitReturnStatement(ReturnStatement* node);
|
||||
void VisitWithEnterStatement(WithEnterStatement* node);
|
||||
void VisitWithExitStatement(WithExitStatement* node);
|
||||
void VisitSwitchStatement(SwitchStatement* node);
|
||||
void VisitLoopStatement(LoopStatement* node);
|
||||
void VisitForInStatement(ForInStatement* node);
|
||||
void VisitTryCatch(TryCatch* node);
|
||||
void VisitTryFinally(TryFinally* node);
|
||||
void VisitDebuggerStatement(DebuggerStatement* node);
|
||||
void VisitFunctionLiteral(FunctionLiteral* node);
|
||||
void VisitFunctionBoilerplateLiteral(FunctionBoilerplateLiteral* node);
|
||||
void VisitConditional(Conditional* node);
|
||||
void VisitSlot(Slot* node);
|
||||
void VisitVariable(Variable* node);
|
||||
void VisitVariableProxy(VariableProxy* node);
|
||||
void VisitLiteral(Literal* node);
|
||||
void VisitRegExpLiteral(RegExpLiteral* node);
|
||||
void VisitObjectLiteral(ObjectLiteral* node);
|
||||
void VisitArrayLiteral(ArrayLiteral* node);
|
||||
void VisitCatchExtensionObject(CatchExtensionObject* node);
|
||||
void VisitAssignment(Assignment* node);
|
||||
void VisitThrow(Throw* node);
|
||||
void VisitProperty(Property* node);
|
||||
void VisitCall(Call* node);
|
||||
void VisitCallNew(CallNew* node);
|
||||
void VisitCallRuntime(CallRuntime* node);
|
||||
void VisitUnaryOperation(UnaryOperation* node);
|
||||
void VisitCountOperation(CountOperation* node);
|
||||
void VisitBinaryOperation(BinaryOperation* node);
|
||||
void VisitCompareOperation(CompareOperation* node);
|
||||
void VisitThisFunction(ThisFunction* node);
|
||||
// AST node visit functions.
|
||||
#define DECLARE_VISIT(type) void Visit##type(type* node);
|
||||
AST_NODE_LIST(DECLARE_VISIT)
|
||||
#undef DECLARE_VISIT
|
||||
|
||||
void VisitVariable(Variable* var);
|
||||
|
||||
private:
|
||||
int weight_;
|
||||
@ -329,7 +297,8 @@ void UsageComputer::VisitCall(Call* node) {
|
||||
|
||||
|
||||
void UsageComputer::VisitCallNew(CallNew* node) {
|
||||
VisitCall(node);
|
||||
Read(node->expression());
|
||||
ReadList(node->arguments());
|
||||
}
|
||||
|
||||
|
||||
|
@ -25,9 +25,8 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Test that we get exceptions for invalid left-hand sides. Also
|
||||
// tests that if the invalid left-hand side is a function call, the
|
||||
// exception is delayed until runtime.
|
||||
// Test that we get exceptions for invalid left-hand sides. The
|
||||
// exceptions are delayed until runtime.
|
||||
|
||||
// Normal assignments:
|
||||
assertThrows("12 = 12");
|
||||
@ -57,12 +56,10 @@ assertDoesNotThrow("if (false) for (eval('var x') = 1;;) print(12);");
|
||||
|
||||
// Assignments to 'this'.
|
||||
assertThrows("this = 42");
|
||||
assertThrows("function f() { this = 12; }");
|
||||
assertThrows("for (this in Array) ;");
|
||||
assertDoesNotThrow("function f() { this = 12; }");
|
||||
assertThrows("for (this in {x:3, y:4, z:5}) ;");
|
||||
assertThrows("for (this = 0;;) ;");
|
||||
assertThrows("this++");
|
||||
assertThrows("++this");
|
||||
assertThrows("this--");
|
||||
assertThrows("--this");
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user