Scope::Upper - Act on upper scopes.
VERSION
- Version 0.19
+ Version 0.33
SYNOPSIS
"reap", "localize", "localize_elem", "localize_delete" and "WORDS" :
higher contexts with respectively "localize", "localize_elem" and
"localize_delete" ;
- * return values immediately to an upper level with "unwind", and know
- which context was in use then with "want_at" ;
+ * return values immediately to an upper level with "unwind", "yield"
+ and "leave" ;
+
+ * gather information about an upper context with "want_at" and
+ "context_info" ;
* execute a subroutine in the setting of an upper subroutine stack
frame with "uplevel" ;
- * uniquely identify contextes with "uid" and "validate_uid".
+ * uniquely identify contexts with "uid" and "validate_uid".
FUNCTIONS
In all those functions, $context refers to the target scope.
will be vivified as soon as the localization occurs and emptied when it
ends, although it will still exist in its glob.
- "localize_delete $what, $key, $context"
+ "localize_delete"
+ localize_delete $what, $key;
+ localize_delete $what, $key, $context;
+
Introduces the deletion of a variable or an array/hash element delayed
to the time of first return into the upper scope denoted by $context.
$what can be:
"local *x".
* A string beginning with '@' or '%', for which the call is equivalent
- to respectiveley "local $a[$key]; delete $a[$key]" and "local
+ to respectively "local $a[$key]; delete $a[$key]" and "local
$h{$key}; delete $h{$key}".
* A string beginning with '&', which more or less does "undef &func"
"exists" anymore. $key is ignored.
"unwind"
- unwind @values;
+ unwind;
unwind @values, $context;
- Returns @values *from* the context pointed by $context, i.e. from the
- subroutine, eval or format at or just above $context, and immediately
- restart the program flow at this point - thus effectively returning to
- an upper scope.
+ Returns @values *from* the subroutine, eval or format context pointed by
+ or just above $context, and immediately restarts the program flow at
+ this point - thus effectively returning @values to an upper scope. If
+ @values is empty, then the $context parameter is optional and defaults
+ to the current context (making the call equivalent to a bare "return;")
+ ; otherwise it is mandatory.
The upper context isn't coerced onto @values, which is hence always
evaluated in list context. This means that
will set $num to 'z'. You can use "want_at" to handle these cases.
+ "yield"
+ yield;
+ yield @values, $context;
+
+ Returns @values *from* the context pointed by or just above $context,
+ and immediately restarts the program flow at this point. If @values is
+ empty, then the $context parameter is optional and defaults to the
+ current context ; otherwise it is mandatory.
+
+ "yield" differs from "unwind" in that it can target *any* upper scope
+ (besides a "s///e" substitution context) and not necessarily a sub, an
+ eval or a format. Hence you can use it to return values from a "do" or a
+ "map" block :
+
+ my $now = do {
+ local $@;
+ eval { require Time::HiRes } or yield time() => HERE;
+ Time::HiRes::time();
+ };
+
+ my @uniq = map {
+ yield if $seen{$_}++; # returns the empty list from the block
+ ...
+ } @things;
+
+ Like for "unwind", the upper context isn't coerced onto @values. You can
+ use the fifth value returned by "context_info" to handle context
+ coercion.
+
+ "leave"
+ leave;
+ leave @values;
+
+ Immediately returns @values from the current block, whatever it may be
+ (besides a "s///e" substitution context). "leave" is actually a synonym
+ for "yield HERE", while "leave @values" is a synonym for "yield @values,
+ HERE".
+
+ Like for "yield", you can use the fifth value returned by "context_info"
+ to handle context coercion.
+
"want_at"
my $want = want_at;
my $want = want_at $context;
- Like "wantarray", but for the subroutine/eval/format at or just above
- $context.
+ Like "wantarray" in perlfunc, but for the subroutine, eval or format
+ context located at or just above $context.
- The previous example can then be "corrected" :
+ It can be used to revise the example showed in "unwind" :
my $num = sub {
my @a = ('a' .. 'z');
will rightfully set $num to 26.
- "uplevel $code, @args, $context"
+ "context_info"
+ my ($package, $filename, $line, $subroutine, $hasargs,
+ $wantarray, $evaltext, $is_require, $hints, $bitmask,
+ $hinthash) = context_info $context;
+
+ Gives information about the context denoted by $context, akin to what
+ "caller" in perlfunc provides but not limited only to subroutine, eval
+ and format contexts. When $context is omitted, it defaults to the
+ current context.
+
+ The returned values are, in order :
+
+ * *(index 0)* : the namespace in use when the context was created ;
+
+ * *(index 1)* : the name of the file at the point where the context
+ was created ;
+
+ * *(index 2)* : the line number at the point where the context was
+ created ;
+
+ * *(index 3)* : the name of the subroutine called for this context, or
+ "undef" if this is not a subroutine context ;
+
+ * *(index 4)* : a boolean indicating whether a new instance of @_ was
+ set up for this context, or "undef" if this is not a subroutine
+ context ;
+
+ * *(index 5)* : the context (in the sense of "wantarray" in perlfunc)
+ in which the context (in our sense) is executed ;
+
+ * *(index 6)* : the contents of the string being compiled for this
+ context, or "undef" if this is not an eval context ;
+
+ * *(index 7)* : a boolean indicating whether this eval context was
+ created by "require", or "undef" if this is not an eval context ;
+
+ * *(index 8)* : the value of the lexical hints in use when the context
+ was created ;
+
+ * *(index 9)* : a bit string representing the warnings in use when the
+ context was created ;
+
+ * *(index 10)* : a reference to the lexical hints hash in use when the
+ context was created (only on perl 5.10 or greater).
+
+ "uplevel"
my @ret = uplevel { ...; return @ret };
- my @ret = uplevel { my @args = @_; ...; return @ret } @args;
- my @ret = uplevel { ... } @args, $context;
+ my @ret = uplevel { my @args = @_; ...; return @ret } @args, $context;
my @ret = &uplevel($callback, @args, $context);
- Executes the code reference $code with arguments @args as if it were
+ Executes the code reference $callback with arguments @args as if it were
located at the subroutine stack frame pointed by $context, effectively
fooling "caller" and "die" into believing that the call actually
happened higher in the stack. The code is executed in the context of the
my @inverses = target(1, 2, 4); # @inverses contains (0, 0.5, 0.25)
my $count = target(1, 2, 4); # $count is 3
+ Note that if @args is empty, then the $context parameter is optional and
+ defaults to the current context ; otherwise it is mandatory.
+
Sub::Uplevel also implements a pure-Perl version of "uplevel". Both are
identical, with the following caveats :
Getting a context from a context
For any of those functions, $from is expected to be a context. When
- omitted, it defaults to the the current context.
+ omitted, it defaults to the current context.
"UP"
my $upper_context = UP;
my $upper_context = UP $from;
- The context of the scope just above $from.
+ The context of the scope just above $from. If $from points to the
+ top-level scope in the current stack, then a warning is emitted and
+ $from is returned (see "DIAGNOSTICS" for details).
"SUB"
my $sub_context = SUB;
my $sub_context = SUB $from;
- The context of the closest subroutine above $from. Note that $from is
- returned if it is already a subroutine context ; hence "SUB SUB == SUB".
+ The context of the closest subroutine above $from. If $from already
+ designates a subroutine context, then it is returned as-is ; hence "SUB
+ SUB == SUB". If no subroutine context is present in the call stack, then
+ a warning is emitted and the current context is returned (see
+ "DIAGNOSTICS" for details).
"EVAL"
my $eval_context = EVAL;
my $eval_context = EVAL $from;
- The context of the closest eval above $from. Note that $from is returned
- if it is already an eval context ; hence "EVAL EVAL == EVAL".
+ The context of the closest eval above $from. If $from already designates
+ an eval context, then it is returned as-is ; hence "EVAL EVAL == EVAL".
+ If no eval context is present in the call stack, then a warning is
+ emitted and the current context is returned (see "DIAGNOSTICS" for
+ details).
Getting a context from a level
Here, $level should denote a number of scopes above the current one.
my $context = SCOPE;
my $context = SCOPE $level;
- The $level-th upper context, regardless of its type.
+ The $level-th upper context, regardless of its type. If $level points
+ above the top-level scope in the current stack, then a warning is
+ emitted and the top-level context is returned (see "DIAGNOSTICS" for
+ details).
"CALLER"
my $context = CALLER;
The context of the $level-th upper subroutine/eval/format. It kind of
corresponds to the context represented by "caller $level", but while
e.g. "caller 0" refers to the caller context, "CALLER 0" will refer to
- the top scope in the current context.
+ the top scope in the current context. If $level points above the
+ top-level scope in the current stack, then a warning is emitted and the
+ top-level context is returned (see "DIAGNOSTICS" for details).
Examples
Where "reap" fires depending on the $cxt :
# $cxt = SCOPE(4), UP SUB UP SUB = UP SUB EVAL = UP CALLER(2) = TOP
...
- Where "unwind", "want_at" and "uplevel" point to depending on the $cxt:
+ Where "unwind", "yield", "want_at", "context_info" and "uplevel" point
+ to depending on the $cxt:
sub {
eval {
sub {
{
- unwind @things => $cxt; # or uplevel { ... } $cxt;
+ unwind @things => $cxt; # or yield @things => $cxt
+ # or uplevel { ... } $cxt
...
}
...
# (*) Note that uplevel() will croak if you pass that scope frame,
# because it cannot target eval scopes.
+DIAGNOSTICS
+ "Cannot target a scope outside of the current stack"
+ This warning is emitted when "UP", "SCOPE" or "CALLER" end up pointing
+ to a context that is above the top-level context of the current stack.
+ It indicates that you tried to go higher than the main scope, or to
+ point across a "DESTROY" method, a signal handler, an overloaded or tied
+ method call, a "require" statement or a "sort" callback. In this case,
+ the resulting context is the highest reachable one.
+
+ "No targetable %s scope in the current stack"
+ This warning is emitted when you ask for an "EVAL" or "SUB" context and
+ no such scope can be found in the call stack. The resulting context is
+ the current one.
+
EXPORT
The functions "reap", "localize", "localize_elem", "localize_delete",
- "unwind", "want_at" and "uplevel" are only exported on request, either
- individually or by the tags ':funcs' and ':all'.
+ "unwind", "yield", "leave", "want_at", "context_info" and "uplevel" are
+ only exported on request, either individually or by the tags ':funcs'
+ and ':all'.
The constant "SU_THREADSAFE" is also only exported on request,
individually or by the tags ':consts' and ':all'.
':words' and ':all'.
CAVEATS
+ It is not possible to act upon a scope that belongs to another perl
+ 'stack', i.e. to target a scope across a "DESTROY" method, a signal
+ handler, an overloaded or tied method call, a "require" statement or a
+ "sort" callback.
+
Be careful that local variables are restored in the reverse order in
which they were localized. Consider those examples:
Moreover, in order to handle "goto" statements properly, "uplevel"
currently has to suffer a run-time overhead proportional to the size of
- the the callback in every case (with a small ratio), and proportional to
- the size of all the code executed as the result of the "uplevel" call
+ the callback in every case (with a small ratio), and proportional to the
+ size of all the code executed as the result of the "uplevel" call
(including subroutine calls inside the callback) when a "goto" statement
is found in the "uplevel" callback. Despite this shortcoming, this XS
version of "uplevel" should still run way faster than the pure-Perl
version from Sub::Uplevel.
+ Starting from "perl" 5.19.4, it is unfortunately no longer possible to
+ reliably throw exceptions from "uplevel"'d code while the debugger is in
+ use. This may be solved in a future version depending on how the core
+ evolves.
+
DEPENDENCIES
- XSLoader (standard since perl 5.006).
+ perl 5.6.1.
+
+ A C compiler. This module may happen to build with a C++ compiler as
+ well, but don't rely on it, as no guarantee is made in this regard.
+
+ XSLoader (core since perl 5.6.0).
SEE ALSO
"local" in perlfunc, "Temporary Values via local()" in perlsub.
Scope::Escape.
AUTHOR
- Vincent Pit, "<perl at profvince.com>", <http://www.profvince.com>.
+ Vincent Pit "<vpit at cpan.org>".
You can contact me by mail or on "irc.perl.org" (vincent).
perldoc Scope::Upper
- Tests code coverage report is available at
- <http://www.profvince.com/perl/cover/Scope-Upper>.
-
ACKNOWLEDGEMENTS
Inspired by Ricardo Signes.
+ The reimplementation of a large part of this module for perl 5.24 was
+ provided by David Mitchell. His work was sponsored by the Perl 5 Core
+ Maintenance Grant from The Perl Foundation.
+
Thanks to Shawn M. Moore for motivation.
COPYRIGHT & LICENSE
- Copyright 2008,2009,2010,2011,2012 Vincent Pit, all rights reserved.
+ Copyright
+ 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2021 Vincent
+ Pit, all rights reserved.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.