Commit f09705ab authored by lrn@chromium.org's avatar lrn@chromium.org

Make invalid break/continue statements an early syntax error.

Previously we delayed the throwing of syntax errors until runtime, so
unreachable errors didn't get reported.
To match a change in JSC, we now stop parsing and report the error immediately.

BUG=69736
TEST=

Review URL: http://codereview.chromium.org/6355006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6341 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent fae90d4f
...@@ -778,7 +778,8 @@ void Parser::ReportMessageAt(Scanner::Location source_location, ...@@ -778,7 +778,8 @@ void Parser::ReportMessageAt(Scanner::Location source_location,
const char* type, const char* type,
Vector<const char*> args) { Vector<const char*> args) {
MessageLocation location(script_, MessageLocation location(script_,
source_location.beg_pos, source_location.end_pos); source_location.beg_pos,
source_location.end_pos);
Handle<JSArray> array = Factory::NewJSArray(args.length()); Handle<JSArray> array = Factory::NewJSArray(args.length());
for (int i = 0; i < args.length(); i++) { for (int i = 0; i < args.length(); i++) {
SetElement(array, i, Factory::NewStringFromUtf8(CStrVector(args[i]))); SetElement(array, i, Factory::NewStringFromUtf8(CStrVector(args[i])));
...@@ -788,6 +789,21 @@ void Parser::ReportMessageAt(Scanner::Location source_location, ...@@ -788,6 +789,21 @@ void Parser::ReportMessageAt(Scanner::Location source_location,
} }
void Parser::ReportMessageAt(Scanner::Location source_location,
const char* type,
Vector<Handle<String> > args) {
MessageLocation location(script_,
source_location.beg_pos,
source_location.end_pos);
Handle<JSArray> array = Factory::NewJSArray(args.length());
for (int i = 0; i < args.length(); i++) {
SetElement(array, i, args[i]);
}
Handle<Object> result = Factory::NewSyntaxError(type, array);
Top::Throw(*result, &location);
}
// Base class containing common code for the different finder classes used by // Base class containing common code for the different finder classes used by
// the parser. // the parser.
class ParserFinder { class ParserFinder {
...@@ -1693,12 +1709,16 @@ Statement* Parser::ParseContinueStatement(bool* ok) { ...@@ -1693,12 +1709,16 @@ Statement* Parser::ParseContinueStatement(bool* ok) {
IterationStatement* target = NULL; IterationStatement* target = NULL;
target = LookupContinueTarget(label, CHECK_OK); target = LookupContinueTarget(label, CHECK_OK);
if (target == NULL) { if (target == NULL) {
// Illegal continue statement. To be consistent with KJS we delay // Illegal continue statement.
// reporting of the syntax error until runtime. const char* message = "illegal_continue";
Handle<String> error_type = Factory::illegal_continue_symbol(); Vector<Handle<String> > args;
if (!label.is_null()) error_type = Factory::unknown_label_symbol(); if (!label.is_null()) {
Expression* throw_error = NewThrowSyntaxError(error_type, label); message = "unknown_label";
return new ExpressionStatement(throw_error); args = Vector<Handle<String> >(&label, 1);
}
ReportMessageAt(scanner().location(), message, args);
*ok = false;
return NULL;
} }
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
return new ContinueStatement(target); return new ContinueStatement(target);
...@@ -1724,12 +1744,16 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) { ...@@ -1724,12 +1744,16 @@ Statement* Parser::ParseBreakStatement(ZoneStringList* labels, bool* ok) {
BreakableStatement* target = NULL; BreakableStatement* target = NULL;
target = LookupBreakTarget(label, CHECK_OK); target = LookupBreakTarget(label, CHECK_OK);
if (target == NULL) { if (target == NULL) {
// Illegal break statement. To be consistent with KJS we delay // Illegal break statement.
// reporting of the syntax error until runtime. const char* message = "illegal_break";
Handle<String> error_type = Factory::illegal_break_symbol(); Vector<Handle<String> > args;
if (!label.is_null()) error_type = Factory::unknown_label_symbol(); if (!label.is_null()) {
Expression* throw_error = NewThrowSyntaxError(error_type, label); message = "unknown_label";
return new ExpressionStatement(throw_error); args = Vector<Handle<String> >(&label, 1);
}
ReportMessageAt(scanner().location(), message, args);
*ok = false;
return NULL;
} }
ExpectSemicolon(CHECK_OK); ExpectSemicolon(CHECK_OK);
return new BreakStatement(target); return new BreakStatement(target);
......
...@@ -430,6 +430,9 @@ class Parser { ...@@ -430,6 +430,9 @@ class Parser {
void ReportMessageAt(Scanner::Location loc, void ReportMessageAt(Scanner::Location loc,
const char* message, const char* message,
Vector<const char*> args); Vector<const char*> args);
void ReportMessageAt(Scanner::Location loc,
const char* message,
Vector<Handle<String> > args);
protected: protected:
FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info, FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info,
......
...@@ -25,17 +25,18 @@ ...@@ -25,17 +25,18 @@
// (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.
// To be compatible with KJS syntax errors for illegal return, break // To be compatible with JSC syntax errors for illegal returns should be delayed
// and continue should be delayed to runtime. // to runtime.
// Invalid continue and break statements are caught at compile time.
// Do not throw syntax errors for illegal return, break and continue // Do not throw syntax errors for illegal return at compile time.
// at compile time.
assertDoesNotThrow("if (false) return;"); assertDoesNotThrow("if (false) return;");
assertDoesNotThrow("if (false) break;");
assertDoesNotThrow("if (false) continue;");
// Throw syntax errors for illegal return, break and continue at // Throw syntax errors for illegal break and continue at compile time.
// compile time. assertThrows("if (false) break;");
assertThrows("if (false) continue;");
// Throw syntax errors for illegal return, break and continue at runtime.
assertThrows("return;"); assertThrows("return;");
assertThrows("break;"); assertThrows("break;");
assertThrows("continue;"); assertThrows("continue;");
...@@ -25,14 +25,14 @@ ...@@ -25,14 +25,14 @@
// (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.
xeval = function(s) { eval(s); } assertThrows("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
xeval("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
foo = function() { eval("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }"); } function foo() {
assertThrows("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
}
foo(); foo();
xeval = function(s) { eval(s); } assertThrows("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
eval("$=function anonymous() { /*noex*/do {} while(({ get x(x) { break ; }, set x() { (undefined);} })); }");
xeval = function(s) { eval(s); } xeval = function(s) { eval(s); }
xeval('$=function(){L: {break L;break L;}};'); xeval('$=function(){L: {break L;break L;}};');
...@@ -25,11 +25,15 @@ ...@@ -25,11 +25,15 @@
// (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.
// We throw syntax errors early for invalid break and continue statements.
// (Notice that the example isn't valid ECMAScript due to the
// function declaration that is not at top level.)
function f() { function f() {
// Force eager compilation of x through the use of eval. The break // Force eager compilation of x through the use of eval. The break
// in function x should not try to break out of the enclosing while. // in function x should not try to break out of the enclosing while.
return eval("while(0) function x() { break; }; 42"); return eval("while(0) function x() { break; }; 42");
}; };
assertEquals(42, f()); assertThrows("f()");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment