}
+njs_inline njs_int_t
+njs_array_validate_args(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_array_iterator_args_t *iargs)
+{
+ njs_int_t ret;
+
+ if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))) {
+ goto failed;
+ }
+
+ iargs->value = njs_argument(args, 0);
+
+ ret = njs_value_length(vm, iargs->value, &iargs->to);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) {
+ goto failed;
+ }
+
+ iargs->from = 0;
+ iargs->function = njs_function(njs_argument(args, 1));
+ iargs->argument = njs_arg(args, nargs, 2);
+
+ return NJS_OK;
+
+failed:
+
+ njs_type_error(vm, "unexpected iterator arguments");
+
+ return NJS_ERROR;
+}
+
+
static njs_int_t
njs_array_handler_for_each(njs_vm_t *vm, njs_array_iterator_args_t *args,
njs_value_t *entry, uint32_t n)
njs_int_t ret;
njs_array_iterator_args_t iargs;
- if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))
- || !njs_is_function(njs_arg(args, nargs, 1)))
- {
- njs_type_error(vm, "unexpected iterator arguments");
- return NJS_ERROR;
- }
-
- iargs.value = njs_argument(args, 0);
- iargs.function = njs_function(&args[1]);
- iargs.argument = njs_arg(args, nargs, 2);
-
- iargs.from = 0;
-
- ret = njs_value_length(vm, iargs.value, &iargs.to);
+ ret = njs_array_validate_args(vm, args, nargs, &iargs);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
njs_int_t ret;
njs_array_iterator_args_t iargs;
- if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))
- || !njs_is_function(njs_arg(args, nargs, 1)))
- {
- njs_type_error(vm, "unexpected iterator arguments");
- return NJS_ERROR;
- }
-
- iargs.value = njs_argument(args, 0);
- iargs.function = njs_function(&args[1]);
- iargs.argument = njs_arg(args, nargs, 2);
-
- iargs.from = 0;
-
- ret = njs_value_length(vm, iargs.value, &iargs.to);
+ ret = njs_array_validate_args(vm, args, nargs, &iargs);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
njs_int_t ret;
njs_array_iterator_args_t iargs;
- if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))
- || !njs_is_function(njs_arg(args, nargs, 1)))
- {
- njs_type_error(vm, "unexpected iterator arguments");
- return NJS_ERROR;
- }
-
- iargs.value = njs_argument(args, 0);
- iargs.function = njs_function(&args[1]);
- iargs.argument = njs_arg(args, nargs, 2);
-
- iargs.from = 0;
-
- ret = njs_value_length(vm, iargs.value, &iargs.to);
+ ret = njs_array_validate_args(vm, args, nargs, &iargs);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
njs_int_t ret;
njs_array_iterator_args_t iargs;
- if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))
- || !njs_is_function(njs_arg(args, nargs, 1)))
- {
- njs_type_error(vm, "unexpected iterator arguments");
- return NJS_ERROR;
- }
-
- iargs.value = njs_argument(args, 0);
- iargs.function = njs_function(&args[1]);
- iargs.argument = njs_arg(args, nargs, 2);
-
- iargs.from = 0;
-
- ret = njs_value_length(vm, iargs.value, &iargs.to);
+ ret = njs_array_validate_args(vm, args, nargs, &iargs);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
njs_int_t ret;
njs_array_iterator_args_t iargs;
- if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))
- || !njs_is_function(njs_arg(args, nargs, 1)))
- {
- njs_type_error(vm, "unexpected iterator arguments");
- return NJS_ERROR;
- }
-
- iargs.value = njs_argument(args, 0);
- iargs.function = njs_function(&args[1]);
- iargs.argument = njs_arg(args, nargs, 2);
-
- iargs.from = 0;
-
- ret = njs_value_length(vm, iargs.value, &iargs.to);
+ ret = njs_array_validate_args(vm, args, nargs, &iargs);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
njs_int_t ret;
njs_array_iterator_args_t iargs;
- if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))
- || !njs_is_function(njs_arg(args, nargs, 1)))
- {
- njs_type_error(vm, "unexpected iterator arguments");
- return NJS_ERROR;
- }
-
- iargs.value = njs_argument(args, 0);
- iargs.function = njs_function(&args[1]);
- iargs.argument = njs_arg(args, nargs, 2);
-
- iargs.from = 0;
-
- ret = njs_value_length(vm, iargs.value, &iargs.to);
+ ret = njs_array_validate_args(vm, args, nargs, &iargs);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
njs_array_t *array;
njs_array_iterator_args_t iargs;
- if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))
- || !njs_is_function(njs_arg(args, nargs, 1)))
- {
- njs_type_error(vm, "unexpected iterator arguments");
- return NJS_ERROR;
+ if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))) {
+ goto unexpected_args;
}
iargs.value = njs_argument(args, 0);
- iargs.function = njs_function(&args[1]);
- iargs.argument = njs_arg(args, nargs, 2);
ret = njs_value_length(vm, iargs.value, &length);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
+ if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) {
+ goto unexpected_args;
+ }
+
iargs.array = njs_array_alloc(vm, length, 0);
if (njs_slow_path(iargs.array == NULL)) {
return NJS_ERROR;
iargs.from = 0;
iargs.to = length;
+ iargs.function = njs_function(njs_argument(args, 1));
+ iargs.argument = njs_arg(args, nargs, 2);
+
ret = njs_array_iterator(vm, &iargs, njs_array_handler_map);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
njs_set_array(&vm->retval, iargs.array);
return NJS_OK;
+
+unexpected_args:
+
+ njs_type_error(vm, "unexpected iterator arguments");
+
+ return NJS_ERROR;
}
njs_value_t accumulator;
njs_array_iterator_args_t iargs;
- if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))
- || !njs_is_function(njs_arg(args, nargs, 1)))
- {
- njs_type_error(vm, "unexpected iterator arguments");
- return NJS_ERROR;
+ ret = njs_array_validate_args(vm, args, nargs, &iargs);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
}
njs_set_invalid(&accumulator);
if (nargs > 2) {
- accumulator = *njs_argument(args, 2);
+ accumulator = *iargs.argument;
}
- iargs.value = njs_argument(args, 0);
- iargs.function = njs_function(&args[1]);
iargs.argument = &accumulator;
- iargs.from = 0;
-
- ret = njs_value_length(vm, iargs.value, &iargs.to);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
-
ret = njs_array_iterator(vm, &iargs, njs_array_handler_reduce);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
njs_value_t accumulator;
njs_array_iterator_args_t iargs;
- if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))
- || !njs_is_function(njs_arg(args, nargs, 1)))
- {
- njs_type_error(vm, "unexpected iterator arguments");
- return NJS_ERROR;
+ if (njs_is_null_or_undefined(njs_arg(args, nargs, 0))) {
+ goto unexpected_args;
}
- njs_set_invalid(&accumulator);
-
iargs.value = njs_argument(args, 0);
- iargs.function = njs_function(&args[1]);
- iargs.argument = &accumulator;
- iargs.to = 0;
ret = njs_value_length(vm, iargs.value, &iargs.from);
if (njs_slow_path(ret != NJS_OK)) {
return ret;
}
+ if (njs_slow_path(!njs_is_function(njs_arg(args, nargs, 1)))) {
+ goto unexpected_args;
+ }
+
+ njs_set_invalid(&accumulator);
+
+ iargs.to = 0;
+ iargs.function = njs_function(njs_argument(args, 1));
+ iargs.argument = &accumulator;
+
if (nargs > 2) {
accumulator = *njs_argument(args, 2);
}
njs_type_error(vm, "Reduce of empty object with no initial value");
+ return NJS_ERROR;
+
+unexpected_args:
+
+ njs_type_error(vm, "unexpected iterator arguments");
+
return NJS_ERROR;
}
{ njs_str("var o = Object.freeze({0: 0, 1: 1, length: 2}); Array.prototype.pop.call(o)"),
njs_str("TypeError: Cannot delete property \"1\" of object") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.pop.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") },
+
{ njs_str("Array.prototype.shift()"),
njs_str("undefined") },
"Array.prototype.forEach.call(x, (v) => a.push(v)); a"),
njs_str("a,b,c,x,y,z,123") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.push.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") },
+
{ njs_str("var a = [1,2,3]; a.shift() +' '+ a[0] +' '+ a.length"),
njs_str("1 2 2") },
"Array.prototype.shift.call(x) +' '+ x[0] +' '+ x.length"),
njs_str("x y 2") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.shift.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") },
+
{ njs_str("var a = [1,2], len = a.unshift(3);"
"len +' '+ a +' '+ a.shift()"),
njs_str("3 3,1,2 3") },
"Array.prototype.forEach.call(obj, (v) => a.push(v)); a"),
njs_str("a,b,c,x,y,z")},
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.unshift.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: Cannot set property \"length\" of object which has only a getter") },
+
{ njs_str("var a=[0], n = 64; while(--n) {a.push(n); a.shift()}; a"),
njs_str("1") },
"Array.prototype.indexOf.call(o, 'd')"),
njs_str("3") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "Array.prototype.indexOf.call(o); i"),
+ njs_str("1") },
+
{ njs_str("[].lastIndexOf(1, -1)"),
njs_str("-1") },
"Array.prototype.lastIndexOf.call(obj, 'y');"),
njs_str("10000001")},
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "Array.prototype.lastIndexOf.call(o); i"),
+ njs_str("1") },
+
{ njs_str("[1,2,3,4].includes()"),
njs_str("false") },
"Array.prototype.forEach.call(s, function (a, b, c) {t = typeof c;}); [t, typeof s];"),
njs_str("object,string") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.forEach.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: unexpected iterator arguments") },
+
{ njs_str("var a = [];"
"a.some(function(v, i, a) { return v > 1 })"),
njs_str("false") },
"var r = Array.prototype.some.call(o, function(v, i, a) { return v === 'd' }); r"),
njs_str("true") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.some.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: unexpected iterator arguments") },
+
{ njs_str("var a = [];"
"a.every(function(v, i, a) { return v > 1 })"),
njs_str("true") },
"var r = Array.prototype.every.call(o, function(el, i, arr) {return el == 'c'}); r"),
njs_str("true") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.every.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: unexpected iterator arguments") },
+
{ njs_str("var o = {0: 'x', 1: 'y', 2: 'z'};"
"Object.defineProperty(o, 'length', {get: () => 4});"
"Object.defineProperty(o, '3', {get: () => 'a'});"
njs_str("RangeError: Maximum call stack size exceeded") },
#endif
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "Array.prototype.fill.call(o); i"),
+ njs_str("1") },
+
{ njs_str("var a = [];"
"a.filter(function(v, i, a) { return v > 1 })"),
njs_str("") },
"var r = Array.prototype.filter.call(o, function(el, i, arr) { return el == 'c' }); r"),
njs_str("c,c") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.filter.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: unexpected iterator arguments") },
+
{ njs_str("var a = [];"
"a.find(function(v, i, a) { return v > 1 })"),
njs_str("undefined") },
"var r = Array.prototype.find.call(o, function(el, i, arr) { return el == 'd' }); r"),
njs_str("d") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.find.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: unexpected iterator arguments") },
+
{ njs_str("var a = [];"
"a.findIndex(function(v, i, a) { return v > 1 })"),
njs_str("-1") },
"var r = Array.prototype.findIndex.call(o, function(el, i, arr) { return el == 'd' }); r"),
njs_str("3") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.findIndex.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: unexpected iterator arguments") },
+
{ njs_str("var a = [];"
"a.map(function(v, i, a) { return v + 1 })"),
njs_str("") },
"var res = Array.prototype.map.call(obj, callbackfn); typeof res[8000]"),
njs_str("undefined") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.map.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: unexpected iterator arguments") },
+
{ njs_str("var a = [];"
"a.reduce(function(p, v, i, a) { return p + v })"),
njs_str("TypeError: Reduce of empty object with no initial value") },
"var r = Array.prototype.reduce.call(o, (a, b) => a + b); r"),
njs_str("abcd") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.reduce.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: unexpected iterator arguments") },
+
{ njs_str("var a = [];"
"a.reduceRight(function(p, v, i, a) { return p + v })"),
njs_str("TypeError: Reduce of empty object with no initial value") },
"Array.prototype.reduceRight.call(o, (p, v) => p + v)"),
njs_str("dcba") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "try {Array.prototype.reduceRight.call(o);}"
+ "catch (e) {i += '; ' + e} i"),
+ njs_str("1; TypeError: unexpected iterator arguments") },
+
{ njs_str("var a = ['1','2','3','4','5','6']; a.sort()"),
njs_str("1,2,3,4,5,6") },
{ njs_str("'абв абв абвгдежз'.includes('абвгд', 9)"),
njs_str("false") },
+ { njs_str("var i = 0; var o = {get length() {i++}};"
+ "Array.prototype.includes.call(o); i"),
+ njs_str("1") },
+
{ njs_str("''.startsWith('')"),
njs_str("true") },