Coverage Report

Created: 2026-01-09 07:26

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-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
}