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..21104e9bb87b2bf788bcfac03c04a679d1025a9a |
--- /dev/null |
+++ b/chrome/tools/profile_reset/jtl_compiler.cc |
@@ -0,0 +1,193 @@ |
+// 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 "base/logging.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_EQ(hash.size(), jtl::kHashSizeInBytes); |
+ *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 = false; |
+ 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::ERROR_NONE; |
+ } |
+ |
+ 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.GetLastContext(); |
+ error_details->line_number = parser.GetLastLineNumber(); |
+ 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::ERROR_NONE) { |
+ if (error_details) { |
+ error_details->context = parser.GetLastContext(); |
+ error_details->line_number = parser.GetLastLineNumber(); |
+ error_details->error_code = error_code; |
+ } |
+ return false; |
+ } |
+ } |
+ |
+ return true; |
+} |