diff --git a/examples/npm/elysia/index.ts b/examples/npm/elysia/index.ts index f3f2fb88..f8db1721 100644 --- a/examples/npm/elysia/index.ts +++ b/examples/npm/elysia/index.ts @@ -3,4 +3,4 @@ import { logger } from './logger'; console.log('started on http://localhost:3000'); -export default new Elysia().use(logger()).get('/', () => 'hello elysia!!\n🐜\n'); +export default new Elysia().use(logger()).get('/', () => `hello elysia!!\n\n🐜 ${Ant.version}\n`); diff --git a/examples/npm/express/index.cjs b/examples/npm/express/index.cjs index 99dcf105..91c337b2 100644 --- a/examples/npm/express/index.cjs +++ b/examples/npm/express/index.cjs @@ -4,9 +4,9 @@ let app = express(); let port = 3000; app.get('/', (_req, res) => { - res.send('Hello World!'); + res.type('txt').send(`hello express!!\n\n🐜 ${Ant.version}\n`); }); app.listen(port, () => { - console.log(`Example app listening on port ${port}`); + console.log(`started on http://localhost:${port}`); }); diff --git a/examples/npm/hono/src/index.ts b/examples/npm/hono/src/index.ts index 415705ba..06347e4e 100644 --- a/examples/npm/hono/src/index.ts +++ b/examples/npm/hono/src/index.ts @@ -4,7 +4,7 @@ import { logger } from 'hono/logger'; const app = new Hono(); app.use(logger()); -app.get('/', c => c.text('hello hono!!\n🐜\n')); +app.get('/', c => c.text(`hello hono!!\n\n🐜 ${Ant.version}\n`)); console.log('started on http://localhost:3000'); diff --git a/examples/results.txt b/examples/results.txt index db385c4c..170689b6 100644 --- a/examples/results.txt +++ b/examples/results.txt @@ -607,7 +607,7 @@ compat-table/es6/String.prototype.startsWith.js: OK compat-table/es6/String.prototype.startsWith.throws-regex.js: OK compat-table/es6/String.raw.js: OK compat-table/es6/Symbol.JSON.stringify.object.js: TypeError: Object.defineProperty called on non-object -compat-table/es6/Symbol.JSON.stringify.primitive.js: failed +compat-table/es6/Symbol.JSON.stringify.primitive.js: OK compat-table/es6/Symbol.Object.js: failed compat-table/es6/Symbol.String.js: OK compat-table/es6/Symbol.defineProperty.js: OK @@ -1042,12 +1042,12 @@ compat-table/es6/template.toString.js: OK compat-table/es6/typed-arrays.ArrayBuffer.Symbol.species.js: OK compat-table/es6/typed-arrays.DataView.Float32.js: failed compat-table/es6/typed-arrays.DataView.Float64.js: OK -compat-table/es6/typed-arrays.DataView.Int8.js: TypeError: undefined is not a function +compat-table/es6/typed-arrays.DataView.Int8.js: OK compat-table/es6/typed-arrays.DataView.Int16.js: OK compat-table/es6/typed-arrays.DataView.Int32.js: OK compat-table/es6/typed-arrays.DataView.Uint8.js: OK -compat-table/es6/typed-arrays.DataView.Uint16.js: TypeError: undefined is not a function -compat-table/es6/typed-arrays.DataView.Uint32.js: TypeError: undefined is not a function +compat-table/es6/typed-arrays.DataView.Uint16.js: OK +compat-table/es6/typed-arrays.DataView.Uint32.js: OK compat-table/es6/typed-arrays.Float32Array.js: failed compat-table/es6/typed-arrays.Float64Array.js: OK compat-table/es6/typed-arrays.Int8Array.js: OK @@ -1248,7 +1248,7 @@ compat-table/es2020/BigInt.js: OK compat-table/es2020/BigUint64Array.js: failed compat-table/es2020/DataView.prototype.getBigInt64.js: TypeError: undefined is not a function compat-table/es2020/DataView.prototype.getBigUint64.js: TypeError: undefined is not a function -compat-table/es2020/Promise.allSettled.js: TypeError: undefined is not a function +compat-table/es2020/Promise.allSettled.js: OK compat-table/es2020/String.prototype.matchAll.js: TypeError: undefined is not a function compat-table/es2020/String.prototype.matchAll.throws-non-global.js: failed compat-table/es2020/globalThis.descriptor.js: OK diff --git a/examples/wasm/cowsay.wasm b/examples/wasm/cowsay.wasm new file mode 100644 index 0000000000000000000000000000000000000000..04195a3720f6c2e8aef7a7b0871ada16b4358847 GIT binary patch literal 771979 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

!xMjTjha!1%!;!ZrR33>F}>QbjnHm@zO! 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

