OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "chrome/tools/profile_reset/jtl_compiler.h" | |
6 | |
7 #include <map> | |
8 #include <string> | |
9 | |
10 #include "base/logging.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/strings/string_util.h" | |
13 #include "chrome/browser/profile_resetter/jtl_foundation.h" | |
14 #include "chrome/tools/profile_reset/jtl_parser.h" | |
15 | |
16 namespace jtl = jtl_foundation; | |
17 | |
18 namespace { | |
19 | |
20 // Serializes symbols into byte-code in a streaming manner. | |
21 class ByteCodeWriter { | |
22 public: | |
23 explicit ByteCodeWriter(std::string* output) : output_(output) {} | |
24 ~ByteCodeWriter() {} | |
25 | |
26 void WriteUint8(uint8 value) { output_->push_back(static_cast<char>(value)); } | |
27 void WriteOpCode(uint8 op_code) { WriteUint8(op_code); } | |
28 void WriteHash(const std::string& hash) { | |
29 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.
| |
30 *output_ += hash; | |
31 } | |
32 void WriteBool(bool value) { WriteUint8(value ? 1u : 0u); } | |
33 | |
34 private: | |
35 std::string* output_; | |
36 | |
37 DISALLOW_COPY_AND_ASSIGN(ByteCodeWriter); | |
38 }; | |
39 | |
40 // Encapsulates meta-data about all instructions, and is capable of transcoding | |
41 // each instruction from a parsed text-based format to byte-code. | |
42 class InstructionSet { | |
43 public: | |
44 InstructionSet() { | |
45 // Define each instruction in this list. | |
46 Add(Instruction("node", jtl::NAVIGATE, Arguments(Hash))); | |
47 Add(Instruction("any", jtl::NAVIGATE_ANY, Arguments())); | |
48 Add(Instruction("back", jtl::NAVIGATE_BACK, Arguments())); | |
49 Add(Instruction("store_bool", jtl::STORE_BOOL, Arguments(Hash, Bool))); | |
50 Add(Instruction("compare_stored_bool", | |
51 jtl::COMPARE_STORED_BOOL, | |
52 Arguments(Hash, Bool, Bool))); | |
53 Add(Instruction("store_hash", jtl::STORE_HASH, Arguments(Hash, Hash))); | |
54 Add(Instruction("compare_stored_hash", | |
55 jtl::COMPARE_STORED_HASH, | |
56 Arguments(Hash, Hash, Hash))); | |
57 Add(Instruction("compare_bool", jtl::COMPARE_NODE_BOOL, Arguments(Bool))); | |
58 Add(Instruction("compare_hash", jtl::COMPARE_NODE_HASH, Arguments(Hash))); | |
59 Add(Instruction("break", jtl::STOP_EXECUTING_SENTENCE, Arguments())); | |
60 } | |
61 | |
62 JtlCompiler::CompileError::ErrorCode TranscodeInstruction( | |
63 const std::string& name, | |
64 const ListValue& arguments, | |
65 bool ends_sentence, | |
66 const jtl::Hasher& hasher, | |
67 ByteCodeWriter* target) const { | |
68 if (instruction_map_.count(name) == 0) | |
69 return JtlCompiler::CompileError::INVALID_OPERATION_NAME; | |
70 const Instruction& instruction(instruction_map_.at(name)); | |
71 if (instruction.argument_types.size() != arguments.GetSize()) | |
72 return JtlCompiler::CompileError::INVALID_ARGUMENT_COUNT; | |
73 target->WriteOpCode(instruction.op_code); | |
74 for (size_t i = 0; i < arguments.GetSize(); ++i) { | |
75 switch (instruction.argument_types[i]) { | |
76 case Bool: { | |
77 bool value; | |
battre
2013/10/01 12:18:26
nit: initialize to false.
engedy
2013/10/01 15:09:33
Done.
| |
78 if (!arguments.GetBoolean(i, &value)) | |
79 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE; | |
80 target->WriteBool(value); | |
81 break; | |
82 } | |
83 case Hash: { | |
84 std::string value; | |
85 if (!arguments.GetString(i, &value)) | |
86 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE; | |
87 target->WriteHash(hasher.GetHash(value)); | |
88 break; | |
89 } | |
90 default: | |
91 NOTREACHED(); | |
92 return JtlCompiler::CompileError::INVALID_ARGUMENT_TYPE; | |
93 } | |
94 } | |
95 if (ends_sentence) | |
96 target->WriteOpCode(jtl::END_OF_SENTENCE); | |
97 return JtlCompiler::CompileError::NO_ERROR; | |
98 } | |
99 | |
100 private: | |
101 // The possible types of an operation's argument. | |
102 enum ArgumentType { | |
103 None, | |
104 Bool, | |
105 Hash | |
106 }; | |
107 | |
108 // Encapsulates meta-data about one instruction. | |
109 struct Instruction { | |
110 Instruction() : op_code(jtl::END_OF_SENTENCE) {} | |
111 Instruction(const char* name, | |
112 jtl_foundation::OpCodes op_code, | |
113 const std::vector<ArgumentType>& argument_types) | |
114 : name(name), op_code(op_code), argument_types(argument_types) {} | |
115 | |
116 std::string name; | |
117 jtl::OpCodes op_code; | |
118 std::vector<ArgumentType> argument_types; | |
119 }; | |
120 | |
121 static std::vector<ArgumentType> Arguments(ArgumentType arg1_type = None, | |
122 ArgumentType arg2_type = None, | |
123 ArgumentType arg3_type = None) { | |
124 std::vector<ArgumentType> result; | |
125 if (arg1_type != None) | |
126 result.push_back(arg1_type); | |
127 if (arg2_type != None) | |
128 result.push_back(arg2_type); | |
129 if (arg3_type != None) | |
130 result.push_back(arg3_type); | |
131 return result; | |
132 } | |
133 | |
134 void Add(const Instruction& instruction) { | |
135 instruction_map_[instruction.name] = instruction; | |
136 } | |
137 | |
138 std::map<std::string, Instruction> instruction_map_; | |
139 | |
140 DISALLOW_COPY_AND_ASSIGN(InstructionSet); | |
141 }; | |
142 | |
143 } // namespace | |
144 | |
145 bool JtlCompiler::Compile(const std::string& source_code, | |
146 const std::string& hash_seed, | |
147 std::string* output_bytecode, | |
148 CompileError* error_details) { | |
149 DCHECK(output_bytecode); | |
150 InstructionSet instruction_set; | |
151 ByteCodeWriter bytecode_writer(output_bytecode); | |
152 jtl::Hasher hasher(hash_seed); | |
153 | |
154 std::string compacted_source_code; | |
155 std::vector<size_t> newline_indices; | |
156 size_t mismatched_quotes_line; | |
157 if (!JtlParser::RemoveCommentsAndAllWhitespace(source_code, | |
158 &compacted_source_code, | |
159 &newline_indices, | |
160 &mismatched_quotes_line)) { | |
161 if (error_details) { | |
162 error_details->context = ""; // No meaningful intra-line context here. | |
163 error_details->line_number = mismatched_quotes_line; | |
164 error_details->error_code = CompileError::MISMATCHED_DOUBLE_QUOTES; | |
165 } | |
166 return false; | |
167 } | |
168 | |
169 JtlParser parser(compacted_source_code, newline_indices); | |
170 while (!parser.HasFinished()) { | |
171 std::string operation_name; | |
172 ListValue arguments; | |
173 bool ends_sentence = false; | |
174 if (!parser.ParseNextOperation( | |
175 &operation_name, &arguments, &ends_sentence)) { | |
176 if (error_details) { | |
177 error_details->context = parser.last_context(); | |
178 error_details->line_number = parser.last_line_number(); | |
179 error_details->error_code = CompileError::PARSING_ERROR; | |
180 } | |
181 return false; | |
182 } | |
183 CompileError::ErrorCode error_code = instruction_set.TranscodeInstruction( | |
184 operation_name, arguments, ends_sentence, hasher, &bytecode_writer); | |
185 if (error_code != CompileError::NO_ERROR) { | |
186 if (error_details) { | |
187 error_details->context = parser.last_context(); | |
188 error_details->line_number = parser.last_line_number(); | |
189 error_details->error_code = error_code; | |
190 } | |
191 return false; | |
192 } | |
193 } | |
194 | |
195 return true; | |
196 } | |
OLD | NEW |