From: Fabrice Bellard Date: Sat, 24 Oct 2026 11:21:43 +0000 (+0200) Subject: fixed pretty printing of Symbol property names and added tests X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=cac7287314e99a3f6dc9272f3c3311823f5f10cc;p=quickjs.git fixed pretty printing of Symbol property names and added tests --- diff --git a/quickjs-libc.c b/quickjs-libc.c index 26e9683..70c27eb 100644 --- a/quickjs-libc.c +++ b/quickjs-libc.c @@ -1213,6 +1213,31 @@ static JSValue js_std_file_printObject(JSContext *ctx, JSValueConst this_val, return JS_UNDEFINED; } +/* for testing only */ + +static void js_sprint_value_write(void *opaque, const char *buf, size_t len) +{ + DynBuf *dbuf = opaque; + dbuf_put(dbuf, (const uint8_t *)buf, len); +} + +static JSValue js_std_file_sprintObject(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv) +{ + DynBuf dbuf; + JSValue res; + + dbuf_init2(&dbuf, JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt); + JS_PrintValue(ctx, js_sprint_value_write, &dbuf, argv[0], NULL); + if (dbuf_error(&dbuf)) { + res = JS_ThrowOutOfMemory(ctx); + } else { + res = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size); + } + dbuf_free(&dbuf); + return res; +} + static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -1671,6 +1696,7 @@ static const JSCFunctionListEntry js_std_funcs[] = { JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ), JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE), JS_CFUNC_DEF("__printObject", 1, js_std_file_printObject ), + JS_CFUNC_DEF("__sprintObject", 1, js_std_file_sprintObject ), }; static const JSCFunctionListEntry js_std_file_proto_funcs[] = { diff --git a/quickjs.c b/quickjs.c index 84f35f5..f85997e 100644 --- a/quickjs.c +++ b/quickjs.c @@ -13995,7 +13995,7 @@ static BOOL is_ascii_ident(const JSString *p) return TRUE; } -static void js_print_atom(JSPrintValueState *s, JSAtom atom) +static void js_print_atom2(JSPrintValueState *s, JSAtom atom, BOOL is_property_name) { int i; if (__JS_AtomIsTaggedInt(atom)) { @@ -14006,7 +14006,16 @@ static void js_print_atom(JSPrintValueState *s, JSAtom atom) assert(atom < s->rt->atom_size); JSString *p; p = s->rt->atom_array[atom]; - if (is_ascii_ident(p)) { + if (p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL || + p->atom_type == JS_ATOM_TYPE_SYMBOL) { + if (is_property_name) + js_putc(s, '['); + js_puts(s, "Symbol(\""); + js_print_string1(s, p, p->len, '\"'); + js_puts(s, "\")"); + if (is_property_name) + js_putc(s, ']'); + } else if (is_ascii_ident(p)) { for(i = 0; i < p->len; i++) { js_putc(s, string_get(p, i)); } @@ -14018,6 +14027,11 @@ static void js_print_atom(JSPrintValueState *s, JSAtom atom) } } +static void js_print_atom(JSPrintValueState *s, JSAtom atom) +{ + js_print_atom2(s, atom, FALSE); +} + /* return 0 if invalid length */ static uint32_t js_print_array_get_length(JSObject *p) { @@ -14332,7 +14346,7 @@ static void js_print_object(JSPrintValueState *s, JSObject *p) if (j < s->options.max_item_count) { pr = &p->prop[i]; js_print_comma(s, &comma_state); - js_print_atom(s, prs->atom); + js_print_atom2(s, prs->atom, TRUE); js_printf(s, ": "); /* XXX: autoinit property */ @@ -14525,9 +14539,7 @@ static void js_print_value(JSPrintValueState *s, JSValueConst val) case JS_TAG_SYMBOL: { JSAtomStruct *p = JS_VALUE_GET_PTR(val); - js_puts(s, "Symbol("); js_print_atom(s, js_get_atom_index(s->rt, p)); - js_putc(s, ')'); } break; case JS_TAG_MODULE: diff --git a/tests/test_std.js b/tests/test_std.js index 3debe40..98ac010 100644 --- a/tests/test_std.js +++ b/tests/test_std.js @@ -322,6 +322,53 @@ function test_async_promise_rejection() os.setTimeout(() => { assert(counter, 3) }, 10); } +function remove_line_nums(s) +{ + return s.replace(/:[0-9]+/g, "") +} + +function test_print_value() +{ + var v; + + v = {x:1, y:1}; + Object.defineProperty(v, "z", { value: 3, writable: true, configurable: true, enumerable: false }); + + assert(std.__sprintObject(v), "{ x: 1, y: 1 }"); + assert(std.__sprintObject([1, 2, 3]), "[ 1, 2, 3 ]"); + assert(std.__sprintObject(-123456789321321323n), "-123456789321321323n"); + assert(std.__sprintObject(Symbol("test")), 'Symbol("test")'); + assert(std.__sprintObject({[Symbol("test")]:1, y: 2}), '{ [Symbol("test")]: 1, y: 2 }'); + + v = [1, 2, 3]; + v.x = 4; + assert(std.__sprintObject(v), "[ 1, 2, 3, x: 4 ]"); + + v = Error("test"); + assert(remove_line_nums(std.__sprintObject(v)), "Error: test\n at test_print_value (tests/test_std.js)\n at (tests/test_std.js)"); + + v = new Int32Array([1, 2, 3]); + assert(std.__sprintObject(v), "Int32Array(3) [ 1, 2, 3 ]"); + + v = new Date(1506098258091); + assert(std.__sprintObject(v), "2017-09-22T16:37:38.091Z"); + + v = new Map(); + v.set("x", 1); + v.set("y", 1); + v.set(2, 3); + assert(std.__sprintObject(v), 'Map(3) { "x" => 1, "y" => 1, 2 => 3 }'); + + v = new Set(); + v.add("x"); + v.add(2); + assert(std.__sprintObject(v), 'Set(2) { "x", 2 }'); + + v = /abc[0-9]/; + assert(std.__sprintObject(v), '/abc[0-9]/'); +} + + test_printf(); test_file1(); test_file2(); @@ -333,4 +380,4 @@ test_timer(); test_ext_json(); test_async_gc(); test_async_promise_rejection(); - +test_print_value();