diff --git a/pl_duk.c b/pl_duk.c index 2a7e50b..1e1717f 100644 --- a/pl_duk.c +++ b/pl_duk.c @@ -83,16 +83,28 @@ static SV* pl_duk_to_perl_impl(pTHX_ duk_context* ctx, int pos, HV* seen) array_top = duk_get_length(ctx, pos); for (j = 0; j < array_top; ++j) { SV* nested = 0; - if (!duk_get_prop_index(ctx, pos, j)) { - continue; /* index doesn't exist => end of array */ - } - nested = sv_2mortal(pl_duk_to_perl_impl(aTHX_ ctx, -1, seen)); - duk_pop(ctx); /* value in current pos */ - if (!nested) { - croak("Could not create Perl SV for array\n"); + + bool exists = duk_get_prop_index(ctx, pos, j); + + /* NB: A nonexistent array value does NOT mean that */ + /* we are at the end of the array; for example, you */ + /* can do `foo[1] = 1` without defining `foo[0]`. */ + + if (exists) { + nested = sv_2mortal(pl_duk_to_perl_impl(aTHX_ ctx, -1, seen)); } - if (av_store(values_array, j, nested)) { - SvREFCNT_inc(nested); + + /* Even if the array value is nonexistent we still */ + /* have to remove it from the stack. */ + duk_pop(ctx); + + if (exists) { + if (!nested) { + croak("Could not create Perl SV for array\n"); + } + if (av_store(values_array, j, nested)) { + SvREFCNT_inc(nested); + } } } } diff --git a/t/26_eval_returns_undef_in_array.t b/t/26_eval_returns_undef_in_array.t new file mode 100644 index 0000000..604bfc7 --- /dev/null +++ b/t/26_eval_returns_undef_in_array.t @@ -0,0 +1,36 @@ +use strict; +use warnings; + +use Test::More; + +use blib; + +use JavaScript::Duktape::XS; + +my $js = JavaScript::Duktape::XS->new(); + +my $got = $js->eval('var foo = []; foo[1] = 123; foo'); + +is_deeply( + $got, + [undef, 123], + '[(empty), 123]', +) or diag explain $got; + +$got = $js->eval('var foo = []; foo[1] = undefined; foo'); + +is_deeply( + $got, + [undef, undef], + '[(empty), undefined]', +) or diag explain $got; + +$got = $js->eval('[undefined, undefined]'); + +is_deeply( + $got, + [undef, undef], + '[undefined, undefined]', +) or diag explain $got; + +done_testing;