Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: runtime/vm/json.cc

Issue 9949054: Basic support for reading and writing JSON objects. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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 #include "vm/json.h"
6
7 #include "platform/assert.h"
8 #include "platform/utils.h"
9 #include "vm/os.h"
10
11 namespace dart {
turnidge 2012/04/09 22:26:42 The classes in the header go "scanner, reader, wri
hausner 2012/04/10 16:26:51 I typically don't read source in a linear way, so
12
13 JSONWriter::JSONWriter(intptr_t buf_size) {
14 ASSERT(buf_size > 0);
15 buf_ = reinterpret_cast<char*>(malloc(buf_size));
16 buf_size_ = buf_size;
17 Clear();
18 }
19
20
21 JSONWriter::~JSONWriter() {
22 if (buf_ != NULL) {
turnidge 2012/04/09 22:26:42 You don't need this if here. It is safe to free/d
hausner 2012/04/10 16:26:51 Done.
23 delete buf_;
turnidge 2012/04/09 22:26:42 Since you're using malloc above, should this be fr
hausner 2012/04/10 16:26:51 Nice catch, thank you. On 2012/04/09 22:26:42, tu
24 }
25 }
26
27
28 void JSONWriter::Clear() {
29 msg_len_ = 0;
30 buf_[0] = '\0';
31 }
32
33
34 intptr_t JSONWriter::Printf(const char* format, ...) {
35 va_list args;
36 va_start(args, format);
37 intptr_t remaining = buf_size_ - msg_len_;
38 ASSERT(remaining >= 0);
39 intptr_t len = OS::VSNPrint(buf_ + msg_len_, remaining, format, args);
40 va_end(args);
41 if (len >= remaining) {
42 GrowBuffer(len + 64); // Somewhat arbitrary slack.
turnidge 2012/04/09 22:26:42 Make the slack amount a named constant.
hausner 2012/04/10 16:26:51 Done.
43 remaining = buf_size_ - msg_len_;
44 ASSERT(remaining > len);
45 va_list args2;
46 va_start(args2, format);
47 intptr_t len2 = OS::VSNPrint(buf_ + msg_len_, remaining, format, args2);
48 va_end(args2);
49 ASSERT(len == len2);
50 }
51 msg_len_ += len;
52 buf_[msg_len_] = '\0';
53 return len;
54 }
55
56
57 void JSONWriter::GrowBuffer(intptr_t len) {
58 intptr_t new_size = buf_size_ + len;
59 char* new_buf = reinterpret_cast<char*>(malloc(new_size));
turnidge 2012/04/09 22:26:42 Consider realloc? It copies the bytes for you.
hausner 2012/04/10 16:26:51 Good suggestion, thank you.
60 intptr_t msg_len = OS::SNPrint(new_buf, new_size, "%s", buf_);
turnidge 2012/04/09 22:26:42 I don't think you should use SNPrint to go the buf
hausner 2012/04/10 16:26:51 Very good point. Replaced with realloc(). On 2012
61 ASSERT(msg_len < new_size);
62 buf_ = new_buf;
63 buf_size_ = new_size;
64 }
65
66
67 JSONReader::JSONReader(const char* json_object)
68 : scanner_(json_object) {
69 Set(json_object);
70 }
71
72 void JSONReader::Set(const char* json_object) {
73 scanner_.Set(json_object);
74 json_object_ = json_object;
75 error_ = false;
76 }
77
78
79 bool JSONReader::Seek(const char* name) {
80 scanner_.Set(json_object_);
turnidge 2012/04/09 22:26:42 Why the call to Set here? Isn't this done already
hausner 2012/04/10 16:26:51 Because a JSON object is by definition an unordere
81 scanner_.Scan();
82 if (scanner_.CurrentToken() != JSONScanner::TokenLBrace) {
83 error_ = true;
84 return false;
85 }
86 scanner_.Scan();
87 while (scanner_.CurrentToken() == JSONScanner::TokenString) {
88 bool found = scanner_.IsStringLiteral(name);
89 scanner_.Scan();
90 if (scanner_.CurrentToken() != JSONScanner::TokenColon) {
91 error_ = true;
92 return false;
93 }
94 scanner_.Scan();
95 switch (scanner_.CurrentToken()) {
96 case JSONScanner::TokenString:
97 case JSONScanner::TokenInteger:
98 case JSONScanner::TokenLBrace:
99 case JSONScanner::TokenLBrack:
100 case JSONScanner::TokenTrue:
101 case JSONScanner::TokenFalse:
102 case JSONScanner::TokenNull:
103 // Found a legal value.
104 if (found) {
105 return true;
106 }
107 break;
108 default:
109 error_ = true;
110 return false;
111 }
112 // Skip the value.
113 if (scanner_.CurrentToken() == JSONScanner::TokenLBrace) {
114 scanner_.Skip(JSONScanner::TokenRBrace);
115 if (scanner_.CurrentToken() != JSONScanner::TokenRBrace) {
116 error_ = true;
117 return false;
118 }
119 } else if (scanner_.CurrentToken() == JSONScanner::TokenLBrack) {
120 scanner_.Skip(JSONScanner::TokenRBrack);
121 if (scanner_.CurrentToken() != JSONScanner::TokenRBrack) {
122 error_ = true;
123 return false;
124 }
125 }
126 scanner_.Scan(); // Value or closing brace or bracket.
127 if (scanner_.CurrentToken() == JSONScanner::TokenComma) {
128 scanner_.Scan();
129 } else {
130 // End of json object or malformed object. Value not found.
131 break;
132 }
133 }
134 return false;
135 }
136
137
138 JSONReader::JSONType JSONReader::Type() const {
139 if (error_) {
140 return kNone;
141 }
142 switch (scanner_.CurrentToken()) {
143 case JSONScanner::TokenString:
144 return kString;
145 case JSONScanner::TokenInteger:
146 return kInteger;
147 case JSONScanner::TokenLBrace:
148 return kObject;
149 case JSONScanner::TokenLBrack:
150 return kArray;
151 case JSONScanner::TokenTrue:
152 case JSONScanner::TokenFalse:
153 case JSONScanner::TokenNull:
154 return kLiteral;
155 default:
156 return kNone;
157 }
158 }
159
160
161 JSONScanner::JSONScanner(const char* msg) {
162 Set(msg);
163 }
164
165
166 void JSONScanner::Set(const char* txt) {
167 current_pos_ = txt;
168 token_start_ = txt;
169 token_length_ = 0;
170 token_ = TokenIllegal;
171 }
172
173
174 void JSONScanner::Recognize(Token t) {
175 ++current_pos_;
176 token_ = t;
177 }
178
179
180 bool JSONScanner::IsLetter(char ch) const {
181 return (('A' <= ch) && (ch <= 'Z')) || (('a' <= ch) && (ch <= 'z'));
182 }
183
184
185 bool JSONScanner::IsDigit(char ch) const {
186 return ('0' <= ch) && (ch <= '9');
187 }
188
189
190 bool JSONScanner::IsLiteral(const char* literal) {
191 int i = 0;
192 while ((literal[i] != '\0') && (current_pos_[i] == literal[i])) {
193 i++;
194 }
195 if ((literal[i] == '\0') && !IsLetter(current_pos_[i])) {
196 current_pos_ += i;
197 return true;
198 }
199 return false;
200 }
201
202
203 bool JSONScanner::IsStringLiteral(const char* literal) const {
204 if (token_ != TokenString) {
205 return false;
206 }
207 int i = 0;
208 while ((i < token_length_) && (token_start_[i] == literal[i])) {
209 i++;
210 }
211 return (i == token_length_) && (literal[i] == '\0');
212 }
213
214
215 void JSONScanner::Skip(Token matching_token) {
216 while (!EOM() && (token_ != TokenIllegal)) {
217 Scan();
218 if (token_ == TokenLBrace) {
219 Skip(TokenRBrace);
220 } else if (token_ == TokenLBrack) {
221 Skip(TokenRBrack);
222 } else if (token_ == matching_token) {
223 return;
224 } else if ((token_ == TokenRBrace) || (token_ == TokenRBrack)) {
225 // Mismatched brace or bracket.
226 token_ = TokenIllegal;
227 }
228 }
229 }
230
231
232 void JSONScanner::ScanString() {
233 ASSERT(*current_pos_ == '"');
234 ++current_pos_;
235 token_start_ = current_pos_;
236 while (*current_pos_ != '"') {
237 if (*current_pos_ == '\0') {
238 token_length_ = 0;
239 token_ = TokenIllegal;
240 return;
241 } else if (*current_pos_ == '\\') {
242 // TODO(hausner): Implement escape sequence.
243 UNIMPLEMENTED();
244 } else if (*current_pos_ < 0) {
245 // UTF-8 not supported.
246 token_length_ = 0;
247 token_ = TokenIllegal;
248 return;
249 } else {
250 ++current_pos_;
251 }
252 }
253 token_ = TokenString;
254 token_length_ = current_pos_ - token_start_;
255 ++current_pos_;
256 }
257
258
259 void JSONScanner::ScanNumber() {
260 if (*current_pos_ == '-') {
261 ++current_pos_;
262 }
263 if (!IsDigit(*current_pos_)) {
264 token_ = TokenIllegal;
265 token_length_ = 0;
266 return;
267 }
268 while (IsDigit(*current_pos_)) {
269 ++current_pos_;
270 }
271 if ((*current_pos_ == '.') ||
272 (*current_pos_ == 'e') ||
273 (*current_pos_ == 'E')) {
274 // Floating point numbers not supported.
275 token_ = TokenIllegal;
276 token_length_ = 0;
277 return;
278 }
279 token_ = TokenInteger;
280 token_length_ = current_pos_ - token_start_;
281 }
282
283
284 void JSONScanner::Scan() {
285 while ((*current_pos_ == ' ') ||
286 (*current_pos_ == '\t') ||
287 (*current_pos_ == '\n')) {
288 ++current_pos_;
289 }
290 token_start_ = current_pos_;
291 if (*current_pos_ == '\0') {
292 token_length_ = 0;
293 token_ = TokenEOM;
294 return;
295 }
296 switch (*current_pos_) {
297 case '{':
298 Recognize(TokenLBrace);
299 break;
300 case '}':
301 Recognize(TokenRBrace);
302 break;
303 case '[':
304 Recognize(TokenLBrack);
305 break;
306 case ']':
307 Recognize(TokenRBrack);
308 break;
309 case ':':
310 Recognize(TokenColon);
311 break;
312 case ',':
313 Recognize(TokenComma);
314 break;
315 case '"':
316 ScanString();
317 break;
318 case '0':
319 case '1':
320 case '2':
321 case '3':
322 case '4':
323 case '5':
324 case '6':
325 case '7':
326 case '8':
327 case '9':
328 case '-':
329 ScanNumber();
330 break;
331 default:
332 if (IsLiteral("true")) {
333 token_ = TokenTrue;
334 } else if (IsLiteral("false")) {
335 token_ = TokenFalse;
336 } else if (IsLiteral("null")) {
337 token_ = TokenNull;
338 } else {
339 token_length_ = 0;
340 token_ = TokenIllegal;
341 }
342 }
343 }
344
345 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698