📄 deparse.pm
字号:
my($op, $cx) = @_; my $opname = $op->flags & OPf_SPECIAL ? 'CORE::require' : 'require'; if (class($op) eq "UNOP" and $op->first->name eq "const" and $op->first->private & OPpCONST_BARE) { my $name = $self->const_sv($op->first)->PV; $name =~ s[/][::]g; $name =~ s/\.pm//g; return "$opname $name"; } else { $self->unop($op, $cx, $opname); }}sub pp_scalar { my $self = shift; my($op, $cx) = @_; my $kid = $op->first; if (not null $kid->sibling) { # XXX Was a here-doc return $self->dquote($op); } $self->unop(@_, "scalar");}sub padval { my $self = shift; my $targ = shift; return $self->{'curcv'}->PADLIST->ARRAYelt(1)->ARRAYelt($targ);}sub anon_hash_or_list { my $self = shift; my($op, $cx) = @_; my($pre, $post) = @{{"anonlist" => ["[","]"], "anonhash" => ["{","}"]}->{$op->name}}; my($expr, @exprs); $op = $op->first->sibling; # skip pushmark for (; !null($op); $op = $op->sibling) { $expr = $self->deparse($op, 6); push @exprs, $expr; } if ($pre eq "{" and $cx < 1) { # Disambiguate that it's not a block $pre = "+{"; } return $pre . join(", ", @exprs) . $post;}sub pp_anonlist { my $self = shift; my ($op, $cx) = @_; if ($op->flags & OPf_SPECIAL) { return $self->anon_hash_or_list($op, $cx); } warn "Unexpected op pp_" . $op->name() . " without OPf_SPECIAL"; return 'XXX';}*pp_anonhash = \&pp_anonlist;sub pp_refgen { my $self = shift; my($op, $cx) = @_; my $kid = $op->first; if ($kid->name eq "null") { $kid = $kid->first; if ($kid->name eq "anonlist" || $kid->name eq "anonhash") { return $self->anon_hash_or_list($op, $cx); } elsif (!null($kid->sibling) and $kid->sibling->name eq "anoncode") { return $self->e_anoncode({ code => $self->padval($kid->sibling->targ) }); } elsif ($kid->name eq "pushmark") { my $sib_name = $kid->sibling->name; if ($sib_name =~ /^(pad|rv2)[ah]v$/ and not $kid->sibling->flags & OPf_REF) { # The @a in \(@a) isn't in ref context, but only when the # parens are there. return "\\(" . $self->pp_list($op->first) . ")"; } elsif ($sib_name eq 'entersub') { my $text = $self->deparse($kid->sibling, 1); # Always show parens for \(&func()), but only with -p otherwise $text = "($text)" if $self->{'parens'} or $kid->sibling->private & OPpENTERSUB_AMPER; return "\\$text"; } } } $self->pfixop($op, $cx, "\\", 20);}sub e_anoncode { my ($self, $info) = @_; my $text = $self->deparse_sub($info->{code}); return "sub " . $text;}sub pp_srefgen { pp_refgen(@_) }sub pp_readline { my $self = shift; my($op, $cx) = @_; my $kid = $op->first; $kid = $kid->first if $kid->name eq "rv2gv"; # <$fh> return "<" . $self->deparse($kid, 1) . ">" if is_scalar($kid); return $self->unop($op, $cx, "readline");}sub pp_rcatline { my $self = shift; my($op) = @_; return "<" . $self->gv_name($self->gv_or_padgv($op)) . ">";}# Unary operators that can occur as pseudo-listops inside double quotessub dq_unop { my $self = shift; my($op, $cx, $name, $prec, $flags) = (@_, 0, 0); my $kid; if ($op->flags & OPf_KIDS) { $kid = $op->first; # If there's more than one kid, the first is an ex-pushmark. $kid = $kid->sibling if not null $kid->sibling; return $self->maybe_parens_unop($name, $kid, $cx); } else { return $name . ($op->flags & OPf_SPECIAL ? "()" : ""); }}sub pp_ucfirst { dq_unop(@_, "ucfirst") }sub pp_lcfirst { dq_unop(@_, "lcfirst") }sub pp_uc { dq_unop(@_, "uc") }sub pp_lc { dq_unop(@_, "lc") }sub pp_quotemeta { maybe_targmy(@_, \&dq_unop, "quotemeta") }sub loopex { my $self = shift; my ($op, $cx, $name) = @_; if (class($op) eq "PVOP") { return "$name " . $op->pv; } elsif (class($op) eq "OP") { return $name; } elsif (class($op) eq "UNOP") { # Note -- loop exits are actually exempt from the # looks-like-a-func rule, but a few extra parens won't hurt return $self->maybe_parens_unop($name, $op->first, $cx); }}sub pp_last { loopex(@_, "last") }sub pp_next { loopex(@_, "next") }sub pp_redo { loopex(@_, "redo") }sub pp_goto { loopex(@_, "goto") }sub pp_dump { loopex(@_, "dump") }sub ftst { my $self = shift; my($op, $cx, $name) = @_; if (class($op) eq "UNOP") { # Genuine `-X' filetests are exempt from the LLAFR, but not # l?stat(); for the sake of clarity, give'em all parens return $self->maybe_parens_unop($name, $op->first, $cx); } elsif (class($op) =~ /^(SV|PAD)OP$/) { return $self->maybe_parens_func($name, $self->pp_gv($op, 1), $cx, 16); } else { # I don't think baseop filetests ever survive ck_ftst, but... return $name; }}sub pp_lstat { ftst(@_, "lstat") }sub pp_stat { ftst(@_, "stat") }sub pp_ftrread { ftst(@_, "-R") }sub pp_ftrwrite { ftst(@_, "-W") }sub pp_ftrexec { ftst(@_, "-X") }sub pp_fteread { ftst(@_, "-r") }sub pp_ftewrite { ftst(@_, "-w") }sub pp_fteexec { ftst(@_, "-x") }sub pp_ftis { ftst(@_, "-e") }sub pp_fteowned { ftst(@_, "-O") }sub pp_ftrowned { ftst(@_, "-o") }sub pp_ftzero { ftst(@_, "-z") }sub pp_ftsize { ftst(@_, "-s") }sub pp_ftmtime { ftst(@_, "-M") }sub pp_ftatime { ftst(@_, "-A") }sub pp_ftctime { ftst(@_, "-C") }sub pp_ftsock { ftst(@_, "-S") }sub pp_ftchr { ftst(@_, "-c") }sub pp_ftblk { ftst(@_, "-b") }sub pp_ftfile { ftst(@_, "-f") }sub pp_ftdir { ftst(@_, "-d") }sub pp_ftpipe { ftst(@_, "-p") }sub pp_ftlink { ftst(@_, "-l") }sub pp_ftsuid { ftst(@_, "-u") }sub pp_ftsgid { ftst(@_, "-g") }sub pp_ftsvtx { ftst(@_, "-k") }sub pp_fttty { ftst(@_, "-t") }sub pp_fttext { ftst(@_, "-T") }sub pp_ftbinary { ftst(@_, "-B") }sub SWAP_CHILDREN () { 1 }sub ASSIGN () { 2 } # has OP= variantsub LIST_CONTEXT () { 4 } # Assignment is in list contextmy(%left, %right);sub assoc_class { my $op = shift; my $name = $op->name; if ($name eq "concat" and $op->first->name eq "concat") { # avoid spurious `=' -- see comment in pp_concat return "concat"; } if ($name eq "null" and class($op) eq "UNOP" and $op->first->name =~ /^(and|x?or)$/ and null $op->first->sibling) { # Like all conditional constructs, OP_ANDs and OP_ORs are topped # with a null that's used as the common end point of the two # flows of control. For precedence purposes, ignore it. # (COND_EXPRs have these too, but we don't bother with # their associativity). return assoc_class($op->first); } return $name . ($op->flags & OPf_STACKED ? "=" : "");}# Left associative operators, like `+', for which# $a + $b + $c is equivalent to ($a + $b) + $cBEGIN { %left = ('multiply' => 19, 'i_multiply' => 19, 'divide' => 19, 'i_divide' => 19, 'modulo' => 19, 'i_modulo' => 19, 'repeat' => 19, 'add' => 18, 'i_add' => 18, 'subtract' => 18, 'i_subtract' => 18, 'concat' => 18, 'left_shift' => 17, 'right_shift' => 17, 'bit_and' => 13, 'bit_or' => 12, 'bit_xor' => 12, 'and' => 3, 'or' => 2, 'xor' => 2, );}sub deparse_binop_left { my $self = shift; my($op, $left, $prec) = @_; if ($left{assoc_class($op)} && $left{assoc_class($left)} and $left{assoc_class($op)} == $left{assoc_class($left)}) { return $self->deparse($left, $prec - .00001); } else { return $self->deparse($left, $prec); }}# Right associative operators, like `=', for which# $a = $b = $c is equivalent to $a = ($b = $c)BEGIN { %right = ('pow' => 22, 'sassign=' => 7, 'aassign=' => 7, 'multiply=' => 7, 'i_multiply=' => 7, 'divide=' => 7, 'i_divide=' => 7, 'modulo=' => 7, 'i_modulo=' => 7, 'repeat=' => 7, 'add=' => 7, 'i_add=' => 7, 'subtract=' => 7, 'i_subtract=' => 7, 'concat=' => 7, 'left_shift=' => 7, 'right_shift=' => 7, 'bit_and=' => 7, 'bit_or=' => 7, 'bit_xor=' => 7, 'andassign' => 7, 'orassign' => 7, );}sub deparse_binop_right { my $self = shift; my($op, $right, $prec) = @_; if ($right{assoc_class($op)} && $right{assoc_class($right)} and $right{assoc_class($op)} == $right{assoc_class($right)}) { return $self->deparse($right, $prec - .00001); } else { return $self->deparse($right, $prec); }}sub binop { my $self = shift; my ($op, $cx, $opname, $prec, $flags) = (@_, 0); my $left = $op->first; my $right = $op->last; my $eq = ""; if ($op->flags & OPf_STACKED && $flags & ASSIGN) { $eq = "="; $prec = 7; } if ($flags & SWAP_CHILDREN) { ($left, $right) = ($right, $left); } $left = $self->deparse_binop_left($op, $left, $prec); $left = "($left)" if $flags & LIST_CONTEXT && $left !~ /^(my|our|local|)[\@\(]/; $right = $self->deparse_binop_right($op, $right, $prec); return $self->maybe_parens("$left $opname$eq $right", $cx, $prec);}sub pp_add { maybe_targmy(@_, \&binop, "+", 18, ASSIGN) }sub pp_multiply { maybe_targmy(@_, \&binop, "*", 19, ASSIGN) }sub pp_subtract { maybe_targmy(@_, \&binop, "-",18, ASSIGN) }sub pp_divide { maybe_targmy(@_, \&binop, "/", 19, ASSIGN) }sub pp_modulo { maybe_targmy(@_, \&binop, "%", 19, ASSIGN) }sub pp_i_add { maybe_targmy(@_, \&binop, "+", 18, ASSIGN) }sub pp_i_multiply { maybe_targmy(@_, \&binop, "*", 19, ASSIGN) }sub pp_i_subtract { maybe_targmy(@_, \&binop, "-", 18, ASSIGN) }sub pp_i_divide { maybe_targmy(@_, \&binop, "/", 19, ASSIGN) }sub pp_i_modulo { maybe_targmy(@_, \&binop, "%", 19, ASSIGN) }sub pp_pow { maybe_targmy(@_, \&binop, "**", 22, ASSIGN) }sub pp_left_shift { maybe_targmy(@_, \&binop, "<<", 17, ASSIGN) }sub pp_right_shift { maybe_targmy(@_, \&binop, ">>", 17, ASSIGN) }sub pp_bit_and { maybe_targmy(@_, \&binop, "&", 13, ASSIGN) }sub pp_bit_or { maybe_targmy(@_, \&binop, "|", 12, ASSIGN) }sub pp_bit_xor { maybe_targmy(@_, \&binop, "^", 12, ASSIGN) }sub pp_eq { binop(@_, "==", 14) }sub pp_ne { binop(@_, "!=", 14) }sub pp_lt { binop(@_, "<", 15) }sub pp_gt { binop(@_, ">", 15) }sub pp_ge { binop(@_, ">=", 15) }sub pp_le { binop(@_, "<=", 15) }sub pp_ncmp { binop(@_, "<=>", 14) }sub pp_i_eq { binop(@_, "==", 14) }sub pp_i_ne { binop(@_, "!=", 14) }sub pp_i_lt { binop(@_, "<", 15) }sub pp_i_gt { binop(@_, ">", 15) }sub pp_i_ge { binop(@_, ">=", 15) }sub pp_i_le { binop(@_, "<=", 15) }sub pp_i_ncmp { binop(@_, "<=>", 14) }sub pp_seq { binop(@_, "eq", 14) }sub pp_sne { binop(@_, "ne", 14) }sub pp_slt { binop(@_, "lt", 15) }sub pp_sgt { binop(@_, "gt", 15) }sub pp_sge { binop(@_, "ge", 15) }sub pp_sle { binop(@_, "le", 15) }sub pp_scmp { binop(@_, "cmp", 14) }sub pp_sassign { binop(@_, "=", 7, SWAP_CHILDREN) }sub pp_aassign { binop(@_, "=", 7, SWAP_CHILDREN | LIST_CONTEXT) }sub pp_smartmatch { my ($self, $op, $cx) = @_; if ($op->flags & OPf_SPECIAL) { return $self->deparse($op->first, $cx); } else { binop(@_, "~~", 14); }}# `.' is special because concats-of-concats are optimized to save copying# by making all but the first concat stacked. The effect is as if the# programmer had written `($a . $b) .= $c', except legal.sub pp_concat { maybe_targmy(@_, \&real_concat) }sub real_concat { my $self = shift; my($op, $cx) = @_; my $left = $op->first; my $right = $op->last; my $eq = ""; my $prec = 18; if ($op->flags & OPf_STACKED and $op->first->name ne "concat") { $eq = "="; $prec = 7; } $left = $self->deparse_binop_left($op, $left, $prec); $right = $self->deparse_binop_right($op, $right, $prec); return $self->maybe_parens("$left .$eq $right", $cx, $prec);}# `x' is weird when the left arg is a listsub pp_repeat { my $self = shift; my($op, $cx) = @_; my $left = $op->first; my $right = $op->last; my $eq = ""; my $prec = 19; if ($op->flags & OPf_STACKED) { $eq = "="; $prec = 7; } if (null($right)) { # list repeat; count is inside left-side ex-list my $kid = $left->first->sibling; # skip pushmark my @exprs; for (; !null($kid->sibling); $kid = $kid->sibling) { push @exprs, $self->deparse($kid, 6); } $right = $kid; $left = "(" . join(", ", @exprs). ")"; } else { $left = $self->deparse_binop_left($op, $left, $prec); } $right = $self->deparse_binop_right($op, $right, $prec); return $self->maybe_parens("$left x$eq $right", $cx, $prec);}sub range { my $self = shift; my ($op, $cx, $type) = @_; my $left = $op->first; my $right = $left->sibling; $left = $self->deparse($left, 9); $right = $self->deparse($right, 9); return $self->maybe_parens("$left $type $right", $cx, 9);}sub pp_flop { my $self = shift; my($op, $cx) = @_; my $flip = $op->first; my $type = ($flip->flags & OPf_SPECIAL) ? "..." : ".."; return $self->range($flip->first, $cx, $type);}# one-line while/until is handled in pp_leavesub logop { my $self = shift; my ($op,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -