]> git.vpit.fr Git - perl/modules/Sub-Op.git/blobdiff - lib/Sub/Op.pm
POD verbatim paragraphs should fit into a terminal
[perl/modules/Sub-Op.git] / lib / Sub / Op.pm
index d8a6b738c7461f856af60f1137ac4ac725f9b9b2..a3334428a1b9a0885b1cc02736530884746d31cc 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 
 =head1 NAME
 
 
 =head1 NAME
 
-Sub::Op - Install subroutines as opcodes.
+Sub::Op - Hook compilation of keyword calls and reference constructors.
 
 =head1 VERSION
 
 
 =head1 VERSION
 
@@ -28,35 +28,50 @@ BEGIN {
 
 =head1 SYNOPSIS
 
 
 =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"
 
 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);
 
     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);
     }
      c.ud       = NULL;
      sub_op_register(aTHX_ &c, 0);
     }
@@ -79,9 +94,9 @@ In your Perl module file :
      __PACKAGE__->bootstrap($VERSION);
     }
 
      __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;
 
 
     1;
 
@@ -98,26 +113,10 @@ In your F<Makefile.PL> :
 
 =head1 DESCRIPTION
 
 
 =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 *
-
-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.
+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.
 
 
-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
 
 
 =cut
 
@@ -255,57 +254,73 @@ C<proto>'s length, in bytes.
 
 =item *
 
 
 =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 *
 
 
 =item *
 
-C<sub_op_check_t check>
-
-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 :
+C<sub_op_check_t ref>
 
 
-    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>
 
 
 =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
 
 
 =back
 
-=head2 C<void sub_op_init(sub_op_config_t *c)>
+=head2 C<sub_op_init>
+
+    void sub_op_init(sub_op_config_t *c);
 
 Initializes the fields of the C<sub_op_config_t> object.
 For future compatibility, it is required to call this function with your config object before storing your actual values.
 It will store safe defaults for members you won't set.
 
 
 Initializes the fields of the C<sub_op_config_t> object.
 For future compatibility, it is required to call this function with your config object before storing your actual values.
 It will store safe defaults for members you won't set.
 
-=head2 C<void sub_op_register(pTHX_ const sub_op_config_t *c, U32 flags)>
+=head2 C<sub_op_register>
+
+    void sub_op_register(pTHX_ const sub_op_config_t *c, U32 flags);
 
 Registers a name and its configuration into L<Sub::Op>.
 The caller is responsible for allocating and freeing the C<sub_op_config_t> object.
 No pointer to it or to its members is kept, except if you pass the flag C<SUB_OP_REGISTER_STEAL> in which case the configuration object will be stolen to be stored into L<Sub::Op>'s internal datastructure.
 
 
 Registers a name and its configuration into L<Sub::Op>.
 The caller is responsible for allocating and freeing the C<sub_op_config_t> object.
 No pointer to it or to its members is kept, except if you pass the flag C<SUB_OP_REGISTER_STEAL> in which case the configuration object will be stolen to be stored into L<Sub::Op>'s internal datastructure.
 
-=head2 C<sub_op_config_t *sub_op_dup(pTHX_ const sub_op_config_t *orig)>
+=head2 C<sub_op_dup>
+
+    sub_op_config_t *sub_op_dup(pTHX_ const sub_op_config_t *orig);
 
 Deeply clones the specified C<sub_op_config_t> object.
 
 
 Deeply clones the specified C<sub_op_config_t> object.
 
-=head2 C<void sub_op_free(pTHX_ sub_op_config_t *c)>
+=head2 C<sub_op_free>
+
+    void sub_op_free(pTHX_ sub_op_config_t *c);
 
 Free the memory associated with the specified C<sub_op_config_t> object.
 
 
 Free the memory associated with the specified C<sub_op_config_t> object.
 
+=head2 C<sub_op_study>
+
+    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
 
 =head1 PERL API
 
-=head2 C<enable $name, [ $pkg ]>
+=head2 C<enable>
+
+    enable($name);
+    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.
 
 
 When C<$pkg> is not set, it defaults to the caller package.
 
@@ -337,9 +352,12 @@ sub enable {
  return;
 }
 
  return;
 }
 
-=head2 C<disable $name, [ $pkg ]>
+=head2 C<disable>
 
 
-Disable the replacement for calls to C<$name> in the package C<$pkg>.
+    disable($name);
+    disable($name, $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.
 
 
 When C<$pkg> is not set, it defaults to the caller package.
 
@@ -402,10 +420,6 @@ L<ExtUtils::Depends>.
 
 L<subs::auto>.
 
 
 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
 L<B::Hooks::OP::Check::EntersubForCV>.
 
 =head1 AUTHOR