X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2FSub-Nary.git;a=blobdiff_plain;f=lib%2FSub%2FNary.pm;fp=lib%2FSub%2FNary.pm;h=313381f435686db10599dac7f30b7e621e031be3;hp=2f700b6fd90507af909b126d4ef7040c520d6412;hb=2eb7d799fbc08f3dbeada52aeac89c781983e081;hpb=1e8e0d19ec48ebdcb83efcc5393df5d3bf519751 diff --git a/lib/Sub/Nary.pm b/lib/Sub/Nary.pm index 2f700b6..313381f 100644 --- a/lib/Sub/Nary.pm +++ b/lib/Sub/Nary.pm @@ -213,7 +213,7 @@ sub power { my %ops; $ops{$_} = 1 for scalops; -$ops{$_} = 0 for qw/stub nextstate pushmark iter unstack/; +$ops{$_} = 0 for qw/stub nextstate iter unstack/; $ops{$_} = 1 for qw/padsv/; $ops{$_} = 'list' for qw/padav/; $ops{$_} = 'list' for qw/padhv rv2hv/; @@ -234,11 +234,33 @@ $ops{$_} = { 0 => 0.5, 4 => 0.5 } for qw/gnbyname gnbyaddr gnetent/; $ops{$_} = { 0 => 0.5, 3 => 0.5 } for qw/gpbyname gpbynumber gprotoent/; $ops{$_} = { 0 => 0.5, 4 => 0.5 } for qw/gsbyname gsbyport gservent/; +# Stolen from B::Deparse + +sub padval { $_[0]->{cv}->[0]->PADLIST->ARRAYelt(1)->ARRAYelt($_[1]) } + +sub gv_or_padgv { + my ($self, $op) = @_; + if (class($op) eq 'PADOP') { + return $self->padval($op->padix) + } else { # class($op) eq "SVOP" + return $op->gv; + } +} + +sub const_sv { + my ($self, $op) = @_; + my $sv = $op->sv; + # the constant could be in the pad (under useithreads) + $sv = $self->padval($op->targ) unless $$sv; + return $sv; +} + sub enter { my ($self, $cv) = @_; return undef, 'list' if class($cv) ne 'CV'; my $op = $cv->ROOT; + return undef, 'list' if null $op; my $tag = tag($op); return undef, { %{$self->{cache}->{$tag}} } if exists $self->{cache}->{$tag}; @@ -256,54 +278,91 @@ sub enter { return undef, $r; } +use Test::More; +use Data::Dumper; + sub inspect { my ($self, $op) = @_; my $n = name($op); - return add($self->inspect_kids($op)), undef if $n eq 'return'; - my $meth = $self->can('pp_' . $n); return $self->$meth($op) if $meth; + my $l; if (exists $ops{$n}) { - my $l = $ops{$n}; + $l = $ops{$n}; $l = { %$l } if ref $l; - return undef, $l; } - if (class($op) eq 'LOGOP' and not null $op->first) { - my @res; + my $c = class($op); + $meth = $self->can('OPc_' . $c); + if ($meth) { + my ($r, $lc) = $self->$meth($op); + $lc = $l if defined $l; + return $r, $lc; + } - my $op = $op->first; - my ($r1, $l1) = $self->inspect($op); - return $r1, $l1 if defined $r1 and zero $l1; - my $c = count $l1; + return undef, (defined $l) ? $l : 0; +} - $op = $op->sibling; - my ($r2, $l2) = $self->inspect($op); +# UNOPs - $op = $op->sibling; - my ($r3, $l3); - if (null $op) { - # If the logop has no else branch, it can also return the *scalar* result of - # the conditional - $l3 = { 1 => 1 }; - } else { - ($r3, $l3) = $self->inspect($op); - } +sub OPc_UNOP { $_[0]->inspect($_[1]->first); } - my $r = add $r1, scale $c / 2, add $r2, $r3; - my $l = scale $c / 2, add $l2, $l3; - return $r, $l - } +# BINOPs + +sub OPc_BINOP { + my ($self, $op) = @_; + + my ($r, $l1) = $self->inspect($op->first); + return $r, $l1 unless defined $l1; + + my ($r2, $l2) = $self->inspect($op->last); + my $c = 1 - count $r; + $r = add $r, scale $c, $r2 if defined $r2; + + my $l = scale +(1 - count $r), normalize combine $l1, $l2; - return $self->inspect_kids($op); + return $r, $l; } -sub inspect_kids { +# LOGOPs + +sub OPc_LOGOP { my ($self, $op) = @_; + my @res; + + $op = $op->first; + return undef, 0 if null $op; + + my ($r1, $l1) = $self->inspect($op); + return $r1, $l1 if defined $r1 and zero $l1; + my $c = count $l1; + + $op = $op->sibling; + my ($r2, $l2) = $self->inspect($op); + + $op = $op->sibling; + my ($r3, $l3); + if (null $op) { + # If the logop has no else branch, it can also return the *scalar* result of + # the conditional + $l3 = { 1 => 1 }; + } else { + ($r3, $l3) = $self->inspect($op); + } - return undef, 0 unless $op->flags & OPf_KIDS; + my $r = add $r1, scale $c / 2, add $r2, $r3; + my $l = scale $c / 2, add $l2, $l3; + return $r, $l; + + return $self->OPc_LISTOP($op); +} + +# LISTOPs + +sub OPc_LISTOP { + my ($self, $op) = @_; $op = $op->first; return undef, 0 if null $op; @@ -340,26 +399,7 @@ sub inspect_kids { return $r, $l; } -# Stolen from B::Deparse - -sub padval { $_[0]->{cv}->[0]->PADLIST->ARRAYelt(1)->ARRAYelt($_[1]) } - -sub gv_or_padgv { - my ($self, $op) = @_; - if (class($op) eq 'PADOP') { - return $self->padval($op->padix) - } else { # class($op) eq "SVOP" - return $op->gv; - } -} - -sub const_sv { - my ($self, $op) = @_; - my $sv = $op->sv; - # the constant could be in the pad (under useithreads) - $sv = $self->padval($op->targ) unless $$sv; - return $sv; -} +sub pp_return { add($_[0]->OPc_LISTOP($_[1])), undef } sub pp_entersub { my ($self, $op) = @_; @@ -388,8 +428,8 @@ sub pp_entersub { $next = $next->sibling; } $n = name($op) - } while ($op->flags & OPf_KIDS and { map { $_ => 1 } qw/null leave/ }->{$n}); - return 'list', undef unless { map { $_ => 1 } qw/gv refgen/ }->{$n}; + } while $op->flags & OPf_KIDS and ($n eq 'null' or $n eq 'leave'); + return 'list', undef unless $n eq 'gv' or $n eq 'refgen'; local $self->{sub} = 1; my ($rc, $lc) = $self->inspect($op); return $r, scale $c, $lc; @@ -429,7 +469,7 @@ sub pp_exit { sub pp_die { my ($self, $op) = @_; - my ($r, undef) = $self->inspect_kids($op); + my ($r, undef) = $self->OPc_LISTOP($op); if (defined $r) { my $c = 1 - count $r; $r->{die} = $c if $c; @@ -505,6 +545,8 @@ sub pp_sassign { return $r, $c ? { 1 => $c } : undef } +=cut + sub pp_aassign { my ($self, $op) = @_; @@ -517,10 +559,12 @@ sub pp_aassign { $self->inspect($op); } +=cut + sub pp_leavetry { my ($self, $op) = @_; - my ($r, $l) = $self->inspect_kids($op); + my ($r, $l) = $self->OPc_LISTOP($op); if (defined $r) { my $d = delete $r->{die}; return $r, $l if not defined $d;