Chromium Code Reviews| Index: chrome/tools/profile_reset/jtl_compiler.cc |
| diff --git a/chrome/tools/profile_reset/jtl_compiler.cc b/chrome/tools/profile_reset/jtl_compiler.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4550dcbf424d72bee9a0be13653034f9f611e92e |
| --- /dev/null |
| +++ b/chrome/tools/profile_reset/jtl_compiler.cc |
| @@ -0,0 +1,196 @@ |
| +// Copyright 2013 The Chromium 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 "chrome/tools/profile_reset/jtl_compiler.h" |
| + |
| +#include <map> |
| +#include <string> |
| + |
| +#include "base/logging.h" |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/strings/string_util.h" |
| +#include "chrome/browser/profile_resetter/jtl_foundation.h" |
| +#include "chrome/tools/profile_reset/jtl_parser.h" |
| + |
| +namespace jtl = jtl_foundation; |
| + |
| +namespace { |
| + |
| +// Serializes symbols into byte-code in a streaming manner. |
| +class ByteCodeWriter { |
| + public: |
| + explicit ByteCodeWriter(std::string* output) : output_(output) {} |
| + ~ByteCodeWriter() {} |
| + |
| + void WriteUint8(uint8 value) { output_->push_back(static_cast<char>(value)); } |
| + void WriteOpCode(uint8 op_code) { WriteUint8(op_code); } |
| + void WriteHash(const std::string& hash) { |
| + CHECK(hash.size() == jtl::kHashSizeInBytes); |
|
battre
2013/10/01 12:18:26
nit: CHECK_EQ(jtl::kHashSizeInBytes, hash.size());
engedy
2013/10/01 15:09:33
Done.
|
| + *output_ += hash; |
| + } |
| + void WriteBool(bool value) { WriteUint8(value ? 1u : 0u); } |
| + |
| + private: |
| + std::string* output_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ByteCodeWriter); |
| +}; |
| + |
| +// Encapsulates meta-data about all instructions, and is capable of transcoding |
| +// each instruction from a parsed text-based format to byte-code. |
| +class InstructionSet { |
| + public: |
| + InstructionSet() { |
| + // Define each instruction in this list. |
| + Add(Instruction("node", jtl::NAVIGATE, Arguments(Hash))); |
| + Add(Instruction("any", jtl::NAVIGATE_ANY, Arguments())); |
| + Add(Instruction("back", jtl::NAVIGATE_BACK, Arguments())); |
| + Add(Instruction("store_bool", jtl::STORE_BOOL, Arguments(Hash, Bool))); |
| + Add(Instruction("compare_stored_bool", |
| + jtl::COMPARE_STORED_BOOL, |
| + Arguments(Hash, Bool, Bool))); |
| + Add(Instruction("store_hash", jtl::STORE_HASH, Arguments(Hash, Hash))); |
| + Add(Instruction("compare_stored_hash", |
| + jtl::COMPARE_STORED_HASH, |
| + Arguments(Hash, Hash, Hash))); |
| + Add(Instruction("compare_bool", jtl::COMPARE_NODE_BOOL, Arguments(Bool))); |
| + Add(Instruction("compare_hash", jtl::COMPARE_NODE_HASH, Arguments(Hash))); |
| + Add(Instruction("break", jtl::STOP_EXECUTING_SENTENCE, Arguments())); |
| + } |
| + |
| + JtlCompiler::CompileError::ErrorCode TranscodeInstruction( |
| + const std::string& name, |
| + const ListValue& arguments, |
| + bool ends_sentence, |
| + const jtl::Hasher& hasher, |
| + ByteCodeWriter* target) const { |
| + if (instruction_map_.count(name) == 0) |
| + return JtlCompiler::CompileError::INVALID_OPERATION_NAME; |
| + const Instruction& instruction(instruction_map_.at(name)); |
| + if (instruction.argument_types.size() != arguments.GetSize()) |
| + return JtlCompiler::CompileError::INVALID_ARGUMENT_COUNT; |
| + target->WriteOpCode(instruction.op_code); |
| + for (size_t i = 0; i < arguments.GetSize(); ++i) { |
| + switch (instruction.argument_types[i]) { |
| + case Bool: { |
| + bool value; |
|
battre
2013/10/01 12:18:26
nit: initialize to false.
engedy
2013/10/01 15:09:33
Done.
|
| + if (!arguments.GetBoolean(i, &value)) |
| + return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE; |
| + target->WriteBool(value); |
| + break; |
| + } |
| + case Hash: { |
| + std::string value; |
| + if (!arguments.GetString(i, &value)) |
| + return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE; |
| + target->WriteHash(hasher.GetHash(value)); |
| + break; |
| + } |
| + default: |
| + NOTREACHED(); |
| + return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE; |
| + } |
| + } |
| + if (ends_sentence) |
| + target->WriteOpCode(jtl::END_OF_SENTENCE); |
| + return JtlCompiler::CompileError::NO_ERROR; |
| + } |
| + |
| + private: |
| + // The possible types of an operation's argument. |
| + enum ArgumentType { |
| + None, |
| + Bool, |
| + Hash |
| + }; |
| + |
| + // Encapsulates meta-data about one instruction. |
| + struct Instruction { |
| + Instruction() : op_code(jtl::END_OF_SENTENCE) {} |
| + Instruction(const char* name, |
| + jtl_foundation::OpCodes op_code, |
| + const std::vector<ArgumentType>& argument_types) |
| + : name(name), op_code(op_code), argument_types(argument_types) {} |
| + |
| + std::string name; |
| + jtl::OpCodes op_code; |
| + std::vector<ArgumentType> argument_types; |
| + }; |
| + |
| + static std::vector<ArgumentType> Arguments(ArgumentType arg1_type = None, |
| + ArgumentType arg2_type = None, |
| + ArgumentType arg3_type = None) { |
| + std::vector<ArgumentType> result; |
| + if (arg1_type != None) |
| + result.push_back(arg1_type); |
| + if (arg2_type != None) |
| + result.push_back(arg2_type); |
| + if (arg3_type != None) |
| + result.push_back(arg3_type); |
| + return result; |
| + } |
| + |
| + void Add(const Instruction& instruction) { |
| + instruction_map_[instruction.name] = instruction; |
| + } |
| + |
| + std::map<std::string, Instruction> instruction_map_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(InstructionSet); |
| +}; |
| + |
| +} // namespace |
| + |
| +bool JtlCompiler::Compile(const std::string& source_code, |
| + const std::string& hash_seed, |
| + std::string* output_bytecode, |
| + CompileError* error_details) { |
| + DCHECK(output_bytecode); |
| + InstructionSet instruction_set; |
| + ByteCodeWriter bytecode_writer(output_bytecode); |
| + jtl::Hasher hasher(hash_seed); |
| + |
| + std::string compacted_source_code; |
| + std::vector<size_t> newline_indices; |
| + size_t mismatched_quotes_line; |
| + if (!JtlParser::RemoveCommentsAndAllWhitespace(source_code, |
| + &compacted_source_code, |
| + &newline_indices, |
| + &mismatched_quotes_line)) { |
| + if (error_details) { |
| + error_details->context = ""; // No meaningful intra-line context here. |
| + error_details->line_number = mismatched_quotes_line; |
| + error_details->error_code = CompileError::MISMATCHED_DOUBLE_QUOTES; |
| + } |
| + return false; |
| + } |
| + |
| + JtlParser parser(compacted_source_code, newline_indices); |
| + while (!parser.HasFinished()) { |
| + std::string operation_name; |
| + ListValue arguments; |
| + bool ends_sentence = false; |
| + if (!parser.ParseNextOperation( |
| + &operation_name, &arguments, &ends_sentence)) { |
| + if (error_details) { |
| + error_details->context = parser.last_context(); |
| + error_details->line_number = parser.last_line_number(); |
| + error_details->error_code = CompileError::PARSING_ERROR; |
| + } |
| + return false; |
| + } |
| + CompileError::ErrorCode error_code = instruction_set.TranscodeInstruction( |
| + operation_name, arguments, ends_sentence, hasher, &bytecode_writer); |
| + if (error_code != CompileError::NO_ERROR) { |
| + if (error_details) { |
| + error_details->context = parser.last_context(); |
| + error_details->line_number = parser.last_line_number(); |
| + error_details->error_code = error_code; |
| + } |
| + return false; |
| + } |
| + } |
| + |
| + return true; |
| +} |