Coverage Report

Created: 2026-03-30 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsJSON.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2017  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
  txBoolean sourceFlag;
67
  txInteger sourceOffset;
68
  txInteger sourceSize;
69
} txJSONParser;
70
71
typedef struct {
72
  txString buffer;
73
  char indent[64];
74
  txInteger indentLength;
75
  txInteger level;
76
  txSize offset;
77
  txSize size;
78
  txSlot* replacer;
79
  txSlot* keys;
80
  txSlot* stack;
81
} txJSONStringifier;
82
83
static void fxParseJSON(txMachine* the, txJSONParser* theParser);
84
static void fxParseJSONArray(txMachine* the, txJSONParser* theParser);
85
static void fxParseJSONObject(txMachine* the, txJSONParser* theParser);
86
static void fxParseJSONToken(txMachine* the, txJSONParser* theParser);
87
static void fxParseJSONValue(txMachine* the, txJSONParser* theParser);
88
static void fxReviveJSON(txMachine* the, txJSONParser* theParser, txSlot* reviver);
89
90
static void fxStringifyJSON(txMachine* the, txJSONStringifier* theStringifier);
91
static void fxStringifyJSONCharacter(txMachine* the, txJSONStringifier* theStringifier, txInteger character);
92
static void fxStringifyJSONChars(txMachine* the, txJSONStringifier* theStringifier, char* s, txSize theSize);
93
static void fxStringifyJSONIndent(txMachine* the, txJSONStringifier* theStringifier);
94
static void fxStringifyJSONInteger(txMachine* the, txJSONStringifier* theStringifier, txInteger theInteger);
95
static void fxStringifyJSONName(txMachine* the, txJSONStringifier* theStringifier, txInteger* theFlag);
96
static void fxStringifyJSONNumber(txMachine* the, txJSONStringifier* theStringifier, txNumber theNumber);
97
static void fxStringifyJSONProperty(txMachine* the, txJSONStringifier* theStringifier, txInteger* theFlag);
98
static void fxStringifyJSONString(txMachine* the, txJSONStringifier* theStringifier, txString theString);
99
static void fxStringifyJSONUnicodeEscape(txMachine* the, txJSONStringifier* theStringifier, txInteger character);
100
101
static txSlot* fxToJSONKeys(txMachine* the, txSlot* reference);
102
103
void fxBuildJSON(txMachine* the)
104
27.0k
{
105
27.0k
  txSlot* slot;
106
27.0k
  mxPush(mxObjectPrototype);
107
27.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
108
27.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_JSON_parse), 2, mxID(_parse), XS_DONT_ENUM_FLAG);
109
27.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_JSON_stringify), 3, mxID(_stringify), XS_DONT_ENUM_FLAG);
110
27.0k
#if mxECMAScript2026
111
27.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_JSON_isRawJSON), 1, mxID(_isRawJSON), XS_DONT_ENUM_FLAG);
112
27.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_JSON_rawJSON), 1, mxID(_rawJSON), XS_DONT_ENUM_FLAG);
113
27.0k
#endif
114
27.0k
  slot = fxNextStringXProperty(the, slot, "JSON", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
115
27.0k
  mxPull(mxJSONObject);
116
27.0k
}
117
118
#define mxIsRawJSON(THE_SLOT) \
119
18
  ((THE_SLOT) && ((THE_SLOT)->next) && ((THE_SLOT)->next->flag & XS_INTERNAL_FLAG) && ((THE_SLOT)->next->kind == XS_RAW_JSON_KIND))
