Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-parsing.cc
index 8fbd60d..22d5056 100644 (file)
@@ -244,8 +244,11 @@ TEST(Preparsing) {
   CHECK_EQ(11, error_location.end_pos);
   // Should not crash.
   const char* message = pre_impl->BuildMessage();
-  pre_impl->BuildArgs();
+  i::Vector<const char*> args = pre_impl->BuildArgs();
   CHECK_GT(strlen(message), 0);
+  args.Dispose();
+  i::DeleteArray(message);
+  delete error_preparse;
 }
 
 
@@ -1019,7 +1022,7 @@ TEST(ScopePositions) {
     int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
     int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
     int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
-    i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1);
+    i::ScopedVector<char> program(kProgramByteSize + 1);
     i::OS::SNPrintF(program, "%s%s%s",
                              source_data[i].outer_prefix,
                              source_data[i].inner_source,
@@ -1099,6 +1102,13 @@ enum ParserFlag {
 };
 
 
+enum ParserSyncTestResult {
+  kSuccessOrError,
+  kSuccess,
+  kError
+};
+
+
 void SetParserFlags(i::ParserBase* parser, i::EnumSet<ParserFlag> flags) {
   parser->set_allow_lazy(flags.Contains(kAllowLazy));
   parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
@@ -1112,7 +1122,8 @@ void SetParserFlags(i::ParserBase* parser, i::EnumSet<ParserFlag> flags) {
 
 
 void TestParserSyncWithFlags(i::Handle<i::String> source,
-                             i::EnumSet<ParserFlag> flags) {
+                             i::EnumSet<ParserFlag> flags,
+                             ParserSyncTestResult result) {
   i::Isolate* isolate = CcTest::i_isolate();
   i::Factory* factory = isolate->factory();
 
@@ -1154,6 +1165,17 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
     i::Handle<i::String> message_string =
         i::Handle<i::String>::cast(i::GetProperty(exception_handle, "message"));
 
+    if (result == kSuccess) {
+      i::OS::Print(
+          "Parser failed on:\n"
+          "\t%s\n"
+          "with error:\n"
+          "\t%s\n"
+          "However, we expected no error.",
+          source->ToCString().get(), message_string->ToCString().get());
+      CHECK(false);
+    }
+
     if (!data.has_error()) {
       i::OS::Print(
           "Parser failed on:\n"
@@ -1187,13 +1209,21 @@ void TestParserSyncWithFlags(i::Handle<i::String> source,
         "However, the parser succeeded",
         source->ToCString().get(), FormatMessage(&data)->ToCString().get());
     CHECK(false);
+  } else if (result == kError) {
+    i::OS::Print(
+        "Expected error on:\n"
+        "\t%s\n"
+        "However, parser and preparser succeeded",
+        source->ToCString().get());
+    CHECK(false);
   }
 }
 
 
 void TestParserSync(const char* source,
                     const ParserFlag* flag_list,
-                    size_t flag_list_length) {
+                    size_t flag_list_length,
+                    ParserSyncTestResult result = kSuccessOrError) {
   i::Handle<i::String> str =
       CcTest::i_isolate()->factory()->NewStringFromAscii(i::CStrVector(source));
   for (int bits = 0; bits < (1 << flag_list_length); bits++) {
@@ -1201,7 +1231,7 @@ void TestParserSync(const char* source,
     for (size_t flag_index = 0; flag_index < flag_list_length; flag_index++) {
       if ((bits & (1 << flag_index)) != 0) flags.Add(flag_list[flag_index]);
     }
-    TestParserSyncWithFlags(str, flags);
+    TestParserSyncWithFlags(str, flags, result);
   }
 }
 
@@ -1345,3 +1375,641 @@ TEST(PreparserStrictOctal) {
   CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.",
            *exception);
 }
+
+
+void RunParserSyncTest(const char* context_data[][2],
+                       const char* statement_data[],
+                       ParserSyncTestResult result) {
+  v8::HandleScope handles(CcTest::isolate());
+  v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
+  v8::Context::Scope context_scope(context);
+
+  int marker;
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      reinterpret_cast<uintptr_t>(&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<char> 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),
+                     result);
+    }
+  }
+}
+
+
+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.
+  const char* context_data[][2] = {
+    { "\"use strict\";", "" },
+    { "var eval; function test_func() {\"use strict\"; ", "}"},
+    { 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;",
+    "var foo = eval = 1;",
+    "var foo = arguments = 1;",
+    "++eval;",
+    "++arguments;",
+    "eval++;",
+    "arguments++;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsEvalAndArgumentsClassic) {
+  // Tests that both preparsing and parsing accept "eval" and "arguments" as
+  // identifiers when needed.
+  const char* context_data[][2] = {
+    { "", "" },
+    { "function test_func() {", "}"},
+    { 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;",
+    "var foo = eval = 1;",
+    "var foo = arguments = 1;",
+    "++eval;",
+    "++arguments;",
+    "eval++;",
+    "arguments++;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(NoErrorsEvalAndArgumentsStrict) {
+  const char* context_data[][2] = {
+    { "\"use strict\";", "" },
+    { "function test_func() { \"use strict\";", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "eval;",
+    "arguments;",
+    "var foo = eval;",
+    "var foo = arguments;",
+    "var foo = { eval: 1 };",
+    "var foo = { arguments: 1 };",
+    "var foo = { }; foo.eval = {};",
+    "var foo = { }; foo.arguments = {};",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsFutureStrictReservedWords) {
+  // Tests that both preparsing and parsing produce the right kind of errors for
+  // 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.
+  const char* context_data[][2] = {
+    { "\"use strict\";", "" },
+    { "function test_func() {\"use strict\"; ", "}"},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var interface;",
+    "var foo, interface;",
+    "try { } catch (interface) { }",
+    "function interface() { }",
+    "function foo(interface) { }",
+    "function foo(bar, interface) { }",
+    "interface = 1;",
+    "var foo = interface = 1;",
+    "++interface;",
+    "interface++;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsFutureStrictReservedWords) {
+  const char* context_data[][2] = {
+    { "", "" },
+    { "function test_func() {", "}"},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var interface;",
+    "var foo, interface;",
+    "try { } catch (interface) { }",
+    "function interface() { }",
+    "function foo(interface) { }",
+    "function foo(bar, interface) { }",
+    "interface = 1;",
+    "var foo = interface = 1;",
+    "++interface;",
+    "interface++;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+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 }
+  };
+
+  const char* statement_data[] = {
+    "var super;",
+    "var foo, super;",
+    "try { } catch (super) { }",
+    "function super() { }",
+    "function foo(super) { }",
+    "function foo(bar, super) { }",
+    "super = 1;",
+    "var foo = super = 1;",
+    "++super;",
+    "super++;",
+    "function foo super",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsYieldClassic) {
+  // In classic mode, it's okay to use "yield" as identifier, *except* inside a
+  // generator (see next test).
+  const char* context_data[][2] = {
+    { "", "" },
+    { "function is_not_gen() {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var yield;",
+    "var foo, yield;",
+    "try { } catch (yield) { }",
+    "function yield() { }",
+    "function foo(yield) { }",
+    "function foo(bar, yield) { }",
+    "yield = 1;",
+    "var foo = yield = 1;",
+    "++yield;",
+    "yield++;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsYieldClassicGenerator) {
+  const char* context_data[][2] = {
+    { "function * is_gen() {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var yield;",
+    "var foo, yield;",
+    "try { } catch (yield) { }",
+    "function yield() { }",
+    // BUG: These should not be allowed, but they are (if kAllowGenerators is
+    // set)
+    // "function foo(yield) { }",
+    // "function foo(bar, yield) { }",
+    "yield = 1;",
+    "var foo = yield = 1;",
+    "++yield;",
+    "yield++;",
+    NULL
+  };
+
+  // If generators are not allowed, the error will be produced at the '*' token,
+  // so this test works both with and without the kAllowGenerators flag.
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(ErrorsYieldStrict) {
+  const char* context_data[][2] = {
+    { "\"use strict\";", "" },
+    { "\"use strict\"; function is_not_gen() {", "}" },
+    { "function test_func() {\"use strict\"; ", "}"},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var yield;",
+    "var foo, yield;",
+    "try { } catch (yield) { }",
+    "function yield() { }",
+    "function foo(yield) { }",
+    "function foo(bar, yield) { }",
+    "yield = 1;",
+    "var foo = yield = 1;",
+    "++yield;",
+    "yield++;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(ErrorsYield) {
+  const char* context_data[][2] = {
+    { "function * is_gen() {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "yield 2;",  // this is legal inside generator
+    "yield * 2;",  // this is legal inside generator
+    NULL
+  };
+
+  // Here we cannot assert that there is no error, since there will be without
+  // the kAllowGenerators flag. However, we test that Parser and PreParser
+  // produce the same errors.
+  RunParserSyncTest(context_data, statement_data, kSuccessOrError);
+}
+
+
+TEST(ErrorsNameOfStrictFunction) {
+  // Tests that illegal tokens as names of a strict function produce the correct
+  // errors.
+  const char* context_data[][2] = {
+    { "", ""},
+    { "\"use strict\";", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "function eval() {\"use strict\";}",
+    "function arguments() {\"use strict\";}",
+    "function interface() {\"use strict\";}",
+    "function yield() {\"use strict\";}",
+    // Future reserved words are always illegal
+    "function super() { }",
+    "function super() {\"use strict\";}",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsNameOfStrictFunction) {
+  const char* context_data[][2] = {
+    { "", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "function eval() { }",
+    "function arguments() { }",
+    "function interface() { }",
+    "function yield() { }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+
+TEST(ErrorsIllegalWordsAsLabelsClassic) {
+  // Using future reserved words as labels is always an error.
+  const char* context_data[][2] = {
+    { "", ""},
+    { "function test_func() {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "super: while(true) { break super; }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(ErrorsIllegalWordsAsLabelsStrict) {
+  // Tests that illegal tokens as labels produce the correct errors.
+  const char* context_data[][2] = {
+    { "\"use strict\";", "" },
+    { "function test_func() {\"use strict\"; ", "}"},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "super: while(true) { break super; }",
+    "interface: while(true) { break interface; }",
+    "yield: while(true) { break yield; }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsIllegalWordsAsLabels) {
+  // Using eval and arguments as labels is legal even in strict mode.
+  const char* context_data[][2] = {
+    { "", ""},
+    { "function test_func() {", "}" },
+    { "\"use strict\";", "" },
+    { "\"use strict\"; function test_func() {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "mylabel: while(true) { break mylabel; }",
+    "eval: while(true) { break eval; }",
+    "arguments: while(true) { break arguments; }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsParenthesizedLabels) {
+  // Parenthesized identifiers shouldn't be recognized as labels.
+  const char* context_data[][2] = {
+    { "", ""},
+    { "function test_func() {", "}" },
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "(mylabel): while(true) { break mylabel; }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsParenthesizedDirectivePrologue) {
+  // Parenthesized directive prologue shouldn't be recognized.
+  const char* context_data[][2] = {
+    { "", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "(\"use strict\"); var eval;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(ErrorsNotAnIdentifierName) {
+  const char* context_data[][2] = {
+    { "", ""},
+    { "\"use strict\";", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var foo = {}; foo.{;",
+    "var foo = {}; foo.};",
+    "var foo = {}; foo.=;",
+    "var foo = {}; foo.888;",
+    "var foo = {}; foo.-;",
+    "var foo = {}; foo.--;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsIdentifierNames) {
+  // Keywords etc. are valid as property names.
+  const char* context_data[][2] = {
+    { "", ""},
+    { "\"use strict\";", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "var foo = {}; foo.if;",
+    "var foo = {}; foo.yield;",
+    "var foo = {}; foo.super;",
+    "var foo = {}; foo.interface;",
+    "var foo = {}; foo.eval;",
+    "var foo = {}; foo.arguments;",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}
+
+
+TEST(DontRegressPreParserDataSizes) {
+  // These tests make sure that PreParser doesn't start producing less data.
+
+  v8::V8::Initialize();
+
+  int marker;
+  CcTest::i_isolate()->stack_guard()->SetStackLimit(
+      reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
+
+  struct TestCase {
+    const char* program;
+    int symbols;
+    int functions;
+  } test_cases[] = {
+    // Labels, variables and functions are recorded as symbols.
+    {"{label: 42}", 1, 0}, {"{label: 42; label2: 43}", 2, 0},
+    {"var x = 42;", 1, 0}, {"var x = 42, y = 43;", 2, 0},
+    {"function foo() {}", 1, 1}, {"function foo() {} function bar() {}", 2, 2},
+    // Labels, variables and functions insize lazy functions are not recorded.
+    {"function lazy() { var a, b, c; }", 1, 1},
+    {"function lazy() { a: 1; b: 2; c: 3; }", 1, 1},
+    {"function lazy() { function a() {} function b() {} function c() {} }", 1,
+     1},
+    {NULL, 0, 0}
+  };
+  // Each function adds 5 elements to the preparse function data.
+  const int kDataPerFunction = 5;
+
+  uintptr_t stack_limit = CcTest::i_isolate()->stack_guard()->real_climit();
+  for (int i = 0; test_cases[i].program; i++) {
+    const char* program = test_cases[i].program;
+    i::Utf8ToUtf16CharacterStream stream(
+        reinterpret_cast<const i::byte*>(program),
+        static_cast<unsigned>(strlen(program)));
+    i::CompleteParserRecorder log;
+    i::Scanner scanner(CcTest::i_isolate()->unicode_cache());
+    scanner.Initialize(&stream);
+
+    i::PreParser preparser(&scanner, &log, stack_limit);
+    preparser.set_allow_lazy(true);
+    preparser.set_allow_natives_syntax(true);
+    i::PreParser::PreParseResult result = preparser.PreParseProgram();
+    CHECK_EQ(i::PreParser::kPreParseSuccess, result);
+    if (log.symbol_ids() != test_cases[i].symbols) {
+      i::OS::Print(
+          "Expected preparse data for program:\n"
+          "\t%s\n"
+          "to contain %d symbols, however, received %d symbols.\n",
+          program, test_cases[i].symbols, log.symbol_ids());
+      CHECK(false);
+    }
+    if (log.function_position() != test_cases[i].functions * kDataPerFunction) {
+      i::OS::Print(
+          "Expected preparse data for program:\n"
+          "\t%s\n"
+          "to contain %d functions, however, received %d functions.\n",
+          program, test_cases[i].functions,
+          log.function_position() / kDataPerFunction);
+      CHECK(false);
+    }
+    i::ScriptDataImpl data(log.ExtractData());
+    CHECK(!data.has_error());
+  }
+}
+
+
+TEST(FunctionDeclaresItselfStrict) {
+  // Tests that we produce the right kinds of errors when a function declares
+  // itself strict (we cannot produce there errors as soon as we see the
+  // offending identifiers, because we don't know at that point whether the
+  // function is strict or not).
+  const char* context_data[][2] = {
+    {"function eval() {", "}"},
+    {"function arguments() {", "}"},
+    {"function yield() {", "}"},
+    {"function interface() {", "}"},
+    {"function foo(eval) {", "}"},
+    {"function foo(arguments) {", "}"},
+    {"function foo(yield) {", "}"},
+    {"function foo(interface) {", "}"},
+    {"function foo(bar, eval) {", "}"},
+    {"function foo(bar, arguments) {", "}"},
+    {"function foo(bar, yield) {", "}"},
+    {"function foo(bar, interface) {", "}"},
+    {"function foo(bar, bar) {", "}"},
+    { NULL, NULL }
+  };
+
+  const char* strict_statement_data[] = {
+    "\"use strict\";",
+    NULL
+  };
+
+  const char* non_strict_statement_data[] = {
+    ";",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, strict_statement_data, kError);
+  RunParserSyncTest(context_data, non_strict_statement_data, kSuccess);
+}
+
+
+TEST(ErrorsTryWithoutCatchOrFinally) {
+  const char* context_data[][2] = {
+    {"", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "try { }",
+    "try { } foo();",
+    "try { } catch (e) foo();",
+    "try { } catch { }",
+    "try { } finally foo();",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsTryCatchFinally) {
+  const char* context_data[][2] = {
+    {"", ""},
+    { NULL, NULL }
+  };
+
+  const char* statement_data[] = {
+    "try { } catch (e) { }",
+    "try { } catch (e) { } finally { }",
+    "try { } finally { }",
+    NULL
+  };
+
+  RunParserSyncTest(context_data, statement_data, kSuccess);
+}