mirror of
https://github.com/bellard/quickjs.git
synced 2025-09-27 05:38:45 +03:00
Compare commits
6 Commits
88179fb985
...
86f2c2fff1
Author | SHA1 | Date | |
---|---|---|---|
|
86f2c2fff1 | ||
|
8b43bae10b | ||
|
fa628f8c52 | ||
|
391cd3feff | ||
|
9f6c190731 | ||
|
8a0a6e92d2 |
17
.github/workflows/ci.yml
vendored
17
.github/workflows/ci.yml
vendored
@ -36,6 +36,10 @@ jobs:
|
|||||||
- name: Run microbench
|
- name: Run microbench
|
||||||
run: |
|
run: |
|
||||||
make microbench
|
make microbench
|
||||||
|
- name: Run test262
|
||||||
|
run: |
|
||||||
|
make test2-bootstrap
|
||||||
|
make test2
|
||||||
|
|
||||||
linux-lto:
|
linux-lto:
|
||||||
name: Linux LTO
|
name: Linux LTO
|
||||||
@ -138,6 +142,10 @@ jobs:
|
|||||||
- name: Run built-in tests
|
- name: Run built-in tests
|
||||||
run: |
|
run: |
|
||||||
make test
|
make test
|
||||||
|
- name: Run test262
|
||||||
|
run: |
|
||||||
|
make test2-bootstrap
|
||||||
|
make test2
|
||||||
|
|
||||||
macos-asan:
|
macos-asan:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
@ -172,7 +180,12 @@ jobs:
|
|||||||
- name: Build + test
|
- name: Build + test
|
||||||
uses: vmactions/freebsd-vm@v1
|
uses: vmactions/freebsd-vm@v1
|
||||||
with:
|
with:
|
||||||
|
# This VM has a tendency to get stuck in the "VM is booting" cycle
|
||||||
|
# for quite a while, so set a shorter timeout
|
||||||
|
timeout-minutes: 15
|
||||||
usesh: true
|
usesh: true
|
||||||
|
copyback: false
|
||||||
|
mem: 16384
|
||||||
prepare: |
|
prepare: |
|
||||||
pkg install -y gmake
|
pkg install -y gmake
|
||||||
run: |
|
run: |
|
||||||
@ -202,6 +215,10 @@ jobs:
|
|||||||
- name: Run built-in tests
|
- name: Run built-in tests
|
||||||
run: |
|
run: |
|
||||||
make CONFIG_COSMO=y test
|
make CONFIG_COSMO=y test
|
||||||
|
- name: Run test262
|
||||||
|
run: |
|
||||||
|
make test2-bootstrap
|
||||||
|
make CONFIG_COSMO=y test2
|
||||||
|
|
||||||
mingw-windows:
|
mingw-windows:
|
||||||
name: MinGW Windows target
|
name: MinGW Windows target
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
2025-09-13:
|
||||||
|
|
||||||
- added JSON modules and import attributes
|
- added JSON modules and import attributes
|
||||||
- added JS_PrintValue() API
|
- added JS_PrintValue() API
|
||||||
- qjs: pretty print objects in print() and console.log()
|
- qjs: pretty print objects in print() and console.log()
|
||||||
@ -12,6 +14,7 @@
|
|||||||
accept JSON5 modules
|
accept JSON5 modules
|
||||||
- added JS_FreePropertyEnum() and JS_AtomToCStringLen() API
|
- added JS_FreePropertyEnum() and JS_AtomToCStringLen() API
|
||||||
- added Error.isError()
|
- added Error.isError()
|
||||||
|
- misc bug fixes
|
||||||
|
|
||||||
2025-04-26:
|
2025-04-26:
|
||||||
|
|
||||||
|
13
Makefile
13
Makefile
@ -54,6 +54,10 @@ PREFIX?=/usr/local
|
|||||||
# use UB sanitizer
|
# use UB sanitizer
|
||||||
#CONFIG_UBSAN=y
|
#CONFIG_UBSAN=y
|
||||||
|
|
||||||
|
# TEST262 bootstrap config: commit id and shallow "since" parameter
|
||||||
|
TEST262_COMMIT?=af3d908437b0912513a594e7167f17658e72d88b
|
||||||
|
TEST262_SINCE?=2025-09-14
|
||||||
|
|
||||||
OBJDIR=.obj
|
OBJDIR=.obj
|
||||||
|
|
||||||
ifdef CONFIG_ASAN
|
ifdef CONFIG_ASAN
|
||||||
@ -464,6 +468,15 @@ stats: qjs$(EXE)
|
|||||||
microbench: qjs$(EXE)
|
microbench: qjs$(EXE)
|
||||||
$(WINE) ./qjs$(EXE) --std tests/microbench.js
|
$(WINE) ./qjs$(EXE) --std tests/microbench.js
|
||||||
|
|
||||||
|
ifeq ($(wildcard test262/features.txt),)
|
||||||
|
test2-bootstrap:
|
||||||
|
git clone --single-branch --shallow-since=$(TEST262_SINCE) https://github.com/tc39/test262.git
|
||||||
|
(cd test262 && git checkout -q $(TEST262_COMMIT) && patch -p1 < ../tests/test262.patch && cd ..)
|
||||||
|
else
|
||||||
|
test2-bootstrap:
|
||||||
|
(cd test262 && git fetch && git reset --hard $(TEST262_COMMIT) && patch -p1 < ../tests/test262.patch && cd ..)
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(wildcard test262o/tests.txt),)
|
ifeq ($(wildcard test262o/tests.txt),)
|
||||||
test2o test2o-update:
|
test2o test2o-update:
|
||||||
@echo test262o tests not installed
|
@echo test262o tests not installed
|
||||||
|
221
quickjs.c
221
quickjs.c
@ -13002,73 +13002,6 @@ static JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)
|
|||||||
return JS_ToString(ctx, val);
|
return JS_ToString(ctx, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue JS_ToQuotedString(JSContext *ctx, JSValueConst val1)
|
|
||||||
{
|
|
||||||
JSValue val;
|
|
||||||
JSString *p;
|
|
||||||
int i;
|
|
||||||
uint32_t c;
|
|
||||||
StringBuffer b_s, *b = &b_s;
|
|
||||||
char buf[16];
|
|
||||||
|
|
||||||
val = JS_ToStringCheckObject(ctx, val1);
|
|
||||||
if (JS_IsException(val))
|
|
||||||
return val;
|
|
||||||
p = JS_VALUE_GET_STRING(val);
|
|
||||||
|
|
||||||
if (string_buffer_init(ctx, b, p->len + 2))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
if (string_buffer_putc8(b, '\"'))
|
|
||||||
goto fail;
|
|
||||||
for(i = 0; i < p->len; ) {
|
|
||||||
c = string_getc(p, &i);
|
|
||||||
switch(c) {
|
|
||||||
case '\t':
|
|
||||||
c = 't';
|
|
||||||
goto quote;
|
|
||||||
case '\r':
|
|
||||||
c = 'r';
|
|
||||||
goto quote;
|
|
||||||
case '\n':
|
|
||||||
c = 'n';
|
|
||||||
goto quote;
|
|
||||||
case '\b':
|
|
||||||
c = 'b';
|
|
||||||
goto quote;
|
|
||||||
case '\f':
|
|
||||||
c = 'f';
|
|
||||||
goto quote;
|
|
||||||
case '\"':
|
|
||||||
case '\\':
|
|
||||||
quote:
|
|
||||||
if (string_buffer_putc8(b, '\\'))
|
|
||||||
goto fail;
|
|
||||||
if (string_buffer_putc8(b, c))
|
|
||||||
goto fail;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (c < 32 || is_surrogate(c)) {
|
|
||||||
snprintf(buf, sizeof(buf), "\\u%04x", c);
|
|
||||||
if (string_buffer_puts8(b, buf))
|
|
||||||
goto fail;
|
|
||||||
} else {
|
|
||||||
if (string_buffer_putc(b, c))
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (string_buffer_putc8(b, '\"'))
|
|
||||||
goto fail;
|
|
||||||
JS_FreeValue(ctx, val);
|
|
||||||
return string_buffer_end(b);
|
|
||||||
fail:
|
|
||||||
JS_FreeValue(ctx, val);
|
|
||||||
string_buffer_free(b);
|
|
||||||
return JS_EXCEPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define JS_PRINT_MAX_DEPTH 8
|
#define JS_PRINT_MAX_DEPTH 8
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -13126,18 +13059,61 @@ static uint32_t js_string_get_length(JSValueConst val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void js_dump_char(JSPrintValueState *s, int c, int sep)
|
/* pretty print the first 'len' characters of 'p' */
|
||||||
|
static void js_print_string1(JSPrintValueState *s, JSString *p, int len, int sep)
|
||||||
{
|
{
|
||||||
if (c == sep || c == '\\') {
|
uint8_t buf[UTF8_CHAR_LEN_MAX];
|
||||||
|
int l, i, c, c1;
|
||||||
|
|
||||||
|
for(i = 0; i < len; i++) {
|
||||||
|
c = string_get(p, i);
|
||||||
|
switch(c) {
|
||||||
|
case '\t':
|
||||||
|
c = 't';
|
||||||
|
goto quote;
|
||||||
|
case '\r':
|
||||||
|
c = 'r';
|
||||||
|
goto quote;
|
||||||
|
case '\n':
|
||||||
|
c = 'n';
|
||||||
|
goto quote;
|
||||||
|
case '\b':
|
||||||
|
c = 'b';
|
||||||
|
goto quote;
|
||||||
|
case '\f':
|
||||||
|
c = 'f';
|
||||||
|
goto quote;
|
||||||
|
case '\\':
|
||||||
|
quote:
|
||||||
js_putc(s, '\\');
|
js_putc(s, '\\');
|
||||||
js_putc(s, c);
|
js_putc(s, c);
|
||||||
} else if (c >= ' ' && c <= 126) {
|
break;
|
||||||
|
default:
|
||||||
|
if (c == sep)
|
||||||
|
goto quote;
|
||||||
|
if (c >= 32 && c <= 126) {
|
||||||
js_putc(s, c);
|
js_putc(s, c);
|
||||||
} else if (c == '\n') {
|
} else if (c < 32 ||
|
||||||
js_putc(s, '\\');
|
(c >= 0x7f && c <= 0x9f)) {
|
||||||
js_putc(s, 'n');
|
escape:
|
||||||
} else {
|
|
||||||
js_printf(s, "\\u%04x", c);
|
js_printf(s, "\\u%04x", c);
|
||||||
|
} else {
|
||||||
|
if (is_hi_surrogate(c)) {
|
||||||
|
if ((i + 1) >= len)
|
||||||
|
goto escape;
|
||||||
|
c1 = string_get(p, i + 1);
|
||||||
|
if (!is_lo_surrogate(c1))
|
||||||
|
goto escape;
|
||||||
|
i++;
|
||||||
|
c = from_surrogate(c, c1);
|
||||||
|
} else if (is_lo_surrogate(c)) {
|
||||||
|
goto escape;
|
||||||
|
}
|
||||||
|
l = unicode_to_utf8(buf, c);
|
||||||
|
s->write_func(s->write_opaque, (char *)buf, l);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13146,12 +13122,10 @@ static void js_print_string_rec(JSPrintValueState *s, JSValueConst val,
|
|||||||
{
|
{
|
||||||
if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
|
if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {
|
||||||
JSString *p = JS_VALUE_GET_STRING(val);
|
JSString *p = JS_VALUE_GET_STRING(val);
|
||||||
uint32_t i, len;
|
uint32_t len;
|
||||||
if (pos < s->options.max_string_length) {
|
if (pos < s->options.max_string_length) {
|
||||||
len = min_uint32(p->len, s->options.max_string_length - pos);
|
len = min_uint32(p->len, s->options.max_string_length - pos);
|
||||||
for(i = 0; i < len; i++) {
|
js_print_string1(s, p, len, sep);
|
||||||
js_dump_char(s, string_get(p, i), sep);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
|
} else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {
|
||||||
JSStringRope *r = JS_VALUE_GET_PTR(val);
|
JSStringRope *r = JS_VALUE_GET_PTR(val);
|
||||||
@ -13224,9 +13198,7 @@ static void js_print_atom(JSPrintValueState *s, JSAtom atom)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
js_putc(s, '"');
|
js_putc(s, '"');
|
||||||
for(i = 0; i < p->len; i++) {
|
js_print_string1(s, p, p->len, '\"');
|
||||||
js_dump_char(s, string_get(p, i), '\"');
|
|
||||||
}
|
|
||||||
js_putc(s, '"');
|
js_putc(s, '"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34952,6 +34924,7 @@ static void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)
|
|||||||
JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
|
JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (b->byte_code_buf)
|
||||||
free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
|
free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);
|
||||||
|
|
||||||
if (b->vardefs) {
|
if (b->vardefs) {
|
||||||
@ -43859,12 +43832,6 @@ static JSValue js_string_trim(JSContext *ctx, JSValueConst this_val,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue js_string___quote(JSContext *ctx, JSValueConst this_val,
|
|
||||||
int argc, JSValueConst *argv)
|
|
||||||
{
|
|
||||||
return JS_ToQuotedString(ctx, this_val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return 0 if before the first char */
|
/* return 0 if before the first char */
|
||||||
static int string_prevc(JSString *p, int *pidx)
|
static int string_prevc(JSString *p, int *pidx)
|
||||||
{
|
{
|
||||||
@ -44352,7 +44319,6 @@ static const JSCFunctionListEntry js_string_proto_funcs[] = {
|
|||||||
JS_ALIAS_DEF("trimLeft", "trimStart" ),
|
JS_ALIAS_DEF("trimLeft", "trimStart" ),
|
||||||
JS_CFUNC_DEF("toString", 0, js_string_toString ),
|
JS_CFUNC_DEF("toString", 0, js_string_toString ),
|
||||||
JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
|
JS_CFUNC_DEF("valueOf", 0, js_string_toString ),
|
||||||
JS_CFUNC_DEF("__quote", 1, js_string___quote ),
|
|
||||||
JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
|
JS_CFUNC_MAGIC_DEF("toLowerCase", 0, js_string_toLowerCase, 1 ),
|
||||||
JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
|
JS_CFUNC_MAGIC_DEF("toUpperCase", 0, js_string_toLowerCase, 0 ),
|
||||||
JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
|
JS_CFUNC_MAGIC_DEF("toLocaleLowerCase", 0, js_string_toLowerCase, 1 ),
|
||||||
@ -46667,10 +46633,72 @@ typedef struct JSONStringifyContext {
|
|||||||
StringBuffer *b;
|
StringBuffer *b;
|
||||||
} JSONStringifyContext;
|
} JSONStringifyContext;
|
||||||
|
|
||||||
static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
|
static int JS_ToQuotedString(JSContext *ctx, StringBuffer *b, JSValueConst val1)
|
||||||
JSValue r = JS_ToQuotedString(ctx, val);
|
{
|
||||||
|
JSValue val;
|
||||||
|
JSString *p;
|
||||||
|
int i;
|
||||||
|
uint32_t c;
|
||||||
|
char buf[16];
|
||||||
|
|
||||||
|
val = JS_ToStringCheckObject(ctx, val1);
|
||||||
|
if (JS_IsException(val))
|
||||||
|
return -1;
|
||||||
|
p = JS_VALUE_GET_STRING(val);
|
||||||
|
|
||||||
|
if (string_buffer_putc8(b, '\"'))
|
||||||
|
goto fail;
|
||||||
|
for(i = 0; i < p->len; ) {
|
||||||
|
c = string_getc(p, &i);
|
||||||
|
switch(c) {
|
||||||
|
case '\t':
|
||||||
|
c = 't';
|
||||||
|
goto quote;
|
||||||
|
case '\r':
|
||||||
|
c = 'r';
|
||||||
|
goto quote;
|
||||||
|
case '\n':
|
||||||
|
c = 'n';
|
||||||
|
goto quote;
|
||||||
|
case '\b':
|
||||||
|
c = 'b';
|
||||||
|
goto quote;
|
||||||
|
case '\f':
|
||||||
|
c = 'f';
|
||||||
|
goto quote;
|
||||||
|
case '\"':
|
||||||
|
case '\\':
|
||||||
|
quote:
|
||||||
|
if (string_buffer_putc8(b, '\\'))
|
||||||
|
goto fail;
|
||||||
|
if (string_buffer_putc8(b, c))
|
||||||
|
goto fail;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (c < 32 || is_surrogate(c)) {
|
||||||
|
snprintf(buf, sizeof(buf), "\\u%04x", c);
|
||||||
|
if (string_buffer_puts8(b, buf))
|
||||||
|
goto fail;
|
||||||
|
} else {
|
||||||
|
if (string_buffer_putc(b, c))
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (string_buffer_putc8(b, '\"'))
|
||||||
|
goto fail;
|
||||||
JS_FreeValue(ctx, val);
|
JS_FreeValue(ctx, val);
|
||||||
return r;
|
return 0;
|
||||||
|
fail:
|
||||||
|
JS_FreeValue(ctx, val);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int JS_ToQuotedStringFree(JSContext *ctx, StringBuffer *b, JSValue val) {
|
||||||
|
int ret = JS_ToQuotedString(ctx, b, val);
|
||||||
|
JS_FreeValue(ctx, val);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
|
static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
|
||||||
@ -46853,13 +46881,11 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
|
|||||||
if (!JS_IsUndefined(v)) {
|
if (!JS_IsUndefined(v)) {
|
||||||
if (has_content)
|
if (has_content)
|
||||||
string_buffer_putc8(jsc->b, ',');
|
string_buffer_putc8(jsc->b, ',');
|
||||||
prop = JS_ToQuotedStringFree(ctx, prop);
|
string_buffer_concat_value(jsc->b, sep);
|
||||||
if (JS_IsException(prop)) {
|
if (JS_ToQuotedString(ctx, jsc->b, prop)) {
|
||||||
JS_FreeValue(ctx, v);
|
JS_FreeValue(ctx, v);
|
||||||
goto exception;
|
goto exception;
|
||||||
}
|
}
|
||||||
string_buffer_concat_value(jsc->b, sep);
|
|
||||||
string_buffer_concat_value(jsc->b, prop);
|
|
||||||
string_buffer_putc8(jsc->b, ':');
|
string_buffer_putc8(jsc->b, ':');
|
||||||
string_buffer_concat_value(jsc->b, sep1);
|
string_buffer_concat_value(jsc->b, sep1);
|
||||||
if (js_json_to_str(ctx, jsc, val, v, indent1))
|
if (js_json_to_str(ctx, jsc, val, v, indent1))
|
||||||
@ -46887,10 +46913,7 @@ static int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,
|
|||||||
switch (JS_VALUE_GET_NORM_TAG(val)) {
|
switch (JS_VALUE_GET_NORM_TAG(val)) {
|
||||||
case JS_TAG_STRING:
|
case JS_TAG_STRING:
|
||||||
case JS_TAG_STRING_ROPE:
|
case JS_TAG_STRING_ROPE:
|
||||||
val = JS_ToQuotedStringFree(ctx, val);
|
return JS_ToQuotedStringFree(ctx, jsc->b, val);
|
||||||
if (JS_IsException(val))
|
|
||||||
goto exception;
|
|
||||||
goto concat_value;
|
|
||||||
case JS_TAG_FLOAT64:
|
case JS_TAG_FLOAT64:
|
||||||
if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
|
if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {
|
||||||
val = JS_NULL;
|
val = JS_NULL;
|
||||||
|
@ -116,6 +116,7 @@ for-of
|
|||||||
generators
|
generators
|
||||||
globalThis
|
globalThis
|
||||||
hashbang
|
hashbang
|
||||||
|
immutable-arraybuffer=skip
|
||||||
import-attributes
|
import-attributes
|
||||||
import-defer=skip
|
import-defer=skip
|
||||||
import.meta
|
import.meta
|
||||||
|
@ -14,9 +14,9 @@ index 9828b15..4a5919d 100644
|
|||||||
+// small: 200,
|
+// small: 200,
|
||||||
+// long: 1000,
|
+// long: 1000,
|
||||||
+// huge: 10000,
|
+// huge: 10000,
|
||||||
+ yield: 20,
|
+ yield: 40,
|
||||||
+ small: 20,
|
+ small: 40,
|
||||||
+ long: 100,
|
+ long: 200,
|
||||||
+ huge: 1000,
|
+ huge: 1000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ function toStr(a)
|
|||||||
case "undefined":
|
case "undefined":
|
||||||
return "undefined";
|
return "undefined";
|
||||||
case "string":
|
case "string":
|
||||||
return a.__quote();
|
return JSON.stringify(a);
|
||||||
case "number":
|
case "number":
|
||||||
if (a == 0 && 1 / a < 0)
|
if (a == 0 && 1 / a < 0)
|
||||||
return "-0";
|
return "-0";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user