details: https://hg.nginx.org/njs/rev/4d26300ddc64 branches: changeset: 2123:4d26300ddc64 user: Dmitry Volyntsev <xei...@nginx.com> date: Thu May 18 18:33:36 2023 -0700 description: Implemented Array.from().
diffstat: src/njs_array.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ src/njs_typed_array.c | 12 +----- src/njs_value.c | 19 ++++++++++ src/njs_value.h | 2 + src/njs_vmcode.c | 2 + src/test/njs_unit_test.c | 34 +++++++++++++++++- 6 files changed, 148 insertions(+), 12 deletions(-) diffs (236 lines): diff -r 25b55a064e42 -r 4d26300ddc64 src/njs_array.c --- a/src/njs_array.c Wed May 17 21:16:19 2023 -0700 +++ b/src/njs_array.c Thu May 18 18:33:36 2023 -0700 @@ -483,6 +483,95 @@ njs_array_constructor(njs_vm_t *vm, njs_ static njs_int_t +njs_array_from(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, + njs_index_t unused, njs_value_t *retval) +{ + int64_t length, i; + njs_int_t ret; + njs_array_t *array; + njs_value_t *this, *items, *mapfn; + njs_value_t arguments[3], value, result; + njs_function_t *function; + + mapfn = njs_arg(args, nargs, 2); + + if (njs_slow_path(!njs_is_function_or_undefined(mapfn))) { + njs_type_error(vm, "\"mapfn\" argument is not callable"); + return NJS_ERROR; + } + + function = NULL; + if (njs_is_function(mapfn)) { + function = njs_function(mapfn); + } + + items = njs_arg(args, nargs, 1); + + ret = njs_value_to_object(vm, items); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + ret = njs_object_length(vm, items, &length); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + this = njs_argument(args, 0); + + if (njs_is_constructor(this)) { + njs_set_number(&arguments[0], length); + + ret = njs_value_construct(vm, this, arguments, 1, &value); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + + } else { + array = njs_array_alloc(vm, 1, length, 0); + if (njs_slow_path(array == NULL)) { + return NJS_ERROR; + } + + njs_set_array(&value, array); + } + + arguments[0] = *njs_arg(args, nargs, 3); + + for (i = 0; i < length; i++) { + ret = njs_value_property_i64(vm, items, i, &result); + if (njs_slow_path(ret == NJS_ERROR)) { + return NJS_ERROR; + } + + if (function != NULL) { + njs_value_assign(&arguments[1], &result); + njs_set_number(&arguments[2], i); + + ret = njs_function_apply(vm, function, arguments, 3, &result); + if (njs_slow_path(ret != NJS_OK)) { + return NJS_ERROR; + } + } + + ret = njs_value_create_data_prop_i64(vm, &value, i, &result, 0); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + } + + ret = njs_object_length_set(vm, &value, length); + if (njs_slow_path(ret == NJS_ERROR)) { + return ret; + } + + njs_value_assign(retval, &value); + + return NJS_OK; +} + + +static njs_int_t njs_array_is_array(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { @@ -526,6 +615,8 @@ static const njs_object_prop_t njs_arra NJS_DECLARE_PROP_HANDLER("prototype", njs_object_prototype_create, 0, 0, 0), + NJS_DECLARE_PROP_NATIVE("from", njs_array_from, 1, 0), + NJS_DECLARE_PROP_NATIVE("isArray", njs_array_is_array, 1, 0), NJS_DECLARE_PROP_NATIVE("of", njs_array_of, 0, 0), diff -r 25b55a064e42 -r 4d26300ddc64 src/njs_typed_array.c --- a/src/njs_typed_array.c Wed May 17 21:16:19 2023 -0700 +++ b/src/njs_typed_array.c Thu May 18 18:33:36 2023 -0700 @@ -222,19 +222,9 @@ njs_typed_array_create(njs_vm_t *vm, njs njs_value_t *args, njs_uint_t nargs, njs_value_t *retval) { njs_int_t ret; - njs_value_t this; - njs_object_t *object; njs_typed_array_t *array; - object = njs_function_new_object(vm, constructor); - if (njs_slow_path(object == NULL)) { - return NJS_ERROR; - } - - njs_set_object(&this, object); - - ret = njs_function_call2(vm, njs_function(constructor), &this, args, - nargs, retval, 1); + ret = njs_value_construct(vm, constructor, args, nargs, retval); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } diff -r 25b55a064e42 -r 4d26300ddc64 src/njs_value.c --- a/src/njs_value.c Wed May 17 21:16:19 2023 -0700 +++ b/src/njs_value.c Thu May 18 18:33:36 2023 -0700 @@ -1681,6 +1681,25 @@ njs_symbol_conversion_failed(njs_vm_t *v njs_int_t +njs_value_construct(njs_vm_t *vm, njs_value_t *constructor, njs_value_t *args, + njs_uint_t nargs, njs_value_t *retval) +{ + njs_value_t this; + njs_object_t *object; + + object = njs_function_new_object(vm, constructor); + if (njs_slow_path(object == NULL)) { + return NJS_ERROR; + } + + njs_set_object(&this, object); + + return njs_function_call2(vm, njs_function(constructor), &this, args, + nargs, retval, 1); +} + + +njs_int_t njs_value_species_constructor(njs_vm_t *vm, njs_value_t *object, njs_value_t *default_constructor, njs_value_t *dst) { diff -r 25b55a064e42 -r 4d26300ddc64 src/njs_value.h --- a/src/njs_value.h Wed May 17 21:16:19 2023 -0700 +++ b/src/njs_value.h Thu May 18 18:33:36 2023 -0700 @@ -1090,6 +1090,8 @@ njs_int_t njs_value_to_object(njs_vm_t * void njs_symbol_conversion_failed(njs_vm_t *vm, njs_bool_t to_string); +njs_int_t njs_value_construct(njs_vm_t *vm, njs_value_t *constructor, + njs_value_t *args, njs_uint_t nargs, njs_value_t *retval); njs_int_t njs_value_species_constructor(njs_vm_t *vm, njs_value_t *object, njs_value_t *default_constructor, njs_value_t *dst); diff -r 25b55a064e42 -r 4d26300ddc64 src/njs_vmcode.c --- a/src/njs_vmcode.c Wed May 17 21:16:19 2023 -0700 +++ b/src/njs_vmcode.c Thu May 18 18:33:36 2023 -0700 @@ -2536,6 +2536,8 @@ njs_function_new_object(njs_vm_t *vm, nj return NULL; } + njs_assert(njs_is_function(constructor)); + function = njs_function(constructor); if (function->bound != NULL) { diff -r 25b55a064e42 -r 4d26300ddc64 src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed May 17 21:16:19 2023 -0700 +++ b/src/test/njs_unit_test.c Thu May 18 18:33:36 2023 -0700 @@ -4561,6 +4561,38 @@ static njs_unit_test_t njs_test[] = { njs_str("Array.isArray([]) ? 'true' : 'false'"), njs_str("true") }, + { njs_str("[" + " [undefined]," + " [null]," + " ['foo']," + " ['foo', c => c.toUpperCase()]," + " [{length: 3, 1:'a', 2:'b'}]," + " [[7,,9], v => v*2]," + "].map(args => { try { return Array.from.apply(Array,args) }" + " catch (e) {return e.toString()}})"), + njs_str("TypeError: cannot convert null or undefined to object," + "TypeError: cannot convert null or undefined to object," + "f,o,o," + "F,O,O," + ",a,b," + "14,NaN,18" + ) }, + + { njs_str("function f() {return Array.from(arguments);}; f(1,2,3)"), + njs_str("1,2,3") }, + + { njs_str("Array.from({ length: 5 }, (v, i) => i)"), + njs_str("0,1,2,3,4") }, + + { njs_str("const range = (start, stop, step) =>" + "Array.from({ length: (stop - start) / step + 1 }, (_, i) => start + i * step);" + "range(1, 10, 2)"), + njs_str("1,3,5,7,9") }, + + { njs_str("var a = Array.from.call(Object, { length: 2, 0:7, 1:9 });" + "[a[0], a[1], Array.isArray(a)]"), + njs_str("7,9,false") }, + { njs_str("Array.of()"), njs_str("") }, @@ -15282,7 +15314,7 @@ static njs_unit_test_t njs_test[] = njs_str("length,name,prototype") }, { njs_str("Object.getOwnPropertyNames(Array)"), - njs_str("name,length,prototype,isArray,of") }, + njs_str("name,length,prototype,from,isArray,of") }, { njs_str("Object.getOwnPropertyNames(Array.isArray)"), njs_str("name,length") }, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel