From 22953f60cfb3d589219e8b8e3fa40979c4077c10 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Wed, 20 Mar 2013 10:40:32 +0200 Subject: [PATCH] initial implementations for Array.prototype every(), some(), forEach(), map(), filter() --- src/duk_builtin_array.c | 143 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 138 insertions(+), 5 deletions(-) diff --git a/src/duk_builtin_array.c b/src/duk_builtin_array.c index 3c6a7c97..ef355817 100644 --- a/src/duk_builtin_array.c +++ b/src/duk_builtin_array.c @@ -184,26 +184,159 @@ int duk_builtin_array_prototype_last_index_of(duk_context *ctx) { return DUK_RET_UNIMPLEMENTED_ERROR; /*FIXME*/ } +/* + * every(), some(), forEach(), map(), filter() + */ + +#define ITER_EVERY 0 +#define ITER_SOME 1 +#define ITER_FOREACH 2 +#define ITER_MAP 3 +#define ITER_FILTER 4 + +/* FIXME: This helper is a bit awkward because the handling for the different iteration + * callers is quite different. This now compiles to a bit less than 500 bytes, so with + * 5 callers the net result is about 100 bytes / caller. + */ + +static int iter_helper(duk_context *ctx, int iter_type) { + int len; + int i; + int k; + int bval; + + /* each call this helper serves has nargs==2 */ + DUK_ASSERT_TOP(ctx, 2); + + duk_push_this_coercible_to_object(ctx); + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH); + len = duk_to_uint32(ctx, -1); + if (!duk_is_callable(ctx, 0)) { + goto type_error; + } + /* if thisArg not supplied, behave as if undefined was supplied */ + + if (iter_type == ITER_MAP || iter_type == ITER_FILTER) { + duk_push_new_array(ctx); + } else { + duk_push_undefined(ctx); + } + + /* stack[0] = callback + * stack[1] = thisArg + * stack[2] = object + * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop) + * stack[4] = result array (or undefined) + */ + + k = 0; /* result index for filter() */ + for (i = 0; i < len; i++) { + DUK_ASSERT_TOP(ctx, 5); + + if (!duk_has_prop_index(ctx, 2, i)) { + continue; + } + + /* The original value needs to be preserved for filter(), hence + * this funny order. We can't re-get the value because of side + * effects. + */ + duk_get_prop_index(ctx, 2, i); + + duk_dup(ctx, 0); + duk_dup(ctx, 1); + duk_dup(ctx, -3); + duk_push_int(ctx, i); + duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */ + duk_call_method(ctx, 3); /* -> [ ... val retval ] */ + + switch (iter_type) { + case ITER_EVERY: + bval = duk_to_boolean(ctx, -1); + if (!bval) { + return 1; + } + break; + case ITER_SOME: { + bval = duk_to_boolean(ctx, -1); + if (bval) { + return 1; + } + break; + case ITER_FOREACH: + /* nop */ + break; + case ITER_MAP: + duk_dup(ctx, -1); + duk_put_prop_index(ctx, 4, i); /* retval to result[i] */ + break; + case ITER_FILTER: + bval = duk_to_boolean(ctx, -1); + if (bval) { + duk_dup(ctx, -2); /* orig value */ + duk_put_prop_index(ctx, 4, k); + k++; + } + break; + default: + DUK_NEVER_HERE(); + break; + } + duk_pop_2(ctx); + + DUK_ASSERT_TOP(ctx, 5); + } + + switch (iter_type) { + case ITER_EVERY: + duk_push_true(ctx); + break; + case ITER_SOME: + duk_push_false(ctx); + break; + case ITER_FOREACH: + duk_push_undefined(ctx); + break; + case ITER_MAP: + case ITER_FILTER: + DUK_ASSERT_TOP(ctx, 5); + DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */ + break; + default: + DUK_NEVER_HERE(); + break; + } + + return 1; + + type_error: + return DUK_RET_TYPE_ERROR; +} + int duk_builtin_array_prototype_every(duk_context *ctx) { - return DUK_RET_UNIMPLEMENTED_ERROR; /*FIXME*/ + return iter_helper(ctx, ITER_EVERY); } int duk_builtin_array_prototype_some(duk_context *ctx) { - return DUK_RET_UNIMPLEMENTED_ERROR; /*FIXME*/ + return iter_helper(ctx, ITER_SOME); } int duk_builtin_array_prototype_for_each(duk_context *ctx) { - return DUK_RET_UNIMPLEMENTED_ERROR; /*FIXME*/ + return iter_helper(ctx, ITER_FOREACH); } int duk_builtin_array_prototype_map(duk_context *ctx) { - return DUK_RET_UNIMPLEMENTED_ERROR; /*FIXME*/ + return iter_helper(ctx, ITER_MAP); } int duk_builtin_array_prototype_filter(duk_context *ctx) { - return DUK_RET_UNIMPLEMENTED_ERROR; /*FIXME*/ + return iter_helper(ctx, ITER_FILTER); } +/* + * reduce(), reduceRight() + */ + static int reduce_helper(duk_context *ctx, int idx_step) { int nargs; int have_acc;