Chromium Code Reviews| Index: test/cctest/interpreter/generate-bytecode-expectations.cc |
| diff --git a/test/cctest/interpreter/generate-bytecode-expectations.cc b/test/cctest/interpreter/generate-bytecode-expectations.cc |
| index 8bf9ba6dfb9ac28e459e71bf1f7480c1962bd074..3956e1312ef5a3240f9fe5a6eddb3aaf48fe4c2c 100644 |
| --- a/test/cctest/interpreter/generate-bytecode-expectations.cc |
| +++ b/test/cctest/interpreter/generate-bytecode-expectations.cc |
| @@ -28,6 +28,9 @@ class ProgramOptions { |
| print_help_(false), |
| read_raw_js_snippet_(false), |
| read_from_stdin_(false), |
| + rebaseline_(false), |
| + wrap_(true), |
| + execute_(true), |
| const_pool_type_( |
| BytecodeExpectationsPrinter::ConstantPoolType::kMixed) {} |
| @@ -37,18 +40,41 @@ class ProgramOptions { |
| bool print_help() const { return print_help_; } |
| bool read_raw_js_snippet() const { return read_raw_js_snippet_; } |
| bool read_from_stdin() const { return read_from_stdin_; } |
| - std::string filename() const { return filename_; } |
| + bool write_to_stdout() const { |
| + return output_filename_.empty() && !rebaseline_; |
| + } |
| + bool rebaseline() const { return rebaseline_; } |
| + bool wrap() const { return wrap_; } |
| + bool execute() const { return execute_; } |
| BytecodeExpectationsPrinter::ConstantPoolType const_pool_type() const { |
| return const_pool_type_; |
| } |
| + std::string input_filename() const { return input_filename_; } |
| + std::string output_filename() const { return output_filename_; } |
| + std::string top_function_name() const { return top_function_name_; } |
| + |
| + void set_const_pool_type( |
| + BytecodeExpectationsPrinter::ConstantPoolType const_pool_type) { |
| + const_pool_type_ = const_pool_type; |
| + } |
| + void set_execute(bool execute) { execute_ = execute; } |
| + void set_wrap(bool wrap) { wrap_ = wrap; } |
| + void set_top_function_name(const std::string& top_function_name) { |
| + top_function_name_ = top_function_name; |
| + } |
| private: |
| bool parsing_failed_; |
| bool print_help_; |
| bool read_raw_js_snippet_; |
| bool read_from_stdin_; |
| + bool rebaseline_; |
| + bool wrap_; |
| + bool execute_; |
| BytecodeExpectationsPrinter::ConstantPoolType const_pool_type_; |
| - std::string filename_; |
| + std::string input_filename_; |
| + std::string output_filename_; |
| + std::string top_function_name_; |
| }; |
| class ArrayBufferAllocator final : public v8::ArrayBuffer::Allocator { |
| @@ -95,8 +121,6 @@ BytecodeExpectationsPrinter::ConstantPoolType ParseConstantPoolType( |
| ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) { |
| ProgramOptions options; |
| - if (argc <= 1) return options; |
| - |
| for (int i = 1; i < argc; ++i) { |
| if (strcmp(argv[i], "--help") == 0) { |
| options.print_help_ = true; |
| @@ -106,13 +130,23 @@ ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) { |
| options.const_pool_type_ = ParseConstantPoolType(argv[i] + 12); |
| } else if (strcmp(argv[i], "--stdin") == 0) { |
| options.read_from_stdin_ = true; |
| + } else if (strcmp(argv[i], "--rebaseline") == 0) { |
| + options.rebaseline_ = true; |
| + } else if (strcmp(argv[i], "--no-wrap") == 0) { |
| + options.wrap_ = false; |
| + } else if (strcmp(argv[i], "--no-execute") == 0) { |
| + options.execute_ = false; |
| + } else if (strncmp(argv[i], "--output=", 9) == 0) { |
| + options.output_filename_ = argv[i] + 9; |
| + } else if (strncmp(argv[i], "--wrapper-name=", 15) == 0) { |
| + options.top_function_name_ = argv[i] + 15; |
| } else if (strncmp(argv[i], "--", 2) != 0) { // It doesn't start with -- |
| - if (!options.filename_.empty()) { |
| + if (!options.input_filename_.empty()) { |
| std::cerr << "ERROR: More than one input file specified\n"; |
| options.parsing_failed_ = true; |
| break; |
| } |
| - options.filename_ = argv[i]; |
| + options.input_filename_ = argv[i]; |
| } else { |
| std::cerr << "ERROR: Unknonwn option " << argv[i] << "\n"; |
| options.parsing_failed_ = true; |
| @@ -123,6 +157,46 @@ ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) { |
| return options; |
| } |
| +bool ParseBoolean(const char* string) { |
| + if (strcmp(string, "yes") == 0) { |
| + return true; |
| + } else if (strcmp(string, "no") == 0) { |
| + return false; |
| + } else { |
| + UNREACHABLE(); |
| + return false; |
| + } |
| +} |
| + |
| +void UpdateOptionsFromHeader(ProgramOptions* options, |
|
rmcilroy
2016/02/18 09:58:33
Nit - make this a member function of ProgramOption
Stefano Sanfilippo
2016/02/18 11:14:12
Done.
|
| + std::istream& stream) { // NOLINT |
| + std::string line; |
| + |
| + // Skip to the beginning of the options header |
| + while (std::getline(stream, line)) { |
| + if (line == "---") break; |
| + } |
| + |
| + while (std::getline(stream, line)) { |
| + if (line.compare(0, 11, "pool type: ") == 0) { |
| + options->set_const_pool_type(ParseConstantPoolType(line.c_str() + 11)); |
| + } else if (line.compare(0, 9, "execute: ") == 0) { |
| + options->set_execute(ParseBoolean(line.c_str() + 9)); |
| + } else if (line.compare(0, 6, "wrap: ") == 0) { |
| + options->set_wrap(ParseBoolean(line.c_str() + 6)); |
| + } else if (line.compare(0, 14, "wrapper name: ") == 0) { |
| + options->set_top_function_name(line.c_str() + 14); |
| + } else if (line == "---") { |
| + break; |
| + } else if (line.empty()) { |
| + continue; |
| + } else { |
| + UNREACHABLE(); |
| + return; |
| + } |
| + } |
| +} |
| + |
| bool ProgramOptions::Validate() const { |
| if (parsing_failed_) return false; |
| if (print_help_) return true; |
| @@ -133,16 +207,26 @@ bool ProgramOptions::Validate() const { |
| return false; |
| } |
| - if (!read_from_stdin_ && filename_.empty()) { |
| + if (!read_from_stdin_ && input_filename_.empty()) { |
| std::cerr << "ERROR: No input file specified.\n"; |
| return false; |
| } |
| - if (read_from_stdin_ && !filename_.empty()) { |
| + if (read_from_stdin_ && !input_filename_.empty()) { |
| std::cerr << "ERROR: Reading from stdin, but input files supplied.\n"; |
| return false; |
| } |
| + if (!wrap_ && !top_function_name_.empty()) { |
| + std::cerr << "ERROR: Not wrapping, but wrapper name specified.\n"; |
| + return false; |
| + } |
| + |
| + if (rebaseline_ && read_raw_js_snippet_) { |
| + std::cerr << "ERROR: Cannot use --rebaseline on a raw JS snippet.\n"; |
| + return false; |
| + } |
| + |
| return true; |
| } |
| @@ -194,41 +278,78 @@ bool ReadNextSnippet(std::istream& stream, std::string* string_out) { // NOLINT |
| return false; |
| } |
| -void ExtractSnippetsFromStream(std::vector<std::string>* snippet_list, |
| - std::istream& body_stream, // NOLINT |
| - bool read_raw_js_snippet) { |
| +std::string UnescapeString(const std::string& escaped_string) { |
| + std::string unescaped_string; |
| + bool previous_was_backslash = false; |
| + for (char c : escaped_string) { |
| + if (previous_was_backslash) { |
| + // If it was not an escape sequence, emit the previous backslash |
| + if (c != '\\' && c != '"') unescaped_string += '\\'; |
| + unescaped_string += c; |
| + previous_was_backslash = false; |
| + } else { |
| + if (c == '\\') { |
| + previous_was_backslash = true; |
| + // Defer emission to the point where we can check if it was an escape. |
| + } else { |
| + unescaped_string += c; |
| + } |
| + } |
| + } |
| + return unescaped_string; |
| +} |
| + |
| +void ExtractSnippets(std::vector<std::string>* snippet_list, |
| + std::istream& body_stream, // NOLINT |
| + bool read_raw_js_snippet) { |
| if (read_raw_js_snippet) { |
| snippet_list->push_back(ReadRawJSSnippet(body_stream)); |
| } else { |
| std::string snippet; |
| while (ReadNextSnippet(body_stream, &snippet)) { |
| - snippet_list->push_back(snippet); |
| + snippet_list->push_back(UnescapeString(snippet)); |
| } |
| } |
| } |
| -bool ExtractSnippets(std::vector<std::string>* snippet_list, |
| - const ProgramOptions& options) { |
| - if (options.read_from_stdin()) { |
| - ExtractSnippetsFromStream(snippet_list, std::cin, |
| - options.read_raw_js_snippet()); |
| - } else { |
| - std::ifstream body_file(options.filename().c_str()); |
| - if (!body_file.is_open()) { |
| - std::cerr << "ERROR: Could not open '" << options.filename() << "'.\n"; |
| - return false; |
| - } |
| - ExtractSnippetsFromStream(snippet_list, body_file, |
| - options.read_raw_js_snippet()); |
| +const char* ConstantPoolTypeToString( |
| + BytecodeExpectationsPrinter::ConstantPoolType type) { |
| + switch (type) { |
| + case BytecodeExpectationsPrinter::ConstantPoolType::kDouble: |
| + return "double"; |
| + case BytecodeExpectationsPrinter::ConstantPoolType::kInteger: |
| + return "integer"; |
| + case BytecodeExpectationsPrinter::ConstantPoolType::kMixed: |
| + return "mixed"; |
| + case BytecodeExpectationsPrinter::ConstantPoolType::kString: |
| + return "string"; |
| + default: |
| + UNREACHABLE(); |
| + return nullptr; |
| } |
| - return true; |
| } |
| -void GenerateExpectationsFile( |
| - std::ostream& stream, // NOLINT |
| - const std::vector<std::string>& snippet_list, |
| - BytecodeExpectationsPrinter::ConstantPoolType const_pool_type, |
| - const char* exec_path) { |
| +const char* BooleanToString(bool value) { return value ? "yes" : "no"; } |
| + |
| +void PrintOptionsHeader(std::ostream& stream, // NOLINT, |
|
rmcilroy
2016/02/18 09:58:33
Also make this a member on ProgramOptions and call
Stefano Sanfilippo
2016/02/18 11:14:12
Done the first part. I have grouped helpers at the
|
| + const ProgramOptions& options) { |
| + stream << "---" |
| + "\npool type: " |
| + << ConstantPoolTypeToString(options.const_pool_type()) |
| + << "\nexecute: " << BooleanToString(options.execute()) |
| + << "\nwrap: " << BooleanToString(options.wrap()); |
| + |
| + if (!options.top_function_name().empty()) { |
| + stream << "\nwrapper name: " << options.top_function_name(); |
| + } |
| + |
| + stream << "\n\n"; |
| +} |
| + |
| +void GenerateExpectationsFile(std::ostream& stream, // NOLINT |
| + const std::vector<std::string>& snippet_list, |
| + const ProgramOptions& options, |
| + const char* exec_path) { |
| V8InitializationScope platform(exec_path); |
| { |
| v8::Isolate::Scope isolate_scope(platform.isolate()); |
| @@ -236,9 +357,16 @@ void GenerateExpectationsFile( |
| v8::Local<v8::Context> context = v8::Context::New(platform.isolate()); |
| v8::Context::Scope context_scope(context); |
| - stream << "#\n# Autogenerated by generate-bytecode-expectations\n#\n\n"; |
| + BytecodeExpectationsPrinter printer(platform.isolate(), |
| + options.const_pool_type()); |
| + printer.set_wrap(options.wrap()); |
| + printer.set_execute(options.execute()); |
| + if (!options.top_function_name().empty()) { |
| + printer.set_top_function_name(options.top_function_name()); |
| + } |
| - BytecodeExpectationsPrinter printer(platform.isolate(), const_pool_type); |
| + stream << "#\n# Autogenerated by generate-bytecode-expectations\n#\n\n"; |
| + PrintOptionsHeader(stream, options); |
| for (const std::string& snippet : snippet_list) { |
| printer.PrintExpectation(stream, snippet); |
| } |
| @@ -253,10 +381,21 @@ void PrintUsage(const char* exec_path) { |
| " --help Print this help message.\n" |
| " --raw-js Read raw JavaScript, instead of the output format.\n" |
| " --stdin Read from standard input instead of file.\n" |
| + " --rebaseline Rebaseline input snippet file.\n" |
| + " --no-wrap Do not wrap the snippet in a function.\n" |
| + " --no-execute Do not execute after compilation.\n" |
| + " --wrapper-name=foo Specify the name of the wrapper function.\n" |
| + " --output=file.name\n" |
| + " Specify the output file. If not specified, output goes to " |
| + "stdout.\n" |
| " --pool-type=(int|double|string|mixed)\n" |
| - " specify the type of the entries in the constant pool " |
| + " Specify the type of the entries in the constant pool " |
| "(default: mixed).\n" |
| "\n" |
| + "When using --rebaseline, flags --no-wrap, --no-execute, " |
| + "--wrapper-name and \n--pool-type will be overridden by the options " |
| + "specified in the input file\n" |
| + "header.\n\n" |
| "Each raw JavaScript file is interpreted as a single snippet.\n\n" |
| "This tool is intended as a help in writing tests.\n" |
| "Please, DO NOT blindly copy and paste the output " |
| @@ -273,11 +412,39 @@ int main(int argc, char** argv) { |
| return options.print_help() ? 0 : 1; |
| } |
| + std::ifstream input_file_handle; |
| + if (!options.read_from_stdin()) { |
| + input_file_handle.open(options.input_filename().c_str()); |
| + if (!input_file_handle.is_open()) { |
| + std::cerr << "ERROR: Could not open '" << options.input_filename() |
| + << "' for reading.\n"; |
| + return 2; |
| + } |
| + } |
| + std::istream& input_stream = |
| + options.read_from_stdin() ? std::cin : input_file_handle; |
| + |
| + if (!options.rebaseline()) { |
| + UpdateOptionsFromHeader(&options, input_stream); |
| + } |
| + CHECK(options.Validate()); |
| + |
| std::vector<std::string> snippet_list; |
| - if (!ExtractSnippets(&snippet_list, options)) { |
| - return 2; |
| + ExtractSnippets(&snippet_list, input_stream, options.read_raw_js_snippet()); |
| + |
| + std::ofstream output_file_handle; |
| + if (!options.write_to_stdout()) { |
| + output_file_handle.open(options.rebaseline() |
| + ? options.input_filename().c_str() |
| + : options.output_filename().c_str()); |
| + if (!output_file_handle.is_open()) { |
| + std::cerr << "ERROR: Could not open '" << options.output_filename() |
| + << "' for writing.\n"; |
| + return 3; |
| + } |
| } |
| + std::ostream& output_stream = |
| + options.write_to_stdout() ? std::cout : output_file_handle; |
| - GenerateExpectationsFile(std::cout, snippet_list, options.const_pool_type(), |
| - argv[0]); |
| + GenerateExpectationsFile(output_stream, snippet_list, options, argv[0]); |
| } |