jseption 0.0.5 → 0.0.7
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/README.md +30 -6
- package/dist/atoms.d.ts +1 -0
- package/dist/atoms.js +2 -1
- package/dist/atoms.js.map +1 -1
- package/dist/builtins/base64.d.ts +14 -0
- package/dist/builtins/base64.js +219 -0
- package/dist/builtins/base64.js.map +1 -0
- package/dist/builtins/bigint.js +3 -3
- package/dist/builtins/bigint.js.map +1 -1
- package/dist/builtins/date.d.ts +1 -0
- package/dist/builtins/date.js +26 -12
- package/dist/builtins/date.js.map +1 -1
- package/dist/builtins/error.js +9 -0
- package/dist/builtins/error.js.map +1 -1
- package/dist/builtins/float16.d.ts +3 -0
- package/dist/builtins/float16.js +69 -0
- package/dist/builtins/float16.js.map +1 -0
- package/dist/builtins/function.js +2 -2
- package/dist/builtins/index.js +9 -6
- package/dist/builtins/index.js.map +1 -1
- package/dist/builtins/iterator.d.ts +2 -0
- package/dist/builtins/iterator.js +624 -0
- package/dist/builtins/iterator.js.map +1 -0
- package/dist/builtins/json.d.ts +13 -1
- package/dist/builtins/json.js +283 -211
- package/dist/builtins/json.js.map +1 -1
- package/dist/builtins/mapset.js +365 -6
- package/dist/builtins/mapset.js.map +1 -1
- package/dist/builtins/math.js +203 -3
- package/dist/builtins/math.js.map +1 -1
- package/dist/builtins/native.js +6 -6
- package/dist/builtins/object.js +9 -2
- package/dist/builtins/object.js.map +1 -1
- package/dist/builtins/promise.js +31 -11
- package/dist/builtins/promise.js.map +1 -1
- package/dist/builtins/proxy.js +2 -2
- package/dist/builtins/reflect.js +6 -2
- package/dist/builtins/reflect.js.map +1 -1
- package/dist/builtins/regexp.js +74 -3
- package/dist/builtins/regexp.js.map +1 -1
- package/dist/builtins/string.js +1 -1
- package/dist/builtins/symbol.js +1 -1
- package/dist/builtins/symbol.js.map +1 -1
- package/dist/builtins/typedarray.d.ts +4 -1
- package/dist/builtins/typedarray.js +325 -37
- package/dist/builtins/typedarray.js.map +1 -1
- package/dist/builtins/weakref.js +7 -7
- package/dist/embed.d.ts +5 -0
- package/dist/embed.js +36 -11
- package/dist/embed.js.map +1 -1
- package/dist/interpreter.js +15 -14
- package/dist/interpreter.js.map +1 -1
- package/dist/jit.d.ts +1 -0
- package/dist/jit.js +51 -13
- package/dist/jit.js.map +1 -1
- package/dist/jit_hook.d.ts +1 -0
- package/dist/jit_hook.js.map +1 -1
- package/dist/jit_runtime.d.ts +1 -1
- package/dist/jit_runtime.js +6 -6
- package/dist/jit_runtime.js.map +1 -1
- package/dist/jit_stack.d.ts +1 -0
- package/dist/jit_stack.js +2 -1
- package/dist/jit_stack.js.map +1 -1
- package/dist/jseption.d.ts +2 -0
- package/dist/jseption.js +1 -0
- package/dist/jseption.js.map +1 -1
- package/dist/membrane.d.ts +6 -0
- package/dist/membrane.js +7 -3
- package/dist/membrane.js.map +1 -1
- package/dist/module.js +5 -3
- package/dist/module.js.map +1 -1
- package/dist/parser.js +26 -9
- package/dist/parser.js.map +1 -1
- package/dist/print.d.ts +12 -0
- package/dist/print.js +494 -0
- package/dist/print.js.map +1 -0
- package/dist/qjs.js +13 -10
- package/dist/qjs.js.map +1 -1
- package/dist/quickjs.d.ts +8 -0
- package/dist/quickjs.js +132 -53
- package/dist/quickjs.js.map +1 -1
- package/dist/std.d.ts +4 -2
- package/dist/std.js +42 -8
- package/dist/std.js.map +1 -1
- package/dist/values.d.ts +31 -27
- package/dist/values.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/dist/builtins/json.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* js_json_check, js_json_to_str, JS_JSONStringify)
|
|
5
5
|
*/
|
|
6
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";
|
|
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_DefinePropertyValueStr, 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, JS_ATOM_NaN, JS_ATOM_Infinity, JS_ThrowSyntaxError, JS_PROP_ENUMERABLE, js_same_value, __JS_AtomIsTaggedInt, __JS_AtomToUInt32, } from "../quickjs.js";
|
|
8
8
|
import { fix_deep_json } from "./native.js";
|
|
9
9
|
/* ---------------------------------------------------------------------
|
|
10
10
|
JSON parser (port of json_next_token / json_parse_value)
|
|
@@ -94,131 +94,67 @@ function is_ident_start_ascii(c) {
|
|
|
94
94
|
function is_ident_continue_ascii(c) {
|
|
95
95
|
return is_ident_start_ascii(c) || is_digit(c);
|
|
96
96
|
}
|
|
97
|
-
/* port of
|
|
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) */
|
|
97
|
+
/* port of json_parse_string: 'p' is the position after the opening quote */
|
|
158
98
|
function json_parse_string(s, sep, p) {
|
|
159
99
|
let out = '';
|
|
160
100
|
for (;;) {
|
|
161
101
|
if (p >= s.buf_end)
|
|
162
|
-
return json_parse_error(s, '
|
|
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++;
|
|
102
|
+
return json_parse_error(s, 'Unexpected end of JSON input');
|
|
103
|
+
let c = s.at(p++);
|
|
168
104
|
if (c === sep)
|
|
169
105
|
break;
|
|
106
|
+
if (c < 0x20)
|
|
107
|
+
return json_parse_error_pos(s, p - 1, 'Bad control character in string literal');
|
|
170
108
|
if (c === 92 /* \ */) {
|
|
171
|
-
|
|
172
|
-
c = s.at(p);
|
|
109
|
+
c = s.at(p++);
|
|
173
110
|
switch (c) {
|
|
174
|
-
case
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
case
|
|
111
|
+
case 98:
|
|
112
|
+
c = 8;
|
|
113
|
+
break; /* \b */
|
|
114
|
+
case 102:
|
|
115
|
+
c = 12;
|
|
116
|
+
break; /* \f */
|
|
117
|
+
case 110:
|
|
118
|
+
c = 10;
|
|
119
|
+
break; /* \n */
|
|
120
|
+
case 114:
|
|
121
|
+
c = 13;
|
|
122
|
+
break; /* \r */
|
|
123
|
+
case 116:
|
|
124
|
+
c = 9;
|
|
125
|
+
break; /* \t */
|
|
181
126
|
case 92: /* \ */
|
|
182
|
-
|
|
127
|
+
case 47: /* / */
|
|
183
128
|
break;
|
|
184
|
-
case
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
}
|
|
129
|
+
case 117: /* u */
|
|
130
|
+
c = 0;
|
|
131
|
+
for (let i = 0; i < 4; i++) {
|
|
132
|
+
const h = from_hex(s.at(p++));
|
|
133
|
+
if (h < 0)
|
|
134
|
+
return json_parse_error_pos(s, p - 1, 'Bad Unicode escape');
|
|
135
|
+
c = (c << 4) | h;
|
|
217
136
|
}
|
|
218
137
|
break;
|
|
138
|
+
case 10: /* escaped newline: multi-line string */
|
|
139
|
+
if (s.ext_json)
|
|
140
|
+
continue;
|
|
141
|
+
return json_parse_error_pos(s, p - 1, 'Bad escaped character');
|
|
142
|
+
case 118: /* v */
|
|
143
|
+
if (s.ext_json) {
|
|
144
|
+
c = 11;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
return json_parse_error_pos(s, p - 1, 'Bad escaped character');
|
|
148
|
+
default:
|
|
149
|
+
if (c === sep)
|
|
150
|
+
break;
|
|
151
|
+
if (p > s.buf_end)
|
|
152
|
+
return json_parse_error(s, 'Unexpected end of JSON input');
|
|
153
|
+
return json_parse_error_pos(s, p - 1, 'Bad escaped character');
|
|
219
154
|
}
|
|
220
155
|
}
|
|
221
|
-
|
|
156
|
+
/* the input is UTF-16: other characters (surrogates included) are copied as is */
|
|
157
|
+
out += String.fromCharCode(c);
|
|
222
158
|
}
|
|
223
159
|
s.tok = -2 /* JSONTok.STRING */;
|
|
224
160
|
s.tok_str = out;
|
|
@@ -239,80 +175,94 @@ function json_parse_ident(s, pp, c) {
|
|
|
239
175
|
pp.p = p;
|
|
240
176
|
return JS_NewAtom(s.ctx, ident);
|
|
241
177
|
}
|
|
242
|
-
/*
|
|
243
|
-
|
|
178
|
+
/* the message of js_parse_error_pos(s, p, "Unexpected token '%c'", *p): the
|
|
179
|
+
NUL past the end of the C buffer ends the formatted message */
|
|
180
|
+
function json_unexpected_char(s, p) {
|
|
181
|
+
const c = s.at(p);
|
|
182
|
+
return json_parse_error_pos(s, p, c === 0 ? "Unexpected token '" : `Unexpected token '${String.fromCharCode(c)}'`);
|
|
183
|
+
}
|
|
184
|
+
/* the input starts with 'str' at position p */
|
|
185
|
+
function json_strstart(s, p, str) {
|
|
186
|
+
return s.buf.startsWith(str, p);
|
|
187
|
+
}
|
|
188
|
+
/* port of json_parse_number: 'p' is the position of the first character */
|
|
244
189
|
function json_parse_number(s, p) {
|
|
245
|
-
const
|
|
246
|
-
let
|
|
247
|
-
|
|
248
|
-
let p_start;
|
|
249
|
-
if (s.at(p) === 43 /* + */) {
|
|
250
|
-
p++;
|
|
251
|
-
}
|
|
252
|
-
else if (s.at(p) === 45 /* - */) {
|
|
190
|
+
const p_start = p;
|
|
191
|
+
let d;
|
|
192
|
+
if (s.at(p) === 43 /* + */ || s.at(p) === 45 /* - */)
|
|
253
193
|
p++;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
p
|
|
264
|
-
|
|
194
|
+
done: {
|
|
195
|
+
if (!is_digit(s.at(p))) {
|
|
196
|
+
if (!s.ext_json)
|
|
197
|
+
return json_unexpected_char(s, p);
|
|
198
|
+
if (json_strstart(s, p, 'Infinity')) {
|
|
199
|
+
p += 8;
|
|
200
|
+
d = s.at(p_start) === 45 ? -Infinity : Infinity;
|
|
201
|
+
break done;
|
|
202
|
+
}
|
|
203
|
+
else if (json_strstart(s, p, 'NaN')) {
|
|
204
|
+
p += 3;
|
|
205
|
+
d = NaN;
|
|
206
|
+
break done;
|
|
207
|
+
}
|
|
208
|
+
else if (s.at(p) !== 46 /* . */) {
|
|
209
|
+
return json_unexpected_char(s, p);
|
|
210
|
+
}
|
|
265
211
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
212
|
+
if (s.at(p) === 48 /* 0 */) {
|
|
213
|
+
if (s.ext_json) {
|
|
214
|
+
/* also accepts base 16, 8 and 2 prefix for integers */
|
|
215
|
+
let radix = 10;
|
|
216
|
+
const c1 = s.at(p + 1);
|
|
217
|
+
if (c1 === 120 || c1 === 88) {
|
|
218
|
+
p += 2;
|
|
219
|
+
radix = 16;
|
|
220
|
+
}
|
|
221
|
+
else if (c1 === 111 || c1 === 79) {
|
|
222
|
+
p += 2;
|
|
223
|
+
radix = 8;
|
|
224
|
+
}
|
|
225
|
+
else if (c1 === 98 || c1 === 66) {
|
|
226
|
+
p += 2;
|
|
227
|
+
radix = 2;
|
|
228
|
+
}
|
|
229
|
+
if (radix !== 10) {
|
|
230
|
+
/* prefix is present */
|
|
231
|
+
if (to_digit(s.at(p)) >= radix)
|
|
232
|
+
return json_unexpected_char(s, p);
|
|
233
|
+
const p_digits = p;
|
|
234
|
+
while (to_digit(s.at(p)) < radix)
|
|
235
|
+
p++;
|
|
236
|
+
/* parseInt is exact for the radixes 2, 8 and 16 */
|
|
237
|
+
d = parseInt(s.buf.substring(p_digits, p), radix);
|
|
238
|
+
if (s.at(p_start) === 45)
|
|
239
|
+
d = -d;
|
|
240
|
+
break done;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (is_digit(s.at(p + 1)))
|
|
244
|
+
return json_parse_error_pos(s, p, 'Unexpected number');
|
|
269
245
|
}
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
246
|
+
while (is_digit(s.at(p)))
|
|
247
|
+
p++;
|
|
248
|
+
if (s.at(p) === 46 /* . */) {
|
|
249
|
+
p++;
|
|
250
|
+
if (!is_digit(s.at(p)))
|
|
251
|
+
return json_parse_error_pos(s, p, 'Unterminated fractional number');
|
|
252
|
+
while (is_digit(s.at(p)))
|
|
253
|
+
p++;
|
|
274
254
|
}
|
|
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)
|
|
255
|
+
if (s.at(p) === 101 /* e */ || s.at(p) === 69 /* E */) {
|
|
284
256
|
p++;
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
((
|
|
290
|
-
|
|
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
|
-
}
|
|
257
|
+
if (s.at(p) === 43 || s.at(p) === 45)
|
|
258
|
+
p++;
|
|
259
|
+
if (!is_digit(s.at(p)))
|
|
260
|
+
return json_parse_error_pos(s, p, 'Exponent part is missing a number');
|
|
261
|
+
while (is_digit(s.at(p)))
|
|
262
|
+
p++;
|
|
299
263
|
}
|
|
264
|
+
d = Number(s.buf.substring(p_start, p));
|
|
300
265
|
}
|
|
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
266
|
s.tok = -3 /* JSONTok.NUMBER */;
|
|
317
267
|
s.tok_num = d;
|
|
318
268
|
s.buf_ptr = p;
|
|
@@ -399,16 +349,14 @@ function json_next_token(s) {
|
|
|
399
349
|
}
|
|
400
350
|
break; /* def_token */
|
|
401
351
|
case 43: /* + */
|
|
402
|
-
if (!s.ext_json
|
|
352
|
+
if (!s.ext_json)
|
|
403
353
|
break;
|
|
404
354
|
return json_parse_number(s, p);
|
|
405
|
-
case
|
|
406
|
-
if (is_digit(s.at(p + 1)))
|
|
355
|
+
case 46: /* . */
|
|
356
|
+
if (!s.ext_json || !is_digit(s.at(p + 1)))
|
|
407
357
|
break;
|
|
408
358
|
return json_parse_number(s, p);
|
|
409
359
|
case 45: /* - */
|
|
410
|
-
if (!is_digit(s.at(p + 1)))
|
|
411
|
-
break;
|
|
412
360
|
return json_parse_number(s, p);
|
|
413
361
|
default:
|
|
414
362
|
if (is_digit(c))
|
|
@@ -449,7 +397,13 @@ function json_parse_expect(s, tok) {
|
|
|
449
397
|
}
|
|
450
398
|
/* current token (through a function so that TypeScript does not narrow s.tok) */
|
|
451
399
|
function cur_tok(s) { return s.tok; }
|
|
452
|
-
function
|
|
400
|
+
function json_parse_record_init_primitive(s, pr, val) {
|
|
401
|
+
pr.value = val;
|
|
402
|
+
pr.source_pos = s.tok_ptr;
|
|
403
|
+
pr.source_len = s.buf_ptr - s.tok_ptr;
|
|
404
|
+
}
|
|
405
|
+
/* 'pr' can be null */
|
|
406
|
+
function json_parse_value(s, depth, pr) {
|
|
453
407
|
const ctx = s.ctx;
|
|
454
408
|
let val = null;
|
|
455
409
|
if (depth > ctx.rt.max_stack_depth)
|
|
@@ -463,6 +417,10 @@ function json_parse_value(s, depth) {
|
|
|
463
417
|
val = JS_NewObject(ctx);
|
|
464
418
|
if (JS_IsException(val))
|
|
465
419
|
return val;
|
|
420
|
+
if (pr) {
|
|
421
|
+
pr.value = val;
|
|
422
|
+
pr.entries = new Map();
|
|
423
|
+
}
|
|
466
424
|
if (cur_tok(s) !== 125 /* } */) {
|
|
467
425
|
for (;;) {
|
|
468
426
|
let prop_name;
|
|
@@ -482,7 +440,12 @@ function json_parse_value(s, depth) {
|
|
|
482
440
|
return JS_EXCEPTION;
|
|
483
441
|
if (json_parse_expect(s, 58 /* : */))
|
|
484
442
|
return JS_EXCEPTION;
|
|
485
|
-
|
|
443
|
+
let pr1 = null;
|
|
444
|
+
if (pr) {
|
|
445
|
+
pr1 = { value: undefined };
|
|
446
|
+
pr.entries.set(prop_name, pr1);
|
|
447
|
+
}
|
|
448
|
+
const prop_val = json_parse_value(s, depth + 1, pr1);
|
|
486
449
|
if (JS_IsException(prop_val))
|
|
487
450
|
return JS_EXCEPTION;
|
|
488
451
|
const ret = JS_DefinePropertyValue(ctx, val, prop_name, prop_val, JS_PROP_C_W_E);
|
|
@@ -507,10 +470,19 @@ function json_parse_value(s, depth) {
|
|
|
507
470
|
val = JS_NewArray(ctx);
|
|
508
471
|
if (JS_IsException(val))
|
|
509
472
|
return val;
|
|
473
|
+
if (pr) {
|
|
474
|
+
pr.value = val;
|
|
475
|
+
pr.elements = [];
|
|
476
|
+
}
|
|
510
477
|
if (cur_tok(s) !== 93 /* ] */) {
|
|
511
478
|
let idx = 0;
|
|
512
479
|
for (;;) {
|
|
513
|
-
|
|
480
|
+
let pr1 = null;
|
|
481
|
+
if (pr) {
|
|
482
|
+
pr1 = { value: undefined };
|
|
483
|
+
pr.elements.push(pr1);
|
|
484
|
+
}
|
|
485
|
+
const el = json_parse_value(s, depth + 1, pr1);
|
|
514
486
|
if (JS_IsException(el))
|
|
515
487
|
return JS_EXCEPTION;
|
|
516
488
|
const ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
|
|
@@ -531,20 +503,36 @@ function json_parse_value(s, depth) {
|
|
|
531
503
|
break;
|
|
532
504
|
case -2 /* JSONTok.STRING */:
|
|
533
505
|
val = s.tok_str;
|
|
506
|
+
if (pr)
|
|
507
|
+
json_parse_record_init_primitive(s, pr, val);
|
|
534
508
|
if (json_next_token(s))
|
|
535
509
|
return JS_EXCEPTION;
|
|
536
510
|
break;
|
|
537
511
|
case -3 /* JSONTok.NUMBER */:
|
|
538
512
|
val = s.tok_num;
|
|
513
|
+
if (pr)
|
|
514
|
+
json_parse_record_init_primitive(s, pr, val);
|
|
539
515
|
if (json_next_token(s))
|
|
540
516
|
return JS_EXCEPTION;
|
|
541
517
|
break;
|
|
542
518
|
case -4 /* JSONTok.IDENT */:
|
|
543
519
|
if (s.tok_atom === JS_ATOM_false || s.tok_atom === JS_ATOM_true) {
|
|
544
520
|
val = (s.tok_atom === JS_ATOM_true);
|
|
521
|
+
if (pr)
|
|
522
|
+
json_parse_record_init_primitive(s, pr, val);
|
|
545
523
|
}
|
|
546
524
|
else if (s.tok_atom === JS_ATOM_null) {
|
|
547
525
|
val = null;
|
|
526
|
+
if (pr)
|
|
527
|
+
json_parse_record_init_primitive(s, pr, val);
|
|
528
|
+
}
|
|
529
|
+
else if (s.tok_atom === JS_ATOM_NaN && s.ext_json) {
|
|
530
|
+
/* Note: json5 identifier handling is ambiguous e.g. is
|
|
531
|
+
'{ NaN: 1 }' a valid JSON5 production ? */
|
|
532
|
+
val = NaN;
|
|
533
|
+
}
|
|
534
|
+
else if (s.tok_atom === JS_ATOM_Infinity && s.ext_json) {
|
|
535
|
+
val = Infinity;
|
|
548
536
|
}
|
|
549
537
|
else {
|
|
550
538
|
return json_unexpected_token(s);
|
|
@@ -566,12 +554,13 @@ function json_unexpected_token(s) {
|
|
|
566
554
|
}
|
|
567
555
|
return JS_EXCEPTION;
|
|
568
556
|
}
|
|
569
|
-
|
|
557
|
+
/* 'pr' (can be null) receives the parse record of the value */
|
|
558
|
+
export function JS_ParseJSON3(ctx, buf, filename, flags, pr) {
|
|
570
559
|
const s = new JSONParseState(ctx, buf, filename);
|
|
571
560
|
s.ext_json = (flags & JS_PARSE_JSON_EXT) !== 0;
|
|
572
561
|
if (json_next_token(s))
|
|
573
562
|
return JS_EXCEPTION;
|
|
574
|
-
const val = json_parse_value(s, 0);
|
|
563
|
+
const val = json_parse_value(s, 0, pr);
|
|
575
564
|
if (JS_IsException(val))
|
|
576
565
|
return val;
|
|
577
566
|
if (s.tok !== -1 /* JSONTok.EOF */) {
|
|
@@ -580,18 +569,36 @@ export function JS_ParseJSON2(ctx, buf, filename, flags) {
|
|
|
580
569
|
}
|
|
581
570
|
return val;
|
|
582
571
|
}
|
|
572
|
+
export function JS_ParseJSON2(ctx, buf, filename, flags) {
|
|
573
|
+
return JS_ParseJSON3(ctx, buf, filename, flags, null);
|
|
574
|
+
}
|
|
583
575
|
export function JS_ParseJSON(ctx, buf, filename) {
|
|
584
576
|
return JS_ParseJSON2(ctx, buf, filename, 0);
|
|
585
577
|
}
|
|
586
578
|
/* ---------------------------------------------------------------------
|
|
587
579
|
JSON.parse
|
|
588
580
|
--------------------------------------------------------------------- */
|
|
589
|
-
|
|
581
|
+
/* if pr !== null, then pr.value === holder by construction */
|
|
582
|
+
function internalize_json_property(ctx, holder, name, reviver, text_str, pr, depth) {
|
|
590
583
|
if (depth > ctx.rt.max_stack_depth)
|
|
591
584
|
return JS_ThrowStackOverflow(ctx);
|
|
592
585
|
const val = JS_GetProperty(ctx, holder, name);
|
|
593
586
|
if (JS_IsException(val))
|
|
594
587
|
return val;
|
|
588
|
+
if (pr) {
|
|
589
|
+
if (pr.elements) {
|
|
590
|
+
pr = __JS_AtomIsTaggedInt(name) ? (pr.elements[__JS_AtomToUInt32(name)] ?? null) : null;
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
pr = pr.entries?.get(name) ?? null;
|
|
594
|
+
}
|
|
595
|
+
/* the source text is only given for an unmodified value */
|
|
596
|
+
if (pr && !js_same_value(ctx, pr.value, val))
|
|
597
|
+
pr = null;
|
|
598
|
+
}
|
|
599
|
+
const context = JS_NewObject(ctx);
|
|
600
|
+
if (JS_IsException(context))
|
|
601
|
+
return JS_EXCEPTION;
|
|
595
602
|
if (JS_IsObject(val)) {
|
|
596
603
|
const is_array = JS_IsArray(ctx, val);
|
|
597
604
|
if (is_array < 0)
|
|
@@ -617,7 +624,7 @@ function internalize_json_property(ctx, holder, name, reviver, depth) {
|
|
|
617
624
|
else {
|
|
618
625
|
prop = atoms[i].atom;
|
|
619
626
|
}
|
|
620
|
-
const new_el = internalize_json_property(ctx, val, prop, reviver, depth + 1);
|
|
627
|
+
const new_el = internalize_json_property(ctx, val, prop, reviver, text_str, pr, depth + 1);
|
|
621
628
|
if (JS_IsException(new_el))
|
|
622
629
|
return JS_EXCEPTION;
|
|
623
630
|
let ret;
|
|
@@ -631,36 +638,89 @@ function internalize_json_property(ctx, holder, name, reviver, depth) {
|
|
|
631
638
|
return JS_EXCEPTION;
|
|
632
639
|
}
|
|
633
640
|
}
|
|
641
|
+
else if (pr) {
|
|
642
|
+
const source = text_str.substring(pr.source_pos, pr.source_pos + pr.source_len);
|
|
643
|
+
if (JS_DefinePropertyValueStr(ctx, context, 'source', source, JS_PROP_C_W_E) < 0)
|
|
644
|
+
return JS_EXCEPTION;
|
|
645
|
+
}
|
|
634
646
|
const name_val = JS_AtomToValue(ctx, name);
|
|
635
647
|
if (JS_IsException(name_val))
|
|
636
648
|
return JS_EXCEPTION;
|
|
637
|
-
return JS_Call(ctx, reviver, holder, [name_val, val]);
|
|
649
|
+
return JS_Call(ctx, reviver, holder, [name_val, val, context]);
|
|
638
650
|
}
|
|
639
651
|
function js_json_parse(ctx, this_val, argv) {
|
|
640
652
|
const str = JS_ToString(ctx, argv[0]);
|
|
641
653
|
if (JS_IsException(str))
|
|
642
654
|
return JS_EXCEPTION;
|
|
655
|
+
if (argv.length > 1 && JS_IsFunction(ctx, argv[1])) {
|
|
656
|
+
/* the ported parser, which keeps the parse records giving the reviver
|
|
657
|
+
the source text of the primitives (its third argument) */
|
|
658
|
+
const reviver = argv[1];
|
|
659
|
+
const root = JS_NewObject(ctx);
|
|
660
|
+
if (JS_IsException(root))
|
|
661
|
+
return JS_EXCEPTION;
|
|
662
|
+
const pr1 = { value: undefined };
|
|
663
|
+
const pr = { value: root, entries: new Map([[JS_ATOM_empty_string, pr1]]) };
|
|
664
|
+
const obj = JS_ParseJSON3(ctx, str, '<input>', 0, pr1);
|
|
665
|
+
if (JS_IsException(obj))
|
|
666
|
+
return obj;
|
|
667
|
+
if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj, JS_PROP_C_W_E) < 0)
|
|
668
|
+
return JS_EXCEPTION;
|
|
669
|
+
return internalize_json_property(ctx, root, JS_ATOM_empty_string, reviver, str, pr, 0);
|
|
670
|
+
}
|
|
643
671
|
/* fast path: the host parser, with the tree re-prototyped to the guest
|
|
644
672
|
intrinsics. On a syntax error the ported parser runs to produce the
|
|
645
673
|
QuickJS error (message, line and column). */
|
|
646
|
-
let obj;
|
|
647
674
|
try {
|
|
648
|
-
|
|
675
|
+
return fix_deep_json(ctx, JSON.parse(str));
|
|
649
676
|
}
|
|
650
677
|
catch {
|
|
651
|
-
|
|
678
|
+
return JS_ParseJSON(ctx, str, '<input>');
|
|
652
679
|
}
|
|
680
|
+
}
|
|
681
|
+
/* JSON.rawJSON objects. The host's are used when it has them, so that the
|
|
682
|
+
host serializer of the JSON.stringify fast path emits their text;
|
|
683
|
+
otherwise they are null-prototype objects recorded here, and
|
|
684
|
+
JSON.stringify uses the ported serializer once one exists. */
|
|
685
|
+
/* (exported so that a test can run without the host functions) */
|
|
686
|
+
export const json_host_raw = {
|
|
687
|
+
rawJSON: JSON.rawJSON,
|
|
688
|
+
isRawJSON: JSON.isRawJSON,
|
|
689
|
+
};
|
|
690
|
+
const guest_raw_json = new WeakSet();
|
|
691
|
+
let guest_raw_json_used = false;
|
|
692
|
+
function js_is_raw_json(v) {
|
|
693
|
+
if (!Q.JS_IsObject(v))
|
|
694
|
+
return false;
|
|
695
|
+
if (json_host_raw.isRawJSON && json_host_raw.isRawJSON(v))
|
|
696
|
+
return true;
|
|
697
|
+
return guest_raw_json_used && guest_raw_json.has(v);
|
|
698
|
+
}
|
|
699
|
+
function js_json_isRawJSON(ctx, this_val, argv) {
|
|
700
|
+
return js_is_raw_json(argv[0]);
|
|
701
|
+
}
|
|
702
|
+
function is_valid_raw_json_char(c) {
|
|
703
|
+
return (c >= 97 && c <= 122) || (c >= 48 && c <= 57) || c === 45 /* - */ || c === 34 /* " */;
|
|
704
|
+
}
|
|
705
|
+
function js_json_rawJSON(ctx, this_val, argv) {
|
|
706
|
+
const str = JS_ToString(ctx, argv[0]);
|
|
707
|
+
if (JS_IsException(str))
|
|
708
|
+
return str;
|
|
709
|
+
const s = str;
|
|
710
|
+
if (s.length === 0 || !is_valid_raw_json_char(s.charCodeAt(0)) || !is_valid_raw_json_char(s.charCodeAt(s.length - 1)) ||
|
|
711
|
+
JS_IsException(js_json_parse(ctx, undefined, [s]))) {
|
|
712
|
+
return JS_ThrowSyntaxError(ctx, 'invalid rawJSON string');
|
|
713
|
+
}
|
|
714
|
+
if (json_host_raw.rawJSON)
|
|
715
|
+
return json_host_raw.rawJSON(s);
|
|
716
|
+
const obj = Q.JS_NewObjectProtoClass(ctx, null, 1 /* JSClassID.OBJECT */);
|
|
653
717
|
if (JS_IsException(obj))
|
|
654
718
|
return obj;
|
|
655
|
-
if (
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
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
|
-
}
|
|
719
|
+
if (JS_DefinePropertyValueStr(ctx, obj, 'rawJSON', s, JS_PROP_ENUMERABLE) < 0)
|
|
720
|
+
return JS_EXCEPTION;
|
|
721
|
+
Q.JS_PreventExtensions(ctx, obj);
|
|
722
|
+
guest_raw_json.add(obj);
|
|
723
|
+
guest_raw_json_used = true;
|
|
664
724
|
return obj;
|
|
665
725
|
}
|
|
666
726
|
function js_json_check(ctx, jsc, holder, val, key) {
|
|
@@ -721,10 +781,17 @@ function js_json_to_str(ctx, jsc, holder, val, indent, depth) {
|
|
|
721
781
|
if (JS_IsException(val))
|
|
722
782
|
return -1;
|
|
723
783
|
}
|
|
724
|
-
else if (cl === 6 /* JSClassID.BOOLEAN */ || cl ===
|
|
784
|
+
else if (cl === 6 /* JSClassID.BOOLEAN */ || cl === 34 /* JSClassID.BIG_INT */) {
|
|
725
785
|
/* This will throw the same error as for the primitive object */
|
|
726
786
|
val = Q.JS_GetAnyOpaque(p);
|
|
727
787
|
}
|
|
788
|
+
else if (js_is_raw_json(p)) {
|
|
789
|
+
const raw = Q.JS_GetPropertyStr(ctx, p, 'rawJSON');
|
|
790
|
+
if (JS_IsException(raw))
|
|
791
|
+
return -1;
|
|
792
|
+
jsc.b.push(String(raw));
|
|
793
|
+
return 0;
|
|
794
|
+
}
|
|
728
795
|
else {
|
|
729
796
|
if (jsc.stack.includes(p)) {
|
|
730
797
|
JS_ThrowTypeError(ctx, 'circular reference');
|
|
@@ -959,18 +1026,23 @@ function js_json_stringify(ctx, this_val, argv) {
|
|
|
959
1026
|
/* fast path: the host serializer (toJSON/replacer are guest functions,
|
|
960
1027
|
called natively). A host TypeError (BigInt, cycle) is reported by the
|
|
961
1028
|
ported serializer with the QuickJS message; guest exceptions thrown by
|
|
962
|
-
toJSON/replacer/getters propagate.
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1029
|
+
toJSON/replacer/getters propagate. The host serializer does not know
|
|
1030
|
+
the guest's own JSON.rawJSON objects (made when the host has none). */
|
|
1031
|
+
if (!guest_raw_json_used) {
|
|
1032
|
+
try {
|
|
1033
|
+
return JSON.stringify(argv[0], argv[1], argv[2]);
|
|
1034
|
+
}
|
|
1035
|
+
catch (e) {
|
|
1036
|
+
if (!(e instanceof TypeError))
|
|
1037
|
+
return Q.js_host_exception_to_guest(ctx, e);
|
|
1038
|
+
}
|
|
969
1039
|
}
|
|
970
1040
|
return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);
|
|
971
1041
|
}
|
|
972
1042
|
const js_json_funcs = [
|
|
1043
|
+
JS_CFUNC_DEF('isRawJSON', 1, js_json_isRawJSON),
|
|
973
1044
|
JS_CFUNC_DEF('parse', 2, js_json_parse),
|
|
1045
|
+
JS_CFUNC_DEF('rawJSON', 1, js_json_rawJSON),
|
|
974
1046
|
JS_CFUNC_DEF('stringify', 3, js_json_stringify),
|
|
975
1047
|
JS_PROP_STRING_DEF(JS_ATOM_Symbol_toStringTag, 'JSON', JS_PROP_CONFIGURABLE),
|
|
976
1048
|
];
|