1 /*************************************************************************/
2 /* variant_construct_string.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30 #include "variant.h"
31
32 class VariantConstruct {
33
34 enum TokenType {
35 TK_CURLY_BRACKET_OPEN,
36 TK_CURLY_BRACKET_CLOSE,
37 TK_BRACKET_OPEN,
38 TK_BRACKET_CLOSE,
39 TK_IDENTIFIER,
40 TK_STRING,
41 TK_NUMBER,
42 TK_COLON,
43 TK_COMMA,
44 TK_EOF,
45 TK_MAX
46 };
47
48 enum Expecting {
49
50 EXPECT_OBJECT,
51 EXPECT_OBJECT_KEY,
52 EXPECT_COLON,
53 EXPECT_OBJECT_VALUE,
54 };
55
56 struct Token {
57
58 TokenType type;
59 Variant value;
60 };
61
62 static const char *tk_name[TK_MAX];
63
64 static String _print_var(const Variant &p_var);
65
66 static Error _get_token(const CharType *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
67 static Error _parse_value(Variant &value, Token &token, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud);
68 static Error _parse_array(Array &array, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud);
69 static Error _parse_dict(Dictionary &object, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud);
70
71 public:
72 static Error parse(const String &p_string, Variant &r_ret, String &r_err_str, int &r_err_line, Variant::ObjectConstruct *p_construct, void *p_ud);
73 };
74
75 const char *VariantConstruct::tk_name[TK_MAX] = {
76 "'{'",
77 "'}'",
78 "'['",
79 "']'",
80 "identifier",
81 "string",
82 "number",
83 "':'",
84 "','",
85 "EOF",
86 };
87
_get_token(const CharType * p_str,int & idx,int p_len,Token & r_token,int & line,String & r_err_str)88 Error VariantConstruct::_get_token(const CharType *p_str, int &idx, int p_len, Token &r_token, int &line, String &r_err_str) {
89
90 while (true) {
91 switch (p_str[idx]) {
92
93 case '\n': {
94
95 line++;
96 idx++;
97 break;
98 };
99 case 0: {
100 r_token.type = TK_EOF;
101 return OK;
102 } break;
103 case '{': {
104
105 r_token.type = TK_CURLY_BRACKET_OPEN;
106 idx++;
107 return OK;
108 };
109 case '}': {
110
111 r_token.type = TK_CURLY_BRACKET_CLOSE;
112 idx++;
113 return OK;
114 };
115 case '[': {
116
117 r_token.type = TK_BRACKET_OPEN;
118 idx++;
119 return OK;
120 };
121 case ']': {
122
123 r_token.type = TK_BRACKET_CLOSE;
124 idx++;
125 return OK;
126 };
127 case ':': {
128
129 r_token.type = TK_COLON;
130 idx++;
131 return OK;
132 };
133 case ',': {
134
135 r_token.type = TK_COMMA;
136 idx++;
137 return OK;
138 };
139 case '"': {
140
141 idx++;
142 String str;
143 while (true) {
144 if (p_str[idx] == 0) {
145 r_err_str = "Unterminated String";
146 return ERR_PARSE_ERROR;
147 } else if (p_str[idx] == '"') {
148 idx++;
149 break;
150 } else if (p_str[idx] == '\\') {
151 //escaped characters...
152 idx++;
153 CharType next = p_str[idx];
154 if (next == 0) {
155 r_err_str = "Unterminated String";
156 return ERR_PARSE_ERROR;
157 }
158 CharType res = 0;
159
160 switch (next) {
161
162 case 'b': res = 8; break;
163 case 't': res = 9; break;
164 case 'n': res = 10; break;
165 case 'f': res = 12; break;
166 case 'r': res = 13; break;
167 case '\"': res = '\"'; break;
168 case '\\': res = '\\'; break;
169 case '/': res = '/'; break;
170 case 'u': {
171 //hexnumbarh - oct is deprecated
172
173 for (int j = 0; j < 4; j++) {
174 CharType c = p_str[idx + j + 1];
175 if (c == 0) {
176 r_err_str = "Unterminated String";
177 return ERR_PARSE_ERROR;
178 }
179 if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
180
181 r_err_str = "Malformed hex constant in string";
182 return ERR_PARSE_ERROR;
183 }
184 CharType v;
185 if (c >= '0' && c <= '9') {
186 v = c - '0';
187 } else if (c >= 'a' && c <= 'f') {
188 v = c - 'a';
189 v += 10;
190 } else if (c >= 'A' && c <= 'F') {
191 v = c - 'A';
192 v += 10;
193 } else {
194 ERR_PRINT("BUG");
195 v = 0;
196 }
197
198 res <<= 4;
199 res |= v;
200 }
201 idx += 4; //will add at the end anyway
202
203 } break;
204 default: {
205
206 r_err_str = "Invalid escape sequence";
207 return ERR_PARSE_ERROR;
208 } break;
209 }
210
211 str += res;
212
213 } else {
214 if (p_str[idx] == '\n')
215 line++;
216 str += p_str[idx];
217 }
218 idx++;
219 }
220
221 r_token.type = TK_STRING;
222 r_token.value = str;
223 return OK;
224
225 } break;
226 default: {
227
228 if (p_str[idx] <= 32) {
229 idx++;
230 break;
231 }
232
233 if (p_str[idx] == '-' || (p_str[idx] >= '0' && p_str[idx] <= '9')) {
234 //a number
235 const CharType *rptr;
236 double number = String::to_double(&p_str[idx], &rptr);
237 idx += (rptr - &p_str[idx]);
238 r_token.type = TK_NUMBER;
239 r_token.value = number;
240 return OK;
241
242 } else if ((p_str[idx] >= 'A' && p_str[idx] <= 'Z') || (p_str[idx] >= 'a' && p_str[idx] <= 'z')) {
243
244 String id;
245
246 while ((p_str[idx] >= 'A' && p_str[idx] <= 'Z') || (p_str[idx] >= 'a' && p_str[idx] <= 'z')) {
247
248 id += p_str[idx];
249 idx++;
250 }
251
252 r_token.type = TK_IDENTIFIER;
253 r_token.value = id;
254 return OK;
255 } else {
256 r_err_str = "Unexpected character.";
257 return ERR_PARSE_ERROR;
258 }
259 }
260 }
261 }
262
263 return ERR_PARSE_ERROR;
264 }
265
_parse_value(Variant & value,Token & token,const CharType * p_str,int & index,int p_len,int & line,String & r_err_str,Variant::ObjectConstruct * p_construct,void * p_ud)266 Error VariantConstruct::_parse_value(Variant &value, Token &token, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud) {
267
268 if (token.type == TK_CURLY_BRACKET_OPEN) {
269
270 Dictionary d;
271 Error err = _parse_dict(d, p_str, index, p_len, line, r_err_str, p_construct, p_ud);
272 if (err)
273 return err;
274 value = d;
275 return OK;
276 } else if (token.type == TK_BRACKET_OPEN) {
277
278 Array a;
279 Error err = _parse_array(a, p_str, index, p_len, line, r_err_str, p_construct, p_ud);
280 if (err)
281 return err;
282 value = a;
283 return OK;
284
285 } else if (token.type == TK_IDENTIFIER) {
286
287 String id = token.value;
288 if (id == "true")
289 value = true;
290 else if (id == "false")
291 value = false;
292 else if (id == "null")
293 value = Variant();
294 else {
295 r_err_str = "Expected 'true','false' or 'null', got '" + id + "'.";
296 return ERR_PARSE_ERROR;
297 }
298 return OK;
299
300 } else if (token.type == TK_NUMBER) {
301
302 value = token.value;
303 return OK;
304 } else if (token.type == TK_STRING) {
305
306 value = token.value;
307 return OK;
308 } else {
309 r_err_str = "Expected value, got " + String(tk_name[token.type]) + ".";
310 return ERR_PARSE_ERROR;
311 }
312
313 return ERR_PARSE_ERROR;
314 }
315
_parse_array(Array & array,const CharType * p_str,int & index,int p_len,int & line,String & r_err_str,Variant::ObjectConstruct * p_construct,void * p_ud)316 Error VariantConstruct::_parse_array(Array &array, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud) {
317
318 Token token;
319 bool need_comma = false;
320
321 while (index < p_len) {
322
323 Error err = _get_token(p_str, index, p_len, token, line, r_err_str);
324 if (err != OK)
325 return err;
326
327 if (token.type == TK_BRACKET_CLOSE) {
328
329 return OK;
330 }
331
332 if (need_comma) {
333
334 if (token.type != TK_COMMA) {
335
336 r_err_str = "Expected ','";
337 return ERR_PARSE_ERROR;
338 } else {
339 need_comma = false;
340 continue;
341 }
342 }
343
344 Variant v;
345 err = _parse_value(v, token, p_str, index, p_len, line, r_err_str, p_construct, p_ud);
346 if (err)
347 return err;
348
349 array.push_back(v);
350 need_comma = true;
351 }
352
353 return OK;
354 }
355
_parse_dict(Dictionary & dict,const CharType * p_str,int & index,int p_len,int & line,String & r_err_str,Variant::ObjectConstruct * p_construct,void * p_ud)356 Error VariantConstruct::_parse_dict(Dictionary &dict, const CharType *p_str, int &index, int p_len, int &line, String &r_err_str, Variant::ObjectConstruct *p_construct, void *p_ud) {
357
358 bool at_key = true;
359 Variant key;
360 Token token;
361 bool need_comma = false;
362
363 while (index < p_len) {
364
365 if (at_key) {
366
367 Error err = _get_token(p_str, index, p_len, token, line, r_err_str);
368 if (err != OK)
369 return err;
370
371 if (token.type == TK_CURLY_BRACKET_CLOSE) {
372
373 return OK;
374 }
375
376 if (need_comma) {
377
378 if (token.type != TK_COMMA) {
379
380 r_err_str = "Expected '}' or ','";
381 return ERR_PARSE_ERROR;
382 } else {
383 need_comma = false;
384 continue;
385 }
386 }
387
388 err = _parse_value(key, token, p_str, index, p_len, line, r_err_str, p_construct, p_ud);
389
390 if (err != OK)
391 return err;
392
393 err = _get_token(p_str, index, p_len, token, line, r_err_str);
394
395 if (err != OK)
396 return err;
397
398 if (token.type != TK_COLON) {
399
400 r_err_str = "Expected ':'";
401 return ERR_PARSE_ERROR;
402 }
403 at_key = false;
404 } else {
405
406 Error err = _get_token(p_str, index, p_len, token, line, r_err_str);
407 if (err != OK)
408 return err;
409
410 Variant v;
411 err = _parse_value(v, token, p_str, index, p_len, line, r_err_str, p_construct, p_ud);
412 if (err)
413 return err;
414 dict[key] = v;
415 need_comma = true;
416 at_key = true;
417 }
418 }
419
420 return OK;
421 }
422
parse(const String & p_string,Variant & r_ret,String & r_err_str,int & r_err_line,Variant::ObjectConstruct * p_construct,void * p_ud)423 Error VariantConstruct::parse(const String &p_string, Variant &r_ret, String &r_err_str, int &r_err_line, Variant::ObjectConstruct *p_construct, void *p_ud) {
424
425 const CharType *str = p_string.ptr();
426 int idx = 0;
427 int len = p_string.length();
428 Token token;
429 r_err_line = 0;
430 String aux_key;
431
432 Error err = _get_token(str, idx, len, token, r_err_line, r_err_str);
433 if (err)
434 return err;
435
436 return _parse_value(r_ret, token, str, idx, len, r_err_line, r_err_str, p_construct, p_ud);
437 }
438