// Copyright 2022 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/parsing/parsing.h" #include #include #include #include #include "src/api/api-inl.h" #include "src/ast/ast-value-factory.h" #include "src/ast/ast.h" #include "src/base/enum-set.h" #include "src/base/strings.h" #include "src/execution/execution.h" #include "src/execution/isolate.h" #include "src/flags/flags.h" #include "src/objects/objects-inl.h" #include "src/objects/objects.h" #include "src/parsing/parse-info.h" #include "src/parsing/parser.h" #include "src/parsing/preparser.h" #include "src/parsing/scanner-character-streams.h" #include "src/parsing/token.h" #include "src/zone/zone-list-inl.h" // crbug.com/v8/8816 #include "test/common/flag-utils.h" #include "test/unittests/parser/scope-test-helper.h" #include "test/unittests/parser/unicode-helpers.h" #include "test/unittests/test-utils.h" namespace v8 { namespace internal { namespace test_parsing { namespace { int* global_use_counts = nullptr; void MockUseCounterCallback(v8::Isolate* isolate, v8::Isolate::UseCounterFeature feature) { ++global_use_counts[feature]; } enum ParserFlag { kAllowLazy, kAllowNatives, }; enum ParserSyncTestResult { kSuccessOrError, kSuccess, kError }; void SetGlobalFlags(base::EnumSet flags) { i::v8_flags.allow_natives_syntax = flags.contains(kAllowNatives); } void SetParserFlags(i::UnoptimizedCompileFlags* compile_flags, base::EnumSet flags) { compile_flags->set_allow_natives_syntax(flags.contains(kAllowNatives)); } struct Input { bool assigned; std::string source; std::vector location; // "Directions" to the relevant scope. }; } // namespace // Helpers for parsing and checking that the result has no error, implemented as // macros to report the correct test error location. #define FAIL_WITH_PENDING_PARSER_ERROR(info, script, isolate) \ do { \ (info)->pending_error_handler()->PrepareErrors( \ (isolate), (info)->ast_value_factory()); \ (info)->pending_error_handler()->ReportErrors((isolate), (script)); \ \ i::Handle exception_handle( \ i::Cast((isolate)->exception()), (isolate)); \ i::DirectHandle message_string = i::Cast( \ i::JSReceiver::GetProperty((isolate), exception_handle, "message") \ .ToHandleChecked()); \ (isolate)->clear_exception(); \ \ Tagged script_source = Cast((script)->source()); \ \ FATAL( \ "Parser failed on:\n" \ "\t%s\n" \ "with error:\n" \ "\t%s\n" \ "However, we expected no error.", \ script_source->ToCString().get(), message_string->ToCString().get()); \ } while (false) #define CHECK_PARSE_PROGRAM(info, script, isolate) \ do { \ if (!i::parsing::ParseProgram((info), script, (isolate), \ parsing::ReportStatisticsMode::kYes)) { \ FAIL_WITH_PENDING_PARSER_ERROR((info), (script), (isolate)); \ } \ \ CHECK(!(info)->pending_error_handler()->has_pending_error()); \ CHECK_NOT_NULL((info)->literal()); \ } while (false) #define CHECK_PARSE_FUNCTION(info, shared, isolate) \ do { \ if (!i::parsing::ParseFunction((info), (shared), (isolate), \ parsing::ReportStatisticsMode::kYes)) { \ FAIL_WITH_PENDING_PARSER_ERROR( \ (info), handle(Cast