Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / tools / profile_reset / jtl_compiler.cc
blobdf6a9eed6d522db0085cd6008595ecbacea75c51
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/tools/profile_reset/jtl_compiler.h"
7 #include <limits>
8 #include <map>
9 #include <numeric>
11 #include "base/logging.h"
12 #include "chrome/browser/profile_resetter/jtl_foundation.h"
13 #include "chrome/tools/profile_reset/jtl_parser.h"
15 namespace jtl = jtl_foundation;
17 namespace {
19 // Serializes symbols into byte-code in a streaming manner.
20 class ByteCodeWriter {
21 public:
22 explicit ByteCodeWriter(std::string* output) : output_(output) {}
23 ~ByteCodeWriter() {}
25 void WriteUint8(uint8 value) { output_->push_back(static_cast<char>(value)); }
26 void WriteUint32(uint32 value) {
27 for (int i = 0; i < 4; ++i) {
28 output_->push_back(static_cast<char>(value & 0xFFu));
29 value >>= 8;
32 void WriteOpCode(uint8 op_code) { WriteUint8(op_code); }
33 void WriteHash(const std::string& hash) {
34 CHECK(jtl::Hasher::IsHash(hash));
35 *output_ += hash;
37 void WriteBool(bool value) { WriteUint8(value ? 1u : 0u); }
39 private:
40 std::string* output_;
42 DISALLOW_COPY_AND_ASSIGN(ByteCodeWriter);
45 // Encapsulates meta-data about all instructions, and is capable of transcoding
46 // each instruction from a parsed text-based format to byte-code.
47 class InstructionSet {
48 public:
49 InstructionSet() {
50 // Define each instruction in this list.
51 // Note:
52 // - Instructions ending in "hash" will write their 'HashString' arguments
53 // directly into the byte-code.
54 // - Instructions ending in "hashed" will first hash their 'String'
55 // arguments, and will write this hash to the byte-code.
56 Add(Instruction("go", jtl::NAVIGATE, Arguments(String)));
57 Add(Instruction("any", jtl::NAVIGATE_ANY, Arguments()));
58 Add(Instruction("back", jtl::NAVIGATE_BACK, Arguments()));
59 Add(Instruction("store_bool", jtl::STORE_BOOL, Arguments(String, Bool)));
60 Add(Instruction("store_hash",
61 jtl::STORE_HASH, Arguments(String, HashString)));
62 Add(Instruction("store_hashed",
63 jtl::STORE_HASH, Arguments(String, String)));
64 Add(Instruction("store_node_bool",
65 jtl::STORE_NODE_BOOL, Arguments(String)));
66 Add(Instruction("store_node_hash",
67 jtl::STORE_NODE_HASH, Arguments(String)));
68 Add(Instruction("store_node_effective_sld_hash",
69 jtl::STORE_NODE_EFFECTIVE_SLD_HASH, Arguments(String)));
70 Add(Instruction("compare_bool", jtl::COMPARE_NODE_BOOL, Arguments(Bool)));
71 Add(Instruction("compare_hashed",
72 jtl::COMPARE_NODE_HASH, Arguments(String)));
73 Add(Instruction("compare_hashed_not",
74 jtl::COMPARE_NODE_HASH_NOT, Arguments(String)));
75 Add(Instruction("compare_stored_bool",
76 jtl::COMPARE_STORED_BOOL,
77 Arguments(String, Bool, Bool)));
78 Add(Instruction("compare_stored_hashed",
79 jtl::COMPARE_STORED_HASH,
80 Arguments(String, String, String)));
81 Add(Instruction("compare_to_stored_bool",
82 jtl::COMPARE_NODE_TO_STORED_BOOL,
83 Arguments(String)));
84 Add(Instruction("compare_to_stored_hash",
85 jtl::COMPARE_NODE_TO_STORED_HASH,
86 Arguments(String)));
87 Add(Instruction("compare_substring_hashed",
88 jtl::COMPARE_NODE_SUBSTRING,
89 Arguments(StringPattern)));
90 Add(Instruction("break", jtl::STOP_EXECUTING_SENTENCE, Arguments()));
93 JtlCompiler::CompileError::ErrorCode TranscodeInstruction(
94 const std::string& name,
95 const base::ListValue& arguments,
96 bool ends_sentence,
97 const jtl::Hasher& hasher,
98 ByteCodeWriter* target) const {
99 if (instruction_map_.count(name) == 0)
100 return JtlCompiler::CompileError::INVALID_OPERATION_NAME;
101 const Instruction& instruction(instruction_map_.at(name));
102 if (instruction.argument_types.size() != arguments.GetSize())
103 return JtlCompiler::CompileError::INVALID_ARGUMENT_COUNT;
104 target->WriteOpCode(instruction.op_code);
105 for (size_t i = 0; i < arguments.GetSize(); ++i) {
106 switch (instruction.argument_types[i]) {
107 case Bool: {
108 bool value = false;
109 if (!arguments.GetBoolean(i, &value))
110 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
111 target->WriteBool(value);
112 break;
114 case String: {
115 std::string value;
116 if (!arguments.GetString(i, &value))
117 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
118 target->WriteHash(hasher.GetHash(value));
119 break;
121 case StringPattern: {
122 std::string value;
123 if (!arguments.GetString(i, &value))
124 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
125 if (value.empty() ||
126 value.size() > std::numeric_limits<uint32>::max())
127 return JtlCompiler::CompileError::INVALID_ARGUMENT_VALUE;
128 target->WriteHash(hasher.GetHash(value));
129 target->WriteUint32(static_cast<uint32>(value.size()));
130 uint32 pattern_sum = std::accumulate(
131 value.begin(), value.end(), static_cast<uint32>(0u));
132 target->WriteUint32(pattern_sum);
133 break;
135 case HashString: {
136 std::string hash_value;
137 if (!arguments.GetString(i, &hash_value) ||
138 !jtl::Hasher::IsHash(hash_value))
139 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
140 target->WriteHash(hash_value);
141 break;
143 default:
144 NOTREACHED();
145 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE;
148 if (ends_sentence)
149 target->WriteOpCode(jtl::END_OF_SENTENCE);
150 return JtlCompiler::CompileError::ERROR_NONE;
153 private:
154 // The possible types of an operation's argument.
155 enum ArgumentType {
156 None,
157 Bool,
158 String,
159 StringPattern,
160 HashString
163 // Encapsulates meta-data about one instruction.
164 struct Instruction {
165 Instruction() : op_code(jtl::END_OF_SENTENCE) {}
166 Instruction(const char* name,
167 jtl_foundation::OpCodes op_code,
168 const std::vector<ArgumentType>& argument_types)
169 : name(name), op_code(op_code), argument_types(argument_types) {}
171 std::string name;
172 jtl::OpCodes op_code;
173 std::vector<ArgumentType> argument_types;
176 static std::vector<ArgumentType> Arguments(ArgumentType arg1_type = None,
177 ArgumentType arg2_type = None,
178 ArgumentType arg3_type = None) {
179 std::vector<ArgumentType> result;
180 if (arg1_type != None)
181 result.push_back(arg1_type);
182 if (arg2_type != None)
183 result.push_back(arg2_type);
184 if (arg3_type != None)
185 result.push_back(arg3_type);
186 return result;
189 void Add(const Instruction& instruction) {
190 instruction_map_[instruction.name] = instruction;
193 std::map<std::string, Instruction> instruction_map_;
195 DISALLOW_COPY_AND_ASSIGN(InstructionSet);
198 } // namespace
200 bool JtlCompiler::Compile(const std::string& source_code,
201 const std::string& hash_seed,
202 std::string* output_bytecode,
203 CompileError* error_details) {
204 DCHECK(output_bytecode);
205 InstructionSet instruction_set;
206 ByteCodeWriter bytecode_writer(output_bytecode);
207 jtl::Hasher hasher(hash_seed);
209 std::string compacted_source_code;
210 std::vector<size_t> newline_indices;
211 size_t mismatched_quotes_line;
212 if (!JtlParser::RemoveCommentsAndAllWhitespace(source_code,
213 &compacted_source_code,
214 &newline_indices,
215 &mismatched_quotes_line)) {
216 if (error_details) {
217 error_details->context = ""; // No meaningful intra-line context here.
218 error_details->line_number = mismatched_quotes_line;
219 error_details->error_code = CompileError::MISMATCHED_DOUBLE_QUOTES;
221 return false;
224 JtlParser parser(compacted_source_code, newline_indices);
225 while (!parser.HasFinished()) {
226 std::string operation_name;
227 base::ListValue arguments;
228 bool ends_sentence = false;
229 if (!parser.ParseNextOperation(
230 &operation_name, &arguments, &ends_sentence)) {
231 if (error_details) {
232 error_details->context = parser.GetLastContext();
233 error_details->line_number = parser.GetLastLineNumber();
234 error_details->error_code = CompileError::PARSING_ERROR;
236 return false;
238 CompileError::ErrorCode error_code = instruction_set.TranscodeInstruction(
239 operation_name, arguments, ends_sentence, hasher, &bytecode_writer);
240 if (error_code != CompileError::ERROR_NONE) {
241 if (error_details) {
242 error_details->context = parser.GetLastContext();
243 error_details->line_number = parser.GetLastLineNumber();
244 error_details->error_code = error_code;
246 return false;
250 return true;