mirror of
https://github.com/bellard/quickjs.git
synced 2026-03-31 12:18:01 +00:00
added JSON.parse source text access
Some checks failed
ci / Linux (Ubuntu) (push) Has been cancelled
ci / Linux LTO (push) Has been cancelled
ci / Linux 32bit (push) Has been cancelled
ci / linux-asan (push) Has been cancelled
ci / linux-msan (push) Has been cancelled
ci / linux-ubsan (push) Has been cancelled
ci / macOS (push) Has been cancelled
ci / macos-asan (push) Has been cancelled
ci / macos-ubsan (push) Has been cancelled
ci / freebsd (push) Has been cancelled
ci / Cosmopolitan (push) Has been cancelled
ci / MinGW Windows target (push) Has been cancelled
ci / Windows MSYS2 (push) Has been cancelled
ci / qemu-alpine (linux/386) (push) Has been cancelled
ci / qemu-alpine (linux/arm/v6) (push) Has been cancelled
ci / qemu-alpine (linux/arm/v7) (push) Has been cancelled
ci / qemu-alpine (linux/arm64) (push) Has been cancelled
ci / qemu-alpine (linux/ppc64le) (push) Has been cancelled
ci / qemu-alpine (linux/riscv64) (push) Has been cancelled
ci / qemu-alpine (linux/s390x) (push) Has been cancelled
Some checks failed
ci / Linux (Ubuntu) (push) Has been cancelled
ci / Linux LTO (push) Has been cancelled
ci / Linux 32bit (push) Has been cancelled
ci / linux-asan (push) Has been cancelled
ci / linux-msan (push) Has been cancelled
ci / linux-ubsan (push) Has been cancelled
ci / macOS (push) Has been cancelled
ci / macos-asan (push) Has been cancelled
ci / macos-ubsan (push) Has been cancelled
ci / freebsd (push) Has been cancelled
ci / Cosmopolitan (push) Has been cancelled
ci / MinGW Windows target (push) Has been cancelled
ci / Windows MSYS2 (push) Has been cancelled
ci / qemu-alpine (linux/386) (push) Has been cancelled
ci / qemu-alpine (linux/arm/v6) (push) Has been cancelled
ci / qemu-alpine (linux/arm/v7) (push) Has been cancelled
ci / qemu-alpine (linux/arm64) (push) Has been cancelled
ci / qemu-alpine (linux/ppc64le) (push) Has been cancelled
ci / qemu-alpine (linux/riscv64) (push) Has been cancelled
ci / qemu-alpine (linux/s390x) (push) Has been cancelled
This commit is contained in:
parent
a31dcef98c
commit
d7ae12ae71
2
TODO
2
TODO
@ -63,4 +63,4 @@ Test262o: 0/11262 errors, 463 excluded
|
||||
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
|
||||
|
||||
Test262:
|
||||
Result: 60/83394 errors, 3348 excluded, 6090 skipped
|
||||
Result: 60/83436 errors, 3348 excluded, 6069 skipped
|
||||
|
||||
@ -147,6 +147,7 @@ DEF(flags, "flags")
|
||||
DEF(global, "global")
|
||||
DEF(unicode, "unicode")
|
||||
DEF(raw, "raw")
|
||||
DEF(rawJSON, "rawJSON")
|
||||
DEF(new_target, "new.target")
|
||||
DEF(this_active_func, "this.active_func")
|
||||
DEF(home_object, "<home_object>")
|
||||
|
||||
403
quickjs.c
403
quickjs.c
@ -168,6 +168,7 @@ enum {
|
||||
JS_CLASS_REGEXP_STRING_ITERATOR, /* u.regexp_string_iterator_data */
|
||||
JS_CLASS_GENERATOR, /* u.generator_data */
|
||||
JS_CLASS_GLOBAL_OBJECT, /* u.global_object */
|
||||
JS_CLASS_RAWJSON,
|
||||
JS_CLASS_PROXY, /* u.proxy_data */
|
||||
JS_CLASS_PROMISE, /* u.promise_data */
|
||||
JS_CLASS_PROMISE_RESOLVE_FUNCTION, /* u.promise_function_data */
|
||||
@ -1597,6 +1598,7 @@ static JSClassShortDef const js_std_class_def[] = {
|
||||
{ JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
|
||||
{ JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */
|
||||
{ JS_ATOM_Object, js_global_object_finalizer, js_global_object_mark }, /* JS_CLASS_GLOBAL_OBJECT */
|
||||
{ JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_RAWJSON */
|
||||
};
|
||||
|
||||
static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,
|
||||
@ -21571,7 +21573,7 @@ typedef struct JSParseState {
|
||||
JSFunctionDef *cur_func;
|
||||
BOOL is_module; /* parsing a module */
|
||||
BOOL allow_html_comments;
|
||||
BOOL ext_json; /* true if accepting JSON superset */
|
||||
BOOL ext_json; /* JSON parsing: true if accepting JSON superset */
|
||||
GetLineColCache get_line_col_cache;
|
||||
} JSParseState;
|
||||
|
||||
@ -48629,23 +48631,189 @@ static int json_parse_expect(JSParseState *s, int tok)
|
||||
return json_next_token(s);
|
||||
}
|
||||
|
||||
static JSValue json_parse_value(JSParseState *s)
|
||||
|
||||
typedef struct {
|
||||
int count;
|
||||
uint32_t hash_size;
|
||||
struct JSONParseRecordEntry *entries;
|
||||
uint32_t *hash_table;
|
||||
} JSONParseRecordObject;
|
||||
|
||||
typedef struct JSONParseRecord {
|
||||
JSValue value;
|
||||
union {
|
||||
JSONParseRecordObject obj;
|
||||
struct {
|
||||
int count;
|
||||
struct JSONParseRecord *elements;
|
||||
} array;
|
||||
struct {
|
||||
uint32_t source_pos;
|
||||
uint32_t source_len;
|
||||
} primitive;
|
||||
} u;
|
||||
} JSONParseRecord;
|
||||
|
||||
typedef struct JSONParseRecordEntry {
|
||||
JSAtom atom;
|
||||
uint32_t hash_next;
|
||||
JSONParseRecord parse_record;
|
||||
} JSONParseRecordEntry;
|
||||
|
||||
static void json_parse_record_init_obj(JSContext *ctx, JSONParseRecord *pr, JSValueConst val)
|
||||
{
|
||||
pr->value = JS_DupValue(ctx, val);
|
||||
pr->u.obj.count = 0;
|
||||
pr->u.obj.entries = NULL;
|
||||
pr->u.obj.hash_table = NULL;
|
||||
pr->u.obj.hash_size = 0;
|
||||
}
|
||||
|
||||
static void json_parse_record_init_array(JSContext *ctx, JSONParseRecord *pr, JSValueConst val)
|
||||
{
|
||||
pr->value = JS_DupValue(ctx, val);
|
||||
pr->u.array.count = 0;
|
||||
pr->u.array.elements = NULL;
|
||||
}
|
||||
|
||||
static void json_parse_record_init_primitive(JSContext *ctx, JSONParseRecord *pr, JSValueConst val,
|
||||
uint32_t source_pos, uint32_t source_len)
|
||||
{
|
||||
pr->value = JS_DupValue(ctx, val);
|
||||
pr->u.primitive.source_pos = source_pos;
|
||||
pr->u.primitive.source_len = source_len;
|
||||
}
|
||||
|
||||
static int json_parse_record_resize_hash(JSContext *ctx, JSONParseRecordObject *po, uint32_t new_hash_size)
|
||||
{
|
||||
uint32_t i, h, *new_hash_table;
|
||||
JSONParseRecordEntry *e;
|
||||
|
||||
new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
|
||||
if (!new_hash_table)
|
||||
return -1;
|
||||
js_free(ctx, po->hash_table);
|
||||
po->hash_table = new_hash_table;
|
||||
po->hash_size = new_hash_size;
|
||||
|
||||
for(i = 0; i < po->hash_size; i++) {
|
||||
po->hash_table[i] = -1;
|
||||
}
|
||||
for(i = 0; i < po->count; i++) {
|
||||
e = &po->entries[i];
|
||||
h = e->atom & (po->hash_size - 1);
|
||||
e->hash_next = po->hash_table[h];
|
||||
po->hash_table[h] = i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static JSONParseRecord *json_parse_record_add(JSContext *ctx, JSONParseRecord *pr, JSAtom key, int *psize)
|
||||
{
|
||||
JSONParseRecordObject *po = &pr->u.obj;
|
||||
JSONParseRecordEntry *e;
|
||||
JSONParseRecord *pr1;
|
||||
uint32_t h;
|
||||
|
||||
if (js_resize_array(ctx, (void **)&po->entries, sizeof(po->entries[0]),
|
||||
psize, po->count + 1)) {
|
||||
return NULL;
|
||||
}
|
||||
/* don't use a hash table when the number of entries is small */
|
||||
if (po->count >= 8 && (po->count + 1) > po->hash_size) {
|
||||
int hash_bits = 32 - clz32(po->count);
|
||||
if (json_parse_record_resize_hash(ctx, po, 1 << hash_bits))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
e = &po->entries[po->count++];
|
||||
e->atom = JS_DupAtom(ctx, key);
|
||||
pr1 = &e->parse_record;
|
||||
pr1->value = JS_UNDEFINED;
|
||||
if (po->hash_size != 0) {
|
||||
h = key & (po->hash_size - 1);
|
||||
e->hash_next = po->hash_table[h];
|
||||
po->hash_table[h] = po->count - 1;
|
||||
}
|
||||
return pr1;
|
||||
}
|
||||
|
||||
static JSONParseRecord *json_parse_record_find(JSONParseRecord *pr, JSAtom key)
|
||||
{
|
||||
JSONParseRecordObject *po = &pr->u.obj;
|
||||
JSONParseRecordEntry *e;
|
||||
uint32_t h, i;
|
||||
|
||||
if (po->hash_size == 0) {
|
||||
for(i = 0; i < po->count; i++) {
|
||||
if (po->entries[i].atom == key)
|
||||
return &po->entries[i].parse_record;
|
||||
}
|
||||
} else {
|
||||
h = key & (po->hash_size - 1);
|
||||
i = po->hash_table[h];
|
||||
while (i != -1) {
|
||||
e = &po->entries[i];
|
||||
if (e->atom == key)
|
||||
return &e->parse_record;
|
||||
i = e->hash_next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void json_free_parse_record(JSContext *ctx, JSONParseRecord *pr)
|
||||
{
|
||||
int i;
|
||||
if (!pr)
|
||||
return;
|
||||
if (JS_IsObject(pr->value)) {
|
||||
if (JS_IsArray(ctx, pr->value)) {
|
||||
for(i = 0; i < pr->u.array.count; i++) {
|
||||
json_free_parse_record(ctx, &pr->u.array.elements[i]);
|
||||
}
|
||||
js_free(ctx, pr->u.array.elements);
|
||||
} else {
|
||||
for(i = 0; i < pr->u.obj.count; i++) {
|
||||
JS_FreeAtom(ctx, pr->u.obj.entries[i].atom);
|
||||
json_free_parse_record(ctx, &pr->u.obj.entries[i].parse_record);
|
||||
}
|
||||
js_free(ctx, pr->u.obj.entries);
|
||||
js_free(ctx, pr->u.obj.hash_table);
|
||||
}
|
||||
}
|
||||
JS_FreeValue(ctx, pr->value);
|
||||
pr->value = JS_UNDEFINED; /* fail safe */
|
||||
}
|
||||
|
||||
/* 'pr' can be NULL */
|
||||
static JSValue json_parse_value(JSParseState *s, JSONParseRecord *pr)
|
||||
{
|
||||
JSContext *ctx = s->ctx;
|
||||
JSValue val = JS_NULL;
|
||||
int ret;
|
||||
|
||||
if (pr) {
|
||||
pr->value = JS_UNDEFINED;
|
||||
}
|
||||
|
||||
switch(s->token.val) {
|
||||
case '{':
|
||||
{
|
||||
JSValue prop_val;
|
||||
JSAtom prop_name;
|
||||
|
||||
JSONParseRecord *pr1;
|
||||
int pr_size;
|
||||
|
||||
if (json_next_token(s))
|
||||
goto fail;
|
||||
val = JS_NewObject(ctx);
|
||||
if (JS_IsException(val))
|
||||
goto fail;
|
||||
if (pr) {
|
||||
json_parse_record_init_obj(ctx, pr, val);
|
||||
pr_size = 0;
|
||||
}
|
||||
if (s->token.val != '}') {
|
||||
for(;;) {
|
||||
if (s->token.val == TOK_STRING) {
|
||||
@ -48662,7 +48830,14 @@ static JSValue json_parse_value(JSParseState *s)
|
||||
goto fail1;
|
||||
if (json_parse_expect(s, ':'))
|
||||
goto fail1;
|
||||
prop_val = json_parse_value(s);
|
||||
if (pr) {
|
||||
pr1 = json_parse_record_add(ctx, pr, prop_name, &pr_size);
|
||||
if (!pr1)
|
||||
goto fail1;
|
||||
} else {
|
||||
pr1 = NULL;
|
||||
}
|
||||
prop_val = json_parse_value(s, pr1);
|
||||
if (JS_IsException(prop_val)) {
|
||||
fail1:
|
||||
JS_FreeAtom(ctx, prop_name);
|
||||
@ -48690,16 +48865,31 @@ static JSValue json_parse_value(JSParseState *s)
|
||||
{
|
||||
JSValue el;
|
||||
uint32_t idx;
|
||||
|
||||
JSONParseRecord *pr1;
|
||||
int pr_size;
|
||||
|
||||
if (json_next_token(s))
|
||||
goto fail;
|
||||
val = JS_NewArray(ctx);
|
||||
if (JS_IsException(val))
|
||||
goto fail;
|
||||
if (pr) {
|
||||
json_parse_record_init_array(ctx, pr, val);
|
||||
pr_size = 0;
|
||||
}
|
||||
if (s->token.val != ']') {
|
||||
idx = 0;
|
||||
for(;;) {
|
||||
el = json_parse_value(s);
|
||||
if (pr) {
|
||||
if (js_resize_array(ctx, (void **)&pr->u.array.elements, sizeof(pr->u.array.elements[0]),
|
||||
&pr_size, pr->u.array.count + 1))
|
||||
goto fail;
|
||||
pr1 = &pr->u.array.elements[pr->u.array.count++];
|
||||
pr1->value = JS_UNDEFINED;
|
||||
} else {
|
||||
pr1 = NULL;
|
||||
}
|
||||
el = json_parse_value(s, pr1);
|
||||
if (JS_IsException(el))
|
||||
goto fail;
|
||||
ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);
|
||||
@ -48720,11 +48910,21 @@ static JSValue json_parse_value(JSParseState *s)
|
||||
break;
|
||||
case TOK_STRING:
|
||||
val = JS_DupValue(ctx, s->token.u.str.str);
|
||||
if (pr) {
|
||||
json_parse_record_init_primitive(ctx, pr, val,
|
||||
s->token.ptr - s->buf_start,
|
||||
s->buf_ptr - s->token.ptr);
|
||||
}
|
||||
if (json_next_token(s))
|
||||
goto fail;
|
||||
break;
|
||||
case TOK_NUMBER:
|
||||
val = s->token.u.num.val;
|
||||
if (pr) {
|
||||
json_parse_record_init_primitive(ctx, pr, val,
|
||||
s->token.ptr - s->buf_start,
|
||||
s->buf_ptr - s->token.ptr);
|
||||
}
|
||||
if (json_next_token(s))
|
||||
goto fail;
|
||||
break;
|
||||
@ -48732,8 +48932,18 @@ static JSValue json_parse_value(JSParseState *s)
|
||||
if (s->token.u.ident.atom == JS_ATOM_false ||
|
||||
s->token.u.ident.atom == JS_ATOM_true) {
|
||||
val = JS_NewBool(ctx, s->token.u.ident.atom == JS_ATOM_true);
|
||||
if (pr) {
|
||||
json_parse_record_init_primitive(ctx, pr, val,
|
||||
s->token.ptr - s->buf_start,
|
||||
s->buf_ptr - s->token.ptr);
|
||||
}
|
||||
} else if (s->token.u.ident.atom == JS_ATOM_null) {
|
||||
val = JS_NULL;
|
||||
if (pr) {
|
||||
json_parse_record_init_primitive(ctx, pr, val,
|
||||
s->token.ptr - s->buf_start,
|
||||
s->buf_ptr - s->token.ptr);
|
||||
}
|
||||
} else if (s->token.u.ident.atom == JS_ATOM_NaN && s->ext_json) {
|
||||
/* Note: json5 identifier handling is ambiguous e.g. is
|
||||
'{ NaN: 1 }' a valid JSON5 production ? */
|
||||
@ -48758,12 +48968,13 @@ static JSValue json_parse_value(JSParseState *s)
|
||||
}
|
||||
return val;
|
||||
fail:
|
||||
json_free_parse_record(ctx, pr);
|
||||
JS_FreeValue(ctx, val);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
const char *filename, int flags)
|
||||
JSValue JS_ParseJSON3(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
const char *filename, int flags, JSONParseRecord *pr)
|
||||
{
|
||||
JSParseState s1, *s = &s1;
|
||||
JSValue val = JS_UNDEFINED;
|
||||
@ -48772,12 +48983,14 @@ JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
|
||||
if (json_next_token(s))
|
||||
goto fail;
|
||||
val = json_parse_value(s);
|
||||
val = json_parse_value(s, pr);
|
||||
if (JS_IsException(val))
|
||||
goto fail;
|
||||
if (s->token.val != TOK_EOF) {
|
||||
if (js_parse_error(s, "unexpected data at the end"))
|
||||
if (js_parse_error(s, "unexpected data at the end")) {
|
||||
json_free_parse_record(ctx, pr);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
fail:
|
||||
@ -48786,17 +48999,25 @@ JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
const char *filename, int flags)
|
||||
{
|
||||
return JS_ParseJSON3(ctx, buf, buf_len, filename, flags, NULL);
|
||||
}
|
||||
|
||||
JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
|
||||
const char *filename)
|
||||
{
|
||||
return JS_ParseJSON2(ctx, buf, buf_len, filename, 0);
|
||||
return JS_ParseJSON3(ctx, buf, buf_len, filename, 0, NULL);
|
||||
}
|
||||
|
||||
/* if pr != NULL, then pr->value = holder by construction */
|
||||
static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
|
||||
JSAtom name, JSValueConst reviver)
|
||||
JSAtom name, JSValueConst reviver,
|
||||
const char *text_str, JSONParseRecord *pr)
|
||||
{
|
||||
JSValue val, new_el, name_val, res;
|
||||
JSValueConst args[2];
|
||||
JSValue val, new_el, name_val, res, context;
|
||||
JSValueConst args[3];
|
||||
int ret, is_array;
|
||||
uint32_t i, len = 0;
|
||||
JSAtom prop;
|
||||
@ -48809,6 +49030,29 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
|
||||
val = JS_GetProperty(ctx, holder, name);
|
||||
if (JS_IsException(val))
|
||||
return val;
|
||||
|
||||
if (pr) {
|
||||
if (JS_IsArray(ctx, pr->value)) {
|
||||
if (__JS_AtomIsTaggedInt(name)) {
|
||||
uint32_t idx = __JS_AtomToUInt32(name);
|
||||
if (idx < pr->u.array.count) {
|
||||
pr = &pr->u.array.elements[idx];
|
||||
} else {
|
||||
pr = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pr = json_parse_record_find(pr, name);
|
||||
}
|
||||
if (pr && !js_same_value(ctx, pr->value, val)) {
|
||||
pr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
context = JS_NewObject(ctx);
|
||||
if (JS_IsException(context))
|
||||
goto fail;
|
||||
|
||||
if (JS_IsObject(val)) {
|
||||
is_array = JS_IsArray(ctx, val);
|
||||
if (is_array < 0)
|
||||
@ -48829,7 +49073,7 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
|
||||
} else {
|
||||
prop = JS_DupAtom(ctx, atoms[i].atom);
|
||||
}
|
||||
new_el = internalize_json_property(ctx, val, prop, reviver);
|
||||
new_el = internalize_json_property(ctx, val, prop, reviver, text_str, pr);
|
||||
if (JS_IsException(new_el)) {
|
||||
JS_FreeAtom(ctx, prop);
|
||||
goto fail;
|
||||
@ -48843,6 +49087,15 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
if (pr) {
|
||||
new_el = JS_NewStringLen(ctx, text_str + pr->u.primitive.source_pos,
|
||||
pr->u.primitive.source_len);
|
||||
if (JS_IsException(new_el))
|
||||
goto fail;
|
||||
if (JS_DefinePropertyValue(ctx, context, JS_ATOM_source, new_el, JS_PROP_C_W_E) < 0)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
JS_FreePropertyEnum(ctx, atoms, len);
|
||||
atoms = NULL;
|
||||
@ -48851,12 +49104,15 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
|
||||
goto fail;
|
||||
args[0] = name_val;
|
||||
args[1] = val;
|
||||
res = JS_Call(ctx, reviver, holder, 2, args);
|
||||
args[2] = context;
|
||||
res = JS_Call(ctx, reviver, holder, 3, args);
|
||||
JS_FreeValue(ctx, name_val);
|
||||
JS_FreeValue(ctx, val);
|
||||
JS_FreeValue(ctx, context);
|
||||
return res;
|
||||
fail:
|
||||
JS_FreePropertyEnum(ctx, atoms, len);
|
||||
JS_FreeValue(ctx, context);
|
||||
JS_FreeValue(ctx, val);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
@ -48864,37 +49120,113 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
|
||||
static JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JSValue obj, root;
|
||||
JSValueConst reviver;
|
||||
JSValue obj;
|
||||
const char *str;
|
||||
size_t len;
|
||||
|
||||
|
||||
str = JS_ToCStringLen(ctx, &len, argv[0]);
|
||||
if (!str)
|
||||
return JS_EXCEPTION;
|
||||
obj = JS_ParseJSON(ctx, str, len, "<input>");
|
||||
JS_FreeCString(ctx, str);
|
||||
if (JS_IsException(obj))
|
||||
return obj;
|
||||
if (argc > 1 && JS_IsFunction(ctx, argv[1])) {
|
||||
JSONParseRecord pr_s, *pr = &pr_s, *pr1;
|
||||
JSValue root;
|
||||
JSValueConst reviver;
|
||||
int size;
|
||||
|
||||
reviver = argv[1];
|
||||
root = JS_NewObject(ctx);
|
||||
if (JS_IsException(root)) {
|
||||
JS_FreeValue(ctx, obj);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
if (JS_IsException(root))
|
||||
goto fail;
|
||||
json_parse_record_init_obj(ctx, pr, root);
|
||||
size = 0;
|
||||
pr1 = json_parse_record_add(ctx, pr, JS_ATOM_empty_string, &size);
|
||||
if (!pr1)
|
||||
goto fail1;
|
||||
|
||||
obj = JS_ParseJSON3(ctx, str, len, "<input>", 0, pr1);
|
||||
if (JS_IsException(obj))
|
||||
goto fail1;
|
||||
|
||||
if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,
|
||||
JS_PROP_C_W_E) < 0) {
|
||||
JS_FreeValue(ctx, obj);
|
||||
fail1:
|
||||
json_free_parse_record(ctx, pr);
|
||||
JS_FreeValue(ctx, root);
|
||||
return JS_EXCEPTION;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,
|
||||
reviver);
|
||||
reviver, str, pr);
|
||||
json_free_parse_record(ctx, pr);
|
||||
JS_FreeValue(ctx, root);
|
||||
} else {
|
||||
obj = JS_ParseJSON3(ctx, str, len, "<input>", 0, NULL);
|
||||
}
|
||||
JS_FreeCString(ctx, str);
|
||||
return obj;
|
||||
fail:
|
||||
JS_FreeCString(ctx, str);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
static JSValue js_json_isRawJSON(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JSValueConst obj = argv[0];
|
||||
if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
|
||||
JSObject *p = JS_VALUE_GET_OBJ(obj);
|
||||
return JS_NewBool(ctx, p->class_id == JS_CLASS_RAWJSON);
|
||||
} else {
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL is_valid_raw_json_char(int c)
|
||||
{
|
||||
return ((c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
c == '-' ||
|
||||
c == '"');
|
||||
}
|
||||
|
||||
static JSValue js_json_rawJSON(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
JSValue str, res, obj;
|
||||
JSString *p;
|
||||
str = JS_ToString(ctx, argv[0]);
|
||||
if (JS_IsException(str))
|
||||
return str;
|
||||
p = JS_VALUE_GET_STRING(str);
|
||||
if (p->len == 0 ||
|
||||
!is_valid_raw_json_char(string_get(p, 0)) ||
|
||||
!is_valid_raw_json_char(string_get(p, p->len - 1))) {
|
||||
goto syntax_error;
|
||||
}
|
||||
res = js_json_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&str);
|
||||
if (JS_IsException(res)) {
|
||||
syntax_error:
|
||||
JS_ThrowSyntaxError(ctx, "invalid rawJSON string");
|
||||
goto fail;
|
||||
}
|
||||
JS_FreeValue(ctx, res);
|
||||
|
||||
obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_RAWJSON);
|
||||
if (JS_IsException(obj))
|
||||
goto fail;
|
||||
if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_rawJSON, str, JS_PROP_ENUMERABLE) < 0) {
|
||||
JS_FreeValue(ctx, obj);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
JS_PreventExtensions(ctx, obj);
|
||||
return obj;
|
||||
fail:
|
||||
JS_FreeValue(ctx, str);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
|
||||
typedef struct JSONStringifyContext {
|
||||
JSValueConst replacer_func;
|
||||
JSValue stack;
|
||||
@ -49064,11 +49396,18 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
|
||||
if (JS_IsException(val))
|
||||
goto exception;
|
||||
goto concat_primitive;
|
||||
} else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT)
|
||||
{
|
||||
} else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT) {
|
||||
/* This will thow the same error as for the primitive object */
|
||||
set_value(ctx, &val, JS_DupValue(ctx, p->u.object_data));
|
||||
goto concat_primitive;
|
||||
} else if (cl == JS_CLASS_RAWJSON) {
|
||||
JSValue val1;
|
||||
val1 = JS_GetProperty(ctx, val, JS_ATOM_rawJSON);
|
||||
if (JS_IsException(val1))
|
||||
goto exception;
|
||||
JS_FreeValue(ctx, val);
|
||||
val = val1;
|
||||
goto concat_value;
|
||||
}
|
||||
v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);
|
||||
if (JS_IsException(v))
|
||||
@ -49357,7 +49696,9 @@ static JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,
|
||||
}
|
||||
|
||||
static const JSCFunctionListEntry js_json_funcs[] = {
|
||||
JS_CFUNC_DEF("isRawJSON", 1, js_json_isRawJSON ),
|
||||
JS_CFUNC_DEF("parse", 2, js_json_parse ),
|
||||
JS_CFUNC_DEF("rawJSON", 1, js_json_rawJSON ),
|
||||
JS_CFUNC_DEF("stringify", 3, js_json_stringify ),
|
||||
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "JSON", JS_PROP_CONFIGURABLE ),
|
||||
};
|
||||
|
||||
@ -150,7 +150,7 @@ IsHTMLDDA
|
||||
iterator-helpers
|
||||
iterator-sequencing
|
||||
json-modules
|
||||
json-parse-with-source=skip
|
||||
json-parse-with-source
|
||||
json-superset
|
||||
legacy-regexp=skip
|
||||
let
|
||||
|
||||
Loading…
Reference in New Issue
Block a user