Sync TLA implementation with upstream

Fixes: https://github.com/quickjs-ng/quickjs/issues/339
This commit is contained in:
Tom Lienard 2024-04-22 10:36:50 +01:00 committed by Saúl Ibarra Corretgé
parent a4e48a6a65
commit d3da56b630
11 changed files with 3489 additions and 2877 deletions

View file

@ -330,6 +330,11 @@ optional properties:
@item backtrace_barrier
Boolean (default = false). If true, error backtraces do not list the
stack frames below the evalScript.
@item async
Boolean (default = false). If true, @code{await} is accepted in the
script and a promise is returned. The promise is resolved with an
object whose @code{value} property holds the value returned by the
script.
@end table
@item loadScript(filename)
@ -717,6 +722,12 @@ write_fd]} or null in case of error.
@item sleep(delay_ms)
Sleep during @code{delay_ms} milliseconds.
@item sleepAsync(delay_ms)
Asynchronouse sleep during @code{delay_ms} milliseconds. Returns a promise. Example:
@example
await os.sleepAsync(500);
@end example
@item setTimeout(func, delay)
Call the function @code{func} after @code{delay} ms. Return a handle
to the timer.

View file

@ -2,53 +2,53 @@
#include "quickjs-libc.h"
const uint32_t qjsc_fib_module_size = 310;
const uint32_t qjsc_fib_module_size = 311;
const uint8_t qjsc_fib_module[310] = {
const uint8_t qjsc_fib_module[311] = {
0x0c, 0x03, 0x2c, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x62, 0x5f,
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x6a,
0x73, 0x06, 0x66, 0x69, 0x62, 0x02, 0x6e, 0x0d,
0xb2, 0x03, 0x00, 0x01, 0x00, 0x00, 0xb4, 0x03,
0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e, 0x01,
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09, 0x00,
0xb4, 0x03, 0x00, 0x01, 0x0c, 0x43, 0xfa, 0x01,
0xb4, 0x03, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00,
0x1a, 0x01, 0xb6, 0x03, 0x00, 0x01, 0x00, 0xb4,
0x03, 0x00, 0x00, 0xd0, 0xb3, 0xa7, 0xe9, 0x03,
0xb3, 0x28, 0xd0, 0xb4, 0xac, 0xe9, 0x03, 0xb4,
0x28, 0xdc, 0xd0, 0xb4, 0x9e, 0xee, 0xdc, 0xd0,
0xb5, 0x9e, 0xee, 0x9d, 0x28, 0xb2, 0x03, 0x02,
0x08, 0x20, 0x04, 0x00, 0x07, 0x06, 0x07, 0x06,
0x12, 0x09, 0x08, 0x07, 0x07, 0x10, 0x07, 0x06,
0x07, 0x06, 0x12, 0x13, 0x08, 0x07, 0x08, 0x16,
0x0c, 0x0c, 0x07, 0x04, 0x0c, 0x0a, 0x0c, 0x0c,
0x07, 0x04, 0x8d, 0x01, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x69, 0x62,
0x28, 0x6e, 0x29, 0x0a, 0x7b, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x20,
0x3c, 0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20, 0x20,
0x00, 0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e,
0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09,
0x00, 0xb4, 0x03, 0x00, 0x01, 0x0c, 0x43, 0xfa,
0x01, 0xb4, 0x03, 0x01, 0x00, 0x01, 0x04, 0x01,
0x00, 0x1a, 0x01, 0xb6, 0x03, 0x00, 0x01, 0x00,
0xb4, 0x03, 0x00, 0x00, 0xd0, 0xb3, 0xa7, 0xe9,
0x03, 0xb3, 0x28, 0xd0, 0xb4, 0xac, 0xe9, 0x03,
0xb4, 0x28, 0xdc, 0xd0, 0xb4, 0x9e, 0xee, 0xdc,
0xd0, 0xb5, 0x9e, 0xee, 0x9d, 0x28, 0xb2, 0x03,
0x02, 0x08, 0x20, 0x04, 0x00, 0x07, 0x06, 0x07,
0x06, 0x12, 0x09, 0x08, 0x07, 0x07, 0x10, 0x07,
0x06, 0x07, 0x06, 0x12, 0x13, 0x08, 0x07, 0x08,
0x16, 0x0c, 0x0c, 0x07, 0x04, 0x0c, 0x0a, 0x0c,
0x0c, 0x07, 0x04, 0x8d, 0x01, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x69,
0x62, 0x28, 0x6e, 0x29, 0x0a, 0x7b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e,
0x20, 0x3c, 0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73,
0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x20,
0x3d, 0x3d, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x3b, 0x0a,
0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x3b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65,
0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x20, 0x3d,
0x3d, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74,
0x75, 0x72, 0x6e, 0x20, 0x31, 0x3b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66,
0x69, 0x62, 0x28, 0x6e, 0x20, 0x2d, 0x20, 0x31,
0x29, 0x20, 0x2b, 0x20, 0x66, 0x69, 0x62, 0x28,
0x6e, 0x20, 0x2d, 0x20, 0x32, 0x29, 0x3b, 0x0a,
0x7d, 0x08, 0xe9, 0x05, 0xbe, 0x00, 0xe0, 0x29,
0x06, 0x2e, 0xb2, 0x03, 0x01, 0x01, 0x06, 0x01,
0x01, 0x00, 0x07, 0x14, 0x02, 0x00,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x66, 0x69, 0x62, 0x28, 0x6e, 0x20, 0x2d, 0x20,
0x31, 0x29, 0x20, 0x2b, 0x20, 0x66, 0x69, 0x62,
0x28, 0x6e, 0x20, 0x2d, 0x20, 0x32, 0x29, 0x3b,
0x0a, 0x7d, 0x08, 0xe9, 0x05, 0xbe, 0x00, 0xe0,
0x29, 0x06, 0x2e, 0xb2, 0x03, 0x01, 0x01, 0x06,
0x01, 0x01, 0x00, 0x07, 0x14, 0x02, 0x00,
};
const uint32_t qjsc_hello_module_size = 177;
const uint32_t qjsc_hello_module_size = 178;
const uint8_t qjsc_hello_module[177] = {
const uint8_t qjsc_hello_module[178] = {
0x0c, 0x07, 0x30, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c,
0x6f, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
@ -60,18 +60,18 @@ const uint8_t qjsc_hello_module[177] = {
0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x10,
0x66, 0x69, 0x62, 0x28, 0x31, 0x30, 0x29, 0x3d,
0x0d, 0xb2, 0x03, 0x01, 0xb4, 0x03, 0x00, 0x00,
0x01, 0x00, 0xb6, 0x03, 0x00, 0x0c, 0x20, 0xfa,
0x01, 0x9e, 0x01, 0x00, 0x00, 0x00, 0x05, 0x01,
0x00, 0x32, 0x00, 0xb6, 0x03, 0x00, 0x0c, 0x08,
0xe9, 0x02, 0x29, 0x38, 0xdc, 0x00, 0x00, 0x00,
0x42, 0xdd, 0x00, 0x00, 0x00, 0x04, 0xde, 0x00,
0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x38, 0xdc,
0x00, 0x00, 0x00, 0x42, 0xdd, 0x00, 0x00, 0x00,
0x04, 0xdf, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00,
0xbb, 0x0a, 0xee, 0x24, 0x02, 0x00, 0x0e, 0x06,
0x2e, 0xb2, 0x03, 0x01, 0x01, 0x0a, 0x01, 0x01,
0x00, 0x04, 0x0a, 0x02, 0x62, 0x00, 0x4d, 0x30,
0x00,
0x01, 0x00, 0xb6, 0x03, 0x00, 0x00, 0x0c, 0x20,
0xfa, 0x01, 0x9e, 0x01, 0x00, 0x00, 0x00, 0x05,
0x01, 0x00, 0x32, 0x00, 0xb6, 0x03, 0x00, 0x0c,
0x08, 0xe9, 0x02, 0x29, 0x38, 0xdc, 0x00, 0x00,
0x00, 0x42, 0xdd, 0x00, 0x00, 0x00, 0x04, 0xde,
0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x38,
0xdc, 0x00, 0x00, 0x00, 0x42, 0xdd, 0x00, 0x00,
0x00, 0x04, 0xdf, 0x00, 0x00, 0x00, 0x65, 0x00,
0x00, 0xbb, 0x0a, 0xee, 0x24, 0x02, 0x00, 0x0e,
0x06, 0x2e, 0xb2, 0x03, 0x01, 0x01, 0x0a, 0x01,
0x01, 0x00, 0x04, 0x0a, 0x02, 0x62, 0x00, 0x4d,
0x30, 0x00,
};
static JSContext *JS_NewCustomContext(JSRuntime *rt)

5132
gen/repl.c

File diff suppressed because it is too large Load diff

View file

@ -2,9 +2,9 @@
#include "quickjs-libc.h"
const uint32_t qjsc_test_fib_size = 166;
const uint32_t qjsc_test_fib_size = 167;
const uint8_t qjsc_test_fib[166] = {
const uint8_t qjsc_test_fib[167] = {
0x0c, 0x07, 0x28, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74,
0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73, 0x10,
@ -15,17 +15,17 @@ const uint8_t qjsc_test_fib[166] = {
0x6f, 0x72, 0x6c, 0x64, 0x10, 0x66, 0x69, 0x62,
0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d, 0xb2, 0x03,
0x01, 0xb4, 0x03, 0x00, 0x00, 0x01, 0x00, 0xb6,
0x03, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e, 0x01,
0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x32, 0x00,
0xb6, 0x03, 0x00, 0x0c, 0x08, 0xe9, 0x02, 0x29,
0x38, 0xdc, 0x00, 0x00, 0x00, 0x42, 0xdd, 0x00,
0x00, 0x00, 0x04, 0xde, 0x00, 0x00, 0x00, 0x24,
0x01, 0x00, 0x0e, 0x38, 0xdc, 0x00, 0x00, 0x00,
0x42, 0xdd, 0x00, 0x00, 0x00, 0x04, 0xdf, 0x00,
0x00, 0x00, 0x65, 0x00, 0x00, 0xbb, 0x0a, 0xee,
0x24, 0x02, 0x00, 0x0e, 0x06, 0x2e, 0xb2, 0x03,
0x01, 0x01, 0x0a, 0x01, 0x01, 0x00, 0x04, 0x0a,
0x02, 0x62, 0x00, 0x4d, 0x30, 0x00,
0x03, 0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e,
0x01, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x32,
0x00, 0xb6, 0x03, 0x00, 0x0c, 0x08, 0xe9, 0x02,
0x29, 0x38, 0xdc, 0x00, 0x00, 0x00, 0x42, 0xdd,
0x00, 0x00, 0x00, 0x04, 0xde, 0x00, 0x00, 0x00,
0x24, 0x01, 0x00, 0x0e, 0x38, 0xdc, 0x00, 0x00,
0x00, 0x42, 0xdd, 0x00, 0x00, 0x00, 0x04, 0xdf,
0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0xbb, 0x0a,
0xee, 0x24, 0x02, 0x00, 0x0e, 0x06, 0x2e, 0xb2,
0x03, 0x01, 0x01, 0x0a, 0x01, 0x01, 0x00, 0x04,
0x0a, 0x02, 0x62, 0x00, 0x4d, 0x30, 0x00,
};
static JSContext *JS_NewCustomContext(JSRuntime *rt)

1
qjs.c
View file

@ -58,6 +58,7 @@ static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
js_module_set_import_meta(ctx, val, TRUE, TRUE);
val = JS_EvalFunction(ctx, val);
}
val = js_std_await(ctx, val);
} else {
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
}

View file

@ -778,6 +778,7 @@ static JSValue js_evalScript(JSContext *ctx, JSValue this_val,
JSValue ret;
JSValue options_obj;
BOOL backtrace_barrier = FALSE;
BOOL is_async = FALSE;
int flags;
if (argc >= 2) {
@ -785,6 +786,9 @@ static JSValue js_evalScript(JSContext *ctx, JSValue this_val,
if (get_bool_option(ctx, &backtrace_barrier, options_obj,
"backtrace_barrier"))
return JS_EXCEPTION;
if (get_bool_option(ctx, &is_async, options_obj,
"async"))
return JS_EXCEPTION;
}
str = JS_ToCStringLen(ctx, &len, argv[0]);
@ -797,6 +801,8 @@ static JSValue js_evalScript(JSContext *ctx, JSValue this_val,
flags = JS_EVAL_TYPE_GLOBAL;
if (backtrace_barrier)
flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;
if (is_async)
flags |= JS_EVAL_FLAG_ASYNC;
ret = JS_Eval(ctx, str, len, "<evalScript>", flags);
JS_FreeCString(ctx, str);
if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {
@ -2114,6 +2120,38 @@ static JSClassDef js_os_timer_class = {
.gc_mark = js_os_timer_mark,
};
/* return a promise */
static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JSRuntime *rt = JS_GetRuntime(ctx);
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
int64_t delay;
JSOSTimer *th;
JSValue promise, resolving_funcs[2];
if (JS_ToInt64(ctx, &delay, argv[0]))
return JS_EXCEPTION;
promise = JS_NewPromiseCapability(ctx, resolving_funcs);
if (JS_IsException(promise))
return JS_EXCEPTION;
th = js_mallocz(ctx, sizeof(*th));
if (!th) {
JS_FreeValue(ctx, promise);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
return JS_EXCEPTION;
}
th->has_object = FALSE;
th->timeout = js__hrtime_ms() + delay;
th->func = JS_DupValue(ctx, resolving_funcs[0]);
list_add_tail(&th->link, &ts->os_timers);
JS_FreeValue(ctx, resolving_funcs[0]);
JS_FreeValue(ctx, resolving_funcs[1]);
return promise;
}
static void call_handler(JSContext *ctx, JSValue func)
{
JSValue ret, func1;
@ -3329,6 +3367,7 @@ static void *worker_func(void *opaque)
JSRuntime *rt;
JSThreadState *ts;
JSContext *ctx;
JSValue val;
rt = JS_NewRuntime();
if (rt == NULL) {
@ -3355,11 +3394,14 @@ static void *worker_func(void *opaque)
js_std_add_helpers(ctx, -1, NULL);
if (!JS_RunModule(ctx, args->basename, args->filename))
js_std_dump_error(ctx);
val = JS_LoadModule(ctx, args->basename, args->filename);
free(args->filename);
free(args->basename);
free(args);
val = js_std_await(ctx, val);
if (JS_IsException(val))
js_std_dump_error(ctx);
JS_FreeValue(ctx, val);
js_std_loop(ctx);
@ -3702,6 +3744,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
// per spec: both functions can cancel timeouts and intervals
JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ),
JS_CFUNC_DEF("clearInterval", 1, js_os_clearTimeout ),
JS_CFUNC_DEF("sleepAsync", 1, js_os_sleepAsync ),
JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
@ -3980,6 +4023,42 @@ void js_std_loop(JSContext *ctx)
}
}
/* Wait for a promise and execute pending jobs while waiting for
it. Return the promise result or JS_EXCEPTION in case of promise
rejection. */
JSValue js_std_await(JSContext *ctx, JSValue obj)
{
JSValue ret;
int state;
for(;;) {
state = JS_PromiseState(ctx, obj);
if (state == JS_PROMISE_FULFILLED) {
ret = JS_PromiseResult(ctx, obj);
JS_FreeValue(ctx, obj);
break;
} else if (state == JS_PROMISE_REJECTED) {
ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj));
JS_FreeValue(ctx, obj);
break;
} else if (state == JS_PROMISE_PENDING) {
JSContext *ctx1;
int err;
err = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
if (err < 0) {
js_std_dump_error(ctx1);
}
if (os_poll_func)
os_poll_func(ctx);
} else {
/* not a promise */
ret = obj;
break;
}
}
return ret;
}
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
int load_only)
{
@ -3998,8 +4077,11 @@ void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
goto exception;
}
js_module_set_import_meta(ctx, obj, FALSE, TRUE);
val = JS_EvalFunction(ctx, obj);
val = js_std_await(ctx, val);
} else {
val = JS_EvalFunction(ctx, obj);
}
val = JS_EvalFunction(ctx, obj);
if (JS_IsException(val)) {
exception:
js_std_dump_error(ctx);

View file

@ -37,6 +37,7 @@ JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
void js_std_loop(JSContext *ctx);
JSValue js_std_await(JSContext *ctx, JSValue obj);
void js_std_init_handlers(JSRuntime *rt);
void js_std_free_handlers(JSRuntime *rt);
void js_std_dump_error(JSContext *ctx);

800
quickjs.c

File diff suppressed because it is too large Load diff

View file

@ -275,6 +275,9 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)
/* don't include the stack frames before this eval in the Error() backtraces */
#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
/* allow top-level await in normal script. JS_Eval() returns a
promise. Only allowed with JS_EVAL_TYPE_GLOBAL */
#define JS_EVAL_FLAG_ASYNC (1 << 7)
typedef JSValue JSCFunction(JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic);
@ -782,7 +785,15 @@ typedef struct {
} JSSharedArrayBufferFunctions;
JS_EXTERN void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf);
typedef enum JSPromiseStateEnum {
JS_PROMISE_PENDING,
JS_PROMISE_FULFILLED,
JS_PROMISE_REJECTED,
} JSPromiseStateEnum;
JS_EXTERN JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);
JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValue promise);
JS_EXTERN JSValue JS_NewSymbol(JSContext *ctx, const char *description, JS_BOOL is_global);
@ -854,8 +865,8 @@ JS_EXTERN int JS_ResolveModule(JSContext *ctx, JSValue obj);
/* only exported for os.Worker() */
JS_EXTERN JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
/* only exported for os.Worker() */
JS_EXTERN JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
const char *filename);
JS_EXTERN JSValue JS_LoadModule(JSContext *ctx, const char *basename,
const char *filename);
/* C function definition */
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
@ -994,21 +1005,6 @@ JS_EXTERN int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *exp
JS_EXTERN int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
const JSCFunctionListEntry *tab, int len);
/* Promise */
#define JS_INVALID_PROMISE_STATE (-1)
typedef enum JSPromiseStateEnum {
JS_PROMISE_PENDING,
JS_PROMISE_FULFILLED,
JS_PROMISE_REJECTED,
} JSPromiseStateEnum;
/* Returns JSPromiseReactionEnum for the promise or JS_INVALID_PROMISE_STATE if the value is not a promise. */
JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);
/* Return the result of the promise if the promise's state is in the FULFILLED or REJECTED state. Otherwise returns JS_UNDEFINED. */
JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValue promise);
/* Version */
#define QJS_VERSION_MAJOR 0

