From 9b3891c126764790c81e187880fbb0d562854a80 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 19 Jan 2026 16:01:39 -0600 Subject: [PATCH] rm spreads and iterators --- internal/engine.cm | 20 +- internal/shop.cm | 41 +- source/quickjs-opcode.h | 8 - source/quickjs.c | 1959 ++------------------------------------- tests/suite.cm | 32 - 5 files changed, 100 insertions(+), 1960 deletions(-) diff --git a/internal/engine.cm b/internal/engine.cm index e539d440..0f72c725 100644 --- a/internal/engine.cm +++ b/internal/engine.cm @@ -788,20 +788,22 @@ $_.clock(_ => { var file_info = shop.file_info ? shop.file_info(locator.path) : null var inject = shop.script_inject_for ? shop.script_inject_for(file_info) : [] - // Build values array for injection - var vals = array(inject, key => { - if (key && key[0] == '$') key = text(key,1) - if (key == 'fd') return fd - return $_[key] - }) + // Build env object for injection + var env = {} + for (var i = 0; i < length(inject); i++) { + var key = inject[i] + if (key && key[0] == '$') key = text(key, 1) + if (key == 'fd') env[key] = fd + else env[key] = $_[key] + } // Create use function bound to the program's package var pkg = file_info ? file_info.package : null var use_fn = function(path) { return shop.use(path, pkg) } - // Call with signature: setup_module(args, use, ..capabilities) - // The script wrapper builds $_ from the injected capabilities for backward compatibility - var val = call(locator.symbol, null, _cell.args.arg, use_fn, ...vals) + // Call with signature: setup_module(args, use, env) + // The script wrapper binds $delay, $start, etc. from env + var val = call(locator.symbol, null, _cell.args.arg, use_fn, env) if (val) throw Error('Program must not return anything'); diff --git a/internal/shop.cm b/internal/shop.cm index 0d3af9b6..bb8b0f72 100644 --- a/internal/shop.cm +++ b/internal/shop.cm @@ -376,17 +376,25 @@ Shop.get_script_capabilities = function(path) { return Shop.script_inject_for(file_info) } -function inject_params(inject) { - if (!inject || !length(inject)) return '' - return ', ' + text(inject, ', ') +function inject_env(inject) { + var env = {} + for (var i = 0; i < length(inject); i++) { + var inj = inject[i] + var key = trim(inj, '$') + if (key == 'fd') env[key] = fd + else env[key] = my$_[key] + } + return env } -function inject_values(inject) { - return array(inject, function(inj) { +function inject_bindings_code(inject) { + var lines = [] + for (var i = 0; i < length(inject); i++) { + var inj = inject[i] var key = trim(inj, '$') - if (key == 'fd') return fd - return my$_[key] - }) + lines.push(`var $${key} = env["${key}"];`) + } + return text(lines, '\n') } // Build the use function for a specific package context @@ -397,9 +405,14 @@ function make_use_fn_code(pkg_arg) { // for script forms, path is the canonical path of the module var script_form = function(path, script, pkg, inject) { var pkg_arg = pkg ? `'${pkg}'` : 'null' - var params = inject_params(inject) - - var fn = `(function setup_module(args, use${params}){ def arg = args; def PACKAGE = ${pkg_arg}; ${script}})` + var binds = inject_bindings_code(inject) + + var fn = `(function setup_module(args, use, env){ +def arg = args; +def PACKAGE = ${pkg_arg}; +${binds} +${script} +})` return fn } @@ -791,13 +804,13 @@ function execute_module(info) // Get file info to determine inject list var file_info = Shop.file_info(mod_resolve.path) var inject = Shop.script_inject_for(file_info) - var vals = inject_values(inject) + var env = inject_env(inject) var pkg = file_info.package var use_fn = make_use_fn(pkg) - // Call with signature: setup_module(args, use, ..capabilities) + // Call with signature: setup_module(args, use, env) // args is null for module loading - used = call(mod_resolve.symbol, context, null, use_fn, ...vals) + used = call(mod_resolve.symbol, context, null, use_fn, env) } else if (c_resolve.scope < 900) { // C only used = call_c_module(c_resolve) diff --git a/source/quickjs-opcode.h b/source/quickjs-opcode.h index 78137978..612fd9de 100644 --- a/source/quickjs-opcode.h +++ b/source/quickjs-opcode.h @@ -138,7 +138,6 @@ DEF( set_name, 5, 1, 1, atom) DEF(set_name_computed, 1, 2, 2, none) DEF( set_proto, 1, 2, 1, none) DEF(define_array_el, 1, 3, 2, none) -DEF( append, 1, 3, 2, none) /* append enumerated object, update length */ DEF(copy_data_properties, 2, 3, 3, u8) DEF( define_method, 6, 2, 1, atom_u8) DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */ @@ -181,14 +180,7 @@ DEF(make_var_ref_ref, 7, 0, 2, atom_u16) DEF( make_var_ref, 5, 0, 2, atom) DEF( for_in_start, 1, 1, 1, none) -DEF( for_of_start, 1, 1, 3, none) DEF( for_in_next, 1, 1, 3, none) -DEF( for_of_next, 2, 3, 5, u8) -DEF(iterator_check_object, 1, 1, 1, none) -DEF(iterator_get_value_done, 1, 2, 3, none) /* catch_offset obj -> catch_offset value done */ -DEF( iterator_close, 1, 3, 0, none) -DEF( iterator_next, 1, 4, 4, none) -DEF( iterator_call, 2, 4, 5, u8) /* arithmetic/logic operations */ DEF( neg, 1, 1, 1, none) diff --git a/source/quickjs.c b/source/quickjs.c index 51823c02..0c16de29 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -170,9 +170,6 @@ enum { JS_CLASS_C_FUNCTION_DATA, /* u.c_function_data_record */ JS_CLASS_FOR_IN_ITERATOR, /* u.for_in_iterator */ JS_CLASS_REGEXP, /* u.regexp */ - JS_CLASS_ARRAY_ITERATOR, /* u.array_iterator_data */ - JS_CLASS_STRING_ITERATOR, /* u.array_iterator_data */ - JS_CLASS_REGEXP_STRING_ITERATOR, /* u.regexp_string_iterator_data */ JS_CLASS_FINALIZATION_REGISTRY, JS_CLASS_BLOB, /* u.opaque (blob *) */ @@ -424,7 +421,6 @@ struct JSContext { JSValue array_ctor; JSValue regexp_ctor; JSValue native_error_proto[JS_NATIVE_ERROR_COUNT]; - JSValue iterator_proto; JSValue array_proto_values; JSValue throw_type_error; JSValue eval_obj; @@ -686,12 +682,6 @@ typedef struct JSBoundFunction { JSValue argv[0]; } JSBoundFunction; -typedef enum JSIteratorKindEnum { - JS_ITERATOR_KIND_KEY, - JS_ITERATOR_KIND_VALUE, - JS_ITERATOR_KIND_KEY_AND_VALUE, -} JSIteratorKindEnum; - typedef struct JSForInIterator { JSValue obj; uint32_t idx; @@ -701,6 +691,13 @@ typedef struct JSForInIterator { JSPropertyEnum *tab_atom; /* is_array = FALSE */ } JSForInIterator; +/* Used by js_object_keys and related functions */ +typedef enum JSIteratorKindEnum { + JS_ITERATOR_KIND_KEY, + JS_ITERATOR_KIND_VALUE, + JS_ITERATOR_KIND_KEY_AND_VALUE, +} JSIteratorKindEnum; + typedef struct JSRegExp { JSString *pattern; JSString *bytecode; /* also contains the flags */ @@ -827,8 +824,6 @@ struct JSObject { struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */ struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */ struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */ - struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */ - struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */ struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */ struct JSFunctionBytecode *function_bytecode; JSVarRef **var_refs; @@ -959,13 +954,6 @@ static void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); static void js_regexp_finalizer(JSRuntime *rt, JSValue val); -static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val); -static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); -static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val); -static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func); - #define HINT_STRING 0 #define HINT_NUMBER 1 #define HINT_NONE 2 @@ -1254,9 +1242,6 @@ static JSClassShortDef const js_std_class_def[] = { { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */ { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark }, /* JS_CLASS_FOR_IN_ITERATOR */ { JS_ATOM_RegExp, js_regexp_finalizer, NULL }, /* JS_CLASS_REGEXP */ - { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */ - { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */ - { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */ }; static int init_class_range(JSRuntime *rt, JSClassShortDef const *tab, @@ -1965,7 +1950,6 @@ static void JS_MarkContext(JSRuntime *rt, JSContext *ctx, for(i = 0; i < rt->class_count; i++) { JS_MarkValue(rt, ctx->class_proto[i], mark_func); } - JS_MarkValue(rt, ctx->iterator_proto, mark_func); JS_MarkValue(rt, ctx->array_ctor, mark_func); JS_MarkValue(rt, ctx->regexp_ctor, mark_func); JS_MarkValue(rt, ctx->function_ctor, mark_func); @@ -2025,7 +2009,6 @@ void JS_FreeContext(JSContext *ctx) JS_FreeValue(ctx, ctx->class_proto[i]); } js_free_rt(rt, ctx->class_proto); - JS_FreeValue(ctx, ctx->iterator_proto); JS_FreeValue(ctx, ctx->array_ctor); JS_FreeValue(ctx, ctx->regexp_ctor); JS_FreeValue(ctx, ctx->function_ctor); @@ -5972,11 +5955,6 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) } } break; - case JS_CLASS_REGEXP: /* u.regexp */ - compute_jsstring_size(p->u.regexp.pattern, hp); - compute_jsstring_size(p->u.regexp.bytecode, hp); - break; - case JS_CLASS_FOR_IN_ITERATOR: /* u.for_in_iterator */ { JSForInIterator *it = p->u.for_in_iterator; @@ -5987,9 +5965,10 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s) } } break; - case JS_CLASS_ARRAY_ITERATOR: /* u.array_iterator_data */ - case JS_CLASS_STRING_ITERATOR: /* u.array_iterator_data */ - /* TODO */ + case JS_CLASS_REGEXP: /* u.regexp */ + compute_jsstring_size(p->u.regexp.pattern, hp); + compute_jsstring_size(p->u.regexp.bytecode, hp); + break; default: /* XXX: class definition should have an opaque block size */ if (p->u.opaque) { @@ -6369,9 +6348,7 @@ static const char *get_func_name(JSContext *ctx, JSValueConst func) val = pr->u.value; if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING) return NULL; - -// char *buf = js_malloc(ctx->rt, 128); -// return JS_AtomGetStr(ctx, buf, 128, prs->atom); + return JS_ToCString(ctx, val); } #define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0) @@ -11787,273 +11764,6 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) return 0; } -static JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj, - JSValueConst method) -{ - JSValue enum_obj; - - enum_obj = JS_Call(ctx, method, obj, 0, NULL); - if (JS_IsException(enum_obj)) - return enum_obj; - if (!JS_IsObject(enum_obj)) { - JS_FreeValue(ctx, enum_obj); - return JS_ThrowTypeErrorNotAnObject(ctx); - } - return enum_obj; -} - -static JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj) -{ - JSValue method, ret; - - method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator); - if (JS_IsException(method)) - return method; - - if (!JS_IsFunction(ctx, method)) { - JS_FreeValue(ctx, method); - return JS_ThrowTypeError(ctx, "value is not iterable"); - } - ret = JS_GetIterator2(ctx, obj, method); - JS_FreeValue(ctx, method); - return ret; -} - -/* return *pdone = 2 if the iterator object is not parsed */ -static JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj, - JSValueConst method, - int argc, JSValueConst *argv, int *pdone) -{ - JSValue obj; - - /* fast path for the built-in iterators (avoid creating the - intermediate result object) */ - if (JS_IsObject(method)) { - JSObject *p = JS_VALUE_GET_OBJ(method); - if (p->class_id == JS_CLASS_C_FUNCTION && - p->u.cfunc.cproto == JS_CFUNC_iterator_next) { - JSCFunctionType func; - JSValueConst args[1]; - - /* in case the function expects one argument */ - if (argc == 0) { - args[0] = JS_NULL; - argv = args; - } - func = p->u.cfunc.c_function; - return func.iterator_next(ctx, enum_obj, argc, argv, - pdone, p->u.cfunc.magic); - } - } - obj = JS_Call(ctx, method, enum_obj, argc, argv); - if (JS_IsException(obj)) - goto fail; - if (!JS_IsObject(obj)) { - JS_FreeValue(ctx, obj); - JS_ThrowTypeError(ctx, "iterator must return an object"); - goto fail; - } - *pdone = 2; - return obj; - fail: - *pdone = FALSE; - return JS_EXCEPTION; -} - -/* Note: always return JS_NULL when *pdone = TRUE. */ -static JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj, - JSValueConst method, - int argc, JSValueConst *argv, BOOL *pdone) -{ - JSValue obj, value, done_val; - int done; - - obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done); - if (JS_IsException(obj)) - goto fail; - if (likely(done == 0)) { - *pdone = FALSE; - return obj; - } else if (done != 2) { - JS_FreeValue(ctx, obj); - *pdone = TRUE; - return JS_NULL; - } else { - done_val = JS_GetProperty(ctx, obj, JS_ATOM_done); - if (JS_IsException(done_val)) - goto fail; - *pdone = JS_ToBoolFree(ctx, done_val); - value = JS_NULL; - if (!*pdone) { - value = JS_GetProperty(ctx, obj, JS_ATOM_value); - } - JS_FreeValue(ctx, obj); - return value; - } - fail: - JS_FreeValue(ctx, obj); - *pdone = FALSE; - return JS_EXCEPTION; -} - -/* return < 0 in case of exception */ -static int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj, - BOOL is_exception_pending) -{ - JSValue method, ret, ex_obj; - int res; - - if (is_exception_pending) { - ex_obj = ctx->rt->current_exception; - ctx->rt->current_exception = JS_UNINITIALIZED; - res = -1; - } else { - ex_obj = JS_NULL; - res = 0; - } - method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return); - if (JS_IsException(method)) { - res = -1; - goto done; - } - if (JS_IsNull(method) || JS_IsNull(method)) { - goto done; - } - ret = JS_CallFree(ctx, method, enum_obj, 0, NULL); - if (!is_exception_pending) { - if (JS_IsException(ret)) { - res = -1; - } else if (!JS_IsObject(ret)) { - JS_ThrowTypeErrorNotAnObject(ctx); - res = -1; - } - } - JS_FreeValue(ctx, ret); - done: - if (is_exception_pending) { - JS_Throw(ctx, ex_obj); - } - return res; -} - -/* obj -> enum_rec (3 slots) */ -static __exception int js_for_of_start(JSContext *ctx, JSValue *sp) -{ - JSValue op1, obj, method; - op1 = sp[-1]; - obj = JS_GetIterator(ctx, op1); - if (JS_IsException(obj)) - return -1; - JS_FreeValue(ctx, op1); - sp[-1] = obj; - method = JS_GetProperty(ctx, obj, JS_ATOM_next); - if (JS_IsException(method)) - return -1; - sp[0] = method; - return 0; -} - -/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset' - objs. If 'done' is true or in case of exception, 'enum_rec' is set - to undefined. If 'done' is true, 'value' is always set to - undefined. */ -static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset) -{ - JSValue value = JS_NULL; - int done = 1; - - if (likely(!JS_IsNull(sp[offset]))) { - value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done); - if (JS_IsException(value)) - done = -1; - if (done) { - /* value is JS_NULL or JS_EXCEPTION */ - /* replace the iteration object with undefined */ - JS_FreeValue(ctx, sp[offset]); - sp[offset] = JS_NULL; - if (done < 0) { - return -1; - } else { - JS_FreeValue(ctx, value); - value = JS_NULL; - } - } - } - sp[0] = value; - sp[1] = JS_NewBool(ctx, done); - return 0; -} - -static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj, - BOOL *pdone) -{ - JSValue done_val, value; - BOOL done; - done_val = JS_GetProperty(ctx, obj, JS_ATOM_done); - if (JS_IsException(done_val)) - goto fail; - done = JS_ToBoolFree(ctx, done_val); - value = JS_GetProperty(ctx, obj, JS_ATOM_value); - if (JS_IsException(value)) - goto fail; - *pdone = done; - return value; - fail: - *pdone = FALSE; - return JS_EXCEPTION; -} - -static __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp) -{ - JSValue obj, value; - BOOL done; - obj = sp[-1]; - if (!JS_IsObject(obj)) { - JS_ThrowTypeError(ctx, "iterator must return an object"); - return -1; - } - value = JS_IteratorGetCompleteValue(ctx, obj, &done); - if (JS_IsException(value)) - return -1; - JS_FreeValue(ctx, obj); - /* put again the catch offset so that exceptions close the - iterator */ - sp[-2] = JS_NewCatchOffset(ctx, 0); - sp[-1] = value; - sp[0] = JS_NewBool(ctx, done); - return 0; -} - -static JSValue js_create_iterator_result(JSContext *ctx, - JSValue val, - BOOL done) -{ - JSValue obj; - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) { - JS_FreeValue(ctx, val); - return obj; - } - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value, - val, JS_PROP_C_W_E) < 0) { - goto fail; - } - if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done, - JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) { - fail: - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; - } - return obj; -} - -static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic); - -static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic); - static BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj) { /* Try and handle fast arrays explicitly */ @@ -12082,86 +11792,6 @@ static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj, return FALSE; } -static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) -{ - JSValue iterator, enumobj, method, value; - int is_array_iterator; - JSValue *arrp; - uint32_t i, count32, pos; - - if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) { - JS_ThrowInternalError(ctx, "invalid index for append"); - return -1; - } - - pos = JS_VALUE_GET_INT(sp[-2]); - - /* XXX: further optimisations: - - use ctx->array_proto_values? - - check if array_iterator_prototype next method is built-in and - avoid constructing actual iterator object? - - build this into js_for_of_start and use in all `for (x of o)` loops - */ - iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator); - if (JS_IsException(iterator)) - return -1; - is_array_iterator = JS_IsCFunction(ctx, iterator, - (JSCFunction *)js_create_array_iterator, - JS_ITERATOR_KIND_VALUE); - JS_FreeValue(ctx, iterator); - - enumobj = JS_GetIterator(ctx, sp[-1]); - if (JS_IsException(enumobj)) - return -1; - method = JS_GetProperty(ctx, enumobj, JS_ATOM_next); - if (JS_IsException(method)) { - JS_FreeValue(ctx, enumobj); - return -1; - } - if (is_array_iterator - && JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0) - && js_get_fast_array(ctx, sp[-1], &arrp, &count32)) { - uint32_t len; - if (js_get_length32(ctx, &len, sp[-1])) - goto exception; - /* if len > count32, the elements >= count32 might be read in - the prototypes and might have side effects */ - if (len != count32) - goto general_case; - /* Handle fast arrays explicitly */ - for (i = 0; i < count32; i++) { - if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, - JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0) - goto exception; - } - } else { - general_case: - for (;;) { - BOOL done; - value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done); - if (JS_IsException(value)) - goto exception; - if (done) { - /* value is JS_NULL */ - break; - } - if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0) - goto exception; - } - } - /* Note: could raise an error if too many elements */ - sp[-2] = JS_NewInt32(ctx, pos); - JS_FreeValue(ctx, enumobj); - JS_FreeValue(ctx, method); - return 0; - -exception: - JS_IteratorClose(ctx, enumobj, TRUE); - JS_FreeValue(ctx, enumobj); - JS_FreeValue(ctx, method); - return -1; -} - static __exception int JS_CopyDataProperties(JSContext *ctx, JSValueConst target, JSValueConst source, @@ -12618,16 +12248,6 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj, ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2)); } break; - case JS_CFUNC_iterator_next: - { - int done; - ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf, - &done, p->u.cfunc.magic); - if (!JS_IsException(ret_val) && done != 2) { - ret_val = js_create_iterator_result(ctx, ret_val, done); - } - } - break; default: abort(); } @@ -14211,49 +13831,6 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj, goto exception; sp += 2; BREAK; - CASE(OP_for_of_start): - sf->cur_pc = pc; - if (js_for_of_start(ctx, sp)) - goto exception; - sp += 1; - *sp++ = JS_NewCatchOffset(ctx, 0); - BREAK; - CASE(OP_for_of_next): - { - int offset = -3 - pc[0]; - pc += 1; - sf->cur_pc = pc; - if (js_for_of_next(ctx, sp, offset)) - goto exception; - sp += 2; - } - BREAK; - CASE(OP_iterator_get_value_done): - sf->cur_pc = pc; - if (js_iterator_get_value_done(ctx, sp)) - goto exception; - sp += 1; - BREAK; - CASE(OP_iterator_check_object): - if (unlikely(!JS_IsObject(sp[-1]))) { - JS_ThrowTypeError(ctx, "iterator must return an object"); - goto exception; - } - BREAK; - - CASE(OP_iterator_close): - /* iter_obj next catch_offset -> */ - sp--; /* drop the catch offset to avoid getting caught by exception */ - JS_FreeValue(ctx, sp[-1]); /* drop the next method */ - sp--; - if (!JS_IsNull(sp[-1])) { - sf->cur_pc = pc; - if (JS_IteratorClose(ctx, sp[-1], FALSE)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - } - sp--; - BREAK; CASE(OP_nip_catch): { JSValue ret_val; @@ -14272,54 +13849,6 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj, } BREAK; - CASE(OP_iterator_next): - /* stack: iter_obj next catch_offset val */ - { - JSValue ret; - sf->cur_pc = pc; - ret = JS_Call(ctx, sp[-3], sp[-4], - 1, (JSValueConst *)(sp - 1)); - if (JS_IsException(ret)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret; - } - BREAK; - - CASE(OP_iterator_call): - /* stack: iter_obj next catch_offset val */ - { - JSValue method, ret; - BOOL ret_flag; - int flags; - flags = *pc++; - sf->cur_pc = pc; - method = JS_GetProperty(ctx, sp[-4], (flags & 1) ? - JS_ATOM_throw : JS_ATOM_return); - if (JS_IsException(method)) - goto exception; - if (JS_IsNull(method) || JS_IsNull(method)) { - ret_flag = TRUE; - } else { - if (flags & 2) { - /* no argument */ - ret = JS_CallFree(ctx, method, sp[-4], - 0, NULL); - } else { - ret = JS_CallFree(ctx, method, sp[-4], - 1, (JSValueConst *)(sp - 1)); - } - if (JS_IsException(ret)) - goto exception; - JS_FreeValue(ctx, sp[-1]); - sp[-1] = ret; - ret_flag = FALSE; - } - sp[0] = JS_NewBool(ctx, ret_flag); - sp += 1; - } - BREAK; - CASE(OP_lnot): { int res; @@ -14872,15 +14401,6 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj, } BREAK; - CASE(OP_append): /* array pos enumobj -- array pos */ - { - sf->cur_pc = pc; - if (js_append_enumerate(ctx, sp)) - goto exception; - JS_FreeValue(ctx, *--sp); - } - BREAK; - CASE(OP_copy_data_properties): /* target source excludeList */ { /* stack offsets (-1 based): @@ -15538,12 +15058,7 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj, JS_FreeValue(ctx, val); if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) { int pos = JS_VALUE_GET_INT(val); - if (pos == 0) { - /* enumerator: close it with a throw */ - JS_FreeValue(ctx, sp[-1]); /* drop the next method */ - sp--; - JS_IteratorClose(ctx, sp[-1], TRUE); - } else { + if (pos != 0) { *sp++ = rt->current_exception; rt->current_exception = JS_UNINITIALIZED; pc = b->byte_code_buf + pos; @@ -15849,7 +15364,6 @@ typedef struct BlockEnv { int drop_count; /* number of stack elements to drop */ int label_finally; /* -1 if none */ int scope_level; - uint8_t has_iterator : 1; uint8_t is_regular_stmt : 1; /* i.e. not a loop statement */ } BlockEnv; @@ -18820,37 +18334,7 @@ static __exception int js_parse_array_literal(JSParseState *s) /* stack has array, index */ while (s->token.val != ']') { if (s->token.val == TOK_ELLIPSIS) { - if (next_token(s)) - return -1; - if (js_parse_assign_expr(s)) - return -1; -#if 1 - emit_op(s, OP_append); -#else - int label_next, label_done; - label_next = new_label(s); - label_done = new_label(s); - /* enumerate object */ - emit_op(s, OP_for_of_start); - emit_op(s, OP_rot5l); - emit_op(s, OP_rot5l); - emit_label(s, label_next); - /* on stack: enum_rec array idx */ - emit_op(s, OP_for_of_next); - emit_u8(s, 2); - emit_goto(s, OP_if_true, label_done); - /* append element */ - /* enum_rec array idx val -> enum_rec array new_idx */ - emit_op(s, OP_define_array_el); - emit_op(s, OP_inc); - emit_goto(s, OP_goto, label_next); - emit_label(s, label_done); - /* close enumeration */ - emit_op(s, OP_drop); /* drop undef val */ - emit_op(s, OP_nip1); /* drop enum_rec */ - emit_op(s, OP_nip1); - emit_op(s, OP_nip1); -#endif + return js_parse_error(s, "spread syntax in array literals is not supported"); } else { need_length = TRUE; if (s->token.val != ',') { @@ -19138,32 +18622,6 @@ static __exception int js_define_var(JSParseState *s, JSAtom name, int tok) return 0; } -static void js_emit_spread_code(JSParseState *s, int depth) -{ - int label_rest_next, label_rest_done; - - /* XXX: could check if enum object is an actual array and optimize - slice extraction. enumeration record and target array are in a - different order from OP_append case. */ - /* enum_rec xxx -- enum_rec xxx array 0 */ - emit_op(s, OP_array_from); - emit_u16(s, 0); - emit_op(s, OP_push_i32); - emit_u32(s, 0); - emit_label(s, label_rest_next = new_label(s)); - emit_op(s, OP_for_of_next); - emit_u8(s, 2 + depth); - label_rest_done = emit_goto(s, OP_if_true, -1); - /* array idx val -- array idx */ - emit_op(s, OP_define_array_el); - emit_op(s, OP_inc); - emit_goto(s, OP_goto, label_rest_next); - emit_label(s, label_rest_done); - /* enum_rec xxx array idx undef -- enum_rec xxx array */ - emit_op(s, OP_drop); - emit_op(s, OP_drop); -} - static int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name) { /* Check for duplicate parameter names */ @@ -19520,121 +18978,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, if (next_token(s)) return -1; } else if (s->token.val == '[') { - BOOL has_spread; - int enum_depth; - BlockEnv block_env; - - if (next_token(s)) - return -1; - /* the block environment is only needed in generators in case - 'yield' triggers a 'return' */ - push_break_entry(s->cur_func, &block_env, - JS_ATOM_NULL, -1, -1, 2); - block_env.has_iterator = TRUE; - emit_op(s, OP_for_of_start); - has_spread = FALSE; - while (s->token.val != ']') { - /* get the next value */ - if (s->token.val == TOK_ELLIPSIS) { - if (next_token(s)) - return -1; - if (s->token.val == ',' || s->token.val == ']') - return js_parse_error(s, "missing binding pattern..."); - has_spread = TRUE; - } - if (s->token.val == ',') { - /* do nothing, skip the value, has_spread is false */ - emit_op(s, OP_for_of_next); - emit_u8(s, 0); - emit_op(s, OP_drop); - emit_op(s, OP_drop); - } else if ((s->token.val == '[' || s->token.val == '{') - && ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' || - tok1 == '=' || tok1 == ']')) { - if (has_spread) { - if (tok1 == '=') - return js_parse_error(s, "rest element cannot have a default value"); - js_emit_spread_code(s, 0); - } else { - emit_op(s, OP_for_of_next); - emit_u8(s, 0); - emit_op(s, OP_drop); - } - if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, export_flag) < 0) - return -1; - } else { - var_name = JS_ATOM_NULL; - if (tok) { - var_name = js_parse_destructuring_var(s, tok, is_arg); - if (var_name == JS_ATOM_NULL) - goto var_error; - if (js_define_var(s, var_name, tok)) - goto var_error; - if (need_var_reference(s, tok)) { - /* Must make a reference for proper `with` semantics */ - emit_op(s, OP_scope_get_var); - emit_atom(s, var_name); - emit_u16(s, s->cur_func->scope_level); - JS_FreeAtom(s->ctx, var_name); - goto lvalue2; - } else { - /* no need to make a reference for let/const */ - opcode = OP_scope_get_var; - scope = s->cur_func->scope_level; - label_lvalue = -1; - enum_depth = 0; - } - } else { - if (js_parse_left_hand_side_expr(s)) - return -1; - lvalue2: - if (get_lvalue(s, &opcode, &scope, &var_name, - &label_lvalue, &enum_depth, FALSE, '[')) { - return -1; - } - } - if (has_spread) { - js_emit_spread_code(s, enum_depth); - } else { - emit_op(s, OP_for_of_next); - emit_u8(s, enum_depth); - emit_op(s, OP_drop); - } - if (s->token.val == '=' && !has_spread) { - /* handle optional default value */ - int label_hasval; - emit_op(s, OP_dup); - emit_op(s, OP_null); - emit_op(s, OP_strict_eq); - label_hasval = emit_goto(s, OP_if_false, -1); - if (next_token(s)) - goto var_error; - emit_op(s, OP_drop); - if (js_parse_assign_expr(s)) - goto var_error; - if (opcode == OP_scope_get_var || opcode == OP_get_ref_value) - set_object_name(s, var_name); - emit_label(s, label_hasval); - } - /* store value into lvalue object */ - put_lvalue(s, opcode, scope, var_name, - label_lvalue, PUT_LVALUE_NOKEEP_DEPTH, - (tok == TOK_DEF || tok == TOK_VAR)); - } - if (s->token.val == ']') - break; - if (has_spread) - return js_parse_error(s, "rest element must be the last one"); - /* accept a trailing comma before the ']' */ - if (js_parse_expect(s, ',')) - return -1; - } - /* close iterator object: - if completed, enum_obj has been replaced by undefined */ - emit_op(s, OP_iterator_close); - pop_break_entry(s->cur_func); - if (next_token(s)) - return -1; + return js_parse_error(s, "array destructuring is not supported"); } else { return js_parse_error(s, "invalid assignment syntax"); } @@ -20009,7 +19353,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) return js_parse_error(s, "Too many call arguments"); } if (s->token.val == TOK_ELLIPSIS) - break; + return js_parse_error(s, "spread syntax in function calls is not supported"); if (js_parse_assign_expr(s)) return -1; arg_count++; @@ -20019,100 +19363,10 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) if (js_parse_expect(s, ',')) return -1; } - if (s->token.val == TOK_ELLIPSIS) { - emit_op(s, OP_array_from); - emit_u16(s, arg_count); - emit_op(s, OP_push_i32); - emit_u32(s, arg_count); - - /* on stack: array idx */ - while (s->token.val != ')') { - if (s->token.val == TOK_ELLIPSIS) { - if (next_token(s)) - return -1; - if (js_parse_assign_expr(s)) - return -1; -#if 1 - /* XXX: could pass is_last indicator? */ - emit_op(s, OP_append); -#else - int label_next, label_done; - label_next = new_label(s); - label_done = new_label(s); - /* push enumerate object below array/idx pair */ - emit_op(s, OP_for_of_start); - emit_op(s, OP_rot5l); - emit_op(s, OP_rot5l); - emit_label(s, label_next); - /* on stack: enum_rec array idx */ - emit_op(s, OP_for_of_next); - emit_u8(s, 2); - emit_goto(s, OP_if_true, label_done); - /* append element */ - /* enum_rec array idx val -> enum_rec array new_idx */ - emit_op(s, OP_define_array_el); - emit_op(s, OP_inc); - emit_goto(s, OP_goto, label_next); - emit_label(s, label_done); - /* close enumeration, drop enum_rec and idx */ - emit_op(s, OP_drop); /* drop undef */ - emit_op(s, OP_nip1); /* drop enum_rec */ - emit_op(s, OP_nip1); - emit_op(s, OP_nip1); -#endif - } else { - if (js_parse_assign_expr(s)) - return -1; - /* array idx val */ - emit_op(s, OP_define_array_el); - emit_op(s, OP_inc); - } - if (s->token.val == ')') - break; - /* accept a trailing comma before the ')' */ - if (js_parse_expect(s, ',')) - return -1; - } - if (next_token(s)) - return -1; - /* drop the index */ - emit_op(s, OP_drop); - - emit_source_pos(s, op_token_ptr); - /* apply function call */ - switch(opcode) { - case OP_get_field: - case OP_get_array_el: - case OP_scope_get_ref: - /* obj func array -> func obj array */ - emit_op(s, OP_perm3); - emit_op(s, OP_apply); - emit_u16(s, call_type == FUNC_CALL_NEW); - break; - case OP_eval: - emit_op(s, OP_apply_eval); - emit_u16(s, fd->scope_level); - fd->has_eval_call = TRUE; - break; - default: - if (call_type == FUNC_CALL_NEW) { - /* obj func array -> func obj array */ - emit_op(s, OP_perm3); - emit_op(s, OP_apply); - emit_u16(s, 1); - } else { - /* func array -> func undef array */ - emit_op(s, OP_null); - emit_op(s, OP_swap); - emit_op(s, OP_apply); - emit_u16(s, 0); - } - break; - } - } else { - if (next_token(s)) - return -1; - emit_func_call: + if (next_token(s)) + return -1; + emit_func_call: + { emit_source_pos(s, op_token_ptr); switch(opcode) { case OP_get_field: @@ -20785,7 +20039,6 @@ static void push_break_entry(JSFunctionDef *fd, BlockEnv *be, be->drop_count = drop_count; be->label_finally = -1; be->scope_level = fd->scope_level; - be->has_iterator = FALSE; be->is_regular_stmt = FALSE; } @@ -20820,12 +20073,7 @@ static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont) emit_goto(s, OP_goto, top->label_break); return 0; } - i = 0; - if (top->has_iterator) { - emit_op(s, OP_iterator_close); - i += 3; - } - for(; i < top->drop_count; i++) + for(i = 0; i < top->drop_count; i++) emit_op(s, OP_drop); if (top->label_finally != -1) { /* must push dummy value to keep same stack depth */ @@ -20852,7 +20100,7 @@ static void emit_return(JSParseState *s, BOOL hasval) top = s->cur_func->top_break; while (top != NULL) { - if (top->has_iterator || top->label_finally != -1) { + if (top->label_finally != -1) { if (!hasval) { emit_op(s, OP_null); hasval = TRUE; @@ -20862,15 +20110,8 @@ static void emit_return(JSParseState *s, BOOL hasval) no easy way to count them, so we use this specific instruction instead. */ emit_op(s, OP_nip_catch); - /* stack: iter_obj next ret_val */ - if (top->has_iterator) { - emit_op(s, OP_rot3r); - emit_op(s, OP_null); /* dummy catch offset */ - emit_op(s, OP_iterator_close); - } else { - /* execute the "finally" block */ - emit_goto(s, OP_gosub, top->label_finally); - } + /* execute the "finally" block */ + emit_goto(s, OP_gosub, top->label_finally); } top = top->prev; } @@ -21052,14 +20293,13 @@ static int is_let(JSParseState *s, int decl_mask) return res; } -/* XXX: handle IteratorClose when exiting the loop before the - enumeration is done */ +/* for-in loop parsing (for-of is not supported) */ static __exception int js_parse_for_in_of(JSParseState *s, int label_name) { JSContext *ctx = s->ctx; JSFunctionDef *fd = s->cur_func; JSAtom var_name; - BOOL has_initializer, is_for_of, has_destructuring; + BOOL has_initializer, has_destructuring; int tok, tok1, opcode, scope, block_scope_level; int label_next, label_expr, label_cont, label_body, label_break; int pos_next, pos_expr; @@ -21067,7 +20307,6 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name) has_initializer = FALSE; has_destructuring = FALSE; - is_for_of = FALSE; block_scope_level = fd->scope_level; label_cont = new_label(s); label_body = new_label(s); @@ -21160,39 +20399,24 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name) JS_FreeAtom(ctx, var_name); if (token_is_pseudo_keyword(s, JS_ATOM_of)) { - break_entry.has_iterator = is_for_of = TRUE; - break_entry.drop_count += 2; - if (has_initializer) - goto initializer_error; + return js_parse_error(s, "'for of' loops are not supported"); } else if (s->token.val == TOK_IN) { if (has_initializer && (tok != TOK_VAR || has_destructuring)) { - initializer_error: - return js_parse_error(s, "a declaration in the head of a for-%s loop can't have an initializer", - is_for_of ? "of" : "in"); + return js_parse_error(s, "a declaration in the head of a for-in loop can't have an initializer"); } } else { - return js_parse_error(s, "expected 'of' or 'in' in for control expression"); + return js_parse_error(s, "expected 'in' in for control expression"); } if (next_token(s)) return -1; - if (is_for_of) { - if (js_parse_assign_expr(s)) - return -1; - } else { - if (js_parse_expr(s)) - return -1; - } + if (js_parse_expr(s)) + return -1; /* close the scope after having evaluated the expression so that the TDZ values are in the closures */ close_scopes(s, s->cur_func->scope_level, block_scope_level); - if (is_for_of) { - emit_op(s, OP_for_of_start); - /* on stack: enum_rec */ - } else { - emit_op(s, OP_for_in_start); - /* on stack: enum_obj */ - } + emit_op(s, OP_for_in_start); + /* on stack: enum_obj */ emit_goto(s, OP_goto, label_cont); if (js_parse_expect(s, ')')) @@ -21224,24 +20448,14 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name) close_scopes(s, s->cur_func->scope_level, block_scope_level); emit_label(s, label_cont); - if (is_for_of) { - emit_op(s, OP_for_of_next); - emit_u8(s, 0); - } else { - emit_op(s, OP_for_in_next); - } - /* on stack: enum_rec / enum_obj value bool */ + emit_op(s, OP_for_in_next); + /* on stack: enum_obj value bool */ emit_goto(s, OP_if_false, label_next); - /* drop the undefined value from for_xx_next */ + /* drop the undefined value from for_in_next */ emit_op(s, OP_drop); emit_label(s, label_break); - if (is_for_of) { - /* close and drop enum_rec */ - emit_op(s, OP_iterator_close); - } else { - emit_op(s, OP_drop); - } + emit_op(s, OP_drop); pop_break_entry(s->cur_func); pop_scope(s); return 0; @@ -25272,9 +24486,6 @@ static __exception int compute_stack_size(JSContext *ctx, goto fail; catch_pos = pos; break; - case OP_for_of_start: - catch_pos = pos; - break; /* we assume the catch offset entry is only removed with some op codes */ case OP_drop: @@ -25285,18 +24496,10 @@ static __exception int compute_stack_size(JSContext *ctx, goto check_catch; case OP_nip1: catch_level = stack_len - 1; - goto check_catch; - case OP_iterator_close: - catch_level = stack_len + 2; check_catch: - /* Note: for for_of_start/for_await_of_start we consider - the catch offset is on the first stack entry instead of - the thirst */ if (catch_pos >= 0) { int level; level = s->stack_level_tab[catch_pos]; - if (bc_buf[catch_pos] != OP_catch) - level++; /* for_of_start, for_wait_of_start */ /* catch_level = stack_level before op_catch is executed ? */ if (catch_level == level) { catch_pos = s->catch_pos_tab[catch_pos]; @@ -25309,8 +24512,6 @@ static __exception int compute_stack_size(JSContext *ctx, goto fail; } stack_len = s->stack_level_tab[catch_pos]; - if (bc_buf[catch_pos] != OP_catch) - stack_len++; /* for_of_start, for_wait_of_start */ stack_len++; /* no stack overflow is possible by construction */ catch_pos = s->catch_pos_tab[catch_pos]; break; @@ -28946,72 +28147,6 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; } -static JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue obj, iter, next_method = JS_NULL; - JSValueConst iterable; - BOOL done; - - /* RequireObjectCoercible() not necessary because it is tested in - JS_GetIterator() by JS_GetProperty() */ - iterable = argv[0]; - - obj = JS_NewObject(ctx); - if (JS_IsException(obj)) - return obj; - - iter = JS_GetIterator(ctx, iterable); - if (JS_IsException(iter)) - goto fail; - next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); - if (JS_IsException(next_method)) - goto fail; - - for(;;) { - JSValue key, value, item; - item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done); - if (JS_IsException(item)) - goto fail; - if (done) - break; - - key = JS_NULL; - value = JS_NULL; - if (!JS_IsObject(item)) { - JS_ThrowTypeErrorNotAnObject(ctx); - goto fail1; - } - key = JS_GetPropertyUint32(ctx, item, 0); - if (JS_IsException(key)) - goto fail1; - value = JS_GetPropertyUint32(ctx, item, 1); - if (JS_IsException(value)) { - JS_FreeValue(ctx, key); - goto fail1; - } - if (JS_DefinePropertyValueValue(ctx, obj, key, value, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) { - fail1: - JS_FreeValue(ctx, item); - goto fail; - } - JS_FreeValue(ctx, item); - } - JS_FreeValue(ctx, next_method); - JS_FreeValue(ctx, iter); - return obj; - fail: - if (JS_IsObject(iter)) { - /* close the iterator object, preserving pending exception */ - JS_IteratorClose(ctx, iter, TRUE); - } - JS_FreeValue(ctx, next_method); - JS_FreeValue(ctx, iter); - JS_FreeValue(ctx, obj); - return JS_EXCEPTION; -} - /* return an empty string if not an object */ static JSValue js_object___getClass(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) @@ -29081,7 +28216,6 @@ static const JSCFunctionListEntry js_object_funcs[] = { JS_CFUNC_DEF("is", 2, js_object_is ), JS_CFUNC_DEF("assign", 2, js_object_assign ), JS_CFUNC_DEF("__getClass", 1, js_object___getClass ), - JS_CFUNC_DEF("fromEntries", 1, js_object_fromEntries ), JS_CFUNC_DEF("hasOwn", 2, js_object_hasOwn ), }; @@ -29282,45 +28416,6 @@ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val, } /* Error class */ - -static JSValue iterator_to_array(JSContext *ctx, JSValueConst items) -{ - JSValue iter, next_method = JS_NULL; - JSValue v, r = JS_NULL; - int64_t k; - BOOL done; - - iter = JS_GetIterator(ctx, items); - if (JS_IsException(iter)) - goto exception; - next_method = JS_GetProperty(ctx, iter, JS_ATOM_next); - if (JS_IsException(next_method)) - goto exception; - r = JS_NewArray(ctx); - if (JS_IsException(r)) - goto exception; - for (k = 0;; k++) { - v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done); - if (JS_IsException(v)) - goto exception_close; - if (done) - break; - if (JS_DefinePropertyValueInt64(ctx, r, k, v, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception_close; - } - done: - JS_FreeValue(ctx, next_method); - JS_FreeValue(ctx, iter); - return r; - exception_close: - JS_IteratorClose(ctx, iter, TRUE); - exception: - JS_FreeValue(ctx, r); - r = JS_EXCEPTION; - goto done; -} - static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic) { @@ -29380,9 +28475,31 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, } if (magic == JS_AGGREGATE_ERROR) { - JSValue error_list = iterator_to_array(ctx, argv[0]); - if (JS_IsException(error_list)) - goto exception; + /* Require errors to be an array (no iterator support) */ + JSValue error_list; + if (JS_IsArray(ctx, argv[0])) { + uint32_t len, i; + if (js_get_length32(ctx, &len, argv[0])) + goto exception; + error_list = JS_NewArray(ctx); + if (JS_IsException(error_list)) + goto exception; + for (i = 0; i < len; i++) { + JSValue item = JS_GetPropertyUint32(ctx, argv[0], i); + if (JS_IsException(item)) { + JS_FreeValue(ctx, error_list); + goto exception; + } + if (JS_DefinePropertyValueUint32(ctx, error_list, i, item, JS_PROP_C_W_E) < 0) { + JS_FreeValue(ctx, error_list); + goto exception; + } + } + } else { + error_list = JS_NewArray(ctx); + if (JS_IsException(error_list)) + goto exception; + } JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE); } @@ -29921,32 +29038,6 @@ fail: return -1; } -typedef struct JSArrayIteratorData { - JSValue obj; - JSIteratorKindEnum kind; - uint32_t idx; -} JSArrayIteratorData; - -static void js_array_iterator_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSArrayIteratorData *it = p->u.array_iterator_data; - if (it) { - JS_FreeValueRT(rt, it->obj); - js_free_rt(rt, it); - } -} - -static void js_array_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSArrayIteratorData *it = p->u.array_iterator_data; - if (it) { - JS_MarkValue(rt, it->obj, mark_func); - } -} - static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab) { JSValue obj; @@ -29964,105 +29055,6 @@ static JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab) return obj; } -static JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, int magic) -{ - JSValue enum_obj, arr; - JSArrayIteratorData *it; - JSIteratorKindEnum kind; - int class_id; - - kind = magic & 3; - if (magic & 4) { - /* string iterator case */ - arr = JS_ToStringCheckObject(ctx, this_val); - class_id = JS_CLASS_STRING_ITERATOR; - } else { - arr = JS_ToObject(ctx, this_val); - class_id = JS_CLASS_ARRAY_ITERATOR; - } - if (JS_IsException(arr)) - goto fail; - enum_obj = JS_NewObjectClass(ctx, class_id); - if (JS_IsException(enum_obj)) - goto fail; - it = js_malloc(ctx, sizeof(*it)); - if (!it) - goto fail1; - it->obj = arr; - it->kind = kind; - it->idx = 0; - JS_SetOpaque(enum_obj, it); - return enum_obj; - fail1: - JS_FreeValue(ctx, enum_obj); - fail: - JS_FreeValue(ctx, arr); - return JS_EXCEPTION; -} - -static JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) -{ - JSArrayIteratorData *it; - uint32_t len, idx; - JSValue val, obj; - - it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR); - if (!it) - goto fail1; - if (JS_IsNull(it->obj)) - goto done; - - if (js_get_length32(ctx, &len, it->obj)) { - fail1: - *pdone = FALSE; - return JS_EXCEPTION; - } - - idx = it->idx; - if (idx >= len) { - JS_FreeValue(ctx, it->obj); - it->obj = JS_NULL; - done: - *pdone = TRUE; - return JS_NULL; - } - it->idx = idx + 1; - *pdone = FALSE; - if (it->kind == JS_ITERATOR_KIND_KEY) { - return JS_NewUint32(ctx, idx); - } else { - val = JS_GetPropertyUint32(ctx, it->obj, idx); - if (JS_IsException(val)) - return JS_EXCEPTION; - if (it->kind == JS_ITERATOR_KIND_VALUE) { - return val; - } else { - JSValueConst args[2]; - JSValue num; - num = JS_NewUint32(ctx, idx); - args[0] = num; - args[1] = val; - obj = js_create_array(ctx, 2, args); - JS_FreeValue(ctx, val); - JS_FreeValue(ctx, num); - return obj; - } - } -} - -static JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - return JS_DupValue(ctx, this_val); -} - -static const JSCFunctionListEntry js_iterator_proto_funcs[] = { - JS_CFUNC_DEF("[Symbol.iterator]", 0, js_iterator_proto_iterator ), -}; - static const JSCFunctionListEntry js_array_proto_funcs[] = { JS_CFUNC_DEF("toString", 0, js_array_toString ), JS_CFUNC_MAGIC_DEF("pop", 0, js_array_pop, 0 ), @@ -30071,15 +29063,6 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = { JS_CFUNC_MAGIC_DEF("unshift", 1, js_array_push, 1 ), JS_CFUNC_MAGIC_DEF("slice", 2, js_array_slice, 0 ), JS_CFUNC_MAGIC_DEF("splice", 2, js_array_slice, 1 ), - JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ), - JS_ALIAS_DEF("[Symbol.iterator]", "values" ), - JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ), - JS_CFUNC_MAGIC_DEF("entries", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ), -}; - -static const JSCFunctionListEntry js_array_iterator_proto_funcs[] = { - JS_ITERATOR_NEXT_DEF("next", 0, js_array_iterator_next, 0 ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Array Iterator", JS_PROP_CONFIGURABLE ), }; /* String */ @@ -30417,44 +29400,6 @@ static JSValue js_string_toString(JSContext *ctx, JSValueConst this_val, return js_thisStringValue(ctx, this_val); } -/* String Iterator */ - -static JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) -{ - JSArrayIteratorData *it; - uint32_t idx, c, start; - JSString *p; - - it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR); - if (!it) { - *pdone = FALSE; - return JS_EXCEPTION; - } - if (JS_IsNull(it->obj)) - goto done; - p = JS_VALUE_GET_STRING(it->obj); - idx = it->idx; - if (idx >= p->len) { - JS_FreeValue(ctx, it->obj); - it->obj = JS_NULL; - done: - *pdone = TRUE; - return JS_NULL; - } - - start = idx; - c = string_getc(p, (int *)&idx); - it->idx = idx; - *pdone = FALSE; - if (c <= 0xffff) { - return js_new_string_char(ctx, c); - } else { - return js_new_string16_len(ctx, p->u.str16 + start, 2); - } -} - static JSValue js_string_concat(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -30477,12 +29422,6 @@ static const JSCFunctionListEntry js_string_proto_funcs[] = { JS_CFUNC_DEF("concat", 1, js_string_concat), JS_CFUNC_DEF("toString", 0, js_string_toString ), JS_CFUNC_DEF("valueOf", 0, js_string_toString ), - JS_CFUNC_MAGIC_DEF("[Symbol.iterator]", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ), -}; - -static const JSCFunctionListEntry js_string_iterator_proto_funcs[] = { - JS_ITERATOR_NEXT_DEF("next", 0, js_string_iterator_next, 0 ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "String Iterator", JS_PROP_CONFIGURABLE ), }; /* RegExp */ @@ -30921,58 +29860,6 @@ void *lre_realloc(void *opaque, void *ptr, size_t size) return js_realloc_rt(ctx->rt, ptr, size); } -static JSValue js_regexp_escape(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue str; - StringBuffer b_s, *b = &b_s; - JSString *p; - uint32_t c, i; - char s[16]; - - if (!JS_IsString(argv[0])) - return JS_ThrowTypeError(ctx, "not a string"); - str = JS_ToString(ctx, argv[0]); /* must call it to linearlize ropes */ - if (JS_IsException(str)) - return JS_EXCEPTION; - p = JS_VALUE_GET_STRING(str); - string_buffer_init2(ctx, b, 0, p->is_wide_char); - for (i = 0; i < p->len; i++) { - c = string_get(p, i); - if (c < 33) { - if (c >= 9 && c <= 13) { - string_buffer_putc8(b, '\\'); - string_buffer_putc8(b, "tnvfr"[c - 9]); - } else { - goto hex2; - } - } else if (c < 128) { - if ((c >= '0' && c <= '9') - || (c >= 'A' && c <= 'Z') - || (c >= 'a' && c <= 'z')) { - if (i == 0) - goto hex2; - } else if (strchr(",-=<>#&!%:;@~'`\"", c)) { - goto hex2; - } else if (c != '_') { - string_buffer_putc8(b, '\\'); - } - string_buffer_putc8(b, c); - } else if (c < 256) { - hex2: - snprintf(s, sizeof(s), "\\x%02x", c); - string_buffer_puts8(b, s); - } else if (is_surrogate(c) || lre_is_space(c)) { - snprintf(s, sizeof(s), "\\u%04x", c); - string_buffer_puts8(b, s); - } else { - string_buffer_putc16(b, c); - } - } - JS_FreeValue(ctx, str); - return string_buffer_end(b); -} - static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { @@ -31298,314 +30185,6 @@ static JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s) return js_regexp_exec(ctx, r, 1, &s); } -static JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValue val; - BOOL ret; - - val = JS_RegExpExec(ctx, this_val, argv[0]); - if (JS_IsException(val)) - return JS_EXCEPTION; - ret = !JS_IsNull(val); - JS_FreeValue(ctx, val); - return JS_NewBool(ctx, ret); -} - -static JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // [Symbol.match](str) - JSValueConst rx = this_val; - JSValue A, S, flags, result, matchStr; - int global, n, fullUnicode, isEmpty; - JSString *p; - - if (!JS_IsObject(rx)) - return JS_ThrowTypeErrorNotAnObject(ctx); - - A = JS_NULL; - flags = JS_NULL; - result = JS_NULL; - matchStr = JS_NULL; - S = JS_ToString(ctx, argv[0]); - if (JS_IsException(S)) - goto exception; - - flags = JS_GetProperty(ctx, rx, JS_ATOM_flags); - if (JS_IsException(flags)) - goto exception; - flags = JS_ToStringFree(ctx, flags); - if (JS_IsException(flags)) - goto exception; - p = JS_VALUE_GET_STRING(flags); - - global = (-1 != string_indexof_char(p, 'g', 0)); - if (!global) { - A = JS_RegExpExec(ctx, rx, S); - } else { - fullUnicode = (string_indexof_char(p, 'u', 0) >= 0 || - string_indexof_char(p, 'v', 0) >= 0); - - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) - goto exception; - A = JS_NewArray(ctx); - if (JS_IsException(A)) - goto exception; - n = 0; - for(;;) { - JS_FreeValue(ctx, result); - result = JS_RegExpExec(ctx, rx, S); - if (JS_IsException(result)) - goto exception; - if (JS_IsNull(result)) - break; - matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0)); - if (JS_IsException(matchStr)) - goto exception; - isEmpty = JS_IsEmptyString(matchStr); - if (JS_DefinePropertyValueInt64(ctx, A, n++, matchStr, JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - if (isEmpty) { - int64_t thisIndex, nextIndex; - if (JS_ToLengthFree(ctx, &thisIndex, - JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0) - goto exception; - p = JS_VALUE_GET_STRING(S); - nextIndex = string_advance_index(p, thisIndex, fullUnicode); - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0) - goto exception; - } - } - if (n == 0) { - JS_FreeValue(ctx, A); - A = JS_NULL; - } - } - JS_FreeValue(ctx, result); - JS_FreeValue(ctx, flags); - JS_FreeValue(ctx, S); - return A; - -exception: - JS_FreeValue(ctx, A); - JS_FreeValue(ctx, result); - JS_FreeValue(ctx, flags); - JS_FreeValue(ctx, S); - return JS_EXCEPTION; -} - -typedef struct JSRegExpStringIteratorData { - JSValue iterating_regexp; - JSValue iterated_string; - BOOL global; - BOOL unicode; - BOOL done; -} JSRegExpStringIteratorData; - -static void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data; - if (it) { - JS_FreeValueRT(rt, it->iterating_regexp); - JS_FreeValueRT(rt, it->iterated_string); - js_free_rt(rt, it); - } -} - -static void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val, - JS_MarkFunc *mark_func) -{ - JSObject *p = JS_VALUE_GET_OBJ(val); - JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data; - if (it) { - JS_MarkValue(rt, it->iterating_regexp, mark_func); - JS_MarkValue(rt, it->iterated_string, mark_func); - } -} - -static JSValue js_regexp_string_iterator_next(JSContext *ctx, - JSValueConst this_val, - int argc, JSValueConst *argv, - BOOL *pdone, int magic) -{ - JSRegExpStringIteratorData *it; - JSValueConst R, S; - JSValue matchStr = JS_NULL, match = JS_NULL; - JSString *sp; - - it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR); - if (!it) - goto exception; - if (it->done) { - *pdone = TRUE; - return JS_NULL; - } - R = it->iterating_regexp; - S = it->iterated_string; - match = JS_RegExpExec(ctx, R, S); - if (JS_IsException(match)) - goto exception; - if (JS_IsNull(match)) { - it->done = TRUE; - *pdone = TRUE; - return JS_NULL; - } else if (it->global) { - matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0)); - if (JS_IsException(matchStr)) - goto exception; - if (JS_IsEmptyString(matchStr)) { - int64_t thisIndex, nextIndex; - if (JS_ToLengthFree(ctx, &thisIndex, - JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0) - goto exception; - sp = JS_VALUE_GET_STRING(S); - nextIndex = string_advance_index(sp, thisIndex, it->unicode); - if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex, - JS_NewInt64(ctx, nextIndex)) < 0) - goto exception; - } - JS_FreeValue(ctx, matchStr); - } else { - it->done = TRUE; - } - *pdone = FALSE; - return match; - exception: - JS_FreeValue(ctx, match); - JS_FreeValue(ctx, matchStr); - *pdone = FALSE; - return JS_EXCEPTION; -} - -static JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // [Symbol.matchAll](str) - JSValueConst R = this_val; - JSValue S, C, flags, matcher, iter; - JSValueConst args[2]; - JSString *strp; - int64_t lastIndex; - JSRegExpStringIteratorData *it; - - if (!JS_IsObject(R)) - return JS_ThrowTypeErrorNotAnObject(ctx); - - C = JS_NULL; - flags = JS_NULL; - matcher = JS_NULL; - iter = JS_NULL; - - S = JS_ToString(ctx, argv[0]); - if (JS_IsException(S)) - goto exception; - C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor); - if (JS_IsException(C)) - goto exception; - flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags)); - if (JS_IsException(flags)) - goto exception; - args[0] = R; - args[1] = flags; - matcher = JS_CallConstructor(ctx, C, 2, args); - if (JS_IsException(matcher)) - goto exception; - if (JS_ToLengthFree(ctx, &lastIndex, - JS_GetProperty(ctx, R, JS_ATOM_lastIndex))) - goto exception; - if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex, - JS_NewInt64(ctx, lastIndex)) < 0) - goto exception; - - iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR); - if (JS_IsException(iter)) - goto exception; - it = js_malloc(ctx, sizeof(*it)); - if (!it) - goto exception; - it->iterating_regexp = matcher; - it->iterated_string = S; - strp = JS_VALUE_GET_STRING(flags); - it->global = string_indexof_char(strp, 'g', 0) >= 0; - it->unicode = (string_indexof_char(strp, 'u', 0) >= 0 || - string_indexof_char(strp, 'v', 0) >= 0); - it->done = FALSE; - JS_SetOpaque(iter, it); - - JS_FreeValue(ctx, C); - JS_FreeValue(ctx, flags); - return iter; - exception: - JS_FreeValue(ctx, S); - JS_FreeValue(ctx, C); - JS_FreeValue(ctx, flags); - JS_FreeValue(ctx, matcher); - JS_FreeValue(ctx, iter); - return JS_EXCEPTION; -} - -typedef struct ValueBuffer { - JSContext *ctx; - JSValue *arr; - JSValue def[4]; - int len; - int size; - int error_status; -} ValueBuffer; - -static int value_buffer_init(JSContext *ctx, ValueBuffer *b) -{ - b->ctx = ctx; - b->len = 0; - b->size = 4; - b->error_status = 0; - b->arr = b->def; - return 0; -} - -static void value_buffer_free(ValueBuffer *b) -{ - while (b->len > 0) - JS_FreeValue(b->ctx, b->arr[--b->len]); - if (b->arr != b->def) - js_free(b->ctx, b->arr); - b->arr = b->def; - b->size = 4; -} - -static int value_buffer_append(ValueBuffer *b, JSValue val) -{ - if (b->error_status) - return -1; - - if (b->len >= b->size) { - int new_size = (b->len + (b->len >> 1) + 31) & ~16; - size_t slack; - JSValue *new_arr; - - if (b->arr == b->def) { - new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack); - if (new_arr) - memcpy(new_arr, b->def, sizeof b->def); - } else { - new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack); - } - if (!new_arr) { - value_buffer_free(b); - JS_FreeValue(b->ctx, val); - b->error_status = -1; - return -1; - } - new_size += slack / sizeof(*new_arr); - b->arr = new_arr; - b->size = new_size; - } - b->arr[b->len++] = val; - return 0; -} - static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx) { JSValue val; @@ -31628,386 +30207,6 @@ static int js_is_standard_regexp(JSContext *ctx, JSValueConst rx) return res; } -static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // [Symbol.replace](str, rep) - JSValueConst rx = this_val, rep = argv[1]; - JSValueConst args[6]; - JSValue flags, str, rep_val, matched, tab, rep_str, namedCaptures, res; - JSString *p, *sp, *rp; - StringBuffer b_s, *b = &b_s; - ValueBuffer v_b, *results = &v_b; - int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode; - uint32_t nCaptures; - int64_t position; - - if (!JS_IsObject(rx)) - return JS_ThrowTypeErrorNotAnObject(ctx); - - string_buffer_init(ctx, b, 0); - value_buffer_init(ctx, results); - - rep_val = JS_NULL; - matched = JS_NULL; - tab = JS_NULL; - flags = JS_NULL; - rep_str = JS_NULL; - namedCaptures = JS_NULL; - - str = JS_ToString(ctx, argv[0]); - if (JS_IsException(str)) - goto exception; - - sp = JS_VALUE_GET_STRING(str); - rp = NULL; - functionalReplace = JS_IsFunction(ctx, rep); - if (!functionalReplace) { - rep_val = JS_ToString(ctx, rep); - if (JS_IsException(rep_val)) - goto exception; - rp = JS_VALUE_GET_STRING(rep_val); - } - - flags = JS_GetProperty(ctx, rx, JS_ATOM_flags); - if (JS_IsException(flags)) - goto exception; - flags = JS_ToStringFree(ctx, flags); - if (JS_IsException(flags)) - goto exception; - p = JS_VALUE_GET_STRING(flags); - - fullUnicode = 0; - is_global = (-1 != string_indexof_char(p, 'g', 0)); - if (is_global) { - fullUnicode = (string_indexof_char(p, 'u', 0) >= 0 || - string_indexof_char(p, 'v', 0) >= 0); - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) - goto exception; - } - - if (rp && rp->len == 0 && is_global && js_is_standard_regexp(ctx, rx)) { - /* use faster version for simple cases */ - res = JS_RegExpDelete(ctx, rx, str); - goto done; - } - for(;;) { - JSValue result; - result = JS_RegExpExec(ctx, rx, str); - if (JS_IsException(result)) - goto exception; - if (JS_IsNull(result)) - break; - if (value_buffer_append(results, result) < 0) - goto exception; - if (!is_global) - break; - JS_FreeValue(ctx, matched); - matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0)); - if (JS_IsException(matched)) - goto exception; - if (JS_IsEmptyString(matched)) { - /* always advance of at least one char */ - int64_t thisIndex, nextIndex; - if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0) - goto exception; - nextIndex = string_advance_index(sp, thisIndex, fullUnicode); - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0) - goto exception; - } - } - nextSourcePosition = 0; - for(j = 0; j < results->len; j++) { - JSValueConst result; - result = results->arr[j]; - if (js_get_length32(ctx, &nCaptures, result) < 0) - goto exception; - JS_FreeValue(ctx, matched); - matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0)); - if (JS_IsException(matched)) - goto exception; - if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index))) - goto exception; - if (position > sp->len) - position = sp->len; - else if (position < 0) - position = 0; - /* ignore substition if going backward (can happen - with custom regexp object) */ - JS_FreeValue(ctx, tab); - tab = JS_NewArray(ctx); - if (JS_IsException(tab)) - goto exception; - if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched), - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - for(n = 1; n < nCaptures; n++) { - JSValue capN; - capN = JS_GetPropertyInt64(ctx, result, n); - if (JS_IsException(capN)) - goto exception; - if (!JS_IsNull(capN)) { - capN = JS_ToStringFree(ctx, capN); - if (JS_IsException(capN)) - goto exception; - } - if (JS_DefinePropertyValueInt64(ctx, tab, n, capN, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - } - JS_FreeValue(ctx, namedCaptures); - namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups); - if (JS_IsException(namedCaptures)) - goto exception; - if (functionalReplace) { - if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - if (!JS_IsNull(namedCaptures)) { - if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - } - args[0] = JS_NULL; - args[1] = tab; - JS_FreeValue(ctx, rep_str); - rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0)); - } else { - JSValue namedCaptures1; - if (!JS_IsNull(namedCaptures)) { - namedCaptures1 = JS_ToObject(ctx, namedCaptures); - if (JS_IsException(namedCaptures1)) - goto exception; - } else { - namedCaptures1 = JS_NULL; - } - args[0] = matched; - args[1] = str; - args[2] = JS_NewInt32(ctx, position); - args[3] = tab; - args[4] = namedCaptures1; - args[5] = rep_val; - JS_FreeValue(ctx, rep_str); - rep_str = js_string___GetSubstitution(ctx, JS_NULL, 6, args); - JS_FreeValue(ctx, namedCaptures1); - } - if (JS_IsException(rep_str)) - goto exception; - if (position >= nextSourcePosition) { - string_buffer_concat(b, sp, nextSourcePosition, position); - string_buffer_concat_value(b, rep_str); - nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len; - } - } - string_buffer_concat(b, sp, nextSourcePosition, sp->len); - res = string_buffer_end(b); - goto done1; - -exception: - res = JS_EXCEPTION; -done: - string_buffer_free(b); -done1: - value_buffer_free(results); - JS_FreeValue(ctx, rep_val); - JS_FreeValue(ctx, matched); - JS_FreeValue(ctx, flags); - JS_FreeValue(ctx, tab); - JS_FreeValue(ctx, rep_str); - JS_FreeValue(ctx, namedCaptures); - JS_FreeValue(ctx, str); - return res; -} - -static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - JSValueConst rx = this_val; - JSValue str, previousLastIndex, currentLastIndex, result, index; - - if (!JS_IsObject(rx)) - return JS_ThrowTypeErrorNotAnObject(ctx); - - result = JS_NULL; - currentLastIndex = JS_NULL; - previousLastIndex = JS_NULL; - str = JS_ToString(ctx, argv[0]); - if (JS_IsException(str)) - goto exception; - - previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex); - if (JS_IsException(previousLastIndex)) - goto exception; - - if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) { - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) { - goto exception; - } - } - result = JS_RegExpExec(ctx, rx, str); - if (JS_IsException(result)) - goto exception; - currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex); - if (JS_IsException(currentLastIndex)) - goto exception; - if (js_same_value(ctx, currentLastIndex, previousLastIndex)) { - JS_FreeValue(ctx, previousLastIndex); - } else { - if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) { - previousLastIndex = JS_NULL; - goto exception; - } - } - JS_FreeValue(ctx, str); - JS_FreeValue(ctx, currentLastIndex); - - if (JS_IsNull(result)) { - return JS_NewInt32(ctx, -1); - } else { - index = JS_GetProperty(ctx, result, JS_ATOM_index); - JS_FreeValue(ctx, result); - return index; - } - -exception: - JS_FreeValue(ctx, result); - JS_FreeValue(ctx, str); - JS_FreeValue(ctx, currentLastIndex); - JS_FreeValue(ctx, previousLastIndex); - return JS_EXCEPTION; -} - -static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val, - int argc, JSValueConst *argv) -{ - // [Symbol.split](str, limit) - JSValueConst rx = this_val; - JSValueConst args[2]; - JSValue str, ctor, splitter, A, flags, z, sub; - JSString *strp; - uint32_t lim, size, p, q; - int unicodeMatching; - int64_t lengthA, e, numberOfCaptures, i; - - if (!JS_IsObject(rx)) - return JS_ThrowTypeErrorNotAnObject(ctx); - - ctor = JS_NULL; - splitter = JS_NULL; - A = JS_NULL; - flags = JS_NULL; - z = JS_NULL; - str = JS_ToString(ctx, argv[0]); - if (JS_IsException(str)) - goto exception; - ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor); - if (JS_IsException(ctor)) - goto exception; - flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags)); - if (JS_IsException(flags)) - goto exception; - strp = JS_VALUE_GET_STRING(flags); - unicodeMatching = (string_indexof_char(strp, 'u', 0) >= 0 || - string_indexof_char(strp, 'v', 0) >= 0); - if (string_indexof_char(strp, 'y', 0) < 0) { - flags = JS_ConcatString3(ctx, "", flags, "y"); - if (JS_IsException(flags)) - goto exception; - } - args[0] = rx; - args[1] = flags; - splitter = JS_CallConstructor(ctx, ctor, 2, args); - if (JS_IsException(splitter)) - goto exception; - A = JS_NewArray(ctx); - if (JS_IsException(A)) - goto exception; - lengthA = 0; - if (JS_IsNull(argv[1])) { - lim = 0xffffffff; - } else { - if (JS_ToUint32(ctx, &lim, argv[1]) < 0) - goto exception; - if (lim == 0) - goto done; - } - strp = JS_VALUE_GET_STRING(str); - p = q = 0; - size = strp->len; - if (size == 0) { - z = JS_RegExpExec(ctx, splitter, str); - if (JS_IsException(z)) - goto exception; - if (JS_IsNull(z)) - goto add_tail; - goto done; - } - while (q < size) { - if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0) - goto exception; - JS_FreeValue(ctx, z); - z = JS_RegExpExec(ctx, splitter, str); - if (JS_IsException(z)) - goto exception; - if (JS_IsNull(z)) { - q = string_advance_index(strp, q, unicodeMatching); - } else { - if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex))) - goto exception; - if (e > size) - e = size; - if (e == p) { - q = string_advance_index(strp, q, unicodeMatching); - } else { - sub = js_sub_string(ctx, strp, p, q); - if (JS_IsException(sub)) - goto exception; - if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, - JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - if (lengthA == lim) - goto done; - p = e; - if (js_get_length64(ctx, &numberOfCaptures, z)) - goto exception; - for(i = 1; i < numberOfCaptures; i++) { - sub = JS_GetPropertyInt64(ctx, z, i); - if (JS_IsException(sub)) - goto exception; - if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - if (lengthA == lim) - goto done; - } - q = p; - } - } - } -add_tail: - if (p > size) - p = size; - sub = js_sub_string(ctx, strp, p, size); - if (JS_IsException(sub)) - goto exception; - if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0) - goto exception; - goto done; -exception: - JS_FreeValue(ctx, A); - A = JS_EXCEPTION; -done: - JS_FreeValue(ctx, str); - JS_FreeValue(ctx, ctor); - JS_FreeValue(ctx, splitter); - JS_FreeValue(ctx, flags); - JS_FreeValue(ctx, z); - return A; -} - -static const JSCFunctionListEntry js_regexp_funcs[] = { - JS_CFUNC_DEF("escape", 1, js_regexp_escape ), -}; - static const JSCFunctionListEntry js_regexp_proto_funcs[] = { JS_CGETSET_DEF("flags", js_regexp_get_flags, NULL ), JS_CGETSET_DEF("source", js_regexp_get_source, NULL ), @@ -32021,18 +30220,7 @@ static const JSCFunctionListEntry js_regexp_proto_funcs[] = { JS_CGETSET_MAGIC_DEF("hasIndices", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ), JS_CFUNC_DEF("exec", 1, js_regexp_exec ), JS_CFUNC_DEF("compile", 2, js_regexp_compile ), - JS_CFUNC_DEF("test", 1, js_regexp_test ), JS_CFUNC_DEF("toString", 0, js_regexp_toString ), - JS_CFUNC_DEF("[Symbol.replace]", 2, js_regexp_Symbol_replace ), - JS_CFUNC_DEF("[Symbol.match]", 1, js_regexp_Symbol_match ), - JS_CFUNC_DEF("[Symbol.matchAll]", 1, js_regexp_Symbol_matchAll ), - JS_CFUNC_DEF("[Symbol.search]", 1, js_regexp_Symbol_search ), - JS_CFUNC_DEF("[Symbol.split]", 2, js_regexp_Symbol_split ), -}; - -static const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = { - JS_ITERATOR_NEXT_DEF("next", 0, js_regexp_string_iterator_next, 0 ), - JS_PROP_STRING_DEF("[Symbol.toStringTag]", "RegExp String Iterator", JS_PROP_CONFIGURABLE ), }; void JS_AddIntrinsicRegExpCompiler(JSContext *ctx) @@ -32052,13 +30240,6 @@ void JS_AddIntrinsicRegExp(JSContext *ctx) obj = JS_NewGlobalCConstructor(ctx, "RegExp", js_regexp_constructor, 2, ctx->class_proto[JS_CLASS_REGEXP]); ctx->regexp_ctor = JS_DupValue(ctx, obj); - JS_SetPropertyFunctionList(ctx, obj, js_regexp_funcs, countof(js_regexp_funcs)); - - ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] = - JS_NewObjectProto(ctx, ctx->iterator_proto); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR], - js_regexp_string_iterator_proto_funcs, - countof(js_regexp_string_iterator_proto_funcs)); } /* JSON */ @@ -37107,12 +35288,6 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) ctx->native_error_proto[i]); } - /* Iterator prototype */ - ctx->iterator_proto = JS_NewObject(ctx); - JS_SetPropertyFunctionList(ctx, ctx->iterator_proto, - js_iterator_proto_funcs, - countof(js_iterator_proto_funcs)); - /* Array */ JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY], js_array_proto_funcs, @@ -37155,11 +35330,6 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) ctx->array_proto_values = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values); - ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_ARRAY_ITERATOR], - js_array_iterator_proto_funcs, - countof(js_array_iterator_proto_funcs)); - /* String */ ctx->class_proto[JS_CLASS_STRING] = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_STRING); @@ -37169,11 +35339,6 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx) JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_funcs, countof(js_string_proto_funcs)); - ctx->class_proto[JS_CLASS_STRING_ITERATOR] = JS_NewObjectProto(ctx, ctx->iterator_proto); - JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING_ITERATOR], - js_string_iterator_proto_funcs, - countof(js_string_iterator_proto_funcs)); - /* ES6 Symbol */ ctx->class_proto[JS_CLASS_SYMBOL] = JS_NewObject(ctx); JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_SYMBOL], js_symbol_proto_funcs, diff --git a/tests/suite.cm b/tests/suite.cm index 05ae04db..4892097d 100644 --- a/tests/suite.cm +++ b/tests/suite.cm @@ -3359,38 +3359,6 @@ return { if (!caught || caught.message != "my error") throw "throw Error object failed" }, - // ============================================================================ - // REGEX TESTS - // ============================================================================ - - test_regex_test: function() { - var re = /hello/ - if (!re.test("hello world")) throw "regex test match failed" - if (re.test("goodbye world")) throw "regex test no match failed" - }, - - test_regex_test_case_sensitive: function() { - var re = /hello/ - if (re.test("HELLO")) throw "regex should be case sensitive by default" - }, - - test_regex_test_case_insensitive: function() { - var re = /hello/i - if (!re.test("HELLO")) throw "regex case insensitive failed" - }, - - test_regex_digit: function() { - var re = /\d+/ - if (!re.test("abc123")) throw "regex digit failed" - if (re.test("abc")) throw "regex digit no match failed" - }, - - test_regex_word_boundary: function() { - var re = /\bword\b/ - if (!re.test("a word here")) throw "regex word boundary failed" - if (re.test("awordhere")) throw "regex word boundary no match failed" - }, - // ============================================================================ // STRING METHOD EDGE CASES // ============================================================================