From: Stephen McCamant Date: Mon, 3 Feb 2003 21:01:07 +0000 (-0500) Subject: B::Concise updates (incl. avoiding use of op_seq) X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=c27ea44e678f02a1903a4aa0e3110ba824fcd93a;p=p5sagit%2Fp5-mst-13.2.git B::Concise updates (incl. avoiding use of op_seq) Message-ID: <15935.7907.976943.74729@syllepsis.MIT.EDU> p4raw-id: //depot/perl@18657 --- diff --git a/ext/B/B/Concise.pm b/ext/B/B/Concise.pm index 7cd198e..b0ea7ea 100644 --- a/ext/B/B/Concise.pm +++ b/ext/B/B/Concise.pm @@ -1,5 +1,5 @@ package B::Concise; -# Copyright (C) 2000-2002 Stephen McCamant. All rights reserved. +# Copyright (C) 2000-2003 Stephen McCamant. All rights reserved. # This program is free software; you can redistribute and/or modify it # under the same terms as Perl itself. @@ -8,7 +8,7 @@ use warnings; use Exporter (); -our $VERSION = "0.52"; +our $VERSION = "0.53"; our @ISA = qw(Exporter); our @EXPORT_OK = qw(set_style add_callback); @@ -44,7 +44,7 @@ my %style = my($format, $gotofmt, $treefmt); my $curcv; -my($seq_base, $cop_seq_base); +my $cop_seq_base; my @callbacks; sub set_style { @@ -59,6 +59,7 @@ sub concise_cv { my ($order, $cvref) = @_; my $cv = svref_2object($cvref); $curcv = $cv; + sequence($cv->START); if ($order eq "exec") { walk_exec($cv->START); } elsif ($order eq "basic") { @@ -119,29 +120,32 @@ sub compile { warn "Option $o unrecognized"; } } - if (@args) { - return sub { + return sub { + if (@args) { for my $objname (@args) { $objname = "main::" . $objname unless $objname =~ /::/; + print "$objname:\n"; eval "concise_cv(\$order, \\&$objname)"; die "concise_cv($order, \\&$objname) failed: $@" if $@; } } - } - if (!@args or $do_main) { - if ($order eq "exec") { - return sub { return if class(main_start) eq "NULL"; - $curcv = main_cv; - walk_exec(main_start) } - } elsif ($order eq "tree") { - return sub { return if class(main_root) eq "NULL"; - $curcv = main_cv; - print tree(main_root, 0) } - } elsif ($order eq "basic") { - return sub { return if class(main_root) eq "NULL"; - $curcv = main_cv; - walk_topdown(main_root, - sub { $_[0]->concise($_[1]) }, 0); } + if (!@args or $do_main) { + print "main program:\n" if $do_main; + sequence(main_start); + if ($order eq "exec") { + return if class(main_start) eq "NULL"; + $curcv = main_cv; + walk_exec(main_start); + } elsif ($order eq "tree") { + return if class(main_root) eq "NULL"; + $curcv = main_cv; + print tree(main_root, 0); + } elsif ($order eq "basic") { + return if class(main_root) eq "NULL"; + $curcv = main_cv; + walk_topdown(main_root, + sub { $_[0]->concise($_[1]) }, 0); + } } } } @@ -169,7 +173,7 @@ my @linenoise = co cr u. cm ut r. l@ s@ r@ mD uD oD rD tD sD wD cD f$ w$ p$ sh e$ k$ g3 g4 s4 g5 s5 T@ C@ L@ G@ A@ S@ Hg Hc Hr Hw Mg Mc Ms Mr Sg Sc So rq do {e e} {t t} g6 G6 6e g7 G7 7e g8 G8 8e g9 G9 9e 6s 7s 8s 9s 6E 7E 8E 9E Pn - Pu GP SP EP Gn Gg GG SG EG g0 c$ lk t$ ;s n>'; + Pu GP SP EP Gn Gg GG SG EG g0 c$ lk t$ ;s n> // /= CO'; my $chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -197,7 +201,14 @@ sub base_n { return $str; } -sub seq { return $_[0]->seq ? base_n($_[0]->seq - $seq_base) : "-" } +my %sequence_num; +my $seq_max = 1; + +sub seq { + my($op) = @_; + return "-" if not exists $sequence_num{$$op}; + return base_n($sequence_num{$$op}); +} sub walk_topdown { my($op, $sub, $level) = @_; @@ -252,6 +263,42 @@ sub walk_exec { walklines(\@lines, 0); } +# The structure of this routine is purposely modeled after op.c's peep() +sub sequence { + my($op) = @_; + my $oldop = 0; + return if class($op) eq "NULL" or exists $sequence_num{$$op}; + for (; $$op; $op = $op->next) { + last if exists $sequence_num{$$op}; + my $name = $op->name; + if ($name =~ /^(null|scalar|lineseq|scope)$/) { + next if $oldop and $ {$op->next}; + } else { + $sequence_num{$$op} = $seq_max++; + if (class($op) eq "LOGOP") { + my $other = $op->other; + $other = $other->next while $other->name eq "null"; + sequence($other); + } elsif (class($op) eq "LOOP") { + my $redoop = $op->redoop; + $redoop = $redoop->next while $redoop->name eq "null"; + sequence($redoop); + my $nextop = $op->nextop; + $nextop = $nextop->next while $nextop->name eq "null"; + sequence($nextop); + my $lastop = $op->lastop; + $lastop = $lastop->next while $lastop->name eq "null"; + sequence($lastop); + } elsif ($name eq "subst" and $ {$op->pmreplstart}) { + my $replstart = $op->pmreplstart; + $replstart = $replstart->next while $replstart->name eq "null"; + sequence($replstart); + } + } + $oldop = $op; + } +} + sub fmt_line { my($hr, $fmt, $level) = @_; my $text = $fmt; @@ -309,10 +356,8 @@ $priv{$_}{64} = "LOCALE" "scmp", "lc", "uc", "lcfirst", "ucfirst"); @{$priv{"sort"}}{1,2,4} = ("NUM", "INT", "REV"); $priv{"threadsv"}{64} = "SVREFd"; -$priv{$_}{16} = "INBIN" for ("open", "backtick"); -$priv{$_}{32} = "INCR" for ("open", "backtick"); -$priv{$_}{64} = "OUTBIN" for ("open", "backtick"); -$priv{$_}{128} = "OUTCR" for ("open", "backtick"); +@{$priv{$_}}{16,32,64,128} = ("INBIN","INCR","OUTBIN","OUTCR") + for ("open", "backtick"); $priv{"exit"}{128} = "VMS"; sub private_flags { @@ -328,6 +373,38 @@ sub private_flags { return join(",", @s); } +sub concise_sv { + my($sv, $hr) = @_; + $hr->{svclass} = class($sv); + $hr->{svaddr} = sprintf("%#x", $$sv); + if ($hr->{svclass} eq "GV") { + my $gv = $sv; + my $stash = $gv->STASH->NAME; + if ($stash eq "main") { + $stash = ""; + } else { + $stash = $stash . "::"; + } + $hr->{svval} = "*$stash" . $gv->SAFENAME; + return "*$stash" . $gv->SAFENAME; + } else { + while (class($sv) eq "RV") { + $hr->{svval} .= "\\"; + $sv = $sv->RV; + } + if (class($sv) eq "SPECIAL") { + $hr->{svval} = ["Null", "sv_undef", "sv_yes", "sv_no"]->[$$sv]; + } elsif ($sv->FLAGS & SVf_NOK) { + $hr->{svval} = $sv->NV; + } elsif ($sv->FLAGS & SVf_IOK) { + $hr->{svval} = $sv->IV; + } elsif ($sv->FLAGS & SVf_POK) { + $hr->{svval} = cstring($sv->PV); + } + return $hr->{svclass} . " " . $hr->{svval}; + } +} + sub concise_op { my ($op, $level, $format) = @_; my %h; @@ -356,15 +433,11 @@ sub concise_op { if ($h{class} eq "PMOP") { my $precomp = $op->precomp; if (defined $precomp) { - # Escape literal control sequences - for ($precomp) { - s/\t/\\t/g; s/\n/\\n/g; s/\r/\\r/g; - # How can we do the below portably? - #s/([\0-\037\177-\377])/"\\".sprintf("%03o", ord($1))/eg; - } - $precomp = "/$precomp/"; + $precomp = cstring($precomp); # Escape literal control sequences + $precomp = "/$precomp/"; + } else { + $precomp = ""; } - else { $precomp = ""; } my $pmreplroot = $op->pmreplroot; my $pmreplstart; if ($$pmreplroot && $pmreplroot->isa("B::GV")) { @@ -399,34 +472,12 @@ sub concise_op { undef $lastnext; $h{arg} = "(other->" . seq($op->other) . ")"; } elsif ($h{class} eq "SVOP") { - my $sv = $op->sv; - $h{svclass} = class($sv); - $h{svaddr} = sprintf("%#x", $$sv); - if ($h{svclass} eq "GV") { - my $gv = $sv; - my $stash = $gv->STASH->NAME; - if ($stash eq "main") { - $stash = ""; - } else { - $stash = $stash . "::"; - } - $h{arg} = "(*$stash" . $gv->SAFENAME . ")"; - $h{svval} = "*$stash" . $gv->SAFENAME; + if (! ${$op->sv}) { + my $sv = (($curcv->PADLIST->ARRAY)[1]->ARRAY)[$op->targ]; + $h{arg} = "[" . concise_sv($sv, \%h) . "]"; + $h{targarglife} = $h{targarg} = ""; } else { - while (class($sv) eq "RV") { - $h{svval} .= "\\"; - $sv = $sv->RV; - } - if (class($sv) eq "SPECIAL") { - $h{svval} = ["Null", "sv_undef", "sv_yes", "sv_no"]->[$$sv]; - } elsif ($sv->FLAGS & SVf_NOK) { - $h{svval} = $sv->NV; - } elsif ($sv->FLAGS & SVf_IOK) { - $h{svval} = $sv->IV; - } elsif ($sv->FLAGS & SVf_POK) { - $h{svval} = cstring($sv->PV); - } - $h{arg} = "($h{svclass} $h{svval})"; + $h{arg} = "(" . concise_sv($op->sv, \%h) . ")"; } } $h{seq} = $h{hyphseq} = seq($op); @@ -515,6 +566,12 @@ sub tree { # compile a little code at the end of the module, and compute the base # sequence number for the user's program as being a small offset # later, so all we have to worry about are changes in the offset. +# (Note that we now only play this game with COP sequence numbers. OP +# sequence numbers aren't used to refer to OPs from a distance, and +# they don't have much significance, so we just generate our own +# sequence numbers which are easier to control. This way we also don't +# stand in the way of a possible future removal of OP sequence +# numbers). # When you say "perl -MO=Concise -e '$a'", the output should look like: @@ -526,15 +583,13 @@ sub tree { # - <1> ex-rv2sv vK/1 ->4 # 3 <$> gvsv(*a) s ->4 -# If either of the marked numbers there aren't 1, it means you need to -# update the corresponding magic number in the next two lines. -# Remember, these need to stay the last things in the module. +# If the second of the marked numbers there isn't 1, it means you need +# to update the corresponding magic number in the next line. +# Remember, this needs to stay the last things in the module. -# Why these are different for MacOS? Does it matter? -my $cop_seq_mnum = $^O eq 'MacOS' ? 12 : 11; -my $seq_mnum = $^O eq 'MacOS' ? 102 : 86; +# Why is this different for MacOS? Does it matter? +my $cop_seq_mnum = $^O eq 'MacOS' ? 10 : 9; $cop_seq_base = svref_2object(eval 'sub{0;}')->START->cop_seq + $cop_seq_mnum; -$seq_base = svref_2object(eval 'sub{}')->START->seq + $seq_mnum; 1; @@ -829,7 +884,7 @@ The address of the OP's next OP, in hexidecimal. =item B<#noise> -The two-character abbreviation for the OP's name. +A one- or two-character abbreviation for the OP's name. =item B<#private> @@ -841,7 +896,9 @@ The numeric value of the OP's private flags. =item B<#seq> -The sequence number of the OP. +The sequence number of the OP. Note that this is now a sequence number +generated by B::Concise, rather than the real op_seq value (for which +see B<#seqnum>). =item B<#seqnum> diff --git a/ext/B/t/concise.t b/ext/B/t/concise.t index ac26d4b..1a07d08 100644 --- a/ext/B/t/concise.t +++ b/ext/B/t/concise.t @@ -19,7 +19,8 @@ $out = runperl(switches => ["-MO=Concise"], prog => '$a', stderr => 1); is($op_base, 1, "Smallest OP sequence number"); -($op_base_p1, $cop_base) = ($out =~ /^(\d+)\s*<;>\s*nextstate\(main (\d+) /m); +($op_base_p1, $cop_base) + = ($out =~ /^(\d+)\s*<;>\s*nextstate\(main (-?\d+) /m); is($op_base_p1, 2, "Second-smallest OP sequence number");