102
repl.js
View file

@ -129,6 +129,7 @@ import * as os from "os";
var plen = 0;
var ps1 = "qjs > ";
var ps2 = " ... ";
var eval_start_time;
var eval_time = 0;
var mexpr = "";
var level = 0;
@ -838,10 +839,8 @@ import * as os from "os";
prompt += ps2;
} else {
if (show_time) {
var t = Math.round(eval_time) + " ";
eval_time = 0;
t = dupstr("0", 5 - t.length) + t;
prompt += t.substring(0, t.length - 4) + "." + t.substring(t.length - 4);
var t = eval_time / 1000;
prompt += t.toFixed(6) + " ";
}
plen = prompt.length;
prompt += ps1;
@ -1507,34 +1506,6 @@ import * as os from "os";
"quit": () => { exit(0); },
}, null);
function eval_and_print(expr) {
var result;
try {
if (use_strict)
expr = '"use strict"; void 0;' + expr;
var now = Date.now();
/* eval as a script */
result = std.evalScript(expr, { backtrace_barrier: true });
eval_time = Date.now() - now;
print(result);
/* set the last result */
g._ = result;
} catch (error) {
std.puts(colors[styles.error]);
if (error instanceof Error) {
console.log(error);
if (error.stack) {
std.puts(error.stack);
}
} else {
std.puts("Throw: ");
console.log(error);
}
std.puts(colors.none);
}
}
function cmd_start() {
std.puts('QuickJS-ng - Type ".help" for help\n');
cmd_readline_start();
@ -1545,33 +1516,88 @@ import * as os from "os";
}
function readline_handle_cmd(expr) {
handle_cmd(expr);
cmd_readline_start();
if (!handle_cmd(expr)) {
cmd_readline_start();
}
}
/* return true if async termination */
function handle_cmd(expr) {
if (!expr)
return;
return false;
if (mexpr) {
expr = mexpr + '\n' + expr;
} else {
if (handle_directive(expr))
return;
return false;
}
var colorstate = colorize_js(expr);
pstate = colorstate[0];
level = colorstate[1];
if (pstate) {
mexpr = expr;
return;
return false;
}
mexpr = "";
eval_and_print(expr);
eval_and_print_start(expr, true);
return true;
}
function eval_and_print_start(expr, is_async) {
var result;
try {
if (use_strict)
expr = '"use strict"; void 0;' + expr;
eval_start_time = os.now();
/* eval as a script */
result = std.evalScript(expr, { backtrace_barrier: true, async: is_async });
if (is_async) {
/* result is a promise */
result.then(print_eval_result, print_eval_error);
} else {
print_eval_result({ value: result });
}
} catch (error) {
print_eval_error(error);
}
}
function print_eval_result(result) {
result = result.value;
eval_time = os.now() - eval_start_time;
print(result);
/* set the last result */
g._ = result;
handle_cmd_end();
}
function print_eval_error(error) {
std.puts(colors[styles.error]);
if (error instanceof Error) {
console.log(error);
if (error.stack) {
std.puts(error.stack);
}
} else {
std.puts("Throw: ");
console.log(error);
}
std.puts(colors.none);
handle_cmd_end();
}
function handle_cmd_end() {
level = 0;
/* run the garbage collector after each command */
std.gc();
cmd_readline_start();
}
function colorize_js(str) {

View file

@ -1198,7 +1198,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
{
JSValue res_val, exception_val;
int ret, error_line, pos, pos_line;
BOOL is_error, has_error_line;
BOOL is_error, has_error_line, ret_promise;
const char *error_name;
pos = skip_comments(buf, 1, &pos_line);
@ -1207,12 +1207,19 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
exception_val = JS_UNDEFINED;
error_name = NULL;
/* a module evaluation returns a promise */
ret_promise = ((eval_flags & JS_EVAL_TYPE_MODULE) != 0);
async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */
res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
if (is_async && !JS_IsException(res_val)) {
JS_FreeValue(ctx, res_val);
if ((is_async || ret_promise) && !JS_IsException(res_val)) {
JSValue promise = JS_UNDEFINED;
if (ret_promise) {
promise = res_val;
} else {
JS_FreeValue(ctx, res_val);
}
for(;;) {
JSContext *ctx1;
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
@ -1220,37 +1227,26 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
res_val = JS_EXCEPTION;
break;
} else if (ret == 0) {
/* test if the test called $DONE() once */
if (async_done != 1) {
res_val = JS_ThrowTypeError(ctx, "$DONE() not called");
if (is_async) {
/* test if the test called $DONE() once */
if (async_done != 1) {
res_val = JS_ThrowTypeError(ctx, "$DONE() not called");
} else {
res_val = JS_UNDEFINED;
}
} else {
res_val = JS_UNDEFINED;
/* check that the returned promise is fulfilled */
JSPromiseStateEnum state = JS_PromiseState(ctx, promise);
if (state == JS_PROMISE_FULFILLED)
res_val = JS_UNDEFINED;
else if (state == JS_PROMISE_REJECTED)
res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise));
else
res_val = JS_ThrowTypeError(ctx, "promise is pending");
}
break;
}
}
} else if ((eval_flags & JS_EVAL_TYPE_MODULE) &&
!JS_IsUndefined(res_val) &&
!JS_IsException(res_val)) {
JSValue promise = res_val;
for(;;) {
JSContext *ctx1;
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
if (ret < 0) {
res_val = JS_EXCEPTION;
break;
}
if (ret == 0) {
JSPromiseStateEnum s = JS_PromiseState(ctx, promise);
if (s == JS_PROMISE_FULFILLED)
res_val = JS_UNDEFINED;
else if (s == JS_PROMISE_REJECTED)
res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise));
else
res_val = JS_EXCEPTION;
break;
}
}
JS_FreeValue(ctx, promise);
}
@ -1887,17 +1883,32 @@ int run_test262_harness_test(const char *filename, BOOL is_module)
js_std_dump_error(ctx);
ret_code = 1;
} else {
JS_FreeValue(ctx, res_val);
JSValue promise = JS_UNDEFINED;
if (is_module) {
promise = res_val;
} else {
JS_FreeValue(ctx, res_val);
}
for(;;) {
JSContext *ctx1;
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
if (ret < 0) {
js_std_dump_error(ctx1);
ret_code = 1;
js_std_dump_error(ctx1);
ret_code = 1;
} else if (ret == 0) {
break;
break;
}
}
}
/* dump the error if the module returned an error. */
if (is_module) {
JSPromiseStateEnum state = JS_PromiseState(ctx, promise);
if (state == JS_PROMISE_REJECTED) {
JS_Throw(ctx, JS_PromiseResult(ctx, promise));
js_std_dump_error(ctx);
ret_code = 1;
}
}
JS_FreeValue(ctx, promise);
}
free(buf);
#ifdef CONFIG_AGENT