From 35354cb9b7e1789945aaddc414a102594ffc3544 Mon Sep 17 00:00:00 2001 From: "marja@chromium.org" Date: Tue, 4 Feb 2014 16:38:47 +0000 Subject: [PATCH] Tests and fixes for (pre)parse errors related to future reserved words. This contains the following fixes: - PreParser was using an error "reserved_word" which doesn't exist in messages.js. Changed it to "unexpected_reserved". BUG=3126 LOG=N R=ulan@chromium.org Review URL: https://codereview.chromium.org/153793002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19076 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/preparser.cc | 4 +- test/cctest/test-parsing.cc | 415 ++++++++++++++++---------------------------- 2 files changed, 155 insertions(+), 264 deletions(-) diff --git a/src/preparser.cc b/src/preparser.cc index 21010ae..b3a271a 100644 --- a/src/preparser.cc +++ b/src/preparser.cc @@ -1497,7 +1497,7 @@ PreParser::Identifier PreParser::ParseIdentifier(bool* ok) { case Token::FUTURE_RESERVED_WORD: { Scanner::Location location = scanner()->location(); ReportMessageAt(location.beg_pos, location.end_pos, - "reserved_word", NULL); + "unexpected_reserved", NULL); *ok = false; return GetIdentifierSymbol(); } @@ -1565,7 +1565,7 @@ void PreParser::StrictModeIdentifierViolation(Scanner::Location location, bool* ok) { const char* type = eval_args_type; if (identifier.IsFutureReserved()) { - type = "reserved_word"; + type = "unexpected_reserved"; } else if (identifier.IsFutureStrictReserved() || identifier.IsYield()) { type = "unexpected_strict_reserved"; } diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index e5cddbf..acd0771 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -1347,200 +1347,70 @@ TEST(PreparserStrictOctal) { } -namespace { - -const char* use_strict_prefix = "\"use strict\";\n"; - -const char* strict_catch_variable_preparse = "strict_catch_variable"; -const char* strict_catch_variable_parse = - "SyntaxError: Catch variable may not be eval or arguments in strict mode"; - -const char* strict_function_name_preparse = "strict_function_name"; -const char* strict_function_name_parse = - "SyntaxError: Function name may not be eval or arguments in strict mode"; - -const char* strict_lhs_assignment_preparse = "strict_lhs_assignment"; -const char* strict_lhs_assignment_parse = - "SyntaxError: Assignment to eval or arguments is not allowed in strict " - "mode"; - -const char* strict_lhs_postfix_preparse = "strict_lhs_postfix"; -const char* strict_lhs_postfix_parse = - "SyntaxError: Postfix increment/decrement may not have eval or arguments " - "operand in strict mode"; - -const char* strict_lhs_prefix_preparse = "strict_lhs_prefix"; -const char* strict_lhs_prefix_parse = - "SyntaxError: Prefix increment/decrement may not have eval or arguments " - "operand in strict mode"; - -const char* strict_param_name_preparse = "strict_param_name"; -const char* strict_param_name_parse = - "SyntaxError: Parameter name eval or arguments is not allowed in strict " - "mode"; - -const char* strict_var_name_preparse = "strict_var_name"; -const char* strict_var_name_parse = - "SyntaxError: Variable name may not be eval or arguments in strict mode"; - -const char* unexpected_strict_reserved_preparse = "unexpected_strict_reserved"; -const char* unexpected_strict_reserved_parse = - "SyntaxError: Unexpected strict mode reserved word"; - -const char* unexpected_token_identifier_preparse = - "unexpected_token_identifier"; -const char* unexpected_token_identifier_parse = - "SyntaxError: Unexpected identifier"; - -struct ParseErrorTestCase { - const char* source; - int error_location_beg; - int error_location_end; - const char* preparse_error_message; - const char* parse_error_message; -}; - - -void VerifyPreParseAndParseNoError(v8::Handle source) { - v8::ScriptData* preparse = v8::ScriptData::PreCompile(source); - CHECK(!preparse->HasError()); - - v8::TryCatch try_catch; - v8::Script::Compile(source); - CHECK(!try_catch.HasCaught()); -} - - -void VerifyPreParseAndParseErrorMessages(v8::Handle source, - int error_location_beg, - int error_location_end, - const char* preparse_error_message, - const char* parse_error_message) { - v8::ScriptData* preparse = v8::ScriptData::PreCompile(source); - CHECK(preparse->HasError()); - i::ScriptDataImpl* pre_impl = - reinterpret_cast(preparse); - i::Scanner::Location error_location = pre_impl->MessageLocation(); - const char* message = pre_impl->BuildMessage(); - CHECK_EQ(0, strcmp(preparse_error_message, message)); - CHECK_EQ(error_location_beg, error_location.beg_pos); - CHECK_EQ(error_location_end, error_location.end_pos); - - v8::TryCatch try_catch; - v8::Script::Compile(source); - CHECK(try_catch.HasCaught()); - v8::String::Utf8Value exception(try_catch.Exception()); - CHECK_EQ(parse_error_message, *exception); - CHECK_EQ(error_location_beg, try_catch.Message()->GetStartPosition()); - CHECK_EQ(error_location_end, try_catch.Message()->GetEndPosition()); -} - -} // namespace - - TEST(ErrorsEvalAndArguments) { // Tests that both preparsing and parsing produce the right kind of errors for // using "eval" and "arguments" as identifiers. Without the strict mode, it's // ok to use "eval" or "arguments" as identifiers. With the strict mode, it // isn't. - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope handles(isolate); - v8::Local context = v8::Context::New(isolate); - v8::Context::Scope context_scope(context); - - int prefix_length = i::StrLength(use_strict_prefix); - - ParseErrorTestCase test_cases[] = { - {"var eval = 42;", 4, 8, strict_var_name_preparse, strict_var_name_parse}, - {"var arguments = 42;", 4, 13, strict_var_name_preparse, - strict_var_name_parse}, - {"var foo, eval;", 9, 13, strict_var_name_preparse, strict_var_name_parse}, - {"var foo, arguments;", 9, 18, strict_var_name_preparse, - strict_var_name_parse}, - {"try { } catch (eval) { }", 15, 19, strict_catch_variable_preparse, - strict_catch_variable_parse}, - {"try { } catch (arguments) { }", 15, 24, strict_catch_variable_preparse, - strict_catch_variable_parse}, - {"function eval() { }", 9, 13, strict_function_name_preparse, - strict_function_name_parse}, - {"function arguments() { }", 9, 18, strict_function_name_preparse, - strict_function_name_parse}, - {"function foo(eval) { }", 13, 17, strict_param_name_preparse, - strict_param_name_parse}, - {"function foo(arguments) { }", 13, 22, strict_param_name_preparse, - strict_param_name_parse}, - {"function foo(bar, eval) { }", 18, 22, strict_param_name_preparse, - strict_param_name_parse}, - {"function foo(bar, arguments) { }", 18, 27, strict_param_name_preparse, - strict_param_name_parse}, - {"eval = 1;", 0, 4, strict_lhs_assignment_preparse, - strict_lhs_assignment_parse}, - {"arguments = 1;", 0, 9, strict_lhs_assignment_preparse, - strict_lhs_assignment_parse}, - {"++eval;", 2, 6, strict_lhs_prefix_preparse, strict_lhs_prefix_parse}, - {"++arguments;", 2, 11, strict_lhs_prefix_preparse, - strict_lhs_prefix_parse}, - {"eval++;", 0, 4, strict_lhs_postfix_preparse, strict_lhs_postfix_parse}, - {"arguments++;", 0, 9, strict_lhs_postfix_preparse, - strict_lhs_postfix_parse}, - {NULL, 0, 0, NULL, NULL} + const char* context_data[][2] = { + { "", "" }, + { "\"use strict\";", "}" }, + { "var eval; function test_func() {", "}"}, + { "var eval; function test_func() {\"use strict\"; ", "}"}, + { NULL, NULL } }; - for (int i = 0; test_cases[i].source; ++i) { - v8::Handle source = - v8::String::NewFromUtf8(isolate, test_cases[i].source); - VerifyPreParseAndParseNoError(source); - - v8::Handle strict_source = v8::String::Concat( - v8::String::NewFromUtf8(isolate, use_strict_prefix), - v8::String::NewFromUtf8(isolate, test_cases[i].source)); - VerifyPreParseAndParseErrorMessages( - strict_source, - test_cases[i].error_location_beg + prefix_length, - test_cases[i].error_location_end + prefix_length, - test_cases[i].preparse_error_message, - test_cases[i].parse_error_message); - } - - // Test cases which produce an error also in non-strict mode. - ParseErrorTestCase error_test_cases[] = { - // In this case we expect something completely different, "(", and get - // "eval". It's always "unexpected identifier, whether we are in strict mode - // or not. - {"function foo eval", 13, 17, unexpected_token_identifier_preparse, - unexpected_token_identifier_parse}, - {"\"use strict\"; function foo eval", 27, 31, - unexpected_token_identifier_preparse, unexpected_token_identifier_parse}, - {NULL, 0, 0, NULL, NULL} + const char* statement_data[] = { + "var eval;", + "var arguments", + "var foo, eval;", + "var foo, arguments;", + "try { } catch (eval) { }", + "try { } catch (arguments) { }", + "function eval() { }", + "function arguments() { }", + "function foo(eval) { }", + "function foo(arguments) { }", + "function foo(bar, eval) { }", + "function foo(bar, arguments) { }", + "eval = 1;", + "arguments = 1;", + "++eval;", + "++arguments;", + "eval++;", + "arguments++;", + NULL }; - for (int i = 0; error_test_cases[i].source; ++i) { - v8::Handle source = - v8::String::NewFromUtf8(isolate, error_test_cases[i].source); - VerifyPreParseAndParseErrorMessages( - source, - error_test_cases[i].error_location_beg, - error_test_cases[i].error_location_end, - error_test_cases[i].preparse_error_message, - error_test_cases[i].parse_error_message); - } + v8::HandleScope handles(CcTest::isolate()); + v8::Handle context = v8::Context::New(CcTest::isolate()); + v8::Context::Scope context_scope(context); - // Test cases where only a sub-scope is strict. - ParseErrorTestCase scoped_test_cases[] = { - {"var eval = 1; function foo() { \"use strict\"; var arguments = 2; }", - 49, 58, strict_var_name_preparse, strict_var_name_parse}, - {NULL, 0, 0, NULL, NULL} - }; + int marker; + CcTest::i_isolate()->stack_guard()->SetStackLimit( + reinterpret_cast(&marker) - 128 * 1024); - for (int i = 0; scoped_test_cases[i].source; ++i) { - v8::Handle source = - v8::String::NewFromUtf8(isolate, scoped_test_cases[i].source); - VerifyPreParseAndParseErrorMessages( - source, - scoped_test_cases[i].error_location_beg, - scoped_test_cases[i].error_location_end, - scoped_test_cases[i].preparse_error_message, - scoped_test_cases[i].parse_error_message); + static const ParserFlag flags[] = { + kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators, + kAllowForOf + }; + for (int i = 0; context_data[i][0] != NULL; ++i) { + for (int j = 0; statement_data[j] != NULL; ++j) { + int kPrefixLen = i::StrLength(context_data[i][0]); + int kStatementLen = i::StrLength(statement_data[j]); + int kSuffixLen = i::StrLength(context_data[i][1]); + int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen; + + // Plug the source code pieces together. + i::ScopedVector program(kProgramSize + 1); + int length = i::OS::SNPrintF(program, + "%s%s%s", + context_data[i][0], + statement_data[j], + context_data[i][1]); + CHECK(length == kProgramSize); + TestParserSync(program.start(), flags, ARRAY_SIZE(flags)); + } } } @@ -1550,93 +1420,114 @@ TEST(ErrorsFutureStrictReservedWords) { // using future strict reserved words as identifiers. Without the strict mode, // it's ok to use future strict reserved words as identifiers. With the strict // mode, it isn't. - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope handles(isolate); - v8::Local context = v8::Context::New(isolate); - v8::Context::Scope context_scope(context); + const char* context_data[][2] = { + { "", "" }, + { "\"use strict\";", "}" }, + { "var eval; function test_func() {", "}"}, + { "var eval; function test_func() {\"use strict\"; ", "}"}, + { NULL, NULL } + }; - const char* use_strict_prefix = "\"use strict\";\n"; - int prefix_length = i::StrLength(use_strict_prefix); - - ParseErrorTestCase test_cases[] = { - {"var interface = 42;", 4, 13, unexpected_strict_reserved_preparse, - unexpected_strict_reserved_parse}, - {"var foo, interface;", 9, 18, unexpected_strict_reserved_preparse, - unexpected_strict_reserved_parse}, - {"try { } catch (interface) { }", 15, 24, - unexpected_strict_reserved_preparse, unexpected_strict_reserved_parse}, - {"function interface() { }", 9, 18, unexpected_strict_reserved_preparse, - unexpected_strict_reserved_parse}, - {"function foo(interface) { }", 13, 22, unexpected_strict_reserved_preparse, - unexpected_strict_reserved_parse}, - {"function foo(bar, interface) { }", 18, 27, - unexpected_strict_reserved_preparse, unexpected_strict_reserved_parse}, - {"interface = 1;", 0, 9, unexpected_strict_reserved_preparse, - unexpected_strict_reserved_parse}, - {"++interface;", 2, 11, unexpected_strict_reserved_preparse, - unexpected_strict_reserved_parse}, - {"interface++;", 0, 9, unexpected_strict_reserved_preparse, - unexpected_strict_reserved_parse}, - {NULL, 0, 0, NULL, NULL} + const char* statement_data[] = { + "var interface = 42;", + "var foo, interface;", + "try { } catch (interface) { }", + "function interface() { }", + "function foo(interface) { }", + "function foo(bar, interface) { }", + "interface = 1;", + "++interface;", + "interface++;", + NULL }; - for (int i = 0; test_cases[i].source; ++i) { - v8::Handle source = - v8::String::NewFromUtf8(isolate, test_cases[i].source); - VerifyPreParseAndParseNoError(source); - - v8::Handle strict_source = v8::String::Concat( - v8::String::NewFromUtf8(isolate, use_strict_prefix), - v8::String::NewFromUtf8(isolate, test_cases[i].source)); - VerifyPreParseAndParseErrorMessages( - strict_source, - test_cases[i].error_location_beg + prefix_length, - test_cases[i].error_location_end + prefix_length, - test_cases[i].preparse_error_message, - test_cases[i].parse_error_message); - } + v8::HandleScope handles(CcTest::isolate()); + v8::Handle context = v8::Context::New(CcTest::isolate()); + v8::Context::Scope context_scope(context); - // Test cases which produce an error also in non-strict mode. - ParseErrorTestCase error_test_cases[] = { - // In this case we expect something completely different, "(", and get a - // strict reserved word. Note that this differs from the "eval or arguments" - // case; there we just report an unexpected identifier. - {"function foo interface", 13, 22, - unexpected_token_identifier_preparse, - unexpected_token_identifier_parse}, - {"\"use strict\"; function foo interface", 27, 36, - unexpected_strict_reserved_preparse, - unexpected_strict_reserved_parse}, - {NULL, 0, 0, NULL, NULL} - }; + int marker; + CcTest::i_isolate()->stack_guard()->SetStackLimit( + reinterpret_cast(&marker) - 128 * 1024); - for (int i = 0; error_test_cases[i].source; ++i) { - v8::Handle source = - v8::String::NewFromUtf8(isolate, error_test_cases[i].source); - VerifyPreParseAndParseErrorMessages( - source, - error_test_cases[i].error_location_beg, - error_test_cases[i].error_location_end, - error_test_cases[i].preparse_error_message, - error_test_cases[i].parse_error_message); + static const ParserFlag flags[] = { + kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators, + kAllowForOf + }; + for (int i = 0; context_data[i][0] != NULL; ++i) { + for (int j = 0; statement_data[j] != NULL; ++j) { + int kPrefixLen = i::StrLength(context_data[i][0]); + int kStatementLen = i::StrLength(statement_data[j]); + int kSuffixLen = i::StrLength(context_data[i][1]); + int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen; + + // Plug the source code pieces together. + i::ScopedVector program(kProgramSize + 1); + int length = i::OS::SNPrintF(program, + "%s%s%s", + context_data[i][0], + statement_data[j], + context_data[i][1]); + CHECK(length == kProgramSize); + TestParserSync(program.start(), flags, ARRAY_SIZE(flags)); + } } +} - // Test cases where only a sub-scope is strict. - ParseErrorTestCase scoped_test_cases[] = { - {"var interface = 1; function foo() { \"use strict\"; var interface = 2; }", - 54, 63, unexpected_strict_reserved_preparse, - unexpected_strict_reserved_parse}, - {NULL, 0, 0, NULL, NULL} + +TEST(ErrorsReservedWords) { + // Tests that both preparsing and parsing produce the right kind of errors for + // using future reserved words as identifiers. These tests don't depend on the + // strict mode. + const char* context_data[][2] = { + { "", "" }, + { "\"use strict\";", "}" }, + { "var eval; function test_func() {", "}"}, + { "var eval; function test_func() {\"use strict\"; ", "}"}, + { NULL, NULL } }; - for (int i = 0; scoped_test_cases[i].source; ++i) { - v8::Handle source = - v8::String::NewFromUtf8(isolate, scoped_test_cases[i].source); - VerifyPreParseAndParseErrorMessages( - source, - scoped_test_cases[i].error_location_beg, - scoped_test_cases[i].error_location_end, - scoped_test_cases[i].preparse_error_message, - scoped_test_cases[i].parse_error_message); + const char* statement_data[] = { + "var super = 42;", + "var foo, super;", + "try { } catch (super) { }", + "function super() { }", + "function foo(super) { }", + "function foo(bar, super) { }", + "super = 1;", + "++super;", + "super++;", + "function foo super", + NULL + }; + + v8::HandleScope handles(CcTest::isolate()); + v8::Handle context = v8::Context::New(CcTest::isolate()); + v8::Context::Scope context_scope(context); + + int marker; + CcTest::i_isolate()->stack_guard()->SetStackLimit( + reinterpret_cast(&marker) - 128 * 1024); + + static const ParserFlag flags[] = { + kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators, + kAllowForOf + }; + for (int i = 0; context_data[i][0] != NULL; ++i) { + for (int j = 0; statement_data[j] != NULL; ++j) { + int kPrefixLen = i::StrLength(context_data[i][0]); + int kStatementLen = i::StrLength(statement_data[j]); + int kSuffixLen = i::StrLength(context_data[i][1]); + int kProgramSize = kPrefixLen + kStatementLen + kSuffixLen; + + // Plug the source code pieces together. + i::ScopedVector program(kProgramSize + 1); + int length = i::OS::SNPrintF(program, + "%s%s%s", + context_data[i][0], + statement_data[j], + context_data[i][1]); + CHECK(length == kProgramSize); + TestParserSync(program.start(), flags, ARRAY_SIZE(flags)); + } } } -- 2.7.4