S*n0_oj@f&- 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 literal 0 HcmV?d00001 diff --git a/examples/wasm/index.mjs b/examples/wasm/index.mjs new file mode 100644 index 00000000..84cd7b10 --- /dev/null +++ b/examples/wasm/index.mjs @@ -0,0 +1,15 @@ +import { readFile } from 'ant:fs'; + +const [wasmFile, ...wasmArgs] = process.argv.slice(2); +if (!wasmFile) { + console.error('Usage: ant wasm.mjs [args...]'); + process.exit(1); +} + +const bytes = await readFile(wasmFile); + +const { instance } = await WebAssembly.instantiate(bytes, { + wasi: { args: [wasmFile, ...wasmArgs] } +}); + +instance.exports._start(); diff --git a/include/common.h b/include/common.h index 7b34dd3a..d58bce5c 100644 --- a/include/common.h +++ b/include/common.h @@ -106,7 +106,14 @@ typedef enum { BRAND_WRITABLE_STREAM_WRITER, BRAND_WRITABLE_STREAM_CONTROLLER, BRAND_TRANSFORM_STREAM, - BRAND_TRANSFORM_STREAM_CONTROLLER + BRAND_TRANSFORM_STREAM_CONTROLLER, + BRAND_WASM_MODULE, + BRAND_WASM_INSTANCE, + BRAND_WASM_GLOBAL, + BRAND_WASM_MEMORY, + BRAND_WASM_TABLE, + BRAND_WASM_TAG, + BRAND_WASM_EXCEPTION } object_brand_id_t; static inline void *mantissa_chk(void *p, const char *func) { diff --git a/include/gc/modules.h b/include/gc/modules.h index bdde63e7..6461fdfa 100644 --- a/include/gc/modules.h +++ b/include/gc/modules.h @@ -29,6 +29,7 @@ void gc_mark_transform_streams(ant_t *js, gc_mark_fn mark); void gc_mark_codec_streams(ant_t *js, gc_mark_fn mark); void gc_mark_compression_streams(ant_t *js, gc_mark_fn mark); void gc_mark_zlib(ant_t *js, gc_mark_fn mark); +void gc_mark_wasm(ant_t *js, gc_mark_fn mark); void gc_mark_abort_signal_object(ant_t *js, ant_value_t signal, gc_mark_fn mark); #endif diff --git a/include/internal.h b/include/internal.h index 023f9ec2..e11e6f8b 100644 --- a/include/internal.h +++ b/include/internal.h @@ -402,6 +402,14 @@ static inline bool js_check_brand(ant_value_t obj, int brand) { return js_brand_id(obj) == brand; } +static inline void js_set_module_default(ant_t *js, ant_value_t lib, ant_value_t ctor_fn, const char *name) { + js_set(js, ctor_fn, name, ctor_fn); + js_set(js, lib, name, ctor_fn); + js_set(js, lib, "default", ctor_fn); + js_set(js, ctor_fn, "default", ctor_fn); + js_set_slot_wb(js, lib, SLOT_DEFAULT, ctor_fn); +} + static inline ant_value_t js_make_ctor(ant_t *js, ant_cfunc_t fn, ant_value_t proto, const char *name, size_t nlen) { ant_value_t obj = js_mkobj(js); js_set_slot(obj, SLOT_CFUNC, js_mkfun(fn)); diff --git a/include/modules/process.h b/include/modules/process.h index df57f4c9..1c5c7c36 100644 --- a/include/modules/process.h +++ b/include/modules/process.h @@ -3,12 +3,13 @@ #include "types.h" +void init_process_module(void); +ant_value_t process_library(ant_t *js); + void process_enable_keypress_events(void); void emit_process_event(const char *event_type, ant_value_t *args, int nargs); -void init_process_module(void); bool has_active_stdin(void); - -ant_value_t process_library(ant_t *js); +bool process_has_event_listeners(const char *event_type); #endif diff --git a/include/modules/regex.h b/include/modules/regex.h index 9a4075cf..122a2d5e 100644 --- a/include/modules/regex.h +++ b/include/modules/regex.h @@ -3,25 +3,29 @@ #include "types.h" +typedef struct { + const char *pattern_ptr; + ant_offset_t pattern_len; + + const char *str_ptr; + ant_offset_t str_len; + + bool global; + bool ignore_case; + bool multiline; +} regex_match_args_t; + void init_regex_module(void); void cleanup_regex_module(void); void gc_sweep_regex_cache(void); -size_t js_to_pcre2_pattern(const char *src, size_t src_len, char *dst, size_t dst_size); - -ant_value_t builtin_regexp_symbol_split(ant_t *js, ant_value_t *args, int nargs); -ant_value_t builtin_regexp_symbol_match(ant_t *js, ant_value_t *args, int nargs); -ant_value_t builtin_regexp_symbol_replace(ant_t *js, ant_value_t *args, int nargs); -ant_value_t builtin_regexp_symbol_search(ant_t *js, ant_value_t *args, int nargs); -ant_value_t builtin_regexp_flags_getter(ant_t *js, ant_value_t *args, int nargs); +size_t js_to_pcre2_pattern( + const char *src, size_t src_len, + char *dst, size_t dst_size, bool v_flag +); ant_value_t is_regexp_like(ant_t *js, ant_value_t value); +ant_value_t do_regex_match_pcre2(ant_t *js, regex_match_args_t args); ant_value_t reject_regexp_arg(ant_t *js, ant_value_t value, const char *method_name); -ant_value_t do_regex_match_pcre2( - ant_t *js, const char *pattern_ptr, ant_offset_t pattern_len, - const char *str_ptr, ant_offset_t str_len, - bool global_flag, bool ignore_case, bool multiline -); - #endif diff --git a/include/modules/wasi.h b/include/modules/wasi.h new file mode 100644 index 00000000..09991d8b --- /dev/null +++ b/include/modules/wasi.h @@ -0,0 +1,15 @@ +#ifndef ANT_WASI_H +#define ANT_WASI_H + +#include "types.h" +#include +#include + +bool wasi_module_has_wasi_imports(void *c_api_module); + +ant_value_t wasi_instantiate( + ant_t *js, const uint8_t *wasm_bytes, size_t wasm_len, + ant_value_t module_obj, ant_value_t wasi_opts +); + +#endif diff --git a/include/modules/wasm.h b/include/modules/wasm.h new file mode 100644 index 00000000..75a11b10 --- /dev/null +++ b/include/modules/wasm.h @@ -0,0 +1,6 @@ +#ifndef ANT_WASM_MODULE_H +#define ANT_WASM_MODULE_H + +void init_wasm_module(void); + +#endif diff --git a/include/watch.h b/include/watch.h index 336d3843..157df6f7 100644 --- a/include/watch.h +++ b/include/watch.h @@ -2,10 +2,24 @@ #define ANT_WATCH_H #include +#include + +int ant_watch_start( + uv_loop_t *loop, + uv_fs_event_t *event, + const char *path, + uv_fs_event_cb callback, + void *data, + unsigned int flags, + char **resolved_path_out +); int ant_watch_run( int argc, char **argv, const char *entry_file, bool no_clear_screen ); +void ant_watch_stop(uv_fs_event_t *event); +char *ant_watch_resolve_path(const char *path); + #endif diff --git a/meson/deps/meson.build b/meson/deps/meson.build index 2203dea7..efce5ea8 100644 --- a/meson/deps/meson.build +++ b/meson/deps/meson.build @@ -107,6 +107,7 @@ argtable3_dep = subproject('argtable3').get_variable('argtable3_dep') minicoro_dep = subproject('minicoro').get_variable('minicoro_dep') crprintf_dep = subproject('crprintf').get_variable('crprintf_dep') uriparser_dep = subproject('uriparser').get_variable('uriparser_dep') +wamr_dep = subproject('wasm-micro-runtime').get_variable('wamr_dep') utf8proc_base_dep = subproject('utf8proc').get_variable('utf8proc_dep') utf8proc_dep = declare_dependency( @@ -214,7 +215,7 @@ ant_deps = [ yyjson_dep, minicoro_dep, uuidv7_dep, uriparser_dep, utf8proc_dep, openssl_dep, zlib_dep, brotli_common_dep, brotli_dec_dep, - brotli_enc_dep, uthash_dep, lmdb_dep, + brotli_enc_dep, uthash_dep, lmdb_dep, wamr_dep, ] + mbedtls_dep + win_deps if get_option('jit') diff --git a/src/ant.c b/src/ant.c index f0851301..4b088403 100644 --- a/src/ant.c +++ b/src/ant.c @@ -1397,6 +1397,15 @@ static size_t strobj(ant_t *js, ant_value_t obj, char *buf, size_t len) { } if (tag_str) { + bool is_timeout = (tlen == 7 && memcmp(tag_str, "Timeout", 7) == 0); + bool is_interval = (tlen == 8 && memcmp(tag_str, "Interval", 8) == 0); + if (is_timeout || is_interval) { + ant_value_t id_val = js_get_slot(obj, SLOT_DATA); + int timer_id = vtype(id_val) == T_NUM ? (int)js_getnum(id_val) : 0; + n += cpy(buf + n, REMAIN(n, len), tag_str, tlen); + n += (size_t) snprintf(buf + n, REMAIN(n, len), " (%d) {\n", timer_id); + goto continue_object_print; + } bool is_blob = (tlen == 4 && memcmp(tag_str, "Blob", 4) == 0); bool is_file = (tlen == 4 && memcmp(tag_str, "File", 4) == 0); if (is_blob || is_file) { @@ -4746,6 +4755,25 @@ static ant_value_t builtin_function_empty(ant_t *js, ant_value_t *args, int narg return js_mkundef(); } +static bool function_uses_native_call(ant_value_t func) { + if (vtype(func) == T_CFUNC) return true; + if (vtype(func) != T_FUNC) return false; + + ant_value_t func_obj = js_func_obj(func); + return vtype(get_slot(func_obj, SLOT_CFUNC)) == T_CFUNC; +} + +static ant_value_t function_call_dispatch( + ant_t *js, + ant_value_t func, + ant_value_t this_arg, + ant_value_t *call_args, + int call_nargs +) { + if (function_uses_native_call(func)) return sv_call_native(js, func, this_arg, call_args, call_nargs); + return sv_vm_call(js->vm, js, func, this_arg, call_args, call_nargs, NULL, false); +} + static ant_value_t builtin_function_call(ant_t *js, ant_value_t *args, int nargs) { ant_value_t func = js->this_val; if (vtype(func) != T_FUNC && vtype(func) != T_CFUNC) { @@ -4753,14 +4781,12 @@ static ant_value_t builtin_function_call(ant_t *js, ant_value_t *args, int nargs } ant_value_t this_arg = (nargs > 0) ? args[0] : js_mkundef(); - ant_value_t *call_args = NULL; - int call_nargs = (nargs > 1) ? nargs - 1 : 0; - if (call_nargs > 0) { - call_args = &args[1]; - } - return sv_vm_call(js->vm, js, func, this_arg, call_args, call_nargs, NULL, false); + int call_nargs = (nargs > 1) ? nargs - 1 : 0; + if (call_nargs > 0) call_args = &args[1]; + + return function_call_dispatch(js, func, this_arg, call_args, call_nargs); } static int extract_array_args(ant_t *js, ant_value_t arr, ant_value_t **out_args) { @@ -4883,8 +4909,9 @@ static ant_value_t builtin_function_apply(ant_t *js, ant_value_t *args, int narg } else if (t != T_UNDEF && t != T_NULL) {} } - ant_value_t result = sv_vm_call(js->vm, js, func, this_arg, call_args, call_nargs, NULL, false); + ant_value_t result = function_call_dispatch(js, func, this_arg, call_args, call_nargs); if (call_args) free(call_args); + return result; } @@ -8344,7 +8371,7 @@ static ant_value_t string_split_impl(ant_t *js, ant_value_t str, ant_value_t *ar } char pcre2_pattern[512]; - size_t pcre2_len = js_to_pcre2_pattern(pattern_ptr, plen, pcre2_pattern, sizeof(pcre2_pattern)); + size_t pcre2_len = js_to_pcre2_pattern(pattern_ptr, plen, pcre2_pattern, sizeof(pcre2_pattern), false); uint32_t options = PCRE2_UTF | PCRE2_UCP | PCRE2_MATCH_UNSET_BACKREF; int errcode; @@ -10667,11 +10694,77 @@ static ant_value_t builtin_Promise_all_reject_handler(ant_t *js, ant_value_t *ar return js_mkundef(); } +static ant_value_t promise_all_settled_make_result(ant_t *js, bool fulfilled, ant_value_t value) { + ant_value_t result = mkobj(js, 0); + if (is_err(result)) return result; + + js_setprop( + js, result, + js_mkstr(js, "status", 6), + js_mkstr(js, fulfilled ? "fulfilled" : "rejected", fulfilled ? 9 : 8) + ); + + js_setprop( + js, result, + js_mkstr(js, fulfilled ? "value" : "reason", fulfilled ? 5 : 6), value + ); + + return result; +} + +static ant_value_t promise_all_settled_store_result( + ant_t *js, + ant_value_t tracker, + int index, + bool fulfilled, + ant_value_t value +) { + ant_value_t results = js_get(js, tracker, "results"); + ant_value_t result = promise_all_settled_make_result(js, fulfilled, value); + ant_value_t remaining_val = 0; + int remaining = 0; + + if (is_err(result)) return result; + arr_set(js, results, (ant_offset_t)index, result); + + remaining_val = js_get(js, tracker, "remaining"); + remaining = (int)tod(remaining_val) - 1; + js_setprop(js, tracker, js_mkstr(js, "remaining", 9), tov((double)remaining)); + + if (remaining == 0) { + ant_value_t result_promise = get_slot(tracker, SLOT_DATA); + js_resolve_promise(js, result_promise, mkval(T_ARR, vdata(results))); + } + + return js_mkundef(); +} + +static ant_value_t builtin_Promise_allSettled_resolve_handler(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t me = js->current_func; + ant_value_t tracker = js_get(js, me, "tracker"); + ant_value_t index_val = js_get(js, me, "index"); + int index = (int)tod(index_val); + ant_value_t value = nargs > 0 ? args[0] : js_mkundef(); + + return promise_all_settled_store_result(js, tracker, index, true, value); +} + +static ant_value_t builtin_Promise_allSettled_reject_handler(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t me = js->current_func; + ant_value_t tracker = js_get(js, me, "tracker"); + ant_value_t index_val = js_get(js, me, "index"); + int index = (int)tod(index_val); + ant_value_t reason = nargs > 0 ? args[0] : js_mkundef(); + + return promise_all_settled_store_result(js, tracker, index, false, reason); +} + typedef struct { ant_value_t tracker; int index; } promise_all_iter_ctx_t; +// TODO: move Promise combinator bookkeeping off JS-visible properties and into slots/native state static iter_action_t promise_all_iter_cb(ant_t *js, ant_value_t value, void *ctx, ant_value_t *out) { GC_ROOT_SAVE(root_mark, js); promise_all_iter_ctx_t *pctx = (promise_all_iter_ctx_t *)ctx; @@ -10726,6 +10819,61 @@ static iter_action_t promise_all_iter_cb(ant_t *js, ant_value_t value, void *ctx return ITER_CONTINUE; } +static iter_action_t promise_all_settled_iter_cb(ant_t *js, ant_value_t value, void *ctx, ant_value_t *out) { + GC_ROOT_SAVE(root_mark, js); + promise_all_iter_ctx_t *pctx = (promise_all_iter_ctx_t *)ctx; + ant_value_t item = value; + GC_ROOT_PIN(js, item); + + if (vtype(item) != T_PROMISE) { + ant_value_t wrap_args[] = { item }; + item = builtin_Promise_resolve(js, wrap_args, 1); + GC_ROOT_PIN(js, item); + } + + ant_value_t resolve_obj = mkobj(js, 0); + if (is_err(resolve_obj)) { + *out = resolve_obj; + GC_ROOT_RESTORE(js, root_mark); + return ITER_ERROR; + } + GC_ROOT_PIN(js, resolve_obj); + set_slot(resolve_obj, SLOT_CFUNC, js_mkfun(builtin_Promise_allSettled_resolve_handler)); + js_setprop(js, resolve_obj, js_mkstr(js, "index", 5), tov((double)pctx->index)); + js_setprop(js, resolve_obj, js_mkstr(js, "tracker", 7), pctx->tracker); + ant_value_t resolve_fn = js_obj_to_func(resolve_obj); + GC_ROOT_PIN(js, resolve_fn); + + ant_value_t reject_obj = mkobj(js, 0); + if (is_err(reject_obj)) { + *out = reject_obj; + GC_ROOT_RESTORE(js, root_mark); + return ITER_ERROR; + } + GC_ROOT_PIN(js, reject_obj); + set_slot(reject_obj, SLOT_CFUNC, js_mkfun(builtin_Promise_allSettled_reject_handler)); + js_setprop(js, reject_obj, js_mkstr(js, "index", 5), tov((double)pctx->index)); + js_setprop(js, reject_obj, js_mkstr(js, "tracker", 7), pctx->tracker); + ant_value_t reject_fn = js_obj_to_func(reject_obj); + GC_ROOT_PIN(js, reject_fn); + + ant_value_t then_args[] = { resolve_fn, reject_fn }; + ant_value_t saved_this = js->this_val; + GC_ROOT_PIN(js, saved_this); + js->this_val = item; + ant_value_t then_result = builtin_promise_then(js, then_args, 2); + js->this_val = saved_this; + if (is_err(then_result)) { + *out = then_result; + GC_ROOT_RESTORE(js, root_mark); + return ITER_ERROR; + } + + pctx->index++; + GC_ROOT_RESTORE(js, root_mark); + return ITER_CONTINUE; +} + static ant_value_t builtin_Promise_all(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "Promise.all requires an iterable"); @@ -10787,6 +10935,65 @@ static ant_value_t builtin_Promise_all(ant_t *js, ant_value_t *args, int nargs) return result_promise; } +static ant_value_t builtin_Promise_allSettled(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "Promise.allSettled requires an iterable"); + + GC_ROOT_SAVE(root_mark, js); + ant_value_t iterable = args[0]; + GC_ROOT_PIN(js, iterable); + uint8_t t = vtype(iterable); + if (t != T_ARR && t != T_OBJ) { + ant_value_t err = js_mkerr(js, "Promise.allSettled requires an iterable"); + GC_ROOT_RESTORE(js, root_mark); + return err; + } + + ant_value_t ctor = js->this_val; + GC_ROOT_PIN(js, ctor); + if (vtype(ctor) != T_FUNC && vtype(ctor) != T_CFUNC) ctor = js_mkundef(); + + ant_value_t result_promise = mkpromise_with_ctor(js, ctor); + GC_ROOT_PIN(js, result_promise); + if (is_err(result_promise)) { + GC_ROOT_RESTORE(js, root_mark); + return result_promise; + } + + ant_value_t tracker = mkobj(js, 0); + GC_ROOT_PIN(js, tracker); + ant_value_t results = mkarr(js); + GC_ROOT_PIN(js, results); + + js_setprop(js, tracker, js_mkstr(js, "remaining", 9), tov(0.0)); + js_setprop(js, tracker, js_mkstr(js, "results", 7), results); + set_slot(tracker, SLOT_DATA, result_promise); + + promise_all_iter_ctx_t ctx = { .tracker = tracker, .index = 0 }; + ant_value_t iter_result = iter_foreach(js, iterable, promise_all_settled_iter_cb, &ctx); + + if (is_err(iter_result)) { + GC_ROOT_RESTORE(js, root_mark); + return iter_result; + } + + int len = ctx.index; + ant_offset_t doff = get_dense_buf(results); + if (doff) { + if ((ant_offset_t)len > dense_capacity(doff)) doff = dense_grow(js, results, (ant_offset_t)len); + if (doff) array_len_set(js, results, (ant_offset_t)len); + } + + if (len == 0) { + js_resolve_promise(js, result_promise, mkval(T_ARR, vdata(results))); + GC_ROOT_RESTORE(js, root_mark); + return result_promise; + } + + js_setprop(js, tracker, js_mkstr(js, "remaining", 9), tov((double)len)); + GC_ROOT_RESTORE(js, root_mark); + return result_promise; +} + typedef struct { ant_value_t result_promise; ant_value_t resolve_fn; @@ -12482,6 +12689,7 @@ ant_t *js_create(void *buf, size_t len) { js_setprop(js, p_ctor_obj, js_mkstr(js, "try", 3), js_mkfun(builtin_Promise_try)); js_setprop(js, p_ctor_obj, js_mkstr(js, "withResolvers", 13), js_mkfun(builtin_Promise_withResolvers)); js_setprop(js, p_ctor_obj, js_mkstr(js, "all", 3), js_mkfun(builtin_Promise_all)); + js_setprop(js, p_ctor_obj, js_mkstr(js, "allSettled", 10), js_mkfun(builtin_Promise_allSettled)); js_setprop(js, p_ctor_obj, js_mkstr(js, "race", 4), js_mkfun(builtin_Promise_race)); js_setprop(js, p_ctor_obj, js_mkstr(js, "any", 3), js_mkfun(builtin_Promise_any)); js_setprop_nonconfigurable(js, p_ctor_obj, "prototype", 9, promise_proto); diff --git a/src/builtins/node/http2.mjs b/src/builtins/node/http2.mjs new file mode 100644 index 00000000..32ea74cd --- /dev/null +++ b/src/builtins/node/http2.mjs @@ -0,0 +1,59 @@ +import * as http from 'node:http'; +import * as https from 'node:https'; + +function clientNotImplemented() { + throw new Error('node:http2 client transport is not implemented yet'); +} + +// compatibility stub only +export class Http2Server extends http.Server {} +export class Http2SecureServer extends https.Server {} + +export class ClientHttp2Session {} +export class ClientHttp2Stream {} +export class ServerHttp2Session {} +export class ServerHttp2Stream {} + +export function createServer(options, requestListener) { + return http.createServer(options, requestListener); +} + +export function createSecureServer(options, requestListener) { + return https.createServer(options, requestListener); +} + +export function connect() { + clientNotImplemented(); +} + +export function getDefaultSettings() { + return {}; +} + +export function getPackedSettings() { + return new Uint8Array(0); +} + +export function getUnpackedSettings() { + return {}; +} + +export const constants = Object.freeze({}); +export const sensitiveHeaders = Object.freeze([]); + +export default { + ClientHttp2Session, + ClientHttp2Stream, + Http2Server, + Http2SecureServer, + ServerHttp2Session, + ServerHttp2Stream, + connect, + constants, + createServer, + createSecureServer, + getDefaultSettings, + getPackedSettings, + getUnpackedSettings, + sensitiveHeaders +}; diff --git a/src/builtins/node/stream.cjs b/src/builtins/node/stream.cjs new file mode 100644 index 00000000..d84a7f6d --- /dev/null +++ b/src/builtins/node/stream.cjs @@ -0,0 +1,563 @@ +'use strict'; + +var EventEmitter = require('node:events').EventEmitter; +var BufferCtor = typeof Buffer !== 'undefined' ? Buffer : require('node:buffer').Buffer; + +function noop() {} + +function nextTick(fn) { + if (typeof process !== 'undefined' && process && typeof process.nextTick === 'function') { + var args = Array.prototype.slice.call(arguments, 1); + process.nextTick(function () { + fn.apply(undefined, args); + }); + return; + } + + Promise.resolve().then(function () { + fn(); + }); +} + +function once(fn) { + var called = false; + return function () { + if (called) return; + called = true; + return fn.apply(this, arguments); + }; +} + +function inherits(target, source) { + Object.getOwnPropertyNames(source).forEach(function (name) { + if (name === 'constructor') return; + if (Object.prototype.hasOwnProperty.call(target, name)) return; + Object.defineProperty(target, name, Object.getOwnPropertyDescriptor(source, name)); + }); +} + +function normalizeChunk(chunk, objectMode, encoding) { + if (objectMode || chunk == null || BufferCtor.isBuffer(chunk) || chunk instanceof Uint8Array) return chunk; + if (typeof chunk === 'string') return BufferCtor.from(chunk, encoding || 'utf8'); + return BufferCtor.from(String(chunk), encoding || 'utf8'); +} + +function toAsyncIterable(source) { + if (source && typeof source[Symbol.asyncIterator] === 'function') return source; + if (source && typeof source[Symbol.iterator] === 'function') { + return { + async *[Symbol.asyncIterator]() { + for (var value of source) yield value; + } + }; + } + + if (source && typeof source.getReader === 'function') { + return { + async *[Symbol.asyncIterator]() { + var reader = source.getReader(); + try { + while (true) { + var result = await reader.read(); + if (!result || result.done) break; + yield result.value; + } + } finally { + if (reader.releaseLock) reader.releaseLock(); + } + } + }; + } + + return { + async *[Symbol.asyncIterator]() { + if (source !== undefined) yield source; + } + }; +} + +function Stream(options) { + if (!(this instanceof Stream)) return new Stream(options); + this.readable = true; + this.writable = true; + this.destroyed = false; + this._paused = false; + this._pipes = []; + this._streamOptions = options || {}; +} + +Stream.prototype = Object.create(EventEmitter.prototype); +Stream.prototype.constructor = Stream; + +Stream.prototype.pipe = function (dest, options) { + var source = this; + var end = !options || options.end !== false; + + function onData(chunk) { + if (!dest || typeof dest.write !== 'function') return; + var ok = dest.write(chunk); + if (ok === false && typeof source.pause === 'function') source.pause(); + } + + function onDrain() { + if (typeof source.resume === 'function') source.resume(); + } + + function onEnd() { + cleanup(); + if (end && dest && typeof dest.end === 'function') dest.end(); + } + + function onClose() { + cleanup(); + } + + function onError(err) { + cleanup(); + if (dest && typeof dest.emit === 'function' && dest.listenerCount('error') > 0) dest.emit('error', err); + } + + function cleanup() { + source.removeListener('data', onData); + source.removeListener('end', onEnd); + source.removeListener('close', onClose); + source.removeListener('error', onError); + if (dest && typeof dest.removeListener === 'function') dest.removeListener('drain', onDrain); + source._pipes = source._pipes.filter(function (entry) { + return entry.dest !== dest; + }); + } + + this._pipes.push({ dest: dest, cleanup: cleanup }); + this.on('data', onData); + this.once('end', onEnd); + this.once('close', onClose); + this.on('error', onError); + if (dest && typeof dest.on === 'function') dest.on('drain', onDrain); + if (dest && typeof dest.emit === 'function') dest.emit('pipe', this); + if (typeof this.resume === 'function') this.resume(); + return dest; +}; + +Stream.prototype.unpipe = function (dest) { + var pipes = this._pipes.slice(); + for (var i = 0; i < pipes.length; i++) { + if (!dest || pipes[i].dest === dest) pipes[i].cleanup(); + } + return this; +}; + +Stream.prototype.pause = function () { + this._paused = true; + this.emit('pause'); + return this; +}; + +Stream.prototype.resume = function () { + this._paused = false; + this.emit('resume'); + return this; +}; + +Stream.prototype.isPaused = function () { + return !!this._paused; +}; + +Stream.prototype.destroy = function (err) { + if (this.destroyed) return this; + + var self = this; + this.destroyed = true; + + function done(destroyErr) { + if (destroyErr) self.emit('error', destroyErr); + self.emit('close'); + } + + if (typeof this._destroy === 'function') { + this._destroy(err || null, once(done)); + } else done(err || null); + + return this; +}; + +function Readable(options) { + Stream.call(this, options); + options = options || {}; + this.readable = true; + this.writable = false; + this.readableEnded = false; + this._readableState = { + objectMode: !!options.objectMode, + ended: false, + endEmitted: false, + flowing: false, + reading: false, + highWaterMark: options.highWaterMark || 16384, + buffer: [] + }; + + if (typeof options.read === 'function') this._read = options.read; +} + +Readable.prototype = Object.create(Stream.prototype); +Readable.prototype.constructor = Readable; + +Readable.prototype._read = noop; + +Readable.prototype._flushReadable = function () { + while (this._readableState.flowing && this._readableState.buffer.length > 0) { + var chunk = this._readableState.buffer.shift(); + this.emit('data', chunk); + } + + if (this._readableState.ended && this._readableState.buffer.length === 0 && !this._readableState.endEmitted) { + this._readableState.endEmitted = true; + this.readableEnded = true; + this.emit('end'); + this.emit('close'); + } +}; + +Readable.prototype._maybeRead = function () { + if (this.destroyed || this._readableState.reading || this._readableState.ended) return; + if (this._readableState.buffer.length > 0) return; + + this._readableState.reading = true; + try { + this._read(this._readableState.highWaterMark); + } finally { + this._readableState.reading = false; + } +}; + +Readable.prototype.push = function (chunk, encoding) { + if (this.destroyed) return false; + + if (chunk === null) { + this._readableState.ended = true; + this._flushReadable(); + return false; + } + + this._readableState.buffer.push(normalizeChunk(chunk, this._readableState.objectMode, encoding)); + if (this._readableState.flowing) this._flushReadable(); + return this._readableState.flowing; +}; + +Readable.prototype.read = function () { + if (this._readableState.buffer.length === 0) this._maybeRead(); + if (this._readableState.buffer.length === 0) return null; + + var chunk = this._readableState.buffer.shift(); + if (this._readableState.flowing) this._flushReadable(); + return chunk; +}; + +Readable.prototype.on = function (event, listener) { + var result = Stream.prototype.on.call(this, event, listener); + if (event === 'data') this.resume(); + return result; +}; + +Readable.prototype.resume = function () { + this._readableState.flowing = true; + Stream.prototype.resume.call(this); + this._maybeRead(); + this._flushReadable(); + return this; +}; + +Readable.prototype.pause = function () { + this._readableState.flowing = false; + return Stream.prototype.pause.call(this); +}; + +Readable.from = function (source, options) { + var readable = new Readable(options); + + nextTick(function () { + (async function () { + try { + for await (var chunk of toAsyncIterable(source)) { + if (readable.destroyed) return; + readable.push(chunk); + } + readable.push(null); + } catch (err) { + readable.destroy(err); + } + })(); + }); + + return readable; +}; + +Readable.fromWeb = function (source, options) { + return Readable.from(source, options); +}; + +function Writable(options) { + Stream.call(this, options); + options = options || {}; + this.readable = false; + this.writable = true; + this.writableEnded = false; + this.writableFinished = false; + this._writableState = { + objectMode: !!options.objectMode || !!options.writableObjectMode, + finished: false, + ended: false + }; + + if (typeof options.write === 'function') this._write = options.write; + if (typeof options.final === 'function') this._final = options.final; + if (typeof options.destroy === 'function') this._destroy = options.destroy; +} + +Writable.prototype = Object.create(Stream.prototype); +Writable.prototype.constructor = Writable; + +Writable.prototype._write = function (_chunk, _encoding, callback) { + callback(); +}; + +Writable.prototype._final = function (callback) { + callback(); +}; + +Writable.prototype.write = function (chunk, encoding, callback) { + if (typeof encoding === 'function') { + callback = encoding; + encoding = undefined; + } + + if (this.writableEnded || this.destroyed) { + var writeErr = new Error('write after end'); + if (typeof callback === 'function') callback(writeErr); + else this.emit('error', writeErr); + return false; + } + + var self = this; + var done = once(function (err) { + if (err) { + self.destroy(err); + if (typeof callback === 'function') callback(err); + return; + } + if (typeof callback === 'function') callback(); + self.emit('drain'); + }); + + try { + this._write(normalizeChunk(chunk, this._writableState.objectMode, encoding), encoding || 'utf8', done); + } catch (err) { + done(err); + return false; + } + + return !this.destroyed; +}; + +Writable.prototype.end = function (chunk, encoding, callback) { + if (typeof chunk === 'function') { + callback = chunk; + chunk = undefined; + encoding = undefined; + } else if (typeof encoding === 'function') { + callback = encoding; + encoding = undefined; + } + + if (chunk !== undefined && chunk !== null) this.write(chunk, encoding); + if (this.writableEnded) { + if (typeof callback === 'function') callback(); + return this; + } + + var self = this; + this.writableEnded = true; + this._writableState.ended = true; + + this._final( + once(function (err) { + if (err) { + self.destroy(err); + if (typeof callback === 'function') callback(err); + return; + } + + self.writableFinished = true; + self._writableState.finished = true; + self.emit('finish'); + if (typeof callback === 'function') callback(); + if (!self.readable) self.emit('close'); + }) + ); + + return this; +}; + +Writable.prototype.cork = noop; +Writable.prototype.uncork = noop; + +function Duplex(options) { + Readable.call(this, options); + Writable.call(this, options); + options = options || {}; + this.readable = true; + this.writable = true; + this.allowHalfOpen = options.allowHalfOpen !== false; +} + +Duplex.prototype = Object.create(Readable.prototype); +Duplex.prototype.constructor = Duplex; +inherits(Duplex.prototype, Writable.prototype); + +function Transform(options) { + Duplex.call(this, options); + options = options || {}; + if (typeof options.transform === 'function') this._transform = options.transform; + if (typeof options.flush === 'function') this._flush = options.flush; +} + +Transform.prototype = Object.create(Duplex.prototype); +Transform.prototype.constructor = Transform; + +Transform.prototype._transform = function (chunk, _encoding, callback) { + callback(null, chunk); +}; + +Transform.prototype._write = function (chunk, encoding, callback) { + var self = this; + this._transform(chunk, encoding, function (err, data) { + if (err) { + callback(err); + return; + } + if (data !== undefined && data !== null) self.push(data); + callback(); + }); +}; + +Transform.prototype._final = function (callback) { + var self = this; + if (typeof this._flush === 'function') { + this._flush(function (err, data) { + if (err) { + callback(err); + return; + } + if (data !== undefined && data !== null) self.push(data); + self.push(null); + callback(); + }); + return; + } + + this.push(null); + callback(); +}; + +function PassThrough(options) { + Transform.call(this, options); +} + +PassThrough.prototype = Object.create(Transform.prototype); +PassThrough.prototype.constructor = PassThrough; + +PassThrough.prototype._transform = function (chunk, _encoding, callback) { + callback(null, chunk); +}; + +function finished(stream, callback) { + callback = once(typeof callback === 'function' ? callback : noop); + + function onFinish() { + cleanup(); + callback(); + } + + function onError(err) { + cleanup(); + callback(err); + } + + function cleanup() { + stream.removeListener('end', onFinish); + stream.removeListener('finish', onFinish); + stream.removeListener('close', onFinish); + stream.removeListener('error', onError); + } + + stream.on('end', onFinish); + stream.on('finish', onFinish); + stream.on('close', onFinish); + stream.on('error', onError); + return stream; +} + +function pipeline() { + var args = Array.prototype.slice.call(arguments); + var callback = typeof args[args.length - 1] === 'function' ? args.pop() : noop; + + if (args.length < 2) { + nextTick(callback); + return args[0]; + } + + var done = once(callback); + for (var i = 0; i < args.length - 1; i++) { + finished(args[i], function (err) { + if (err) done(err); + }); + args[i].pipe(args[i + 1]); + } + + finished(args[args.length - 1], done); + return args[args.length - 1]; +} + +var promises = { + pipeline: function () { + var args = Array.prototype.slice.call(arguments); + return new Promise(function (resolve, reject) { + args.push(function (err) { + if (err) reject(err); + else resolve(); + }); + pipeline.apply(undefined, args); + }); + }, + finished: function (stream) { + return new Promise(function (resolve, reject) { + finished(stream, function (err) { + if (err) reject(err); + else resolve(); + }); + }); + } +}; + +Stream.Stream = Stream; +Stream.Readable = Readable; +Stream.Writable = Writable; +Stream.Duplex = Duplex; +Stream.Transform = Transform; +Stream.PassThrough = PassThrough; +Stream.pipeline = pipeline; +Stream.finished = finished; +Stream.promises = promises; + +module.exports = Stream; +module.exports.default = Stream; +module.exports.Stream = Stream; +module.exports.Readable = Readable; +module.exports.Writable = Writable; +module.exports.Duplex = Duplex; +module.exports.Transform = Transform; +module.exports.PassThrough = PassThrough; +module.exports.pipeline = pipeline; +module.exports.finished = finished; +module.exports.promises = promises; diff --git a/src/builtins/node/stub.txt b/src/builtins/node/stub.txt new file mode 100644 index 00000000..bf95cff1 --- /dev/null +++ b/src/builtins/node/stub.txt @@ -0,0 +1,7 @@ +// TODO: +the following builtins are currently compatibility stubs, not full node.js implementations: + +- https.mjs +- http2.mjs +- tls.mjs +- stream.cjs diff --git a/src/builtins/node/tls.mjs b/src/builtins/node/tls.mjs new file mode 100644 index 00000000..a47e6d3b --- /dev/null +++ b/src/builtins/node/tls.mjs @@ -0,0 +1,131 @@ +import net from 'node:net'; +import internalTls from 'ant:internal/tls'; + +function defineTlsState(target) { + if (!target || (typeof target !== 'object' && typeof target !== 'function')) return target; + + if (target.encrypted === undefined) target.encrypted = true; + if (target.authorized === undefined) target.authorized = true; + if (target.authorizationError === undefined) target.authorizationError = null; + if (target.secureConnecting === undefined) target.secureConnecting = false; + + return target; +} + +function wrapSocket(socket) { + if (!socket || (typeof socket !== 'object' && typeof socket !== 'function')) return socket; + defineTlsState(socket); + + if (!(socket instanceof TLSSocket)) { + Object.setPrototypeOf(socket, TLSSocket.prototype); + } + + return socket; +} + +function createConnectionArgs(args) { + if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null) { + return args[0]; + } + + const [port, host, options] = args; + const normalized = Object.create(null); + + if (typeof port === 'number') normalized.port = port; + if (typeof host === 'string') normalized.host = host; + if (options && typeof options === 'object') Object.assign(normalized, options); + return normalized; +} + +export class TLSSocket extends net.Socket { + constructor(socket, options = undefined) { + if (socket && typeof socket === 'object') { + super(options); + return wrapSocket(socket); + } + + super(socket); + defineTlsState(this); + } + + getCipher() { + return undefined; + } + + getProtocol() { + return undefined; + } + + getSession() { + return undefined; + } + + getPeerCertificate() { + return {}; + } + + renegotiate(_options, callback) { + if (typeof callback === 'function') callback(null); + return true; + } +} + +export class SecureContext { + constructor(options) { + return internalTls.createContext(options); + } +} + +export function createSecureContext(options) { + return internalTls.createContext(options); +} + +export function isSecureContext(value) { + return internalTls.isContext(value); +} + +export function setConfigPath(path) { + return internalTls.setConfigPath(path); +} + +export function checkServerIdentity() { + return undefined; +} + +export function getCiphers() { + return []; +} + +export function createConnection(...args) { + const socket = net.connect(createConnectionArgs(args)); + return wrapSocket(socket); +} + +export function connect(...args) { + return createConnection(...args); +} + +export const rootCertificates = Object.freeze([]); +export const DEFAULT_ECDH_CURVE = 'auto'; +export const DEFAULT_MIN_VERSION = 'TLSv1.2'; +export const DEFAULT_MAX_VERSION = 'TLSv1.3'; +export const CLIENT_RENEG_LIMIT = 3; +export const CLIENT_RENEG_WINDOW = 600; + +export default { + TLSSocket, + SecureContext, + CLIENT_RENEG_LIMIT, + CLIENT_RENEG_WINDOW, + DEFAULT_ECDH_CURVE, + DEFAULT_MIN_VERSION, + DEFAULT_MAX_VERSION, + rootCertificates, + checkServerIdentity, + connect, + createConnection, + createSecureContext, + getCiphers, + isSecureContext, + setConfigPath +}; diff --git a/src/esm/commonjs.c b/src/esm/commonjs.c index 188bcff0..f92d8fb6 100644 --- a/src/esm/commonjs.c +++ b/src/esm/commonjs.c @@ -33,6 +33,7 @@ static ant_value_t esm_cjs_require(ant_t *js, ant_value_t *args, int nargs) { ant_value_t default_export = js_get_slot(ns, SLOT_DEFAULT); if (vtype(default_export) != T_UNDEF) return default_export; } + return ns; } diff --git a/src/gc/objects.c b/src/gc/objects.c index a6208792..1ce78a59 100644 --- a/src/gc/objects.c +++ b/src/gc/objects.c @@ -483,6 +483,7 @@ static void gc_mark_roots(ant_t *js) { gc_mark_codec_streams(js, gc_mark_value); gc_mark_compression_streams(js, gc_mark_value); gc_mark_zlib(js, gc_mark_value); + gc_mark_wasm(js, gc_mark_value); for ( ant_object_t *obj = g_pending_promises; diff --git a/src/main.c b/src/main.c index d9f57d2a..29c62906 100644 --- a/src/main.c +++ b/src/main.c @@ -79,6 +79,7 @@ #include "modules/domexception.h" #include "modules/abort.h" #include "modules/globals.h" +#include "modules/wasm.h" #include "modules/structured-clone.h" #include "modules/v8.h" #include "modules/worker_threads.h" @@ -579,6 +580,7 @@ int main(int argc, char *argv[]) { init_timer_module(); init_domexception_module(); init_globals_module(); + init_wasm_module(); init_builtin_module(); init_buffer_module(); init_structured_clone_module(); diff --git a/src/modules/abort.c b/src/modules/abort.c index 9343b357..b51b3779 100644 --- a/src/modules/abort.c +++ b/src/modules/abort.c @@ -44,6 +44,10 @@ static abort_timeout_entry_t *timeout_entries = NULL; static ant_value_t g_signal_proto = 0; static bool g_initialized = false; +static inline unsigned int abort_array_len(UT_array *arr) { + return arr ? utarray_len(arr) : 0; +} + static abort_signal_data_t *get_signal_data(ant_value_t obj) { ant_value_t slot = js_get_slot(obj, SLOT_DATA); if (vtype(slot) != T_NUM) return NULL; @@ -80,8 +84,18 @@ void signal_do_abort(ant_t *js, ant_value_t signal_obj, ant_value_t reason) { abort_signal_data_t *data = get_signal_data(signal_obj); if (!data || data->aborted) return; - UT_array *queue; utarray_new(queue, &abort_value_icd); - UT_array *to_fire; utarray_new(to_fire, &abort_value_icd); + UT_array *queue = NULL; + UT_array *to_fire = NULL; + + utarray_new(queue, &abort_value_icd); + utarray_new(to_fire, &abort_value_icd); + + if (!queue || !to_fire) { + if (queue) utarray_free(queue); + if (to_fire) utarray_free(to_fire); + signal_mark_aborted(js, signal_obj, reason); + return; + } utarray_push_back(queue, &signal_obj); @@ -93,17 +107,18 @@ void signal_do_abort(ant_t *js, ant_value_t signal_obj, ant_value_t reason) { d->aborted = true; d->fired = true; d->reason = reason; + js_set(js, *cur, "aborted", js_true); js_set(js, *cur, "reason", reason); utarray_push_back(to_fire, cur); - unsigned int nf = utarray_len(d->followers); + unsigned int nf = abort_array_len(d->followers); for (unsigned int i = 0; i < nf; i++) { ant_value_t *sig = (ant_value_t *)utarray_eltptr(d->followers, i); utarray_push_back(queue, sig); }} + utarray_free(queue); - for (unsigned int qi = 0; qi < utarray_len(to_fire); qi++) { ant_value_t *cur = (ant_value_t *)utarray_eltptr(to_fire, qi); abort_signal_data_t *d = get_signal_data(*cur); @@ -120,9 +135,12 @@ void signal_do_abort(ant_t *js, ant_value_t signal_obj, ant_value_t reason) { process_microtasks(js); } - unsigned int n = utarray_len(d->listeners); - for (unsigned int i = 0; i < n;) { + for (unsigned int i = 0;;) { + unsigned int n = abort_array_len(d->listeners); + if (i >= n) break; abort_listener_t *entry = (abort_listener_t *)utarray_eltptr(d->listeners, i); + + if (!entry) break; ant_value_t cb = entry->callback; bool once = entry->once; @@ -140,7 +158,7 @@ void abort_signal_remove_listener(ant_t *js, ant_value_t signal, ant_value_t cal abort_signal_data_t *data = get_signal_data(signal); if (!data) return; - unsigned int n = utarray_len(data->listeners); + unsigned int n = abort_array_len(data->listeners); for (unsigned int i = 0; i < n; i++) { abort_listener_t *entry = (abort_listener_t *)utarray_eltptr(data->listeners, i); if (entry->callback != callback) continue; @@ -156,8 +174,16 @@ static ant_value_t make_new_signal(ant_t *js) { data->aborted = false; data->fired = false; data->reason = js_mkundef(); + utarray_new(data->listeners, &abort_listener_icd); utarray_new(data->followers, &abort_value_icd); + + if (!data->listeners || !data->followers) { + if (data->listeners) utarray_free(data->listeners); + if (data->followers) utarray_free(data->followers); + free(data); + return js_mkerr(js, "AbortSignal: out of memory"); + } ant_value_t obj = js_mkobj(js); js_set_slot(obj, SLOT_DATA, ANT_PTR(data)); @@ -189,14 +215,14 @@ static ant_value_t abort_signal_add_event_listener(ant_t *js, ant_value_t *args, if (vtype(once_val) != T_UNDEF) once = js_truthy(js, once_val); } else if (nargs >= 3 && vtype(args[2]) == T_BOOL) once = js_truthy(js, args[2]); - unsigned int n = utarray_len(data->listeners); + unsigned int n = abort_array_len(data->listeners); for (unsigned int i = 0; i < n; i++) { abort_listener_t *e = (abort_listener_t *)utarray_eltptr(data->listeners, i); if (e->callback == args[1] && e->once == once) return js_mkundef(); } abort_listener_t entry = { args[1], once }; - utarray_push_back(data->listeners, &entry); + if (data->listeners) utarray_push_back(data->listeners, &entry); return js_mkundef(); } @@ -211,7 +237,7 @@ static ant_value_t abort_signal_remove_event_listener(ant_t *js, ant_value_t *ar abort_signal_data_t *data = get_signal_data(js_getthis(js)); if (!data) return js_mkundef(); - unsigned int n = utarray_len(data->listeners); + unsigned int n = abort_array_len(data->listeners); for (unsigned int i = 0; i < n; i++) { abort_listener_t *e = (abort_listener_t *)utarray_eltptr(data->listeners, i); if (e->callback != args[1]) continue; @@ -280,7 +306,7 @@ static ant_value_t abort_signal_static_any(ant_t *js, ant_value_t *args, int nar ant_value_t sig = js_arr_get(js, args[0], i); abort_signal_data_t *d = get_signal_data(sig); if (!d) continue; - utarray_push_back(d->followers, &composite); + if (d->followers) utarray_push_back(d->followers, &composite); } return composite; @@ -296,7 +322,7 @@ ant_value_t abort_signal_create_dependent(ant_t *js, ant_value_t source) { if (!d) return composite; if (d->aborted) signal_mark_aborted(js, composite, d->reason); - else utarray_push_back(d->followers, &composite); + else if (d->followers) utarray_push_back(d->followers, &composite); return composite; } @@ -430,14 +456,14 @@ void gc_mark_abort_signal_object(ant_t *js, ant_value_t signal, gc_mark_fn mark) if (!data) return; mark(js, data->reason); - unsigned int listener_count = utarray_len(data->listeners); + unsigned int listener_count = abort_array_len(data->listeners); for (unsigned int i = 0; i < listener_count; i++) { abort_listener_t *entry = (abort_listener_t *)utarray_eltptr(data->listeners, i); if (!entry) continue; mark(js, entry->callback); } - unsigned int follower_count = utarray_len(data->followers); + unsigned int follower_count = abort_array_len(data->followers); for (unsigned int i = 0; i < follower_count; i++) { ant_value_t *follower = (ant_value_t *)utarray_eltptr(data->followers, i); if (!follower) continue; @@ -473,5 +499,5 @@ void abort_signal_add_listener(ant_t *js, ant_value_t signal, ant_value_t callba } abort_listener_t entry = { callback, false }; - utarray_push_back(data->listeners, &entry); + if (data->listeners) utarray_push_back(data->listeners, &entry); } diff --git a/src/modules/buffer.c b/src/modules/buffer.c index 488f4ee2..21c05311 100644 --- a/src/modules/buffer.c +++ b/src/modules/buffer.c @@ -221,32 +221,6 @@ static void *ta_arena_alloc(size_t size) { return ptr; } -static ant_value_t js_arraybuffer_slice(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_typedarray_slice(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_typedarray_subarray(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_typedarray_fill(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_typedarray_at(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_typedarray_set(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_typedarray_copyWithin(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_typedarray_toReversed(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_typedarray_toSorted(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_typedarray_with(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_dataview_getUint8(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_dataview_setUint8(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_dataview_getInt16(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_dataview_setInt16(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_dataview_getInt32(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_dataview_setInt32(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_dataview_getFloat32(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_dataview_setFloat32(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_dataview_getFloat64(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_dataview_setFloat64(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_typedarray_toString(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_buffer_slice(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_buffer_toString(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_buffer_toBase64(ant_t *js, ant_value_t *args, int nargs); -static ant_value_t js_buffer_write(ant_t *js, ant_value_t *args, int nargs); - ArrayBufferData *create_array_buffer_data(size_t length) { ArrayBufferData *data = ant_calloc(sizeof(ArrayBufferData) + length); if (!data) return NULL; @@ -1304,6 +1278,51 @@ static ant_value_t js_dataview_constructor(ant_t *js, ant_value_t *args, int nar return obj; } +// DataView.prototype.getUint8(byteOffset) +static ant_value_t js_dataview_getInt8(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "getInt8 requires byteOffset"); + + ant_value_t this_val = js_getthis(js); + ant_value_t dv_data_val = js_get_slot(this_val, SLOT_DATA); + + if (vtype(dv_data_val) != T_NUM) { + return js_mkerr(js, "Not a DataView"); + } + + DataViewData *dv = (DataViewData *)(uintptr_t)js_getnum(dv_data_val); + size_t offset = (size_t)js_getnum(args[0]); + + if (offset >= dv->byte_length) { + return js_mkerr(js, "Offset out of bounds"); + } + + int8_t value = (int8_t)dv->buffer->data[dv->byte_offset + offset]; + return js_mknum((double)value); +} + +// DataView.prototype.setInt8(byteOffset, value) +static ant_value_t js_dataview_setInt8(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 2) return js_mkerr(js, "setInt8 requires byteOffset and value"); + + ant_value_t this_val = js_getthis(js); + ant_value_t dv_data_val = js_get_slot(this_val, SLOT_DATA); + + if (vtype(dv_data_val) != T_NUM) { + return js_mkerr(js, "Not a DataView"); + } + + DataViewData *dv = (DataViewData *)(uintptr_t)js_getnum(dv_data_val); + size_t offset = (size_t)js_getnum(args[0]); + int8_t value = (int8_t)js_to_int32(js_getnum(args[1])); + + if (offset >= dv->byte_length) { + return js_mkerr(js, "Offset out of bounds"); + } + + dv->buffer->data[dv->byte_offset + offset] = (uint8_t)value; + return js_mkundef(); +} + // DataView.prototype.getUint8(byteOffset) static ant_value_t js_dataview_getUint8(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "getUint8 requires byteOffset"); @@ -1380,6 +1399,67 @@ static ant_value_t js_dataview_getInt16(ant_t *js, ant_value_t *args, int nargs) return js_mknum((double)value); } +// DataView.prototype.getUint16(byteOffset, littleEndian) +static ant_value_t js_dataview_getUint16(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "getUint16 requires byteOffset"); + + ant_value_t this_val = js_getthis(js); + ant_value_t dv_data_val = js_get_slot(this_val, SLOT_DATA); + + if (vtype(dv_data_val) != T_NUM) { + return js_mkerr(js, "Not a DataView"); + } + + DataViewData *dv = (DataViewData *)(uintptr_t)js_getnum(dv_data_val); + size_t offset = (size_t)js_getnum(args[0]); + bool little_endian = (nargs > 1 && js_truthy(js, args[1])); + + if (offset + 2 > dv->byte_length) { + return js_mkerr(js, "Offset out of bounds"); + } + + uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; + uint16_t value; + + if (little_endian) value = (uint16_t)(ptr[0] | (ptr[1] << 8)); + else value = (uint16_t)((ptr[0] << 8) | ptr[1]); + + return js_mknum((double)value); +} + +// DataView.prototype.setUint16(byteOffset, value, littleEndian) +static ant_value_t js_dataview_setUint16(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 2) return js_mkerr(js, "setUint16 requires byteOffset and value"); + + ant_value_t this_val = js_getthis(js); + ant_value_t dv_data_val = js_get_slot(this_val, SLOT_DATA); + + if (vtype(dv_data_val) != T_NUM) { + return js_mkerr(js, "Not a DataView"); + } + + DataViewData *dv = (DataViewData *)(uintptr_t)js_getnum(dv_data_val); + size_t offset = (size_t)js_getnum(args[0]); + uint16_t value = (uint16_t)js_to_uint32(js_getnum(args[1])); + bool little_endian = (nargs > 2 && js_truthy(js, args[2])); + + if (offset + 2 > dv->byte_length) { + return js_mkerr(js, "Offset out of bounds"); + } + + uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; + + if (little_endian) { + ptr[0] = (uint8_t)(value & 0xFF); + ptr[1] = (uint8_t)((value >> 8) & 0xFF); + } else { + ptr[0] = (uint8_t)((value >> 8) & 0xFF); + ptr[1] = (uint8_t)(value & 0xFF); + } + + return js_mkundef(); +} + // DataView.prototype.getInt32(byteOffset, littleEndian) static ant_value_t js_dataview_getInt32(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "getInt32 requires byteOffset"); @@ -1514,6 +1594,69 @@ static ant_value_t js_dataview_setInt32(ant_t *js, ant_value_t *args, int nargs) return js_mkundef(); } +// DataView.prototype.getUint32(byteOffset, littleEndian) +static ant_value_t js_dataview_getUint32(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "getUint32 requires byteOffset"); + + ant_value_t this_val = js_getthis(js); + ant_value_t dv_data_val = js_get_slot(this_val, SLOT_DATA); + + if (vtype(dv_data_val) != T_NUM) { + return js_mkerr(js, "Not a DataView"); + } + + DataViewData *dv = (DataViewData *)(uintptr_t)js_getnum(dv_data_val); + size_t offset = (size_t)js_getnum(args[0]); + bool little_endian = (nargs > 1 && js_truthy(js, args[1])); + + if (offset + 4 > dv->byte_length) { + return js_mkerr(js, "Offset out of bounds"); + } + + uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; + uint32_t value; + + if (little_endian) value = (uint32_t)(ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24)); + else value = (uint32_t)((ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]); + + return js_mknum((double)value); +} + +// DataView.prototype.setUint32(byteOffset, value, littleEndian) +static ant_value_t js_dataview_setUint32(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 2) return js_mkerr(js, "setUint32 requires byteOffset and value"); + + ant_value_t this_val = js_getthis(js); + ant_value_t dv_data_val = js_get_slot(this_val, SLOT_DATA); + + if (vtype(dv_data_val) != T_NUM) { + return js_mkerr(js, "Not a DataView"); + } + + DataViewData *dv = (DataViewData *)(uintptr_t)js_getnum(dv_data_val); + size_t offset = (size_t)js_getnum(args[0]); + + uint32_t value = js_to_uint32(js_getnum(args[1])); + bool little_endian = (nargs > 2 && js_truthy(js, args[2])); + + if (offset + 4 > dv->byte_length) return js_mkerr(js, "Offset out of bounds"); + uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset; + + if (little_endian) { + ptr[0] = (uint8_t)(value & 0xFF); + ptr[1] = (uint8_t)((value >> 8) & 0xFF); + ptr[2] = (uint8_t)((value >> 16) & 0xFF); + ptr[3] = (uint8_t)((value >> 24) & 0xFF); + } else { + ptr[0] = (uint8_t)((value >> 24) & 0xFF); + ptr[1] = (uint8_t)((value >> 16) & 0xFF); + ptr[2] = (uint8_t)((value >> 8) & 0xFF); + ptr[3] = (uint8_t)(value & 0xFF); + } + + return js_mkundef(); +} + // DataView.prototype.setFloat32(byteOffset, value, littleEndian) static ant_value_t js_dataview_setFloat32(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 2) return js_mkerr(js, "setFloat32 requires byteOffset and value"); @@ -2267,12 +2410,18 @@ void init_buffer_module() { ant_value_t dataview_proto = js_mkobj(js); js_set_proto_init(dataview_proto, object_proto); + js_set(js, dataview_proto, "getInt8", js_mkfun(js_dataview_getInt8)); + js_set(js, dataview_proto, "setInt8", js_mkfun(js_dataview_setInt8)); js_set(js, dataview_proto, "getUint8", js_mkfun(js_dataview_getUint8)); js_set(js, dataview_proto, "setUint8", js_mkfun(js_dataview_setUint8)); js_set(js, dataview_proto, "getInt16", js_mkfun(js_dataview_getInt16)); js_set(js, dataview_proto, "setInt16", js_mkfun(js_dataview_setInt16)); + js_set(js, dataview_proto, "getUint16", js_mkfun(js_dataview_getUint16)); + js_set(js, dataview_proto, "setUint16", js_mkfun(js_dataview_setUint16)); js_set(js, dataview_proto, "getInt32", js_mkfun(js_dataview_getInt32)); js_set(js, dataview_proto, "setInt32", js_mkfun(js_dataview_setInt32)); + js_set(js, dataview_proto, "getUint32", js_mkfun(js_dataview_getUint32)); + js_set(js, dataview_proto, "setUint32", js_mkfun(js_dataview_setUint32)); js_set(js, dataview_proto, "getFloat32", js_mkfun(js_dataview_getFloat32)); js_set(js, dataview_proto, "setFloat32", js_mkfun(js_dataview_setFloat32)); js_set(js, dataview_proto, "getFloat64", js_mkfun(js_dataview_getFloat64)); diff --git a/src/modules/child_process.c b/src/modules/child_process.c index e4de1975..7079c8a0 100644 --- a/src/modules/child_process.c +++ b/src/modules/child_process.c @@ -1189,6 +1189,79 @@ static ant_value_t builtin_exec(ant_t *js, ant_value_t *args, int nargs) { return cp->promise; } +static ant_value_t exec_file_close_callback(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t fn = js_getcurrentfunc(js); + ant_value_t ctx = js_get_slot(fn, SLOT_DATA); + + ant_value_t callback = js_get(js, ctx, "callback"); + ant_value_t child = js_get(js, ctx, "child"); + + ant_value_t stdout_val = js_get(js, child, "stdoutText"); + ant_value_t stderr_val = js_get(js, child, "stderrText"); + ant_value_t exit_code_val = js_get(js, child, "exitCode"); + ant_value_t cb_args[3]; + + if (!is_callable(callback)) return js_mkundef(); + + if (vtype(exit_code_val) == T_NUM && (int)js_getnum(exit_code_val) != 0) { + char err_msg[256]; + snprintf(err_msg, sizeof(err_msg), "Command failed with exit code %d", (int)js_getnum(exit_code_val)); + cb_args[0] = js_make_error_silent(js, JS_ERR_GENERIC, err_msg); + } else cb_args[0] = js_mknull(); + + cb_args[1] = stdout_val; + cb_args[2] = stderr_val; + + ant_value_t result = sv_vm_call(js->vm, js, callback, js_mkundef(), cb_args, 3, NULL, false); + if (vtype(result) == T_ERR) log_listener_error(js, "execFile", result); + return js_mkundef(); +} + +static ant_value_t builtin_execFile(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t argv = js_mkundef(); + ant_value_t options = js_mkundef(); + ant_value_t callback = js_mkundef(); + + ant_value_t spawn_args[3]; + ant_value_t child; + + if (nargs < 1) return js_mkerr(js, "execFile() requires a file"); + if (vtype(args[0]) != T_STR) return js_mkerr(js, "File must be a string"); + + if (nargs >= 2 && is_callable(args[nargs - 1])) { + callback = args[nargs - 1]; + nargs--; + } + + if (nargs >= 2) { + if (vtype(args[1]) == T_ARR) { + argv = args[1]; + if (nargs >= 3 && is_special_object(args[2])) options = args[2]; + } else if (is_special_object(args[1])) options = args[1]; + } + + spawn_args[0] = args[0]; + spawn_args[1] = argv; + spawn_args[2] = options; + + child = builtin_spawn(js, spawn_args, 3); + if (vtype(child) != T_OBJ || !is_callable(callback)) return child; + + ant_value_t ctx = js_mkobj(js); + js_set(js, ctx, "callback", callback); + js_set(js, ctx, "child", child); + + // TODO: reduce duck-typing + ant_value_t close_listener = js_heavy_mkfun(js, exec_file_close_callback, ctx); + ant_value_t once_fn = js_get(js, child, "once"); + ant_value_t once_args[2] = { js_mkstr(js, "close", 5), close_listener }; + + ant_value_t once_result = sv_vm_call(js->vm, js, once_fn, child, once_args, 2, NULL, false); + if (vtype(once_result) == T_ERR) return once_result; + + return child; +} + static ant_value_t builtin_execSync(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "execSync() requires a command"); if (vtype(args[0]) != T_STR) return js_mkerr(js, "Command must be a string"); @@ -1539,6 +1612,38 @@ static ant_value_t builtin_spawnSync(ant_t *js, ant_value_t *args, int nargs) { } #endif +static ant_value_t builtin_execFileSync(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t argv = js_mkundef(); + ant_value_t options = js_mkundef(); + + ant_value_t spawn_args[3]; + ant_value_t result; + ant_value_t status; + + if (nargs < 1) return js_mkerr(js, "execFileSync() requires a file"); + if (vtype(args[0]) != T_STR) return js_mkerr(js, "File must be a string"); + + if (nargs >= 2) { + if (vtype(args[1]) == T_ARR) { + argv = args[1]; + if (nargs >= 3 && is_special_object(args[2])) options = args[2]; + } else if (is_special_object(args[1])) options = args[1]; + } + + spawn_args[0] = args[0]; + spawn_args[1] = argv; + spawn_args[2] = options; + + result = builtin_spawnSync(js, spawn_args, 3); + if (vtype(result) != T_OBJ) return result; + + status = js_get(js, result, "status"); + if (vtype(status) == T_NUM && (int)js_getnum(status) != 0) + return js_mkerr(js, "Command failed with exit code %d", (int)js_getnum(status)); + + return js_get(js, result, "stdout"); +} + static ant_value_t builtin_fork(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "fork() requires a module path"); if (vtype(args[0]) != T_STR) return js_mkerr(js, "Module path must be a string"); @@ -1598,7 +1703,9 @@ ant_value_t child_process_library(ant_t *js) { js_set(js, lib, "spawn", js_mkfun(builtin_spawn)); js_set(js, lib, "exec", js_mkfun(builtin_exec)); + js_set(js, lib, "execFile", js_mkfun(builtin_execFile)); js_set(js, lib, "execSync", js_mkfun(builtin_execSync)); + js_set(js, lib, "execFileSync", js_mkfun(builtin_execFileSync)); js_set(js, lib, "spawnSync", js_mkfun(builtin_spawnSync)); js_set(js, lib, "fork", js_mkfun(builtin_fork)); js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "child_process", 13)); diff --git a/src/modules/crypto.c b/src/modules/crypto.c index 5371d6f3..1b845ee9 100644 --- a/src/modules/crypto.c +++ b/src/modules/crypto.c @@ -1,6 +1,7 @@ #include #include #include +#include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wimplicit-int-conversion" @@ -14,12 +15,222 @@ #endif #include "ant.h" +#include "base64.h" #include "errors.h" #include "runtime.h" #include "modules/crypto.h" #include "modules/buffer.h" #include "modules/symbol.h" +typedef enum { + CRYPTO_TEXT_UTF8 = 0, + CRYPTO_TEXT_HEX, + CRYPTO_TEXT_BASE64, + CRYPTO_TEXT_LATIN1 +} crypto_text_encoding_t; + +typedef struct { + EVP_MD_CTX *ctx; + const EVP_MD *md; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int digest_len; + bool finalized; +} ant_hash_state_t; + +static ant_value_t crypto_make_buffer(ant_t *js, const uint8_t *data, size_t len) { + ArrayBufferData *buffer = create_array_buffer_data(len); + if (!buffer) return js_mkerr(js, "Failed to allocate Buffer"); + if (len > 0 && data) memcpy(buffer->data, data, len); + return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, len, "Buffer"); +} + +static bool crypto_get_mutable_bytes(ant_value_t value, uint8_t **out, size_t *len) { + ant_value_t slot = js_get_slot(value, SLOT_BUFFER); + if (vtype(slot) == T_TYPEDARRAY) { + TypedArrayData *ta = (TypedArrayData *)js_gettypedarray(slot); + if (!ta || !ta->buffer || ta->buffer->is_detached) return false; + *out = ta->buffer->data + ta->byte_offset; + *len = ta->byte_length; + return true; + } + + if (vtype(slot) == T_NUM) { + ArrayBufferData *ab = (ArrayBufferData *)(uintptr_t)(size_t)js_getnum(slot); + if (!ab || ab->is_detached) return false; + *out = ab->data; + *len = ab->length; + return true; + } + + return false; +} + +static crypto_text_encoding_t crypto_parse_encoding(const char *str, size_t len) { + if (len == 3 && strncasecmp(str, "hex", 3) == 0) return CRYPTO_TEXT_HEX; + if (len == 6 && strncasecmp(str, "base64", 6) == 0) return CRYPTO_TEXT_BASE64; + if (len == 9 && strncasecmp(str, "base64url", 9) == 0) return CRYPTO_TEXT_BASE64; + + if ( + (len == 5 && strncasecmp(str, "ascii", 5) == 0) || + (len == 6 && strncasecmp(str, "latin1", 6) == 0) || + (len == 6 && strncasecmp(str, "binary", 6) == 0) + ) return CRYPTO_TEXT_LATIN1; + + return CRYPTO_TEXT_UTF8; +} + +static uint8_t crypto_hex_nibble(char ch) { + if (ch >= '0' && ch <= '9') return (uint8_t)(ch - '0'); + if (ch >= 'a' && ch <= 'f') return (uint8_t)(10 + ch - 'a'); + if (ch >= 'A' && ch <= 'F') return (uint8_t)(10 + ch - 'A'); + return 0xFFu; +} + +static uint8_t *crypto_decode_hex(const char *str, size_t len, size_t *out_len) { + if ((len & 1u) != 0) return NULL; + + uint8_t *buf = malloc(len / 2u); + if (!buf) return NULL; + + for (size_t i = 0; i < len; i += 2u) { + uint8_t hi = crypto_hex_nibble(str[i]); + uint8_t lo = crypto_hex_nibble(str[i + 1u]); + if (hi == 0xFFu || lo == 0xFFu) { + free(buf); + return NULL; + } + buf[i / 2u] = (uint8_t)((hi << 4u) | lo); + } + + *out_len = len / 2u; + return buf; +} + +static ant_value_t crypto_get_input_bytes( + ant_t *js, ant_value_t value, ant_value_t encoding_val, + const uint8_t **out_bytes, size_t *out_len, uint8_t **owned +) { + const uint8_t *bytes = NULL; + size_t len = 0; + uint8_t *buf = NULL; + + ant_value_t string_val; + size_t str_len = 0; + + const char *str = NULL; + crypto_text_encoding_t enc = CRYPTO_TEXT_UTF8; + + if (buffer_source_get_bytes(js, value, &bytes, &len)) { + *out_bytes = bytes; + *out_len = len; + *owned = NULL; + return js_mkundef(); + } + + string_val = js_tostring_val(js, value); + if (is_err(string_val)) return string_val; + + str = js_getstr(js, string_val, &str_len); + if (!str) return js_mkerr(js, "Failed to convert hash input to string"); + + if (vtype(encoding_val) == T_STR) { + size_t enc_len = 0; + const char *enc_str = js_getstr(js, encoding_val, &enc_len); + if (enc_str) enc = crypto_parse_encoding(enc_str, enc_len); + } + + switch (enc) { + case CRYPTO_TEXT_HEX: + buf = crypto_decode_hex(str, str_len, &len); + if (!buf) return js_mkerr(js, "Invalid hex string"); + bytes = buf; + break; + case CRYPTO_TEXT_BASE64: + buf = ant_base64_decode(str, str_len, &len); + if (!buf) return js_mkerr(js, "Invalid base64 string"); + bytes = buf; + break; + case CRYPTO_TEXT_LATIN1: + buf = malloc(str_len); + if (!buf) return js_mkerr(js, "Out of memory"); + for (size_t i = 0; i < str_len; i++) buf[i] = (uint8_t)str[i]; + bytes = buf; + len = str_len; + break; + case CRYPTO_TEXT_UTF8: + default: + bytes = (const uint8_t *)str; + len = str_len; + break; + } + + *out_bytes = bytes; + *out_len = len; + *owned = buf; + return js_mkundef(); +} + +static ant_hash_state_t *crypto_get_hash_state(ant_value_t value) { + ant_value_t slot = js_get_slot(value, SLOT_DATA); + if (vtype(slot) != T_NUM) return NULL; + + ant_hash_state_t *state = (ant_hash_state_t *)(uintptr_t)js_getnum(slot); + return (state && state->ctx) ? state : NULL; +} + +static ant_value_t crypto_require_hash_state( + ant_t *js, ant_value_t value, ant_hash_state_t **out_state +) { + ant_hash_state_t *state = crypto_get_hash_state(value); + if (!state) return js_mkerr(js, "Invalid Hash state"); + *out_state = state; + return js_mkundef(); +} + +static ant_value_t crypto_digest_result( + ant_t *js, const uint8_t *digest, size_t digest_len, ant_value_t encoding_val +) { + if (vtype(encoding_val) != T_STR) return crypto_make_buffer(js, digest, digest_len); + + size_t enc_len = 0; + const char *enc = js_getstr(js, encoding_val, &enc_len); + if (!enc) return crypto_make_buffer(js, digest, digest_len); + + crypto_text_encoding_t encoding = crypto_parse_encoding(enc, enc_len); + + if (encoding == CRYPTO_TEXT_HEX) { + char *hex = malloc(digest_len * 2u + 1u); + if (!hex) return js_mkerr(js, "Out of memory"); + for (size_t i = 0; i < digest_len; i++) { + snprintf(hex + (i * 2u), 3, "%02x", digest[i]); + } + ant_value_t result = js_mkstr(js, hex, digest_len * 2u); + free(hex); + return result; + } + + if (encoding == CRYPTO_TEXT_BASE64) { + size_t out_len = 0; + char *encoded = ant_base64_encode(digest, digest_len, &out_len); + if (!encoded) return js_mkerr(js, "Failed to encode base64"); + + if (enc_len == 9 && strncasecmp(enc, "base64url", 9) == 0) { + for (size_t i = 0; i < out_len; i++) { + if (encoded[i] == '+') encoded[i] = '-'; + else if (encoded[i] == '/') encoded[i] = '_'; + } + while (out_len > 0 && encoded[out_len - 1u] == '=') out_len--; + } + + ant_value_t result = js_mkstr(js, encoded, out_len); + free(encoded); + + return result; + } + + return crypto_make_buffer(js, digest, digest_len); +} + int ensure_crypto_init(void) { static int crypto_initialized = 0; @@ -83,17 +294,9 @@ static ant_value_t js_crypto_random_bytes(ant_t *js, ant_value_t *args, int narg } randombytes_buf(random_bytes, length); - - ant_value_t array = js_mkobj(js); - js_set(js, array, "length", js_mknum((double)length)); - - for (int i = 0; i < length; i++) { - char key[16]; - snprintf(key, sizeof(key), "%d", i); - js_set(js, array, key, js_mknum((double)random_bytes[i])); - } - + ant_value_t array = crypto_make_buffer(js, random_bytes, (size_t)length); free(random_bytes); + return array; } @@ -167,11 +370,180 @@ static ant_value_t js_crypto_get_random_values(ant_t *js, ant_value_t *args, int return args[0]; } +static ant_value_t js_crypto_random_fill_sync(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "randomFillSync requires a target"); + if (ensure_crypto_init() < 0) return js_mkerr(js, "libsodium initialization failed"); + + uint8_t *bytes = NULL; + size_t len = 0; + if (!crypto_get_mutable_bytes(args[0], &bytes, &len)) { + return js_mkerr(js, "randomFillSync target must be a Buffer, TypedArray, or ArrayBuffer"); + } + + size_t offset = 0; + if (nargs >= 2 && vtype(args[1]) != T_UNDEF) { + double num = js_to_number(js, args[1]); + if (num < 0) return js_mkerr(js, "randomFillSync offset must be non-negative"); + offset = (size_t)num; + } + + size_t size = len - offset; + if (nargs >= 3 && vtype(args[2]) != T_UNDEF) { + double num = js_to_number(js, args[2]); + if (num < 0) return js_mkerr(js, "randomFillSync size must be non-negative"); + size = (size_t)num; + } + + if (offset > len || size > len - offset) { + return js_mkerr(js, "randomFillSync range is out of bounds"); + } + + randombytes_buf(bytes + offset, size); + return args[0]; +} + +static ant_value_t js_hash_update(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t this_val = js_getthis(js); + ant_hash_state_t *state = NULL; + + const uint8_t *bytes = NULL; + size_t len = 0; + + uint8_t *owned = NULL; + ant_value_t err; + + err = crypto_require_hash_state(js, this_val, &state); + if (is_err(err)) return err; + if (state->finalized) return js_mkerr(js, "Hash digest already called"); + if (nargs < 1) return js_mkerr(js, "Hash.update requires data"); + + ant_value_t encoding = (nargs >= 2) ? args[1] : js_mkundef(); + err = crypto_get_input_bytes(js, args[0], encoding, &bytes, &len, &owned); + if (is_err(err)) goto cleanup; + + if (EVP_DigestUpdate(state->ctx, bytes, len) != 1) { + err = js_mkerr(js, "Hash update failed"); + goto cleanup; + } + + err = this_val; + +cleanup: + if (owned) free(owned); + return err; +} + +static ant_value_t js_hash_digest(ant_t *js, ant_value_t *args, int nargs) { + ant_hash_state_t *state = NULL; + ant_value_t err = crypto_require_hash_state(js, js_getthis(js), &state); + + if (is_err(err)) return err; + if (state->finalized) return js_mkerr(js, "Hash digest already called"); + + if (EVP_DigestFinal_ex(state->ctx, state->digest, &state->digest_len) != 1) { + return js_mkerr(js, "Hash digest failed"); + } + + state->finalized = true; + EVP_MD_CTX_free(state->ctx); + state->ctx = NULL; + + return crypto_digest_result(js, state->digest, state->digest_len, nargs >= 1 ? args[0] : js_mkundef()); +} + +static ant_value_t js_crypto_create_hash(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "createHash requires an algorithm"); + + ant_value_t algo_val = js_tostring_val(js, args[0]); + if (is_err(algo_val)) return algo_val; + + size_t algo_len = 0; + const char *algo = js_getstr(js, algo_val, &algo_len); + if (!algo || algo_len == 0) return js_mkerr(js, "Invalid hash algorithm"); + + char *algo_name = strndup(algo, algo_len); + if (!algo_name) return js_mkerr(js, "Out of memory"); + + const EVP_MD *md = EVP_get_digestbyname(algo_name); + free(algo_name); + if (!md) return js_mkerr_typed(js, JS_ERR_TYPE, "Unsupported hash algorithm"); + + ant_hash_state_t *state = calloc(1, sizeof(*state)); + if (!state) return js_mkerr(js, "Out of memory"); + + state->ctx = EVP_MD_CTX_new(); + state->md = md; + if (!state->ctx || EVP_DigestInit_ex(state->ctx, md, NULL) != 1) { + if (state->ctx) EVP_MD_CTX_free(state->ctx); + free(state); + return js_mkerr(js, "Failed to initialize hash"); + } + + ant_value_t obj = js_mkobj(js); + js_set(js, obj, "update", js_mkfun(js_hash_update)); + js_set(js, obj, "digest", js_mkfun(js_hash_digest)); + + js_set_slot(obj, SLOT_DATA, ANT_PTR(state)); + js_set_sym(js, obj, get_toStringTag_sym(), js_mkstr(js, "Hash", 4)); + + return obj; +} + +static ant_value_t js_crypto_hash(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t algo_val; + ant_value_t output_encoding; + + const char *algo; + size_t algo_len = 0; + char *algo_name = NULL; + + const EVP_MD *md = NULL; + const uint8_t *bytes = NULL; + + size_t len = 0; + uint8_t *owned = NULL; + + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int digest_len = 0; + ant_value_t err; + + if (nargs < 2) return js_mkerr(js, "hash requires algorithm and data"); + output_encoding = nargs >= 3 ? args[2] : js_mkundef(); + + algo_val = js_tostring_val(js, args[0]); + if (is_err(algo_val)) return algo_val; + + algo = js_getstr(js, algo_val, &algo_len); + if (!algo || algo_len == 0) return js_mkerr(js, "Invalid hash algorithm"); + + algo_name = strndup(algo, algo_len); + if (!algo_name) return js_mkerr(js, "Out of memory"); + + md = EVP_get_digestbyname(algo_name); + free(algo_name); + if (!md) return js_mkerr_typed(js, JS_ERR_TYPE, "Unsupported hash algorithm"); + + err = crypto_get_input_bytes(js, args[1], js_mkundef(), &bytes, &len, &owned); + if (is_err(err)) goto cleanup; + + if (EVP_Digest(bytes, len, digest, &digest_len, md, NULL) != 1) { + err = js_mkerr(js, "Hash failed"); + goto cleanup; + } + + err = crypto_digest_result(js, digest, digest_len, output_encoding); + +cleanup: + if (owned) free(owned); + return err; +} + static ant_value_t create_crypto_obj(ant_t *js) { ant_value_t crypto_obj = js_mkobj(js); js_set(js, crypto_obj, "random", js_mkfun(js_crypto_random)); js_set(js, crypto_obj, "randomBytes", js_mkfun(js_crypto_random_bytes)); + js_set(js, crypto_obj, "randomFillSync", js_mkfun(js_crypto_random_fill_sync)); js_set(js, crypto_obj, "randomUUID", js_mkfun(js_crypto_random_uuid)); js_set(js, crypto_obj, "randomUUIDv7", js_mkfun(js_crypto_random_uuidv7)); js_set(js, crypto_obj, "getRandomValues", js_mkfun(js_crypto_get_random_values)); @@ -191,7 +563,10 @@ ant_value_t crypto_library(ant_t *js) { ant_value_t webcrypto = create_crypto_obj(js); js_set(js, lib, "webcrypto", webcrypto); + js_set(js, lib, "hash", js_mkfun(js_crypto_hash)); + js_set(js, lib, "createHash", js_mkfun(js_crypto_create_hash)); js_set(js, lib, "randomBytes", js_mkfun(js_crypto_random_bytes)); + js_set(js, lib, "randomFillSync", js_mkfun(js_crypto_random_fill_sync)); js_set(js, lib, "randomUUID", js_mkfun(js_crypto_random_uuid)); js_set(js, lib, "getRandomValues", js_mkfun(js_crypto_get_random_values)); js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "crypto", 6)); diff --git a/src/modules/events.c b/src/modules/events.c index 5196b8ff..6e8ef8d5 100644 --- a/src/modules/events.c +++ b/src/modules/events.c @@ -542,7 +542,7 @@ void js_dispatch_global_event(ant_t *js, ant_value_t event_obj) { static bool eventemitter_add_listener_impl( ant_t *js, ant_value_t target, const char *event_type, - ant_value_t listener, bool once + ant_value_t listener, bool once, bool prepend ) { EventType *evt = NULL; EventListenerEntry entry = {0}; @@ -559,7 +559,15 @@ static bool eventemitter_add_listener_impl( entry.signal = js_mkundef(); entry.once = once; entry.capture = false; - utarray_push_back(evt->listeners, &entry); + + if (!prepend || utarray_len(evt->listeners) == 0) utarray_push_back(evt->listeners, &entry); + else { + utarray_push_back(evt->listeners, &entry); + EventListenerEntry *items = (EventListenerEntry *)utarray_eltptr(evt->listeners, 0); + if (!items) return false; + memmove(items + 1, items, (utarray_len(evt->listeners) - 1u) * sizeof(*items)); + items[0] = entry; + } return true; } @@ -634,28 +642,36 @@ bool eventemitter_add_listener( ant_value_t target, const char *event_type, ant_value_t listener, bool once ) { - return eventemitter_add_listener_impl(js, target, event_type, listener, once); + return eventemitter_add_listener_impl(js, target, event_type, listener, once, false); } -static ant_value_t js_eventemitter_add(ant_t *js, ant_value_t *args, int nargs, bool once) { +static ant_value_t js_eventemitter_add(ant_t *js, ant_value_t *args, int nargs, bool once, bool prepend) { const char *event_type = NULL; if (nargs < 2) return js_mkerr(js, "requires 2 arguments (event, listener)"); event_type = js_getstr(js, args[0], NULL); if (!event_type) return js_mkerr(js, "event must be a string"); - if (!eventemitter_add_listener_impl(js, js_getthis(js), event_type, args[1], once)) + if (!eventemitter_add_listener_impl(js, js_getthis(js), event_type, args[1], once, prepend)) return js_mkerr(js, "listener must be a function"); return js_getthis(js); } static ant_value_t js_eventemitter_on(ant_t *js, ant_value_t *args, int nargs) { - return js_eventemitter_add(js, args, nargs, false); + return js_eventemitter_add(js, args, nargs, false, false); } static ant_value_t js_eventemitter_once(ant_t *js, ant_value_t *args, int nargs) { - return js_eventemitter_add(js, args, nargs, true); + return js_eventemitter_add(js, args, nargs, true, false); +} + +static ant_value_t js_eventemitter_prepend_listener(ant_t *js, ant_value_t *args, int nargs) { + return js_eventemitter_add(js, args, nargs, false, true); +} + +static ant_value_t js_eventemitter_prepend_once_listener(ant_t *js, ant_value_t *args, int nargs) { + return js_eventemitter_add(js, args, nargs, true, true); } static ant_value_t js_eventemitter_removeAllListeners(ant_t *js, ant_value_t *args, int nargs) { @@ -680,14 +696,15 @@ static ant_value_t js_eventemitter_listenerCount(ant_t *js, ant_value_t *args, i static ant_value_t js_eventemitter_eventNames(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); ant_value_t result = js_mkarr(js); + EventType **events = get_or_create_emitter_events(js, this_obj); if (events && *events) { EventType *evt, *tmp; - HASH_ITER(hh, *events, evt, tmp) { - if (utarray_len(evt->listeners) > 0) - js_arr_push(js, result, js_mkstr(js, evt->event_type, strlen(evt->event_type))); - } + HASH_ITER(hh, *events, evt, tmp) if (utarray_len(evt->listeners) > 0) js_arr_push( + js, result, js_mkstr(js, evt->event_type, strlen(evt->event_type)) + ); } + return result; } @@ -699,6 +716,8 @@ ant_value_t events_library(ant_t *js) { js_set(js, eventemitter_proto, "on", js_mkfun(js_eventemitter_on)); js_set(js, eventemitter_proto, "addListener", js_mkfun(js_eventemitter_on)); js_set(js, eventemitter_proto, "once", js_mkfun(js_eventemitter_once)); + js_set(js, eventemitter_proto, "prependListener", js_mkfun(js_eventemitter_prepend_listener)); + js_set(js, eventemitter_proto, "prependOnceListener", js_mkfun(js_eventemitter_prepend_once_listener)); js_set(js, eventemitter_proto, "off", js_mkfun(js_eventemitter_off)); js_set(js, eventemitter_proto, "removeListener", js_mkfun(js_eventemitter_off)); js_set(js, eventemitter_proto, "emit", js_mkfun(js_eventemitter_emit)); @@ -712,8 +731,7 @@ ant_value_t events_library(ant_t *js) { js_set_descriptor(js, eventemitter_ctor, "name", 4, 0); ant_value_t ctor_fn = js_obj_to_func_ex(eventemitter_ctor, SV_CALL_IS_DEFAULT_CTOR); - js_set(js, lib, "EventEmitter", ctor_fn); - js_set(js, lib, "default", ctor_fn); + js_set_module_default(js, lib, ctor_fn, "EventEmitter"); js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "events", 6)); return lib; diff --git a/src/modules/fs.c b/src/modules/fs.c index 10631f91..202cf80b 100644 --- a/src/modules/fs.c +++ b/src/modules/fs.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -11,18 +12,23 @@ #include #include "ant.h" +#include "ptr.h" #include "utf8.h" #include "utils.h" #include "base64.h" #include "errors.h" +#include "watch.h" #include "internal.h" #include "runtime.h" #include "descriptors.h" +#include "gc/roots.h" #include "gc/modules.h" +#include "silver/engine.h" #include "modules/fs.h" #include "modules/buffer.h" +#include "modules/events.h" #include "modules/symbol.h" #define fs_err_code(js, code, op, path) ({ \ @@ -42,6 +48,553 @@ typedef enum { FS_ENC_ASCII, } fs_encoding_t; +typedef enum { + FS_OP_READ, + FS_OP_WRITE, + FS_OP_UNLINK, + FS_OP_MKDIR, + FS_OP_RMDIR, + FS_OP_STAT, + FS_OP_READ_BYTES, + FS_OP_EXISTS, + FS_OP_READDIR, + FS_OP_ACCESS, + FS_OP_REALPATH, + FS_OP_WRITE_FD, + FS_OP_OPEN, + FS_OP_CLOSE +} fs_op_type_t; + +typedef struct fs_request_s { + uv_fs_t uv_req; + ant_t *js; + ant_value_t promise; + + char *path; + char *data; + char *error_msg; + size_t data_len; + + fs_op_type_t op_type; + fs_encoding_t encoding; + uv_file fd; + + int completed; + int failed; + int recursive; + int error_code; +} fs_request_t; + +typedef enum { + FS_WATCH_MODE_EVENT = 0, + FS_WATCH_MODE_STAT +} fs_watch_mode_t; + +typedef union { + uv_fs_event_t event; + uv_fs_poll_t poll; +} fs_watcher_handle_t; + +typedef struct fs_watcher_s { + ant_t *js; + ant_value_t obj; + ant_value_t callback; + fs_watcher_handle_t handle; + uv_stat_t last_stat; + + struct fs_watcher_s *next_active; + char *path; + + bool last_stat_valid; + bool in_active_list; + bool closing; + bool handle_closed; + bool finalized; + bool persistent; + + fs_watch_mode_t mode; +} fs_watcher_t; + +typedef struct { + bool persistent; + bool recursive; + ant_value_t listener; +} fs_watch_options_t; + +typedef struct { + bool persistent; + unsigned int interval_ms; + ant_value_t listener; +} fs_watchfile_options_t; + +static ant_value_t g_fswatcher_proto = 0; +static ant_value_t g_fswatcher_ctor = 0; + +static fs_watcher_t *active_watchers = NULL; +static UT_array *pending_requests = NULL; + +enum { FS_WATCHER_NATIVE_TAG = 0x46535754u }; // FSWT + +static fs_watcher_t *fs_watcher_data(ant_value_t value) { + if (!js_check_native_tag(value, FS_WATCHER_NATIVE_TAG)) return NULL; + return (fs_watcher_t *)js_get_native_ptr(value); +} + +static void fs_add_active_watcher(fs_watcher_t *watcher) { + if (!watcher || watcher->in_active_list) return; + watcher->next_active = active_watchers; + active_watchers = watcher; + watcher->in_active_list = true; +} + +static void fs_remove_active_watcher(fs_watcher_t *watcher) { + fs_watcher_t **it = NULL; + if (!watcher || !watcher->in_active_list) return; + + for (it = &active_watchers; *it; it = &(*it)->next_active) { + if (*it != watcher) continue; + *it = watcher->next_active; + watcher->next_active = NULL; + watcher->in_active_list = false; + return; + } +} + +static ant_value_t fs_call_value( + ant_t *js, + ant_value_t fn, + ant_value_t this_val, + ant_value_t *args, + int nargs +) { + ant_value_t saved_this = js->this_val; + ant_value_t result = js_mkundef(); + + js->this_val = this_val; + if (vtype(fn) == T_CFUNC) + result = ((ant_value_t (*)(ant_t *, ant_value_t *, int))vdata(fn))(js, args, nargs); + else result = sv_vm_call(js->vm, js, fn, this_val, args, nargs, NULL, false); + js->this_val = saved_this; + + return result; +} + +static ant_value_t fs_stats_object_new( + ant_t *js, + mode_t mode, + double size, + double uid, + double gid +) { + ant_value_t stat_obj = js_mkobj(js); + ant_value_t proto = js_get_ctor_proto(js, "Stats", 5); + + if (is_object_type(proto) || is_special_object(proto)) + js_set_proto_init(stat_obj, proto); + + js_set_slot(stat_obj, SLOT_DATA, js_mknum((double)mode)); + js_set(js, stat_obj, "size", js_mknum(size)); + js_set(js, stat_obj, "mode", js_mknum((double)mode)); + js_set(js, stat_obj, "uid", js_mknum(uid)); + js_set(js, stat_obj, "gid", js_mknum(gid)); + + return stat_obj; +} + +static ant_value_t fs_stats_object_from_uv(ant_t *js, const uv_stat_t *st) { + if (!st) return fs_stats_object_new(js, 0, 0.0, 0.0, 0.0); + return fs_stats_object_new( + js, (mode_t)st->st_mode, + (double)st->st_size, (double)st->st_uid, (double)st->st_gid + ); +} + +static ant_value_t fs_stats_object_from_posix(ant_t *js, const struct stat *st) { + if (!st) return fs_stats_object_new(js, 0, 0.0, 0.0, 0.0); + return fs_stats_object_new( + js, st->st_mode, + (double)st->st_size, (double)st->st_uid, (double)st->st_gid + ); +} + +static bool fs_stat_path_sync(const char *path, uv_stat_t *out) { + uv_fs_t req; + int rc = 0; + + if (!path || !out) return false; + memset(out, 0, sizeof(*out)); + + rc = uv_fs_stat(NULL, &req, path, NULL); + if (rc < 0) { + uv_fs_req_cleanup(&req); + return false; + } + + *out = req.statbuf; + uv_fs_req_cleanup(&req); + return true; +} + +static const char *fs_watch_basename(const char *path) { + const char *name = NULL; + + if (!path || !*path) return NULL; + name = strrchr(path, '/'); +#ifdef _WIN32 + { + const char *alt = strrchr(path, '\\'); + if (!name || (alt && alt > name)) name = alt; + } +#endif + return name ? name + 1 : path; +} + +static ant_value_t fs_watch_error(ant_t *js, int status, const char *path) { + ant_value_t props = js_mkobj(js); + const char *code = uv_err_name(status); + js_set(js, props, "code", js_mkstr(js, code, strlen(code))); + + return js_mkerr_props( + js, JS_ERR_TYPE, + props, "%s: %s", + path ? path : "watch", + uv_strerror(status) + ); +} + +static void fs_watcher_free(fs_watcher_t *watcher) { + if (!watcher) return; + free(watcher->path); + free(watcher); +} + +static uv_handle_t *fs_watcher_uv_handle(fs_watcher_t *watcher) { + if (!watcher) return NULL; + if (watcher->mode == FS_WATCH_MODE_STAT) return (uv_handle_t *)&watcher->handle.poll; + return (uv_handle_t *)&watcher->handle.event; +} + +static void fs_watcher_on_handle_closed(uv_handle_t *handle) { + fs_watcher_t *watcher = (fs_watcher_t *)handle->data; + + if (!watcher) return; + watcher->handle_closed = true; + watcher->closing = false; + if (watcher->finalized) fs_watcher_free(watcher); +} + +static void fs_watcher_close_native(fs_watcher_t *watcher) { + uv_handle_t *handle = NULL; + + if (!watcher) return; + if (watcher->closing || watcher->handle_closed) return; + + handle = fs_watcher_uv_handle(watcher); + if (!handle) return; + + fs_remove_active_watcher(watcher); + if (watcher->mode == FS_WATCH_MODE_STAT) uv_fs_poll_stop(&watcher->handle.poll); + else ant_watch_stop(&watcher->handle.event); + watcher->closing = true; + uv_close(handle, fs_watcher_on_handle_closed); +} + +static void fs_watcher_emit_error(fs_watcher_t *watcher, int status) { + ant_value_t args[1]; + + if (!watcher || vtype(watcher->obj) != T_OBJ) return; + args[0] = fs_watch_error(watcher->js, status, watcher->path); + eventemitter_emit_args(watcher->js, watcher->obj, "error", args, 1); +} + +static void fs_watcher_emit_change(fs_watcher_t *watcher, const char *filename, int events) { + ant_value_t args[2]; + const char *event_name = "change"; + const char *name = filename; + + if (!watcher || vtype(watcher->obj) != T_OBJ) return; + if ((events & UV_RENAME) != 0) event_name = "rename"; + if (!name || !*name) name = fs_watch_basename(watcher->path); + + args[0] = js_mkstr(watcher->js, event_name, strlen(event_name)); + args[1] = name ? js_mkstr(watcher->js, name, strlen(name)) : js_mkundef(); + eventemitter_emit_args(watcher->js, watcher->obj, "change", args, 2); +} + +static void fs_watcher_invoke_watchfile_stats( + fs_watcher_t *watcher, + const uv_stat_t *curr, + const uv_stat_t *prev +) { + uv_stat_t curr_stat; + uv_stat_t prev_stat; + ant_value_t args[2]; + + if (!watcher || !is_callable(watcher->callback)) return; + + memset(&curr_stat, 0, sizeof(curr_stat)); + memset(&prev_stat, 0, sizeof(prev_stat)); + if (curr) curr_stat = *curr; + if (prev) prev_stat = *prev; + + watcher->last_stat = curr_stat; + watcher->last_stat_valid = curr != NULL; + + args[0] = fs_stats_object_from_uv(watcher->js, &curr_stat); + args[1] = fs_stats_object_from_uv(watcher->js, &prev_stat); + fs_call_value(watcher->js, watcher->callback, js_mkundef(), args, 2); +} + +static void fs_watcher_on_event( + uv_fs_event_t *handle, + const char *filename, + int events, + int status +) { + fs_watcher_t *watcher = (fs_watcher_t *)handle->data; + + if (!watcher) return; + if (status < 0) { + fs_watcher_emit_error(watcher, status); + return; + } + + if ((events & (UV_CHANGE | UV_RENAME)) == 0) return; + fs_watcher_emit_change(watcher, filename, events); +} + +static void fs_watcher_on_poll( + uv_fs_poll_t *handle, + int status, + const uv_stat_t *prev, + const uv_stat_t *curr +) { + fs_watcher_t *watcher = (fs_watcher_t *)handle->data; + uv_stat_t missing = {0}; + + if (!watcher) return; + if (status < 0 && status != UV_ENOENT) return; + if (status == UV_ENOENT) { + if (watcher->last_stat_valid) fs_watcher_invoke_watchfile_stats(watcher, &missing, &watcher->last_stat); + else fs_watcher_invoke_watchfile_stats(watcher, &missing, &missing); + return; + } + + fs_watcher_invoke_watchfile_stats(watcher, curr, prev); +} + +static ant_value_t js_fswatcher_close(ant_t *js, ant_value_t *args, int nargs) { + fs_watcher_t *watcher = fs_watcher_data(js->this_val); + + if (!watcher) return js->this_val; + fs_watcher_close_native(watcher); + return js->this_val; +} + +static ant_value_t js_fswatcher_ref(ant_t *js, ant_value_t *args, int nargs) { + fs_watcher_t *watcher = fs_watcher_data(js->this_val); + uv_handle_t *handle = NULL; + + if (!watcher || watcher->handle_closed) return js->this_val; + handle = fs_watcher_uv_handle(watcher); + if (handle) uv_ref(handle); + watcher->persistent = true; + return js->this_val; +} + +static ant_value_t js_fswatcher_unref(ant_t *js, ant_value_t *args, int nargs) { + fs_watcher_t *watcher = fs_watcher_data(js->this_val); + uv_handle_t *handle = NULL; + + if (!watcher || watcher->handle_closed) return js->this_val; + handle = fs_watcher_uv_handle(watcher); + if (handle) uv_unref(handle); + watcher->persistent = false; + return js->this_val; +} + +static ant_value_t js_fswatcher_ctor(ant_t *js, ant_value_t *args, int nargs) { + return js_mkerr_typed(js, JS_ERR_TYPE, "FSWatcher cannot be constructed directly"); +} + +static void fs_watcher_finalize(ant_t *js, ant_object_t *obj) { + fs_watcher_t *watcher = NULL; + if (!obj) return; + + watcher = (fs_watcher_t *)obj->native.ptr; + obj->native.ptr = NULL; + if (!watcher) return; + + watcher->finalized = true; + fs_watcher_close_native(watcher); + if (watcher->handle_closed) fs_watcher_free(watcher); +} + +static void fs_init_watch_constructors(ant_t *js) { + ant_value_t events = 0; + ant_value_t ee_ctor = 0; + ant_value_t ee_proto = 0; + + if (g_fswatcher_proto && g_fswatcher_ctor) return; + + events = events_library(js); + ee_ctor = js_get(js, events, "EventEmitter"); + ee_proto = js_get(js, ee_ctor, "prototype"); + + g_fswatcher_proto = js_mkobj(js); + js_set_proto_init(g_fswatcher_proto, ee_proto); + + js_set(js, g_fswatcher_proto, "close", js_mkfun(js_fswatcher_close)); + js_set(js, g_fswatcher_proto, "ref", js_mkfun(js_fswatcher_ref)); + js_set(js, g_fswatcher_proto, "unref", js_mkfun(js_fswatcher_unref)); + + js_set_sym(js, g_fswatcher_proto, get_toStringTag_sym(), js_mkstr(js, "FSWatcher", 9)); + g_fswatcher_ctor = js_make_ctor(js, js_fswatcher_ctor, g_fswatcher_proto, "FSWatcher", 9); +} + +static bool fs_parse_watch_options(ant_t *js, ant_value_t *args, int nargs, fs_watch_options_t *out) { + ant_value_t options = js_mkundef(); + ant_value_t persistent_val = js_mkundef(); + + if (!out) return false; + + memset(out, 0, sizeof(*out)); + out->persistent = true; + out->listener = js_mkundef(); + + if (nargs > 1) { + if (is_callable(args[1])) out->listener = args[1]; + else options = args[1]; + } + + if (nargs > 2 && is_callable(args[2])) out->listener = args[2]; + if (vtype(options) == T_UNDEF || vtype(options) == T_NULL || vtype(options) == T_STR) return true; + if (vtype(options) != T_OBJ) return false; + + persistent_val = js_get(js, options, "persistent"); + if (vtype(persistent_val) != T_UNDEF) out->persistent = js_truthy(js, persistent_val); + out->recursive = js_truthy(js, js_get(js, options, "recursive")); + return true; +} + +static bool fs_parse_watchfile_options( + ant_t *js, + ant_value_t *args, + int nargs, + fs_watchfile_options_t *out +) { + ant_value_t options = js_mkundef(); + ant_value_t persistent_val = js_mkundef(); + + if (!out) return false; + + memset(out, 0, sizeof(*out)); + out->persistent = true; + out->interval_ms = 5007; + out->listener = js_mkundef(); + + if (nargs > 1) { + if (is_callable(args[1])) { + out->listener = args[1]; + return true; + } + options = args[1]; + } + + if (nargs > 2 && is_callable(args[2])) out->listener = args[2]; + if (!is_callable(out->listener)) return false; + if (vtype(options) == T_UNDEF || vtype(options) == T_NULL) return true; + if (vtype(options) != T_OBJ) return false; + + persistent_val = js_get(js, options, "persistent"); + if (vtype(persistent_val) != T_UNDEF) out->persistent = js_truthy(js, persistent_val); + { + ant_value_t interval_val = js_get(js, options, "interval"); + if (vtype(interval_val) == T_NUM && js_getnum(interval_val) > 0) + out->interval_ms = (unsigned int)js_getnum(interval_val); + } + return true; +} + +static fs_watcher_t *fs_watcher_new(ant_t *js, fs_watch_mode_t mode) { + fs_watcher_t *watcher = calloc(1, sizeof(*watcher)); + + if (!watcher) return NULL; + watcher->js = js; + watcher->obj = js_mkundef(); + watcher->callback = js_mkundef(); + watcher->persistent = true; + watcher->mode = mode; + + return watcher; +} + +static int fs_watcher_start_event(fs_watcher_t *watcher, const char *path, bool persistent, bool recursive) { + unsigned int flags = 0; + + if (!watcher || !path) return UV_EINVAL; +#ifdef UV_FS_EVENT_RECURSIVE + if (recursive) flags |= UV_FS_EVENT_RECURSIVE; +#else + (void)recursive; +#endif + + watcher->persistent = persistent; + return ant_watch_start( + uv_default_loop(), + &watcher->handle.event, + path, fs_watcher_on_event, + watcher, flags, &watcher->path + ); +} + +static int fs_watcher_start_poll(fs_watcher_t *watcher, const char *path, bool persistent, unsigned int interval_ms) { + int rc = 0; + + if (!watcher || !path) return UV_EINVAL; + + watcher->path = ant_watch_resolve_path(path); + if (!watcher->path) return UV_ENOMEM; + + rc = uv_fs_poll_init(uv_default_loop(), &watcher->handle.poll); + if (rc != 0) goto fail; + + watcher->handle.poll.data = watcher; + rc = uv_fs_poll_start(&watcher->handle.poll, fs_watcher_on_poll, watcher->path, interval_ms); + if (rc != 0) goto fail; + + watcher->persistent = persistent; + return 0; + +fail: + free(watcher->path); + watcher->path = NULL; + return rc; +} + +static ant_value_t fs_watcher_make_object(ant_t *js, fs_watcher_t *watcher) { + ant_value_t obj = 0; + + if (!watcher) return js_mkerr(js, "Out of memory"); + fs_init_watch_constructors(js); + + obj = js_mkobj(js); + js_set_proto_init(obj, g_fswatcher_proto); + js_set_native_ptr(obj, watcher); + js_set_native_tag(obj, FS_WATCHER_NATIVE_TAG); + js_set_finalizer(obj, fs_watcher_finalize); + watcher->obj = obj; + + return obj; +} + +static void fs_request_fail(fs_request_t *req, int uv_code) { + req->failed = 1; + req->error_code = uv_code; + if (req->error_msg) free(req->error_msg); + req->error_msg = strdup(uv_strerror(uv_code)); +} + static ant_value_t fs_coerce_path(ant_t *js, ant_value_t arg) { if (vtype(arg) == T_STR) return arg; if (is_object_type(arg)) { @@ -51,6 +604,134 @@ static ant_value_t fs_coerce_path(ant_t *js, ant_value_t arg) { return js_mkundef(); } +static int fs_remove_path_recursive(const char *path, bool recursive, bool force) { + uv_fs_t req; + + int result = uv_fs_lstat(NULL, &req, path, NULL); + if (result < 0) { + uv_fs_req_cleanup(&req); + return (force && result == UV_ENOENT) ? 0 : result; + } + + uv_stat_t statbuf = req.statbuf; + uv_fs_req_cleanup(&req); + + if ((statbuf.st_mode & S_IFMT) != S_IFDIR) { + result = uv_fs_unlink(NULL, &req, path, NULL); + uv_fs_req_cleanup(&req); + return (force && result == UV_ENOENT) ? 0 : result; + } + + if (!recursive) return UV_EISDIR; + result = uv_fs_scandir(NULL, &req, path, 0, NULL); + + if (result < 0) { + uv_fs_req_cleanup(&req); + return (force && result == UV_ENOENT) ? 0 : result; + } + + for (;;) { + uv_dirent_t entry; + result = uv_fs_scandir_next(&req, &entry); + if (result == UV_EOF) break; + if (result < 0) { + uv_fs_req_cleanup(&req); + return result; + } + + size_t path_len = strlen(path); + size_t name_len = strlen(entry.name); + + bool needs_sep = path_len > 0 && path[path_len - 1] != '/'; + char *child = malloc(path_len + (needs_sep ? 1u : 0u) + name_len + 1u); + if (!child) { + uv_fs_req_cleanup(&req); + return UV_ENOMEM; + } + + memcpy(child, path, path_len); + if (needs_sep) child[path_len++] = '/'; + memcpy(child + path_len, entry.name, name_len + 1u); + + result = fs_remove_path_recursive(child, true, force); + free(child); + if (result < 0) { + uv_fs_req_cleanup(&req); + return result; + } + } + + uv_fs_req_cleanup(&req); + result = uv_fs_rmdir(NULL, &req, path, NULL); + uv_fs_req_cleanup(&req); + return (force && result == UV_ENOENT) ? 0 : result; +} + +static bool fs_parse_rm_options(ant_t *js, ant_value_t options, bool *recursive_out, bool *force_out) { + if (recursive_out) *recursive_out = false; + if (force_out) *force_out = false; + + if (vtype(options) == T_UNDEF || vtype(options) == T_NULL) return true; + if (vtype(options) != T_OBJ) return false; + + if (recursive_out) *recursive_out = js_truthy(js, js_get(js, options, "recursive")); + if (force_out) *force_out = js_truthy(js, js_get(js, options, "force")); + return true; +} + +static ant_value_t fs_rm_impl(ant_t *js, ant_value_t *args, int nargs, bool return_promise) { + ant_value_t promise = 0; + ant_value_t path_val; + size_t path_len = 0; + const char *path = NULL; + bool recursive = false; + bool force = false; + int result; + + if (return_promise) promise = js_mkpromise(js); + if (nargs < 1) { + ant_value_t err = js_mkerr(js, "rm() requires a path argument"); + if (!return_promise) return err; + js_reject_promise(js, promise, err); + return promise; + } + + path_val = fs_coerce_path(js, args[0]); + if (vtype(path_val) != T_STR) { + ant_value_t err = js_mkerr(js, "rm() path must be a string"); + if (!return_promise) return err; + js_reject_promise(js, promise, err); + return promise; + } + + path = js_getstr(js, path_val, &path_len); + if (!path) { + ant_value_t err = js_mkerr(js, "Failed to get path string"); + if (!return_promise) return err; + js_reject_promise(js, promise, err); + return promise; + } + + if (!fs_parse_rm_options(js, nargs >= 2 ? args[1] : js_mkundef(), &recursive, &force)) { + ant_value_t err = js_mkerr_typed(js, JS_ERR_TYPE, "rm() options must be an object"); + if (!return_promise) return err; + js_reject_promise(js, promise, err); + return promise; + } + + result = fs_remove_path_recursive(path, recursive, force); + if (result < 0) { + ant_value_t err = js_mkerr(js, "%s", uv_strerror(result)); + if (!return_promise) return err; + js_reject_promise(js, promise, err); + return promise; + } + + if (!return_promise) return js_mkundef(); + js_resolve_promise(js, promise, js_mkundef()); + return promise; +} + static fs_encoding_t parse_encoding(ant_t *js, ant_value_t arg) { size_t len; const char *str = NULL; @@ -137,44 +818,9 @@ static ant_value_t encode_data(ant_t *js, const char *data, size_t len, fs_encod } } -typedef enum { - FS_OP_READ, - FS_OP_WRITE, - FS_OP_UNLINK, - FS_OP_MKDIR, - FS_OP_RMDIR, - FS_OP_STAT, - FS_OP_READ_BYTES, - FS_OP_EXISTS, - FS_OP_READDIR, - FS_OP_ACCESS, - FS_OP_REALPATH, - FS_OP_WRITE_FD, - FS_OP_OPEN, - FS_OP_CLOSE -} fs_op_type_t; - -typedef struct fs_request_s { - uv_fs_t uv_req; - ant_t *js; - ant_value_t promise; - char *path; - char *data; - char *error_msg; - size_t data_len; - fs_op_type_t op_type; - fs_encoding_t encoding; - uv_file fd; - int completed; - int failed; - int recursive; -} fs_request_t; - -static UT_array *pending_requests = NULL; - static void free_fs_request(fs_request_t *req) { if (!req) return; - + if (req->path) free(req->path); if (req->data) free(req->data); if (req->error_msg) free(req->error_msg); @@ -204,13 +850,25 @@ static ant_value_t fs_read_to_uint8array(ant_t *js, const char *data, size_t len static void complete_request(fs_request_t *req) { if (req->failed) { - const char *err_msg = req->error_msg ? req->error_msg : "Unknown error"; - ant_value_t reject_value = js_mkerr(req->js, "%s", err_msg); + const char *err_msg = req->error_msg + ? req->error_msg + : "Unknown error"; + + ant_value_t props = js_mkobj(req->js); + ant_value_t reject_value; + + if (req->error_code) { + const char *code = uv_err_name(req->error_code); + js_set(req->js, props, "code", js_mkstr(req->js, code, strlen(code))); + js_set(req->js, props, "errno", js_mknum((double)req->error_code)); + if (req->path) js_set(req->js, props, "path", js_mkstr(req->js, req->path, strlen(req->path))); + reject_value = js_mkerr_props(req->js, JS_ERR_TYPE, props, "%s", err_msg); + } else reject_value = js_mkerr(req->js, "%s", err_msg); + if (is_err(reject_value)) { reject_value = req->js->thrown_value; - if (vtype(reject_value) == T_UNDEF) { + if (vtype(reject_value) == T_UNDEF) reject_value = js_mkstr(req->js, err_msg, strlen(err_msg)); - } req->js->thrown_exists = false; req->js->thrown_value = js_mkundef(); } @@ -236,8 +894,7 @@ static void on_read_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; @@ -257,8 +914,7 @@ static void on_open_for_read(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; @@ -271,8 +927,7 @@ static void on_open_for_read(uv_fs_t *uv_req) { int stat_result = uv_fs_fstat(uv_default_loop(), &stat_req, req->fd, NULL); if (stat_result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(stat_result)); + fs_request_fail(req, stat_result); req->completed = 1; uv_fs_t close_req; uv_fs_close(uv_default_loop(), &close_req, req->fd, NULL); @@ -301,8 +956,7 @@ static void on_open_for_read(uv_fs_t *uv_req) { int read_result = uv_fs_read(uv_default_loop(), uv_req, req->fd, &buf, 1, 0, on_read_complete); if (read_result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(read_result)); + fs_request_fail(req, read_result); req->completed = 1; uv_fs_t close_req; uv_fs_close(uv_default_loop(), &close_req, req->fd, NULL); @@ -316,8 +970,7 @@ static void on_write_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); } uv_fs_t close_req; @@ -332,8 +985,7 @@ static void on_open_for_write(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; @@ -346,8 +998,7 @@ static void on_open_for_write(uv_fs_t *uv_req) { int write_result = uv_fs_write(uv_default_loop(), uv_req, req->fd, &buf, 1, 0, on_write_complete); if (write_result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(write_result)); + fs_request_fail(req, write_result); req->completed = 1; uv_fs_t close_req; uv_fs_close(uv_default_loop(), &close_req, req->fd, NULL); @@ -361,8 +1012,7 @@ static void on_unlink_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); } uv_fs_req_cleanup(uv_req); @@ -375,8 +1025,7 @@ static void on_mkdir_complete(uv_fs_t *uv_req) { if (uv_req->result < 0) { if (!req->recursive || uv_req->result != UV_EEXIST) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); }} uv_fs_req_cleanup(uv_req); @@ -388,8 +1037,7 @@ static void on_rmdir_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); } uv_fs_req_cleanup(uv_req); @@ -401,23 +1049,13 @@ static void on_stat_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; } - ant_value_t stat_obj = js_mkobj(req->js); - ant_value_t proto = js_get_ctor_proto(req->js, "Stats", 5); - if (is_object_type(proto)) js_set_proto_init(stat_obj, proto); - - uv_stat_t *st = &uv_req->statbuf; - js_set_slot(stat_obj, SLOT_DATA, js_mknum((double)st->st_mode)); - js_set(req->js, stat_obj, "size", js_mknum((double)st->st_size)); - js_set(req->js, stat_obj, "mode", js_mknum((double)st->st_mode)); - js_set(req->js, stat_obj, "uid", js_mknum((double)st->st_uid)); - js_set(req->js, stat_obj, "gid", js_mknum((double)st->st_gid)); + ant_value_t stat_obj = fs_stats_object_from_uv(req->js, &uv_req->statbuf); req->completed = 1; js_resolve_promise(req->js, req->promise, stat_obj); @@ -429,8 +1067,7 @@ static void on_realpath_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0 || !uv_req->ptr) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; @@ -464,8 +1101,7 @@ static void on_access_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; @@ -481,8 +1117,7 @@ static void on_readdir_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; @@ -631,8 +1266,7 @@ static ant_value_t builtin_fs_readFile(ant_t *js, ant_value_t *args, int nargs) int result = uv_fs_open(uv_default_loop(), &req->uv_req, req->path, O_RDONLY, 0, on_open_for_read); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -663,8 +1297,7 @@ static ant_value_t builtin_fs_readBytes(ant_t *js, ant_value_t *args, int nargs) int result = uv_fs_open(uv_default_loop(), &req->uv_req, req->path, O_RDONLY, 0, on_open_for_read); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -863,8 +1496,7 @@ static ant_value_t builtin_fs_writeFile(ant_t *js, ant_value_t *args, int nargs) int result = uv_fs_open(uv_default_loop(), &req->uv_req, req->path, O_WRONLY | O_CREAT | O_TRUNC, 0644, on_open_for_write); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -919,8 +1551,7 @@ static ant_value_t builtin_fs_unlink(ant_t *js, ant_value_t *args, int nargs) { int result = uv_fs_unlink(uv_default_loop(), &req->uv_req, req->path, on_unlink_complete); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1024,8 +1655,7 @@ static ant_value_t builtin_fs_mkdir(ant_t *js, ant_value_t *args, int nargs) { req->completed = 1; complete_request(req); } else { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1085,8 +1715,7 @@ static ant_value_t builtin_fs_rmdir(ant_t *js, ant_value_t *args, int nargs) { int result = uv_fs_rmdir(uv_default_loop(), &req->uv_req, req->path, on_rmdir_complete); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1094,6 +1723,14 @@ static ant_value_t builtin_fs_rmdir(ant_t *js, ant_value_t *args, int nargs) { return req->promise; } +static ant_value_t builtin_fs_rmSync(ant_t *js, ant_value_t *args, int nargs) { + return fs_rm_impl(js, args, nargs, false); +} + +static ant_value_t builtin_fs_rm(ant_t *js, ant_value_t *args, int nargs) { + return fs_rm_impl(js, args, nargs, true); +} + static ant_value_t stat_isFile(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this = js_getthis(js); ant_value_t mode_val = js_get_slot(this, SLOT_DATA); @@ -1125,17 +1762,7 @@ static ant_value_t stat_isSymbolicLink(ant_t *js, ant_value_t *args, int nargs) } static ant_value_t create_stats_object(ant_t *js, struct stat *st) { - ant_value_t stat_obj = js_mkobj(js); - ant_value_t proto = js_get_ctor_proto(js, "Stats", 5); - if (is_special_object(proto)) js_set_proto_init(stat_obj, proto); - - js_set_slot(stat_obj, SLOT_DATA, js_mknum((double)st->st_mode)); - js_set(js, stat_obj, "size", js_mknum((double)st->st_size)); - js_set(js, stat_obj, "mode", js_mknum((double)st->st_mode)); - js_set(js, stat_obj, "uid", js_mknum((double)st->st_uid)); - js_set(js, stat_obj, "gid", js_mknum((double)st->st_gid)); - - return stat_obj; + return fs_stats_object_from_posix(js, st); } static const char *errno_to_code(int err_num) { @@ -1161,7 +1788,6 @@ static const char *errno_to_code(int err_num) { static ant_value_t builtin_fs_statSync(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "statSync() requires a path argument"); - if (vtype(args[0]) != T_STR) return js_mkerr(js, "statSync() path must be a string"); size_t path_len; @@ -1186,7 +1812,6 @@ static ant_value_t builtin_fs_statSync(ant_t *js, ant_value_t *args, int nargs) static ant_value_t builtin_fs_stat(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "stat() requires a path argument"); - if (vtype(args[0]) != T_STR) return js_mkerr(js, "stat() path must be a string"); size_t path_len; @@ -1207,8 +1832,61 @@ static ant_value_t builtin_fs_stat(ant_t *js, ant_value_t *args, int nargs) { int result = uv_fs_stat(uv_default_loop(), &req->uv_req, req->path, on_stat_complete); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); + req->completed = 1; + complete_request(req); + } + + return req->promise; +} + +static ant_value_t builtin_fs_lstatSync(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "lstatSync() requires a path argument"); + if (vtype(args[0]) != T_STR) return js_mkerr(js, "lstatSync() path must be a string"); + + size_t path_len; + char *path = js_getstr(js, args[0], &path_len); + if (!path) return js_mkerr(js, "Failed to get path string"); + + char *path_cstr = strndup(path, path_len); + if (!path_cstr) return js_mkerr(js, "Out of memory"); + + struct stat st; + int result = lstat(path_cstr, &st); + + if (result != 0) { + const char *code = errno_to_code(errno); + ant_value_t err = fs_err_code(js, code, "lstat", path_cstr); + free(path_cstr); return err; + } + + free(path_cstr); + return create_stats_object(js, &st); +} + +static ant_value_t builtin_fs_lstat(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 1) return js_mkerr(js, "lstat() requires a path argument"); + if (vtype(args[0]) != T_STR) return js_mkerr(js, "lstat() path must be a string"); + + size_t path_len; + char *path = js_getstr(js, args[0], &path_len); + if (!path) return js_mkerr(js, "Failed to get path string"); + + + fs_request_t *req = calloc(1, sizeof(fs_request_t)); + if (!req) return js_mkerr(js, "Out of memory"); + + req->js = js; + req->op_type = FS_OP_STAT; + req->promise = js_mkpromise(js); + req->path = strndup(path, path_len); + req->uv_req.data = req; + + utarray_push_back(pending_requests, &req); + int result = uv_fs_lstat(uv_default_loop(), &req->uv_req, req->path, on_stat_complete); + + if (result < 0) { + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1218,7 +1896,6 @@ static ant_value_t builtin_fs_stat(ant_t *js, ant_value_t *args, int nargs) { static ant_value_t builtin_fs_existsSync(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "existsSync() requires a path argument"); - if (vtype(args[0]) != T_STR) return js_mkerr(js, "existsSync() path must be a string"); size_t path_len; @@ -1237,7 +1914,6 @@ static ant_value_t builtin_fs_existsSync(ant_t *js, ant_value_t *args, int nargs static ant_value_t builtin_fs_exists(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "exists() requires a path argument"); - if (vtype(args[0]) != T_STR) return js_mkerr(js, "exists() path must be a string"); size_t path_len; @@ -1269,7 +1945,6 @@ static ant_value_t builtin_fs_exists(ant_t *js, ant_value_t *args, int nargs) { static ant_value_t builtin_fs_accessSync(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "accessSync() requires a path argument"); - if (vtype(args[0]) != T_STR) return js_mkerr(js, "accessSync() path must be a string"); size_t path_len; @@ -1297,7 +1972,6 @@ static ant_value_t builtin_fs_accessSync(ant_t *js, ant_value_t *args, int nargs static ant_value_t builtin_fs_access(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "access() requires a path argument"); - if (vtype(args[0]) != T_STR) return js_mkerr(js, "access() path must be a string"); size_t path_len; @@ -1323,8 +1997,7 @@ static ant_value_t builtin_fs_access(ant_t *js, ant_value_t *args, int nargs) { int result = uv_fs_access(uv_default_loop(), &req->uv_req, req->path, mode, on_access_complete); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1378,8 +2051,7 @@ static ant_value_t builtin_fs_realpath(ant_t *js, ant_value_t *args, int nargs) int result = uv_fs_realpath(uv_default_loop(), &req->uv_req, req->path, on_realpath_complete); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1389,7 +2061,6 @@ static ant_value_t builtin_fs_realpath(ant_t *js, ant_value_t *args, int nargs) static ant_value_t builtin_fs_readdirSync(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "readdirSync() requires a path argument"); - if (vtype(args[0]) != T_STR) return js_mkerr(js, "readdirSync() path must be a string"); size_t path_len; @@ -1423,7 +2094,6 @@ static ant_value_t builtin_fs_readdirSync(ant_t *js, ant_value_t *args, int narg static ant_value_t builtin_fs_readdir(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "readdir() requires a path argument"); - if (vtype(args[0]) != T_STR) return js_mkerr(js, "readdir() path must be a string"); size_t path_len; @@ -1444,8 +2114,7 @@ static ant_value_t builtin_fs_readdir(ant_t *js, ant_value_t *args, int nargs) { int result = uv_fs_scandir(uv_default_loop(), &req->uv_req, req->path, 0, on_readdir_complete); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1457,8 +2126,7 @@ static void on_write_fd_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; @@ -1488,21 +2156,20 @@ static ant_value_t builtin_fs_readSync(ant_t *js, ant_value_t *args, int nargs) int64_t position = -1; if (nargs >= 3) { - if (vtype(args[2]) == T_OBJ) { - ant_value_t off_val = js_get(js, args[2], "offset"); - ant_value_t len_val = js_get(js, args[2], "length"); - ant_value_t pos_val = js_get(js, args[2], "position"); - if (vtype(off_val) == T_NUM) offset = (size_t)js_getnum(off_val); - if (vtype(len_val) == T_NUM) length = (size_t)js_getnum(len_val); - else length = buf_len - offset; - if (vtype(pos_val) == T_NUM) position = (int64_t)js_getnum(pos_val); - } else if (vtype(args[2]) == T_NUM) { - offset = (size_t)js_getnum(args[2]); - length = buf_len - offset; - if (nargs >= 4 && vtype(args[3]) == T_NUM) length = (size_t)js_getnum(args[3]); - if (nargs >= 5 && vtype(args[4]) == T_NUM) position = (int64_t)js_getnum(args[4]); - } - } + if (vtype(args[2]) == T_OBJ) { + ant_value_t off_val = js_get(js, args[2], "offset"); + ant_value_t len_val = js_get(js, args[2], "length"); + ant_value_t pos_val = js_get(js, args[2], "position"); + if (vtype(off_val) == T_NUM) offset = (size_t)js_getnum(off_val); + if (vtype(len_val) == T_NUM) length = (size_t)js_getnum(len_val); + else length = buf_len - offset; + if (vtype(pos_val) == T_NUM) position = (int64_t)js_getnum(pos_val); + } else if (vtype(args[2]) == T_NUM) { + offset = (size_t)js_getnum(args[2]); + length = buf_len - offset; + if (nargs >= 4 && vtype(args[3]) == T_NUM) length = (size_t)js_getnum(args[3]); + if (nargs >= 5 && vtype(args[4]) == T_NUM) position = (int64_t)js_getnum(args[4]); + }} if (offset > buf_len) return js_mkerr(js, "offset is out of bounds"); if (offset + length > buf_len) return js_mkerr(js, "length extends beyond buffer"); @@ -1611,21 +2278,20 @@ static ant_value_t builtin_fs_write_fd(ant_t *js, ant_value_t *args, int nargs) size_t length = buf_len; if (nargs >= 3) { - if (vtype(args[2]) == T_OBJ) { - ant_value_t off_val = js_get(js, args[2], "offset"); - ant_value_t len_val = js_get(js, args[2], "length"); - ant_value_t pos_val = js_get(js, args[2], "position"); - if (vtype(off_val) == T_NUM) offset = (size_t)js_getnum(off_val); - if (vtype(len_val) == T_NUM) length = (size_t)js_getnum(len_val); - else length = buf_len - offset; - if (vtype(pos_val) == T_NUM) position = (int64_t)js_getnum(pos_val); - } else if (vtype(args[2]) == T_NUM) { - offset = (size_t)js_getnum(args[2]); - length = buf_len - offset; - if (nargs >= 4 && vtype(args[3]) == T_NUM) length = (size_t)js_getnum(args[3]); - if (nargs >= 5 && vtype(args[4]) == T_NUM) position = (int64_t)js_getnum(args[4]); - } - } + if (vtype(args[2]) == T_OBJ) { + ant_value_t off_val = js_get(js, args[2], "offset"); + ant_value_t len_val = js_get(js, args[2], "length"); + ant_value_t pos_val = js_get(js, args[2], "position"); + if (vtype(off_val) == T_NUM) offset = (size_t)js_getnum(off_val); + if (vtype(len_val) == T_NUM) length = (size_t)js_getnum(len_val); + else length = buf_len - offset; + if (vtype(pos_val) == T_NUM) position = (int64_t)js_getnum(pos_val); + } else if (vtype(args[2]) == T_NUM) { + offset = (size_t)js_getnum(args[2]); + length = buf_len - offset; + if (nargs >= 4 && vtype(args[3]) == T_NUM) length = (size_t)js_getnum(args[3]); + if (nargs >= 5 && vtype(args[4]) == T_NUM) position = (int64_t)js_getnum(args[4]); + }} if (offset > buf_len) return js_mkerr(js, "offset is out of bounds"); if (offset + length > buf_len) return js_mkerr(js, "length extends beyond buffer"); @@ -1656,8 +2322,7 @@ static ant_value_t builtin_fs_write_fd(ant_t *js, ant_value_t *args, int nargs) int result = uv_fs_write(uv_default_loop(), &req->uv_req, req->fd, &buf, 1, position, on_write_fd_complete); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1758,8 +2423,7 @@ static ant_value_t builtin_fs_writev_fd(ant_t *js, ant_value_t *args, int nargs) int result = uv_fs_write(uv_default_loop(), &req->uv_req, req->fd, &buf, 1, position, on_write_fd_complete); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1830,8 +2494,7 @@ static void on_open_fd_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; @@ -1867,8 +2530,7 @@ static ant_value_t builtin_fs_open_fd(ant_t *js, ant_value_t *args, int nargs) { int result = uv_fs_open(uv_default_loop(), &req->uv_req, req->path, flags, mode, on_open_fd_complete); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1880,8 +2542,7 @@ static void on_close_fd_complete(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror((int)uv_req->result)); + fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; @@ -1912,8 +2573,7 @@ static ant_value_t builtin_fs_close_fd(ant_t *js, ant_value_t *args, int nargs) int result = uv_fs_close(uv_default_loop(), &req->uv_req, req->fd, on_close_fd_complete); if (result < 0) { - req->failed = 1; - req->error_msg = strdup(uv_strerror(result)); + fs_request_fail(req, result); req->completed = 1; complete_request(req); } @@ -1921,6 +2581,129 @@ static ant_value_t builtin_fs_close_fd(ant_t *js, ant_value_t *args, int nargs) return req->promise; } +static ant_value_t builtin_fs_watch(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t path_val = 0; + ant_value_t watcher_obj = 0; + fs_watch_options_t opts; + fs_watcher_t *watcher = NULL; + uv_handle_t *handle = NULL; + const char *path = NULL; + size_t path_len = 0; + int rc = 0; + + if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "watch() requires a path argument"); + if (!fs_parse_watch_options(js, args, nargs, &opts)) + return js_mkerr_typed(js, JS_ERR_TYPE, "watch() options must be a string, object, or callback"); + + path_val = fs_coerce_path(js, args[0]); + if (vtype(path_val) != T_STR) return js_mkerr_typed(js, JS_ERR_TYPE, "watch() path must be a string or URL"); + + path = js_getstr(js, path_val, &path_len); + if (!path || path_len == 0) return js_mkerr(js, "watch() path must not be empty"); + + watcher = fs_watcher_new(js, FS_WATCH_MODE_EVENT); + if (!watcher) return js_mkerr(js, "Out of memory"); + + watcher_obj = fs_watcher_make_object(js, watcher); + if (is_err(watcher_obj)) { + fs_watcher_free(watcher); + return watcher_obj; + } + + rc = fs_watcher_start_event(watcher, path, opts.persistent, opts.recursive); + if (rc != 0) { + js_set_native_ptr(watcher_obj, NULL); + fs_watcher_free(watcher); + return fs_watch_error(js, rc, path); + } + + fs_add_active_watcher(watcher); + if (!opts.persistent) { + handle = fs_watcher_uv_handle(watcher); + if (handle) uv_unref(handle); + } + if (is_callable(opts.listener)) + eventemitter_add_listener(js, watcher_obj, "change", opts.listener, false); + return watcher_obj; +} + +static ant_value_t builtin_fs_watchFile(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t path_val = 0; + fs_watchfile_options_t opts; + + fs_watcher_t *watcher = NULL; + uv_handle_t *handle = NULL; + + const char *path = NULL; + size_t path_len = 0; + int rc = 0; + + if (nargs < 2) + return js_mkerr_typed(js, JS_ERR_TYPE, "watchFile() requires a path and listener"); + if (!fs_parse_watchfile_options(js, args, nargs, &opts)) + return js_mkerr_typed(js, JS_ERR_TYPE, "watchFile() requires a listener callback"); + + path_val = fs_coerce_path(js, args[0]); + if (vtype(path_val) != T_STR) return js_mkerr_typed(js, JS_ERR_TYPE, "watchFile() path must be a string or URL"); + + path = js_getstr(js, path_val, &path_len); + if (!path || path_len == 0) return js_mkerr(js, "watchFile() path must not be empty"); + + watcher = fs_watcher_new(js, FS_WATCH_MODE_STAT); + if (!watcher) return js_mkerr(js, "Out of memory"); + + watcher->callback = opts.listener; + watcher->last_stat_valid = fs_stat_path_sync(path, &watcher->last_stat); + + rc = fs_watcher_start_poll(watcher, path, opts.persistent, opts.interval_ms); + if (rc != 0) { + fs_watcher_free(watcher); + return fs_watch_error(js, rc, path); + } + + fs_add_active_watcher(watcher); + if (!opts.persistent) { + handle = fs_watcher_uv_handle(watcher); + if (handle) uv_unref(handle); + } + return js_mkundef(); +} + +static ant_value_t builtin_fs_unwatchFile(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t path_val = 0; + ant_value_t listener = js_mkundef(); + + char *resolved = NULL; + fs_watcher_t *watcher = NULL; + fs_watcher_t *next = NULL; + + const char *path = NULL; + size_t path_len = 0; + + if (nargs < 1) return js_mkundef(); + + path_val = fs_coerce_path(js, args[0]); + if (vtype(path_val) != T_STR) return js_mkundef(); + + path = js_getstr(js, path_val, &path_len); + if (!path || path_len == 0) return js_mkundef(); + if (nargs > 1 && is_callable(args[1])) listener = args[1]; + + resolved = ant_watch_resolve_path(path); + if (!resolved) return js_mkundef(); + + for (watcher = active_watchers; watcher; watcher = next) { + next = watcher->next_active; + if (watcher->mode != FS_WATCH_MODE_STAT) continue; + if (!watcher->path || strcmp(watcher->path, resolved) != 0) continue; + if (is_callable(listener) && watcher->callback != listener) continue; + fs_watcher_close_native(watcher); + } + + free(resolved); + return js_mkundef(); +} + void init_fs_module(void) { utarray_new(pending_requests, &ut_ptr_icd); @@ -1942,6 +2725,164 @@ void init_fs_module(void) { js_set(js, glob, "Stats", js_obj_to_func(stats_ctor)); } +static ant_value_t fs_callback_success_handler(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t ctx = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); + ant_value_t callback = js_get_slot(ctx, SLOT_DATA); + + if (!is_callable(callback)) return js_mkundef(); + + if (js_truthy(js, js_get(js, ctx, "existsStyle"))) { + ant_value_t cb_args[1] = { nargs > 0 ? args[0] : js_false }; + fs_call_value(js, callback, js_mkundef(), cb_args, 1); + return js_mkundef(); + } + + ant_value_t cb_args[2] = { js_mknull(), nargs > 0 ? args[0] : js_mkundef() }; + fs_call_value(js, callback, js_mkundef(), cb_args, 2); + return js_mkundef(); +} + +static ant_value_t fs_callback_error_handler(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t ctx = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); + ant_value_t callback = js_get_slot(ctx, SLOT_DATA); + ant_value_t cb_args[1]; + + if (!is_callable(callback)) return js_mkundef(); + + if (js_truthy(js, js_get(js, ctx, "existsStyle"))) { + cb_args[0] = js_false; + fs_call_value(js, callback, js_mkundef(), cb_args, 1); + return js_mkundef(); + } + + cb_args[0] = nargs > 0 ? args[0] : js_mkundef(); + fs_call_value(js, callback, js_mkundef(), cb_args, 1); + return js_mkundef(); +} + +static void fs_callback_emit_success( + ant_t *js, + ant_value_t callback, + bool exists_style, + ant_value_t value +) { + if (exists_style) { + ant_value_t cb_args[1] = { value }; + fs_call_value(js, callback, js_mkundef(), cb_args, 1); + return; + } + + ant_value_t cb_args[2] = { js_mknull(), value }; + fs_call_value(js, callback, js_mkundef(), cb_args, 2); +} + +static void fs_callback_emit_error( + ant_t *js, + ant_value_t callback, + bool exists_style, + ant_value_t error +) { + ant_value_t cb_args[1]; + + cb_args[0] = exists_style ? js_false : error; + fs_call_value(js, callback, js_mkundef(), cb_args, 1); +} + +static ant_value_t fs_callback_attach_promise( + ant_t *js, + ant_value_t promise, + ant_value_t callback, + bool exists_style +) { + GC_ROOT_SAVE(root_mark, js); + ant_value_t success_ctx = js_mkobj(js); + ant_value_t error_ctx = js_mkobj(js); + ant_value_t success_fn = js_mkundef(); + ant_value_t error_fn = js_mkundef(); + + GC_ROOT_PIN(js, promise); + GC_ROOT_PIN(js, callback); + GC_ROOT_PIN(js, success_ctx); + GC_ROOT_PIN(js, error_ctx); + + js_set_slot(success_ctx, SLOT_DATA, callback); + js_set_slot(error_ctx, SLOT_DATA, callback); + if (exists_style) { + js_set(js, success_ctx, "existsStyle", js_true); + js_set(js, error_ctx, "existsStyle", js_true); + } + + success_fn = js_heavy_mkfun(js, fs_callback_success_handler, success_ctx); + error_fn = js_heavy_mkfun(js, fs_callback_error_handler, error_ctx); + GC_ROOT_PIN(js, success_fn); + GC_ROOT_PIN(js, error_fn); + + js_promise_then(js, promise, success_fn, error_fn); + GC_ROOT_RESTORE(js, root_mark); + return js_mkundef(); +} + +static ant_value_t fs_callback_wrapper_call(ant_t *js, ant_value_t *args, int nargs) { + GC_ROOT_SAVE(root_mark, js); + ant_value_t wrapper = js_getcurrentfunc(js); + ant_value_t config = js_get_slot(wrapper, SLOT_DATA); + ant_value_t original = js_get_slot(config, SLOT_DATA); + + ant_value_t callback = js_mkundef(); + ant_value_t result = js_mkundef(); + ant_value_t this_arg = js_getthis(js); + ant_value_t ex = js_mkundef(); + + bool exists_style = false; + int call_nargs = nargs; + + GC_ROOT_PIN(js, original); + GC_ROOT_PIN(js, this_arg); + + exists_style = js_truthy(js, js_get(js, config, "existsStyle")); + if (nargs > 0 && is_callable(args[nargs - 1])) { + callback = args[nargs - 1]; + GC_ROOT_PIN(js, callback); + call_nargs--; + } + + result = fs_call_value(js, original, this_arg, args, call_nargs); + GC_ROOT_PIN(js, result); + + if (!is_callable(callback)) { + GC_ROOT_RESTORE(js, root_mark); + return result; + } + + if (is_err(result) || js->thrown_exists) { + ex = js->thrown_exists ? js->thrown_value : result; + GC_ROOT_PIN(js, ex); + js->thrown_exists = false; + js->thrown_value = js_mkundef(); + js->thrown_stack = js_mkundef(); + fs_callback_emit_error(js, callback, exists_style, ex); + GC_ROOT_RESTORE(js, root_mark); + return js_mkundef(); + } + + if (vtype(result) != T_PROMISE) { + fs_callback_emit_success(js, callback, exists_style, result); + GC_ROOT_RESTORE(js, root_mark); + return js_mkundef(); + } + + GC_ROOT_RESTORE(js, root_mark); + return fs_callback_attach_promise(js, result, callback, exists_style); +} + +static ant_value_t fs_make_callback_wrapper(ant_t *js, ant_value_t original, bool exists_style) { + ant_value_t config = js_mkobj(js); + + js_set_slot(config, SLOT_DATA, original); + if (exists_style) js_set(js, config, "existsStyle", js_true); + return js_heavy_mkfun(js, fs_callback_wrapper_call, config); +} + static void fs_set_promise_methods(ant_t *js, ant_value_t lib) { js_set(js, lib, "readFile", js_mkfun(builtin_fs_readFile)); js_set(js, lib, "open", js_mkfun(builtin_fs_open_fd)); @@ -1949,16 +2890,37 @@ static void fs_set_promise_methods(ant_t *js, ant_value_t lib) { js_set(js, lib, "writeFile", js_mkfun(builtin_fs_writeFile)); js_set(js, lib, "write", js_mkfun(builtin_fs_write_fd)); js_set(js, lib, "writev", js_mkfun(builtin_fs_writev_fd)); + js_set(js, lib, "rm", js_mkfun(builtin_fs_rm)); js_set(js, lib, "unlink", js_mkfun(builtin_fs_unlink)); js_set(js, lib, "mkdir", js_mkfun(builtin_fs_mkdir)); js_set(js, lib, "rmdir", js_mkfun(builtin_fs_rmdir)); js_set(js, lib, "stat", js_mkfun(builtin_fs_stat)); + js_set(js, lib, "lstat", js_mkfun(builtin_fs_lstat)); js_set(js, lib, "exists", js_mkfun(builtin_fs_exists)); js_set(js, lib, "access", js_mkfun(builtin_fs_access)); js_set(js, lib, "readdir", js_mkfun(builtin_fs_readdir)); js_set(js, lib, "realpath", js_mkfun(builtin_fs_realpath)); } +static void fs_set_callback_compatible_methods(ant_t *js, ant_value_t lib) { + js_set(js, lib, "readFile", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_readFile), false)); + js_set(js, lib, "open", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_open_fd), false)); + js_set(js, lib, "close", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_close_fd), false)); + js_set(js, lib, "writeFile", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_writeFile), false)); + js_set(js, lib, "write", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_write_fd), false)); + js_set(js, lib, "writev", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_writev_fd), false)); + js_set(js, lib, "rm", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_rm), false)); + js_set(js, lib, "unlink", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_unlink), false)); + js_set(js, lib, "mkdir", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_mkdir), false)); + js_set(js, lib, "rmdir", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_rmdir), false)); + js_set(js, lib, "stat", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_stat), false)); + js_set(js, lib, "lstat", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_lstat), false)); + js_set(js, lib, "exists", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_exists), true)); + js_set(js, lib, "access", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_access), false)); + js_set(js, lib, "readdir", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_readdir), false)); + js_set(js, lib, "realpath", fs_make_callback_wrapper(js, js_mkfun(builtin_fs_realpath), false)); +} + static ant_value_t fs_make_constants(ant_t *js) { ant_value_t constants = js_mkobj(js); js_set(js, constants, "F_OK", js_mknum(F_OK)); @@ -1988,7 +2950,9 @@ static ant_value_t builtin_fs_promises_getter(ant_t *js, ant_value_t *args, int ant_value_t fs_library(ant_t *js) { ant_value_t lib = js_mkobj(js); ant_value_t realpath_sync = js_mkfun(builtin_fs_realpathSync); - fs_set_promise_methods(js, lib); + + fs_set_callback_compatible_methods(js, lib); + fs_init_watch_constructors(js); js_set(js, lib, "readFileSync", js_mkfun(builtin_fs_readFileSync)); js_set(js, lib, "readSync", js_mkfun(builtin_fs_readSync)); @@ -2001,14 +2965,20 @@ ant_value_t fs_library(ant_t *js) { js_set(js, lib, "appendFileSync", js_mkfun(builtin_fs_appendFileSync)); js_set(js, lib, "copyFileSync", js_mkfun(builtin_fs_copyFileSync)); js_set(js, lib, "renameSync", js_mkfun(builtin_fs_renameSync)); + js_set(js, lib, "rmSync", js_mkfun(builtin_fs_rmSync)); js_set(js, lib, "unlinkSync", js_mkfun(builtin_fs_unlinkSync)); js_set(js, lib, "mkdirSync", js_mkfun(builtin_fs_mkdirSync)); js_set(js, lib, "rmdirSync", js_mkfun(builtin_fs_rmdirSync)); js_set(js, lib, "statSync", js_mkfun(builtin_fs_statSync)); + js_set(js, lib, "lstatSync", js_mkfun(builtin_fs_lstatSync)); js_set(js, lib, "existsSync", js_mkfun(builtin_fs_existsSync)); js_set(js, lib, "accessSync", js_mkfun(builtin_fs_accessSync)); js_set(js, lib, "readdirSync", js_mkfun(builtin_fs_readdirSync)); js_set(js, lib, "realpathSync", realpath_sync); + js_set(js, lib, "watch", js_mkfun(builtin_fs_watch)); + js_set(js, lib, "watchFile", js_mkfun(builtin_fs_watchFile)); + js_set(js, lib, "unwatchFile", js_mkfun(builtin_fs_unwatchFile)); + js_set(js, lib, "FSWatcher", g_fswatcher_ctor); js_set(js, realpath_sync, "native", realpath_sync); js_set_getter_desc( @@ -2039,10 +3009,20 @@ int has_pending_fs_ops(void) { } void gc_mark_fs(ant_t *js, gc_mark_fn mark) { + fs_watcher_t *watcher = NULL; + + if (g_fswatcher_proto) mark(js, g_fswatcher_proto); + if (g_fswatcher_ctor) mark(js, g_fswatcher_ctor); if (!pending_requests) return; + unsigned int len = utarray_len(pending_requests); for (unsigned int i = 0; i < len; i++) { fs_request_t **reqp = (fs_request_t **)utarray_eltptr(pending_requests, i); if (reqp && *reqp) { mark(js, (*reqp)->promise); } } + + for (watcher = active_watchers; watcher; watcher = watcher->next_active) { + if (vtype(watcher->obj) == T_OBJ) mark(js, watcher->obj); + if (vtype(watcher->callback) != T_UNDEF) mark(js, watcher->callback); + } } diff --git a/src/modules/module.c b/src/modules/module.c index 5c5a8813..fb63c356 100644 --- a/src/modules/module.c +++ b/src/modules/module.c @@ -40,6 +40,7 @@ static ant_value_t builtin_createRequire_call(ant_t *js, ant_value_t *args, int ant_value_t default_export = js_get_slot(ns, SLOT_DEFAULT); if (vtype(default_export) != T_UNDEF) return default_export; } + return ns; } diff --git a/src/modules/net.c b/src/modules/net.c index 3679e8fc..ef338d14 100644 --- a/src/modules/net.c +++ b/src/modules/net.c @@ -93,8 +93,8 @@ static bool g_default_auto_select_family = true; static double g_default_auto_select_family_attempt_timeout = 250.0; enum { - NET_SERVER_NATIVE_TAG = 0x4e455453u, - NET_SOCKET_NATIVE_TAG = 0x4e45544bu, + NET_SERVER_NATIVE_TAG = 0x4e455453u, // NETS + NET_SOCKET_NATIVE_TAG = 0x4e45544bu, // NETK }; static ant_value_t net_not_implemented(ant_t *js, const char *what); @@ -595,10 +595,6 @@ static bool net_server_parse_host(const char *input, const char **out) { *out = "0.0.0.0"; return true; } - if (strcmp(input, "localhost") == 0) { - *out = "127.0.0.1"; - return true; - } *out = input; return true; } @@ -865,10 +861,48 @@ static ant_value_t js_net_server_address(ant_t *js, ant_value_t *args, int nargs if (!server || !server->listening) return out; if (server->path) return js_mkstr(js, server->path, strlen(server->path)); + struct sockaddr_storage saddr; + int saddr_len = sizeof(saddr); + + if (uv_tcp_getsockname(&server->listener.handle.tcp, (struct sockaddr *)&saddr, &saddr_len) == 0) { + char addr_str[INET6_ADDRSTRLEN] = {0}; + const char *family = "IPv4"; + int port = server->port; + + if (saddr.ss_family == AF_INET) { + struct sockaddr_in *sa = (struct sockaddr_in *)&saddr; + inet_ntop(AF_INET, &sa->sin_addr, addr_str, sizeof(addr_str)); + port = ntohs(sa->sin_port); + } else if (saddr.ss_family == AF_INET6) { + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&saddr; + inet_ntop(AF_INET6, &sa6->sin6_addr, addr_str, sizeof(addr_str)); + port = ntohs(sa6->sin6_port); + family = "IPv6"; + } + + out = js_mkobj(js); + js_set(js, out, "port", js_mknum((double)port)); + js_set(js, out, "family", js_mkstr(js, family, strlen(family))); + js_set(js, out, "address", js_mkstr(js, addr_str, strlen(addr_str))); + + return out; + } + + struct in6_addr addr6; out = js_mkobj(js); js_set(js, out, "port", js_mknum(server->port)); - js_set(js, out, "family", js_mkstr(js, "IPv4", 4)); - js_set(js, out, "address", js_mkstr(js, server->host, strlen(server->host))); + + if (server->host && inet_pton(AF_INET6, server->host, &addr6) == 1) { + char normalized[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &addr6, normalized, sizeof(normalized)); + js_set(js, out, "family", js_mkstr(js, "IPv6", 4)); + js_set(js, out, "address", js_mkstr(js, normalized, strlen(normalized))); + } else { + const char *h = server->host ? server->host : "0.0.0.0"; + js_set(js, out, "family", js_mkstr(js, "IPv4", 4)); + js_set(js, out, "address", js_mkstr(js, h, strlen(h))); + } + return out; } diff --git a/src/modules/process.c b/src/modules/process.c index 6ea1d3ff..f71c67ac 100644 --- a/src/modules/process.c +++ b/src/modules/process.c @@ -342,6 +342,13 @@ void emit_process_event(const char *event_type, ant_value_t *args, int nargs) { } } +bool process_has_event_listeners(const char *event_type) { + ProcessEventType *evt = NULL; + if (!event_type) return false; + HASH_FIND_STR(process_events, event_type, evt); + return evt && evt->listener_count > 0; +} + static void emit_stdio_event(ProcessEventType **events, const char *event_type, ant_value_t *args, int nargs) { if (!rt->js) return; ProcessEventType *evt = NULL; diff --git a/src/modules/readline.c b/src/modules/readline.c index aeefb3cb..c0636827 100644 --- a/src/modules/readline.c +++ b/src/modules/readline.c @@ -1,3 +1,5 @@ +// TODO: cleanup module, make cleaner + #include // IWYU pragma: keep #include @@ -199,11 +201,18 @@ static void emit_event(ant_t *js, rl_interface_t *iface, const char *event_type, } } +static bool rl_has_event_listener(rl_interface_t *iface, const char *event_type) { + RLEventType *evt = NULL; + if (!iface || !event_type) return false; + HASH_FIND_STR(iface->events, event_type, evt); + return evt != NULL && evt->listener_count > 0; +} + static ant_value_t get_history_array(ant_t *js, rl_interface_t *iface) { ant_value_t arr = js_mkarr(js); - for (int i = 0; i < iface->history.count; i++) { - js_arr_push(js, arr, js_mkstr(js, iface->history.lines[i], strlen(iface->history.lines[i]))); - } + for (int i = 0; i < iface->history.count; i++) js_arr_push( + js, arr, js_mkstr(js, iface->history.lines[i], strlen(iface->history.lines[i])) + ); return arr; } @@ -522,15 +531,18 @@ static void on_stdin_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *bu } else if (c == 127 || c == 8) { handle_backspace(iface); } else if (c == 3) { - emit_event(js, iface, "SIGINT", NULL, 0); + if (rl_has_event_listener(iface, "SIGINT")) { + emit_event(js, iface, "SIGINT", NULL, 0); + } else if (process_has_event_listeners("SIGINT")) { + ant_value_t sig_arg = js_mkstr(js, "SIGINT", 6); + emit_process_event("SIGINT", &sig_arg, 1); + } else raise(SIGINT); } else if (c == 4) { if (iface->line_len == 0) { emit_event(js, iface, "close", NULL, 0); iface->closed = true; uv_read_stop(stream); - } else { - handle_delete(iface); - } + } else handle_delete(iface); } else if (c == 1) { iface->line_pos = 0; refresh_line(iface); @@ -562,18 +574,13 @@ static void start_reading(rl_interface_t *iface) { if (!iface->tty_initialized) { uv_loop_t *loop = uv_default_loop(); - int is_tty = uv_guess_handle(STDIN_FILENO) == UV_TTY; if (is_tty) { - if (uv_tty_init(loop, &iface->tty_in, STDIN_FILENO, 1) != 0) { - return; - } + if (uv_tty_init(loop, &iface->tty_in, STDIN_FILENO, 1) != 0) return; uv_tty_set_mode(&iface->tty_in, UV_TTY_MODE_RAW); } else { - if (uv_tty_init(loop, &iface->tty_in, STDIN_FILENO, 1) != 0) { - return; - } + if (uv_tty_init(loop, &iface->tty_in, STDIN_FILENO, 1) != 0) return; } iface->tty_in.data = iface; @@ -698,6 +705,37 @@ static ant_value_t rl_interface_off(ant_t *js, ant_value_t *args, int nargs) { return this_obj; } +static ant_value_t rl_interface_remove_all_listeners(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t this_obj = js_getthis(js); + rl_interface_t *iface = get_interface(js, this_obj); + + RLEventType *evt = NULL; + RLEventType *tmp = NULL; + char *event = NULL; + + if (!iface) return js_mkerr(js, "Invalid Interface"); + if (nargs < 1 || vtype(args[0]) == T_UNDEF) { + HASH_ITER(hh, iface->events, evt, tmp) { + HASH_DEL(iface->events, evt); + free(evt->event_type); + free(evt); + } + return this_obj; + } + + event = js_getstr(js, args[0], NULL); + if (!event) return this_obj; + + HASH_FIND_STR(iface->events, event, evt); + if (!evt) return this_obj; + + HASH_DEL(iface->events, evt); + free(evt->event_type); + free(evt); + + return this_obj; +} + static ant_value_t rl_interface_emit(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); @@ -1162,6 +1200,7 @@ static ant_value_t rl_create_interface(ant_t *js, ant_value_t *args, int nargs) js_set(js, obj, "off", js_mkfun(rl_interface_off)); js_set(js, obj, "addListener", js_mkfun(rl_interface_on)); js_set(js, obj, "removeListener", js_mkfun(rl_interface_off)); + js_set(js, obj, "removeAllListeners", js_mkfun(rl_interface_remove_all_listeners)); js_set(js, obj, "emit", js_mkfun(rl_interface_emit)); js_set(js, obj, "close", js_mkfun(rl_interface_close)); @@ -1181,6 +1220,8 @@ static ant_value_t rl_create_interface(ant_t *js, ant_value_t *args, int nargs) js_set(js, obj, "terminal", js_bool(iface->terminal)); js_set_sym(js, obj, get_asyncIterator_sym(), js_mkfun(rl_interface_async_iterator)); js_set_sym(js, obj, get_toStringTag_sym(), js_mkstr(js, "Interface", 9)); + + start_reading(iface); return obj; } diff --git a/src/modules/regex.c b/src/modules/regex.c index 17adbe84..fe9320b0 100644 --- a/src/modules/regex.c +++ b/src/modules/regex.c @@ -1,3 +1,5 @@ +// TODO: cleanup module, make cleaner + #include #include #include @@ -65,25 +67,85 @@ static inline bool is_class_shorthand(char c) { return c == 'w' || c == 'W' || c == 'd' || c == 'D' || c == 's' || c == 'S'; } -size_t js_to_pcre2_pattern(const char *src, size_t src_len, char *dst, size_t dst_size) { +static size_t v_close_bracket(const char *src, size_t src_len, size_t open) { + int depth = 0; + for (size_t i = open; i < src_len; i++) { + if (src[i] == '\\' && i + 1 < src_len) { i++; continue; } + if (src[i] == '[') depth++; + else if (src[i] == ']') { if (--depth == 0) return i; } + } + return src_len; +} + +static size_t v_translate_part(const char *p, size_t len, char *out, size_t out_size) { + if (len && p[0] == '[') return js_to_pcre2_pattern(p, len, out, out_size, false); + char tmp[1024]; + if (len >= sizeof(tmp) - 2) return 0; + tmp[0] = '['; memcpy(tmp + 1, p, len); tmp[len + 1] = ']'; + return js_to_pcre2_pattern(tmp, len + 2, out, out_size, false); +} + +static int v_set_op(const char *src, size_t start, size_t end, size_t *op_pos) { + int depth = 0; + for (size_t i = start; i < end; ) { + if (src[i] == '\\' && i + 1 < end) { + char n = src[i + 1]; + if ((n == 'p' || n == 'P') && i + 2 < end && src[i + 2] == '{') { + i += 3; while (i < end && src[i] != '}') i++; if (i < end) i++; continue; + } + if ((n == 'u' || n == 'x') && i + 2 < end && src[i + 2] == '{') { + i += 3; while (i < end && src[i] != '}') i++; if (i < end) i++; continue; + } + i += 2; continue; + } + if (src[i] == '[') { depth++; i++; continue; } + if (src[i] == ']') { if (depth > 0) { depth--; i++; continue; } break; } + if (!depth && i + 1 < end) { + if (src[i] == '&' && src[i+1] == '&') { *op_pos = i; return 1; } + if (src[i] == '-' && src[i+1] == '-') { *op_pos = i; return 2; } + } + i++; + } + return 0; +} + +size_t js_to_pcre2_pattern(const char *src, size_t src_len, char *dst, size_t dst_size, bool v_flag) { size_t di = 0; - bool in_charclass = false; + int charclass_depth = 0; #define OUT(ch) do { if (di < dst_size - 1) dst[di++] = (ch); } while(0) for (size_t si = 0; si < src_len && di < dst_size - 1; si++) { - if (src[si] == '[' && !in_charclass) { - in_charclass = true; + if (src[si] == '[') { + if (v_flag && charclass_depth == 0) { + size_t close = v_close_bracket(src, src_len, si); + size_t op_pos; + int op_type = v_set_op(src, si + 1, close, &op_pos); + if (op_type && close < src_len) { + char ao[1024], bo[1024]; + size_t aol = v_translate_part(&src[si + 1], op_pos - si - 1, ao, sizeof(ao)); + size_t bol = v_translate_part(&src[op_pos + 2], close - op_pos - 2, bo, sizeof(bo)); + const char *la = op_type == 1 ? ao : bo, *ra = op_type == 1 ? bo : ao; + size_t ll = op_type == 1 ? aol : bol, rl = op_type == 1 ? bol : aol; + OUT('('); OUT('?'); OUT(op_type == 1 ? '=' : '!'); + for (size_t k = 0; k < ll; k++) OUT(la[k]); + OUT(')'); + for (size_t k = 0; k < rl; k++) OUT(ra[k]); + si = close; + continue; + } + } + charclass_depth++; OUT('['); continue; } - if (src[si] == ']' && in_charclass) { - in_charclass = false; + if (src[si] == ']' && charclass_depth > 0) { + charclass_depth--; OUT(']'); continue; } - if (in_charclass && src[si] == '-' && si > 0 && src[si - 1] != '[' && + if (charclass_depth > 0 && src[si] == '-' && si > 0 && src[si - 1] != '[' && si + 1 < src_len && src[si + 1] != ']') { bool prev_is_shorthand = (si >= 2 && src[si - 2] == '\\' && is_class_shorthand(src[si - 1])); bool next_is_shorthand = (si + 2 < src_len && src[si + 1] == '\\' && is_class_shorthand(src[si + 2])); @@ -227,6 +289,21 @@ size_t js_to_pcre2_pattern(const char *src, size_t src_len, char *dst, size_t ds }; bool has_eq = (memchr(prop, '=', prop_len) != NULL); bool has_colon = (memchr(prop, ':', prop_len) != NULL); + if (!has_eq && !has_colon && next == 'p' && charclass_depth == 0) { + static const struct { const char *name; const char *exp; } sprops[] = { + {"Emoji_Keycap_Sequence", + "(?:\\x{23}\\x{fe0f}\\x{20e3}|\\x{2a}\\x{fe0f}\\x{20e3}|[\\x{30}-\\x{39}]\\x{fe0f}\\x{20e3})"}, + {"RGI_Emoji", + "(?:[\\x{1f1e6}-\\x{1f1ff}]{2}|(?:\\p{Emoji}[\\x{1f3fb}-\\x{1f3ff}]?\\x{200d})+\\p{Emoji}[\\x{1f3fb}-\\x{1f3ff}]?|\\p{Emoji}[\\x{1f3fb}-\\x{1f3ff}]|\\p{Emoji}\\x{fe0f}?)"}, + }; + for (size_t m = 0; m < sizeof(sprops)/sizeof(sprops[0]); m++) { + if (strlen(sprops[m].name) == prop_len && memcmp(sprops[m].name, prop, prop_len) == 0) { + for (const char *r = sprops[m].exp; *r && di < dst_size - 1; r++) OUT(*r); + si = brace_end; + goto next_char; + } + } + } if (has_eq || has_colon) { char sep = has_eq ? '=' : ':'; const char *val = memchr(prop, sep, prop_len); @@ -247,6 +324,25 @@ size_t js_to_pcre2_pattern(const char *src, size_t src_len, char *dst, size_t ds } } } + if (!has_eq && !has_colon) { + static const struct { const char *name; const char *range; } rangeprops[] = { + {"ASCII", "\\x{0}-\\x{7f}"}, + {"Any", "\\x{0}-\\x{10ffff}"}, + }; + for (size_t m = 0; m < sizeof(rangeprops)/sizeof(rangeprops[0]); m++) { + if (strlen(rangeprops[m].name) == prop_len && memcmp(rangeprops[m].name, prop, prop_len) == 0) { + if (charclass_depth > 0) { + for (const char *r = rangeprops[m].range; *r; r++) OUT(*r); + } else { + OUT('['); if (next == 'P') OUT('^'); + for (const char *r = rangeprops[m].range; *r; r++) OUT(*r); + OUT(']'); + } + si = brace_end; + goto next_char; + } + } + } const char *replacement = NULL; if (!has_eq && !has_colon) { for (size_t m = 0; m < sizeof(gc_map)/sizeof(gc_map[0]); m++) { @@ -270,7 +366,7 @@ size_t js_to_pcre2_pattern(const char *src, size_t src_len, char *dst, size_t ds } } } - if (extra_range && !in_charclass) { + if (extra_range && charclass_depth == 0) { const char *pfx = (next == 'p') ? "(?:\\p{" : "(?:\\P{"; for (const char *r = pfx; *r; r++) OUT(*r); for (size_t k = brace_start; k < brace_end; k++) OUT(src[k]); @@ -316,30 +412,38 @@ size_t js_to_pcre2_pattern(const char *src, size_t src_len, char *dst, size_t ds : js_setprop(js, obj, js_mkstr(js, key, klen), val)) static void regexp_init_flags(ant_t *js, ant_value_t obj, const char *fstr, ant_offset_t flen, bool is_new) { - bool g = false, i = false, m = false, s = false, u = false, y = false; + bool d = false, g = false, i = false, m = false; + bool s = false, u = false, v = false, y = false; + for (ant_offset_t k = 0; k < flen; k++) { + if (fstr[k] == 'd') d = true; if (fstr[k] == 'g') g = true; if (fstr[k] == 'i') i = true; if (fstr[k] == 'm') m = true; if (fstr[k] == 's') s = true; if (fstr[k] == 'u') u = true; + if (fstr[k] == 'v') v = true; if (fstr[k] == 'y') y = true; } - char sorted[8]; int si = 0; + char sorted[10]; int si = 0; + if (d) sorted[si++] = 'd'; if (g) sorted[si++] = 'g'; if (i) sorted[si++] = 'i'; if (m) sorted[si++] = 'm'; if (s) sorted[si++] = 's'; if (u) sorted[si++] = 'u'; + if (v) sorted[si++] = 'v'; if (y) sorted[si++] = 'y'; REGEXP_SET_PROP(js, obj, "flags", 5, js_mkstr(js, sorted, si), is_new); + REGEXP_SET_PROP(js, obj, "hasIndices", 10, mkval(T_BOOL, d ? 1 : 0), is_new); REGEXP_SET_PROP(js, obj, "global", 6, mkval(T_BOOL, g ? 1 : 0), is_new); REGEXP_SET_PROP(js, obj, "ignoreCase", 10, mkval(T_BOOL, i ? 1 : 0), is_new); REGEXP_SET_PROP(js, obj, "multiline", 9, mkval(T_BOOL, m ? 1 : 0), is_new); REGEXP_SET_PROP(js, obj, "dotAll", 6, mkval(T_BOOL, s ? 1 : 0), is_new); REGEXP_SET_PROP(js, obj, "unicode", 7, mkval(T_BOOL, u ? 1 : 0), is_new); + REGEXP_SET_PROP(js, obj, "unicodeSets", 11, mkval(T_BOOL, v ? 1 : 0), is_new); REGEXP_SET_PROP(js, obj, "sticky", 6, mkval(T_BOOL, y ? 1 : 0), is_new); REGEXP_SET_PROP(js, obj, "lastIndex", 9, tov(0), is_new); } @@ -461,7 +565,7 @@ static bool regex_get_or_compile(ant_t *js, ant_value_t regexp_obj, compiled_reg ant_offset_t plen, poff = vstr(js, source_val, &plen); const char *pattern_ptr = (char *)(uintptr_t)(poff); - bool ignore_case = false, multiline = false, dotall = false, sticky = false, unicode = false; + bool ignore_case = false, multiline = false, dotall = false, sticky = false, unicode = false, v_flag = false; ant_offset_t flags_off = lkp(js, regexp_obj, "flags", 5); if (flags_off != 0) { ant_value_t flags_val = js_propref_load(js, flags_off); @@ -474,12 +578,13 @@ static bool regex_get_or_compile(ant_t *js, ant_value_t regexp_obj, compiled_reg if (flags_str[i] == 's') dotall = true; if (flags_str[i] == 'y') sticky = true; if (flags_str[i] == 'u') unicode = true; + if (flags_str[i] == 'v') v_flag = true; } } } char pcre2_pattern[4096]; - size_t pcre2_len = js_to_pcre2_pattern(pattern_ptr, plen, pcre2_pattern, sizeof(pcre2_pattern)); + size_t pcre2_len = js_to_pcre2_pattern(pattern_ptr, plen, pcre2_pattern, sizeof(pcre2_pattern), v_flag); uint32_t options = PCRE2_UTF | PCRE2_UCP | PCRE2_MATCH_UNSET_BACKREF | PCRE2_DUPNAMES; if (ignore_case) options |= PCRE2_CASELESS; @@ -859,7 +964,7 @@ static ant_value_t builtin_regexp_test(ant_t *js, ant_value_t *args, int nargs) return mkval(T_BOOL, vtype(result) != T_NULL ? 1 : 0); } -ant_value_t builtin_regexp_flags_getter(ant_t *js, ant_value_t *args, int nargs) { +static ant_value_t builtin_regexp_flags_getter(ant_t *js, ant_value_t *args, int nargs) { (void)args; (void)nargs; ant_value_t rx = js->this_val; if (!is_object_type(rx)) @@ -883,7 +988,7 @@ ant_value_t builtin_regexp_flags_getter(ant_t *js, ant_value_t *args, int nargs) return js_mkstr(js, buf, n); } -ant_value_t builtin_regexp_symbol_match(ant_t *js, ant_value_t *args, int nargs) { +static ant_value_t builtin_regexp_symbol_match(ant_t *js, ant_value_t *args, int nargs) { ant_value_t rx = js->this_val; if (!is_object_type(rx)) return js_mkerr_typed(js, JS_ERR_TYPE, "RegExp.prototype[@@match] called on non-object"); @@ -932,7 +1037,7 @@ ant_value_t builtin_regexp_symbol_match(ant_t *js, ant_value_t *args, int nargs) } } -ant_value_t builtin_regexp_symbol_replace(ant_t *js, ant_value_t *args, int nargs) { +static ant_value_t builtin_regexp_symbol_replace(ant_t *js, ant_value_t *args, int nargs) { ant_value_t rx = js->this_val; if (!is_object_type(rx)) return js_mkerr_typed(js, JS_ERR_TYPE, "RegExp.prototype[@@replace] called on non-object"); @@ -1072,7 +1177,7 @@ ant_value_t builtin_regexp_symbol_replace(ant_t *js, ant_value_t *args, int narg return ret; } -ant_value_t builtin_regexp_symbol_search(ant_t *js, ant_value_t *args, int nargs) { +static ant_value_t builtin_regexp_symbol_search(ant_t *js, ant_value_t *args, int nargs) { ant_value_t rx = js->this_val; if (!is_object_type(rx)) return js_mkerr_typed(js, JS_ERR_TYPE, "RegExp.prototype[@@search] called on non-object"); @@ -1098,7 +1203,7 @@ ant_value_t builtin_regexp_symbol_search(ant_t *js, ant_value_t *args, int nargs return vtype(idx) == T_NUM ? idx : tov(-1); } -ant_value_t builtin_regexp_symbol_split(ant_t *js, ant_value_t *args, int nargs) { +static ant_value_t builtin_regexp_symbol_split(ant_t *js, ant_value_t *args, int nargs) { ant_value_t rx = js_getthis(js); if (!is_object_type(rx)) return js_mkerr_typed(js, JS_ERR_TYPE, "RegExp.prototype[@@split] called on non-object"); @@ -1228,17 +1333,13 @@ ant_value_t builtin_regexp_symbol_split(ant_t *js, ant_value_t *args, int nargs) return mkval(T_ARR, vdata(A)); } -ant_value_t do_regex_match_pcre2( - ant_t *js, const char *pattern_ptr, ant_offset_t pattern_len, - const char *str_ptr, ant_offset_t str_len, - bool global_flag, bool ignore_case, bool multiline -) { +ant_value_t do_regex_match_pcre2(ant_t *js, regex_match_args_t args) { char pcre2_pattern[4096]; - size_t pcre2_len = js_to_pcre2_pattern(pattern_ptr, pattern_len, pcre2_pattern, sizeof(pcre2_pattern)); + size_t pcre2_len = js_to_pcre2_pattern(args.pattern_ptr, args.pattern_len, pcre2_pattern, sizeof(pcre2_pattern), false); uint32_t options = PCRE2_UTF | PCRE2_UCP | PCRE2_MATCH_UNSET_BACKREF | PCRE2_DUPNAMES; - if (ignore_case) options |= PCRE2_CASELESS; - if (multiline) options |= PCRE2_MULTILINE; + if (args.ignore_case) options |= PCRE2_CASELESS; + if (args.multiline) options |= PCRE2_MULTILINE; int errcode; PCRE2_SIZE erroffset; @@ -1259,16 +1360,16 @@ ant_value_t do_regex_match_pcre2( PCRE2_SIZE pos = 0; int match_count = 0; - while (pos <= str_len) { - int rc = pcre2_match(re, (PCRE2_SPTR)str_ptr, str_len, pos, 0, match_data, NULL); + while (pos <= (PCRE2_SIZE)args.str_len) { + int rc = pcre2_match(re, (PCRE2_SPTR)args.str_ptr, args.str_len, pos, 0, match_data, NULL); if (rc < 0) break; PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data); PCRE2_SIZE match_start = ovector[0]; PCRE2_SIZE match_end = ovector[1]; - if (global_flag) { - ant_value_t match_str = js_mkstr(js, str_ptr + match_start, match_end - match_start); + if (args.global) { + ant_value_t match_str = js_mkstr(js, args.str_ptr + match_start, match_end - match_start); if (is_err(match_str)) { pcre2_match_data_free(match_data); pcre2_code_free(re); @@ -1282,7 +1383,7 @@ ant_value_t do_regex_match_pcre2( if (start == PCRE2_UNSET) { js_arr_push(js, result_arr, js_mkundef()); } else { - ant_value_t match_str = js_mkstr(js, str_ptr + start, end - start); + ant_value_t match_str = js_mkstr(js, args.str_ptr + start, end - start); if (is_err(match_str)) { pcre2_match_data_free(match_data); pcre2_code_free(re); @@ -1295,7 +1396,7 @@ ant_value_t do_regex_match_pcre2( } match_count++; - if (!global_flag) break; + if (!args.global) break; if (match_start == match_end) { pos = match_end + 1; } else { pos = match_end; } @@ -1537,7 +1638,7 @@ static ant_value_t builtin_string_search(ant_t *js, ant_value_t *args, int nargs const char *str_ptr = (char *)(uintptr_t)(str_off); char pcre2_pattern[4096]; - size_t pcre2_len = js_to_pcre2_pattern(pattern_ptr, pattern_len, pcre2_pattern, sizeof(pcre2_pattern)); + size_t pcre2_len = js_to_pcre2_pattern(pattern_ptr, pattern_len, pcre2_pattern, sizeof(pcre2_pattern), false); uint32_t options = PCRE2_UTF | PCRE2_UCP | PCRE2_MATCH_UNSET_BACKREF | PCRE2_DUPNAMES; if (ignore_case) options |= PCRE2_CASELESS; @@ -1624,10 +1725,11 @@ static ant_value_t builtin_string_match(ant_t *js, ant_value_t *args, int nargs) ant_offset_t str_len, str_off = vstr(js, str, &str_len); const char *str_ptr = (char *)(uintptr_t)(str_off); - ant_value_t result = do_regex_match_pcre2( - js, pattern_ptr, pattern_len, - str_ptr, str_len, global_flag, ignore_case, multiline - ); + ant_value_t result = do_regex_match_pcre2(js, (regex_match_args_t){ + .pattern_ptr = pattern_ptr, .pattern_len = pattern_len, + .str_ptr = str_ptr, .str_len = str_len, + .global = global_flag, .ignore_case = ignore_case, .multiline = multiline, + }); if (!global_flag && vtype(result) == T_ARR) { js_setprop(js, result, js_mkstr(js, "input", 5), str); @@ -1660,6 +1762,7 @@ void init_regex_module(void) { js_set_sym(js, regexp_proto, get_match_sym(), js_mkfun(builtin_regexp_symbol_match)); js_set_sym(js, regexp_proto, get_replace_sym(), js_mkfun(builtin_regexp_symbol_replace)); js_set_sym(js, regexp_proto, get_search_sym(), js_mkfun(builtin_regexp_symbol_search)); + js_set_sym(js, regexp_proto, get_toStringTag_sym(), js_mkstr(js, "RegExp", 6)); js_set_getter_desc(js, regexp_proto, "flags", 5, js_mkfun(builtin_regexp_flags_getter), JS_DESC_C); js_setprop(js, regexp_proto, js_mkstr(js, "compile", 7), js_mkfun(builtin_regexp_compile)); diff --git a/src/modules/timer.c b/src/modules/timer.c index 9a856349..cffb7788 100644 --- a/src/modules/timer.c +++ b/src/modules/timer.c @@ -60,9 +60,7 @@ static struct { static void add_timer_entry(timer_entry_t *entry) { entry->next = timer_state.timers; entry->prev = NULL; - if (timer_state.timers) { - timer_state.timers->prev = entry; - } + if (timer_state.timers) timer_state.timers->prev = entry; timer_state.timers = entry; } @@ -73,12 +71,17 @@ static void remove_timer_entry(timer_entry_t *entry) { } static int timer_entry_is_registered(timer_entry_t *entry) { - for (timer_entry_t *it = timer_state.timers; it != NULL; it = it->next) { + for (timer_entry_t *it = timer_state.timers; it != NULL; it = it->next) if (it == entry) return 1; - } return 0; } +static timer_entry_t *find_timer_entry_by_id(int timer_id) { + for (timer_entry_t *entry = timer_state.timers; entry != NULL; entry = entry->next) + if (entry->timer_id == timer_id) return entry; + return NULL; +} + static int timer_copy_args(timer_entry_t *entry, ant_value_t *args, int nargs) { entry->nargs = nargs > 2 ? nargs - 2 : 0; if (entry->nargs > 0) { @@ -90,26 +93,63 @@ static int timer_copy_args(timer_entry_t *entry, ant_value_t *args, int nargs) { } static ant_value_t timer_to_primitive(ant_t *js, ant_value_t *args, int nargs) { - return js_get(js, js_getthis(js), "id"); + return js_get_slot(js_getthis(js), SLOT_DATA); +} + +static ant_value_t js_timer_ref(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t this_obj = js_getthis(js); + timer_entry_t *entry = find_timer_entry_by_id((int)js_getnum(js_get_slot(this_obj, SLOT_DATA))); + if (entry && !entry->closed && !uv_is_closing((uv_handle_t *)&entry->handle)) + uv_ref((uv_handle_t *)&entry->handle); + return this_obj; +} + +static ant_value_t js_timer_unref(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t this_obj = js_getthis(js); + timer_entry_t *entry = find_timer_entry_by_id((int)js_getnum(js_get_slot(this_obj, SLOT_DATA))); + if (entry && !entry->closed && !uv_is_closing((uv_handle_t *)&entry->handle)) + uv_unref((uv_handle_t *)&entry->handle); + return this_obj; +} + +static ant_value_t js_timer_has_ref(ant_t *js, ant_value_t *args, int nargs) { + timer_entry_t *entry = find_timer_entry_by_id((int)js_getnum(js_get_slot(js_getthis(js), SLOT_DATA))); + if (!entry || entry->closed || uv_is_closing((uv_handle_t *)&entry->handle)) return js_false; + return js_bool(uv_has_ref((const uv_handle_t *)&entry->handle) != 0); } static ant_value_t timer_make_object(ant_t *js, int id, double delay_ms, int is_interval, ant_value_t callback) { ant_value_t obj = js_mkobj(js); - - js_set(js, obj, "id", js_mknum((double)id)); + js_set(js, obj, "delay", js_mknum(delay_ms)); js_set(js, obj, "repeat", is_interval ? js_mknum(delay_ms) : js_mknull()); + js_set(js, obj, "callback", callback); + js_set_descriptor(js, obj, "callback", 8, JS_DESC_W | JS_DESC_C); - js_set_sym(js, obj, get_toStringTag_sym(), js_mkstr(js, is_interval ? "Interval" : "Timeout", is_interval ? 8 : 7)); - js_set_sym(js, obj, get_toPrimitive_sym(), js_mkfun(timer_to_primitive)); + js_set(js, obj, "ref", js_mkfun(js_timer_ref)); + js_set_descriptor(js, obj, "ref", 3, JS_DESC_W | JS_DESC_C); + + js_set(js, obj, "unref", js_mkfun(js_timer_unref)); + js_set_descriptor(js, obj, "unref", 5, JS_DESC_W | JS_DESC_C); + + js_set(js, obj, "hasRef", js_mkfun(js_timer_has_ref)); + js_set_descriptor(js, obj, "hasRef", 6, JS_DESC_W | JS_DESC_C); + + js_set_sym(js, obj, get_toStringTag_sym(), js_mkstr(js, is_interval + ? "Interval" + : "Timeout", is_interval ? 8 : 7) + ); + js_set_slot(obj, SLOT_DATA, js_mknum((double)id)); + js_set_sym(js, obj, get_toPrimitive_sym(), js_mkfun(timer_to_primitive)); + return obj; } static int timer_id_from_arg(ant_t *js, ant_value_t arg) { if (vtype(arg) == T_NUM) return (int)js_getnum(arg); - return (int)js_getnum(js_get(js, arg, "id")); + return (int)js_getnum(js_get_slot(arg, SLOT_DATA)); } static void timer_close_cb(uv_handle_t *h) { @@ -143,11 +183,9 @@ static void timer_callback(uv_timer_t *handle) { sv_vm_call(js->vm, js, entry->callback, js_mkundef(), entry->args, entry->nargs, NULL, false); process_microtasks(js); - if (!entry->is_interval) { - if (!uv_is_closing((uv_handle_t *)&entry->handle)) { - uv_close((uv_handle_t *)&entry->handle, timer_close_cb); - } - } + if (!entry->is_interval) if (!uv_is_closing((uv_handle_t *)&entry->handle)) uv_close( + (uv_handle_t *)&entry->handle, timer_close_cb + ); } // setTimeout(callback, delay, ...args) diff --git a/src/modules/tls.c b/src/modules/tls.c index b1ef220d..d63aca4a 100644 --- a/src/modules/tls.c +++ b/src/modules/tls.c @@ -23,7 +23,7 @@ typedef struct ant_tls_context_wrap_s { bool closed; } ant_tls_context_wrap_t; -enum { TLS_CONTEXT_NATIVE_TAG = 0x544c5343u }; +enum { TLS_CONTEXT_NATIVE_TAG = 0x544c5343u }; // TLSC static ant_value_t g_tls_context_proto = 0; static void tls_context_free(ant_tls_context_wrap_t *wrap) { diff --git a/src/modules/util.c b/src/modules/util.c index e93492f7..776f4b63 100644 --- a/src/modules/util.c +++ b/src/modules/util.c @@ -1,3 +1,5 @@ +// TODO: split module into smaller files + #include // IWYU pragma: keep #include @@ -254,6 +256,196 @@ static ant_value_t util_strip_vt_control_characters(ant_t *js, ant_value_t *args return out; } +static inline bool util_env_is_inline_ws(char ch) { + return ch == ' ' || ch == '\t' || ch == '\r'; +} + +static inline bool util_env_is_ident_start(char ch) { + return + (ch >= 'A' && ch <= 'Z') || + (ch >= 'a' && ch <= 'z') || + ch == '_'; +} + +static inline bool util_env_is_ident_continue(char ch) { + return util_env_is_ident_start(ch) || (ch >= '0' && ch <= '9'); +} + +static void util_env_skip_inline_ws(const char *src, size_t len, size_t *cursor) { + while (*cursor < len && util_env_is_inline_ws(src[*cursor])) (*cursor)++; +} + +static void util_env_skip_line(const char *src, size_t len, size_t *cursor) { + while (*cursor < len && src[*cursor] != '\n') (*cursor)++; + if (*cursor < len && src[*cursor] == '\n') (*cursor)++; +} + +static bool util_env_consume_export(const char *src, size_t len, size_t *cursor) { + if (*cursor + 6 > len) return false; + if (memcmp(src + *cursor, "export", 6) != 0) return false; + + if ( + *cursor + 6 < len && + !util_env_is_inline_ws(src[*cursor + 6]) && + src[*cursor + 6] != '\n' + ) return false; + + *cursor += 6; + util_env_skip_inline_ws(src, len, cursor); + return true; +} + +static bool util_env_parse_key( + const char *src, size_t len, size_t *cursor, + size_t *key_start, size_t *key_end +) { + if (*cursor >= len || !util_env_is_ident_start(src[*cursor])) return false; + *key_start = *cursor; (*cursor)++; + + while (*cursor < len && util_env_is_ident_continue(src[*cursor])) (*cursor)++; + *key_end = *cursor; + + return true; +} + +static void util_env_set_entry( + ant_t *js, ant_value_t obj, const char *key, + size_t key_len, ant_value_t value +) { + ant_value_t key_str = js_mkstr(js, key, key_len); + js_setprop(js, obj, key_str, value); +} + +static ant_value_t util_env_parse_quoted_value( + ant_t *js, const char *src, + size_t len, size_t *cursor +) { + util_sb_t sb = {0}; + ant_value_t value = js_mkstr(js, "", 0); + char quote; + + if (*cursor >= len) return value; + quote = src[(*cursor)++]; + + while (*cursor < len) { + char ch = src[(*cursor)++]; + if (ch == quote) goto done; + if (ch != '\\' || *cursor >= len) { + util_sb_append_c(&sb, ch); + continue; + } + + char esc = src[(*cursor)++]; + if (quote != '"') { + util_sb_append_c(&sb, esc); + continue; + } + + switch (esc) { + case 'n': util_sb_append_c(&sb, '\n'); break; + case 'r': util_sb_append_c(&sb, '\r'); break; + case 't': util_sb_append_c(&sb, '\t'); break; + case '\\': util_sb_append_c(&sb, '\\'); break; + case '"': util_sb_append_c(&sb, '"'); break; + default: util_sb_append_c(&sb, esc); break; + } + } + +done: + value = js_mkstr(js, sb.buf ? sb.buf : "", sb.len); + free(sb.buf); + + while (*cursor < len && src[*cursor] != '\n') { + if (src[*cursor] == '#') break; + (*cursor)++; + } + + return value; +} + +static ant_value_t util_env_parse_unquoted_value( + ant_t *js, const char *src, + size_t len, size_t *cursor +) { + size_t value_start = *cursor; + size_t value_end = *cursor; + bool saw_space = false; + + while (*cursor < len && src[*cursor] != '\n' && src[*cursor] != '\r') { + if (src[*cursor] == '#') { + if (*cursor == value_start || saw_space) goto done; + } + + saw_space = util_env_is_inline_ws(src[*cursor]); + (*cursor)++; + value_end = *cursor; + } + +done: + while (value_start < value_end && util_env_is_inline_ws(src[value_start])) { + value_start++; + } + while (value_end > value_start && util_env_is_inline_ws(src[value_end - 1])) { + value_end--; + } + + return js_mkstr(js, src + value_start, value_end - value_start); +} + +static ant_value_t util_parse_env(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t out = js_mkobj(js); + if (nargs < 1) return out; + + char cbuf[512]; + js_cstr_t cstr = js_to_cstr(js, args[0], cbuf, sizeof(cbuf)); + const char *src = cstr.ptr; + size_t len = strlen(src); + size_t i = 0; + + if (len >= 3 && + (unsigned char)src[0] == 0xEF && + (unsigned char)src[1] == 0xBB && + (unsigned char)src[2] == 0xBF) { + i = 3; + } + + while (i < len) { + size_t key_start = 0; + size_t key_end = 0; + ant_value_t value = js_mkstr(js, "", 0); + + util_env_skip_inline_ws(src, len, &i); + if (i >= len) break; + if (src[i] == '\n') { + i++; + continue; + } + if (src[i] == '#') goto skip_line; + + util_env_consume_export(src, len, &i); + if (!util_env_parse_key(src, len, &i, &key_start, &key_end)) goto skip_line; + + util_env_skip_inline_ws(src, len, &i); + if (i >= len || src[i] != '=') goto skip_line; + i++; + util_env_skip_inline_ws(src, len, &i); + + if (i < len && (src[i] == '"' || src[i] == '\'' || src[i] == '`')) { + value = util_env_parse_quoted_value(js, src, len, &i); + } else { + value = util_env_parse_unquoted_value(js, src, len, &i); + } + + util_env_set_entry(js, out, src + key_start, key_end - key_start, value); + +skip_line: + util_env_skip_line(src, len, &i); + } + + if (cstr.needs_free) free((void *)cstr.ptr); + return out; +} + static const util_style_entry_t *util_find_style(const char *name) { for (size_t i = 0; i < sizeof(util_styles) / sizeof(util_styles[0]); i++) { if (strcmp(name, util_styles[i].name) == 0) return &util_styles[i]; @@ -416,6 +608,26 @@ static ant_value_t util_promisify(ant_t *js, ant_value_t *args, int nargs) { return js_heavy_mkfun(js, util_promisified_call, args[0]); } +static ant_value_t util_inherits(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 2 || !is_callable(args[0]) || !is_callable(args[1])) { + return js_mkerr(js, "inherits(ctor, superCtor) requires constructor functions"); + } + + ant_value_t ctor = args[0]; + ant_value_t super_ctor = args[1]; + ant_value_t ctor_proto = js_get(js, ctor, "prototype"); + ant_value_t super_proto = js_get(js, super_ctor, "prototype"); + + if (!is_object_type(ctor_proto) || !is_object_type(super_proto)) { + return js_mkerr(js, "inherits(ctor, superCtor) requires prototype objects"); + } + + js_set(js, ctor, "super_", super_ctor); + js_set_proto_init(ctor_proto, super_proto); + + return js_mkundef(); +} + ant_value_t util_library(ant_t *js) { ant_value_t lib = js_mkobj(js); @@ -423,6 +635,8 @@ ant_value_t util_library(ant_t *js) { js_set(js, lib, "formatWithOptions", js_mkfun(util_format_with_options)); js_set(js, lib, "inspect", js_mkfun(util_inspect)); js_set(js, lib, "deprecate", js_mkfun(util_deprecate)); + js_set(js, lib, "inherits", js_mkfun(util_inherits)); + js_set(js, lib, "parseEnv", js_mkfun(util_parse_env)); js_set(js, lib, "promisify", js_mkfun(util_promisify)); js_set(js, lib, "stripVTControlCharacters", js_mkfun(util_strip_vt_control_characters)); js_set(js, lib, "styleText", js_mkfun(util_style_text)); diff --git a/src/modules/wasi.c b/src/modules/wasi.c new file mode 100644 index 00000000..b12df1f7 --- /dev/null +++ b/src/modules/wasi.c @@ -0,0 +1,202 @@ +#include +#include +#include + +#include "ant.h" +#include "errors.h" +#include "internal.h" + +#include "ptr.h" +#include "modules/buffer.h" +#include "modules/wasi.h" +#include "wasm_c_api.h" +#include "wasm_export.h" + +enum { + WASI_INSTANCE_TAG = 0x57415349u, // WASI + WASI_FUNC_TAG = 0x57415346u, // WASF +}; + +typedef struct { + uint8_t *binary; + wasm_module_t module; + wasm_module_inst_t inst; + wasm_exec_env_t exec_env; +} wasi_instance_handle_t; + +typedef struct { + ant_t *js; + wasm_module_inst_t inst; + wasm_exec_env_t exec_env; + wasm_function_inst_t func; +} wasi_func_env_t; + +static ant_value_t wasi_exported_func_call(ant_t *js, ant_value_t *args, int nargs) { + if (!js_check_native_tag(js->current_func, WASI_FUNC_TAG)) + return js_mkerr(js, "Invalid WASI function"); + wasi_func_env_t *env = (wasi_func_env_t *)js_get_native_ptr(js->current_func); + + uint32_t param_count = wasm_func_get_param_count(env->func, env->inst); + uint32_t result_count = wasm_func_get_result_count(env->func, env->inst); + + uint32_t wasm_argv[32]; + memset(wasm_argv, 0, sizeof(wasm_argv)); + + for (int i = 0; i < nargs && (uint32_t)i < param_count; i++) { + wasm_argv[i] = (uint32_t)js_getnum(args[i]); + } + + if (!wasm_runtime_call_wasm(env->exec_env, env->func, param_count, wasm_argv)) { + const char *exception = wasm_runtime_get_exception(env->inst); + return js_mkerr(js, "%s", exception ? exception : "WASI function call failed"); + } + + if (result_count == 0) return js_mkundef(); + return js_mknum((double)(int32_t)wasm_argv[0]); +} + +static void wasi_instance_finalize(ant_t *js, ant_object_t *obj) { + if (obj->native.tag != WASI_INSTANCE_TAG) return; + wasi_instance_handle_t *handle = (wasi_instance_handle_t *)obj->native.ptr; + + if (!handle) return; + if (handle->exec_env) wasm_runtime_destroy_exec_env(handle->exec_env); + if (handle->inst) wasm_runtime_deinstantiate(handle->inst); + if (handle->module) wasm_runtime_unload(handle->module); + + free(handle->binary); + free(handle); +} + +bool wasi_module_has_wasi_imports(void *c_api_module) { + wasm_importtype_vec_t import_types = {0}; + wasm_module_imports((wasm_module_t *)c_api_module, &import_types); + + bool has_wasi = false; + for (size_t i = 0; i < import_types.size; i++) { + const wasm_name_t *mod = wasm_importtype_module(import_types.data[i]); + if (mod && mod->size >= 22 && memcmp(mod->data, "wasi_snapshot_preview1", 22) == 0) { + has_wasi = true; + break; + }} + + wasm_importtype_vec_delete(&import_types); + return has_wasi; +} + +ant_value_t wasi_instantiate( + ant_t *js, const uint8_t *wasm_bytes, size_t wasm_len, + ant_value_t module_obj, ant_value_t wasi_opts +) { + char error_buf[128] = {0}; + uint8_t *bin_copy = malloc(wasm_len); + + if (!bin_copy) return js_mkerr(js, "out of memory"); + memcpy(bin_copy, wasm_bytes, wasm_len); + + wasm_module_t rt_module = wasm_runtime_load(bin_copy, (uint32_t)wasm_len, error_buf, sizeof(error_buf)); + if (!rt_module) { + free(bin_copy); + return js_mkerr(js, "%s", error_buf[0] ? error_buf : "Failed to load WASI module"); + } + + const char *dirs[] = { "." }; + ant_value_t args_val = is_object_type(wasi_opts) + ? js_get(js, wasi_opts, "args") + : js_mkundef(); + + int argc = vtype(args_val) == T_ARR ? (int)js_arr_len(js, args_val) : 0; + if (argc < 1) argc = 1; + + char *argv[argc]; + if (vtype(args_val) == T_ARR) { + for (int i = 0; i < argc; i++) + argv[i] = js_getstr(js, js_arr_get(js, args_val, (ant_offset_t)i), NULL); + } else argv[0] = (char *)"wasi"; + + wasm_runtime_set_wasi_args(rt_module, dirs, 1, NULL, 0, NULL, 0, argv, argc); + wasm_module_inst_t inst = wasm_runtime_instantiate(rt_module, 512 * 1024, 256 * 1024, error_buf, sizeof(error_buf)); + + if (!inst) { + wasm_runtime_unload(rt_module); + free(bin_copy); + return js_mkerr(js, "%s", error_buf[0] ? error_buf : "Failed to instantiate WASI module"); + } + + wasm_exec_env_t exec_env = wasm_runtime_create_exec_env(inst, 512 * 1024); + if (!exec_env) { + wasm_runtime_deinstantiate(inst); + wasm_runtime_unload(rt_module); + free(bin_copy); + return js_mkerr(js, "Failed to create WASI exec env"); + } + + wasi_instance_handle_t *handle = calloc(1, sizeof(*handle)); + if (!handle) { + wasm_runtime_destroy_exec_env(exec_env); + wasm_runtime_deinstantiate(inst); + wasm_runtime_unload(rt_module); + free(bin_copy); + return js_mkerr(js, "out of memory"); + } + + handle->binary = bin_copy; + handle->module = rt_module; + handle->inst = inst; + handle->exec_env = exec_env; + + ant_value_t instance_obj = js_mkobj(js); + ant_value_t exports_obj = js_mkobj(js); + + js_set_native_ptr(instance_obj, handle); + js_set_native_tag(instance_obj, WASI_INSTANCE_TAG); + js_set_slot_wb(js, instance_obj, SLOT_CTOR, module_obj); + js_set_finalizer(instance_obj, wasi_instance_finalize); + + int32_t export_count = wasm_runtime_get_export_count(rt_module); + for (int32_t i = 0; i < export_count; i++) { + wasm_export_t export_info; + wasm_runtime_get_export_type(rt_module, i, &export_info); + + if (export_info.kind == WASM_IMPORT_EXPORT_KIND_FUNC) { + wasm_function_inst_t func = wasm_runtime_lookup_function(inst, export_info.name); + if (!func) continue; + + wasi_func_env_t *fenv = calloc(1, sizeof(*fenv)); + if (!fenv) continue; + fenv->js = js; + fenv->inst = inst; + fenv->exec_env = exec_env; + fenv->func = func; + + ant_value_t obj = js_mkobj(js); + js_set_slot(obj, SLOT_CFUNC, js_mkfun(wasi_exported_func_call)); + js_set_native_ptr(obj, fenv); + js_set_native_tag(obj, WASI_FUNC_TAG); + js_set(js, exports_obj, export_info.name, js_obj_to_func(obj)); + } + else if (export_info.kind == WASM_IMPORT_EXPORT_KIND_MEMORY) { + void *mem_data = wasm_runtime_addr_app_to_native(inst, 0); + wasm_memory_inst_t mem = wasm_runtime_get_default_memory(inst); + uint64_t pages = mem ? wasm_memory_get_cur_page_count(mem) : 0; + size_t mem_size = (size_t)(pages * 65536); + + ArrayBufferData *buffer = calloc(1, sizeof(ArrayBufferData)); + if (buffer && mem_data) { + buffer->data = (uint8_t *)mem_data; + buffer->length = mem_size; + buffer->capacity = mem_size; + buffer->ref_count = 1; + ant_value_t ab = create_arraybuffer_obj(js, buffer); + ant_value_t mem_obj = js_mkobj(js); + js_set_slot_wb(js, mem_obj, SLOT_DATA, ab); + js_set(js, exports_obj, export_info.name, mem_obj); + } + } + } + + js_set_slot_wb(js, instance_obj, SLOT_ENTRIES, exports_obj); + js_set(js, instance_obj, "exports", exports_obj); + + return instance_obj; +} diff --git a/src/modules/wasm.c b/src/modules/wasm.c new file mode 100644 index 00000000..4aa06a39 --- /dev/null +++ b/src/modules/wasm.c @@ -0,0 +1,1265 @@ +#include +#include +#include +#include + +#include "ant.h" +#include "errors.h" +#include "runtime.h" +#include "internal.h" +#include "descriptors.h" + +#include "gc/modules.h" +#include "silver/engine.h" +#include "modules/buffer.h" +#include "modules/wasm.h" +#include "modules/wasi.h" +#include "wasm_c_api.h" + +typedef struct { + wasm_store_t *store; + wasm_module_t *module; +} wasm_module_handle_t; + +typedef struct { + wasm_instance_t *instance; + wasm_extern_vec_t exports; + wasm_func_t **host_funcs; + size_t host_func_count; +} wasm_instance_handle_t; + +typedef enum { + WASM_EXTERN_WRAP_GLOBAL = 1, + WASM_EXTERN_WRAP_MEMORY, + WASM_EXTERN_WRAP_TABLE, +} wasm_extern_wrap_kind_t; + +typedef struct { + wasm_extern_wrap_kind_t kind; + wasm_store_t *store; + bool own_handle; + bool use_cached_value; + wasm_val_t cached_value; + union { + wasm_global_t *global; + wasm_memory_t *memory; + wasm_table_t *table; + } as; +} wasm_extern_handle_t; + +typedef struct { + ant_t *js; + wasm_store_t *store; + ant_value_t owner; + ant_value_t fn; +} wasm_import_func_env_t; + +static wasm_engine_t *g_wasm_engine = NULL; + +static wasm_import_func_env_t **g_wasm_import_envs = NULL; +static size_t g_wasm_import_env_count = 0; +static size_t g_wasm_import_env_cap = 0; + +static void wasm_register_import_env(wasm_import_func_env_t *env) { + if (g_wasm_import_env_count == g_wasm_import_env_cap) { + size_t new_cap = g_wasm_import_env_cap ? g_wasm_import_env_cap * 2 : 16; + wasm_import_func_env_t **new_arr = realloc(g_wasm_import_envs, new_cap * sizeof(*new_arr)); + if (!new_arr) return; + g_wasm_import_envs = new_arr; + g_wasm_import_env_cap = new_cap; + } + g_wasm_import_envs[g_wasm_import_env_count++] = env; +} + +static void wasm_unregister_import_env(wasm_import_func_env_t *env) { + for (size_t i = 0; i < g_wasm_import_env_count; i++) { + if (g_wasm_import_envs[i] != env) continue; + g_wasm_import_envs[i] = g_wasm_import_envs[--g_wasm_import_env_count]; + return; + } +} + +static void wasm_import_func_env_finalizer(void *env_ptr) { + wasm_import_func_env_t *env = (wasm_import_func_env_t *)env_ptr; + wasm_unregister_import_env(env); + free(env); +} + +static ant_value_t g_wasm_module_proto = 0; +static ant_value_t g_wasm_instance_proto = 0; +static ant_value_t g_wasm_global_proto = 0; +static ant_value_t g_wasm_memory_proto = 0; +static ant_value_t g_wasm_table_proto = 0; +static ant_value_t g_wasm_tag_proto = 0; +static ant_value_t g_wasm_exception_proto = 0; + +static ant_value_t g_wasm_compileerror_proto = 0; +static ant_value_t g_wasm_linkerror_proto = 0; +static ant_value_t g_wasm_runtimeerror_proto = 0; + +static bool ensure_wasm_engine(void) { + if (g_wasm_engine) return true; + g_wasm_engine = wasm_engine_new(); + return g_wasm_engine != NULL; +} + +static size_t wasm_name_len(const wasm_name_t *name) { + if (!name || !name->data) return 0; + if (name->size > 0 && name->data[name->size - 1] == '\0') return name->size - 1; + return name->size; +} + +static const char *wasm_extern_kind_name(wasm_externkind_t kind) { + switch (kind) { + case WASM_EXTERN_FUNC: return "function"; + case WASM_EXTERN_GLOBAL: return "global"; + case WASM_EXTERN_TABLE: return "table"; + case WASM_EXTERN_MEMORY: return "memory"; + default: return "unknown"; + } +} + +static wasm_valkind_t wasm_valkind_from_string(const char *name, size_t len, bool *ok) { + *ok = true; + if (len == 3 && !memcmp(name, "i32", 3)) return WASM_I32; + if (len == 3 && !memcmp(name, "i64", 3)) return WASM_I64; + if (len == 3 && !memcmp(name, "f32", 3)) return WASM_F32; + if (len == 3 && !memcmp(name, "f64", 3)) return WASM_F64; + if (len == 9 && !memcmp(name, "externref", 9)) return WASM_EXTERNREF; + if (len == 7 && !memcmp(name, "funcref", 7)) return WASM_FUNCREF; + *ok = false; + return WASM_I32; +} + +static wasm_module_handle_t *wasm_module_handle(ant_value_t value) { + if (!js_check_brand(value, BRAND_WASM_MODULE)) return NULL; + ant_value_t slot = js_get_slot(value, SLOT_DATA); + if (vtype(slot) != T_NUM) return NULL; + return (wasm_module_handle_t *)(uintptr_t)(size_t)js_getnum(slot); +} + +static wasm_instance_handle_t *wasm_instance_handle(ant_value_t value) { + if (!js_check_brand(value, BRAND_WASM_INSTANCE)) return NULL; + ant_value_t slot = js_get_slot(value, SLOT_DATA); + if (vtype(slot) != T_NUM) return NULL; + return (wasm_instance_handle_t *)(uintptr_t)(size_t)js_getnum(slot); +} + +static wasm_extern_handle_t *wasm_extern_handle(ant_value_t value, wasm_extern_wrap_kind_t kind) { + if ((kind == WASM_EXTERN_WRAP_GLOBAL && !js_check_brand(value, BRAND_WASM_GLOBAL)) + || (kind == WASM_EXTERN_WRAP_MEMORY && !js_check_brand(value, BRAND_WASM_MEMORY)) + || (kind == WASM_EXTERN_WRAP_TABLE && !js_check_brand(value, BRAND_WASM_TABLE))) { + return NULL; + } + + ant_value_t slot = js_get_slot(value, SLOT_DATA); + if (vtype(slot) != T_NUM) return NULL; + wasm_extern_handle_t *handle = (wasm_extern_handle_t *)(uintptr_t)(size_t)js_getnum(slot); + return handle && handle->kind == kind ? handle : NULL; +} + +static ant_value_t wasm_make_error(ant_t *js, ant_value_t proto, const char *name, const char *message) { + ant_value_t err = js_make_error_silent(js, JS_ERR_TYPE, message ? message : ""); + if (vtype(err) != T_OBJ) return err; + js_set(js, err, "name", js_mkstr(js, name, strlen(name))); + if (is_object_type(proto)) js_set_proto_init(err, proto); + return err; +} + +static ant_value_t wasm_make_compile_error(ant_t *js, const char *message) { + return wasm_make_error(js, g_wasm_compileerror_proto, "CompileError", message); +} + +static ant_value_t wasm_make_link_error(ant_t *js, const char *message) { + return wasm_make_error(js, g_wasm_linkerror_proto, "LinkError", message); +} + +static ant_value_t wasm_make_runtime_error(ant_t *js, const char *message) { + return wasm_make_error(js, g_wasm_runtimeerror_proto, "RuntimeError", message); +} + +static ant_value_t wasm_error_value(ant_t *js, ant_value_t value) { + if (is_err(value) && js->thrown_exists) + return js->thrown_value; + return value; +} + +static void wasm_reject_with_error(ant_t *js, ant_value_t promise, ant_value_t error) { + js_reject_promise(js, promise, error); +} + +static bool wasm_buffer_source_to_vec(ant_t *js, ant_value_t value, wasm_byte_vec_t *out, char *error_buf, size_t error_buf_len) { + const uint8_t *bytes = NULL; + size_t len = 0; + memset(out, 0, sizeof(*out)); + + if (!buffer_source_get_bytes(js, value, &bytes, &len)) { + snprintf(error_buf, error_buf_len, "Expected a BufferSource"); + return false; + } + + wasm_byte_vec_new_uninitialized(out, len); + if (len > 0 && !out->data) { + snprintf(error_buf, error_buf_len, "Out of memory"); + return false; + } + + if (len > 0) memcpy(out->data, bytes, len); + return true; +} + +static ant_value_t wasm_value_from_i64(ant_t *js, int64_t value) { + char buf[64]; + int n = snprintf(buf, sizeof(buf), "%" PRId64, value); + if (n < 0) return js_mkerr(js, "Failed to convert i64"); + return js_mkbigint(js, buf, (size_t)n, value < 0); +} + +static ant_value_t wasm_value_to_js(ant_t *js, const wasm_val_t *value) { + switch (value->kind) { + case WASM_I32: return js_mknum((double)value->of.i32); + case WASM_I64: return wasm_value_from_i64(js, value->of.i64); + case WASM_F32: return js_mknum((double)value->of.f32); + case WASM_F64: return js_mknum(value->of.f64); + case WASM_EXTERNREF: + case WASM_FUNCREF: + return value->of.ref ? js_mkundef() : js_mknull(); + default: + return js_mkundef(); + } +} + +static bool js_value_to_i64(ant_t *js, ant_value_t value, int64_t *out) { + if (vtype(value) == T_BIGINT) { + ant_value_t str_val = js_tostring_val(js, value); + if (is_err(str_val) || vtype(str_val) != T_STR) return false; + const char *str = js_str(js, str_val); + if (!str) return false; + char *end = NULL; + long long parsed = strtoll(str, &end, 10); + if (!end || *end != '\0') return false; + *out = (int64_t)parsed; + return true; + } + + double d = js_to_number(js, value); + if (!isfinite(d)) return false; + *out = (int64_t)d; + return true; +} + +static bool js_value_to_wasm(ant_t *js, ant_value_t value, wasm_valkind_t kind, wasm_val_t *out) { + memset(out, 0, sizeof(*out)); + out->kind = kind; + + switch (kind) { + case WASM_I32: + out->of.i32 = (int32_t)js_to_number(js, value); + return true; + case WASM_I64: + return js_value_to_i64(js, value, &out->of.i64); + case WASM_F32: + out->of.f32 = (float)js_to_number(js, value); + return true; + case WASM_F64: + out->of.f64 = js_to_number(js, value); + return true; + case WASM_EXTERNREF: + case WASM_FUNCREF: + out->of.ref = NULL; + return vtype(value) == T_NULL || vtype(value) == T_UNDEF; + default: + return false; + } +} + +static ant_value_t wasm_js_from_result_vec(ant_t *js, wasm_val_vec_t *results) { + if (!results || results->size == 0) return js_mkundef(); + if (results->size == 1) return wasm_value_to_js(js, &results->data[0]); + + ant_value_t arr = js_mkarr(js); + for (size_t i = 0; i < results->size; i++) { + js_arr_push(js, arr, wasm_value_to_js(js, &results->data[i])); + } + return arr; +} + +static ant_value_t wasm_trap_to_error(ant_t *js, wasm_trap_t *trap) { + wasm_message_t message = WASM_EMPTY_VEC; + wasm_trap_message(trap, &message); + + ant_value_t err = wasm_make_runtime_error(js, message.data ? message.data : "WebAssembly trap"); + + wasm_byte_vec_delete(&message); + wasm_trap_delete(trap); + return err; +} + +static ant_value_t wasm_wrap_module(ant_t *js, wasm_store_t *store, wasm_module_t *module) { + wasm_module_handle_t *handle = calloc(1, sizeof(*handle)); + if (!handle) { + if (module) wasm_module_delete(module); + if (store) wasm_store_delete(store); + return js_mkerr(js, "out of memory"); + } + + handle->store = store; + handle->module = module; + + ant_value_t obj = js_mkobj(js); + js_set_proto_init(obj, g_wasm_module_proto); + js_set_slot(obj, SLOT_BRAND, js_mknum(BRAND_WASM_MODULE)); + js_set_slot(obj, SLOT_DATA, ANT_PTR(handle)); + return obj; +} + +static void wasm_module_finalize(ant_t *js, ant_object_t *obj) { + (void)js; + if (!obj->extra_slots) return; + + ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; + for (uint8_t i = 0; i < obj->extra_count; i++) { + if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; + wasm_module_handle_t *handle = (wasm_module_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); + if (!handle) return; + if (handle->module) wasm_module_delete(handle->module); + if (handle->store) wasm_store_delete(handle->store); + free(handle); + return; + } +} + +static ant_value_t wasm_wrap_instance(ant_t *js, wasm_instance_handle_t *handle, ant_value_t module_ref) { + ant_value_t obj = js_mkobj(js); + js_set_proto_init(obj, g_wasm_instance_proto); + js_set_slot(obj, SLOT_BRAND, js_mknum(BRAND_WASM_INSTANCE)); + js_set_slot(obj, SLOT_DATA, ANT_PTR(handle)); + js_set_slot_wb(js, obj, SLOT_CTOR, module_ref); + return obj; +} + +static void wasm_instance_finalize(ant_t *js, ant_object_t *obj) { + (void)js; + if (!obj->extra_slots) return; + + ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; + for (uint8_t i = 0; i < obj->extra_count; i++) { + if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; + wasm_instance_handle_t *handle = (wasm_instance_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); + if (!handle) return; + for (size_t j = 0; j < handle->host_func_count; j++) { + if (handle->host_funcs[j]) wasm_func_delete(handle->host_funcs[j]); + } + free(handle->host_funcs); + wasm_extern_vec_delete(&handle->exports); + free(handle); + return; + } +} + +static ant_value_t wasm_wrap_extern_object(ant_t *js, wasm_extern_wrap_kind_t kind, ant_value_t proto, int brand, wasm_store_t *store, bool own_handle, void *ptr, ant_value_t owner) { + wasm_extern_handle_t *handle = calloc(1, sizeof(*handle)); + if (!handle) return js_mkerr(js, "out of memory"); + + handle->kind = kind; + handle->store = store; + handle->own_handle = own_handle; + handle->cached_value = (wasm_val_t)WASM_INIT_VAL; + + switch (kind) { + case WASM_EXTERN_WRAP_GLOBAL: handle->as.global = (wasm_global_t *)ptr; break; + case WASM_EXTERN_WRAP_MEMORY: handle->as.memory = (wasm_memory_t *)ptr; break; + case WASM_EXTERN_WRAP_TABLE: handle->as.table = (wasm_table_t *)ptr; break; + } + + ant_value_t obj = js_mkobj(js); + js_set_proto_init(obj, proto); + js_set_slot(obj, SLOT_BRAND, js_mknum(brand)); + js_set_slot(obj, SLOT_DATA, ANT_PTR(handle)); + if (is_object_type(owner)) js_set_slot_wb(js, obj, SLOT_ENTRIES, owner); + return obj; +} + +static void wasm_extern_finalize(ant_t *js, ant_object_t *obj) { + (void)js; + if (!obj->extra_slots) return; + + ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; + for (uint8_t i = 0; i < obj->extra_count; i++) { + if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; + wasm_extern_handle_t *handle = (wasm_extern_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); + if (!handle) return; + + if (handle->own_handle) { + switch (handle->kind) { + case WASM_EXTERN_WRAP_GLOBAL: + if (handle->as.global) wasm_global_delete(handle->as.global); + break; + case WASM_EXTERN_WRAP_MEMORY: + if (handle->as.memory) wasm_memory_delete(handle->as.memory); + break; + case WASM_EXTERN_WRAP_TABLE: + if (handle->as.table) wasm_table_delete(handle->as.table); + break; + } + if (handle->store) wasm_store_delete(handle->store); + } + + free(handle); + return; + } +} + +static ant_value_t js_wasm_exported_func_call(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t state = js_get_slot(js->current_func, SLOT_DATA); + if (vtype(state) != T_OBJ) return js_mkerr(js, "Invalid WebAssembly function"); + + ant_value_t func_ptr = js_get_slot(state, SLOT_DATA); + if (vtype(func_ptr) != T_NUM) return js_mkerr(js, "Invalid WebAssembly function"); + + wasm_func_t *func = (wasm_func_t *)(uintptr_t)(size_t)js_getnum(func_ptr); + if (!func) return js_mkerr(js, "Invalid WebAssembly function"); + + wasm_functype_t *type = wasm_func_type(func); + if (!type) return js_mkerr(js, "Failed to inspect WebAssembly function"); + + const wasm_valtype_vec_t *params = wasm_functype_params(type); + const wasm_valtype_vec_t *results_t = wasm_functype_results(type); + + wasm_val_vec_t wasm_args = WASM_EMPTY_VEC; + wasm_val_vec_t wasm_results = WASM_EMPTY_VEC; + wasm_trap_t *trap = NULL; + ant_value_t result = js_mkundef(); + + wasm_val_vec_new_uninitialized(&wasm_args, params ? params->size : 0); + wasm_val_vec_new_uninitialized(&wasm_results, results_t ? results_t->size : 0); + + for (size_t i = 0; params && i < params->size; i++) { + if ((int)i >= nargs) { + wasm_val_vec_delete(&wasm_args); + wasm_val_vec_delete(&wasm_results); + wasm_functype_delete(type); + return js_mkerr_typed(js, JS_ERR_TYPE, "Missing WebAssembly argument"); + } + + if (!js_value_to_wasm(js, args[i], wasm_valtype_kind(params->data[i]), &wasm_args.data[i])) { + wasm_val_vec_delete(&wasm_args); + wasm_val_vec_delete(&wasm_results); + wasm_functype_delete(type); + return js_mkerr_typed(js, JS_ERR_TYPE, "Unsupported WebAssembly argument type"); + } + } + + trap = wasm_func_call(func, &wasm_args, &wasm_results); + if (trap) { + result = wasm_trap_to_error(js, trap); + wasm_val_vec_delete(&wasm_args); + wasm_val_vec_delete(&wasm_results); + wasm_functype_delete(type); + return js_throw(js, result); + } + + result = wasm_js_from_result_vec(js, &wasm_results); + + wasm_val_vec_delete(&wasm_args); + wasm_val_vec_delete(&wasm_results); + wasm_functype_delete(type); + return result; +} + +static ant_value_t wasm_wrap_export_value(ant_t *js, ant_value_t instance_obj, const wasm_exporttype_t *export_type, wasm_extern_t *external) { + switch (wasm_extern_kind(external)) { + case WASM_EXTERN_FUNC: { + ant_value_t state = js_mkobj(js); + js_set_slot(state, SLOT_DATA, ANT_PTR(wasm_extern_as_func(external))); + js_set_slot_wb(js, state, SLOT_ENTRIES, instance_obj); + return js_heavy_mkfun(js, js_wasm_exported_func_call, state); + } + case WASM_EXTERN_GLOBAL: { + ant_value_t obj = wasm_wrap_extern_object( + js, WASM_EXTERN_WRAP_GLOBAL, g_wasm_global_proto, BRAND_WASM_GLOBAL, + NULL, false, wasm_extern_as_global(external), instance_obj + ); + if (vtype(obj) == T_OBJ) js_set_finalizer(obj, wasm_extern_finalize); + return obj; + } + case WASM_EXTERN_MEMORY: { + ant_value_t obj = wasm_wrap_extern_object( + js, WASM_EXTERN_WRAP_MEMORY, g_wasm_memory_proto, BRAND_WASM_MEMORY, + NULL, false, wasm_extern_as_memory(external), instance_obj + ); + if (vtype(obj) == T_OBJ) js_set_finalizer(obj, wasm_extern_finalize); + return obj; + } + case WASM_EXTERN_TABLE: { + ant_value_t obj = wasm_wrap_extern_object( + js, WASM_EXTERN_WRAP_TABLE, g_wasm_table_proto, BRAND_WASM_TABLE, + NULL, false, wasm_extern_as_table(external), instance_obj + ); + if (vtype(obj) == T_OBJ) js_set_finalizer(obj, wasm_extern_finalize); + return obj; + } + default: + (void)export_type; + return js_mkundef(); + } +} + +static ant_value_t wasm_module_from_bytes(ant_t *js, ant_value_t value, ant_value_t *out_module) { + wasm_byte_vec_t binary = WASM_EMPTY_VEC; + wasm_store_t *store = NULL; + wasm_module_t *module = NULL; + char error_buf[128] = {0}; + + *out_module = js_mkundef(); + + if (!ensure_wasm_engine()) return js_mkerr(js, "Failed to initialize WebAssembly engine"); + if (!(store = wasm_store_new(g_wasm_engine))) return js_mkerr(js, "Failed to create WebAssembly store"); + + if (!wasm_buffer_source_to_vec(js, value, &binary, error_buf, sizeof(error_buf))) { + wasm_store_delete(store); + return js_mkerr_typed(js, JS_ERR_TYPE, "%s", error_buf); + } + + if (!wasm_module_validate(store, &binary)) { + wasm_byte_vec_delete(&binary); + wasm_store_delete(store); + return wasm_make_compile_error(js, "Invalid WebAssembly binary"); + } + + module = wasm_module_new(store, &binary); + wasm_byte_vec_delete(&binary); + if (!module) { + wasm_store_delete(store); + return wasm_make_compile_error(js, "Failed to compile WebAssembly module"); + } + + *out_module = wasm_wrap_module(js, store, module); + if (vtype(*out_module) == T_OBJ) { + js_set_finalizer(*out_module, wasm_module_finalize); + js_set_slot_wb(js, *out_module, SLOT_MAP, value); + } + return js_mkundef(); +} + +static ant_value_t js_wasm_module_ctor(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t module = js_mkundef(); + ant_value_t err; + + if (vtype(js->new_target) == T_UNDEF) + return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Module constructor requires 'new'"); + if (nargs < 1) + return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Module requires a BufferSource"); + + err = wasm_module_from_bytes(js, args[0], &module); + if (is_err(err)) return err; + if (vtype(module) != T_OBJ) return js_throw(js, wasm_error_value(js, err)); + return module; +} + +static ant_value_t wasm_module_type_descriptors(ant_t *js, ant_value_t module_obj, bool imports) { + wasm_module_handle_t *handle = wasm_module_handle(module_obj); + if (!handle) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Module"); + + ant_value_t arr = js_mkarr(js); + if (imports) { + wasm_importtype_vec_t vec = WASM_EMPTY_VEC; + wasm_module_imports(handle->module, &vec); + for (size_t i = 0; i < vec.size; i++) { + const wasm_importtype_t *entry = vec.data[i]; + const wasm_name_t *module_name = wasm_importtype_module(entry); + const wasm_name_t *name = wasm_importtype_name(entry); + const wasm_externtype_t *type = wasm_importtype_type(entry); + + ant_value_t item = js_mkobj(js); + js_set(js, item, "module", js_mkstr(js, module_name->data, wasm_name_len(module_name))); + js_set(js, item, "name", js_mkstr(js, name->data, wasm_name_len(name))); + js_set(js, item, "kind", js_mkstr(js, wasm_extern_kind_name(wasm_externtype_kind(type)), strlen(wasm_extern_kind_name(wasm_externtype_kind(type))))); + js_arr_push(js, arr, item); + } + wasm_importtype_vec_delete(&vec); + } else { + wasm_exporttype_vec_t vec = WASM_EMPTY_VEC; + wasm_module_exports(handle->module, &vec); + for (size_t i = 0; i < vec.size; i++) { + const wasm_exporttype_t *entry = vec.data[i]; + const wasm_name_t *name = wasm_exporttype_name(entry); + const wasm_externtype_t *type = wasm_exporttype_type(entry); + + ant_value_t item = js_mkobj(js); + js_set(js, item, "name", js_mkstr(js, name->data, wasm_name_len(name))); + js_set(js, item, "kind", js_mkstr(js, wasm_extern_kind_name(wasm_externtype_kind(type)), strlen(wasm_extern_kind_name(wasm_externtype_kind(type))))); + js_arr_push(js, arr, item); + } + wasm_exporttype_vec_delete(&vec); + } + + return arr; +} + +static ant_value_t js_wasm_module_imports(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Module.imports requires 1 argument"); + return wasm_module_type_descriptors(js, args[0], true); +} + +static ant_value_t js_wasm_module_exports(ant_t *js, ant_value_t *args, int nargs) { + if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Module.exports requires 1 argument"); + return wasm_module_type_descriptors(js, args[0], false); +} + +static ant_value_t js_wasm_instance_exports_getter(ant_t *js, ant_value_t *args, int nargs) { + if (!js_check_brand(js->this_val, BRAND_WASM_INSTANCE)) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Instance"); + return js_get_slot(js->this_val, SLOT_ENTRIES); +} + +static ant_value_t wasm_property_get_nested(ant_t *js, ant_value_t base, const wasm_name_t *name) { + if (!is_object_type(base)) return js_mkundef(); + return js_getprop_fallback(js, base, name && name->data ? name->data : ""); +} + +static wasm_trap_t *wasm_import_func_callback(void *env_ptr, const wasm_val_vec_t *args, wasm_val_vec_t *results) { + wasm_import_func_env_t *env = (wasm_import_func_env_t *)env_ptr; + ant_t *js = env->js; + + ant_value_t *js_args = NULL; + ant_value_t result = js_mkundef(); + wasm_message_t trap_msg = WASM_EMPTY_VEC; + + if (args && args->size > 0) { + js_args = calloc(args->size, sizeof(*js_args)); + if (!js_args) { + wasm_name_new_from_string_nt(&trap_msg, "Out of memory"); + wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); + wasm_byte_vec_delete(&trap_msg); + return trap; + } + } + + for (size_t i = 0; args && i < args->size; i++) { + js_args[i] = wasm_value_to_js(js, &args->data[i]); + } + + result = sv_vm_call(js->vm, js, env->fn, js_mkundef(), js_args, args ? (int)args->size : 0, NULL, false); + free(js_args); + + if (is_err(result)) { + const char *msg = "WebAssembly import threw"; + if (vtype(js->thrown_value) == T_OBJ) { + const char *message = get_str_prop(js, js->thrown_value, "message", 7, NULL); + if (message && *message) msg = message; + } + wasm_name_new_from_string_nt(&trap_msg, msg); + wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); + wasm_byte_vec_delete(&trap_msg); + return trap; + } + + if (results && results->size > 0) { + if (results->size == 1) { + if (!js_value_to_wasm(js, result, results->data[0].kind, &results->data[0])) { + wasm_name_new_from_string_nt(&trap_msg, "Unsupported import return value"); + wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); + wasm_byte_vec_delete(&trap_msg); + return trap; + } + } else { + if (vtype(result) != T_ARR) { + wasm_name_new_from_string_nt(&trap_msg, "Expected an array for multi-value return"); + wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); + wasm_byte_vec_delete(&trap_msg); + return trap; + } + + for (size_t i = 0; i < results->size; i++) { + ant_value_t item = js_arr_get(js, result, (ant_offset_t)i); + if (!js_value_to_wasm(js, item, results->data[i].kind, &results->data[i])) { + wasm_name_new_from_string_nt(&trap_msg, "Unsupported import return value"); + wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); + wasm_byte_vec_delete(&trap_msg); + return trap; + } + } + }} + + return NULL; +} + +static ant_value_t wasm_instantiate_module(ant_t *js, ant_value_t module_obj, ant_value_t import_obj, ant_value_t *out_instance) { + wasm_module_handle_t *module_handle = wasm_module_handle(module_obj); + wasm_importtype_vec_t import_types = WASM_EMPTY_VEC; + wasm_exporttype_vec_t export_types = WASM_EMPTY_VEC; + + wasm_extern_t **imports = NULL; + wasm_func_t **owned_host_funcs = NULL; + + size_t owned_host_func_count = 0; + wasm_extern_vec_t exports = WASM_EMPTY_VEC; + + wasm_trap_t *trap = NULL; + wasm_instance_t *instance = NULL; + ant_value_t instance_obj = js_mkundef(); + ant_value_t exports_obj = js_mkobj(js); + + *out_instance = js_mkundef(); + + if (!module_handle) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Module"); + + if (wasi_module_has_wasi_imports(module_handle->module)) { + ant_value_t wasi_opts = is_object_type(import_obj) ? js_get(js, import_obj, "wasi") : js_mkundef(); + if (!is_object_type(import_obj) || is_object_type(wasi_opts)) { + ant_value_t bytes_src = js_get_slot(module_obj, SLOT_MAP); + wasm_byte_vec_t binary = WASM_EMPTY_VEC; + char wasi_err[128] = {0}; + if (!wasm_buffer_source_to_vec(js, bytes_src, &binary, wasi_err, sizeof(wasi_err))) { + return js_mkerr(js, "WASI: cannot extract module bytes"); + } + *out_instance = wasi_instantiate(js, (const uint8_t *)binary.data, binary.size, module_obj, wasi_opts); + wasm_byte_vec_delete(&binary); + return is_err(*out_instance) ? *out_instance : js_mkundef(); + } + } + + wasm_module_imports(module_handle->module, &import_types); + if (import_types.size > 0) { + imports = calloc(import_types.size, sizeof(*imports)); + owned_host_funcs = calloc(import_types.size, sizeof(*owned_host_funcs)); + if (!imports || !owned_host_funcs) { + free(imports); + free(owned_host_funcs); + wasm_importtype_vec_delete(&import_types); + return js_mkerr(js, "out of memory"); + } + } + + for (size_t i = 0; i < import_types.size; i++) { + const wasm_importtype_t *import_type = import_types.data[i]; + const wasm_name_t *module_name = wasm_importtype_module(import_type); + const wasm_name_t *field_name = wasm_importtype_name(import_type); + const wasm_externtype_t *extern_type = wasm_importtype_type(import_type); + + ant_value_t namespace_obj = wasm_property_get_nested(js, import_obj, module_name); + ant_value_t value = wasm_property_get_nested(js, namespace_obj, field_name); + wasm_externkind_t kind = wasm_externtype_kind(extern_type); + + if (kind == WASM_EXTERN_MEMORY || kind == WASM_EXTERN_TABLE) { + free(imports); + free(owned_host_funcs); + wasm_importtype_vec_delete(&import_types); + return wasm_make_link_error(js, "The current WAMR backend does not support memory/table imports"); + } + + if (kind == WASM_EXTERN_FUNC) { + const wasm_functype_t *func_type = wasm_externtype_as_functype_const(extern_type); + wasm_import_func_env_t *env = NULL; + + if (!is_callable(value)) { + free(imports); + free(owned_host_funcs); + wasm_importtype_vec_delete(&import_types); + return wasm_make_link_error(js, "Missing function import"); + } + + env = calloc(1, sizeof(*env)); + if (!env) { + free(imports); + free(owned_host_funcs); + wasm_importtype_vec_delete(&import_types); + return js_mkerr(js, "out of memory"); + } + + env->js = js; + env->store = module_handle->store; + env->owner = module_obj; + env->fn = value; + wasm_register_import_env(env); + + + owned_host_funcs[owned_host_func_count] = wasm_func_new_with_env( + module_handle->store, + func_type, + wasm_import_func_callback, + env, + wasm_import_func_env_finalizer + ); + + if (!owned_host_funcs[owned_host_func_count]) { + free(env); + free(imports); + free(owned_host_funcs); + wasm_importtype_vec_delete(&import_types); + return wasm_make_link_error(js, "Failed to create function import"); + } + + imports[i] = wasm_func_as_extern(owned_host_funcs[owned_host_func_count]); + owned_host_func_count++; + continue; + } + + if (kind == WASM_EXTERN_GLOBAL) { + wasm_extern_handle_t *handle = wasm_extern_handle(value, WASM_EXTERN_WRAP_GLOBAL); + if (!handle || !handle->as.global) { + free(imports); + free(owned_host_funcs); + wasm_importtype_vec_delete(&import_types); + return wasm_make_link_error(js, "Missing global import"); + } + imports[i] = wasm_global_as_extern(handle->as.global); + continue; + } + } + + { + wasm_extern_vec_t import_vec = WASM_EMPTY_VEC; + if (imports && import_types.size > 0) + import_vec = (wasm_extern_vec_t){ import_types.size, imports, import_types.size, sizeof(*imports), NULL }; + + instance = wasm_instance_new(module_handle->store, module_handle->module, &import_vec, &trap); + } + + free(imports); + wasm_importtype_vec_delete(&import_types); + + if (!instance) { + for (size_t i = 0; i < owned_host_func_count; i++) { + if (owned_host_funcs[i]) wasm_func_delete(owned_host_funcs[i]); + } + free(owned_host_funcs); + if (trap) return wasm_trap_to_error(js, trap); + return wasm_make_link_error(js, "Failed to instantiate WebAssembly module"); + } + + wasm_instance_exports(instance, &exports); + wasm_module_exports(module_handle->module, &export_types); + + { + wasm_instance_handle_t *inst_handle = calloc(1, sizeof(*inst_handle)); + if (!inst_handle) { + wasm_extern_vec_delete(&exports); + wasm_exporttype_vec_delete(&export_types); + return js_mkerr(js, "out of memory"); + } + inst_handle->instance = instance; + inst_handle->exports = exports; + inst_handle->host_funcs = owned_host_funcs; + inst_handle->host_func_count = owned_host_func_count; + + instance_obj = wasm_wrap_instance(js, inst_handle, module_obj); + } + if (vtype(instance_obj) != T_OBJ) { + wasm_exporttype_vec_delete(&export_types); + return instance_obj; + } + js_set_finalizer(instance_obj, wasm_instance_finalize); + + for (size_t i = 0; i < export_types.size && i < exports.size; i++) { + const wasm_exporttype_t *export_type = export_types.data[i]; + const wasm_name_t *name = wasm_exporttype_name(export_type); + ant_value_t export_value = wasm_wrap_export_value(js, instance_obj, export_type, exports.data[i]); + js_setprop(js, exports_obj, js_mkstr(js, name->data, wasm_name_len(name)), export_value); + } + + wasm_exporttype_vec_delete(&export_types); + js_set_slot_wb(js, instance_obj, SLOT_ENTRIES, exports_obj); + if (is_object_type(import_obj)) js_set_slot_wb(js, instance_obj, SLOT_MAP, import_obj); + + *out_instance = instance_obj; + return js_mkundef(); +} + +static ant_value_t js_wasm_instance_ctor(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t instance = js_mkundef(); + ant_value_t import_obj = (nargs >= 2 && is_object_type(args[1])) ? args[1] : js_mkundef(); + ant_value_t err; + + if (vtype(js->new_target) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Instance constructor requires 'new'"); + if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Instance requires a module"); + + err = wasm_instantiate_module(js, args[0], import_obj, &instance); + if (is_err(err)) return err; + if (vtype(instance) != T_OBJ) return js_throw(js, wasm_error_value(js, err)); + + return instance; +} + +static ant_value_t js_wasm_global_value_getter(ant_t *js, ant_value_t *args, int nargs) { + wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_GLOBAL); + wasm_val_t value = WASM_INIT_VAL; + + if (!handle || !handle->as.global) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Global"); + if (handle->use_cached_value) return wasm_value_to_js(js, &handle->cached_value); + + wasm_global_get(handle->as.global, &value); + return wasm_value_to_js(js, &value); +} + +static ant_value_t js_wasm_global_value_setter(ant_t *js, ant_value_t *args, int nargs) { + wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_GLOBAL); + wasm_globaltype_t *type = NULL; + + const wasm_valtype_t *content = NULL; + wasm_val_t value = WASM_INIT_VAL; + + if (!handle || !handle->as.global) + return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Global"); + if (nargs < 1) return js_mkundef(); + + type = wasm_global_type(handle->as.global); + if (!type) return js_mkerr(js, "Failed to inspect WebAssembly.Global"); + if (wasm_globaltype_mutability(type) != WASM_VAR) { + wasm_globaltype_delete(type); + return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Global is immutable"); + } + + content = wasm_globaltype_content(type); + if (!js_value_to_wasm(js, args[0], wasm_valtype_kind(content), &value)) { + wasm_globaltype_delete(type); + return js_mkerr_typed(js, JS_ERR_TYPE, "Unsupported global value"); + } + + if (handle->use_cached_value) handle->cached_value = value; + else wasm_global_set(handle->as.global, &value); + wasm_globaltype_delete(type); + + return js_mkundef(); +} + +static ant_value_t js_wasm_global_value_of(ant_t *js, ant_value_t *args, int nargs) { + return js_wasm_global_value_getter(js, NULL, 0); +} + +static ant_value_t js_wasm_global_ctor(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t descriptor; + ant_value_t mutable_val; + + const char *value_type; + ant_offset_t value_type_len = 0; + bool ok = false; + + wasm_valkind_t kind; + wasm_store_t *store = NULL; + wasm_valtype_t *valtype = NULL; + wasm_globaltype_t *globaltype = NULL; + wasm_global_t *global = NULL; + wasm_val_t initial = WASM_INIT_VAL; + ant_value_t result; + + if (vtype(js->new_target) == T_UNDEF) + return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Global constructor requires 'new'"); + if (nargs < 1 || !is_object_type(args[0])) + return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Global requires a descriptor object"); + if (!ensure_wasm_engine()) + return js_mkerr(js, "Failed to initialize WebAssembly engine"); + + descriptor = args[0]; + value_type = get_str_prop(js, descriptor, "value", 5, &value_type_len); + if (!value_type) + return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Global descriptor requires a value type"); + + kind = wasm_valkind_from_string(value_type, value_type_len, &ok); + if (!ok) + return js_mkerr_typed(js, JS_ERR_TYPE, "Unsupported WebAssembly.Global value type"); + + if (!js_value_to_wasm(js, nargs >= 2 ? args[1] : js_mknum(0), kind, &initial)) + return js_mkerr_typed(js, JS_ERR_TYPE, "Unsupported WebAssembly.Global initial value"); + + mutable_val = js_get(js, descriptor, "mutable"); + store = wasm_store_new(g_wasm_engine); + if (!store) return js_mkerr(js, "Failed to create WebAssembly store"); + + valtype = wasm_valtype_new(kind); + globaltype = wasm_globaltype_new(valtype, js_truthy(js, mutable_val) ? WASM_VAR : WASM_CONST); + global = globaltype ? wasm_global_new(store, globaltype, &initial) : NULL; + + wasm_globaltype_delete(globaltype); + + if (!global) { + wasm_store_delete(store); + return js_throw(js, wasm_make_runtime_error(js, "Failed to create WebAssembly.Global")); + } + + result = wasm_wrap_extern_object( + js, WASM_EXTERN_WRAP_GLOBAL, g_wasm_global_proto, BRAND_WASM_GLOBAL, + store, true, global, js_mkundef() + ); + if (vtype(result) == T_OBJ) { + wasm_extern_handle_t *handle = wasm_extern_handle(result, WASM_EXTERN_WRAP_GLOBAL); + if (handle) { + handle->use_cached_value = true; + handle->cached_value = initial; + } + js_set_finalizer(result, wasm_extern_finalize); + } + return result; +} + +static ant_value_t js_wasm_memory_buffer_getter(ant_t *js, ant_value_t *args, int nargs) { + wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_MEMORY); + byte_t *data; size_t len; ArrayBufferData *buffer; + + if (!handle || !handle->as.memory) + return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Memory"); + + data = wasm_memory_data(handle->as.memory); + len = wasm_memory_data_size(handle->as.memory); + buffer = calloc(1, sizeof(ArrayBufferData)); + + if (!buffer) return js_mkerr(js, "out of memory"); + buffer->data = (uint8_t *)data; + buffer->length = len; + buffer->capacity = len; + buffer->ref_count = 1; + + return create_arraybuffer_obj(js, buffer); +} + +static ant_value_t js_wasm_memory_grow(ant_t *js, ant_value_t *args, int nargs) { + return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not support host-side memory.grow"); +} + +static ant_value_t js_wasm_memory_ctor(ant_t *js, ant_value_t *args, int nargs) { + if (vtype(js->new_target) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Memory constructor requires 'new'"); + return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not support standalone WebAssembly.Memory"); +} + +static ant_value_t js_wasm_table_length_getter(ant_t *js, ant_value_t *args, int nargs) { + wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_TABLE); + if (!handle || !handle->as.table) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Table"); + return js_mknum((double)wasm_table_size(handle->as.table)); +} + +static ant_value_t js_wasm_table_get(ant_t *js, ant_value_t *args, int nargs) { + wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_TABLE); + wasm_ref_t *ref; + uint32_t index; + + if (!handle || !handle->as.table) + return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Table"); + + index = (uint32_t)(nargs > 0 ? js_to_number(js, args[0]) : 0); + ref = wasm_table_get(handle->as.table, index); + + if (!ref) return js_mknull(); + wasm_ref_delete(ref); + + return js_mknull(); +} + +static ant_value_t js_wasm_table_set(ant_t *js, ant_value_t *args, int nargs) { + wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_TABLE); + uint32_t index; + + if (!handle || !handle->as.table) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Table"); + if (nargs < 2) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Table.set requires 2 arguments"); + + index = (uint32_t)js_to_number(js, args[0]); + if (!wasm_table_set(handle->as.table, index, NULL)) return js_mkerr_typed(js, JS_ERR_TYPE, "Failed to update WebAssembly.Table"); + + return js_mkundef(); +} + +static ant_value_t js_wasm_table_grow(ant_t *js, ant_value_t *args, int nargs) { + return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not support host-side table.grow"); +} + +static ant_value_t js_wasm_table_ctor(ant_t *js, ant_value_t *args, int nargs) { + if (vtype(js->new_target) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Table constructor requires 'new'"); + return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not support standalone WebAssembly.Table"); +} + +static ant_value_t js_wasm_tag_ctor(ant_t *js, ant_value_t *args, int nargs) { + return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not expose WebAssembly.Tag"); +} + +static ant_value_t js_wasm_exception_ctor(ant_t *js, ant_value_t *args, int nargs) { + return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not expose WebAssembly.Exception"); +} + +static ant_value_t js_wasm_validate(ant_t *js, ant_value_t *args, int nargs) { + wasm_byte_vec_t binary = WASM_EMPTY_VEC; + wasm_store_t *store; + + char error_buf[128] = {0}; + bool ok; + + if (nargs < 1) return js_false; + if (!ensure_wasm_engine()) return js_false; + if (!(store = wasm_store_new(g_wasm_engine))) return js_false; + + if (!wasm_buffer_source_to_vec(js, args[0], &binary, error_buf, sizeof(error_buf))) { + wasm_store_delete(store); + return js_false; + } + + ok = wasm_module_validate(store, &binary); + wasm_byte_vec_delete(&binary); + wasm_store_delete(store); + + return js_bool(ok); +} + +static ant_value_t js_wasm_compile(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t promise = js_mkpromise(js); + ant_value_t module = js_mkundef(); + ant_value_t err; + + if (nargs < 1) { + wasm_reject_with_error(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.compile requires 1 argument")); + return promise; + } + + err = wasm_module_from_bytes(js, args[0], &module); + if (is_err(err) || vtype(module) != T_OBJ) { + wasm_reject_with_error(js, promise, wasm_error_value(js, err)); + return promise; + } + + js_resolve_promise(js, promise, module); + return promise; +} + +static ant_value_t js_wasm_instantiate(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t promise = js_mkpromise(js); + ant_value_t module = js_mkundef(); + ant_value_t instance = js_mkundef(); + ant_value_t import_obj = (nargs >= 2 && is_object_type(args[1])) ? args[1] : js_mkundef(); + ant_value_t err; + + if (nargs < 1) { + wasm_reject_with_error(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.instantiate requires 1 argument")); + return promise; + } + + if (wasm_module_handle(args[0])) { + err = wasm_instantiate_module(js, args[0], import_obj, &instance); + if (is_err(err) || vtype(instance) != T_OBJ) { + wasm_reject_with_error(js, promise, wasm_error_value(js, err)); + return promise; + } + js_resolve_promise(js, promise, instance); + return promise; + } + + err = wasm_module_from_bytes(js, args[0], &module); + if (is_err(err) || vtype(module) != T_OBJ) { + wasm_reject_with_error(js, promise, wasm_error_value(js, err)); + return promise; + } + + err = wasm_instantiate_module(js, module, import_obj, &instance); + if (is_err(err) || vtype(instance) != T_OBJ) { + wasm_reject_with_error(js, promise, wasm_error_value(js, err)); + return promise; + } + + ant_value_t result = js_mkobj(js); + js_set(js, result, "module", module); + js_set(js, result, "instance", instance); + js_resolve_promise(js, promise, result); + + return promise; +} + +static ant_value_t js_wasm_compile_error_ctor(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t msg = (nargs > 0) ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); + if (is_err(msg)) return msg; + return wasm_make_error(js, g_wasm_compileerror_proto, "CompileError", js_str(js, msg)); +} + +static ant_value_t js_wasm_link_error_ctor(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t msg = (nargs > 0) ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); + if (is_err(msg)) return msg; + return wasm_make_error(js, g_wasm_linkerror_proto, "LinkError", js_str(js, msg)); +} + +static ant_value_t js_wasm_runtime_error_ctor(ant_t *js, ant_value_t *args, int nargs) { + ant_value_t msg = (nargs > 0) ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); + if (is_err(msg)) return msg; + return wasm_make_error(js, g_wasm_runtimeerror_proto, "RuntimeError", js_str(js, msg)); +} + +void gc_mark_wasm(ant_t *js, gc_mark_fn mark) { +for (size_t i = 0; i < g_wasm_import_env_count; i++) { + wasm_import_func_env_t *env = g_wasm_import_envs[i]; + mark(js, env->fn); + mark(js, env->owner); +}} + +void init_wasm_module(void) { + ant_t *js = rt->js; + ant_value_t global = js_glob(js); + + ant_value_t error_proto = js_get_ctor_proto(js, "Error", 5); + ant_value_t ns = js_mkobj(js); + + if (!ensure_wasm_engine()) return; + + g_wasm_module_proto = js_mkobj(js); + g_wasm_instance_proto = js_mkobj(js); + g_wasm_global_proto = js_mkobj(js); + g_wasm_memory_proto = js_mkobj(js); + g_wasm_table_proto = js_mkobj(js); + g_wasm_tag_proto = js_mkobj(js); + g_wasm_exception_proto = js_mkobj(js); + + g_wasm_compileerror_proto = js_mkobj(js); + g_wasm_linkerror_proto = js_mkobj(js); + g_wasm_runtimeerror_proto = js_mkobj(js); + + js_set_proto_init(g_wasm_module_proto, js_get_ctor_proto(js, "Object", 6)); + js_set_proto_init(g_wasm_instance_proto, js_get_ctor_proto(js, "Object", 6)); + js_set_proto_init(g_wasm_global_proto, js_get_ctor_proto(js, "Object", 6)); + js_set_proto_init(g_wasm_memory_proto, js_get_ctor_proto(js, "Object", 6)); + js_set_proto_init(g_wasm_table_proto, js_get_ctor_proto(js, "Object", 6)); + js_set_proto_init(g_wasm_tag_proto, js_get_ctor_proto(js, "Object", 6)); + js_set_proto_init(g_wasm_exception_proto, js_get_ctor_proto(js, "Object", 6)); + + js_set_proto_init(g_wasm_compileerror_proto, error_proto); + js_set_proto_init(g_wasm_linkerror_proto, error_proto); + js_set_proto_init(g_wasm_runtimeerror_proto, error_proto); + + js_set(js, g_wasm_global_proto, "valueOf", js_mkfun(js_wasm_global_value_of)); + js_set_getter_desc(js, g_wasm_global_proto, "value", 5, js_mkfun(js_wasm_global_value_getter), JS_DESC_C); + js_set_setter_desc(js, g_wasm_global_proto, "value", 5, js_mkfun(js_wasm_global_value_setter), JS_DESC_C); + + js_set_getter_desc(js, g_wasm_instance_proto, "exports", 7, js_mkfun(js_wasm_instance_exports_getter), JS_DESC_C); + js_set_getter_desc(js, g_wasm_memory_proto, "buffer", 6, js_mkfun(js_wasm_memory_buffer_getter), JS_DESC_C); + js_set(js, g_wasm_memory_proto, "grow", js_mkfun(js_wasm_memory_grow)); + + js_set_getter_desc(js, g_wasm_table_proto, "length", 6, js_mkfun(js_wasm_table_length_getter), JS_DESC_C); + js_set(js, g_wasm_table_proto, "get", js_mkfun(js_wasm_table_get)); + js_set(js, g_wasm_table_proto, "set", js_mkfun(js_wasm_table_set)); + js_set(js, g_wasm_table_proto, "grow", js_mkfun(js_wasm_table_grow)); + + ant_value_t module_ctor = js_make_ctor(js, js_wasm_module_ctor, g_wasm_module_proto, "Module", 6); + ant_value_t instance_ctor = js_make_ctor(js, js_wasm_instance_ctor, g_wasm_instance_proto, "Instance", 8); + ant_value_t global_ctor = js_make_ctor(js, js_wasm_global_ctor, g_wasm_global_proto, "Global", 6); + ant_value_t memory_ctor = js_make_ctor(js, js_wasm_memory_ctor, g_wasm_memory_proto, "Memory", 6); + ant_value_t table_ctor = js_make_ctor(js, js_wasm_table_ctor, g_wasm_table_proto, "Table", 5); + ant_value_t tag_ctor = js_make_ctor(js, js_wasm_tag_ctor, g_wasm_tag_proto, "Tag", 3); + ant_value_t exception_ctor = js_make_ctor(js, js_wasm_exception_ctor, g_wasm_exception_proto, "Exception", 9); + + ant_value_t compile_error_ctor = js_make_ctor(js, js_wasm_compile_error_ctor, g_wasm_compileerror_proto, "CompileError", 12); + ant_value_t link_error_ctor = js_make_ctor(js, js_wasm_link_error_ctor, g_wasm_linkerror_proto, "LinkError", 9); + ant_value_t runtime_error_ctor = js_make_ctor(js, js_wasm_runtime_error_ctor, g_wasm_runtimeerror_proto, "RuntimeError", 12); + + js_set(js, module_ctor, "imports", js_mkfun(js_wasm_module_imports)); + js_set(js, module_ctor, "exports", js_mkfun(js_wasm_module_exports)); + + js_set(js, ns, "validate", js_mkfun(js_wasm_validate)); + js_set(js, ns, "compile", js_mkfun(js_wasm_compile)); + js_set(js, ns, "instantiate", js_mkfun(js_wasm_instantiate)); + + js_set(js, ns, "Module", module_ctor); + js_set(js, ns, "Instance", instance_ctor); + js_set(js, ns, "Global", global_ctor); + js_set(js, ns, "Memory", memory_ctor); + js_set(js, ns, "Table", table_ctor); + js_set(js, ns, "Tag", tag_ctor); + js_set(js, ns, "Exception", exception_ctor); + js_set(js, ns, "CompileError", compile_error_ctor); + js_set(js, ns, "LinkError", link_error_ctor); + js_set(js, ns, "RuntimeError", runtime_error_ctor); + + js_set(js, global, "WebAssembly", ns); + js_set_descriptor(js, global, "WebAssembly", 11, JS_DESC_W | JS_DESC_C); +} diff --git a/src/net/listener.c b/src/net/listener.c index b141e592..4e2d8c42 100644 --- a/src/net/listener.c +++ b/src/net/listener.c @@ -2,7 +2,9 @@ #ifndef _WIN32 #include +#include #include +#include #include #endif #include @@ -11,6 +13,38 @@ #include "net/connection.h" #include "net/listener.h" +static int sockaddr_from_addrinfo(const struct addrinfo *ai, int port, struct sockaddr_storage *out) { + if (ai->ai_family == AF_INET) { + struct sockaddr_in sa; + memcpy(&sa, ai->ai_addr, sizeof(sa)); + sa.sin_port = htons((uint16_t)port); + memcpy(out, &sa, sizeof(sa)); + return 0; + } + + if (ai->ai_family == AF_INET6) { + struct sockaddr_in6 sa6; + memcpy(&sa6, ai->ai_addr, sizeof(sa6)); + sa6.sin6_port = htons((uint16_t)port); + memcpy(out, &sa6, sizeof(sa6)); + return 0; + } + + return UV_ENOENT; +} + +static int resolve_hostname(const char *hostname, int port, struct sockaddr_storage *out) { + struct addrinfo hints = {0}, *res = NULL; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(hostname, NULL, &hints, &res) != 0 || !res) return UV_ENOENT; + int rc = sockaddr_from_addrinfo(res, port, out); + freeaddrinfo(res); + + return rc; +} + static void ant_listener_close_cb(uv_handle_t *handle) { ant_listener_t *listener = (ant_listener_t *)handle->data; if (!listener) return; @@ -54,13 +88,14 @@ int ant_listener_listen_tcp( ant_listener_t *listener, uv_loop_t *loop, const char *hostname, - int port, - int backlog, + int port, int backlog, uint64_t idle_timeout_ms, const ant_listener_callbacks_t *callbacks, void *user_data ) { - struct sockaddr_in addr; + struct sockaddr_storage addr; + struct sockaddr *sockaddr = (struct sockaddr *)&addr; + int rc = 0; int addr_len = sizeof(addr); @@ -78,18 +113,24 @@ int ant_listener_listen_tcp( uv_tcp_init(loop, &listener->handle.tcp); listener->handle.tcp.data = listener; - rc = uv_ip4_addr(hostname, port, &addr); + memset(&addr, 0, sizeof(addr)); + rc = uv_ip4_addr(hostname, port, (struct sockaddr_in *)&addr); + + if (rc != 0) rc = uv_ip6_addr(hostname, port, (struct sockaddr_in6 *)&addr); + if (rc != 0) rc = resolve_hostname(hostname, port, &addr); if (rc != 0) return rc; - rc = uv_tcp_bind(&listener->handle.tcp, (const struct sockaddr *)&addr, 0); + rc = uv_tcp_bind(&listener->handle.tcp, sockaddr, 0); if (rc != 0) return rc; rc = uv_listen((uv_stream_t *)&listener->handle.tcp, listener->backlog, ant_listener_accept_cb); if (rc != 0) return rc; listener->started = true; - if (port == 0 && uv_tcp_getsockname(&listener->handle.tcp, (struct sockaddr *)&addr, &addr_len) == 0) - listener->port = ntohs(addr.sin_port); + if (port == 0 && uv_tcp_getsockname(&listener->handle.tcp, sockaddr, &addr_len) == 0) { + if (addr.ss_family == AF_INET) listener->port = ntohs(((struct sockaddr_in *)sockaddr)->sin_port); + else if (addr.ss_family == AF_INET6) listener->port = ntohs(((struct sockaddr_in6 *)sockaddr)->sin6_port); + } return 0; } diff --git a/src/silver/ast.c b/src/silver/ast.c index 19e5279e..315bb2e5 100644 --- a/src/silver/ast.c +++ b/src/silver/ast.c @@ -795,8 +795,9 @@ static sv_ast_t *parse_primary(P) { ant_offset_t flags_start = POS; while (POS < CLEN) { char c = CODE[POS]; - if (c == 'g' || c == 'i' || c == 'm' || c == 's' || c == 'u' || c == 'y') - POS++; + if ( + c == 'd' || c == 'g' || c == 'i' || c == 'm' || + c == 's' || c == 'u' || c == 'v' || c == 'y') POS++; else break; } diff --git a/src/silver/compiler.c b/src/silver/compiler.c index 9debd75f..05451638 100644 --- a/src/silver/compiler.c +++ b/src/silver/compiler.c @@ -1113,6 +1113,7 @@ static void hoist_lexical_pattern(sv_compiler_t *c, sv_ast_t *pat, ensure_local_at_depth(c, pat->str, pat->len, is_const, c->scope_depth); break; case N_ASSIGN_PAT: + case N_ASSIGN: hoist_lexical_pattern(c, pat->left, is_const); break; case N_REST: @@ -3183,6 +3184,7 @@ static void for_collect_pattern_slots(sv_compiler_t *c, sv_ast_t *pat, break; } case N_ASSIGN_PAT: + case N_ASSIGN: for_collect_pattern_slots(c, pat->left, slots, count, cap); break; case N_REST: diff --git a/src/silver/ops/literals.h b/src/silver/ops/literals.h index ddbd860b..bc7b8f93 100644 --- a/src/silver/ops/literals.h +++ b/src/silver/ops/literals.h @@ -86,13 +86,13 @@ static inline void sv_op_array(sv_vm_t *vm, ant_t *js, uint8_t *ip) { vm->stack[vm->sp++] = arr; } +// TODO: reduce duplication with regex.c static inline void sv_op_regexp(sv_vm_t *vm, ant_t *js) { ant_value_t pattern = vm->stack[vm->sp - 2]; - ant_value_t flags = vm->stack[vm->sp - 1]; + ant_value_t flags = vm->stack[vm->sp - 1]; vm->sp -= 2; ant_value_t regexp_obj = mkobj(js, 0); - ant_value_t regexp_proto = js_get_ctor_proto(js, "RegExp", 6); if (vtype(regexp_proto) == T_OBJ) js_set_proto_init(regexp_obj, regexp_proto); @@ -106,27 +106,38 @@ static inline void sv_op_regexp(sv_vm_t *vm, ant_t *js) { fstr = (const char *)(uintptr_t)(foff); } - bool g = false, i = false, m = false, s = false, y = false; + bool d = false, g = false, i = false, m = false; + bool s = false, u = false, v = false, y = false; + for (ant_offset_t k = 0; k < flen; k++) { + if (fstr[k] == 'd') d = true; if (fstr[k] == 'g') g = true; if (fstr[k] == 'i') i = true; if (fstr[k] == 'm') m = true; if (fstr[k] == 's') s = true; + if (fstr[k] == 'u') u = true; + if (fstr[k] == 'v') v = true; if (fstr[k] == 'y') y = true; } - char sorted[8]; int si = 0; + char sorted[10]; int si = 0; + if (d) sorted[si++] = 'd'; if (g) sorted[si++] = 'g'; if (i) sorted[si++] = 'i'; if (m) sorted[si++] = 'm'; if (s) sorted[si++] = 's'; + if (u) sorted[si++] = 'u'; + if (v) sorted[si++] = 'v'; if (y) sorted[si++] = 'y'; js_mkprop_fast(js, regexp_obj, "flags", 5, js_mkstr(js, sorted, si)); + js_mkprop_fast(js, regexp_obj, "hasIndices", 10, mkval(T_BOOL, d ? 1 : 0)); js_mkprop_fast(js, regexp_obj, "global", 6, mkval(T_BOOL, g ? 1 : 0)); js_mkprop_fast(js, regexp_obj, "ignoreCase", 10, mkval(T_BOOL, i ? 1 : 0)); js_mkprop_fast(js, regexp_obj, "multiline", 9, mkval(T_BOOL, m ? 1 : 0)); js_mkprop_fast(js, regexp_obj, "dotAll", 6, mkval(T_BOOL, s ? 1 : 0)); + js_mkprop_fast(js, regexp_obj, "unicode", 7, mkval(T_BOOL, u ? 1 : 0)); + js_mkprop_fast(js, regexp_obj, "unicodeSets", 11, mkval(T_BOOL, v ? 1 : 0)); js_mkprop_fast(js, regexp_obj, "sticky", 6, mkval(T_BOOL, y ? 1 : 0)); js_mkprop_fast(js, regexp_obj, "lastIndex", 9, tov(0)); diff --git a/src/types/modules/fs.d.ts b/src/types/modules/fs.d.ts index 5e23f81e..e596a333 100644 --- a/src/types/modules/fs.d.ts +++ b/src/types/modules/fs.d.ts @@ -10,6 +10,26 @@ declare module 'fs' { } type Encoding = 'utf8' | 'utf-8' | 'utf16le' | 'ucs2' | 'ucs-2' | 'latin1' | 'binary' | 'base64' | 'base64url' | 'hex' | 'ascii'; + type WatchEventType = 'rename' | 'change'; + + interface FSWatcher { + close(): this; + ref(): this; + unref(): this; + on(event: 'change', listener: (eventType: WatchEventType, filename?: string) => void): this; + on(event: 'error', listener: (error: Error) => void): this; + } + + interface WatchOptions { + persistent?: boolean; + recursive?: boolean; + encoding?: Encoding | 'buffer'; + } + + interface WatchFileOptions { + persistent?: boolean; + interval?: number; + } const constants: { F_OK: number; @@ -45,7 +65,9 @@ declare module 'fs' { function appendFileSync(path: string, data: string): void; function copyFileSync(src: string, dest: string): void; function renameSync(oldPath: string, newPath: string): void; + function rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise; function unlink(path: string): Promise; + function rmSync(path: string, options?: { recursive?: boolean; force?: boolean }): void; function unlinkSync(path: string): void; function mkdir(path: string, options?: { recursive?: boolean; mode?: number }): Promise; function mkdirSync(path: string, options?: number | { recursive?: boolean; mode?: number }): void; @@ -64,6 +86,18 @@ declare module 'fs' { namespace realpathSync { function native(path: string): string; } + function watch(path: string, listener?: (eventType: WatchEventType, filename?: string) => void): FSWatcher; + function watch( + path: string, + options: WatchOptions | Encoding | 'buffer', + listener?: (eventType: WatchEventType, filename?: string) => void + ): FSWatcher; + function watchFile(path: string, listener: (curr: Stats, prev: Stats) => void): void; + function watchFile(path: string, options: WatchFileOptions, listener: (curr: Stats, prev: Stats) => void): void; + function unwatchFile(path: string, listener?: (curr: Stats, prev: Stats) => void): void; + const FSWatcher: { + prototype: FSWatcher; + }; } declare module 'ant:fs' { @@ -108,6 +142,7 @@ declare module 'fs/promises' { function writeFile(path: string, data: string | ArrayBufferView): Promise; function write(fd: number, data: string | ArrayBufferView, offset?: number, length?: number, position?: number | null): Promise; function writev(fd: number, buffers: ArrayBufferView[], position?: number): Promise; + function rm(path: string, options?: { recursive?: boolean; force?: boolean }): Promise; function unlink(path: string): Promise; function mkdir(path: string, options?: { recursive?: boolean; mode?: number }): Promise; function rmdir(path: string): Promise; diff --git a/src/types/modules/util.d.ts b/src/types/modules/util.d.ts index 76d067a4..f1146e2c 100644 --- a/src/types/modules/util.d.ts +++ b/src/types/modules/util.d.ts @@ -7,21 +7,13 @@ declare module 'util' { } function format(format?: unknown, ...args: unknown[]): string; - function formatWithOptions( - inspectOptions: unknown, - format?: unknown, - ...args: unknown[] - ): string; + function formatWithOptions(inspectOptions: unknown, format?: unknown, ...args: unknown[]): string; function inspect(value: unknown, options?: unknown): string; - function promisify( - fn: (...args: unknown[]) => unknown - ): (...args: unknown[]) => Promise; + function inherits(ctor: (...args: unknown[]) => unknown, superCtor: (...args: unknown[]) => unknown): void; + function parseEnv(content: string): Record; + function promisify(fn: (...args: unknown[]) => unknown): (...args: unknown[]) => Promise; function stripVTControlCharacters(str: string): string; - function styleText( - format: StyleTextFormat, - text: string, - options?: StyleTextOptions - ): string; + function styleText(format: StyleTextFormat, text: string, options?: StyleTextOptions): string; } declare module 'ant:util' { diff --git a/src/utf8.c b/src/utf8.c index 2398b431..b83593c7 100644 --- a/src/utf8.c +++ b/src/utf8.c @@ -53,15 +53,17 @@ static bool utf8_json_quote_append_u_escape( char *utf8_json_quote(const char *str, size_t byte_len, size_t *out_len) { size_t utf16_len = utf16_strlen(str, byte_len); - char *raw = NULL; size_t raw_len = 0; - size_t raw_cap = 0; + size_t raw_cap = byte_len + 4; + + char *raw = malloc(raw_cap); + if (!raw) return NULL; if (!utf8_json_quote_append_char(&raw, &raw_len, &raw_cap, '"')) goto oom; for (size_t i = 0; i < utf16_len; i++) { uint32_t cu = utf16_code_unit_at(str, byte_len, i); - + if (cu >= 0xD800 && cu <= 0xDBFF && i + 1 < utf16_len) { uint32_t cu2 = utf16_code_unit_at(str, byte_len, i + 1); if (cu2 >= 0xDC00 && cu2 <= 0xDFFF) { diff --git a/src/watch.c b/src/watch.c index c36e593f..b221977b 100644 --- a/src/watch.c +++ b/src/watch.c @@ -44,7 +44,7 @@ static void watch_clear_screen(void) { fflush(stdout); } -static char *watch_resolve_path(const char *path) { +char *ant_watch_resolve_path(const char *path) { #ifdef _WIN32 char *resolved = _fullpath(NULL, path, 0); if (resolved) return resolved; @@ -56,6 +56,44 @@ static char *watch_resolve_path(const char *path) { #endif } +int ant_watch_start( + uv_loop_t *loop, + uv_fs_event_t *event, + const char *path, + uv_fs_event_cb callback, + void *data, + unsigned int flags, + char **resolved_path_out +) { + char *watch_path = NULL; + int rc = 0; + + if (!loop || !event || !path || !callback) return UV_EINVAL; + + watch_path = ant_watch_resolve_path(path); + if (!watch_path) return UV_ENOMEM; + + rc = uv_fs_event_init(loop, event); + if (rc != 0) goto cleanup; + + event->data = data; + rc = uv_fs_event_start(event, callback, watch_path, flags); + if (rc != 0) goto cleanup; + + if (resolved_path_out) *resolved_path_out = watch_path; + else free(watch_path); + return 0; + +cleanup: + free(watch_path); + return rc; +} + +void ant_watch_stop(uv_fs_event_t *event) { + if (!event) return; + uv_fs_event_stop(event); +} + static char **watch_build_child_argv(int argc, char **argv) { char **child_argv = calloc((size_t)argc + 1, sizeof(char *)); if (!child_argv) return NULL; @@ -238,7 +276,7 @@ int ant_watch_run(int argc, char **argv, const char *entry_file, bool no_clear_s watch_state_t state = {0}; state.child_argv = watch_build_child_argv(argc, argv); - state.watch_path = watch_resolve_path(entry_file); + state.watch_path = ant_watch_resolve_path(entry_file); state.no_clear_screen = no_clear_screen; state.final_exit_code = EXIT_SUCCESS; @@ -256,13 +294,15 @@ int ant_watch_run(int argc, char **argv, const char *entry_file, bool no_clear_s return EXIT_FAILURE; } - rc = uv_fs_event_init(&state.loop, &state.fs_event); - if (rc == 0) state.fs_event_inited = true; + rc = ant_watch_start( + &state.loop, + &state.fs_event, + state.watch_path, + watch_on_fs_event, + &state, 0, NULL + ); - if (rc == 0) { - state.fs_event.data = &state; - rc = uv_fs_event_start(&state.fs_event, watch_on_fs_event, state.watch_path, 0); - } + if (rc == 0) state.fs_event_inited = true; if (rc != 0) { crfprintf(stderr, msg.watch_file_failed, state.watch_path, uv_strerror(rc)); diff --git a/tests/readable_stream_abort_capture.mjs b/tests/readable_stream_abort_capture.mjs new file mode 100644 index 00000000..1f45b834 --- /dev/null +++ b/tests/readable_stream_abort_capture.mjs @@ -0,0 +1,85 @@ +function assert(condition, message) { + if (!condition) throw new Error(message); +} + +function makeAbortError() { + try { + return new DOMException('aborted', 'AbortError'); + } catch { + const error = new Error('aborted'); + error.name = 'AbortError'; + return error; + } +} + +function abortRequest(request, reason) { + if (request.status === 10 || request.status === 11) request.status = 12; + request.fatalError = reason; + if (request.destination) { + try { + request.destination.error?.(reason); + } catch {} + request.destination = null; + } +} + +async function runIteration(index) { + const controller = new AbortController(); + const signal = controller.signal; + const request = { + status: 10, + destination: null, + fatalError: null, + seen: 0, + }; + + setTimeout(() => { + if (request.status === 10) request.status = 11; + }, 0); + + const listener = () => { + abortRequest(request, signal.reason ?? makeAbortError()); + signal.removeEventListener('abort', listener); + }; + + signal.addEventListener('abort', listener); + + const stream = new ReadableStream({ + pull(controllerObj) { + request.seen++; + + if (request.status === 13) { + request.status = 14; + controllerObj.error(request.fatalError); + return; + } + + if (request.status !== 14 && request.destination === null) { + request.destination = controllerObj; + controllerObj.enqueue(new Uint8Array([index & 255])); + controllerObj.close(); + request.destination = null; + } + }, + cancel(reason) { + request.destination = null; + abortRequest(request, reason); + }, + }, { highWaterMark: 0 }); + + queueMicrotask(() => controller.abort(makeAbortError())); + + const reader = stream.getReader(); + try { + await reader.read(); + } catch {} + + assert(request.seen >= 1, `pull was not invoked for iteration ${index}`); +} + +for (let i = 0; i < 2000; i++) { + await runIteration(i); + if ((i + 1) % 100 === 0) console.log(`iter:${i + 1}`); +} + +console.log('ok'); diff --git a/tests/repro_fsevents_direntry_bug.mjs b/tests/repro_fsevents_direntry_bug.mjs new file mode 100644 index 00000000..aea5a719 --- /dev/null +++ b/tests/repro_fsevents_direntry_bug.mjs @@ -0,0 +1,216 @@ +// Repro attempt for the watcher-side `dirObj.has(...)` failure without Vite. +// +// Run with: +// ant tests/repro_fsevents_direntry_bug.mjs +// +// This uses only `fsevents` plus a tiny local watcher shim that mirrors the +// chokidar/Vite code path around: +// const dirObj = this.fsw._getWatchedDir(dirname(pp)); +// if (dirObj.has(base)) return; + +import fs from 'node:fs'; +import { EventEmitter } from 'node:events'; +import path from 'node:path'; +import fsevents from '/Users/themackabu/.ant/pkg/exec/vite/node_modules/fsevents/fsevents.js'; + +class DirEntry { + constructor(dir) { + this.path = dir; + this.items = new Set(); + } + + add(item) { + const { items } = this; + if (!items) return; + if (item !== '.' && item !== '..') items.add(item); + } + + has(item) { + const { items } = this; + if (!items) return; + return items.has(item); + } +} + +class MiniWatcher { + constructor(root) { + this.root = path.resolve(root); + this._watched = new Map(); + } + + _getWatchedDir(directory) { + const dir = path.resolve(directory); + if (!this._watched.has(dir)) { + this._watched.set(dir, new DirEntry(dir)); + } + return this._watched.get(dir); + } + + emitAdd(newPath, stats) { + const pp = path.resolve(newPath); + const isDir = stats.isDirectory(); + const dirObj = this._getWatchedDir(path.dirname(pp)); + const base = path.basename(pp); + + if (isDir) this._getWatchedDir(pp); + + console.log('[emitAdd]', { + pp, + base, + dir: dirObj.path, + hasType: typeof dirObj.has, + addType: typeof dirObj.add, + itemsType: typeof dirObj.items, + itemsHasType: typeof dirObj.items?.has, + }); + + if (dirObj.has(base)) { + console.log('[emitAdd] already present', base); + return; + } + + dirObj.add(base); + console.log('[emitAdd] added', base); + } +} + +function statSafe(file) { + try { + return fs.statSync(file); + } catch (error) { + console.log('[stat error]', file, error?.name, error?.message); + return null; + } +} + +async function walkEntries(root, emitEntry) { + const pending = [root]; + const seen = new Set(); + + while (pending.length > 0) { + const dir = pending.pop(); + const resolvedDir = path.resolve(dir); + if (seen.has(resolvedDir)) continue; + seen.add(resolvedDir); + let entries; + + try { + entries = await fs.promises.readdir(resolvedDir); + } catch (error) { + console.log('[readdir error]', resolvedDir, error?.name, error?.message); + continue; + } + + for (const name of entries) { + const fullPath = path.join(resolvedDir, name); + let stats; + + try { + stats = await fs.promises.lstat(fullPath); + } catch (error) { + console.log('[lstat error]', fullPath, error?.name, error?.message); + continue; + } + + await emitEntry({ + path: path.relative(root, fullPath), + fullPath, + stats, + }); + + if (stats.isDirectory()) pending.push(fullPath); + } + } +} + +function makeReaddirpLikeStream(root) { + const stream = new EventEmitter(); + + queueMicrotask(async () => { + try { + await walkEntries(root, async (entry) => { + stream.emit('data', entry); + }); + stream.emit('end'); + } catch (error) { + stream.emit('error', error); + } + }); + + return stream; +} + +const root = process.cwd(); +const watcher = new MiniWatcher(root); +const probeFile = path.join(root, 'tmp', 'fsevents-direntry-probe.txt'); + +process.on('unhandledRejection', (reason) => { + console.log('[unhandledRejection]', reason?.name, reason?.message); + if (reason?.stack) console.log(reason.stack); +}); + +process.on('uncaughtException', (error) => { + console.log('[uncaughtException]', error?.name, error?.message); + if (error?.stack) console.log(error.stack); + process.exitCode = 1; +}); + +const stop = fsevents.watch(root, (fullPath, flags, id) => { + const info = fsevents.getInfo(fullPath, flags, id); + const target = path.resolve(fullPath); + + console.log('[fsevent]', { + fullPath: target, + event: info.event, + type: info.type, + }); + + const stats = statSafe(target); + if (!stats) return; + + try { + watcher.emitAdd(target, stats); + } catch (error) { + console.log('[emitAdd throw]', error?.name, error?.message); + if (error?.stack) console.log(error.stack); + } +}); + +console.log('watching', root); + +fs.mkdirSync(path.dirname(probeFile), { recursive: true }); +fs.writeFileSync(probeFile, `probe ${Date.now()}\n`); +console.log('wrote probe file', probeFile); + +const stream = makeReaddirpLikeStream(root); +stream.on('data', (entry) => { + console.log('[stream:data]', entry.path); + + try { + watcher.emitAdd(entry.fullPath, entry.stats); + } catch (error) { + console.log('[stream emitAdd throw]', error?.name, error?.message); + if (error?.stack) console.log(error.stack); + } +}); +stream.on('error', (error) => { + console.log('[stream:error]', error?.name, error?.message); + if (error?.stack) console.log(error.stack); +}); +stream.on('end', () => { + console.log('[stream:end]'); +}); + +setTimeout(() => { + try { + fs.appendFileSync(probeFile, 'update\n'); + console.log('updated probe file', probeFile); + } catch (error) { + console.log('[appendFileSync throw]', error?.name, error?.message); + if (error?.stack) console.log(error.stack); + } +}, 250); + +await new Promise((resolve) => setTimeout(resolve, 1500)); +await stop(); +console.log('stopped'); diff --git a/tests/repro_vite_startup_watcher_bug.mjs b/tests/repro_vite_startup_watcher_bug.mjs new file mode 100644 index 00000000..cdde0690 --- /dev/null +++ b/tests/repro_vite_startup_watcher_bug.mjs @@ -0,0 +1,25 @@ +// Repro: Vite dev server startup triggers watcher-side +// `TypeError: undefined is not a function` inside chokidar/fsevents. +// +// Run with: +// ant tests/repro_vite_startup_watcher_bug.mjs + +import * as vite from '/Users/themackabu/.ant/pkg/exec/vite/node_modules/vite/dist/node/index.js'; + +process.on('unhandledRejection', (reason) => { + console.log('[unhandledRejection]', reason?.name, reason?.message); + if (reason?.stack) console.log(reason.stack); +}); + +const server = await vite.createServer({ + configFile: false, + root: process.cwd(), +}); + +await server.listen(); +console.log('listening'); + +setTimeout(async () => { + console.log('done wait'); + await server.close(); +}, 1500); diff --git a/tests/repro_vite_watcher_add_bug.mjs b/tests/repro_vite_watcher_add_bug.mjs new file mode 100644 index 00000000..6c2be5fd --- /dev/null +++ b/tests/repro_vite_watcher_add_bug.mjs @@ -0,0 +1,32 @@ +// Repro: Vite's chokidar watcher path triggers +// `TypeError: undefined is not a function` without needing full server startup. +// +// Run with: +// ant tests/repro_vite_watcher_add_bug.mjs + +import * as vite from '/Users/themackabu/.ant/pkg/exec/vite/node_modules/vite/dist/node/index.js'; + +process.on('unhandledRejection', (reason) => { + console.log('[unhandledRejection]', reason?.name, reason?.message); + if (reason?.stack) console.log(reason.stack); +}); + +const server = await vite.createServer({ + configFile: false, + root: process.cwd(), + optimizeDeps: { noDiscovery: true, entries: [] }, +}); + +server.watcher.add([ + '.env.local', + '.env.development', + '.env.development.local', + '.definitely-missing', +]); + +console.log('watcher.add issued'); + +setTimeout(async () => { + console.log('done wait'); + await server.close(); +}, 1500); diff --git a/tests/test_wasm_webassembly_api.mjs b/tests/test_wasm_webassembly_api.mjs new file mode 100644 index 00000000..d2008523 --- /dev/null +++ b/tests/test_wasm_webassembly_api.mjs @@ -0,0 +1,75 @@ +import { readFileSync } from 'ant:fs'; + +function assert(condition, message) { + if (!condition) throw new Error(message); +} + +function fixture(path) { + return readFileSync(import.meta.dirname + '/../' + path); +} + +const api = globalThis.WebAssembly; + +assert(api && typeof api === 'object', 'globalThis.WebAssembly should exist'); + +for (const name of [ + 'Global', + 'Instance', + 'Memory', + 'Module', + 'Table', + 'Tag', + 'Exception', + 'CompileError', + 'LinkError', + 'RuntimeError', +]) { + assert(typeof api[name] === 'function', `WebAssembly.${name} should exist`); +} + +const incrementer = fixture('wpt/wasm/webapi/resources/incrementer.wasm'); + +assert(WebAssembly.validate(incrementer) === true, 'incrementer.wasm should validate'); + +const module = new WebAssembly.Module(incrementer); +const descriptors = WebAssembly.Module.exports(module); +assert(Array.isArray(descriptors), 'WebAssembly.Module.exports() should return an array'); +assert( + descriptors.some(entry => entry && entry.name === 'increment' && entry.kind === 'function'), + 'incrementer.wasm should export increment()', +); + +const instance = new WebAssembly.Instance(module); +assert(typeof instance.exports.increment === 'function', 'instance.exports.increment should exist'); +assert(instance.exports.increment(41) === 42, 'increment(41) should return 42'); + +const compiled = await WebAssembly.compile(incrementer); +assert(compiled instanceof WebAssembly.Module, 'WebAssembly.compile() should resolve a module'); + +const instantiated = await WebAssembly.instantiate(incrementer); +assert(instantiated.module instanceof WebAssembly.Module, 'instantiate(bytes) should return a module'); +assert(instantiated.instance instanceof WebAssembly.Instance, 'instantiate(bytes) should return an instance'); +assert(instantiated.instance.exports.increment(9) === 10, 'instantiate(bytes) should wire exports'); + +const global = new WebAssembly.Global({ value: 'i32', mutable: true }, 7); +assert(global.value === 7, 'WebAssembly.Global should expose its initial value'); +global.value = 11; +assert(global.value === 11, 'WebAssembly.Global should accept writes'); +assert(global.valueOf() === 11, 'WebAssembly.Global.prototype.valueOf() should read the value'); + +const invalid = new Uint8Array([0x00, 0x61, 0x62, 0x63]); +assert(WebAssembly.validate(invalid) === false, 'invalid wasm bytes should fail validation'); + +let sawCompileError = false; +try { + new WebAssembly.Module(invalid); +} catch (error) { + sawCompileError = true; + assert( + error instanceof WebAssembly.CompileError || error?.name === 'CompileError', + 'invalid module should throw CompileError', + ); +} +assert(sawCompileError, 'invalid module construction should fail'); + +console.log('wasm:webassembly-api:ok'); diff --git a/tests/tmp_bind_async_test.mjs b/tests/tmp_bind_async_test.mjs new file mode 100644 index 00000000..4b0ad599 --- /dev/null +++ b/tests/tmp_bind_async_test.mjs @@ -0,0 +1,34 @@ +import net from 'node:net'; + +// replicate exactly what vite does +const server = net.createServer(); +const origListen = server.listen.bind(server); + +console.log('server type:', typeof server); +console.log('origListen type:', typeof origListen); + +server.listen = async (port, ...args) => { + console.log('async wrapper called, port=', port, 'args=', args); + try { + await Promise.resolve(); // simulate initServer + console.log('after await, calling origListen...'); + return origListen(port, ...args); + } catch (e) { + server.emit('error', e); + return; + } +}; + +await new Promise((resolve, reject) => { + server.on('error', (e) => { + console.log('error event:', e.message); + reject(e); + }); + server.on('listening', () => { + console.log('listening on', server.address()); + server.close(resolve); + }); + server.listen(0, '127.0.0.1'); +}); + +console.log('done'); diff --git a/tests/tmp_ipv6_bind_test.mjs b/tests/tmp_ipv6_bind_test.mjs new file mode 100644 index 00000000..9ec07a64 --- /dev/null +++ b/tests/tmp_ipv6_bind_test.mjs @@ -0,0 +1,26 @@ +import net from 'node:net'; + +function tryListen(port, host) { + return new Promise((resolve) => { + const server = net.createServer(); + server.once('error', (e) => { + console.log(` error on ${host}:${port} — code=${e.code} message=${e.message}`); + server.close(() => resolve({ ok: false, code: e.code })); + }); + server.once('listening', () => { + const addr = server.address(); + console.log(` listening on ${JSON.stringify(addr)}`); + server.close(() => resolve({ ok: true })); + }); + server.listen(port, host); + }); +} + +const hosts = ['0.0.0.0', '::', '0000:0000:0000:0000:0000:0000:0000:0000']; +for (const host of hosts) { + process.stdout.write(`tryListen(9874, '${host}') ... `); + const result = await tryListen(9874, host); + console.log(result.ok ? 'ok' : `fail(${result.code})`); +} + +console.log('done'); diff --git a/tests/tmp_vite_fs_trace.mjs b/tests/tmp_vite_fs_trace.mjs new file mode 100644 index 00000000..ee603e1d --- /dev/null +++ b/tests/tmp_vite_fs_trace.mjs @@ -0,0 +1,30 @@ +import fs from 'node:fs'; + +for (const name of ['access', 'readFile', 'readdir', 'realpath', 'rm', 'stat']) { + const original = fs.promises?.[name]; + if (typeof original !== 'function') continue; + fs.promises[name] = async function (...args) { + try { + return await original.apply(this, args); + } catch (error) { + console.log(`fs.promises.${name}`, args[0], error?.name, error?.message); + throw error; + } + }; +} + +process.on('unhandledRejection', (reason) => { + console.log('unhandledRejection', reason?.name, reason?.message); + if (reason?.stack) console.log(reason.stack); +}); + +const vite = await import('/Users/themackabu/.ant/pkg/exec/vite/node_modules/vite/dist/node/index.js'); +const server = await vite.createServer({ configFile: false, root: process.cwd() }); + +try { + await server.listen(); + console.log('listen ok'); +} catch (error) { + console.log('listen', error?.name, error?.message); + if (error?.stack) console.log(error.stack); +} diff --git a/tests/tmp_vite_initserver_trace.mjs b/tests/tmp_vite_initserver_trace.mjs new file mode 100644 index 00000000..4ff2d3af --- /dev/null +++ b/tests/tmp_vite_initserver_trace.mjs @@ -0,0 +1,61 @@ +const vite = await import('/Users/themackabu/.ant/pkg/exec/vite/node_modules/vite/dist/node/index.js'); + +async function run(label, fn) { + try { + const value = await fn(); + console.log(label, 'ok', typeof value); + return value; + } catch (error) { + console.log(label, error?.name, error?.message); + if (error?.stack) console.log(error.stack); + return null; + } +} + +const config = await run('resolveConfig', () => + vite.resolveConfig({ configFile: false, root: process.cwd() }, 'serve') +); +if (!config) process.exit(1); + +const server = await run('createServer', () => + vite.createServer({ configFile: false, root: process.cwd() }) +); +if (!server) process.exit(1); + +// call each piece of initServer manually in the same order Vite does, +// so we can see which one hangs +console.log('\n-- manual initServer sequence --'); + +console.log('calling buildStart...'); +await run('buildStart', () => + server.environments.client.pluginContainer.buildStart() +); + +console.log('calling client.listen...'); +await run('client.listen', () => + server.environments.client.listen(server) +); + +console.log('calling ssr.listen...'); +await run('ssr.listen', () => + server.environments.ssr.listen(server) +); + +console.log('\n-- second pass (simulates initServer re-run) --'); + +console.log('calling buildStart (2nd)...'); +await run('buildStart2', () => + server.environments.client.pluginContainer.buildStart() +); + +console.log('calling client.listen (2nd)...'); +await run('client.listen2', () => + server.environments.client.listen(server) +); + +console.log('calling ssr.listen (2nd)...'); +await run('ssr.listen2', () => + server.environments.ssr.listen(server) +); + +console.log('\ndone'); diff --git a/tests/tmp_vite_listen_trace.mjs b/tests/tmp_vite_listen_trace.mjs new file mode 100644 index 00000000..82d57b05 --- /dev/null +++ b/tests/tmp_vite_listen_trace.mjs @@ -0,0 +1,77 @@ +import net from 'node:net'; +import http from 'node:http'; +import { promises as dns } from 'node:dns'; + +const wildcardHosts = new Set(['0.0.0.0', '::', '0000:0000:0000:0000:0000:0000:0000:0000']); + +function tryListen(port, host) { + return new Promise((resolve) => { + const server = net.createServer(); + server.once('error', (e) => { + server.close(() => resolve({ ok: false, code: e.code })); + }); + server.once('listening', () => { + server.close(() => resolve({ ok: true })); + }); + server.listen(port, host); + }); +} + +async function isPortAvailable(port) { + for (const host of wildcardHosts) { + console.log(` isPortAvailable: tryListen(${port}, '${host}')`); + const r = await tryListen(port, host).catch(() => ({ ok: true })); + console.log(` isPortAvailable: tryListen(${port}, '${host}') => ${JSON.stringify(r)}`); + if (!r.ok) return false; + } + return true; +} + +// step 1: dns.promises.lookup (resolveHostname) +console.log('step 1: dns.promises.lookup'); +const [a, b] = await Promise.all([ + dns.lookup('localhost'), + dns.lookup('localhost', { verbatim: true }), +]); +console.log('lookup results:', a, b); + +// step 2: isPortAvailable +console.log('\nstep 2: isPortAvailable(5173)'); +const avail = await isPortAvailable(5173); +console.log('isPortAvailable =>', avail); + +// step 3: tryBindServer via real http.createServer + listen +console.log('\nstep 3: tryBindServer'); +const httpServer = http.createServer((req, res) => res.end('ok')); + +// mimic Vite's listen wrapper +const origListen = httpServer.listen.bind(httpServer); +httpServer.listen = async (port, ...args) => { + console.log(' wrapped listen called, port=', port); + return origListen(port, ...args); +}; + +const bindResult = await new Promise((resolve) => { + const onError = (e) => { + httpServer.off('error', onError); + httpServer.off('listening', onListening); + resolve({ success: false, error: e }); + }; + const onListening = () => { + httpServer.off('error', onError); + httpServer.off('listening', onListening); + resolve({ success: true }); + }; + httpServer.on('error', onError); + httpServer.on('listening', onListening); + httpServer.listen(5173, 'localhost'); +}); + +console.log('tryBindServer result:', bindResult.success ? 'success' : `fail: ${bindResult.error?.message}`); +if (bindResult.success) { + console.log('address:', httpServer.address()); + await new Promise((resolve) => httpServer.close(resolve)); + console.log('server closed'); +} + +console.log('\ndone'); diff --git a/tests/tmp_vite_server_trace.mjs b/tests/tmp_vite_server_trace.mjs new file mode 100644 index 00000000..3dc02552 --- /dev/null +++ b/tests/tmp_vite_server_trace.mjs @@ -0,0 +1,47 @@ +const vite = await import('/Users/themackabu/.ant/pkg/exec/vite/node_modules/vite/dist/node/index.js'); + +async function run(label, fn) { + try { + const value = await fn(); + console.log(label, 'ok', typeof value); + return value; + } catch (error) { + console.log(label, error?.name, error?.message); + if (error?.stack) console.log(error.stack); + return null; + } +} + +const config = await run('resolveConfig', () => + vite.resolveConfig({ configFile: false, root: process.cwd() }, 'serve') +); + +if (config) { + const server = await run('createServer', () => + vite.createServer({ configFile: false, root: process.cwd() }) + ); + + if (server) { + const httpServer = server.httpServer; + + // Patch origListen (Vite's async wrapper) to catch the inner rejection + const viteAsyncWrapper = httpServer.listen; + httpServer.listen = function(...args) { + console.log('[trace] httpServer.listen called, port=', args[0], 'host=', args[1]); + const p = viteAsyncWrapper.apply(this, args); + if (p && typeof p.then === 'function') { + p.then( + () => console.log('[trace] async wrapper resolved'), + (e) => console.log('[trace] async wrapper rejected:', e?.message) + ); + } + return p; + }; + + await run('server.listen', async () => { + await server.listen(); + await server.close(); + return server; + }); + } +} diff --git a/tests/tmp_vite_trace.mjs b/tests/tmp_vite_trace.mjs new file mode 100644 index 00000000..65312f23 --- /dev/null +++ b/tests/tmp_vite_trace.mjs @@ -0,0 +1,55 @@ +const vite = await import('/Users/themackabu/.ant/pkg/exec/vite/node_modules/vite/dist/node/index.js'); +const chunk = await import('/Users/themackabu/.ant/pkg/exec/vite/node_modules/vite/dist/node/chunks/node.js'); +const config = await vite.resolveConfig({ configFile: false, root: process.cwd() }, 'serve'); +const env = new vite.DevEnvironment('client', config, { + hot: true, + transport: vite.createServerHotChannel(), + disableDepsOptimizer: true +}); + +function tryStringify(label, value) { + try { + const out = JSON.stringify(value, (_, item) => { + if (typeof item === 'function' || item instanceof RegExp) return item.toString(); + return item; + }); + console.log(label, 'ok', typeof out, out?.length ?? 0); + } catch (error) { + console.log(label, error?.name, error?.message); + } +} + +tryStringify('env.config.resolve', env.config.resolve); +tryStringify('env.config.assetsInclude', env.config.assetsInclude); +tryStringify('env.config.plugins', env.config.plugins.map((p) => p.name)); +tryStringify('env.config.optimizeDeps.include', env.config.optimizeDeps.include); +tryStringify('env config-hash-shape', { + define: !env.config.keepProcessEnv ? process.env.NODE_ENV || env.config.mode : null, + root: env.config.root, + resolve: env.config.resolve, + assetsInclude: env.config.assetsInclude, + plugins: env.config.plugins.map((p) => p.name), + optimizeDeps: { + include: env.config.optimizeDeps.include, + exclude: env.config.optimizeDeps.exclude, + rolldownOptions: { + ...env.config.optimizeDeps.rolldownOptions, + plugins: undefined, + onLog: undefined, + onwarn: undefined, + checks: undefined, + output: { + ...env.config.optimizeDeps.rolldownOptions?.output, + plugins: undefined + } + } + }, + optimizeDepsPluginNames: env.config.optimizeDepsPluginNames +}); + +try { + const metadata = chunk.at(env, String(Date.now())); + console.log('initDepsOptimizerMetadata ok', typeof metadata); +} catch (error) { + console.log('initDepsOptimizerMetadata', error?.name, error?.message); +} diff --git a/tests/todo_rsc_action_rsc_post.mjs b/tests/todo_rsc_action_rsc_post.mjs new file mode 100644 index 00000000..12ebe762 --- /dev/null +++ b/tests/todo_rsc_action_rsc_post.mjs @@ -0,0 +1,23 @@ +function assert(cond, msg) { + if (!cond) throw new Error(msg); +} + +const { default: handler } = await import('../todo/rsc/dist/rsc/index.js'); + +const response = await handler.fetch( + new Request('http://localhost/_.rsc', { + method: 'POST', + headers: { + 'x-rsc-action': '710363d987f5#updateServerCounter', + }, + body: '[1]', + }), +); + +console.log(`status:${response.status}`); +console.log(`content-type:${response.headers.get('content-type') || 'missing'}`); + +assert( + response.headers.get('content-type') === 'text/x-component;charset=utf-8', + 'expected RSC action response content-type' +); diff --git a/tests/todo_rsc_form_action_markup.mjs b/tests/todo_rsc_form_action_markup.mjs new file mode 100644 index 00000000..e5da552e --- /dev/null +++ b/tests/todo_rsc_form_action_markup.mjs @@ -0,0 +1,47 @@ +function assert(cond, msg) { + if (!cond) throw new Error(msg); +} + +async function readUntil(response, marker, limit = 32768) { + const stream = response.body; + assert(stream, 'expected response body stream'); + + const reader = stream.getReader(); + const decoder = new TextDecoder(); + let text = ''; + + while (text.length < limit) { + const chunk = await reader.read(); + if (chunk.done) break; + text += decoder.decode(chunk.value, { stream: true }); + if (text.includes(marker)) break; + } + + text += decoder.decode(); + return text; +} + +const mod = await import('../todo/rsc/dist/rsc/index.js'); +const handler = mod.default; + +assert(handler && typeof handler.fetch === 'function', 'expected todo/rsc handler.fetch'); + +const response = await handler.fetch(new Request('http://localhost/')); +assert(response.status === 200, `expected status 200, got ${response.status}`); + +const html = await readUntil(response, ''); +const formStart = html.indexOf('', formStart); +assert(formEnd !== -1, 'expected form closing tag'); + +const snippet = html.slice(formStart, formEnd + 7); +console.log(snippet); + +assert( + snippet.includes('$ACTION_') || + snippet.includes('javascript:throw new Error') || + snippet.includes('formAction'), + 'expected server action metadata or replay marker in form markup', +); diff --git a/vendor/packagefiles/wasm-micro-runtime/meson.build b/vendor/packagefiles/wasm-micro-runtime/meson.build new file mode 100644 index 00000000..3188f2b5 --- /dev/null +++ b/vendor/packagefiles/wasm-micro-runtime/meson.build @@ -0,0 +1,169 @@ +project('wasm-micro-runtime', 'c', default_options: ['c_std=gnu11', 'warning_level=0']) + +cc = meson.get_compiler('c') + +if host_machine.system() == 'windows' + wamr_platform = 'windows' +elif host_machine.system() == 'darwin' + wamr_platform = 'darwin' +else + wamr_platform = 'linux' +endif + +common_c_args = [ + '-DNDEBUG', + '-DBH_MALLOC=wasm_runtime_malloc', + '-DBH_FREE=wasm_runtime_free', + '-DWASM_ENABLE_INTERP=1', + '-DWASM_ENABLE_FAST_INTERP=0', + '-DWASM_ENABLE_AOT=0', + '-DWASM_ENABLE_JIT=0', + '-DWASM_ENABLE_FAST_JIT=0', + '-DWASM_ENABLE_LIBC_BUILTIN=0', + '-DWASM_ENABLE_LIBC_WASI=1', + '-DWASM_ENABLE_MULTI_MODULE=0', + '-DWASM_ENABLE_BULK_MEMORY=1', + '-DWASM_ENABLE_BULK_MEMORY_OPT=1', + '-DWASM_ENABLE_SHARED_MEMORY=0', + '-DWASM_ENABLE_REF_TYPES=1', + '-DWASM_ENABLE_CALL_INDIRECT_OVERLONG=1', + '-DWASM_ENABLE_MINI_LOADER=0', + '-DWASM_DISABLE_HW_BOUND_CHECK=1', + '-DWASM_DISABLE_STACK_HW_BOUND_CHECK=1', + '-DWASM_DISABLE_WAKEUP_BLOCKING_OP=0', + '-DWASM_ENABLE_SIMD=0', + '-DWASM_ENABLE_MODULE_INST_CONTEXT=1', + '-DWASM_GLOBAL_HEAP_SIZE=' + (10 * 1024 * 1024).to_string(), +] + +if wamr_platform == 'windows' + common_c_args += ['-DBH_PLATFORM_WINDOWS', '-DWASM_HAVE_MREMAP=0'] +elif wamr_platform == 'darwin' + common_c_args += ['-DBH_PLATFORM_DARWIN', '-DWASM_HAVE_MREMAP=0'] +else + common_c_args += ['-DBH_PLATFORM_LINUX', '-DWASM_HAVE_MREMAP=1'] +endif + +if host_machine.cpu_family() == 'aarch64' + common_c_args += ['-DBUILD_TARGET_AARCH64', '-DBUILD_TARGET=AARCH64'] +elif host_machine.cpu_family() == 'x86_64' + common_c_args += ['-DBUILD_TARGET_X86_64', '-DBUILD_TARGET=X86_64'] +else + error('Unsupported WAMR target: ' + host_machine.cpu_family()) +endif + +wamr_inc = include_directories( + '.', + 'core', + 'core/iwasm/include', + 'core/iwasm/common', + 'core/iwasm/interpreter', + 'core/iwasm/libraries/libc-wasi', + 'core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/include', + 'core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src', + 'core/shared/mem-alloc', + 'core/shared/utils', + 'core/shared/platform/' + wamr_platform, + 'core/shared/platform/include', + 'core/shared/platform/common/libc-util', + 'core/shared/platform/common/memory', + 'core/shared/platform/common/posix', +) + +wamr_sources = files( + 'core/shared/platform/' + wamr_platform + '/platform_init.c', + 'core/shared/platform/common/libc-util/libc_errno.c', + 'core/shared/platform/common/memory/mremap.c', + 'core/shared/platform/common/posix/posix_blocking_op.c', + 'core/shared/platform/common/posix/posix_clock.c', + 'core/shared/platform/common/posix/posix_malloc.c', + 'core/shared/platform/common/posix/posix_memmap.c', + 'core/shared/platform/common/posix/posix_sleep.c', + 'core/shared/platform/common/posix/posix_thread.c', + 'core/shared/platform/common/posix/posix_time.c', + 'core/shared/utils/bh_assert.c', + 'core/shared/utils/bh_bitmap.c', + 'core/shared/utils/bh_common.c', + 'core/shared/utils/bh_hashmap.c', + 'core/shared/utils/bh_leb128.c', + 'core/shared/utils/bh_list.c', + 'core/shared/utils/bh_log.c', + 'core/shared/utils/bh_queue.c', + 'core/shared/utils/bh_vector.c', + 'core/shared/utils/runtime_timer.c', + 'core/shared/mem-alloc/mem_alloc.c', + 'core/shared/mem-alloc/ems/ems_alloc.c', + 'core/shared/mem-alloc/ems/ems_gc.c', + 'core/shared/mem-alloc/ems/ems_hmu.c', + 'core/shared/mem-alloc/ems/ems_kfc.c', + 'core/iwasm/common/wasm_application.c', + 'core/iwasm/common/wasm_blocking_op.c', + 'core/iwasm/common/wasm_c_api.c', + 'core/iwasm/common/wasm_exec_env.c', + 'core/iwasm/common/wasm_loader_common.c', + 'core/iwasm/common/wasm_memory.c', + 'core/iwasm/common/wasm_native.c', + 'core/iwasm/common/wasm_runtime_common.c', + 'core/iwasm/common/wasm_shared_memory.c', + 'core/iwasm/interpreter/wasm_loader.c', + 'core/iwasm/interpreter/wasm_runtime.c', + 'core/iwasm/interpreter/wasm_interp_classic.c', + 'core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c', + 'core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/posix.c', + 'core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/str.c', + 'core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/random.c', + 'core/iwasm/libraries/libc-wasi/sandboxed-system-primitives/src/blocking_op.c', +) + +if host_machine.cpu_family() == 'aarch64' + if wamr_platform == 'darwin' + wamr_sources += files('core/iwasm/common/arch/invokeNative_aarch64.s') + else + wamr_sources += files('core/iwasm/common/arch/invokeNative_aarch64.s') + endif +elif host_machine.cpu_family() == 'x86_64' + wamr_sources += files('core/iwasm/common/arch/invokeNative_em64.s') +else + wamr_sources += files('core/iwasm/common/arch/invokeNative_general.c') +endif + +if wamr_platform == 'windows' + wamr_sources += files( + 'core/shared/platform/windows/win_file.c', + 'core/shared/platform/windows/win_socket.c', + ) +else + wamr_sources += files( + 'core/shared/platform/common/posix/posix_file.c', + 'core/shared/platform/common/posix/posix_socket.c', + ) +endif + +wamr_lib = static_library( + 'wamr', + wamr_sources, + include_directories: wamr_inc, + c_args: common_c_args, +) + +wamr_dep = declare_dependency( + link_with: wamr_lib, + include_directories: wamr_inc, + compile_args: [ + '-DWASM_ENABLE_INTERP=1', + '-DWASM_ENABLE_LIBC_WASI=1', + '-DWASM_ENABLE_MODULE_INST_CONTEXT=1', + '-DWASM_ENABLE_BULK_MEMORY=1', + '-DWASM_ENABLE_REF_TYPES=1', + '-DWASM_ENABLE_SHARED_MEMORY=0', + '-DWASM_ENABLE_SIMD=0', + '-DWASM_ENABLE_AOT=0', + '-DWASM_ENABLE_MULTI_MODULE=0', + '-DWASM_ENABLE_TAGS=0', + '-DWASM_CONFIGURABLE_BOUNDS_CHECKS=0', + ], + dependencies: [ + cc.find_library('m', required: true), + dependency('threads'), + ], +) diff --git a/vendor/wasm-micro-runtime.wrap b/vendor/wasm-micro-runtime.wrap new file mode 100644 index 00000000..37c197ba --- /dev/null +++ b/vendor/wasm-micro-runtime.wrap @@ -0,0 +1,8 @@ +[wrap-git] +url = https://github.com/bytecodealliance/wasm-micro-runtime.git +revision = 92f40918bbfad35546a1512b10bd25eaa31add4d +depth = 1 +patch_directory = wasm-micro-runtime + +[provide] +wasm-micro-runtime = wamr_dep