t/00-load.t
t/01-import.t
t/05-words.t
+t/06-want_at.t
t/11-reap-level.t
t/12-reap-block.t
t/13-reap-ctl.t
ST(0) = sv_2mortal(newSViv(level));
XSRETURN(1);
+void
+want_at(...)
+PROTOTYPE: ;$
+PREINIT:
+ I32 cxix = cxstack_ix, level = 0;
+PPCODE:
+ if (items) {
+ SV *lsv = ST(0);
+ if (SvOK(lsv))
+ level = SvIV(lsv);
+ if (level < 0)
+ level = 0;
+ else if (level > cxix)
+ level = cxix;
+ }
+ cxix -= level;
+ while (cxix > 0) {
+ PERL_CONTEXT *cx = cxstack + cxix--;
+ switch (CxTYPE(cx)) {
+ case CXt_SUB:
+ case CXt_EVAL:
+ case CXt_FORMAT: {
+ I32 gimme = cx->blk_gimme;
+ switch (gimme) {
+ case G_VOID: XSRETURN_UNDEF; break;
+ case G_SCALAR: XSRETURN_NO; break;
+ case G_ARRAY: XSRETURN_YES; break;
+ }
+ break;
+ }
+ }
+ }
+ XSRETURN_UNDEF;
+
void
reap(SV *hook, ...)
PROTOTYPE: &;$
Returns C<@values> I<from> the context indicated by C<$level>, i.e. from the subroutine, eval or format just above C<$level>.
The upper level isn't coerced onto C<@values>, which is hence always evaluated in list context.
+=head2 C<want_at $level>
+
+Like C<wantarray>, but for the subroutine/eval/format context just above C<$level>.
+
=head1 WORDS
=head2 C<TOP>
=head1 EXPORT
-The functions L</reap>, L</localize>, L</localize_elem>, L</localize_delete> and L</unwind> are only exported on request, either individually or by the tags C<':funcs'> and C<':all'>.
+The functions L</reap>, L</localize>, L</localize_elem>, L</localize_delete>, L</unwind> and L</want_at> are only exported on request, either individually or by the tags C<':funcs'> and C<':all'>.
Same goes for the words L</TOP>, L</HERE>, L</UP>, L</DOWN>, L</SUB>, L</EVAL> and L</CALLER> that are only exported on request, individually or by the tags C<':words'> and C<':all'>.
our @EXPORT = ();
our %EXPORT_TAGS = (
- funcs => [ qw/reap localize localize_elem localize_delete unwind/ ],
+ funcs => [ qw/reap localize localize_elem localize_delete unwind want_at/ ],
words => [ qw/TOP HERE UP DOWN SUB EVAL CALLER/ ],
);
our @EXPORT_OK = map { @$_ } values %EXPORT_TAGS;
use strict;
use warnings;
-use Test::More tests => 12;
+use Test::More tests => 13;
require Scope::Upper;
-for (qw/reap localize localize_elem localize_delete unwind TOP HERE UP DOWN SUB EVAL CALLER/) {
+for (qw/reap localize localize_elem localize_delete unwind want_at TOP HERE UP DOWN SUB EVAL CALLER/) {
eval { Scope::Upper->import($_) };
is($@, '', 'import ' . $_);
}
--- /dev/null
+#!perl -T
+
+use strict;
+use warnings;
+
+use Test::More tests => 16;
+
+use Scope::Upper qw/want_at/;
+
+sub check {
+ my ($w, $exp, $desc) = @_;
+ my $cx = sub {
+ my $a = shift;
+ if (!defined $a) {
+ return 'void';
+ } elsif ($a) {
+ return 'list';
+ } else {
+ return 'scalar';
+ }
+ };
+ is $cx->($w), $cx->($exp), $desc;
+}
+
+my $w;
+
+check want_at, undef, 'main : want_at';
+check want_at(0), undef, 'main : want_at(0)';
+check want_at(1), undef, 'main : want_at(1)';
+check want_at(-1), undef, 'main : want_at(-1)';
+
+my @a = sub {
+ check want_at, 1, 'sub0 : want_at';
+ {
+ check want_at, 1, 'sub : want_at';
+ check want_at(1), 1, 'sub : want_at(1)';
+ for (1) {
+ check want_at, 1, 'for : want_at';
+ check want_at(1), 1, 'for : want_at(1)';
+ check want_at(2), 1, 'for : want_at(2)';
+ }
+ my $x = eval {
+ do {
+ check want_at, 0, 'do : want_at';
+ check want_at(1), 0, 'do : want_at(0)';
+ check want_at(2), 1, 'do : want_at(1)';
+ };
+ check want_at, 0, 'eval : want_at';
+ check want_at(1), 1, 'eval : want_at(0)';
+ check want_at(2), 1, 'eval : want_at(1)';
+ };
+ }
+}->();