=head1 NAME
-Sub::Op - Install subroutines as opcodes.
+Sub::Op - Hook compilation of keyword calls and reference constructors.
=head1 VERSION
=head1 SYNOPSIS
+In the end user Perl code :
+
+ {
+ use Sub::Recall;
+ # There's no "call" symbol defined in this scope
+
+ # Compiles to "sub { $_[0] + $_[1] }->(1, 2)"
+ my $three = call { $_[0] + $_[1] } 1, 2;
+ }
+
In your XS file :
#include "sub_op.h"
- STATIC OP *scalar_util_reftype(pTHX) {
- dSP;
- dMARK;
- SV *sv = POPs;
- if (SvMAGICAL(sv))
- mg_get(sv);
- if (SvROK(sv))
- PUSHs(sv_reftype(SvRV(sv), 0));
- else
- PUSHs(&PL_sv_undef);
- RETURN;
+ STATIC OP *sub_recall_call(pTHX_ OP *, void *ud_) {
+ OP *ex_list, *pushmark, *refgen, *gvop, *last_arg, *rv2cv;
+
+ ex_list = cUNOPo->op_first;
+ pushmark = cUNOPx(ex_list)->op_first;
+ refgen = pushmark->op_sibling;
+ gvop = sub_op_study(o, &last_arg, &rv2cv);
+
+ /* Replace the function name by the refgen that contains the anon sub */
+ op_free(rv2cv);
+ last_arg->op_sibling = refgen;
+ pushmark->op_sibling = refgen->op_sibling;
+ refgen->op_sibling = NULL;
+
+ return o;
}
- MODULE = Scalar::Util::Ops PACKAGE = Scalar::Util::Ops
+ MODULE = Sub::Recall PACKAGE = Sub::Recall
BOOT:
{
sub_op_config_t c;
sub_op_init(&c);
- c.name = "reftype";
- c.namelen = sizeof("reftype")-1;
- c.proto = "$";
- c.protolen = sizeof("$")-1;
- c.pp = scalar_util_reftype;
- c.check = 0;
+ c.name = "call";
+ c.namelen = sizeof("call")-1;
+ c.proto = "&@";
+ c.protolen = sizeof("&@")-1;
+ c.call = sub_recall_call;
+ c.ref = 0;
c.ud = NULL;
sub_op_register(aTHX_ &c, 0);
}
__PACKAGE__->bootstrap($VERSION);
}
- sub import { Sub::Op::enable(reftype => scalar caller) }
+ sub import { Sub::Op::enable(call => scalar caller) }
- sub unimport { Sub::Op::disable(reftype => scalar caller) }
+ sub unimport { Sub::Op::disable(call => scalar caller) }
1;
=head1 DESCRIPTION
-This module provides a C and Perl API for replacing subroutine calls by custom opcodes.
-This has two main advantages :
-
-=over 4
-
-=item *
-
-it gets rid of the overhead of a normal subroutine call ;
-
-=item *
+This module provides a C and Perl API for hooking compilation of subroutine calls and reference constructors for a given name and prototype, and this without polluting the caller namespace with a dummy symbol.
+This allows you to define customized keywords that compile to whatever construct you want.
-there's no symbol table entry defined for the subroutine.
-
-=back
-
-Subroutine calls with and without parenthesis are handled.
-Ampersand calls are B<not> replaced, and as such will still allow to call a subroutine with same name defined earlier.
-This may or may not be considered as a bug, but it gives the same semantics as Perl keywords, so I believe it's reasonable.
-
-When L<B> and L<B::Deparse> are loaded, they get automatically monkeypatched so that introspecting modules like L<B::Concise> and L<B::Deparse> still produce a valid output.
+Subroutine calls with and without parenthesis are handled, but ampersand calls are B<not> caught.
=cut
=item *
-C<Perl_ppaddr_t pp>
+C<sub_op_check_t call>
-The pp function that will be called instead of the subroutine.
-C<Perl_ppaddr_t> is a typedef'd function pointer defined by perl as :
+An optional callback that will be fired each time C<perl> compiles a function call to C<name>.
+You can use it to attach extra info to those ops (e.g. with a pointer table), perform some optimizations to the optree, or completely replace the call.
+C<sub_op_check_t> is a typedef'd function pointer defined by :
- typedef OP *(*Perl_ppaddr_t)(pTHX);
+ typedef OP *(*sub_op_check_t)(pTHX_ OP *, void *);
=item *
-C<sub_op_check_t check>
+C<sub_op_check_t ref>
-An optional callback that will be called each time a call to C<name> is replaced.
-You can use it to attach extra info to those ops (e.g. with a pointer table) or to perform more optimizations to the optree.
-C<sub_op_check_t> is a typedef'd function pointer defined by :
-
- typedef OP *(*sub_op_check_t)(pTHX_ OP *, void *);
+An optional callback that will be fired each time a reference to C<name> is taken.
=item *
C<void *ud>
-An optional user data passed to the C<check> callback.
+An optional user data passed to the C<call> and C<ref> callbacks.
=back
Free the memory associated with the specified C<sub_op_config_t> object.
+=head2 C<OP *sub_op_study(OP *o, OP **last_arg_p, OP **rv2cv_p)>
+
+Studies the subset of the optree based on C<o>, expecting it to be an C<entersub> or C<rv2cv> op (the ones you get in the C<call> and C<ref> callbacks).
+If the tree is well-formed, C<*last_arg_p> will be set to the last argument of the call, C<*rv2cv_p> to the C<rv2cv> op that resolves the function name, and the C<gv> op will be returned.
+Otherwise, this function returns C<NULL>.
+
=head1 PERL API
=head2 C<enable $name, [ $pkg ]>
-Enable the replacement with a custom opcode of calls to the C<$name> subroutine of the C<$pkg> package in the current lexical scope.
-A pp callback must have been registered for C<$name> by calling the C function C<sub_op_register> in the XS section of your module.
+Enable the capture of function calls and references constructors to C<$name> in the C<$pkg> package in the current lexical scope.
+You must have registered an appropriate C<sub_op_config_t> configuration by calling the C function C<sub_op_register> in the XS section of your module.
When C<$pkg> is not set, it defaults to the caller package.
=head2 C<disable $name, [ $pkg ]>
-Disable the replacement for calls to C<$name> in the package C<$pkg>.
+Disable the capture of function calls and reference constructors to C<$name> in the package C<$pkg>.
When C<$pkg> is not set, it defaults to the caller package.
L<subs::auto>.
-L<B::Hooks::XSUB::CallAsOp> provides a C API to declare XSUBs that effectively call a specific PP function.
-Thus, it allows you to write XSUBs with the PP stack conventions used for implementing perl core keywords.
-There's no opcode replacement and no parsing hacks.
-
L<B::Hooks::OP::Check::EntersubForCV>.
=head1 AUTHOR