jseption 0.0.0-stage → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +26 -0
- package/README.md +191 -2
- package/dist/atoms.d.ts +255 -0
- package/dist/atoms.js +445 -0
- package/dist/atoms.js.map +1 -0
- package/dist/builtins/array.d.ts +3 -0
- package/dist/builtins/array.js +116 -0
- package/dist/builtins/array.js.map +1 -0
- package/dist/builtins/bigint.d.ts +3 -0
- package/dist/builtins/bigint.js +122 -0
- package/dist/builtins/bigint.js.map +1 -0
- package/dist/builtins/boolean.d.ts +2 -0
- package/dist/builtins/boolean.js +26 -0
- package/dist/builtins/boolean.js.map +1 -0
- package/dist/builtins/date.d.ts +3 -0
- package/dist/builtins/date.js +1046 -0
- package/dist/builtins/date.js.map +1 -0
- package/dist/builtins/error.d.ts +2 -0
- package/dist/builtins/error.js +154 -0
- package/dist/builtins/error.js.map +1 -0
- package/dist/builtins/function.d.ts +5 -0
- package/dist/builtins/function.js +164 -0
- package/dist/builtins/function.js.map +1 -0
- package/dist/builtins/global.d.ts +2 -0
- package/dist/builtins/global.js +29 -0
- package/dist/builtins/global.js.map +1 -0
- package/dist/builtins/index.d.ts +3 -0
- package/dist/builtins/index.js +139 -0
- package/dist/builtins/index.js.map +1 -0
- package/dist/builtins/json.d.ts +6 -0
- package/dist/builtins/json.js +984 -0
- package/dist/builtins/json.js.map +1 -0
- package/dist/builtins/mapset.d.ts +4 -0
- package/dist/builtins/mapset.js +234 -0
- package/dist/builtins/mapset.js.map +1 -0
- package/dist/builtins/math.d.ts +2 -0
- package/dist/builtins/math.js +62 -0
- package/dist/builtins/math.js.map +1 -0
- package/dist/builtins/native.d.ts +22 -0
- package/dist/builtins/native.js +250 -0
- package/dist/builtins/native.js.map +1 -0
- package/dist/builtins/number.d.ts +4 -0
- package/dist/builtins/number.js +76 -0
- package/dist/builtins/number.js.map +1 -0
- package/dist/builtins/object.d.ts +12 -0
- package/dist/builtins/object.js +575 -0
- package/dist/builtins/object.js.map +1 -0
- package/dist/builtins/promise.d.ts +13 -0
- package/dist/builtins/promise.js +582 -0
- package/dist/builtins/promise.js.map +1 -0
- package/dist/builtins/proxy.d.ts +3 -0
- package/dist/builtins/proxy.js +226 -0
- package/dist/builtins/proxy.js.map +1 -0
- package/dist/builtins/reflect.d.ts +2 -0
- package/dist/builtins/reflect.js +109 -0
- package/dist/builtins/reflect.js.map +1 -0
- package/dist/builtins/regexp.d.ts +2 -0
- package/dist/builtins/regexp.js +203 -0
- package/dist/builtins/regexp.js.map +1 -0
- package/dist/builtins/string.d.ts +4 -0
- package/dist/builtins/string.js +135 -0
- package/dist/builtins/string.js.map +1 -0
- package/dist/builtins/symbol.d.ts +3 -0
- package/dist/builtins/symbol.js +98 -0
- package/dist/builtins/symbol.js.map +1 -0
- package/dist/builtins/typedarray.d.ts +15 -0
- package/dist/builtins/typedarray.js +1838 -0
- package/dist/builtins/typedarray.js.map +1 -0
- package/dist/builtins/weakref.d.ts +18 -0
- package/dist/builtins/weakref.js +130 -0
- package/dist/builtins/weakref.js.map +1 -0
- package/dist/dump.d.ts +2 -0
- package/dist/dump.js +124 -0
- package/dist/dump.js.map +1 -0
- package/dist/embed.d.ts +18 -0
- package/dist/embed.js +286 -0
- package/dist/embed.js.map +1 -0
- package/dist/interpreter.d.ts +81 -0
- package/dist/interpreter.js +3768 -0
- package/dist/interpreter.js.map +1 -0
- package/dist/jit.d.ts +59 -0
- package/dist/jit.js +3440 -0
- package/dist/jit.js.map +1 -0
- package/dist/jit_hook.d.ts +21 -0
- package/dist/jit_hook.js +4 -0
- package/dist/jit_hook.js.map +1 -0
- package/dist/jit_runtime.d.ts +104 -0
- package/dist/jit_runtime.js +721 -0
- package/dist/jit_runtime.js.map +1 -0
- package/dist/jit_stack.d.ts +24 -0
- package/dist/jit_stack.js +227 -0
- package/dist/jit_stack.js.map +1 -0
- package/dist/jseption.d.ts +15 -0
- package/dist/jseption.js +61 -0
- package/dist/jseption.js.map +1 -0
- package/dist/opcodes.d.ts +347 -0
- package/dist/opcodes.js +322 -0
- package/dist/opcodes.js.map +1 -0
- package/dist/parser.d.ts +283 -0
- package/dist/parser.js +9752 -0
- package/dist/parser.js.map +1 -0
- package/dist/qjs.d.ts +2 -0
- package/dist/qjs.js +122 -0
- package/dist/qjs.js.map +1 -0
- package/dist/quickjs.d.ts +460 -0
- package/dist/quickjs.js +3408 -0
- package/dist/quickjs.js.map +1 -0
- package/dist/std.d.ts +4 -0
- package/dist/std.js +273 -0
- package/dist/std.js.map +1 -0
- package/dist/values.d.ts +447 -0
- package/dist/values.js +461 -0
- package/dist/values.js.map +1 -0
- package/package.json +59 -4
|
@@ -0,0 +1,984 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* JSON object (port of the JSON part of quickjs.c: json_next_token,
|
|
3
|
+
* json_parse_value, JS_ParseJSON, internalize_json_property,
|
|
4
|
+
* js_json_check, js_json_to_str, JS_JSONStringify)
|
|
5
|
+
*/
|
|
6
|
+
import * as Q from "../quickjs.js";
|
|
7
|
+
import { JS_EXCEPTION, JS_IsException, JS_IsUndefined, JS_IsObject, JS_IsFunction, JS_IsArray, JS_NewObject, JS_NewArray, JS_NewErrorNative, JS_Throw, JS_ThrowTypeError, JS_ThrowStackOverflow, JS_DefinePropertyValue, JS_DefinePropertyValueUint32, JS_GetProperty, JS_GetPropertyInt64, JS_GetPropertyValue, JS_DeleteProperty, JS_GetOwnPropertyNamesInternal, JS_PROP_C_W_E, JS_PROP_WRITABLE, JS_PROP_CONFIGURABLE, JS_GPN_STRING_MASK, JS_GPN_ENUM_ONLY, JS_ATOM_NULL, JS_ATOM_empty_string, JS_ATOM_toJSON, JS_ATOM_fileName, JS_ATOM_lineNumber, JS_ATOM_columnNumber, JS_ATOM_Symbol_toStringTag, JS_ATOM_true, JS_ATOM_false, JS_ATOM_null, JS_ValueToAtom, JS_NewAtomUInt32, JS_AtomToValue, JS_Call, JS_ToString, JS_ToNumber, JS_ToInt32Clamp, JS_ToQuotedString, js_get_length64, build_backtrace, JS_SetPropertyFunctionList, JS_CFUNC_DEF, JS_PROP_STRING_DEF, JS_OBJECT_DEF, JS_NewAtom, } from "../quickjs.js";
|
|
8
|
+
import { fix_deep_json } from "./native.js";
|
|
9
|
+
/* ---------------------------------------------------------------------
|
|
10
|
+
JSON parser (port of json_next_token / json_parse_value)
|
|
11
|
+
--------------------------------------------------------------------- */
|
|
12
|
+
export const JS_PARSE_JSON_EXT = 1 << 0; /* allow extended JSON (comments, trailing commas, ...) */
|
|
13
|
+
class JSONParseState {
|
|
14
|
+
ctx;
|
|
15
|
+
buf;
|
|
16
|
+
buf_end;
|
|
17
|
+
buf_ptr = 0;
|
|
18
|
+
last_ptr = 0;
|
|
19
|
+
filename;
|
|
20
|
+
ext_json = false;
|
|
21
|
+
/* current token */
|
|
22
|
+
tok = -1 /* JSONTok.EOF */;
|
|
23
|
+
tok_ptr = 0; /* start position of the token */
|
|
24
|
+
tok_str = ''; /* TOK_STRING value */
|
|
25
|
+
tok_num = 0; /* TOK_NUMBER value */
|
|
26
|
+
tok_atom = JS_ATOM_NULL; /* TOK_IDENT atom */
|
|
27
|
+
constructor(ctx, buf, filename) {
|
|
28
|
+
this.ctx = ctx;
|
|
29
|
+
this.buf = buf;
|
|
30
|
+
this.buf_end = buf.length;
|
|
31
|
+
this.filename = filename;
|
|
32
|
+
}
|
|
33
|
+
/* character code at position p, 0 past the end (like the NUL terminated C buffer) */
|
|
34
|
+
at(p) {
|
|
35
|
+
return p < this.buf_end ? this.buf.charCodeAt(p) : 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const CP_LS = 0x2028;
|
|
39
|
+
const CP_PS = 0x2029;
|
|
40
|
+
function get_line_col(buf, pos) {
|
|
41
|
+
let line = 1, col = 1;
|
|
42
|
+
const n = Math.min(pos, buf.length);
|
|
43
|
+
for (let i = 0; i < n; i++) {
|
|
44
|
+
const c = buf.charCodeAt(i);
|
|
45
|
+
if (c === 10) {
|
|
46
|
+
line++;
|
|
47
|
+
col = 1;
|
|
48
|
+
}
|
|
49
|
+
else if (c === 13) {
|
|
50
|
+
if (buf.charCodeAt(i + 1) !== 10) {
|
|
51
|
+
line++;
|
|
52
|
+
col = 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (c === CP_LS || c === CP_PS) {
|
|
56
|
+
line++;
|
|
57
|
+
col = 1;
|
|
58
|
+
}
|
|
59
|
+
else
|
|
60
|
+
col++;
|
|
61
|
+
}
|
|
62
|
+
return [line, col];
|
|
63
|
+
}
|
|
64
|
+
/* port of js_parse_error_pos / js_parse_error_v: throw a SyntaxError
|
|
65
|
+
with the position of 'pos' in the input */
|
|
66
|
+
function json_parse_error_pos(s, pos, msg) {
|
|
67
|
+
const ctx = s.ctx;
|
|
68
|
+
const [line, col] = get_line_col(s.buf, pos);
|
|
69
|
+
const obj = JS_NewErrorNative(ctx, 3 /* JSErrorEnum.SYNTAX_ERROR */, msg);
|
|
70
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_fileName, s.filename, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
71
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_lineNumber, line, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
72
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_columnNumber, col, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
73
|
+
build_backtrace(ctx, obj, s.filename, line, col, 0);
|
|
74
|
+
JS_Throw(ctx, obj);
|
|
75
|
+
return -1;
|
|
76
|
+
}
|
|
77
|
+
function json_parse_error(s, msg) {
|
|
78
|
+
return json_parse_error_pos(s, s.tok_ptr, msg);
|
|
79
|
+
}
|
|
80
|
+
function is_digit(c) { return c >= 48 && c <= 57; }
|
|
81
|
+
function from_hex(c) {
|
|
82
|
+
if (c >= 48 && c <= 57)
|
|
83
|
+
return c - 48;
|
|
84
|
+
if (c >= 65 && c <= 70)
|
|
85
|
+
return c - 55;
|
|
86
|
+
if (c >= 97 && c <= 102)
|
|
87
|
+
return c - 87;
|
|
88
|
+
return -1;
|
|
89
|
+
}
|
|
90
|
+
/* ASCII identifier start / continue (lre_is_id_start / lre_is_id_continue restricted to ASCII) */
|
|
91
|
+
function is_ident_start_ascii(c) {
|
|
92
|
+
return (c >= 97 && c <= 122) || (c >= 65 && c <= 90) || c === 95 /* _ */ || c === 36 /* $ */;
|
|
93
|
+
}
|
|
94
|
+
function is_ident_continue_ascii(c) {
|
|
95
|
+
return is_ident_start_ascii(c) || is_digit(c);
|
|
96
|
+
}
|
|
97
|
+
/* port of lre_parse_escape(&p, TRUE): returns the code point, -1 if
|
|
98
|
+
malformed, -2 if unknown escape; pp.p is updated */
|
|
99
|
+
function lre_parse_escape(s, pp) {
|
|
100
|
+
let p = pp.p;
|
|
101
|
+
let c = s.at(p++);
|
|
102
|
+
switch (c) {
|
|
103
|
+
case 98:
|
|
104
|
+
c = 8;
|
|
105
|
+
break; /* \b */
|
|
106
|
+
case 102:
|
|
107
|
+
c = 12;
|
|
108
|
+
break; /* \f */
|
|
109
|
+
case 110:
|
|
110
|
+
c = 10;
|
|
111
|
+
break; /* \n */
|
|
112
|
+
case 114:
|
|
113
|
+
c = 13;
|
|
114
|
+
break; /* \r */
|
|
115
|
+
case 116:
|
|
116
|
+
c = 9;
|
|
117
|
+
break; /* \t */
|
|
118
|
+
case 118:
|
|
119
|
+
c = 11;
|
|
120
|
+
break; /* \v */
|
|
121
|
+
case 120: /* x */
|
|
122
|
+
case 117: /* u */
|
|
123
|
+
{
|
|
124
|
+
if (s.at(p) === 123 /* { */) {
|
|
125
|
+
p++;
|
|
126
|
+
c = 0;
|
|
127
|
+
for (;;) {
|
|
128
|
+
const h = from_hex(s.at(p++));
|
|
129
|
+
if (h < 0)
|
|
130
|
+
return -1;
|
|
131
|
+
c = (c << 4) | h;
|
|
132
|
+
if (c > 0x10ffff)
|
|
133
|
+
return -1;
|
|
134
|
+
if (s.at(p) === 125 /* } */)
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
p++;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const n = (c === 120) ? 2 : 4;
|
|
141
|
+
c = 0;
|
|
142
|
+
for (let i = 0; i < n; i++) {
|
|
143
|
+
const h = from_hex(s.at(p++));
|
|
144
|
+
if (h < 0)
|
|
145
|
+
return -1;
|
|
146
|
+
c = (c << 4) | h;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
break;
|
|
151
|
+
default:
|
|
152
|
+
return -2;
|
|
153
|
+
}
|
|
154
|
+
pp.p = p;
|
|
155
|
+
return c;
|
|
156
|
+
}
|
|
157
|
+
/* port of js_parse_string() in JSON mode (s->cur_func == NULL) */
|
|
158
|
+
function json_parse_string(s, sep, p) {
|
|
159
|
+
let out = '';
|
|
160
|
+
for (;;) {
|
|
161
|
+
if (p >= s.buf_end)
|
|
162
|
+
return json_parse_error(s, 'unexpected end of string');
|
|
163
|
+
let c = s.at(p);
|
|
164
|
+
if (c < 0x20) {
|
|
165
|
+
return json_parse_error_pos(s, p, 'invalid character in a JSON string');
|
|
166
|
+
}
|
|
167
|
+
p++;
|
|
168
|
+
if (c === sep)
|
|
169
|
+
break;
|
|
170
|
+
if (c === 92 /* \ */) {
|
|
171
|
+
const p_escape = p - 1;
|
|
172
|
+
c = s.at(p);
|
|
173
|
+
switch (c) {
|
|
174
|
+
case 0:
|
|
175
|
+
if (p >= s.buf_end)
|
|
176
|
+
return json_parse_error(s, 'unexpected end of string');
|
|
177
|
+
p++;
|
|
178
|
+
break;
|
|
179
|
+
case 39: /* ' */
|
|
180
|
+
case 34: /* " */
|
|
181
|
+
case 92: /* \ */
|
|
182
|
+
p++;
|
|
183
|
+
break;
|
|
184
|
+
case 13: /* \r: accept DOS and MAC newline sequences */
|
|
185
|
+
if (s.at(p + 1) === 10)
|
|
186
|
+
p++;
|
|
187
|
+
/* fall through */
|
|
188
|
+
case 10:
|
|
189
|
+
/* ignore escaped newline sequence */
|
|
190
|
+
p++;
|
|
191
|
+
continue;
|
|
192
|
+
default:
|
|
193
|
+
if (c >= 48 && c <= 57) {
|
|
194
|
+
/* JSON case: no octal escapes */
|
|
195
|
+
return json_parse_error_pos(s, p_escape, 'malformed escape sequence in string literal');
|
|
196
|
+
}
|
|
197
|
+
else if (c >= 0x80) {
|
|
198
|
+
p++;
|
|
199
|
+
/* LS or PS are skipped */
|
|
200
|
+
if (c === CP_LS || c === CP_PS)
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const pp = { p };
|
|
205
|
+
const ret = lre_parse_escape(s, pp);
|
|
206
|
+
if (ret === -1) {
|
|
207
|
+
return json_parse_error_pos(s, p_escape, 'malformed escape sequence in string literal');
|
|
208
|
+
}
|
|
209
|
+
else if (ret < 0) {
|
|
210
|
+
/* ignore the '\' (could output a warning) */
|
|
211
|
+
p++;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
p = pp.p;
|
|
215
|
+
c = ret;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
out += (c > 0xffff) ? String.fromCodePoint(c) : String.fromCharCode(c);
|
|
222
|
+
}
|
|
223
|
+
s.tok = -2 /* JSONTok.STRING */;
|
|
224
|
+
s.tok_str = out;
|
|
225
|
+
s.buf_ptr = p;
|
|
226
|
+
return 0;
|
|
227
|
+
}
|
|
228
|
+
/* port of json_parse_ident: only pure ascii identifiers are accepted */
|
|
229
|
+
function json_parse_ident(s, pp, c) {
|
|
230
|
+
let p = pp.p;
|
|
231
|
+
let ident = String.fromCharCode(c);
|
|
232
|
+
for (;;) {
|
|
233
|
+
c = s.at(p);
|
|
234
|
+
if (c >= 128 || !is_ident_continue_ascii(c))
|
|
235
|
+
break;
|
|
236
|
+
ident += String.fromCharCode(c);
|
|
237
|
+
p++;
|
|
238
|
+
}
|
|
239
|
+
pp.p = p;
|
|
240
|
+
return JS_NewAtom(s.ctx, ident);
|
|
241
|
+
}
|
|
242
|
+
/* port of js_atof() with radix 10 and no flags (JSON) or
|
|
243
|
+
ATOD_ACCEPT_BIN_OCT with radix 0 (extended JSON). Returns -1 on error. */
|
|
244
|
+
function json_parse_number(s, p) {
|
|
245
|
+
const ext = s.ext_json;
|
|
246
|
+
let is_neg = false;
|
|
247
|
+
let radix = 10;
|
|
248
|
+
let p_start;
|
|
249
|
+
if (s.at(p) === 43 /* + */) {
|
|
250
|
+
p++;
|
|
251
|
+
}
|
|
252
|
+
else if (s.at(p) === 45 /* - */) {
|
|
253
|
+
p++;
|
|
254
|
+
is_neg = true;
|
|
255
|
+
}
|
|
256
|
+
if (ext && s.at(p) === 48 /* 0 */) {
|
|
257
|
+
const c1 = s.at(p + 1);
|
|
258
|
+
if (c1 === 120 || c1 === 88) {
|
|
259
|
+
p += 2;
|
|
260
|
+
radix = 16;
|
|
261
|
+
}
|
|
262
|
+
else if (c1 === 111 || c1 === 79) {
|
|
263
|
+
p += 2;
|
|
264
|
+
radix = 8;
|
|
265
|
+
}
|
|
266
|
+
else if (c1 === 98 || c1 === 66) {
|
|
267
|
+
p += 2;
|
|
268
|
+
radix = 2;
|
|
269
|
+
}
|
|
270
|
+
if (radix !== 10) {
|
|
271
|
+
/* there must be a digit after the prefix */
|
|
272
|
+
if (to_digit(s.at(p)) >= radix)
|
|
273
|
+
return json_parse_error_pos(s, p, 'invalid number literal');
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
let is_float = false;
|
|
277
|
+
p_start = p;
|
|
278
|
+
while (to_digit(s.at(p)) < radix)
|
|
279
|
+
p++;
|
|
280
|
+
if (s.at(p) === 46 /* . */ && (p > p_start || to_digit(s.at(p + 1)) < radix)) {
|
|
281
|
+
is_float = true;
|
|
282
|
+
p++;
|
|
283
|
+
while (to_digit(s.at(p)) < radix)
|
|
284
|
+
p++;
|
|
285
|
+
}
|
|
286
|
+
if (p > p_start) {
|
|
287
|
+
const c = s.at(p);
|
|
288
|
+
if (((c === 101 || c === 69) && radix === 10) ||
|
|
289
|
+
((c === 112 || c === 80) && (radix === 2 || radix === 8 || radix === 16))) {
|
|
290
|
+
let p1 = p + 1;
|
|
291
|
+
is_float = true;
|
|
292
|
+
if (s.at(p1) === 43 || s.at(p1) === 45)
|
|
293
|
+
p1++;
|
|
294
|
+
if (is_digit(s.at(p1))) {
|
|
295
|
+
p = p1 + 1;
|
|
296
|
+
while (is_digit(s.at(p)))
|
|
297
|
+
p++;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (p === p_start)
|
|
302
|
+
return json_parse_error_pos(s, p, 'invalid number literal');
|
|
303
|
+
const text = s.buf.substring(p_start, p);
|
|
304
|
+
let d;
|
|
305
|
+
if (radix === 10) {
|
|
306
|
+
d = Number(text);
|
|
307
|
+
}
|
|
308
|
+
else if (is_float) {
|
|
309
|
+
return json_parse_error_pos(s, p_start, 'invalid number literal');
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
d = parseInt(text, radix);
|
|
313
|
+
}
|
|
314
|
+
if (is_neg)
|
|
315
|
+
d = -d;
|
|
316
|
+
s.tok = -3 /* JSONTok.NUMBER */;
|
|
317
|
+
s.tok_num = d;
|
|
318
|
+
s.buf_ptr = p;
|
|
319
|
+
return 0;
|
|
320
|
+
}
|
|
321
|
+
function to_digit(c) {
|
|
322
|
+
if (c >= 48 && c <= 57)
|
|
323
|
+
return c - 48;
|
|
324
|
+
if (c >= 65 && c <= 90)
|
|
325
|
+
return c - 65 + 10;
|
|
326
|
+
if (c >= 97 && c <= 122)
|
|
327
|
+
return c - 97 + 10;
|
|
328
|
+
return 36;
|
|
329
|
+
}
|
|
330
|
+
function json_next_token(s) {
|
|
331
|
+
let p = s.last_ptr = s.buf_ptr;
|
|
332
|
+
for (;;) {
|
|
333
|
+
s.tok_ptr = p;
|
|
334
|
+
const c = s.at(p);
|
|
335
|
+
switch (c) {
|
|
336
|
+
case 0:
|
|
337
|
+
if (p >= s.buf_end) {
|
|
338
|
+
s.tok = -1 /* JSONTok.EOF */;
|
|
339
|
+
s.buf_ptr = p;
|
|
340
|
+
return 0;
|
|
341
|
+
}
|
|
342
|
+
break; /* def_token */
|
|
343
|
+
case 39: /* ' */
|
|
344
|
+
if (!s.ext_json)
|
|
345
|
+
break; /* JSON does not accept single quoted strings */
|
|
346
|
+
/* fall through */
|
|
347
|
+
case 34: /* " */
|
|
348
|
+
if (json_parse_string(s, c, p + 1)) {
|
|
349
|
+
s.tok = -5 /* JSONTok.ERROR */;
|
|
350
|
+
return -1;
|
|
351
|
+
}
|
|
352
|
+
return 0;
|
|
353
|
+
case 13: /* \r: accept DOS and MAC newline sequences */
|
|
354
|
+
if (s.at(p + 1) === 10)
|
|
355
|
+
p++;
|
|
356
|
+
/* fall through */
|
|
357
|
+
case 10:
|
|
358
|
+
p++;
|
|
359
|
+
continue;
|
|
360
|
+
case 12: /* \f */
|
|
361
|
+
case 11: /* \v */
|
|
362
|
+
if (!s.ext_json)
|
|
363
|
+
break; /* JSONWhitespace does not match <VT>, nor <FF> */
|
|
364
|
+
/* fall through */
|
|
365
|
+
case 32:
|
|
366
|
+
case 9:
|
|
367
|
+
p++;
|
|
368
|
+
continue;
|
|
369
|
+
case 47: /* / */
|
|
370
|
+
if (!s.ext_json)
|
|
371
|
+
break; /* JSON does not accept comments */
|
|
372
|
+
if (s.at(p + 1) === 42 /* * */) {
|
|
373
|
+
p += 2;
|
|
374
|
+
for (;;) {
|
|
375
|
+
if (p >= s.buf_end) {
|
|
376
|
+
json_parse_error(s, 'unexpected end of comment');
|
|
377
|
+
s.tok = -5 /* JSONTok.ERROR */;
|
|
378
|
+
return -1;
|
|
379
|
+
}
|
|
380
|
+
if (s.at(p) === 42 && s.at(p + 1) === 47) {
|
|
381
|
+
p += 2;
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
p++;
|
|
385
|
+
}
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
else if (s.at(p + 1) === 47) {
|
|
389
|
+
p += 2;
|
|
390
|
+
for (;;) {
|
|
391
|
+
if (p >= s.buf_end)
|
|
392
|
+
break;
|
|
393
|
+
const c1 = s.at(p);
|
|
394
|
+
if (c1 === 13 || c1 === 10 || c1 === CP_LS || c1 === CP_PS)
|
|
395
|
+
break;
|
|
396
|
+
p++;
|
|
397
|
+
}
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
break; /* def_token */
|
|
401
|
+
case 43: /* + */
|
|
402
|
+
if (!s.ext_json || !is_digit(s.at(p + 1)))
|
|
403
|
+
break;
|
|
404
|
+
return json_parse_number(s, p);
|
|
405
|
+
case 48: /* 0 */
|
|
406
|
+
if (is_digit(s.at(p + 1)))
|
|
407
|
+
break;
|
|
408
|
+
return json_parse_number(s, p);
|
|
409
|
+
case 45: /* - */
|
|
410
|
+
if (!is_digit(s.at(p + 1)))
|
|
411
|
+
break;
|
|
412
|
+
return json_parse_number(s, p);
|
|
413
|
+
default:
|
|
414
|
+
if (is_digit(c))
|
|
415
|
+
return json_parse_number(s, p);
|
|
416
|
+
if (is_ident_start_ascii(c)) {
|
|
417
|
+
/* identifier: only pure ascii characters are accepted */
|
|
418
|
+
const pp = { p: p + 1 };
|
|
419
|
+
const atom = json_parse_ident(s, pp, c);
|
|
420
|
+
if (atom === JS_ATOM_NULL) {
|
|
421
|
+
s.tok = -5 /* JSONTok.ERROR */;
|
|
422
|
+
return -1;
|
|
423
|
+
}
|
|
424
|
+
s.tok_atom = atom;
|
|
425
|
+
s.tok = -4 /* JSONTok.IDENT */;
|
|
426
|
+
s.buf_ptr = pp.p;
|
|
427
|
+
return 0;
|
|
428
|
+
}
|
|
429
|
+
if (c >= 128) {
|
|
430
|
+
json_parse_error(s, 'unexpected character');
|
|
431
|
+
s.tok = -5 /* JSONTok.ERROR */;
|
|
432
|
+
return -1;
|
|
433
|
+
}
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
436
|
+
/* def_token */
|
|
437
|
+
s.tok = c;
|
|
438
|
+
p++;
|
|
439
|
+
s.buf_ptr = p;
|
|
440
|
+
return 0;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function json_parse_expect(s, tok) {
|
|
444
|
+
if (s.tok !== tok) {
|
|
445
|
+
/* XXX: dump token correctly in all cases */
|
|
446
|
+
return json_parse_error(s, `expecting '${String.fromCharCode(tok)}'`);
|
|
447
|
+
}
|
|
448
|
+
return json_next_token(s);
|
|
449
|
+
}
|
|
450
|
+
/* current token (through a function so that TypeScript does not narrow s.tok) */
|
|
451
|
+
function cur_tok(s) { return s.tok; }
|
|
452
|
+
function json_parse_value(s, depth) {
|
|
453
|
+
const ctx = s.ctx;
|
|
454
|
+
let val = null;
|
|
455
|
+
if (depth > ctx.rt.max_stack_depth)
|
|
456
|
+
return JS_ThrowStackOverflow(ctx);
|
|
457
|
+
const tok = s.tok;
|
|
458
|
+
switch (tok) {
|
|
459
|
+
case 123: /* { */
|
|
460
|
+
{
|
|
461
|
+
if (json_next_token(s))
|
|
462
|
+
return JS_EXCEPTION;
|
|
463
|
+
val = JS_NewObject(ctx);
|
|
464
|
+
if (JS_IsException(val))
|
|
465
|
+
return val;
|
|
466
|
+
if (cur_tok(s) !== 125 /* } */) {
|
|
467
|
+
for (;;) {
|
|
468
|
+
let prop_name;
|
|
469
|
+
if (cur_tok(s) === -2 /* JSONTok.STRING */) {
|
|
470
|
+
prop_name = JS_ValueToAtom(ctx, s.tok_str);
|
|
471
|
+
if (prop_name === JS_ATOM_NULL)
|
|
472
|
+
return JS_EXCEPTION;
|
|
473
|
+
}
|
|
474
|
+
else if (s.ext_json && cur_tok(s) === -4 /* JSONTok.IDENT */) {
|
|
475
|
+
prop_name = s.tok_atom;
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
json_parse_error(s, 'expecting property name');
|
|
479
|
+
return JS_EXCEPTION;
|
|
480
|
+
}
|
|
481
|
+
if (json_next_token(s))
|
|
482
|
+
return JS_EXCEPTION;
|
|
483
|
+
if (json_parse_expect(s, 58 /* : */))
|
|
484
|
+
return JS_EXCEPTION;
|
|
485
|
+
const prop_val = json_parse_value(s, depth + 1);
|
|
486
|
+
if (JS_IsException(prop_val))
|
|
487
|
+
return JS_EXCEPTION;
|
|
488
|
+
const ret = JS_DefinePropertyValue(ctx, val, prop_name, prop_val, JS_PROP_C_W_E);
|
|
489
|
+
if (ret < 0)
|
|
490
|
+
return JS_EXCEPTION;
|
|
491
|
+
if (cur_tok(s) !== 44 /* , */)
|
|
492
|
+
break;
|
|
493
|
+
if (json_next_token(s))
|
|
494
|
+
return JS_EXCEPTION;
|
|
495
|
+
if (s.ext_json && cur_tok(s) === 125)
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (json_parse_expect(s, 125 /* } */))
|
|
500
|
+
return JS_EXCEPTION;
|
|
501
|
+
}
|
|
502
|
+
break;
|
|
503
|
+
case 91: /* [ */
|
|
504
|
+
{
|
|
505
|
+
if (json_next_token(s))
|
|
506
|
+
return JS_EXCEPTION;
|
|
507
|
+
val = JS_NewArray(ctx);
|
|
508
|
+
if (JS_IsException(val))
|
|
509
|
+
return val;
|
|
510
|
+
if (cur_tok(s) !== 93 /* ] */) {
|
|
511
|
+
let idx = 0;
|
|
512
|
+
for (;;) {
|
|
513
|
+
const el = json_parse_value(s, depth + 1);
|
|
514
|
+
if (JS_IsException(el))
|
|
515
|
+
return JS_EXCEPTION;
|
|
516
|
+
const ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
|
|
517
|
+
if (ret < 0)
|
|
518
|
+
return JS_EXCEPTION;
|
|
519
|
+
if (cur_tok(s) !== 44 /* , */)
|
|
520
|
+
break;
|
|
521
|
+
if (json_next_token(s))
|
|
522
|
+
return JS_EXCEPTION;
|
|
523
|
+
idx++;
|
|
524
|
+
if (s.ext_json && cur_tok(s) === 93)
|
|
525
|
+
break;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
if (json_parse_expect(s, 93 /* ] */))
|
|
529
|
+
return JS_EXCEPTION;
|
|
530
|
+
}
|
|
531
|
+
break;
|
|
532
|
+
case -2 /* JSONTok.STRING */:
|
|
533
|
+
val = s.tok_str;
|
|
534
|
+
if (json_next_token(s))
|
|
535
|
+
return JS_EXCEPTION;
|
|
536
|
+
break;
|
|
537
|
+
case -3 /* JSONTok.NUMBER */:
|
|
538
|
+
val = s.tok_num;
|
|
539
|
+
if (json_next_token(s))
|
|
540
|
+
return JS_EXCEPTION;
|
|
541
|
+
break;
|
|
542
|
+
case -4 /* JSONTok.IDENT */:
|
|
543
|
+
if (s.tok_atom === JS_ATOM_false || s.tok_atom === JS_ATOM_true) {
|
|
544
|
+
val = (s.tok_atom === JS_ATOM_true);
|
|
545
|
+
}
|
|
546
|
+
else if (s.tok_atom === JS_ATOM_null) {
|
|
547
|
+
val = null;
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
return json_unexpected_token(s);
|
|
551
|
+
}
|
|
552
|
+
if (json_next_token(s))
|
|
553
|
+
return JS_EXCEPTION;
|
|
554
|
+
break;
|
|
555
|
+
default:
|
|
556
|
+
return json_unexpected_token(s);
|
|
557
|
+
}
|
|
558
|
+
return val;
|
|
559
|
+
}
|
|
560
|
+
function json_unexpected_token(s) {
|
|
561
|
+
if (s.tok === -1 /* JSONTok.EOF */) {
|
|
562
|
+
json_parse_error(s, 'Unexpected end of JSON input');
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
json_parse_error(s, `unexpected token: '${s.buf.substring(s.tok_ptr, s.buf_ptr)}'`);
|
|
566
|
+
}
|
|
567
|
+
return JS_EXCEPTION;
|
|
568
|
+
}
|
|
569
|
+
export function JS_ParseJSON2(ctx, buf, filename, flags) {
|
|
570
|
+
const s = new JSONParseState(ctx, buf, filename);
|
|
571
|
+
s.ext_json = (flags & JS_PARSE_JSON_EXT) !== 0;
|
|
572
|
+
if (json_next_token(s))
|
|
573
|
+
return JS_EXCEPTION;
|
|
574
|
+
const val = json_parse_value(s, 0);
|
|
575
|
+
if (JS_IsException(val))
|
|
576
|
+
return val;
|
|
577
|
+
if (s.tok !== -1 /* JSONTok.EOF */) {
|
|
578
|
+
json_parse_error(s, 'unexpected data at the end');
|
|
579
|
+
return JS_EXCEPTION;
|
|
580
|
+
}
|
|
581
|
+
return val;
|
|
582
|
+
}
|
|
583
|
+
export function JS_ParseJSON(ctx, buf, filename) {
|
|
584
|
+
return JS_ParseJSON2(ctx, buf, filename, 0);
|
|
585
|
+
}
|
|
586
|
+
/* ---------------------------------------------------------------------
|
|
587
|
+
JSON.parse
|
|
588
|
+
--------------------------------------------------------------------- */
|
|
589
|
+
function internalize_json_property(ctx, holder, name, reviver, depth) {
|
|
590
|
+
if (depth > ctx.rt.max_stack_depth)
|
|
591
|
+
return JS_ThrowStackOverflow(ctx);
|
|
592
|
+
const val = JS_GetProperty(ctx, holder, name);
|
|
593
|
+
if (JS_IsException(val))
|
|
594
|
+
return val;
|
|
595
|
+
if (JS_IsObject(val)) {
|
|
596
|
+
const is_array = JS_IsArray(ctx, val);
|
|
597
|
+
if (is_array < 0)
|
|
598
|
+
return JS_EXCEPTION;
|
|
599
|
+
let len;
|
|
600
|
+
let atoms = null;
|
|
601
|
+
if (is_array) {
|
|
602
|
+
len = js_get_length64(ctx, val);
|
|
603
|
+
if (len < 0)
|
|
604
|
+
return JS_EXCEPTION;
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
607
|
+
atoms = JS_GetOwnPropertyNamesInternal(ctx, val, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
|
|
608
|
+
if (!atoms)
|
|
609
|
+
return JS_EXCEPTION;
|
|
610
|
+
len = atoms.length;
|
|
611
|
+
}
|
|
612
|
+
for (let i = 0; i < len; i++) {
|
|
613
|
+
let prop;
|
|
614
|
+
if (is_array) {
|
|
615
|
+
prop = JS_NewAtomUInt32(ctx, i);
|
|
616
|
+
}
|
|
617
|
+
else {
|
|
618
|
+
prop = atoms[i].atom;
|
|
619
|
+
}
|
|
620
|
+
const new_el = internalize_json_property(ctx, val, prop, reviver, depth + 1);
|
|
621
|
+
if (JS_IsException(new_el))
|
|
622
|
+
return JS_EXCEPTION;
|
|
623
|
+
let ret;
|
|
624
|
+
if (JS_IsUndefined(new_el)) {
|
|
625
|
+
ret = JS_DeleteProperty(ctx, val, prop, 0);
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);
|
|
629
|
+
}
|
|
630
|
+
if (ret < 0)
|
|
631
|
+
return JS_EXCEPTION;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
const name_val = JS_AtomToValue(ctx, name);
|
|
635
|
+
if (JS_IsException(name_val))
|
|
636
|
+
return JS_EXCEPTION;
|
|
637
|
+
return JS_Call(ctx, reviver, holder, [name_val, val]);
|
|
638
|
+
}
|
|
639
|
+
function js_json_parse(ctx, this_val, argv) {
|
|
640
|
+
const str = JS_ToString(ctx, argv[0]);
|
|
641
|
+
if (JS_IsException(str))
|
|
642
|
+
return JS_EXCEPTION;
|
|
643
|
+
/* fast path: the host parser, with the tree re-prototyped to the guest
|
|
644
|
+
intrinsics. On a syntax error the ported parser runs to produce the
|
|
645
|
+
QuickJS error (message, line and column). */
|
|
646
|
+
let obj;
|
|
647
|
+
try {
|
|
648
|
+
obj = fix_deep_json(ctx, JSON.parse(str));
|
|
649
|
+
}
|
|
650
|
+
catch {
|
|
651
|
+
obj = JS_ParseJSON(ctx, str, '<input>');
|
|
652
|
+
}
|
|
653
|
+
if (JS_IsException(obj))
|
|
654
|
+
return obj;
|
|
655
|
+
if (argv.length > 1 && JS_IsFunction(ctx, argv[1])) {
|
|
656
|
+
const reviver = argv[1];
|
|
657
|
+
const root = JS_NewObject(ctx);
|
|
658
|
+
if (JS_IsException(root))
|
|
659
|
+
return JS_EXCEPTION;
|
|
660
|
+
if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj, JS_PROP_C_W_E) < 0)
|
|
661
|
+
return JS_EXCEPTION;
|
|
662
|
+
obj = internalize_json_property(ctx, root, JS_ATOM_empty_string, reviver, 0);
|
|
663
|
+
}
|
|
664
|
+
return obj;
|
|
665
|
+
}
|
|
666
|
+
function js_json_check(ctx, jsc, holder, val, key) {
|
|
667
|
+
/* check for object.toJSON method */
|
|
668
|
+
/* ECMA specifies this is done only for Object and BigInt */
|
|
669
|
+
if (JS_IsObject(val) || typeof val === 'bigint') {
|
|
670
|
+
const f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);
|
|
671
|
+
if (JS_IsException(f))
|
|
672
|
+
return JS_EXCEPTION;
|
|
673
|
+
if (JS_IsFunction(ctx, f)) {
|
|
674
|
+
val = JS_Call(ctx, f, val, [key]);
|
|
675
|
+
if (JS_IsException(val))
|
|
676
|
+
return JS_EXCEPTION;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
if (!JS_IsUndefined(jsc.replacer_func)) {
|
|
680
|
+
val = JS_Call(ctx, jsc.replacer_func, holder, [key, val]);
|
|
681
|
+
if (JS_IsException(val))
|
|
682
|
+
return JS_EXCEPTION;
|
|
683
|
+
}
|
|
684
|
+
switch (typeof val) {
|
|
685
|
+
case 'object':
|
|
686
|
+
if (val === null)
|
|
687
|
+
return val;
|
|
688
|
+
if (Q.JS_IsObject(val)) {
|
|
689
|
+
if (JS_IsFunction(ctx, val))
|
|
690
|
+
break;
|
|
691
|
+
return val;
|
|
692
|
+
}
|
|
693
|
+
if (JS_IsException(val))
|
|
694
|
+
return val;
|
|
695
|
+
break; /* symbol */
|
|
696
|
+
case 'string':
|
|
697
|
+
case 'number':
|
|
698
|
+
case 'boolean':
|
|
699
|
+
case 'bigint':
|
|
700
|
+
return val;
|
|
701
|
+
default:
|
|
702
|
+
break;
|
|
703
|
+
}
|
|
704
|
+
return undefined;
|
|
705
|
+
}
|
|
706
|
+
function js_json_to_str(ctx, jsc, holder, val, indent, depth) {
|
|
707
|
+
if (depth > ctx.rt.max_stack_depth) {
|
|
708
|
+
JS_ThrowStackOverflow(ctx);
|
|
709
|
+
return -1;
|
|
710
|
+
}
|
|
711
|
+
if (Q.JS_IsObject(val)) {
|
|
712
|
+
const p = val;
|
|
713
|
+
const cl = Q.JS_GetClassID(p);
|
|
714
|
+
if (cl === 5 /* JSClassID.STRING */) {
|
|
715
|
+
val = JS_ToString(ctx, val);
|
|
716
|
+
if (JS_IsException(val))
|
|
717
|
+
return -1;
|
|
718
|
+
}
|
|
719
|
+
else if (cl === 4 /* JSClassID.NUMBER */) {
|
|
720
|
+
val = JS_ToNumber(ctx, val);
|
|
721
|
+
if (JS_IsException(val))
|
|
722
|
+
return -1;
|
|
723
|
+
}
|
|
724
|
+
else if (cl === 6 /* JSClassID.BOOLEAN */ || cl === 33 /* JSClassID.BIG_INT */) {
|
|
725
|
+
/* This will throw the same error as for the primitive object */
|
|
726
|
+
val = Q.JS_GetAnyOpaque(p);
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
if (jsc.stack.includes(p)) {
|
|
730
|
+
JS_ThrowTypeError(ctx, 'circular reference');
|
|
731
|
+
return -1;
|
|
732
|
+
}
|
|
733
|
+
const indent1 = indent + jsc.gap;
|
|
734
|
+
let sep, sep1;
|
|
735
|
+
if (jsc.gap !== '') {
|
|
736
|
+
sep = '\n' + indent1;
|
|
737
|
+
sep1 = ' ';
|
|
738
|
+
}
|
|
739
|
+
else {
|
|
740
|
+
sep = jsc.empty;
|
|
741
|
+
sep1 = jsc.empty;
|
|
742
|
+
}
|
|
743
|
+
jsc.stack.push(p);
|
|
744
|
+
const ret = JS_IsArray(ctx, val);
|
|
745
|
+
if (ret < 0)
|
|
746
|
+
return -1;
|
|
747
|
+
if (ret) {
|
|
748
|
+
const len = js_get_length64(ctx, val);
|
|
749
|
+
if (len < 0)
|
|
750
|
+
return -1;
|
|
751
|
+
jsc.b.push('[');
|
|
752
|
+
for (let i = 0; i < len; i++) {
|
|
753
|
+
if (i > 0)
|
|
754
|
+
jsc.b.push(',');
|
|
755
|
+
jsc.b.push(sep);
|
|
756
|
+
let v = JS_GetPropertyInt64(ctx, val, i);
|
|
757
|
+
if (JS_IsException(v))
|
|
758
|
+
return -1;
|
|
759
|
+
/* XXX: could do this string conversion only when needed */
|
|
760
|
+
const prop = String(i);
|
|
761
|
+
v = js_json_check(ctx, jsc, val, v, prop);
|
|
762
|
+
if (JS_IsException(v))
|
|
763
|
+
return -1;
|
|
764
|
+
if (JS_IsUndefined(v))
|
|
765
|
+
v = null;
|
|
766
|
+
if (js_json_to_str(ctx, jsc, val, v, indent1, depth + 1))
|
|
767
|
+
return -1;
|
|
768
|
+
}
|
|
769
|
+
if (len > 0 && jsc.gap !== '') {
|
|
770
|
+
jsc.b.push('\n');
|
|
771
|
+
jsc.b.push(indent);
|
|
772
|
+
}
|
|
773
|
+
jsc.b.push(']');
|
|
774
|
+
}
|
|
775
|
+
else {
|
|
776
|
+
let tab;
|
|
777
|
+
if (jsc.property_list !== null) {
|
|
778
|
+
tab = jsc.property_list;
|
|
779
|
+
}
|
|
780
|
+
else {
|
|
781
|
+
const keys = js_object_keys(ctx, val);
|
|
782
|
+
if (!keys)
|
|
783
|
+
return -1;
|
|
784
|
+
tab = keys;
|
|
785
|
+
}
|
|
786
|
+
const len = tab.length;
|
|
787
|
+
jsc.b.push('{');
|
|
788
|
+
let has_content = false;
|
|
789
|
+
for (let i = 0; i < len; i++) {
|
|
790
|
+
let prop = tab[i];
|
|
791
|
+
let v = JS_GetPropertyValue(ctx, val, prop);
|
|
792
|
+
if (JS_IsException(v))
|
|
793
|
+
return -1;
|
|
794
|
+
v = js_json_check(ctx, jsc, val, v, prop);
|
|
795
|
+
if (JS_IsException(v))
|
|
796
|
+
return -1;
|
|
797
|
+
if (!JS_IsUndefined(v)) {
|
|
798
|
+
if (has_content)
|
|
799
|
+
jsc.b.push(',');
|
|
800
|
+
prop = JS_ToQuotedString(ctx, prop);
|
|
801
|
+
if (JS_IsException(prop))
|
|
802
|
+
return -1;
|
|
803
|
+
jsc.b.push(sep);
|
|
804
|
+
jsc.b.push(prop);
|
|
805
|
+
jsc.b.push(':');
|
|
806
|
+
jsc.b.push(sep1);
|
|
807
|
+
if (js_json_to_str(ctx, jsc, val, v, indent1, depth + 1))
|
|
808
|
+
return -1;
|
|
809
|
+
has_content = true;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
if (has_content && jsc.gap !== '') {
|
|
813
|
+
jsc.b.push('\n');
|
|
814
|
+
jsc.b.push(indent);
|
|
815
|
+
}
|
|
816
|
+
jsc.b.push('}');
|
|
817
|
+
}
|
|
818
|
+
jsc.stack.pop();
|
|
819
|
+
return 0;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
/* concat_primitive */
|
|
823
|
+
switch (typeof val) {
|
|
824
|
+
case 'string': {
|
|
825
|
+
const q = JS_ToQuotedString(ctx, val);
|
|
826
|
+
if (JS_IsException(q))
|
|
827
|
+
return -1;
|
|
828
|
+
jsc.b.push(q);
|
|
829
|
+
return 0;
|
|
830
|
+
}
|
|
831
|
+
case 'number':
|
|
832
|
+
if (!Number.isFinite(val)) {
|
|
833
|
+
jsc.b.push('null');
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
jsc.b.push(String(val));
|
|
837
|
+
}
|
|
838
|
+
return 0;
|
|
839
|
+
case 'boolean':
|
|
840
|
+
jsc.b.push(val ? 'true' : 'false');
|
|
841
|
+
return 0;
|
|
842
|
+
case 'object':
|
|
843
|
+
if (val === null) {
|
|
844
|
+
jsc.b.push('null');
|
|
845
|
+
return 0;
|
|
846
|
+
}
|
|
847
|
+
return 0;
|
|
848
|
+
case 'bigint':
|
|
849
|
+
/* reject big numbers: use toJSON method to override */
|
|
850
|
+
JS_ThrowTypeError(ctx, 'Do not know how to serialize a BigInt');
|
|
851
|
+
return -1;
|
|
852
|
+
default:
|
|
853
|
+
return 0;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
/* own enumerable string keys of an object (js_object_keys with JS_ITERATOR_KIND_KEY) */
|
|
857
|
+
function js_object_keys(ctx, obj) {
|
|
858
|
+
const tab = JS_GetOwnPropertyNamesInternal(ctx, obj, JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY);
|
|
859
|
+
if (!tab)
|
|
860
|
+
return null;
|
|
861
|
+
const res = [];
|
|
862
|
+
for (const e of tab) {
|
|
863
|
+
const v = JS_AtomToValue(ctx, e.atom);
|
|
864
|
+
if (JS_IsException(v))
|
|
865
|
+
return null;
|
|
866
|
+
res.push(v);
|
|
867
|
+
}
|
|
868
|
+
return res;
|
|
869
|
+
}
|
|
870
|
+
export function JS_JSONStringify(ctx, obj, replacer, space0) {
|
|
871
|
+
const jsc = {
|
|
872
|
+
replacer_func: undefined,
|
|
873
|
+
stack: [],
|
|
874
|
+
property_list: null,
|
|
875
|
+
gap: '',
|
|
876
|
+
empty: '',
|
|
877
|
+
b: [],
|
|
878
|
+
};
|
|
879
|
+
if (JS_IsFunction(ctx, replacer)) {
|
|
880
|
+
jsc.replacer_func = replacer;
|
|
881
|
+
}
|
|
882
|
+
else {
|
|
883
|
+
const res = JS_IsArray(ctx, replacer);
|
|
884
|
+
if (res < 0)
|
|
885
|
+
return JS_EXCEPTION;
|
|
886
|
+
if (res) {
|
|
887
|
+
/* XXX: enumeration is not fully correct */
|
|
888
|
+
jsc.property_list = [];
|
|
889
|
+
const n = js_get_length64(ctx, replacer);
|
|
890
|
+
if (n < 0)
|
|
891
|
+
return JS_EXCEPTION;
|
|
892
|
+
for (let i = 0; i < n; i++) {
|
|
893
|
+
let v = JS_GetPropertyInt64(ctx, replacer, i);
|
|
894
|
+
if (JS_IsException(v))
|
|
895
|
+
return JS_EXCEPTION;
|
|
896
|
+
if (Q.JS_IsObject(v)) {
|
|
897
|
+
if (Q.JS_GetClassID(v) === 5 /* JSClassID.STRING */ || Q.JS_GetClassID(v) === 4 /* JSClassID.NUMBER */) {
|
|
898
|
+
v = JS_ToString(ctx, v);
|
|
899
|
+
if (JS_IsException(v))
|
|
900
|
+
return JS_EXCEPTION;
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
else if (typeof v === 'number') {
|
|
907
|
+
v = JS_ToString(ctx, v);
|
|
908
|
+
if (JS_IsException(v))
|
|
909
|
+
return JS_EXCEPTION;
|
|
910
|
+
}
|
|
911
|
+
else if (typeof v !== 'string') {
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
914
|
+
if (!jsc.property_list.includes(v)) {
|
|
915
|
+
jsc.property_list.push(v);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
let space = space0;
|
|
921
|
+
if (Q.JS_IsObject(space)) {
|
|
922
|
+
if (Q.JS_GetClassID(space) === 4 /* JSClassID.NUMBER */) {
|
|
923
|
+
space = JS_ToNumber(ctx, space);
|
|
924
|
+
}
|
|
925
|
+
else if (Q.JS_GetClassID(space) === 5 /* JSClassID.STRING */) {
|
|
926
|
+
space = JS_ToString(ctx, space);
|
|
927
|
+
}
|
|
928
|
+
if (JS_IsException(space))
|
|
929
|
+
return JS_EXCEPTION;
|
|
930
|
+
}
|
|
931
|
+
if (typeof space === 'number') {
|
|
932
|
+
const n = JS_ToInt32Clamp(ctx, space, 0, 10, 0);
|
|
933
|
+
if (JS_IsException(n))
|
|
934
|
+
return JS_EXCEPTION;
|
|
935
|
+
jsc.gap = ' '.substring(0, n);
|
|
936
|
+
}
|
|
937
|
+
else if (typeof space === 'string') {
|
|
938
|
+
jsc.gap = space.substring(0, Math.min(space.length, 10));
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
jsc.gap = jsc.empty;
|
|
942
|
+
}
|
|
943
|
+
const wrapper = JS_NewObject(ctx);
|
|
944
|
+
if (JS_IsException(wrapper))
|
|
945
|
+
return JS_EXCEPTION;
|
|
946
|
+
if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string, obj, JS_PROP_C_W_E) < 0)
|
|
947
|
+
return JS_EXCEPTION;
|
|
948
|
+
let val = js_json_check(ctx, jsc, wrapper, obj, jsc.empty);
|
|
949
|
+
if (JS_IsException(val))
|
|
950
|
+
return JS_EXCEPTION;
|
|
951
|
+
if (JS_IsUndefined(val))
|
|
952
|
+
return undefined;
|
|
953
|
+
if (js_json_to_str(ctx, jsc, wrapper, val, jsc.empty, 0))
|
|
954
|
+
return JS_EXCEPTION;
|
|
955
|
+
return jsc.b.join('');
|
|
956
|
+
}
|
|
957
|
+
function js_json_stringify(ctx, this_val, argv) {
|
|
958
|
+
// stringify(val, replacer, space)
|
|
959
|
+
/* fast path: the host serializer (toJSON/replacer are guest functions,
|
|
960
|
+
called natively). A host TypeError (BigInt, cycle) is reported by the
|
|
961
|
+
ported serializer with the QuickJS message; guest exceptions thrown by
|
|
962
|
+
toJSON/replacer/getters propagate. */
|
|
963
|
+
try {
|
|
964
|
+
return JSON.stringify(argv[0], argv[1], argv[2]);
|
|
965
|
+
}
|
|
966
|
+
catch (e) {
|
|
967
|
+
if (!(e instanceof TypeError))
|
|
968
|
+
return Q.js_host_exception_to_guest(ctx, e);
|
|
969
|
+
}
|
|
970
|
+
return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
|
|
971
|
+
}
|
|
972
|
+
const js_json_funcs = [
|
|
973
|
+
JS_CFUNC_DEF('parse', 2, js_json_parse),
|
|
974
|
+
JS_CFUNC_DEF('stringify', 3, js_json_stringify),
|
|
975
|
+
JS_PROP_STRING_DEF(JS_ATOM_Symbol_toStringTag, 'JSON', JS_PROP_CONFIGURABLE),
|
|
976
|
+
];
|
|
977
|
+
const js_json_obj = [
|
|
978
|
+
JS_OBJECT_DEF('JSON', js_json_funcs, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE),
|
|
979
|
+
];
|
|
980
|
+
export function JS_AddIntrinsicJSON(ctx) {
|
|
981
|
+
/* add JSON as autoinit object */
|
|
982
|
+
JS_SetPropertyFunctionList(ctx, ctx.global_obj, js_json_obj);
|
|
983
|
+
}
|
|
984
|
+
//# sourceMappingURL=json.js.map
|