/src/moddable/xs/sources/xsJSON.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2016-2025 Moddable Tech, Inc. |
3 | | * |
4 | | * This file is part of the Moddable SDK Runtime. |
5 | | * |
6 | | * The Moddable SDK Runtime is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * The Moddable SDK Runtime is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License |
17 | | * along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | * This file incorporates work covered by the following copyright and |
20 | | * permission notice: |
21 | | * |
22 | | * Copyright (C) 2010-2016 Marvell International Ltd. |
23 | | * Copyright (C) 2002-2010 Kinoma, Inc. |
24 | | * |
25 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
26 | | * you may not use this file except in compliance with the License. |
27 | | * You may obtain a copy of the License at |
28 | | * |
29 | | * http://www.apache.org/licenses/LICENSE-2.0 |
30 | | * |
31 | | * Unless required by applicable law or agreed to in writing, software |
32 | | * distributed under the License is distributed on an "AS IS" BASIS, |
33 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
34 | | * See the License for the specific language governing permissions and |
35 | | * limitations under the License. |
36 | | */ |
37 | | |
38 | | #include "xsAll.h" |
39 | | |
40 | | enum { |
41 | | XS_NO_JSON_TOKEN, |
42 | | XS_JSON_TOKEN_COLON, |
43 | | XS_JSON_TOKEN_COMMA, |
44 | | XS_JSON_TOKEN_EOF, |
45 | | XS_JSON_TOKEN_FALSE, |
46 | | XS_JSON_TOKEN_INTEGER, |
47 | | XS_JSON_TOKEN_LEFT_BRACE, |
48 | | XS_JSON_TOKEN_LEFT_BRACKET, |
49 | | XS_JSON_TOKEN_NULL, |
50 | | XS_JSON_TOKEN_NUMBER, |
51 | | XS_JSON_TOKEN_RIGHT_BRACE, |
52 | | XS_JSON_TOKEN_RIGHT_BRACKET, |
53 | | XS_JSON_TOKEN_STRING, |
54 | | XS_JSON_TOKEN_TRUE, |
55 | | }; |
56 | | |
57 | | typedef struct { |
58 | | txSlot* slot; |
59 | | txSize offset; |
60 | | txInteger integer; |
61 | | txNumber number; |
62 | | txSlot* string; |
63 | | txInteger token; |
64 | | txSlot* keys; |
65 | | txInteger line; |
66 | | } txJSONParser; |
67 | | |
68 | | typedef struct { |
69 | | txString buffer; |
70 | | char indent[64]; |
71 | | txInteger indentLength; |
72 | | txInteger level; |
73 | | txSize offset; |
74 | | txSize size; |
75 | | txSlot* replacer; |
76 | | txSlot* keys; |
77 | | txSlot* stack; |
78 | | } txJSONStringifier; |
79 | | |
80 | | static void fxParseJSON(txMachine* the, txJSONParser* theParser); |
81 | | static void fxParseJSONArray(txMachine* the, txJSONParser* theParser); |
82 | | static void fxParseJSONObject(txMachine* the, txJSONParser* theParser); |
83 | | static void fxParseJSONToken(txMachine* the, txJSONParser* theParser); |
84 | | static void fxParseJSONValue(txMachine* the, txJSONParser* theParser); |
85 | | static void fxReviveJSON(txMachine* the, txSlot* reviver); |
86 | | |
87 | | static void fxStringifyJSON(txMachine* the, txJSONStringifier* theStringifier); |
88 | | static void fxStringifyJSONCharacter(txMachine* the, txJSONStringifier* theStringifier, txInteger character); |
89 | | static void fxStringifyJSONChars(txMachine* the, txJSONStringifier* theStringifier, char* s, txSize theSize); |
90 | | static void fxStringifyJSONIndent(txMachine* the, txJSONStringifier* theStringifier); |
91 | | static void fxStringifyJSONInteger(txMachine* the, txJSONStringifier* theStringifier, txInteger theInteger); |
92 | | static void fxStringifyJSONName(txMachine* the, txJSONStringifier* theStringifier, txInteger* theFlag); |
93 | | static void fxStringifyJSONNumber(txMachine* the, txJSONStringifier* theStringifier, txNumber theNumber); |
94 | | static void fxStringifyJSONProperty(txMachine* the, txJSONStringifier* theStringifier, txInteger* theFlag); |
95 | | static void fxStringifyJSONString(txMachine* the, txJSONStringifier* theStringifier, txString theString); |
96 | | static void fxStringifyJSONUnicodeEscape(txMachine* the, txJSONStringifier* theStringifier, txInteger character); |
97 | | |
98 | | static txSlot* fxToJSONKeys(txMachine* the, txSlot* reference); |
99 | | |
100 | | void fxBuildJSON(txMachine* the) |
101 | 40.1k | { |
102 | 40.1k | txSlot* slot; |
103 | 40.1k | mxPush(mxObjectPrototype); |
104 | 40.1k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
105 | 40.1k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_JSON_parse), 2, mxID(_parse), XS_DONT_ENUM_FLAG); |
106 | 40.1k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_JSON_stringify), 3, mxID(_stringify), XS_DONT_ENUM_FLAG); |
107 | 40.1k | slot = fxNextStringXProperty(the, slot, "JSON", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
108 | 40.1k | mxPull(mxJSONObject); |
109 | 40.1k | } |
110 | | |
111 | | void fx_JSON_parse(txMachine* the) |
112 | 70.4k | { |
113 | 70.4k | volatile txJSONParser aParser = {0}; |
114 | | |
115 | 70.4k | if (mxArgc < 1) |
116 | 1.63k | mxSyntaxError("no buffer"); |
117 | 68.8k | if ((mxArgc > 1) && mxIsReference(mxArgv(1)) && fxIsArray(the, mxArgv(1)->value.reference)) |
118 | 24 | aParser.keys = fxToJSONKeys(the, mxArgv(1)); |
119 | 68.8k | fxToString(the, mxArgv(0)); |
120 | 68.8k | aParser.slot = mxArgv(0); |
121 | 68.8k | aParser.offset = 0; |
122 | 68.8k | fxParseJSON(the, (txJSONParser*)&aParser); |
123 | 68.8k | mxPullSlot(mxResult); |
124 | 68.8k | if (aParser.keys) |
125 | 6 | mxPop(); |
126 | 68.8k | if ((mxArgc > 1) && mxIsReference(mxArgv(1)) && mxIsCallable(mxArgv(1)->value.reference)) { |
127 | 157 | txSlot* instance; |
128 | 157 | txID id; |
129 | 157 | mxPush(mxObjectPrototype); |
130 | 157 | instance = fxNewObjectInstance(the); |
131 | 157 | id = fxID(the, ""); |
132 | 157 | mxBehaviorDefineOwnProperty(the, instance, id, 0, mxResult, XS_GET_ONLY); |
133 | 157 | mxPushSlot(mxArgv(1)); |
134 | 157 | mxCall(); |
135 | 157 | mxPushUndefined(); |
136 | 157 | fxKeyAt(the, id, 0, the->stack); |
137 | 157 | mxPushSlot(mxResult); |
138 | 157 | fxReviveJSON(the, mxArgv(1)); |
139 | 157 | mxPullSlot(mxResult); |
140 | 157 | } |
141 | 68.8k | } |
142 | | |
143 | | void fxParseJSON(txMachine* the, txJSONParser* theParser) |
144 | 68.8k | { |
145 | 68.8k | mxPush(mxEmptyString); |
146 | 68.8k | theParser->string = the->stack; |
147 | 68.8k | theParser->line = 1; |
148 | 68.8k | fxParseJSONToken(the, theParser); |
149 | 68.8k | fxParseJSONValue(the, theParser); |
150 | 68.8k | if (theParser->token != XS_JSON_TOKEN_EOF) |
151 | 9.05k | mxSyntaxError("%ld: missing EOF", theParser->line); |
152 | 68.8k | } |
153 | | |
154 | | void fxParseJSONArray(txMachine* the, txJSONParser* theParser) |
155 | 10.4M | { |
156 | 10.4M | txSlot* anArray; |
157 | 10.4M | txIndex aLength; |
158 | 10.4M | txSlot* anItem; |
159 | | |
160 | 10.4M | mxCheckCStack(); |
161 | 10.4M | fxParseJSONToken(the, theParser); |
162 | 10.4M | mxPush(mxArrayPrototype); |
163 | 10.4M | anArray = fxNewArrayInstance(the); |
164 | 10.4M | aLength = 0; |
165 | 10.4M | anItem = fxLastProperty(the, anArray); |
166 | 26.3M | for (;;) { |
167 | 26.3M | if (theParser->token == XS_JSON_TOKEN_RIGHT_BRACKET) |
168 | 8.44M | break; |
169 | 17.9M | if (aLength) { |
170 | 10.2M | if (theParser->token == XS_JSON_TOKEN_COMMA) |
171 | 10.2M | fxParseJSONToken(the, theParser); |
172 | 3.03k | else |
173 | 3.03k | mxSyntaxError("%ld: missing ,", theParser->line); |
174 | 10.2M | } |
175 | 17.9M | fxParseJSONValue(the, theParser); |
176 | 17.9M | aLength++; |
177 | 17.9M | anItem->next = fxNewSlot(the); |
178 | 17.9M | anItem = anItem->next; |
179 | 17.9M | anItem->kind = the->stack->kind; |
180 | 17.9M | anItem->value = the->stack->value; |
181 | 17.9M | mxPop(); |
182 | 17.9M | } |
183 | 10.4M | anArray->next->value.array.length = aLength; |
184 | 10.4M | fxCacheArray(the, anArray); |
185 | 10.4M | fxParseJSONToken(the, theParser); |
186 | 10.4M | } |
187 | | |
188 | | void fxParseJSONToken(txMachine* the, txJSONParser* theParser) |
189 | 48.2M | { |
190 | 48.2M | txInteger character; |
191 | 48.2M | txBoolean escaped; |
192 | 48.2M | txNumber number; |
193 | 48.2M | txSize offset; |
194 | 48.2M | txSize size; |
195 | 48.2M | txString p, s; |
196 | | |
197 | 48.2M | theParser->integer = 0; |
198 | 48.2M | theParser->number = 0; |
199 | 48.2M | theParser->string->value.string = mxEmptyString.value.string; |
200 | 48.2M | theParser->string->kind = mxEmptyString.kind; |
201 | 48.2M | theParser->token = XS_NO_JSON_TOKEN; |
202 | 48.2M | p = theParser->slot->value.string + theParser->offset; |
203 | 97.5M | while (theParser->token == XS_NO_JSON_TOKEN) { |
204 | 49.4M | switch (*p) { |
205 | 12.1k | case 0: |
206 | 12.1k | theParser->token = XS_JSON_TOKEN_EOF; |
207 | 12.1k | break; |
208 | 300k | case 10: |
209 | 300k | p++; |
210 | 300k | theParser->line++; |
211 | 300k | break; |
212 | 1.27k | case 13: |
213 | 1.27k | p++; |
214 | 1.27k | theParser->line++; |
215 | 1.27k | if (*p == 10) |
216 | 201 | p++; |
217 | 1.27k | break; |
218 | 9.55k | case '\t': |
219 | 913k | case ' ': |
220 | 913k | p++; |
221 | 913k | break; |
222 | 25.3k | case '-': |
223 | 592k | case '0': |
224 | 740k | case '1': |
225 | 830k | case '2': |
226 | 848k | case '3': |
227 | 1.00M | case '4': |
228 | 1.23M | case '5': |
229 | 1.35M | case '6': |
230 | 8.37M | case '7': |
231 | 9.44M | case '8': |
232 | 9.67M | case '9': |
233 | 9.67M | s = p; |
234 | 9.67M | if (*p == '-') |
235 | 25.3k | p++; |
236 | 9.67M | if (('0' <= *p) && (*p <= '9')) { |
237 | 9.67M | if (*p == '0') { |
238 | 569k | p++; |
239 | 569k | } |
240 | 9.10M | else { |
241 | 9.10M | p++; |
242 | 10.8M | while (('0' <= *p) && (*p <= '9')) |
243 | 1.78M | p++; |
244 | 9.10M | } |
245 | 9.67M | if (*p == '.') { |
246 | 25.3k | p++; |
247 | 25.3k | if (('0' <= *p) && (*p <= '9')) { |
248 | 23.2k | p++; |
249 | 1.61M | while (('0' <= *p) && (*p <= '9')) |
250 | 1.58M | p++; |
251 | 23.2k | } |
252 | 2.09k | else |
253 | 2.09k | goto error; |
254 | 25.3k | } |
255 | 9.67M | if ((*p == 'e') || (*p == 'E')) { |
256 | 31.2k | p++; |
257 | 31.2k | if ((*p == '+') || (*p == '-')) |
258 | 8.64k | p++; |
259 | 31.2k | if (('0' <= *p) && (*p <= '9')) { |
260 | 23.9k | p++; |
261 | 96.1k | while (('0' <= *p) && (*p <= '9')) |
262 | 72.1k | p++; |
263 | 23.9k | } |
264 | 7.33k | else |
265 | 7.33k | goto error; |
266 | 31.2k | } |
267 | 9.67M | } |
268 | 3.41k | else |
269 | 3.41k | goto error; |
270 | 9.66M | size = mxPtrDiff(p - s); |
271 | 9.66M | if ((size_t)(size + 1) > sizeof(the->nameBuffer)) |
272 | 22 | mxSyntaxError("%ld: number overflow", theParser->line); |
273 | 9.66M | c_memcpy(the->nameBuffer, s, size); |
274 | 9.66M | the->nameBuffer[size] = 0; |
275 | 9.66M | theParser->number = fxStringToNumber(the, the->nameBuffer, 0); |
276 | 9.66M | theParser->integer = (txInteger)theParser->number; |
277 | 9.66M | number = theParser->integer; |
278 | 9.66M | if ((theParser->number == number) && (theParser->number != -0)) |
279 | 9.04M | theParser->token = XS_JSON_TOKEN_INTEGER; |
280 | 621k | else |
281 | 621k | theParser->token = XS_JSON_TOKEN_NUMBER; |
282 | 9.66M | break; |
283 | 12.9M | case ',': |
284 | 12.9M | p++; |
285 | 12.9M | theParser->token = XS_JSON_TOKEN_COMMA; |
286 | 12.9M | break; |
287 | 2.90M | case ':': |
288 | 2.90M | p++; |
289 | 2.90M | theParser->token = XS_JSON_TOKEN_COLON; |
290 | 2.90M | break; |
291 | 10.4M | case '[': |
292 | 10.4M | p++; |
293 | 10.4M | theParser->token = XS_JSON_TOKEN_LEFT_BRACKET; |
294 | 10.4M | break; |
295 | 8.44M | case ']': |
296 | 8.44M | p++; |
297 | 8.44M | theParser->token = XS_JSON_TOKEN_RIGHT_BRACKET; |
298 | 8.44M | break; |
299 | 266k | case '{': |
300 | 266k | p++; |
301 | 266k | theParser->token = XS_JSON_TOKEN_LEFT_BRACE; |
302 | 266k | break; |
303 | 70.8k | case '}': |
304 | 70.8k | p++; |
305 | 70.8k | theParser->token = XS_JSON_TOKEN_RIGHT_BRACE; |
306 | 70.8k | break; |
307 | 3.34M | case '"': |
308 | 3.34M | p++; |
309 | 3.34M | escaped = 0; |
310 | 3.34M | offset = mxPtrDiff(p - theParser->slot->value.string); |
311 | 3.34M | size = 0; |
312 | 72.8M | for (;;) { |
313 | 72.8M | p = mxStringByteDecode(p, &character); |
314 | 72.8M | if (character < 32) { |
315 | 3.16k | goto error; |
316 | 3.16k | } |
317 | 72.8M | else if (character == '"') { |
318 | 3.33M | break; |
319 | 3.33M | } |
320 | 69.5M | else if (character == '\\') { |
321 | 25.7k | escaped = 1; |
322 | 25.7k | switch (*p) { |
323 | 698 | case '"': |
324 | 1.20k | case '/': |
325 | 1.98k | case '\\': |
326 | 4.91k | case 'b': |
327 | 6.09k | case 'f': |
328 | 7.96k | case 'n': |
329 | 9.50k | case 'r': |
330 | 10.9k | case 't': |
331 | 10.9k | p++; |
332 | 10.9k | size++; |
333 | 10.9k | break; |
334 | 13.2k | case 'u': |
335 | 13.2k | p++; |
336 | 13.2k | if (fxParseUnicodeEscape(&p, &character, 0, '\\')) |
337 | 10.8k | size += mxStringByteLength(character); |
338 | 2.31k | else |
339 | 2.31k | goto error; |
340 | 10.8k | break; |
341 | 10.8k | default: |
342 | 1.63k | goto error; |
343 | 25.7k | } |
344 | 25.7k | } |
345 | 69.5M | else { |
346 | 69.5M | size += mxStringByteLength(character); |
347 | 69.5M | } |
348 | 72.8M | } |
349 | 3.33M | s = theParser->string->value.string = fxNewChunk(the, size + 1); |
350 | 3.33M | theParser->string->kind = XS_STRING_KIND; |
351 | 3.33M | p = theParser->slot->value.string + offset; |
352 | 3.33M | if (escaped) { |
353 | 18.2M | for (;;) { |
354 | 18.2M | if (*p == '"') { |
355 | 15.4k | p++; |
356 | 15.4k | *s = 0; |
357 | 15.4k | break; |
358 | 15.4k | } |
359 | 18.1M | else if (*p == '\\') { |
360 | 20.0k | p++; |
361 | 20.0k | switch (*p) { |
362 | 496 | case '"': |
363 | 804 | case '/': |
364 | 1.39k | case '\\': |
365 | 1.39k | *s++ = *p++; |
366 | 1.39k | break; |
367 | 2.73k | case 'b': |
368 | 2.73k | p++; |
369 | 2.73k | *s++ = '\b'; |
370 | 2.73k | break; |
371 | 985 | case 'f': |
372 | 985 | p++; |
373 | 985 | *s++ = '\f'; |
374 | 985 | break; |
375 | 1.46k | case 'n': |
376 | 1.46k | p++; |
377 | 1.46k | *s++ = '\n'; |
378 | 1.46k | break; |
379 | 1.35k | case 'r': |
380 | 1.35k | p++; |
381 | 1.35k | *s++ = '\r'; |
382 | 1.35k | break; |
383 | 1.21k | case 't': |
384 | 1.21k | p++; |
385 | 1.21k | *s++ = '\t'; |
386 | 1.21k | break; |
387 | 10.7k | case 'u': |
388 | 10.7k | p++; |
389 | 10.7k | fxParseUnicodeEscape(&p, &character, 0, '\\'); |
390 | 10.7k | s = mxStringByteEncode(s, character); |
391 | 10.7k | break; |
392 | 20.0k | } |
393 | 20.0k | } |
394 | 18.1M | else { |
395 | 18.1M | *s++ = *p++; |
396 | 18.1M | } |
397 | 18.2M | } |
398 | 15.4k | } |
399 | 3.32M | else { |
400 | 3.32M | c_memcpy(s, p, size); |
401 | 3.32M | p += size + 1; |
402 | 3.32M | s[size] = 0; |
403 | 3.32M | } |
404 | 3.33M | theParser->token = XS_JSON_TOKEN_STRING; |
405 | 3.33M | break; |
406 | 5.90k | case 'f': |
407 | 5.90k | p++; |
408 | 5.90k | if (*p != 'a') goto error; |
409 | 4.49k | p++; |
410 | 4.49k | if (*p != 'l') goto error; |
411 | 3.20k | p++; |
412 | 3.20k | if (*p != 's') goto error; |
413 | 2.99k | p++; |
414 | 2.99k | if (*p != 'e') goto error; |
415 | 1.95k | p++; |
416 | 1.95k | theParser->token = XS_JSON_TOKEN_FALSE; |
417 | 1.95k | break; |
418 | 3.41k | case 'n': |
419 | 3.41k | p++; |
420 | 3.41k | if (*p != 'u') goto error; |
421 | 2.00k | p++; |
422 | 2.00k | if (*p != 'l') goto error; |
423 | 1.51k | p++; |
424 | 1.51k | if (*p != 'l') goto error; |
425 | 1.20k | p++; |
426 | 1.20k | theParser->token = XS_JSON_TOKEN_NULL; |
427 | 1.20k | break; |
428 | 57.2k | case 't': |
429 | 57.2k | p++; |
430 | 57.2k | if (*p != 'r') goto error; |
431 | 56.4k | p++; |
432 | 56.4k | if (*p != 'u') goto error; |
433 | 55.4k | p++; |
434 | 55.4k | if (*p != 'e') goto error; |
435 | 53.8k | p++; |
436 | 53.8k | theParser->token = XS_JSON_TOKEN_TRUE; |
437 | 53.8k | break; |
438 | 8.31k | default: |
439 | 37.7k | error: |
440 | 37.7k | mxSyntaxError("%ld: invalid character", theParser->line); |
441 | 0 | break; |
442 | 49.4M | } |
443 | 49.4M | } |
444 | 48.1M | theParser->offset = mxPtrDiff(p - theParser->slot->value.string); |
445 | 48.1M | } |
446 | | |
447 | | void fxParseJSONObject(txMachine* the, txJSONParser* theParser) |
448 | 266k | { |
449 | 266k | txSlot* anObject; |
450 | 266k | txBoolean comma = 0; |
451 | 266k | txSlot* at; |
452 | 266k | txIndex index; |
453 | 266k | txID id; |
454 | 266k | txSlot* aProperty; |
455 | | |
456 | 266k | mxCheckCStack(); |
457 | 266k | fxParseJSONToken(the, theParser); |
458 | 266k | mxPush(mxObjectPrototype); |
459 | 266k | anObject = fxNewObjectInstance(the); |
460 | 2.98M | for (;;) { |
461 | 2.98M | if (theParser->token == XS_JSON_TOKEN_RIGHT_BRACE) |
462 | 69.8k | break; |
463 | 2.91M | if (comma) { |
464 | 2.65M | if (theParser->token == XS_JSON_TOKEN_COMMA) |
465 | 2.65M | fxParseJSONToken(the, theParser); |
466 | 2.04k | else |
467 | 2.04k | mxSyntaxError("%ld: missing ,", theParser->line); |
468 | 2.65M | } |
469 | 2.90M | if (theParser->token != XS_JSON_TOKEN_STRING) |
470 | 1.57k | mxSyntaxError("%ld: missing name", theParser->line); |
471 | 2.90M | mxPushString(theParser->string->value.string); |
472 | 2.90M | at = the->stack; |
473 | 2.90M | index = 0; |
474 | 2.90M | if (theParser->keys) { |
475 | 61 | at->kind = XS_UNDEFINED_KIND; |
476 | 61 | if (fxStringToIndex(the, at->value.string, &index)) |
477 | 15 | id = 0; |
478 | 46 | else |
479 | 46 | id = fxFindName(the, at->value.string); |
480 | 61 | if (id != XS_NO_ID) { |
481 | 15 | txSlot* item = theParser->keys->value.reference->next; |
482 | 44 | while (item) { |
483 | 37 | if ((item->value.at.id == id) && (item->value.at.index == index)) { |
484 | 8 | at->value.at.id = id; |
485 | 8 | at->value.at.index = index; |
486 | 8 | at->kind = XS_AT_KIND; |
487 | 8 | break; |
488 | 8 | } |
489 | 29 | item = item->next; |
490 | 29 | } |
491 | 15 | } |
492 | 61 | } |
493 | 2.90M | else { |
494 | 2.90M | if (fxStringToIndex(the, at->value.string, &index)) |
495 | 2.37M | id = 0; |
496 | 527k | else |
497 | 527k | id = fxNewName(the, at); |
498 | 2.90M | at->value.at.id = id; |
499 | 2.90M | at->value.at.index = index; |
500 | 2.90M | at->kind = XS_AT_KIND; |
501 | 2.90M | } |
502 | 2.90M | fxParseJSONToken(the, theParser); |
503 | 2.90M | if (theParser->token != XS_JSON_TOKEN_COLON) |
504 | 4.58k | mxSyntaxError("%ld: missing :", theParser->line); |
505 | 2.90M | fxParseJSONToken(the, theParser); |
506 | 2.90M | fxParseJSONValue(the, theParser); |
507 | 2.90M | if ((at->kind == XS_AT_KIND) && (the->stack->kind != XS_UNDEFINED_KIND)) { |
508 | 2.71M | aProperty = mxBehaviorSetProperty(the, anObject, at->value.at.id, at->value.at.index, XS_OWN); |
509 | 2.71M | aProperty->kind = the->stack->kind; |
510 | 2.71M | aProperty->value = the->stack->value; |
511 | 2.71M | } |
512 | 2.90M | mxPop(); |
513 | 2.90M | mxPop(); |
514 | 2.90M | comma = 1; |
515 | 2.90M | } |
516 | 257k | fxParseJSONToken(the, theParser); |
517 | 257k | } |
518 | | |
519 | | void fxParseJSONValue(txMachine* the, txJSONParser* theParser) |
520 | 20.8M | { |
521 | 20.8M | switch (theParser->token) { |
522 | 1.82k | case XS_JSON_TOKEN_FALSE: |
523 | 1.82k | mxPushBoolean(0); |
524 | 1.82k | fxParseJSONToken(the, theParser); |
525 | 1.82k | break; |
526 | 53.7k | case XS_JSON_TOKEN_TRUE: |
527 | 53.7k | mxPushBoolean(1); |
528 | 53.7k | fxParseJSONToken(the, theParser); |
529 | 53.7k | break; |
530 | 1.19k | case XS_JSON_TOKEN_NULL: |
531 | 1.19k | mxPushNull(); |
532 | 1.19k | fxParseJSONToken(the, theParser); |
533 | 1.19k | break; |
534 | 9.03M | case XS_JSON_TOKEN_INTEGER: |
535 | 9.03M | mxPushInteger(theParser->integer); |
536 | 9.03M | fxParseJSONToken(the, theParser); |
537 | 9.03M | break; |
538 | 616k | case XS_JSON_TOKEN_NUMBER: |
539 | 616k | mxPushNumber(theParser->number); |
540 | 616k | fxParseJSONToken(the, theParser); |
541 | 616k | break; |
542 | 426k | case XS_JSON_TOKEN_STRING: |
543 | 426k | mxPushString(theParser->string->value.string); |
544 | 426k | fxParseJSONToken(the, theParser); |
545 | 426k | break; |
546 | 266k | case XS_JSON_TOKEN_LEFT_BRACE: |
547 | 266k | fxParseJSONObject(the, theParser); |
548 | 266k | break; |
549 | 10.4M | case XS_JSON_TOKEN_LEFT_BRACKET: |
550 | 10.4M | fxParseJSONArray(the, theParser); |
551 | 10.4M | break; |
552 | 1.69k | default: |
553 | 1.69k | mxPushUndefined(); |
554 | 1.69k | mxSyntaxError("%ld: invalid value", theParser->line); |
555 | 0 | break; |
556 | 20.8M | } |
557 | 20.8M | } |
558 | | |
559 | | void fxReviveJSON(txMachine* the, txSlot* reviver) |
560 | 39.1k | { |
561 | 39.1k | txSlot* reference = the->stack; |
562 | 39.1k | mxCheckCStack(); |
563 | 39.1k | if (mxIsReference(reference)) { |
564 | 30.6k | txSlot* instance = reference->value.reference; |
565 | 30.6k | if (fxIsArray(the, instance)) { |
566 | 12.2k | txIndex length, index; |
567 | 12.2k | mxPushSlot(reference); |
568 | 12.2k | mxGetID(mxID(_length)); |
569 | 12.2k | length = (txIndex)fxToLength(the, the->stack); |
570 | 12.2k | mxPop(); |
571 | 12.2k | index = 0; |
572 | 32.7k | while (index < length) { |
573 | 20.4k | mxPushSlot(reference); |
574 | 20.4k | mxPushSlot(reviver); |
575 | 20.4k | mxCall(); |
576 | 20.4k | mxPushUndefined(); |
577 | 20.4k | fxKeyAt(the, 0, index, the->stack); |
578 | 20.4k | mxPushSlot(reference); |
579 | 20.4k | mxGetIndex(index); |
580 | 20.4k | fxReviveJSON(the, reviver); |
581 | 20.4k | if (mxIsUndefined(the->stack)) { |
582 | 13 | mxBehaviorDeleteProperty(the, reference->value.reference, 0, index); |
583 | 13 | } |
584 | 20.4k | else { |
585 | 20.4k | mxBehaviorDefineOwnProperty(the, reference->value.reference, 0, index, the->stack, XS_GET_ONLY); |
586 | 20.4k | } |
587 | 20.4k | mxPop(); |
588 | 20.4k | index++; |
589 | 20.4k | } |
590 | 12.2k | } |
591 | 18.4k | else { |
592 | 18.4k | txSlot* at = fxNewInstance(the); |
593 | 18.4k | mxBehaviorOwnKeys(the, instance, XS_EACH_NAME_FLAG, at); |
594 | 36.9k | while ((at = at->next)) { |
595 | 18.5k | mxPushSlot(reference); |
596 | 18.5k | mxPushSlot(reviver); |
597 | 18.5k | mxCall(); |
598 | 18.5k | mxPushUndefined(); |
599 | 18.5k | fxKeyAt(the, at->value.at.id, at->value.at.index, the->stack); |
600 | 18.5k | mxPushSlot(reference); |
601 | 18.5k | mxGetAll(at->value.at.id, at->value.at.index); |
602 | 18.5k | fxReviveJSON(the, reviver); |
603 | 18.5k | if (mxIsUndefined(the->stack)) { |
604 | 146 | mxBehaviorDeleteProperty(the, reference->value.reference, at->value.at.id, at->value.at.index); |
605 | 146 | } |
606 | 18.3k | else { |
607 | 18.3k | mxBehaviorDefineOwnProperty(the, reference->value.reference, at->value.at.id, at->value.at.index, the->stack, XS_GET_ONLY); |
608 | 18.3k | } |
609 | 18.5k | mxPop(); |
610 | 18.5k | } |
611 | 18.4k | mxPop(); |
612 | 18.4k | } |
613 | 30.6k | } |
614 | 39.1k | mxRunCount(2); |
615 | 39.1k | } |
616 | | |
617 | | void fx_JSON_stringify(txMachine* the) |
618 | 398k | { |
619 | 398k | volatile txJSONStringifier aStringifier = {0}; |
620 | 398k | mxTry(the) { |
621 | 398k | fxStringifyJSON(the, (txJSONStringifier*)&aStringifier); |
622 | 398k | if (aStringifier.offset) { |
623 | 322k | fxStringifyJSONChars(the, (txJSONStringifier*)&aStringifier, "\0", 1); |
624 | 322k | mxResult->value.string = (txString)fxNewChunk(the, aStringifier.offset); |
625 | 322k | c_memcpy(mxResult->value.string, aStringifier.buffer, aStringifier.offset); |
626 | 322k | mxResult->kind = XS_STRING_KIND; |
627 | 322k | } |
628 | 398k | c_free(aStringifier.buffer); |
629 | 398k | } |
630 | 398k | mxCatch(the) { |
631 | 2.44k | if (aStringifier.buffer) |
632 | 2.44k | c_free(aStringifier.buffer); |
633 | 2.44k | fxJump(the); |
634 | 2.44k | } |
635 | 398k | } |
636 | | |
637 | | void fxStringifyJSON(txMachine* the, txJSONStringifier* theStringifier) |
638 | 398k | { |
639 | 398k | txSlot* aSlot; |
640 | 398k | txInteger aFlag; |
641 | 398k | txSlot* instance; |
642 | | |
643 | 398k | aSlot = fxGetInstance(the, mxThis); |
644 | 398k | theStringifier->offset = 0; |
645 | 398k | theStringifier->size = 1024; |
646 | 398k | theStringifier->buffer = c_malloc(1024); |
647 | 398k | if (!theStringifier->buffer) |
648 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
649 | | |
650 | 398k | if (mxArgc > 1) { |
651 | 7.75k | aSlot = mxArgv(1); |
652 | 7.75k | if (mxIsReference(aSlot)) { |
653 | 7.63k | if (fxIsCallable(the, aSlot)) |
654 | 7.51k | theStringifier->replacer = mxArgv(1); |
655 | 116 | else if (fxIsArray(the, fxGetInstance(the, aSlot))) |
656 | 107 | theStringifier->keys = fxToJSONKeys(the, aSlot); |
657 | 7.63k | } |
658 | 7.75k | } |
659 | 398k | if (mxArgc > 2) { |
660 | 111 | aSlot = mxArgv(2); |
661 | 111 | if (mxIsReference(aSlot)) { |
662 | 24 | txSlot* instance = fxGetInstance(the, aSlot); |
663 | 24 | if (mxIsNumber(instance)) { |
664 | 8 | fxToNumber(the, aSlot); |
665 | 8 | } |
666 | 16 | else if (mxIsString(instance)) { |
667 | 5 | fxToString(the, aSlot); |
668 | 5 | } |
669 | 24 | } |
670 | 111 | if ((aSlot->kind == XS_INTEGER_KIND) || (aSlot->kind == XS_NUMBER_KIND)) { |
671 | 47 | txInteger aCount = fxToInteger(the, aSlot), anIndex; |
672 | 47 | if (aCount < 0) |
673 | 10 | aCount = 0; |
674 | 37 | else if (aCount > 10) |
675 | 4 | aCount = 10; |
676 | 171 | for (anIndex = 0; anIndex < aCount; anIndex++) |
677 | 124 | theStringifier->indent[anIndex] = ' '; |
678 | 47 | theStringifier->indentLength = aCount; |
679 | 47 | } |
680 | 64 | else if (mxIsStringPrimitive(aSlot)) { |
681 | 23 | txInteger aCount = fxUnicodeLength(aSlot->value.string, C_NULL); |
682 | 23 | if (aCount > 10) { |
683 | 8 | aCount = fxUnicodeToUTF8Offset(aSlot->value.string, 10); |
684 | 8 | } |
685 | 15 | else { |
686 | 15 | aCount = (txInteger)c_strlen(aSlot->value.string); |
687 | 15 | } |
688 | 23 | c_memcpy(theStringifier->indent, aSlot->value.string, aCount); |
689 | 23 | theStringifier->indent[aCount] = 0; |
690 | 23 | theStringifier->indentLength = aCount; |
691 | 23 | } |
692 | 111 | } |
693 | | |
694 | 398k | theStringifier->stack = the->stack; |
695 | 398k | mxPush(mxObjectPrototype); |
696 | 398k | instance = fxNewObjectInstance(the); |
697 | 398k | aFlag = 0; |
698 | 398k | if (mxArgc > 0) |
699 | 398k | mxPushSlot(mxArgv(0)); |
700 | 350 | else |
701 | 350 | mxPushUndefined(); |
702 | 398k | fxNextSlotProperty(the, instance, the->stack, mxID(__empty_string_), XS_NO_FLAG); |
703 | 398k | mxPush(mxEmptyString); |
704 | 398k | fxStringifyJSONProperty(the, theStringifier, &aFlag); |
705 | 398k | mxPop(); |
706 | 398k | } |
707 | | |
708 | | void fxStringifyJSONCharacter(txMachine* the, txJSONStringifier* theStringifier, txInteger character) |
709 | 39.0M | { |
710 | 39.0M | txSize size = mxStringByteLength(character); |
711 | 39.0M | if ((theStringifier->offset + size) >= theStringifier->size) { |
712 | 64.1k | char* aBuffer; |
713 | 64.1k | theStringifier->size += ((size / 1024) + 1) * 1024; |
714 | 64.1k | aBuffer = c_realloc(theStringifier->buffer, theStringifier->size); |
715 | 64.1k | if (!aBuffer) |
716 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
717 | 64.1k | theStringifier->buffer = aBuffer; |
718 | 64.1k | } |
719 | 39.0M | mxStringByteEncode(theStringifier->buffer + theStringifier->offset, character); |
720 | 39.0M | theStringifier->offset += size; |
721 | 39.0M | } |
722 | | |
723 | | void fxStringifyJSONChars(txMachine* the, txJSONStringifier* theStringifier, char* s, txSize theSize) |
724 | 308M | { |
725 | | //fprintf(stderr, "%s", s); |
726 | 308M | if ((theStringifier->offset + theSize) >= theStringifier->size) { |
727 | 346k | char* aBuffer; |
728 | 346k | theStringifier->size += ((theSize / 1024) + 1) * 1024; |
729 | 346k | aBuffer = c_realloc(theStringifier->buffer, theStringifier->size); |
730 | 346k | if (!aBuffer) |
731 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
732 | 346k | theStringifier->buffer = aBuffer; |
733 | 346k | } |
734 | 308M | c_memcpy(theStringifier->buffer + theStringifier->offset, s, theSize); |
735 | 308M | theStringifier->offset += theSize; |
736 | 308M | } |
737 | | |
738 | | void fxStringifyJSONIndent(txMachine* the, txJSONStringifier* theStringifier) |
739 | 42.8M | { |
740 | 42.8M | txInteger aLevel; |
741 | 42.8M | if (theStringifier->indent[0]) { |
742 | 478 | fxStringifyJSONChars(the, theStringifier, "\n", 1); |
743 | 1.44k | for (aLevel = 0; aLevel < theStringifier->level; aLevel++) |
744 | 968 | fxStringifyJSONChars(the, theStringifier, theStringifier->indent, theStringifier->indentLength); |
745 | 478 | } |
746 | 42.8M | } |
747 | | |
748 | | void fxStringifyJSONInteger(txMachine* the, txJSONStringifier* theStringifier, txInteger theInteger) |
749 | 42.2M | { |
750 | 42.2M | char aBuffer[256]; |
751 | 42.2M | fxIntegerToString(the, theInteger, aBuffer, sizeof(aBuffer)); |
752 | 42.2M | fxStringifyJSONChars(the, theStringifier, aBuffer, (txSize)c_strlen(aBuffer)); |
753 | 42.2M | } |
754 | | |
755 | | void fxStringifyJSONName(txMachine* the, txJSONStringifier* theStringifier, txInteger* theFlag) |
756 | 42.9M | { |
757 | 42.9M | txSlot* aSlot = the->stack; |
758 | 42.9M | if (*theFlag & 1) { |
759 | 42.3M | fxStringifyJSONChars(the, theStringifier, ",", 1); |
760 | 42.3M | fxStringifyJSONIndent(the, theStringifier); |
761 | 42.3M | } |
762 | 592k | else |
763 | 592k | *theFlag |= 1; |
764 | 42.9M | if (*theFlag & 2) { |
765 | 42.5M | if (aSlot->kind == XS_INTEGER_KIND) { |
766 | 42.2M | fxStringifyJSONChars(the, theStringifier, "\"", 1); |
767 | 42.2M | fxStringifyJSONInteger(the, theStringifier, aSlot->value.integer); |
768 | 42.2M | fxStringifyJSONChars(the, theStringifier, "\"", 1); |
769 | 42.2M | } |
770 | 302k | else |
771 | 302k | fxStringifyJSONString(the, theStringifier, aSlot->value.string); |
772 | 42.5M | fxStringifyJSONChars(the, theStringifier, ":", 1); |
773 | 42.5M | if (theStringifier->indent[0]) |
774 | 210 | fxStringifyJSONChars(the, theStringifier, " ", 1); |
775 | 42.5M | } |
776 | 42.9M | mxPop(); // POP KEY |
777 | 42.9M | } |
778 | | |
779 | | void fxStringifyJSONNumber(txMachine* the, txJSONStringifier* theStringifier, txNumber theNumber) |
780 | 122k | { |
781 | 122k | int fpclass = c_fpclassify(theNumber); |
782 | 122k | if ((fpclass != C_FP_NAN) && (fpclass != C_FP_INFINITE)) { |
783 | 39.5k | char aBuffer[256]; |
784 | 39.5k | fxNumberToString(the, theNumber, aBuffer, sizeof(aBuffer), 0, 0); |
785 | 39.5k | fxStringifyJSONChars(the, theStringifier, aBuffer, (txSize)c_strlen(aBuffer)); |
786 | 39.5k | } |
787 | 83.2k | else |
788 | 83.2k | fxStringifyJSONChars(the, theStringifier, "null", 4); |
789 | 122k | } |
790 | | |
791 | | void fxStringifyJSONProperty(txMachine* the, txJSONStringifier* theStringifier, txInteger* theFlag) |
792 | 43.1M | { |
793 | 43.1M | txSlot* aWrapper = the->stack + 2; |
794 | 43.1M | txSlot* aValue = the->stack + 1; |
795 | 43.1M | txSlot* aKey = the->stack; |
796 | 43.1M | txSlot* anInstance; |
797 | 43.1M | txSlot* aSlot; |
798 | 43.1M | txInteger aFlag; |
799 | 43.1M | txIndex aLength, anIndex; |
800 | | |
801 | 43.1M | mxCheckCStack(); |
802 | 43.1M | if (mxIsReference(aValue) || mxIsBigInt(aValue)) { |
803 | | /* THIS */ |
804 | 249k | mxPushSlot(aValue); |
805 | | /* FUNCTION */ |
806 | 249k | mxDub(); |
807 | 249k | mxGetID(mxID(_toJSON)); |
808 | 249k | if (mxIsReference(the->stack) && mxIsFunction(the->stack->value.reference)) { |
809 | 9.61k | mxCall(); |
810 | 9.61k | mxPushSlot(aKey); |
811 | 9.61k | fxToString(the, the->stack); |
812 | 9.61k | mxRunCount(1); |
813 | 9.61k | mxPullSlot(aValue); |
814 | 9.61k | } |
815 | 249k | the->stack = aKey; |
816 | 249k | } |
817 | 43.1M | if (theStringifier->replacer) { |
818 | | /* THIS */ |
819 | 53.6k | mxPushSlot(aWrapper); |
820 | | /* FUNCTION */ |
821 | 53.6k | mxPushSlot(theStringifier->replacer); |
822 | 53.6k | mxCall(); |
823 | | /* ARGUMENTS */ |
824 | 53.6k | mxPushSlot(aKey); |
825 | 53.6k | fxToString(the, the->stack); |
826 | 53.6k | mxPushSlot(aValue); |
827 | | /* COUNT */ |
828 | 53.6k | mxRunCount(2); |
829 | 53.6k | mxPullSlot(aValue); |
830 | 53.6k | the->stack = aKey; |
831 | 53.6k | } |
832 | 43.1M | if (mxIsReference(aValue)) { |
833 | 285k | mxPushSlot(aValue); |
834 | 285k | anInstance = fxToInstance(the, the->stack); |
835 | 285k | if (anInstance->flag & XS_LEVEL_FLAG) |
836 | 6 | mxTypeError("cyclic value"); |
837 | 285k | the->stack = aKey; |
838 | 285k | aSlot = anInstance->next; |
839 | 285k | if (aSlot && (aSlot->flag & XS_INTERNAL_FLAG)) { |
840 | 203k | if ((aSlot->kind == XS_INTEGER_KIND) || (aSlot->kind == XS_NUMBER_KIND)) { |
841 | 3 | fxToNumber(the, aValue); |
842 | 3 | } |
843 | 203k | else if (mxIsStringPrimitive(aSlot)) { |
844 | 10 | fxToString(the, aValue); |
845 | 10 | } |
846 | 203k | else if ((aSlot->kind == XS_BOOLEAN_KIND) || (aSlot->kind == XS_BIGINT_KIND) || (aSlot->kind == XS_BIGINT_X_KIND)) { |
847 | 9 | aValue->kind = aSlot->kind; |
848 | 9 | aValue->value = aSlot->value; |
849 | 9 | } |
850 | 203k | } |
851 | 285k | } |
852 | 43.1M | if (aValue->kind == XS_NULL_KIND) { |
853 | 3.87k | fxStringifyJSONName(the, theStringifier, theFlag); |
854 | 3.87k | fxStringifyJSONChars(the, theStringifier, "null", 4); |
855 | 3.87k | } |
856 | 43.1M | else if (aValue->kind == XS_BOOLEAN_KIND) { |
857 | 88.4k | fxStringifyJSONName(the, theStringifier, theFlag); |
858 | 88.4k | if (aValue->value.boolean) |
859 | 2.14k | fxStringifyJSONChars(the, theStringifier, "true", 4); |
860 | 86.2k | else |
861 | 86.2k | fxStringifyJSONChars(the, theStringifier, "false", 5); |
862 | 88.4k | } |
863 | 43.0M | else if (aValue->kind == XS_INTEGER_KIND) { |
864 | 3.15k | fxStringifyJSONName(the, theStringifier, theFlag); |
865 | 3.15k | fxStringifyJSONInteger(the, theStringifier, aValue->value.integer); |
866 | 3.15k | } |
867 | 43.0M | else if (aValue->kind == XS_NUMBER_KIND) { |
868 | 122k | fxStringifyJSONName(the, theStringifier, theFlag); |
869 | 122k | fxStringifyJSONNumber(the, theStringifier, aValue->value.number); |
870 | 122k | } |
871 | 42.8M | else if ((aValue->kind == XS_STRING_KIND) || (aValue->kind == XS_STRING_X_KIND)) { |
872 | 42.4M | fxStringifyJSONName(the, theStringifier, theFlag); |
873 | 42.4M | fxStringifyJSONString(the, theStringifier, aValue->value.string); |
874 | 42.4M | } |
875 | 440k | else if ((aValue->kind == XS_BIGINT_KIND) || (aValue->kind == XS_BIGINT_X_KIND)) { |
876 | 8 | mxTypeError("stringify bigint"); |
877 | 8 | } |
878 | 440k | else if ((aValue->kind == XS_REFERENCE_KIND) && !fxIsCallable(the, aValue)) { |
879 | 269k | mxTry(the) { |
880 | 269k | fxStringifyJSONName(the, theStringifier, theFlag); |
881 | 269k | if (anInstance->flag & XS_MARK_FLAG) |
882 | 0 | mxTypeError("read only value"); |
883 | 269k | anInstance->flag |= XS_LEVEL_FLAG; |
884 | 269k | if (fxIsArray(the, anInstance)) { |
885 | 51.3k | fxStringifyJSONChars(the, theStringifier, "[", 1); |
886 | 51.3k | theStringifier->level++; |
887 | 51.3k | fxStringifyJSONIndent(the, theStringifier); |
888 | 51.3k | aFlag = 4; |
889 | 51.3k | mxPushReference(anInstance); |
890 | 51.3k | mxGetID(mxID(_length)); |
891 | 51.3k | aLength = fxToInteger(the, the->stack); |
892 | 51.3k | mxPop(); |
893 | 105k | for (anIndex = 0; anIndex < aLength; anIndex++) { |
894 | 54.1k | mxPushReference(anInstance); |
895 | 54.1k | mxGetIndex(anIndex); |
896 | 54.1k | mxPushInteger(anIndex); |
897 | 54.1k | fxStringifyJSONProperty(the, theStringifier, &aFlag); |
898 | 54.1k | } |
899 | 51.3k | theStringifier->level--; |
900 | 51.3k | fxStringifyJSONIndent(the, theStringifier); |
901 | 51.3k | fxStringifyJSONChars(the, theStringifier, "]", 1); |
902 | 51.3k | } |
903 | 218k | else { |
904 | 218k | fxStringifyJSONChars(the, theStringifier, "{", 1); |
905 | 218k | theStringifier->level++; |
906 | 218k | fxStringifyJSONIndent(the, theStringifier); |
907 | 218k | aFlag = 2; |
908 | 218k | { |
909 | 218k | txSlot* at; |
910 | 218k | txSlot* property; |
911 | 218k | if (theStringifier->keys) { |
912 | 109 | mxPushUndefined(); |
913 | 109 | at = theStringifier->keys->value.reference; |
914 | 109 | } |
915 | 218k | else { |
916 | 218k | at = fxNewInstance(the); |
917 | 218k | mxBehaviorOwnKeys(the, anInstance, XS_EACH_NAME_FLAG, at); |
918 | 218k | } |
919 | 218k | mxPushUndefined(); |
920 | 218k | property = the->stack; |
921 | 218k | mxPushReference(anInstance); |
922 | 42.8M | while ((at = at->next)) { |
923 | 42.6M | if (mxBehaviorGetOwnProperty(the, anInstance, at->value.at.id, at->value.at.index, property) && !(property->flag & XS_DONT_ENUM_FLAG)) { |
924 | 42.6M | mxPushReference(anInstance); |
925 | 42.6M | mxGetAll(at->value.at.id, at->value.at.index); |
926 | 42.6M | if (at->value.at.id) |
927 | 394k | fxPushKeyString(the, at->value.at.id, C_NULL); |
928 | 42.2M | else |
929 | 42.2M | mxPushInteger((txInteger)at->value.at.index); |
930 | 42.6M | fxStringifyJSONProperty(the, theStringifier, &aFlag); |
931 | 42.6M | } |
932 | 42.6M | } |
933 | 218k | mxPop(); |
934 | 218k | mxPop(); |
935 | 218k | mxPop(); |
936 | 218k | } |
937 | 218k | theStringifier->level--; |
938 | 218k | fxStringifyJSONIndent(the, theStringifier); |
939 | 218k | fxStringifyJSONChars(the, theStringifier, "}", 1); |
940 | 218k | } |
941 | 269k | anInstance->flag &= ~XS_LEVEL_FLAG; |
942 | 269k | } |
943 | 269k | mxCatch(the) { |
944 | 16 | if (anInstance->flag & XS_LEVEL_FLAG) |
945 | 16 | anInstance->flag &= ~XS_LEVEL_FLAG; |
946 | 16 | fxJump(the); |
947 | 16 | } |
948 | 269k | } |
949 | 170k | else { |
950 | 170k | if (*theFlag & 4) { |
951 | 2.61k | if (*theFlag & 1) { |
952 | 36 | fxStringifyJSONChars(the, theStringifier, ",", 1); |
953 | 36 | fxStringifyJSONIndent(the, theStringifier); |
954 | 36 | } |
955 | 2.57k | else |
956 | 2.57k | *theFlag |= 1; |
957 | 2.61k | fxStringifyJSONChars(the, theStringifier, "null", 4); |
958 | 2.61k | } |
959 | 170k | } |
960 | 43.1M | mxPop(); // POP VALUE |
961 | 43.1M | } |
962 | | |
963 | | void fxStringifyJSONString(txMachine* the, txJSONStringifier* theStringifier, txString theString) |
964 | 42.7M | { |
965 | 42.7M | fxStringifyJSONChars(the, theStringifier, "\"", 1); |
966 | 91.5M | for (;;) { |
967 | 91.5M | txInteger character; |
968 | 91.5M | theString = mxStringByteDecode(theString, &character); |
969 | 91.5M | if (character == C_EOF) |
970 | 42.7M | break; |
971 | 48.8M | if (character < 8) |
972 | 2.83M | fxStringifyJSONUnicodeEscape(the, theStringifier, character); |
973 | 45.9M | else if (character == 8) |
974 | 39.8k | fxStringifyJSONChars(the, theStringifier, "\\b", 2); |
975 | 45.9M | else if (character == 9) |
976 | 18.1k | fxStringifyJSONChars(the, theStringifier, "\\t", 2); |
977 | 45.9M | else if (character == 10) |
978 | 64.7k | fxStringifyJSONChars(the, theStringifier, "\\n", 2); |
979 | 45.8M | else if (character == 11) |
980 | 73.3k | fxStringifyJSONUnicodeEscape(the, theStringifier, character); |
981 | 45.7M | else if (character == 12) |
982 | 297k | fxStringifyJSONChars(the, theStringifier, "\\f", 2); |
983 | 45.4M | else if (character == 13) |
984 | 1.36k | fxStringifyJSONChars(the, theStringifier, "\\r", 2); |
985 | 45.4M | else if (character < 32) |
986 | 829k | fxStringifyJSONUnicodeEscape(the, theStringifier, character); |
987 | 44.6M | else if (character < 34) |
988 | 468k | fxStringifyJSONCharacter(the, theStringifier, character); |
989 | 44.1M | else if (character == 34) |
990 | 1.79M | fxStringifyJSONChars(the, theStringifier, "\\\"", 2); |
991 | 42.3M | else if (character < 92) |
992 | 6.28M | fxStringifyJSONCharacter(the, theStringifier, character); |
993 | 36.1M | else if (character == 92) |
994 | 3.38M | fxStringifyJSONChars(the, theStringifier, "\\\\", 2); |
995 | 32.7M | else if (character < 127) |
996 | 6.63M | fxStringifyJSONCharacter(the, theStringifier, character); |
997 | 26.0M | else if ((0xD800 <= character) && (character <= 0xDFFF)) |
998 | 401k | fxStringifyJSONUnicodeEscape(the, theStringifier, character); |
999 | 25.6M | else |
1000 | 25.6M | fxStringifyJSONCharacter(the, theStringifier, character); |
1001 | 48.8M | } |
1002 | 42.7M | fxStringifyJSONChars(the, theStringifier, "\"", 1); |
1003 | 42.7M | } |
1004 | | |
1005 | | void fxStringifyJSONUnicodeEscape(txMachine* the, txJSONStringifier* theStringifier, txInteger character) |
1006 | 4.14M | { |
1007 | 4.14M | char buffer[16]; |
1008 | 4.14M | txString p = buffer; |
1009 | 4.14M | *p++ = '\\'; |
1010 | 4.14M | *p++ = 'u'; |
1011 | 4.14M | p = fxStringifyUnicodeEscape(p, character, '\\'); |
1012 | 4.14M | fxStringifyJSONChars(the, theStringifier, buffer, mxPtrDiff(p - buffer)); |
1013 | 4.14M | } |
1014 | | |
1015 | | txSlot* fxToJSONKeys(txMachine* the, txSlot* reference) |
1016 | 131 | { |
1017 | 131 | txSlot* list = fxNewInstance(the); |
1018 | 131 | txSlot* item = list; |
1019 | 131 | txSlot* slot; |
1020 | 131 | txIndex length, i; |
1021 | 131 | mxPushSlot(reference); |
1022 | 131 | mxGetID(mxID(_length)); |
1023 | 131 | length = (txIndex)fxToLength(the, the->stack); |
1024 | 131 | mxPop(); |
1025 | 131 | i = 0; |
1026 | 510 | while (i < length) { |
1027 | 379 | txBoolean flag = 0; |
1028 | 379 | txID id = XS_NO_ID; |
1029 | 379 | txIndex index = 0; |
1030 | 379 | mxPushSlot(reference); |
1031 | 379 | mxGetIndex(i); |
1032 | 379 | slot = the->stack; |
1033 | 448 | again: |
1034 | 448 | if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) { |
1035 | 177 | if (fxStringToIndex(the, slot->value.string, &index)) |
1036 | 5 | flag = 1; |
1037 | 172 | else { |
1038 | 172 | if (slot->kind == XS_STRING_X_KIND) |
1039 | 0 | id = fxNewNameX(the, slot->value.string); |
1040 | 172 | else |
1041 | 172 | id = fxNewName(the, slot); |
1042 | 172 | flag = 1; |
1043 | 172 | } |
1044 | 177 | } |
1045 | 271 | else if (slot->kind == XS_INTEGER_KIND) { |
1046 | 67 | if (fxIntegerToIndex(the, slot->value.integer, &index)) |
1047 | 48 | flag = 1; |
1048 | 19 | else { |
1049 | 19 | fxToString(the, slot); |
1050 | 19 | goto again; |
1051 | 19 | } |
1052 | 67 | } |
1053 | 204 | else if (slot->kind == XS_NUMBER_KIND){ |
1054 | 56 | if (fxNumberToIndex(the, slot->value.number, &index)) |
1055 | 8 | flag = 1; |
1056 | 48 | else { |
1057 | 48 | fxToString(the, slot); |
1058 | 48 | goto again; |
1059 | 48 | } |
1060 | 56 | } |
1061 | 148 | else if (slot->kind == XS_REFERENCE_KIND) { |
1062 | 7 | txSlot* instance = slot->value.reference; |
1063 | 7 | if (mxIsNumber(instance) || mxIsString(instance)) { |
1064 | 2 | fxToString(the, slot); |
1065 | 2 | goto again; |
1066 | 2 | } |
1067 | 7 | } |
1068 | 379 | if (flag) { |
1069 | 233 | txSlot* already = list->next; |
1070 | 532 | while (already) { |
1071 | 308 | if ((already->value.at.id == id) && (already->value.at.index == index)) |
1072 | 9 | break; |
1073 | 299 | already = already->next; |
1074 | 299 | } |
1075 | 233 | if (!already) { |
1076 | 224 | item = item->next = fxNewSlot(the); |
1077 | 224 | item->value.at.id = id; |
1078 | 224 | item->value.at.index = index; |
1079 | 224 | item->kind = XS_AT_KIND; |
1080 | 224 | } |
1081 | 233 | } |
1082 | 379 | mxPop(); |
1083 | 379 | i++; |
1084 | 379 | } |
1085 | 131 | return the->stack; |
1086 | 131 | } |