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 {
|
class Call: public Expression {
|
||||||
public:
|
public:
|
||||||
Call(Expression* expression,
|
Call(Expression* expression, ZoneList<Expression*>* arguments, int pos)
|
||||||
ZoneList<Expression*>* arguments,
|
: expression_(expression), arguments_(arguments), pos_(pos) { }
|
||||||
int pos)
|
|
||||||
: expression_(expression),
|
|
||||||
arguments_(arguments),
|
|
||||||
pos_(pos) { }
|
|
||||||
|
|
||||||
virtual void Accept(AstVisitor* v);
|
virtual void Accept(AstVisitor* v);
|
||||||
|
|
||||||
@ -981,12 +977,21 @@ class Call: public Expression {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class CallNew: public Call {
|
class CallNew: public Expression {
|
||||||
public:
|
public:
|
||||||
CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos)
|
CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos)
|
||||||
: Call(expression, arguments, pos) { }
|
: expression_(expression), arguments_(arguments), pos_(pos) { }
|
||||||
|
|
||||||
virtual void Accept(AstVisitor* v);
|
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 {
|
} else {
|
||||||
Expression* expression = ParseExpression(false, CHECK_OK);
|
Expression* expression = ParseExpression(false, CHECK_OK);
|
||||||
if (peek() == Token::IN) {
|
if (peek() == Token::IN) {
|
||||||
// Report syntax error if the expression is an invalid
|
// Signal a reference error if the expression is an invalid
|
||||||
// left-hand side expression.
|
// 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->IsValidLeftHandSide()) {
|
||||||
if (expression != NULL && expression->AsCall() != NULL) {
|
Handle<String> type = Factory::invalid_lhs_in_for_in_symbol();
|
||||||
// According to ECMA-262 host function calls are permitted to
|
expression = NewThrowReferenceError(type);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ForInStatement* loop = NEW(ForInStatement(labels));
|
ForInStatement* loop = NEW(ForInStatement(labels));
|
||||||
Target target(this, loop);
|
Target target(this, loop);
|
||||||
@ -2755,30 +2743,15 @@ Expression* Parser::ParseAssignmentExpression(bool accept_IN, bool* ok) {
|
|||||||
return expression;
|
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->IsValidLeftHandSide()) {
|
||||||
if (expression != NULL && expression->AsCall() != NULL) {
|
Handle<String> type = Factory::invalid_lhs_in_assignment_symbol();
|
||||||
// According to ECMA-262 host function calls are permitted to
|
expression = NewThrowReferenceError(type);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Token::Value op = Next(); // Get assignment operator.
|
Token::Value op = Next(); // Get assignment operator.
|
||||||
int pos = scanner().location().beg_pos;
|
int pos = scanner().location().beg_pos;
|
||||||
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
|
Expression* right = ParseAssignmentExpression(accept_IN, CHECK_OK);
|
||||||
@ -2951,45 +2924,37 @@ Expression* Parser::ParseUnaryExpression(bool* ok) {
|
|||||||
Token::Value op = peek();
|
Token::Value op = peek();
|
||||||
if (Token::IsUnaryOp(op)) {
|
if (Token::IsUnaryOp(op)) {
|
||||||
op = Next();
|
op = Next();
|
||||||
Expression* x = ParseUnaryExpression(CHECK_OK);
|
Expression* expression = ParseUnaryExpression(CHECK_OK);
|
||||||
|
|
||||||
// Compute some expressions involving only number literals.
|
// Compute some expressions involving only number literals.
|
||||||
if (x && x->AsLiteral() && x->AsLiteral()->handle()->IsNumber()) {
|
if (expression != NULL && expression->AsLiteral() &&
|
||||||
double x_val = x->AsLiteral()->handle()->Number();
|
expression->AsLiteral()->handle()->IsNumber()) {
|
||||||
|
double value = expression->AsLiteral()->handle()->Number();
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Token::ADD:
|
case Token::ADD:
|
||||||
return x;
|
return expression;
|
||||||
case Token::SUB:
|
case Token::SUB:
|
||||||
return NewNumberLiteral(-x_val);
|
return NewNumberLiteral(-value);
|
||||||
case Token::BIT_NOT:
|
case Token::BIT_NOT:
|
||||||
return NewNumberLiteral(~DoubleToInt32(x_val));
|
return NewNumberLiteral(~DoubleToInt32(value));
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NEW(UnaryOperation(op, x));
|
return NEW(UnaryOperation(op, expression));
|
||||||
|
|
||||||
} else if (Token::IsCountOp(op)) {
|
} else if (Token::IsCountOp(op)) {
|
||||||
op = Next();
|
op = Next();
|
||||||
Expression* x = ParseUnaryExpression(CHECK_OK);
|
Expression* expression = ParseUnaryExpression(CHECK_OK);
|
||||||
if (x == NULL || !x->IsValidLeftHandSide()) {
|
// Signal a reference error if the expression is an invalid
|
||||||
if (x != NULL && x->AsCall() != NULL) {
|
// left-hand side expression. We could report this as a syntax
|
||||||
// According to ECMA-262 host function calls are permitted to
|
// error here but for compatibility with JSC we choose to report the
|
||||||
// return references. This cannot happen in our system so we
|
// error at runtime.
|
||||||
// will always get an error. We could report this as a syntax
|
if (expression == NULL || !expression->IsValidLeftHandSide()) {
|
||||||
// error here but for compatibility with KJS and SpiderMonkey we
|
Handle<String> type = Factory::invalid_lhs_in_prefix_op_symbol();
|
||||||
// choose to report the error at runtime.
|
expression = NewThrowReferenceError(type);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return NEW(CountOperation(true /* prefix */, op, x));
|
return NEW(CountOperation(true /* prefix */, op, expression));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return ParsePostfixExpression(ok);
|
return ParsePostfixExpression(ok);
|
||||||
@ -3001,30 +2966,20 @@ Expression* Parser::ParsePostfixExpression(bool* ok) {
|
|||||||
// PostfixExpression ::
|
// PostfixExpression ::
|
||||||
// LeftHandSideExpression ('++' | '--')?
|
// LeftHandSideExpression ('++' | '--')?
|
||||||
|
|
||||||
Expression* result = ParseLeftHandSideExpression(CHECK_OK);
|
Expression* expression = ParseLeftHandSideExpression(CHECK_OK);
|
||||||
if (!scanner_.has_line_terminator_before_next() && Token::IsCountOp(peek())) {
|
if (!scanner_.has_line_terminator_before_next() && Token::IsCountOp(peek())) {
|
||||||
if (result == NULL || !result->IsValidLeftHandSide()) {
|
// Signal a reference error if the expression is an invalid
|
||||||
if (result != NULL && result->AsCall() != NULL) {
|
// left-hand side expression. We could report this as a syntax
|
||||||
// According to ECMA-262 host function calls are permitted to
|
// error here but for compatibility with JSC we choose to report the
|
||||||
// return references. This cannot happen in our system so we
|
// error at runtime.
|
||||||
// will always get an error. We could report this as a syntax
|
if (expression == NULL || !expression->IsValidLeftHandSide()) {
|
||||||
// error here but for compatibility with KJS and SpiderMonkey we
|
Handle<String> type = Factory::invalid_lhs_in_postfix_op_symbol();
|
||||||
// choose to report the error at runtime.
|
expression = NewThrowReferenceError(type);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Token::Value next = Next();
|
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:
|
public:
|
||||||
static bool Traverse(AstNode* node);
|
static bool Traverse(AstNode* node);
|
||||||
|
|
||||||
void VisitBlock(Block* node);
|
// AST node visit functions.
|
||||||
void VisitDeclaration(Declaration* node);
|
#define DECLARE_VISIT(type) void Visit##type(type* node);
|
||||||
void VisitExpressionStatement(ExpressionStatement* node);
|
AST_NODE_LIST(DECLARE_VISIT)
|
||||||
void VisitEmptyStatement(EmptyStatement* node);
|
#undef DECLARE_VISIT
|
||||||
void VisitIfStatement(IfStatement* node);
|
|
||||||
void VisitContinueStatement(ContinueStatement* node);
|
void VisitVariable(Variable* var);
|
||||||
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);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int weight_;
|
int weight_;
|
||||||
@ -329,7 +297,8 @@ void UsageComputer::VisitCall(Call* node) {
|
|||||||
|
|
||||||
|
|
||||||
void UsageComputer::VisitCallNew(CallNew* 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
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Test that we get exceptions for invalid left-hand sides. Also
|
// Test that we get exceptions for invalid left-hand sides. The
|
||||||
// tests that if the invalid left-hand side is a function call, the
|
// exceptions are delayed until runtime.
|
||||||
// exception is delayed until runtime.
|
|
||||||
|
|
||||||
// Normal assignments:
|
// Normal assignments:
|
||||||
assertThrows("12 = 12");
|
assertThrows("12 = 12");
|
||||||
@ -57,12 +56,10 @@ assertDoesNotThrow("if (false) for (eval('var x') = 1;;) print(12);");
|
|||||||
|
|
||||||
// Assignments to 'this'.
|
// Assignments to 'this'.
|
||||||
assertThrows("this = 42");
|
assertThrows("this = 42");
|
||||||
assertThrows("function f() { this = 12; }");
|
assertDoesNotThrow("function f() { this = 12; }");
|
||||||
assertThrows("for (this in Array) ;");
|
assertThrows("for (this in {x:3, y:4, z:5}) ;");
|
||||||
assertThrows("for (this = 0;;) ;");
|
assertThrows("for (this = 0;;) ;");
|
||||||
assertThrows("this++");
|
assertThrows("this++");
|
||||||
assertThrows("++this");
|
assertThrows("++this");
|
||||||
assertThrows("this--");
|
assertThrows("this--");
|
||||||
assertThrows("--this");
|
assertThrows("--this");
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user