OLD | NEW |
| (Empty) |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #ifndef RUNTIME_VM_JSON_PARSER_H_ | |
6 #define RUNTIME_VM_JSON_PARSER_H_ | |
7 | |
8 #include "vm/allocation.h" | |
9 #include "vm/zone.h" | |
10 #include "vm/growable_array.h" | |
11 | |
12 namespace dart { | |
13 | |
14 class ParsedJSONArray; | |
15 | |
16 class ParsedJSONValue : public ZoneAllocated { | |
17 public: | |
18 virtual ~ParsedJSONValue() {} | |
19 | |
20 virtual bool IsObject() const { return false; } | |
21 virtual bool IsArray() const { return false; } | |
22 virtual bool IsString() const { return false; } | |
23 virtual bool IsNumber() const { return false; } | |
24 virtual bool IsBoolean() const { return false; } | |
25 virtual bool IsError() const { return false; } | |
26 }; | |
27 | |
28 class ParsedJSONString : public ParsedJSONValue { | |
29 public: | |
30 explicit ParsedJSONString(const char* value) : value_(value) {} | |
31 bool Equals(const char* other) { return strcmp(value_, other) == 0; } | |
32 const char* value() { return value_; } | |
33 virtual bool IsString() const { return true; } | |
34 | |
35 private: | |
36 const char* value_; | |
37 }; | |
38 | |
39 class ParsedJSONNumber : public ParsedJSONValue { | |
40 public: | |
41 explicit ParsedJSONNumber(int64_t value) : value_(value) {} | |
42 | |
43 int64_t value() { return value_; } | |
44 virtual bool IsNumber() const { return true; } | |
45 | |
46 private: | |
47 int64_t value_; | |
48 }; | |
49 | |
50 class ParsedJSONBoolean : public ParsedJSONValue { | |
51 public: | |
52 explicit ParsedJSONBoolean(bool value) : value_(value) {} | |
53 | |
54 bool value() { return value_; } | |
55 virtual bool IsBoolean() const { return true; } | |
56 | |
57 private: | |
58 bool value_; | |
59 }; | |
60 | |
61 class ParsedJSONNull : public ParsedJSONValue { | |
62 public: | |
63 virtual bool IsNull() const { return true; } | |
64 }; | |
65 | |
66 class ParsedJSONObject : public ParsedJSONValue { | |
67 public: | |
68 ParsedJSONObject(intptr_t length, ParsedJSONValue** keys_and_values) | |
69 : length_(length), keys_and_values_(keys_and_values) {} | |
70 | |
71 ParsedJSONValue* At(const char* key) const { | |
72 for (intptr_t i = 0; i < length_; i += 2) { | |
73 ASSERT(keys_and_values_[i]->IsString()); | |
74 ParsedJSONString* jskey = | |
75 static_cast<ParsedJSONString*>(keys_and_values_[i]); | |
76 if (jskey->Equals(key)) { | |
77 return keys_and_values_[i + 1]; | |
78 } | |
79 } | |
80 return NULL; | |
81 } | |
82 | |
83 virtual bool IsObject() const { return true; } | |
84 | |
85 ParsedJSONNumber* NumberAt(const char* key) { | |
86 ParsedJSONValue* member = At(key); | |
87 if ((member == NULL) || !member->IsNumber()) { | |
88 return NULL; | |
89 } | |
90 return static_cast<ParsedJSONNumber*>(member); | |
91 } | |
92 | |
93 ParsedJSONString* StringAt(const char* key) { | |
94 ParsedJSONValue* member = At(key); | |
95 if ((member == NULL) || !member->IsString()) { | |
96 return NULL; | |
97 } | |
98 return static_cast<ParsedJSONString*>(member); | |
99 } | |
100 | |
101 ParsedJSONBoolean* BooleanAt(const char* key) { | |
102 ParsedJSONValue* member = At(key); | |
103 if ((member == NULL) || !member->IsBoolean()) { | |
104 return NULL; | |
105 } | |
106 return static_cast<ParsedJSONBoolean*>(member); | |
107 } | |
108 | |
109 inline ParsedJSONArray* ArrayAt(const char* key); | |
110 | |
111 private: | |
112 intptr_t length_; | |
113 ParsedJSONValue** keys_and_values_; | |
114 }; | |
115 | |
116 class ParsedJSONArray : public ParsedJSONValue { | |
117 public: | |
118 ParsedJSONArray(intptr_t length, ParsedJSONValue** elements) | |
119 : length_(length), elements_(elements) {} | |
120 | |
121 ParsedJSONValue* At(intptr_t index) const { | |
122 ASSERT(index < length_); | |
123 return elements_[index]; | |
124 } | |
125 | |
126 intptr_t Length() const { return length_; } | |
127 | |
128 virtual bool IsArray() const { return true; } | |
129 | |
130 ParsedJSONObject* ObjectAt(intptr_t index) { | |
131 ParsedJSONValue* element = At(index); | |
132 if ((element == NULL) || !element->IsObject()) { | |
133 return NULL; | |
134 } | |
135 return static_cast<ParsedJSONObject*>(element); | |
136 } | |
137 | |
138 ParsedJSONNumber* NumberAt(intptr_t index) { | |
139 ParsedJSONValue* element = At(index); | |
140 if ((element == NULL) || !element->IsNumber()) { | |
141 return NULL; | |
142 } | |
143 return static_cast<ParsedJSONNumber*>(element); | |
144 } | |
145 | |
146 private: | |
147 intptr_t length_; | |
148 ParsedJSONValue** elements_; | |
149 }; | |
150 | |
151 class ParsedJSONError : public ParsedJSONValue { | |
152 public: | |
153 explicit ParsedJSONError(const char* message, intptr_t position) | |
154 : message_(message), position_(position) {} | |
155 | |
156 virtual bool IsError() const { return true; } | |
157 | |
158 const char* message() const { return message_; } | |
159 intptr_t position() const { return position_; } | |
160 | |
161 private: | |
162 const char* message_; | |
163 intptr_t position_; | |
164 }; | |
165 | |
166 class JSONParser { | |
167 public: | |
168 JSONParser(const char* buffer, intptr_t length, Zone* zone) | |
169 : buffer_(buffer), position_(0), length_(length), zone_(zone) {} | |
170 | |
171 ParsedJSONValue* ParseValue() { | |
172 ConsumeWhitespace(); | |
173 if (Peek() == '\"') return ParseString(); | |
174 if (IsDigitOrMinus(Peek())) return ParseNumber(); | |
175 if (Peek() == '{') return ParseObject(); | |
176 if (Peek() == '[') return ParseArray(); | |
177 if (PeekAndConsume("true")) return new (zone_) ParsedJSONBoolean(true); | |
178 if (PeekAndConsume("false")) return new (zone_) ParsedJSONBoolean(false); | |
179 if (PeekAndConsume("null")) return new (zone_) ParsedJSONNull(); | |
180 return Error("value expected"); | |
181 } | |
182 | |
183 private: | |
184 intptr_t Available() const { return length_ - position_; } | |
185 char Peek() const { | |
186 if (position_ < length_) return buffer_[position_]; | |
187 return 0; | |
188 } | |
189 char Consume() { | |
190 ASSERT(position_ < length_); | |
191 return buffer_[position_++]; | |
192 } | |
193 bool PeekAndConsume(const char* expected) { | |
194 intptr_t n = strlen(expected); | |
195 if (Available() < n) return false; | |
196 if (strncmp(&buffer_[position_], expected, n) != 0) return false; | |
197 position_ += n; | |
198 return true; | |
199 } | |
200 void ConsumeWhitespace() { | |
201 while ((Available() > 0) && (buffer_[position_] < ' ')) | |
202 position_++; | |
203 } | |
204 bool IsDigit(char c) { return c >= '0' && c <= '9'; } | |
205 bool IsDigitOrMinus(char c) { return (c == '-') || (c >= '0' && c <= '9'); } | |
206 | |
207 ParsedJSONValue* ParseString() { | |
208 ConsumeWhitespace(); | |
209 if (Peek() != '\"') return Error("string expected"); | |
210 Consume(); | |
211 intptr_t start = position_; | |
212 for (;;) { | |
213 if (Available() == 0) return Error("unterminated string"); | |
214 if (Consume() == '\"') break; | |
215 } | |
216 intptr_t end = position_ - 1; | |
217 | |
218 char* cstr = zone_->Alloc<char>(end - start + 1); | |
219 intptr_t dst_pos = 0; | |
220 for (intptr_t src_pos = start; src_pos < end; src_pos++) { | |
221 if (buffer_[src_pos] == '\\') { | |
222 src_pos++; | |
223 } | |
224 cstr[dst_pos++] = buffer_[src_pos]; | |
225 } | |
226 cstr[dst_pos] = '\0'; | |
227 | |
228 return new (zone_) ParsedJSONString(cstr); | |
229 } | |
230 | |
231 ParsedJSONValue* ParseNumber() { | |
232 ConsumeWhitespace(); | |
233 bool negate = false; | |
234 if (Peek() == '-') { | |
235 Consume(); | |
236 negate = true; | |
237 } | |
238 if (!IsDigit(Peek())) return Error("number expected"); | |
239 int64_t value = 0; | |
240 for (;;) { | |
241 if (!IsDigit(Peek())) break; | |
242 char c = Consume(); | |
243 value *= 10; | |
244 value += (c - '0'); | |
245 } | |
246 if (negate) { | |
247 value = -value; | |
248 } | |
249 return new (zone_) ParsedJSONNumber(value); | |
250 } | |
251 | |
252 ParsedJSONValue* ParseObject() { | |
253 ConsumeWhitespace(); | |
254 if (Peek() != '{') return Error("object expected"); | |
255 Consume(); | |
256 ConsumeWhitespace(); | |
257 if (Peek() == '}') return new (zone_) ParsedJSONObject(0, NULL); | |
258 ZoneGrowableArray<ParsedJSONValue*>* keys_and_values = | |
259 new (zone_) ZoneGrowableArray<ParsedJSONValue*>(zone_, 6); | |
260 for (;;) { | |
261 ParsedJSONValue* key = ParseString(); | |
262 if (key->IsError()) return key; | |
263 ConsumeWhitespace(); | |
264 if (Consume() != ':') return Error(": expected"); | |
265 ConsumeWhitespace(); | |
266 ParsedJSONValue* value = ParseValue(); | |
267 if (value->IsError()) return value; | |
268 ConsumeWhitespace(); | |
269 | |
270 keys_and_values->Add(key); | |
271 keys_and_values->Add(value); | |
272 | |
273 char c = Consume(); | |
274 if (c == '}') break; | |
275 if (c != ',') return Error(", expected (object)"); | |
276 ConsumeWhitespace(); | |
277 } | |
278 | |
279 return new (zone_) | |
280 ParsedJSONObject(keys_and_values->length(), keys_and_values->data()); | |
281 } | |
282 | |
283 ParsedJSONValue* ParseArray() { | |
284 ConsumeWhitespace(); | |
285 if (Peek() != '[') return Error("array expected"); | |
286 Consume(); | |
287 ConsumeWhitespace(); | |
288 if (Peek() == ']') { | |
289 Consume(); | |
290 return new (zone_) ParsedJSONArray(0, NULL); | |
291 } | |
292 ZoneGrowableArray<ParsedJSONValue*>* elements = | |
293 new (zone_) ZoneGrowableArray<ParsedJSONValue*>(zone_, 6); | |
294 for (;;) { | |
295 ParsedJSONValue* element = ParseValue(); | |
296 if (element->IsError()) return element; | |
297 ConsumeWhitespace(); | |
298 | |
299 elements->Add(element); | |
300 | |
301 char c = Consume(); | |
302 if (c == ']') break; | |
303 if (c != ',') return Error(", expected (array)"); | |
304 ConsumeWhitespace(); | |
305 } | |
306 | |
307 return new (zone_) ParsedJSONArray(elements->length(), elements->data()); | |
308 } | |
309 | |
310 private: | |
311 ParsedJSONError* Error(const char* message) { | |
312 return new (zone_) ParsedJSONError(message, position_); | |
313 } | |
314 | |
315 const char* const buffer_; | |
316 intptr_t position_; | |
317 intptr_t length_; | |
318 Zone* zone_; | |
319 }; | |
320 | |
321 ParsedJSONArray* ParsedJSONObject::ArrayAt(const char* key) { | |
322 ParsedJSONValue* member = At(key); | |
323 if ((member == NULL) || !member->IsArray()) { | |
324 return NULL; | |
325 } | |
326 return static_cast<ParsedJSONArray*>(member); | |
327 } | |
328 | |
329 } // namespace dart | |
330 | |
331 #endif // RUNTIME_VM_JSON_PARSER_H_ | |
OLD | NEW |