]> git.vpit.fr Git - perl/modules/Sub-Nary.git/commitdiff
Add support for die()
authorVincent Pit <vince@profvince.com>
Thu, 21 Aug 2008 10:16:11 +0000 (12:16 +0200)
committerVincent Pit <vince@profvince.com>
Thu, 21 Aug 2008 10:16:11 +0000 (12:16 +0200)
MANIFEST
Nary.xs
lib/Sub/Nary.pm
t/16-combine.t
t/27-die.t [new file with mode: 0644]

index cb97b5cd4cc65361b3a7f81f9a87f81ceeb46d51..e81815703bc0273b5549932475935e5c20312216 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -18,6 +18,7 @@ t/23-branch.t
 t/24-ops.t
 t/25-grepmap.t
 t/26-exit.t
+t/27-die.t
 t/90-boilerplate.t
 t/91-pod.t
 t/92-pod-coverage.t
diff --git a/Nary.xs b/Nary.xs
index 0329eea6439cb62c80bcadb24546d02ef7f1abe8..66eced60f0e7e930024e74e4a3a8d453af9799c3 100644 (file)
--- a/Nary.xs
+++ b/Nary.xs
@@ -31,6 +31,7 @@ STATIC void sn_store_ent(pTHX_ HV *tb, SV *key, SV *val, U32 hash) {
 
 STATIC U32 sn_hash_list = 0;
 STATIC U32 sn_hash_exit = 0;
+STATIC U32 sn_hash_die  = 0;
 
 /* --- XS ------------------------------------------------------------------ */
 
@@ -42,6 +43,7 @@ BOOT:
 {
  PERL_HASH(sn_hash_list, "list", 4);
  PERL_HASH(sn_hash_exit, "exit", 4);
+ PERL_HASH(sn_hash_die,  "die",  3);
 }
 
 void
@@ -248,13 +250,13 @@ PROTOTYPE: @
 PREINIT:
  HV *res[3];
  SV *val;
- SV *exit1, *list1;
+ SV *kexit, *klist, *kdie;
  SV *temp;
  HE *key, *old;
  I32 i;
  I32 n = 0, o;
  I32 j, n1, n2;
- NV pl = 0, pe = 0;
+ NV pe = 0, pd = 0, pl = 0;
  sn_combcache *cache = NULL;
  I32 cachelen = 1;
 CODE:
@@ -268,7 +270,7 @@ CODE:
  temp = sv_2mortal(newSViv(0));
  for (i = 0; i < items; ++i) {
   SV *cur = ST(i);
-  NV pe1 = 0, pl1 = 0;
+  NV pe1 = 0, pd1 = 0, pd2, pl1 = 0;
   if (!SvOK(cur))
    continue;
   if (!SvROK(cur)) {
@@ -285,29 +287,42 @@ CODE:
    res[o] = newHV();
   else
    hv_clear(res[o]);
-  exit1 = hv_delete((HV *) cur, "exit", 4, 0);
+  kexit = hv_delete((HV *) cur, "exit", 4, 0);
   n1    = hv_iterinit((HV *) cur);
-  if (exit1) {
+  if (kexit) {
    if (!n1) {
-    pe = 1;
+    pe = 1 - pd;
     pl = 0;
     n  = o;
     break;
    }
-   pe1 = SvNV(exit1);
+   pe1 = SvNV(kexit);
   }
-  list1 = hv_delete((HV *) cur, "list", 4, 0);
-  if (list1) {
+  kdie  = hv_delete((HV *) cur, "die", 3, 0);
+  if (kdie) {
    if (n1 == 1) {
-    pl = 1 - pe;
+    pd = 1 - pe;
+    pl = 0;
+    n  = o;
+    break;
+   }
+   --n1;
+   pd1 = SvNV(kdie);
+  }
+  klist = hv_delete((HV *) cur, "list", 4, 0);
+  if (klist) {
+   if (n1 == 1) {
+    pl = 1 - (pe + pd);
     n  = o;
     break;
    }
-   pl1 = SvNV(list1);
+   pl1 = SvNV(klist);
   }
-  pl = pl1 * (1 - pe) + pl * (1 - pe1) - pl * pl1;
-  pe = pe + (1 - pe) * pe1;
-  n2 = hv_iterinit(res[n]);
+  pl  = pl1 * (1 - (pd + pe)) + pl * (1 - (pd1 + pe1)) - pl * pl1;
+  pd2 = pd1 * (1 - pe)        + pd                     - pd * pd1;
+  pe  = pe1 * (1 - pd)        + pe                     - pe * pe1;
+  pd  = pd2;
+  n2  = hv_iterinit(res[n]);
   if (!n2) {
    cache[0].k = 0;
    cache[0].v = 1;
@@ -343,6 +358,8 @@ CODE:
  SvREFCNT_dec(res[2]);
  if (pe)
   sn_store(res[n], "exit", 4, newSVnv(pe), sn_hash_exit);
+ if (pd)
+  sn_store(res[n], "die",  3, newSVnv(pd), sn_hash_die);
  if (pl)
   sn_store(res[n], "list", 4, newSVnv(pl), sn_hash_list);
  if (n == 1)
index f789e696c1796665076cec790c2a915da7afb333..159dd8e6bc9a31fb753478eec7c573feb852bad1 100644 (file)
@@ -426,6 +426,20 @@ sub pp_exit {
  return $r, undef;
 }
 
+sub pp_die {
+ my ($self, $op) = @_;
+
+ my ($r, undef) = $self->inspect_kids($op);
+ if (defined $r) {
+  my $c = 1 - count $r;
+  $r->{die} = $c if $c;
+ } else {
+  $r = { die => 1 };
+ }
+
+ return $r, undef;
+}
+
 sub pp_goto {
  my ($self, $op) = @_;
 
@@ -503,6 +517,18 @@ sub pp_aassign {
  $self->inspect($op);
 }
 
+sub pp_leavetry {
+ my ($self, $op) = @_;
+
+ my ($r, $l) = $self->inspect_kids($op);
+ if (defined $r) {
+  my $d = delete $r->{die};
+  $r->{0} += $d if defined $d;
+ }
+
+ return $r, $l;
+}
+
 sub pp_leaveloop {
  my ($self, $op) = @_;
 
index 7f0b459e35cdd8511c339352763d5dd7b7fb6985..bfd9d4e86a48401a68092c739cc8e02f3de7dd2f 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 41;
+use Test::More tests => 60;
 
 use Sub::Nary;
 
@@ -12,7 +12,11 @@ use Sub::Nary;
 my $h12 = { 1 => 0.5, 2 => 0.5 };
 my $h1l = { 1 => 0.5, list => 0.5 };
 my $h1e = { 1 => 0.5, exit => 0.5 };
+my $h1d = { 1 => 0.5, die  => 0.5 };
 my $h1le = { 1 => 0.25, list => 0.25, exit => 0.5 };
+my $h12e = { 1 => 0.25, 2    => 0.25, exit => 0.5 };
+my $h1ld = { 1 => 0.25, list => 0.25, die  => 0.5 };
+my $h12d = { 1 => 0.25, 2    => 0.25, die  => 0.5 };
 
 my @tests = (
  [ [ ],          undef ],
@@ -57,11 +61,44 @@ my @tests = (
  [ [ 'exit', 1 ],             'exit' ],
  [ [ { %$h1e }, 1 ],          { exit => 0.5, 2 => 0.5 } ],
  [ [ { %$h1e }, { %$h1e } ],  { exit => 0.75, 2 => 0.25 } ],
+
  [ [ { %$h1e }, { %$h1l } ],  { exit => 0.5, list => 0.25, 2 => 0.25 } ],
  [ [ { %$h1l }, { %$h1e } ],  { exit => 0.5, list => 0.25, 2 => 0.25 } ],
  [ [ { %$h1l }, { %$h1le } ], { exit => 0.5, list => 0.375, 2 => 0.125 } ],
  [ [ { %$h1e }, { %$h1le } ], { exit => 0.75, list => 0.125, 2 => 0.125 } ],
 
+ [ [ 'die' ],                 'die' ],
+ [ [ 'die', 2 ],              'die' ],
+ [ [ { %$h1d }, 2 ],          { die => 0.5, 3 => 0.5 } ],
+ [ [ { %$h1d }, 1 ],          { die => 0.5, 2 => 0.5 } ],
+ [ [ { %$h1d }, { %$h1d } ],  { die => 0.75, 2 => 0.25 } ],
+
+ [ [ { %$h1d }, { %$h1l } ],  { die => 0.5, list => 0.25, 2 => 0.25 } ],
+ [ [ { %$h1l }, { %$h1d } ],  { die => 0.5, list => 0.25, 2 => 0.25 } ],
+ [ [ { %$h1l }, { %$h1ld } ], { die => 0.5, list => 0.375, 2 => 0.125 } ],
+ [ [ { %$h1d }, { %$h1ld } ], { die => 0.75, list => 0.125, 2 => 0.125 } ],
+
+ [ [ { %$h1e }, { %$h1d } ],  { exit => 0.5,   die => 0.25, 2 => 0.25 } ],
+ [ [ { %$h1d }, { %$h1e } ],  { exit => 0.25,  die => 0.5,  2 => 0.25 } ],
+ [ [ { %$h1e }, { %$h1ld } ], { exit => 0.5,   die => 0.25,
+                                list => 0.125, 2 => 0.125 } ],
+ [ [ { %$h1d }, { %$h1le } ], { exit => 0.25,  die => 0.5,
+                                list => 0.125, 2 => 0.125 } ],
+
+ [ [ { %$h12d }, { %$h1le } ], { exit => 0.25,  die => 0.5,
+                                 list => 0.125, 2 => 0.0625, 3 => 0.0625 } ],
+ [ [ { %$h12e }, { %$h1ld } ], { exit => 0.5,    die => 0.25,
+                                 list => 0.125, 2 => 0.0625, 3 => 0.0625 } ],
+ [ [ { %$h1ld }, { %$h12e } ], { exit => 0.25,  die => 0.5,
+                                 list => 0.125, 2 => 0.0625, 3 => 0.0625 } ],
+ [ [ { %$h1le }, { %$h12d } ], { exit => 0.5,    die => 0.25,
+                                 list => 0.125, 2 => 0.0625, 3 => 0.0625 } ],
+
+ [ [ { %$h1ld }, { %$h1le } ], { exit => 0.25,   die => 0.5,
+                                 list => 0.1875, 2 => 0.0625  } ],
+ [ [ { %$h1le }, { %$h1ld } ], { exit => 0.5,    die => 0.25,
+                                 list => 0.1875, 2 => 0.0625  } ],
+
  [ [ $h1l, $h1l ],              { 2 => 0.25, list => 0.5 } ], # Side effects
 );
 
diff --git a/t/27-die.t b/t/27-die.t
new file mode 100644 (file)
index 0000000..3880282
--- /dev/null
@@ -0,0 +1,47 @@
+#!perl -T
+
+use strict;
+use warnings;
+
+use Test::More tests => 12;
+
+use Sub::Nary;
+
+my $sn = Sub::Nary->new();
+
+my ($x, $y);
+
+sub dies {
+ if ($x) {
+  die do { return 3, 4 if $y }
+ }
+ @_[0 .. 2];
+}
+
+my @tests = (
+ [ sub { die },                        { die => 1 } ],
+ [ sub { die 1 },                      { die => 1 } ],
+ [ sub { if ($x) { die } },            { die => 0.5, 1 => 0.5 } ],
+ [ sub { if (die) { return 1, 2 } },   { die => 1 } ],
+ [ sub { die do { return 3, 4 } },     { 2 => 1 } ],
+ [ sub { $x ? die($y ? die : return(2, 3)) : 4 },
+                                       { die => 0.25, 2 => 0.25, 1 => 0.5 } ],
+
+ [ \&dies,                             { die => 0.25, 2 => 0.25, 3 => 0.5 } ],
+ [ sub { dies(), do { $x ? @_ : 1 } }, { die => 0.25, 3 => 0.125, 4 => 0.25,
+                                          list => (0.25 + 0.5) * 0.5 } ],
+ [ sub { dies(), 1, do { $x ? @_ : 1 } },
+          { die => 0.25, 4 => 0.125, 5 => 0.25, list => (0.25 + 0.5) * 0.5 } ],
+
+ [ sub { eval "1, do { die }, 3" },    'list' ],
+ [ sub { eval { die } },               { 0 => 1 } ],
+ [ sub { eval { $x ? die : (4, 5) } }, { 0 => 0.5, 2 => 0.5 } ],
+);
+
+my $i = 1;
+for (@tests) {
+ my $r = $sn->nary($_->[0]);
+ my $exp = ref $_->[1] ? $_->[1] : { $_->[1] => 1 };
+ is_deeply($r, $exp, 'die test ' . $i);
+ ++$i;
+}