]> git.kaiwu.me - quickjs.git/commitdiff
fixed pretty printing of Symbol property names and added tests
authorFabrice Bellard <fabrice@bellard.org>
Sat, 24 Oct 2026 11:21:43 +0000 (13:21 +0200)
committerFabrice Bellard <fabrice@bellard.org>
Sat, 24 Oct 2026 11:21:43 +0000 (13:21 +0200)
quickjs-libc.c
quickjs.c
tests/test_std.js

index 26e9683a5d42088e8c57fd1f71e18878a3118af0..70c27eb264ae99d1eb66b15e66978a997adbfdc9 100644 (file)
@@ -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[] = {
index 84f35f5c8d54fd943b235eed92646700c015e172..f85997e9d398fa1b6eebd38d192a8e1e6ccda58d 100644 (file)
--- 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:
index 3debe4039b2d1ce60e5023af348a48d2c2c866cb..98ac010eae1fda6987bd11cb82892f318b76afc0 100644 (file)
@@ -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 <anonymous> (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();