120
121
void fx_JSON_isRawJSON(txMachine* the)
122
29
{
123
29
  if (mxArgc < 1)
124
0
    mxTypeError("no text");
125
29
  txSlot* slot = mxArgv(0);
126
29
  mxResult->kind = XS_BOOLEAN_KIND;
127
29
  mxResult->value.boolean = (mxIsReference(slot) && mxIsRawJSON(slot->value.reference)) ? 1 : 0;
128
29
}
129
130
void fx_JSON_parse(txMachine* the)
131
46.4k
{
132
46.4k
  volatile txJSONParser aParser = {0};
133
46.4k
  if (mxArgc < 1)
134
6.46k
    mxSyntaxError("no buffer");
135
39.9k
  fxToString(the, mxArgv(0));
136
39.9k
  aParser.slot = mxArgv(0);
137
39.9k
  aParser.offset = 0;
138
39.9k
  mxPush(mxEmptyString);
139
39.9k
  aParser.string = the->stack;
140
39.9k
  aParser.line = 1;
141
39.9k
  if ((mxArgc > 1) && mxIsReference(mxArgv(1))) {
142
711
    if (fxIsArray(the, mxArgv(1)->value.reference))
143
13
      aParser.keys = fxToJSONKeys(the, mxArgv(1));
144
698
    else if (mxIsCallable(mxArgv(1)->value.reference))
145
467
      aParser.sourceFlag = 1;
146
711
  }
147
39.9k
  fxParseJSON(the, (txJSONParser*)&aParser);
148
39.9k
  if (aParser.sourceFlag) {
149
460
    txSlot* valueReference = the->stack + 1;
150
460
    txSlot* sourceReference = the->stack;
151
460
    txSlot* instance;
152
460
    txID id;
153
460
    mxPush(mxObjectPrototype);
154
460
    instance = fxNewObjectInstance(the);
155
460
    id = fxID(the, "");
156
460
    mxBehaviorDefineOwnProperty(the, instance, id, 0, valueReference, XS_GET_ONLY);
157
460
    mxPushSlot(mxArgv(1));
158
460
    mxCall();
159
460
    mxPushUndefined();
160
460
    fxKeyAt(the, id, 0, the->stack);
161
460
    mxPushSlot(valueReference);
162
460
    mxPushSlot(sourceReference);
163
460
    fxReviveJSON(the, (txJSONParser*)&aParser, mxArgv(1));
164
460
  }
165
39.9k
  mxPullSlot(mxResult);
166
39.9k
}
167
168
void fxParseJSON(txMachine* the, txJSONParser* theParser)
169
40.0k
{
170
40.0k
  fxParseJSONToken(the, theParser);
171
40.0k
  fxParseJSONValue(the, theParser);
172
40.0k
  if (theParser->token != XS_JSON_TOKEN_EOF)
173
3.64k
    mxSyntaxError("%ld: missing EOF", theParser->line);
174
40.0k
}
175
176
void fxParseJSONArray(txMachine* the, txJSONParser* theParser)
177
8.80M
{
178
8.80M
  txSlot* sourceArray = NULL;
179
8.80M
  txSlot* sourceItem;
180
8.80M
  txSlot* valueArray;
181
8.80M
  txSlot* valueItem;
182
8.80M
  txIndex length;
183
184
8.80M
  mxCheckCStack();
185
8.80M
  fxParseJSONToken(the, theParser);
186
8.80M
  mxPush(mxArrayPrototype);
187
8.80M
  valueArray = fxNewArrayInstance(the);
188
8.80M
  valueItem = fxLastProperty(the, valueArray);
189
8.80M
  if (theParser->sourceFlag) {
190
108
    mxPush(mxArrayPrototype);
191
108
    sourceArray = fxNewArrayInstance(the);
192
108
    sourceItem = fxLastProperty(the, sourceArray);
193
108
  }
194
8.80M
  length = 0;
195
23.5M
  for (;;) {
196
23.5M
    if (theParser->token == XS_JSON_TOKEN_RIGHT_BRACKET)
197
7.12M
      break;
198
16.4M
    if (length) {
199
10.8M
      if (theParser->token == XS_JSON_TOKEN_COMMA)
200
10.8M
        fxParseJSONToken(the, theParser);
201
1.69k
      else
202
1.69k
        mxSyntaxError("%ld: missing ,", theParser->line);  
203
10.8M
    }  
204
16.4M
    fxParseJSONValue(the, theParser);
205
16.4M
    length++;
206
16.4M
    if (theParser->sourceFlag) {
207
210
      sourceItem->next = fxNewSlot(the);
208
210
      sourceItem = sourceItem->next;
209
210
      sourceItem->kind = the->stack->kind;
210
210
      sourceItem->value = the->stack->value;
211
210
      mxPop();
212
210
    }
213
16.4M
    valueItem->next = fxNewSlot(the);
214
16.4M
    valueItem = valueItem->next;
215
16.4M
    valueItem->kind = the->stack->kind;
216
16.4M
    valueItem->value = the->stack->value;
217
16.4M
    mxPop();
218
16.4M
  }
219
8.80M
  valueArray->next->value.array.length = length;
220
8.80M
  fxCacheArray(the, valueArray);
221
8.80M
  if (theParser->sourceFlag) {
222
104
    sourceArray->next->value.array.length = length;
223
104
    fxCacheArray(the, sourceArray);
224
104
  }
225
8.80M
  fxParseJSONToken(the, theParser);
226
8.80M
}
227
228
void fxParseJSONToken(txMachine* the, txJSONParser* theParser)
229
44.2M
{
230
44.2M
  txInteger character;
231
44.2M
  txBoolean escaped;
232
44.2M
  txNumber number;
233
44.2M
  txSize offset;
234
44.2M
  txSize size;
235
44.2M
  txString p, s;
236
237
44.2M
  theParser->integer = 0;
238
44.2M
  theParser->number = 0;
239
44.2M
  theParser->string->value.string = mxEmptyString.value.string;
240
44.2M
  theParser->string->kind = mxEmptyString.kind;
241
44.2M
  theParser->token = XS_NO_JSON_TOKEN;
242
44.2M
  p = theParser->slot->value.string + theParser->offset;
243
89.5M
  while (theParser->token == XS_NO_JSON_TOKEN) {
244
45.2M
    switch (*p) {
245
11.6k
    case 0:
246
11.6k
      theParser->token = XS_JSON_TOKEN_EOF;
247
11.6k
      break;
248
115k
    case 10:
249
115k
      p++;
250
115k
      theParser->line++;
251
115k
      break;
252
816
    case 13:
253
816
      p++;
254
816
      theParser->line++;
255
816
      if (*p == 10)
256
230
        p++;
257
816
      break;
258
7.42k
    case '\t':
259
876k
    case ' ':
260
876k
      p++;
261
876k
      break;
262
17.7k
    case '-':
263
91.4k
    case '0':
264
202k
    case '1':
265
283k
    case '2':
266
302k
    case '3':
267
440k
    case '4':
268
613k
    case '5':
269
749k
    case '6':
270
8.44M
    case '7':
271
9.35M
    case '8':
272
9.55M
    case '9':
273
9.55M
      s = p;
274
9.55M
      if (*p == '-')
275
17.7k
        p++;
276
9.55M
      if (('0' <= *p) && (*p <= '9')) {
277
9.55M
        if (*p == '0') {
278
74.7k
          p++;
279
74.7k
        }
280
9.48M
        else {
281
9.48M
          p++;
282
10.0M
          while (('0' <= *p) && (*p <= '9'))
283
565k
            p++;
284
9.48M
        }
285
9.55M
        if (*p == '.') {
286
19.2k
          p++;
287
19.2k
          if (('0' <= *p) && (*p <= '9')) {
288
18.5k
            p++;
289
149k
            while (('0' <= *p) && (*p <= '9'))
290
130k
              p++;
291
18.5k
          }
292
667
          else
293
667
            goto error;
294
19.2k
        }
295
9.55M
        if ((*p == 'e') || (*p == 'E')) {
296
23.8k
          p++;
297
23.8k
          if ((*p == '+') || (*p == '-'))
298
8.88k
            p++;
299
23.8k
          if (('0' <= *p) && (*p <= '9')) {
300
22.3k
            p++;
301
62.6k
            while (('0' <= *p) && (*p <= '9'))
302
40.3k
              p++;
303
22.3k
          }
304
1.51k
          else
305
1.51k
            goto error;
306
23.8k
        }
307
9.55M
      }
308
1.47k
      else
309
1.47k
        goto error;
310
9.55M
      size = mxPtrDiff(p - s);
311
9.55M
      if (theParser->sourceFlag) {
312
131
        theParser->sourceOffset = mxPtrDiff(s - theParser->slot->value.string);
313
131
        theParser->sourceSize = size;
314
131
      }
315
9.55M
      if ((size_t)(size + 1) > sizeof(the->nameBuffer))
316
6
        mxSyntaxError("%ld: number overflow", theParser->line);
317
9.55M
      c_memcpy(the->nameBuffer, s, size);
318
9.55M
      the->nameBuffer[size] = 0;
319
9.55M
      theParser->number = fxStringToNumber(the, the->nameBuffer, 0);
320
9.55M
      theParser->integer = (txInteger)theParser->number;
321
9.55M
      number = theParser->integer;
322
9.55M
      if ((theParser->number == number) && (theParser->number != -0))
323
9.43M
        theParser->token = XS_JSON_TOKEN_INTEGER;
324
120k
      else
325
120k
        theParser->token = XS_JSON_TOKEN_NUMBER;
326
9.55M
      break;
327
13.0M
    case ',':
328
13.0M
      p++;
329
13.0M
      theParser->token = XS_JSON_TOKEN_COMMA;
330
13.0M
      break;  
331
2.50M
    case ':':
332
2.50M
      p++;
333
2.50M
      theParser->token = XS_JSON_TOKEN_COLON;
334
2.50M
      break;  
335
8.80M
    case '[':
336
8.80M
      p++;
337
8.80M
      theParser->token = XS_JSON_TOKEN_LEFT_BRACKET;
338
8.80M
      break;  
339
7.12M
    case ']':
340
7.12M
      p++;
341
7.12M
      theParser->token = XS_JSON_TOKEN_RIGHT_BRACKET;
342
7.12M
      break;  
343
249k
    case '{':
344
249k
      p++;
345
249k
      theParser->token = XS_JSON_TOKEN_LEFT_BRACE;
346
249k
      break;  
347
62.2k
    case '}':
348
62.2k
      p++;
349
62.2k
      theParser->token = XS_JSON_TOKEN_RIGHT_BRACE;
350
62.2k
      break;  
351
2.82M
    case '"':
352
2.82M
      s = p;
353
2.82M
      p++;
354
2.82M
      escaped = 0;
355
2.82M
      offset = mxPtrDiff(p - theParser->slot->value.string);
356
2.82M
      size = 0;
357
67.1M
      for (;;) {
358
67.1M
        p = mxStringByteDecode(p, &character);
359
67.1M
        if (character < 32) {
360
1.24k
          goto error;
361
1.24k
        }
362
67.1M
        else if (character == '"') {
363
2.81M
          break;
364
2.81M
        }
365
64.3M
        else if (character == '\\') {
366
88.2k
          escaped = 1;
367
88.2k
          switch (*p) {
368
1.77k
          case '"':
369
2.35k
          case '/':
370
3.06k
          case '\\':
371
5.83k
          case 'b':
372
7.60k
          case 'f':
373
8.80k
          case 'n':
374
76.9k
          case 'r':
375
78.2k
          case 't':
376
78.2k
            p++;
377
78.2k
            size++;
378
78.2k
            break;
379
9.28k
          case 'u':
380
9.28k
            p++;
381
9.28k
            if (fxParseUnicodeEscape(&p, &character, 0, '\\'))
382
8.43k
              size += mxStringByteLength(character);
383
854
            else
384
854
              goto error;
385
8.43k
            break;
386
8.43k
          default:
387
704
            goto error;
388
88.2k
          }
389
88.2k
        }
390
64.2M
        else {
391
64.2M
          size += mxStringByteLength(character);
392
64.2M
        }
393
67.1M
      }
394
2.81M
      if (theParser->sourceFlag) {
395
24
        theParser->sourceOffset = mxPtrDiff(s - theParser->slot->value.string);
396
24
        theParser->sourceSize = mxPtrDiff(p - s);
397
24
      }
398
2.81M
      s = theParser->string->value.string = fxNewChunk(the, size + 1);
399
2.81M
      theParser->string->kind = XS_STRING_KIND;
400
2.81M
      p = theParser->slot->value.string + offset;
401
2.81M
      if (escaped) {
402
14.7M
        for (;;) {
403
14.7M
          if (*p == '"') {
404
17.4k
            p++;
405
17.4k
            *s = 0;
406
17.4k
            break;
407
17.4k
          }
408
14.7M
          else if (*p == '\\') {
409
85.0k
            p++;
410
85.0k
            switch (*p) {
411
1.56k
            case '"':
412
1.95k
            case '/':
413
2.46k
            case '\\':
414
2.46k
              *s++ = *p++;
415
2.46k
              break;
416
2.57k
            case 'b':
417
2.57k
              p++;
418
2.57k
              *s++ = '\b';
419
2.57k
              break;
420
1.58k
            case 'f':
421
1.58k
              p++;
422
1.58k
              *s++ = '\f';
423
1.58k
              break;
424
1.00k
            case 'n':
425
1.00k
              p++;
426
1.00k
              *s++ = '\n';
427
1.00k
              break;
428
67.9k
            case 'r':
429
67.9k
              p++;
430
67.9k
              *s++ = '\r';
431
67.9k
              break;
432
1.09k
            case 't':
433
1.09k
              p++;
434
1.09k
              *s++ = '\t';
435
1.09k
              break;
436
8.20k
            case 'u':
437
8.20k
              p++;
438
8.20k
              fxParseUnicodeEscape(&p, &character, 0, '\\');
439
8.20k
              s = mxStringByteEncode(s, character);
440
8.20k
              break;
441
85.0k
            }
442
85.0k
          }
443
14.6M
          else {
444
14.6M
            *s++ = *p++;
445
14.6M
          }
446
14.7M
        }
447
17.4k
      }
448
2.80M
      else {
449
2.80M
        c_memcpy(s, p, size);
450
2.80M
        p += size + 1;
451
2.80M
        s[size] = 0;
452
2.80M
      }
453
2.81M
      theParser->token = XS_JSON_TOKEN_STRING;
454
2.81M
      break;
455
4.30k
    case 'f':
456
4.30k
      s = p;
457
4.30k
      p++;
458
4.30k
      if (*p != 'a') goto error;  
459
3.80k
      p++;
460
3.80k
      if (*p != 'l') goto error;  
461
3.75k
      p++;
462
3.75k
      if (*p != 's') goto error;  
463
3.15k
      p++;
464
3.15k
      if (*p != 'e') goto error;  
465
2.31k
      p++;
466
2.31k
      if (theParser->sourceFlag) {
467
236
        theParser->sourceOffset = mxPtrDiff(s - theParser->slot->value.string);
468
236
        theParser->sourceSize = mxPtrDiff(p - s);
469
236
      }
470
2.31k
      theParser->token = XS_JSON_TOKEN_FALSE;
471
2.31k
      break;
472
1.72k
    case 'n':
473
1.72k
      s = p;
474
1.72k
      p++;
475
1.72k
      if (*p != 'u') goto error;
476
1.40k
      p++;
477
1.40k
      if (*p != 'l') goto error;
478
662
      p++;
479
662
      if (*p != 'l') goto error;
480
570
      p++;
481
570
      if (theParser->sourceFlag) {
482
198
        theParser->sourceOffset = mxPtrDiff(s - theParser->slot->value.string);
483
198
        theParser->sourceSize = mxPtrDiff(p - s);
484
198
      }
485
570
      theParser->token = XS_JSON_TOKEN_NULL;
486
570
      break;
487
40.0k
    case 't':
488
40.0k
      s = p;
489
40.0k
      p++;
490
40.0k
      if (*p != 'r') goto error;
491
38.7k
      p++;
492
38.7k
      if (*p != 'u') goto error;
493
38.0k
      p++;
494
38.0k
      if (*p != 'e') goto error;
495
37.5k
      p++;
496
37.5k
      if (theParser->sourceFlag) {
497
21
        theParser->sourceOffset = mxPtrDiff(s - theParser->slot->value.string);
498
21
        theParser->sourceSize = mxPtrDiff(p - s);
499
21
      }
500
37.5k
      theParser->token = XS_JSON_TOKEN_TRUE;
501
37.5k
      break;
502
8.85k
    default:
503
20.9k
    error:
504
20.9k
      mxSyntaxError("%ld: invalid character", theParser->line); 
505
0
      break;
506
45.2M
    }
507
45.2M
  }
508
44.2M
  theParser->offset = mxPtrDiff(p - theParser->slot->value.string);
509
44.2M
}
510
511
void fxParseJSONObject(txMachine* the, txJSONParser* theParser)
512
249k
{
513
249k
  txSlot* sourceObject = NULL;
514
249k
  txSlot* valueObject;
515
249k
  txBoolean comma = 0;
516
249k
  txSlot* at;
517
249k
  txIndex index;
518
249k
  txID id;
519
249k
  txSlot* property;
520
521
249k
  mxCheckCStack();
522
249k
  fxParseJSONToken(the, theParser);
523
249k
  mxPush(mxObjectPrototype);
524
249k
  valueObject = fxNewObjectInstance(the);
525
249k
  if (theParser->sourceFlag) {
526
9
    mxPush(mxObjectPrototype);
527
9
    sourceObject = fxNewObjectInstance(the);
528
9
  }
529
2.56M
  for (;;) {
530
2.56M
    if (theParser->token == XS_JSON_TOKEN_RIGHT_BRACE)
531
62.1k
      break;
532
2.50M
    if (comma) {
533
2.26M
      if (theParser->token == XS_JSON_TOKEN_COMMA)
534
2.26M
        fxParseJSONToken(the, theParser);
535
495
      else
536
495
        mxSyntaxError("%ld: missing ,", theParser->line);  
537
2.26M
    }  
538
2.50M
    if (theParser->token != XS_JSON_TOKEN_STRING)
539
630
      mxSyntaxError("%ld: missing name", theParser->line);
540
2.50M
    mxPushString(theParser->string->value.string);
541
2.50M
    at = the->stack;
542
2.50M
    index = 0;
543
2.50M
    if (theParser->keys) {
544
26
      at->kind = XS_UNDEFINED_KIND;
545
26
      if (fxStringToIndex(the, at->value.string, &index))
546
4
        id = 0;
547
22
      else
548
22
        id = fxFindName(the, at->value.string);
549
26
      if (id != XS_NO_ID) {
550
5
        txSlot* item = theParser->keys->value.reference->next;
551
12
        while (item) {
552
9
          if ((item->value.at.id == id) && (item->value.at.index == index)) {
553
2
            at->value.at.id = id;
554
2
            at->value.at.index = index;
555
2
            at->kind = XS_AT_KIND;
556
2
            break;
557
2
          }
558
7
          item = item->next;
559
7
        }
560
5
      }
561
26
    }
562
2.50M
    else {
563
2.50M
      if (fxStringToIndex(the, at->value.string, &index))
564
2.02M
        id = 0;
565
477k
      else
566
477k
        id = fxNewName(the, at);
567
2.50M
      at->value.at.id = id;
568
2.50M
            at->value.at.index = index;
569
2.50M
      at->kind = XS_AT_KIND;
570
2.50M
    }
571
2.50M
    fxParseJSONToken(the, theParser);
572
2.50M
    if (theParser->token != XS_JSON_TOKEN_COLON)
573
2.76k
      mxSyntaxError("%ld: missing :", theParser->line);
574
2.50M
    fxParseJSONToken(the, theParser);
575
2.50M
    fxParseJSONValue(the, theParser);
576
2.50M
    if (theParser->sourceFlag) {
577
23
      property = mxBehaviorSetProperty(the, sourceObject, at->value.at.id, at->value.at.index, XS_OWN);
578
23
      property->kind = the->stack->kind;
579
23
      property->value = the->stack->value;
580
23
      mxPop(); // source
581
23
    }
582
2.50M
    if ((at->kind == XS_AT_KIND) && (the->stack->kind != XS_UNDEFINED_KIND)) {
583
2.32M
      property = mxBehaviorSetProperty(the, valueObject, at->value.at.id, at->value.at.index, XS_OWN);
584
2.32M
      property->kind = the->stack->kind;
585
2.32M
      property->value = the->stack->value;
586
2.32M
    }
587
2.50M
    mxPop(); // value
588
2.50M
    mxPop(); // at
589
2.50M
    comma = 1;
590
2.50M
  }
591
245k
  fxParseJSONToken(the, theParser);
592
245k
}
593
594
void fxParseJSONValue(txMachine* the, txJSONParser* theParser)
595
18.9M
{
596
18.9M
  if (theParser->token == XS_JSON_TOKEN_LEFT_BRACE)
597
249k
    fxParseJSONObject(the, theParser);
598
18.7M
  else if (theParser->token == XS_JSON_TOKEN_LEFT_BRACKET)
599
8.80M
    fxParseJSONArray(the, theParser);
600
9.90M
  else {
601
9.90M
    switch (theParser->token) {
602
2.10k
    case XS_JSON_TOKEN_FALSE:
603
2.10k
      mxPushBoolean(0);
604
2.10k
      break;
605
37.5k
    case XS_JSON_TOKEN_TRUE:
606
37.5k
      mxPushBoolean(1);
607
37.5k
      break;
608
564
    case XS_JSON_TOKEN_NULL:
609
564
      mxPushNull();
610
564
      break;
611
9.42M
    case XS_JSON_TOKEN_INTEGER:
612
9.42M
      mxPushInteger(theParser->integer);
613
9.42M
      break;
614
120k
    case XS_JSON_TOKEN_NUMBER:
615
120k
      mxPushNumber(theParser->number);
616
120k
      break;
617
311k
    case XS_JSON_TOKEN_STRING:
618
311k
      mxPushString(theParser->string->value.string);
619
311k
      break;
620
1.24k
    default:
621
1.24k
      mxPushUndefined();
622
1.24k
      mxSyntaxError("%ld: invalid value", theParser->line);
623
0
      break;
624
9.90M
    }
625
9.90M
    if (theParser->sourceFlag) {
626
585
      txSlot* value = the->stack;
627
585
      txSlot* list;
628
585
      txSlot* slot;
629
585
      mxPushList();
630
585
      list = the->stack;
631
585
      slot = list->value.list.first = fxNewSlot(the);
632
585
      slot->kind = XS_DATA_VIEW_KIND;
633
585
      slot->value.dataView.offset = theParser->sourceOffset;
634
585
      slot->value.dataView.size = theParser->sourceSize;
635
585
      slot = slot->next = list->value.list.last = fxNewSlot(the);
636
585
      slot->kind = value->kind;
637
585
      slot->value = value->value;
638
585
    }
639
9.90M
    fxParseJSONToken(the, theParser);
640
9.90M
  }
641
18.9M
}
642
643
void fxReviveJSON(txMachine* the, txJSONParser* theParser, txSlot* reviver)
644
14.2k
{
645
14.2k
  txSlot* valueReference = the->stack + 1;
646
14.2k
  txSlot* sourceReference = the->stack;
647
14.2k
  mxCheckCStack();
648
14.2k
  if (mxIsReference(valueReference)) {
649
13.6k
    txSlot* instance = valueReference->value.reference;
650
13.6k
    if (fxIsArray(the, instance)) {
651
3.62k
      txIndex length, index;
652
3.62k
      mxPushSlot(valueReference);
653
3.62k
      mxGetID(mxID(_length));
654
3.62k
      length = (txIndex)fxToLength(the, the->stack);
655
3.62k
      mxPop();
656
3.62k
      index = 0;
657
7.25k
      while (index < length) {
658
3.63k
        mxPushSlot(valueReference);
659
3.63k
        mxPushSlot(reviver);
660
3.63k
        mxCall();
661
3.63k
        mxPushUndefined();
662
3.63k
        fxKeyAt(the, 0, index, the->stack);
663
3.63k
        mxPushSlot(valueReference);
664
3.63k
        mxGetIndex(index);
665
3.63k
        if (mxIsReference(sourceReference)) {
666
203
          mxPushSlot(sourceReference);
667
203
          mxGetIndex(index);
668
203
        }
669
3.43k
        else
670
3.43k
          mxPushUndefined();
671
3.63k
        fxReviveJSON(the, theParser, reviver);
672
3.63k
        if (mxIsUndefined(the->stack)) {
673
4
          mxBehaviorDeleteProperty(the, valueReference->value.reference, 0, index);
674
4
        }
675
3.63k
        else {
676
3.63k
          mxBehaviorDefineOwnProperty(the, valueReference->value.reference, 0, index, the->stack, XS_GET_ONLY);
677
3.63k
        }
678
3.63k
        mxPop();
679
3.63k
        index++;
680
3.63k
      }
681
3.62k
    }
682
10.0k
    else {
683
10.0k
      txSlot* at = fxNewInstance(the);
684
10.0k
      mxBehaviorOwnKeys(the, instance, XS_EACH_NAME_FLAG, at);
685
20.1k
      while ((at = at->next)) {
686
10.1k
        mxPushSlot(valueReference);
687
10.1k
        mxPushSlot(reviver);
688
10.1k
                mxCall();
689
10.1k
        mxPushUndefined();
690
10.1k
        fxKeyAt(the, at->value.at.id, at->value.at.index, the->stack);
691
10.1k
        mxPushSlot(valueReference);
692
10.1k
        mxGetAll(at->value.at.id, at->value.at.index);
693
10.1k
        if (mxIsReference(sourceReference)) {
694
16
          mxPushSlot(sourceReference);
695
16
          mxGetAll(at->value.at.id, at->value.at.index);
696
16
        }
697
10.1k
        else
698
10.1k
          mxPushUndefined();
699
10.1k
        fxReviveJSON(the, theParser, reviver);
700
10.1k
        if (mxIsUndefined(the->stack)) {
701
137
          mxBehaviorDeleteProperty(the, valueReference->value.reference, at->value.at.id, at->value.at.index);
702
137
        }
703
9.99k
        else {
704
9.99k
          mxBehaviorDefineOwnProperty(the, valueReference->value.reference, at->value.at.id, at->value.at.index, the->stack, XS_GET_ONLY);
705
9.99k
        }
706
10.1k
        mxPop();
707
10.1k
      }
708
10.0k
      mxPop();
709
10.0k
    }
710
13.6k
  }
711
14.2k
  if ((sourceReference->kind == XS_LIST_KIND) && fxIsSameValue(the, valueReference, sourceReference->value.list.last, 0)) {
712
474
    txSlot* view = sourceReference->value.list.first;
713
474
    txInteger offset = view->value.dataView.offset;
714
474
    txInteger size = view->value.dataView.size;
715
474
    txSlot* instance;
716
474
    txSlot* source;
717
474
    mxPop();
718
474
    mxPush(mxObjectPrototype);
719
474
    instance = fxNewObjectInstance(the);
720
474
    source = instance->next = fxNewSlot(the);
721
474
    source->value.string = fxNewChunk(the, size + 1);
722
474
    c_memcpy(source->value.string, theParser->slot->value.string + offset, size);
723
474
    source->value.string[size] = 0;
724
474
    source->kind = XS_STRING_KIND;
725
474
    source->ID = mxID(_source);
726
474
  }
727
13.7k
  else {
728
13.7k
    mxPop();
729
13.7k
    mxPush(mxObjectPrototype);
730
13.7k
    fxNewObjectInstance(the);
731
13.7k
  }
732
14.2k
  mxRunCount(3);
733
14.2k
}
734
735
void fx_JSON_rawJSON(txMachine* the)
736
82
{
737
82
  txSlot* slot;
738
82
  txString string;
739
82
  txSize length;
740
82
  txSlot* instance;
741
82
  txSlot* property;
742
82
  volatile txJSONParser aParser = {0};
743
82
  if (mxArgc > 0)
744
82
    mxPushSlot(mxArgv(0));
745
0
  else
746
0
    mxPushUndefined();
747
82
  slot = the->stack;
748
82
  string = fxToString(the, slot);
749
82
  length = (txSize)c_strlen(string);
750
82
  if (length == 0) 
751
3
    mxSyntaxError("empty string");
752
79
  else {
753
79
    char first = string[0];
754
79
    char last = string[length - 1];
755
79
    if ((first == 0x09) || (first == 0x0A) || (first == 0x0D) || (first == 0x20) || (last == 0x09) || (last == 0x0A) || (last == 0x0D) || (last == 0x20))
756
31
    mxSyntaxError("invalid string");
757
79
  }
758
48
  aParser.slot = slot;
759
48
  aParser.offset = 0;
760
48
  mxPush(mxEmptyString);
761
48
  aParser.string = the->stack;
762
48
  aParser.line = 1;
763
48
  fxParseJSON(the, (txJSONParser*)&aParser);
764
48
  if (mxIsReference(the->stack))
765
0
    mxSyntaxError("invalid string");
766
48
  mxPop();
767
48
  instance = fxNewInstance(the);
768
48
  instance->flag |= XS_EXOTIC_FLAG | XS_DONT_PATCH_FLAG;
769
48
  property = instance->next = fxNewSlot(the);
770
48
  property->flag = XS_INTERNAL_FLAG | XS_DONT_DELETE_FLAG | XS_DONT_SET_FLAG;
771
48
  property->kind = XS_RAW_JSON_KIND;
772
48
  property = property->next = fxNewSlot(the);
773
48
  property->ID = mxID(_rawJSON);
774
48
  property->flag = XS_DONT_DELETE_FLAG | XS_DONT_SET_FLAG;
775
48
  property->kind = slot->kind;
776
48
  property->value = slot->value;
777
48
  mxPullSlot(mxResult);
778
48
}
779
780
void fx_JSON_stringify(txMachine* the)
781
160k
{
782
160k
  volatile txJSONStringifier aStringifier = {0};
783
160k
  mxTry(the) {
784
160k
    fxStringifyJSON(the, (txJSONStringifier*)&aStringifier);
785
160k
    if (aStringifier.offset) {
786
157k
      fxStringifyJSONChars(the, (txJSONStringifier*)&aStringifier, "\0", 1);
787
157k
      mxResult->value.string = (txString)fxNewChunk(the, aStringifier.offset);
788
157k
      c_memcpy(mxResult->value.string, aStringifier.buffer, aStringifier.offset);
789
157k
      mxResult->kind = XS_STRING_KIND;
790
157k
    }
791
160k
    c_free(aStringifier.buffer);
792
160k
  }
793
160k
  mxCatch(the) {
794
18
    if (aStringifier.buffer)
795
18
      c_free(aStringifier.buffer);
796
18
    fxJump(the);
797
18
  }
798
160k
}
799
800
void fxStringifyJSON(txMachine* the, txJSONStringifier* theStringifier)
801
160k
{
802
160k
  txSlot* aSlot;
803
160k
  txInteger aFlag;
804
160k
  txSlot* instance;
805
  
806
160k
  aSlot = fxGetInstance(the, mxThis);
807
160k
  theStringifier->offset = 0;
808
160k
  theStringifier->size = 1024;
809
160k
  theStringifier->buffer = c_malloc(1024);
810
160k
  if (!theStringifier->buffer)
811
0
    fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
812
813
160k
  if (mxArgc > 1) {
814
2.84k
    aSlot = mxArgv(1);
815
2.84k
    if (mxIsReference(aSlot)) {
816
2.74k
      if (fxIsCallable(the, aSlot))
817
2.67k
        theStringifier->replacer = mxArgv(1);
818
74
      else if (fxIsArray(the, fxGetInstance(the, aSlot)))
819
68
        theStringifier->keys = fxToJSONKeys(the, aSlot);
820
2.74k
    }
821
2.84k
  }
822
160k
  if (mxArgc > 2) {
823
89
    aSlot = mxArgv(2);
824
89
    if (mxIsReference(aSlot)) {
825
22
      txSlot* instance = fxGetInstance(the, aSlot);
826
22
      if (mxIsNumber(instance)) {
827
6
        fxToNumber(the, aSlot);
828
6
      }
829
16
      else if (mxIsString(instance)) {
830
8
        fxToString(the, aSlot);
831
8
      }
832
22
    }
833
89
    if ((aSlot->kind == XS_INTEGER_KIND) || (aSlot->kind == XS_NUMBER_KIND)) {
834
29
      txInteger aCount = fxToInteger(the, aSlot), anIndex;
835
29
      if (aCount < 0)
836
5
        aCount = 0;
837
24
      else if (aCount > 10)
838
2
        aCount = 10;
839
127
      for (anIndex = 0; anIndex < aCount; anIndex++)
840
98
        theStringifier->indent[anIndex] = ' ';
841
29
      theStringifier->indentLength = aCount;
842
29
    }
843
60
    else if (mxIsStringPrimitive(aSlot)) {
844
34
      txInteger aCount = fxUnicodeLength(aSlot->value.string, C_NULL);
845
34
      if (aCount > 10) {
846
8
        aCount = fxUnicodeToUTF8Offset(aSlot->value.string, 10);
847
8
      }
848
26
      else {
849
26
        aCount = (txInteger)c_strlen(aSlot->value.string);
850
26
      }
851
34
      c_memcpy(theStringifier->indent, aSlot->value.string, aCount);
852
34
      theStringifier->indent[aCount] = 0;
853
34
      theStringifier->indentLength = aCount;
854
34
    }
855
89
  }
856
857
160k
  theStringifier->stack = the->stack;
858
160k
  mxPush(mxObjectPrototype);
859
160k
  instance = fxNewObjectInstance(the);
860
160k
  aFlag = 0;
861
160k
  if (mxArgc > 0)
862
160k
    mxPushSlot(mxArgv(0));
863
14
  else
864
14
    mxPushUndefined();
865
160k
  fxNextSlotProperty(the, instance, the->stack, mxID(__empty_string_), XS_NO_FLAG);
866
160k
  mxPush(mxEmptyString);
867
160k
  fxStringifyJSONProperty(the, theStringifier, &aFlag);
868
160k
  mxPop();
869
160k
}
870
871
void fxStringifyJSONCharacter(txMachine* the, txJSONStringifier* theStringifier, txInteger character)
872
22.5M
{
873
22.5M
    txSize size = mxStringByteLength(character);
874
22.5M
  if ((theStringifier->offset + size) >= theStringifier->size) {
875
51.3k
    char* aBuffer;
876
51.3k
    theStringifier->size += ((size / 1024) + 1) * 1024;
877
51.3k
    aBuffer = c_realloc(theStringifier->buffer, theStringifier->size);
878
51.3k
    if (!aBuffer)
879
0
      fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
880
51.3k
    theStringifier->buffer = aBuffer;
881
51.3k
  }
882
22.5M
  mxStringByteEncode(theStringifier->buffer + theStringifier->offset, character);
883
22.5M
  theStringifier->offset += size;
884
22.5M
}
885
886
void fxStringifyJSONChars(txMachine* the, txJSONStringifier* theStringifier, char* s, txSize theSize)
887
184M
{
888
    //fprintf(stderr, "%s", s);
889
184M
  if ((theStringifier->offset + theSize) >= theStringifier->size) {
890
198k
    char* aBuffer;
891
198k
    theStringifier->size += ((theSize / 1024) + 1) * 1024;
892
198k
    aBuffer = c_realloc(theStringifier->buffer, theStringifier->size);
893
198k
    if (!aBuffer)
894
0
      fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
895
198k
    theStringifier->buffer = aBuffer;
896
198k
  }
897
184M
  c_memcpy(theStringifier->buffer + theStringifier->offset, s, theSize);
898
184M
  theStringifier->offset += theSize;
899
184M
}
900
901
void fxStringifyJSONIndent(txMachine* the, txJSONStringifier* theStringifier)
902
25.8M
{
903
25.8M
  txInteger aLevel;
904
25.8M
  if (theStringifier->indent[0]) {
905
661
    fxStringifyJSONChars(the, theStringifier, "\n", 1);
906
2.09k
    for (aLevel = 0; aLevel < theStringifier->level; aLevel++)
907
1.43k
      fxStringifyJSONChars(the, theStringifier, theStringifier->indent, theStringifier->indentLength);
908
661
  }
909
25.8M
}
910
911
void fxStringifyJSONInteger(txMachine* the, txJSONStringifier* theStringifier, txInteger theInteger)
912
25.4M
{
913
25.4M
  char aBuffer[256];
914
25.4M
  fxIntegerToString(the, theInteger, aBuffer, sizeof(aBuffer));
915
25.4M
  fxStringifyJSONChars(the, theStringifier, aBuffer, (txSize)c_strlen(aBuffer));
916
25.4M
}
917
918
void fxStringifyJSONName(txMachine* the, txJSONStringifier* theStringifier, txInteger* theFlag)
919
25.8M
{
920
25.8M
  txSlot* aSlot = the->stack;
921
25.8M
  if (*theFlag & 1) {
922
25.4M
    fxStringifyJSONChars(the, theStringifier, ",", 1);
923
25.4M
    fxStringifyJSONIndent(the, theStringifier);
924
25.4M
  }
925
362k
  else
926
362k
    *theFlag |= 1;
927
25.8M
  if (*theFlag & 2) {
928
25.6M
    if (aSlot->kind == XS_INTEGER_KIND) {
929
25.4M
      fxStringifyJSONChars(the, theStringifier, "\"", 1);
930
25.4M
      fxStringifyJSONInteger(the, theStringifier, aSlot->value.integer);
931
25.4M
      fxStringifyJSONChars(the, theStringifier, "\"", 1);
932
25.4M
    }
933
206k
    else
934
206k
      fxStringifyJSONString(the, theStringifier, aSlot->value.string);
935
25.6M
    fxStringifyJSONChars(the, theStringifier, ":", 1);
936
25.6M
    if (theStringifier->indent[0])
937
245
      fxStringifyJSONChars(the, theStringifier, " ", 1);
938
25.6M
  }
939
25.8M
  mxPop(); // POP KEY
940
25.8M
}
941
942
void fxStringifyJSONNumber(txMachine* the, txJSONStringifier* theStringifier, txNumber theNumber)
943
67.2k
{
944
67.2k
  int fpclass = c_fpclassify(theNumber);
945
67.2k
  if ((fpclass != C_FP_NAN) && (fpclass != C_FP_INFINITE)) {
946
19.0k
    char aBuffer[256];
947
19.0k
    fxNumberToString(the, theNumber, aBuffer, sizeof(aBuffer), 0, 0);
948
19.0k
    fxStringifyJSONChars(the, theStringifier, aBuffer, (txSize)c_strlen(aBuffer));
949
19.0k
  }
950
48.2k
  else
951
48.2k
    fxStringifyJSONChars(the, theStringifier, "null", 4);
952
67.2k
}
953
954
void fxStringifyJSONProperty(txMachine* the, txJSONStringifier* theStringifier, txInteger* theFlag)
955
25.9M
{
956
25.9M
  txSlot* aWrapper = the->stack + 2;
957
25.9M
  txSlot* aValue = the->stack + 1;
958
25.9M
  txSlot* aKey = the->stack;
959
25.9M
  txSlot* anInstance;
960
25.9M
  txSlot* aSlot;
961
25.9M
  txInteger aFlag;
962
25.9M
  txIndex aLength, anIndex;
963
  
964
25.9M
  mxCheckCStack();
965
25.9M
  if (mxIsReference(aValue) || mxIsBigInt(aValue)) {
966
    /* THIS */
967
171k
    mxPushSlot(aValue);
968
    /* FUNCTION */
969
171k
    mxDub();
970
171k
    mxGetID(mxID(_toJSON));
971
171k
    if (mxIsReference(the->stack) && mxIsFunction(the->stack->value.reference))  {
972
2.43k
      mxCall();
973
2.43k
      mxPushSlot(aKey);
974
2.43k
      fxToString(the, the->stack);
975
2.43k
      mxRunCount(1);
976
2.43k
      mxPullSlot(aValue);
977
2.43k
    }
978
171k
    the->stack = aKey;
979
171k
  }
980
25.9M
  if (theStringifier->replacer) {
981
    /* THIS */
982
48.7k
    mxPushSlot(aWrapper);
983
    /* FUNCTION */
984
48.7k
    mxPushSlot(theStringifier->replacer);
985
48.7k
    mxCall();
986
    /* ARGUMENTS */
987
48.7k
    mxPushSlot(aKey);
988
48.7k
    fxToString(the, the->stack);
989
48.7k
    mxPushSlot(aValue);
990
    /* COUNT */
991
48.7k
    mxRunCount(2);
992
48.7k
    mxPullSlot(aValue);
993
48.7k
    the->stack = aKey;
994
48.7k
  }
995
25.9M
  if (mxIsReference(aValue)) {
996
215k
    mxPushSlot(aValue);
997
215k
    anInstance = fxToInstance(the, the->stack);
998
215k
    if (anInstance->flag & XS_LEVEL_FLAG)
999
8
      mxTypeError("cyclic value");
1000
214k
    the->stack = aKey;
1001
214k
    aSlot = anInstance->next;
1002
214k
    if (aSlot && (aSlot->flag & XS_INTERNAL_FLAG)) {
1003
133k
      if ((aSlot->kind == XS_INTEGER_KIND) || (aSlot->kind == XS_NUMBER_KIND)) {
1004
3
        fxToNumber(the, aValue);
1005
3
      }
1006
133k
      else if (mxIsStringPrimitive(aSlot)) {
1007
3
        fxToString(the, aValue);
1008
3
      }
1009
133k
      else if ((aSlot->kind == XS_BOOLEAN_KIND) || (aSlot->kind == XS_BIGINT_KIND) || (aSlot->kind == XS_BIGINT_X_KIND)) {
1010
8
        aValue->kind = aSlot->kind;
1011
8
        aValue->value = aSlot->value;
1012
8
      }
1013
133k
      else if (aSlot->kind == XS_RAW_JSON_KIND) {
1014
24
        mxPushSlot(aValue);
1015
24
        mxGetID(mxID(_rawJSON));
1016
24
        aValue->kind = the->stack->kind;
1017
24
        aValue->value = the->stack->value;
1018
24
        the->stack = aKey;
1019
24
        fxStringifyJSONName(the, theStringifier, theFlag);
1020
24
        fxStringifyJSONChars(the, theStringifier, aValue->value.string, (txSize)c_strlen(aValue->value.string));
1021
24
        mxPop(); // POP VALUE
1022
24
        return;
1023
24
      }
1024
133k
    }
1025
214k
  }
1026
25.9M
  if (aValue->kind == XS_NULL_KIND) {
1027
1.17k
    fxStringifyJSONName(the, theStringifier, theFlag);
1028
1.17k
    fxStringifyJSONChars(the, theStringifier, "null", 4);
1029
1.17k
  }
1030
25.9M
  else if (aValue->kind == XS_BOOLEAN_KIND) {
1031
88.0k
    fxStringifyJSONName(the, theStringifier, theFlag);
1032
88.0k
    if (aValue->value.boolean)
1033
175
      fxStringifyJSONChars(the, theStringifier, "true", 4);
1034
87.8k
    else
1035
87.8k
      fxStringifyJSONChars(the, theStringifier, "false", 5);
1036
88.0k
  }
1037
25.8M
  else if (aValue->kind == XS_INTEGER_KIND) {
1038
745
    fxStringifyJSONName(the, theStringifier, theFlag);
1039
745
    fxStringifyJSONInteger(the, theStringifier, aValue->value.integer);
1040
745
  }
1041
25.8M
  else if (aValue->kind == XS_NUMBER_KIND) {
1042
67.2k
    fxStringifyJSONName(the, theStringifier, theFlag);
1043
67.2k
    fxStringifyJSONNumber(the, theStringifier, aValue->value.number);
1044
67.2k
  }
1045
25.7M
  else if ((aValue->kind == XS_STRING_KIND) || (aValue->kind == XS_STRING_X_KIND)) {
1046
25.4M
    fxStringifyJSONName(the, theStringifier, theFlag);
1047
25.4M
    fxStringifyJSONString(the, theStringifier, aValue->value.string);
1048
25.4M
  }
1049
297k
  else if ((aValue->kind == XS_BIGINT_KIND) || (aValue->kind == XS_BIGINT_X_KIND)) {
1050
8
    mxTypeError("stringify bigint");
1051
8
  }
1052
297k
  else if ((aValue->kind == XS_REFERENCE_KIND) && !fxIsCallable(the, aValue)) {
1053
205k
    mxTry(the) {
1054
205k
      fxStringifyJSONName(the, theStringifier, theFlag);
1055
205k
      if (anInstance->flag & XS_MARK_FLAG)
1056
0
        mxTypeError("read only value");
1057
205k
      anInstance->flag |= XS_LEVEL_FLAG;
1058
205k
      if (fxIsArray(the, anInstance)) {
1059
47.3k
        fxStringifyJSONChars(the, theStringifier, "[", 1);
1060
47.3k
        mxPushReference(anInstance);
1061
47.3k
        mxGetID(mxID(_length));
1062
47.3k
        aLength = fxToInteger(the, the->stack);
1063
47.3k
        if (aLength > 0) {
1064
46.5k
          theStringifier->level++;
1065
46.5k
          fxStringifyJSONIndent(the, theStringifier);
1066
46.5k
          aFlag = 4;
1067
46.5k
          mxPop();
1068
94.0k
          for (anIndex = 0; anIndex < aLength; anIndex++) {
1069
47.4k
            mxPushReference(anInstance);
1070
47.4k
            mxGetIndex(anIndex);
1071
47.4k
            mxPushInteger(anIndex);
1072
47.4k
            fxStringifyJSONProperty(the, theStringifier, &aFlag);
1073
47.4k
          }
1074
46.5k
          theStringifier->level--;
1075
46.5k
          fxStringifyJSONIndent(the, theStringifier);
1076
46.5k
        }
1077
47.3k
        fxStringifyJSONChars(the, theStringifier, "]", 1);
1078
47.3k
      }
1079
157k
      else {
1080
157k
        fxStringifyJSONChars(the, theStringifier, "{", 1);
1081
157k
        {
1082
157k
          txSlot* at;
1083
157k
          txSlot* property;
1084
157k
          if (theStringifier->keys) {
1085
70
            mxPushUndefined();
1086
70
            at = theStringifier->keys->value.reference;
1087
70
          }
1088
157k
          else {
1089
157k
            at = fxNewInstance(the);
1090
157k
            mxBehaviorOwnKeys(the, anInstance, XS_EACH_NAME_FLAG, at);
1091
157k
          }
1092
157k
          if (at->next) {
1093
157k
            theStringifier->level++;
1094
157k
            fxStringifyJSONIndent(the, theStringifier);
1095
157k
            aFlag = 2;
1096
157k
            mxPushUndefined();
1097
157k
            property = the->stack;
1098
157k
            mxPushReference(anInstance);
1099
25.8M
            while ((at = at->next)) {
1100
25.7M
              if (mxBehaviorGetOwnProperty(the, anInstance, at->value.at.id, at->value.at.index, property) && !(property->flag & XS_DONT_ENUM_FLAG)) {
1101
25.7M
                mxPushReference(anInstance);
1102
25.7M
                mxGetAll(at->value.at.id, at->value.at.index);
1103
25.7M
                if (at->value.at.id)
1104
294k
                  fxPushKeyString(the, at->value.at.id, C_NULL);
1105
25.4M
                else
1106
25.4M
                  mxPushInteger((txInteger)at->value.at.index);
1107
25.7M
                fxStringifyJSONProperty(the, theStringifier, &aFlag);
1108
25.7M
              }
1109
25.7M
            }
1110
157k
            mxPop();
1111
157k
            mxPop();
1112
157k
            theStringifier->level--;
1113
157k
            fxStringifyJSONIndent(the, theStringifier);
1114
157k
          }
1115
157k
          mxPop();
1116
157k
        }
1117
157k
        fxStringifyJSONChars(the, theStringifier, "}", 1);
1118
157k
      }
1119
205k
      anInstance->flag &= ~XS_LEVEL_FLAG;
1120
205k
    }
1121
205k
    mxCatch(the) {
1122
20
      if (anInstance->flag & XS_LEVEL_FLAG)
1123
20
        anInstance->flag &= ~XS_LEVEL_FLAG;
1124
20
      fxJump(the);
1125
20
    }
1126
205k
  }
1127
91.8k
  else {
1128
91.8k
    if (*theFlag & 4) {
1129
484
      if (*theFlag & 1) {
1130
244
        fxStringifyJSONChars(the, theStringifier, ",", 1);
1131
244
        fxStringifyJSONIndent(the, theStringifier);
1132
244
      }
1133
240
      else
1134
240
        *theFlag |= 1;
1135
484
      fxStringifyJSONChars(the, theStringifier, "null", 4);
1136
484
    }
1137
91.8k
  }
1138
25.9M
  mxPop(); // POP VALUE
1139
25.9M
}
1140
1141
void fxStringifyJSONString(txMachine* the, txJSONStringifier* theStringifier, txString theString)
1142
25.6M
{
1143
25.6M
  fxStringifyJSONChars(the, theStringifier, "\"", 1);
1144
53.0M
  for (;;) {
1145
53.0M
    txInteger character;  
1146
53.0M
    theString = mxStringByteDecode(theString, &character);
1147
53.0M
    if (character == C_EOF)
1148
25.6M
      break;
1149
27.3M
    if (character < 8)
1150
2.33M
      fxStringifyJSONUnicodeEscape(the, theStringifier, character);
1151
24.9M
    else if (character == 8)
1152
22.4k
      fxStringifyJSONChars(the, theStringifier, "\\b", 2); 
1153
24.9M
    else if (character == 9)
1154
3.58k
      fxStringifyJSONChars(the, theStringifier, "\\t", 2); 
1155
24.9M
    else if (character == 10)
1156
22.6k
      fxStringifyJSONChars(the, theStringifier, "\\n", 2); 
1157
24.9M
    else if (character == 11)
1158
41.3k
      fxStringifyJSONUnicodeEscape(the, theStringifier, character); 
1159
24.8M
    else if (character == 12)
1160
115k
      fxStringifyJSONChars(the, theStringifier, "\\f", 2);
1161
24.7M
    else if (character == 13)
1162
818
      fxStringifyJSONChars(the, theStringifier, "\\r", 2);
1163
24.7M
    else if (character < 32)
1164
488k
      fxStringifyJSONUnicodeEscape(the, theStringifier, character);
1165
24.2M
    else if (character < 34)
1166
233k
      fxStringifyJSONCharacter(the, theStringifier, character);
1167
24.0M
    else if (character == 34)
1168
495k
      fxStringifyJSONChars(the, theStringifier, "\\\"", 2);
1169
23.5M
    else if (character < 92)
1170
3.29M
      fxStringifyJSONCharacter(the, theStringifier, character);
1171
20.2M
    else if (character == 92)
1172
781k
      fxStringifyJSONChars(the, theStringifier, "\\\\", 2);
1173
19.4M
    else if (character < 127)
1174
4.28M
      fxStringifyJSONCharacter(the, theStringifier, character);
1175
15.1M
    else if ((0xD800 <= character) && (character <= 0xDFFF))
1176
457k
      fxStringifyJSONUnicodeEscape(the, theStringifier, character);
1177
14.7M
    else
1178
14.7M
      fxStringifyJSONCharacter(the, theStringifier, character);
1179
27.3M
  }
1180
25.6M
  fxStringifyJSONChars(the, theStringifier, "\"", 1);
1181
25.6M
}
1182
1183
void fxStringifyJSONUnicodeEscape(txMachine* the, txJSONStringifier* theStringifier, txInteger character)
1184
3.32M
{
1185
3.32M
  char buffer[16];
1186
3.32M
  txString p = buffer;
1187
3.32M
  *p++ = '\\'; 
1188
3.32M
  *p++ = 'u'; 
1189
3.32M
  p = fxStringifyUnicodeEscape(p, character, '\\');
1190
3.32M
  fxStringifyJSONChars(the, theStringifier, buffer, mxPtrDiff(p - buffer));
1191
3.32M
}
1192
1193
txSlot* fxToJSONKeys(txMachine* the, txSlot* reference)
1194
81
{
1195
81
  txSlot* list = fxNewInstance(the);
1196
81
  txSlot* item = list;
1197
81
  txSlot* slot;
1198
81
  txIndex length, i;
1199
81
  mxPushSlot(reference);
1200
81
  mxGetID(mxID(_length));
1201
81
  length = (txIndex)fxToLength(the, the->stack);
1202
81
  mxPop();
1203
81
  i = 0;
1204
308
  while (i < length) {
1205
227
    txBoolean flag = 0;
1206
227
    txID id = XS_NO_ID;
1207
227
    txIndex index = 0;
1208
227
    mxPushSlot(reference);
1209
227
    mxGetIndex(i);
1210
227
    slot = the->stack;
1211
278
  again:
1212
278
    if ((slot->kind == XS_STRING_KIND) || (slot->kind == XS_STRING_X_KIND)) {
1213
113
      if (fxStringToIndex(the, slot->value.string, &index))
1214
7
        flag = 1;
1215
106
      else {
1216
106
        if (slot->kind == XS_STRING_X_KIND)
1217
0
          id = fxNewNameX(the, slot->value.string);
1218
106
        else
1219
106
          id = fxNewName(the, slot);
1220
106
        flag = 1;
1221
106
      }
1222
113
    }
1223
165
    else if (slot->kind == XS_INTEGER_KIND) {
1224
72
      if (fxIntegerToIndex(the, slot->value.integer, &index))
1225
53
        flag = 1;
1226
19
      else {
1227
19
        fxToString(the, slot);
1228
19
        goto again;
1229
19
      }
1230
72
    }
1231
93
    else if (slot->kind == XS_NUMBER_KIND){
1232
34
      if (fxNumberToIndex(the, slot->value.number, &index))
1233
4
        flag = 1;
1234
30
      else {
1235
30
        fxToString(the, slot);
1236
30
        goto again;
1237
30
      }
1238
34
    }
1239
59
    else if (slot->kind == XS_REFERENCE_KIND) {
1240
4
      txSlot* instance = slot->value.reference;
1241
4
      if (mxIsNumber(instance) || mxIsString(instance)) {
1242
2
        fxToString(the, slot);
1243
2
        goto again;
1244
2
      }
1245
4
    }
1246
227
    if (flag) {
1247
170
      txSlot* already = list->next;
1248
479
      while (already) {
1249
329
        if ((already->value.at.id == id) && (already->value.at.index == index))
1250
20
          break;
1251
309
        already = already->next;
1252
309
      }
1253
170
      if (!already) {
1254
150
        item = item->next = fxNewSlot(the);
1255
150
        item->value.at.id = id;
1256
150
        item->value.at.index = index;
1257
150
        item->kind = XS_AT_KIND;
1258
150
      }
1259
170
    }
1260
227
    mxPop();
1261
227
    i++;
1262
227
  }
1263
81
  return the->stack;
1264
81
}