summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embed.fnc2
-rw-r--r--op.c11
-rw-r--r--op.h24
-rw-r--r--pod/perlguts.pod68
4 files changed, 104 insertions, 1 deletions
diff --git a/embed.fnc b/embed.fnc
index 054616a4c5..15bd938ce3 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -214,7 +214,7 @@ pR |OP* |block_end |I32 floor|NULLOK OP* seq
ApR |I32 |block_gimme
: Used in perly.y
pR |int |block_start |int full
-Aop |void |blockhook_register |NN BHK *hk
+Aodp |void |blockhook_register |NN BHK *hk
: Used in perl.c
p |void |boot_core_UNIVERSAL
: Used in perl.c
diff --git a/op.c b/op.c
index 9caf8cdc5c..d832c997de 100644
--- a/op.c
+++ b/op.c
@@ -2343,6 +2343,17 @@ Perl_block_end(pTHX_ I32 floor, OP *seq)
return retval;
}
+/*
+=head1 Compile-time scope hooks
+
+=for apidoc Ao||blockhook_register
+
+Register a set of hooks to be called when the Perl lexical scope changes
+at compile time. See L<perlguts/"Compile-time scope hooks">.
+
+=cut
+*/
+
void
Perl_blockhook_register(pTHX_ BHK *hk)
{
diff --git a/op.h b/op.h
index ac34f1d19b..30a41c8edd 100644
--- a/op.h
+++ b/op.h
@@ -653,6 +653,30 @@ struct block_hooks {
void (*bhk_eval) (pTHX_ OP *const saveop);
};
+/*
+=head1 Compile-time scope hooks
+
+=for apidoc m|U32|BhkFLAGS|BHK *hk
+Return the BHK's flags.
+
+=for apidoc m|void *|BhkENTRY|BHK *hk|which
+Return an entry from the BHK structure. I<which> is a preprocessor token
+indicating which entry to return. If the appropriate flag is not set
+this will return NULL. The type of the return value depends on which
+entry you ask for.
+
+=for apidoc Am|void|BhkENTRY_set|BHK *hk|which|void *ptr
+Set an entry in the BHK structure, and set the flags to indicate it is
+valid. I<which> is a preprocessing token indicating which entry to set.
+The type of I<ptr> depends on the entry.
+
+=for apidoc m|void|CALL_BLOCK_HOOKS|which|arg
+Call all the registered block hooks for type I<which>. I<which> is a
+preprocessing token; the type of I<arg> depends on I<which>.
+
+=cut
+*/
+
#define BhkFLAGS(hk) ((hk)->bhk_flags)
#define BHKf_start 0x01
diff --git a/pod/perlguts.pod b/pod/perlguts.pod
index b6cec65bbb..d0178e7285 100644
--- a/pod/perlguts.pod
+++ b/pod/perlguts.pod
@@ -1842,6 +1842,74 @@ file, add the line:
This function should be as efficient as possible to keep your programs
running as fast as possible.
+=head2 Compile-time scope hooks
+
+As of perl 5.14 it is possible to hook into the compile-time lexical
+scope mechanism using C<Perl_blockhook_register>. This is used like
+this:
+
+ STATIC void my_start_hook(pTHX_ int full);
+ STATIC BHK my_hooks;
+
+ BOOT:
+ BhkENTRY_set(&my_hooks, start, my_start_hook);
+ Perl_blockhook_register(aTHX_ &my_hooks);
+
+This will arrange to have C<my_start_hook> called at the start of
+compiling every lexical scope. The available hooks are:
+
+=over 4
+
+=item C<void start(pTHX_ int full)>
+
+This is called just after starting a new lexical scope. Note that Perl
+code like
+
+ if ($x) { ... }
+
+creates two scopes: the first starts at the C<(> and has C<full == 1>,
+the second starts at the C<{> and has C<full == 0>. Both end at the
+C<}>, so calls to C<start> and C<pre/post_end> will match. Anything
+pushed onto the save stack by this hook will be popped just before the
+scope ends (between the C<pre_> and C<post_end> hooks, in fact).
+
+=item C<void pre_end(pTHX_ OP **o)>
+
+This is called at the end of a lexical scope, just before unwinding the
+stack. I<o> is the root of the optree representing the scope; it is a
+double pointer so you can replace the OP if you need to.
+
+=item C<void post_end(pTHX_ OP **o)>
+
+This is called at the end of a lexical scope, just after unwinding the
+stack. I<o> is as above. Note that it is possible for calls to C<pre_>
+and C<post_end> to nest, if there is something on the save stack that
+calls string eval.
+
+=item C<void eval(pTHX_ OP *const o)>
+
+This is called just before starting to compile an C<eval STRING>, C<do
+FILE>, C<require> or C<use>, after the eval has been set up. I<o> is the
+OP that requested the eval, and will normally be an C<OP_ENTEREVAL>,
+C<OP_DOFILE> or C<OP_REQUIRE>.
+
+=back
+
+Once you have your hook functions, you need a C<BHK> structure to put
+them in. It's best to allocate it statically, since there is no way to
+free it once it's registered. The function pointers should be inserted
+into this structure using the C<BhkENTRY_set> macro, which will also set
+flags indicating which entries are valid. If you do need to allocate
+your C<BHK> dynamically for some reason, be sure to zero it before you
+start.
+
+Once registered, there is no mechanism to switch these hooks off, so if
+that is necessary you will need to do this yourself. An entry in C<%^H>
+is probably the best way, so the effect is lexically scoped. You should
+also be aware that generally speaking at least one scope will have
+opened before your extension is loaded, so you will see some
+C<pre/post_end> pairs that didn't have a matching C<start>.
+
=head1 Examining internal data structures with the C<dump> functions
To aid debugging, the source file F<dump.c> contains a number of