diff options
author | Gerard Goossen <gerard@tty.nl> | 2007-03-26 21:42:48 +0000 |
---|---|---|
committer | Dave Mitchell <davem@fdisolutions.com> | 2007-03-26 21:42:48 +0000 |
commit | 5b637447559beb710f02c7c6ec643905285a3dd8 (patch) | |
tree | 65e01c710f656be72b644171f07bd9ff2b66b9d3 /mad/Nomad.pm | |
parent | f8cc3bc6be850fbfb3161ff0957a723930f41e5b (diff) | |
download | perl-5b637447559beb710f02c7c6ec643905285a3dd8.tar.gz |
Rename mad/nomad to mad/Nomad.pm
Subject: Re: [PATCH] p55 tests
Message-ID: <20070322174056.GE24152@ostwald>
p4raw-id: //depot/perl@30767
Diffstat (limited to 'mad/Nomad.pm')
-rwxr-xr-x | mad/Nomad.pm | 3049 |
1 files changed, 3049 insertions, 0 deletions
diff --git a/mad/Nomad.pm b/mad/Nomad.pm new file mode 100755 index 0000000000..c62ae6a9b4 --- /dev/null +++ b/mad/Nomad.pm @@ -0,0 +1,3049 @@ +#!/usr/bin/perl + +# Suboptimal things: +# ast type info is generally still implicit +# the combined madness calls are actually losing type information +# brace madprops tend to be too low in the tree +# could use about 18 more refactorings... +# lots of unused cruft left around from previous refactorings + +use strict; +use warnings; +use Carp; + +use P5AST; +use P5re; + +my $dowarn = 0; +my $YAML = 0; +my $deinterpolate; + +while (@ARGV and $ARGV[0] =~ /^-./) { + my $switch = shift; + if ($switch eq '-w') { + $dowarn = 1; + } + elsif ($switch eq '-Y') { + $YAML = 1; + } + elsif ($switch eq '-d') { + $deinterpolate = 1; + } + else { + die "Unrecognized switch: -$switch"; + } +} + +@ARGV = ('foo.xml') unless @ARGV; +my $filename = shift; + +$::curstate = 0; +$::prevstate = 0; +$::curenc = 1; # start in iso-8859-1, sigh... + +$::H = "HeredocHere000"; +%::H = (); + +my @enc = ( + 'utf-8', + 'iso-8859-1', +); + +my %enc = ( + 'utf-8' => 0, + 'iso-8859-1' => 1, +); + +my %madtype = ( + '$' => 'p5::sigil', + '@' => 'p5::sigil', + '%' => 'p5::sigil', + '&' => 'p5::sigil', + '*' => 'p5::sigil', + 'o' => 'p5::operator', + '~' => 'p5::operator', + '+' => 'p5::punct', + '?' => 'p5::punct', + ':' => 'p5::punct', + ',' => 'p5::punct', + ';' => 'p5::punct', + '#' => 'p5::punct', + '(' => 'p5::opener', + ')' => 'p5::closer', + '[' => 'p5::opener', + ']' => 'p5::closer', + '{' => 'p5::opener', + '}' => 'p5::closer', + '1' => 'p5::punct', + '2' => 'p5::punct', + 'a' => 'p5::operator', + 'A' => 'p5::operator', + 'd' => 'p5::declarator', + 'E' => 'p5::text', + 'L' => 'p5::label', + 'm' => 'p5::remod', +# 'n' => 'p5::name', + 'q' => 'p5::openquote', + 'Q' => 'p5::closequote', + '=' => 'p5::text', + 'R' => 'p5::text', + 's' => 'p5::text', + 's' => 'p5::declarator', +# 'V' => 'p5::version', + 'X' => 'p5::token', +); + +$SIG{__DIE__} = sub { + my $e = shift; + $e =~ s/\n$/\n [NODE $filename line $::prevstate->{line}]/ if $::prevstate; + confess $e; +}; + +use Data::Dumper; +$Data::Dumper::Indent = 1; +$Data::Dumper::Quotekeys = 0; + +sub d { + my $text = Dumper(@_); + # doesn't scale well, alas + 1 while $text =~ s/(.*)^([^\n]*)bless\( \{\n(.*?)^(\s*\}), '([^']*)' \)([^\n]*)/$1$2$5 {\n$3$4$6 # $5/ms; + $text =~ s/PLXML:://g; + if ($text) { + my ($package, $filename, $line) = caller; + my $subroutine = (caller(1))[3]; + $text =~ s/\n?\z/, called from $subroutine, line $line\n/; + warn $text; + } +}; + +{ + + my %xmlrepl = ( + '&' => '&', + "'" => ''', + '"' => '&dquo;', + '<' => '<', + '>' => '>', + "\n" => ' ', + "\t" => '	', + ); + + sub x { + my $indent = 0; + if (@_ > 1) { + warn xdolist($indent,"LIST",@_); + } + else { + my $type = ref $_[0]; + if ($type) { + warn xdoitem($indent,$type,@_); + } + else { + warn xdoitem($indent,"ITEM",@_); + } + } + } + + sub xdolist { + my $indent = shift; + my $tag = shift; + my $in = ' ' x ($indent * 2); + my $result; + $result .= "$in<$tag>\n" if defined $tag; + for my $it (@_) { + my $itt = ref $it || "ITEM"; + $itt =~ s/::/:/g; + $result .= xdoitem($indent+1,$itt,$it); + } + $result .= "$in</$tag>\n" if defined $tag; + return $result; + } + + sub xdohash { + my $indent = shift; + my $tag = shift; + my $hash = shift; + my $in = ' ' x ($indent * 2); + my $result = "$in<$tag>\n"; + my @keys = sort keys %$hash; + my $longest = 0; + for my $k (@keys) { + $longest = length($k) if length($k) > $longest; + } + my $K; + for my $k (@keys) { + my $tmp; + $K = $$hash{$k}, next if $k eq 'Kids'; + my $sp = ' ' x ($longest - length($k)); + if (ref $$hash{$k}) { + $tmp = xdoitem($indent+1,"kv",$$hash{$k}); + $tmp =~ s!^ *<kv>\n *</kv>!$in <kv/>!; + } + else { + $tmp = xdoitem($indent+1,"kv",$$hash{$k}); + } + $k =~ s/([\t\n'"<>&])/$xmlrepl{$1}/g; + $tmp =~ s/<kv/<kv k='$k'$sp/ or + $tmp =~ s/^(.*)$/$in <kv k='$k'>\n$in $1$in <\/kv>\n/s; + $result .= $tmp; + } + if ($K and @$K) { + $result .= xdolist($indent, undef, @$K); + } + $result .= "$in</$tag>\n"; + } + + sub xdoitem { + my $indent = shift; + my $tag = shift; + my $item = shift; + my $in = ' ' x ($indent * 2); + my $r = ref $item; + if (not $r) { + $item =~ s/([\t\n'"<>&])/$xmlrepl{$1}/g; + return "$in<$tag>$item</$tag>\n"; + } + (my $newtag = $r) =~ s/::/:/g; + my $t = "$item"; + if ($t =~ /\bARRAY\b/) { + if (@{$item}) { + return xdolist($indent,$tag,@{$item}); + } + else { + return "$in<$tag />\n"; + } + } + if ($t =~ /\bHASH\b/) { + return xdohash($indent,$tag,$item); + } + if ($r =~ /^p5::/) { + return "$in<$newtag>$$item</$newtag>\n"; + } + else { + return "$in<$newtag type='$r'/>\n"; + } + } + + my %trepl = ( + "'" => '\\\'', + '"' => '\\"', + "\n" => '\\n', + "\t" => '\\t', + ); + + sub t { + my $indent = 0; + if (@_ > 1) { + tdolist($indent,"LIST",@_); + } + else { + my $type = ref $_[0]; + if ($type) { + tdoitem($indent,$type,@_); + } + else { + tdoitem($indent,"ITEM",@_); + } + } + print STDERR "\n"; + } + + sub tdolist { + my $indent = shift; + my $tag = shift || "ARRAY"; + my $in = ' ' x ($indent * 2); + if (@_) { + print STDERR "[\n"; + for my $it (@_) { + my $itt = ref $it || "ITEM"; + print STDERR $in," "; + tdoitem($indent+1,$itt,$it); + print STDERR "\n"; + } + print STDERR "$in]"; + } + else { + print STDERR "[]"; + } + } + + sub tdohash { + my $indent = shift; + my $tag = shift; + my $hash = shift; + my $in = ' ' x ($indent * 2); + + print STDERR "$tag => {\n"; + + my @keys = sort keys %$hash; + my $longest = 0; + for my $k (@keys) { + $longest = length($k) if length($k) > $longest; + } + my $K; + for my $k (@keys) { + my $sp = ' ' x ($longest - length($k)); + print STDERR "$in $k$sp => "; + tdoitem($indent+1,"",$$hash{$k}); + if ($k eq 'Kids') { + print STDERR " # Kids"; + } + print STDERR "\n"; + } + print STDERR "$in} # $tag"; + } + + sub tdoitem { + my $indent = shift; + my $tag = shift; + my $item = shift; + if (not defined $item) { + print STDERR "UNDEF"; + return; + } +# my $in = ' ' x ($indent * 2); + my $r = ref $item; + if (not $r) { + $item =~ s/([\t\n"])/$trepl{$1}/g; + print STDERR "\"$item\""; + return; + } + my $t = "$item"; + if ($r =~ /^p5::/) { + my $str = $$item{uni}; + my $enc = $enc[$$item{enc}] . ' '; + $enc =~ s/iso-8859-1 //; + $str =~ s/([\t\n"])/$trepl{$1}/g; + print STDERR "$r $enc\"$str\""; + } + elsif ($t =~ /\bARRAY\b/) { + tdolist($indent,$tag,@{$item}); + } + elsif ($t =~ /\bHASH\b/) { + tdohash($indent,$tag,$item); + } + else { + print STDERR "$r type='$r'"; + } + } +} + +sub encnum { + my $encname = shift; + if (not exists $enc{$encname}) { + push @enc, $encname; + return $enc{$encname} = $#enc; + } + return $enc{$encname}; +} + +use PLXML; + +use XML::Parser; +my $p1 = new XML::Parser(Style => 'Objects', Pkg => 'PLXML'); +$p1->setHandlers('Char' => sub { warn "Chars $_[1]" if $_[1] =~ /\S/; }); + +# First slurp XML into tree of objects. + +my $root = $p1->parsefile($filename); + +# Now turn XML tree into something more like an AST. + +PLXML::prepreproc($root->[0]); +my $ast = P5AST->new('Kids' => [$root->[0]->ast()]); +#::t($ast); + +if ($YAML) { + require YAML::Syck; + print YAML::Syck::Dump($ast); + exit; +} + +# Finally, walk AST to produce new program. + +my $text = $ast->p5text(); # returns encoded, must output raw +print $text; + +package p5::text; + +use Encode; + +sub new { + my $class = shift; + my $text = shift; + die "Too many args to new" if @_; + die "Attempt to bless non-text $text" if ref $text; + return bless( { uni => $text, + enc => $::curenc, + }, $class); +} + +sub uni { my $self = shift; $$self{uni}; } # internal stuff all in utf8 + +sub enc { + my $self = shift; + my $enc = $enc[$$self{enc} || 0]; + return encode($enc, $$self{uni}); +} + +package p5::closequote; BEGIN { @p5::closequote::ISA = 'p5::punct'; } +package p5::closer; BEGIN { @p5::closer::ISA = 'p5::punct'; } +package p5::declarator; BEGIN { @p5::declarator::ISA = 'p5::token'; } +package p5::junk; BEGIN { @p5::junk::ISA = 'p5::text'; } +package p5::label; BEGIN { @p5::label::ISA = 'p5::token'; } +#package p5::name; BEGIN { @p5::name::ISA = 'p5::token'; } +package p5::opener; BEGIN { @p5::opener::ISA = 'p5::punct'; } +package p5::openquote; BEGIN { @p5::openquote::ISA = 'p5::punct'; } +package p5::operator; BEGIN { @p5::operator::ISA = 'p5::token'; } +package p5::punct; BEGIN { @p5::punct::ISA = 'p5::token'; } +package p5::remod; BEGIN { @p5::remod::ISA = 'p5::token'; } +package p5::sigil; BEGIN { @p5::sigil::ISA = 'p5::punct'; } +package p5::token; BEGIN { @p5::token::ISA = 'p5::text'; } +#package p5::version; BEGIN { @p5::version::ISA = 'p5::token'; } + +################################################################ +# Routines to turn XML tree into an AST. Mostly this amounts to hoisting +# misplaced nodes and flattening various things into lists. + +package PLXML; + +sub AUTOLOAD { + ::x("AUTOLOAD $PLXML::AUTOLOAD", @_); + return "[[[ $PLXML::AUTOLOAD ]]]"; +} + +sub prepreproc { + my $self = shift; + my $kids = $$self{Kids}; + $self->{mp} = {}; + if (defined $kids) { + my $i; + for ($i = 0; $i < @$kids; $i++) { + if (ref $kids->[$i] eq "PLXML::madprops") { + $self->{mp} = splice(@$kids, $i, 1)->hash($self,@_); + $i--; + next; + } + else { + prepreproc($kids->[$i], $self, @_); + } + } + } +} + +sub preproc { + my $self = shift; + if (ref $self eq 'PLXML::op_null' and $$self{was}) { + return "PLXML::op_$$self{was}"->key(); + } + else { + return $self->key(); + } +} + +sub newtype { + my $self = shift; + my $t = ref $self || $self; + $t = "PLXML::op_$$self{was}" if $t eq 'PLXML::op_null' and $$self{was}; + $t =~ s/PLXML/P5AST/ or die "Bad type: $t"; + return $t; +} + +sub madness { + my $self = shift; + my @keys = split(' ', shift); + my @vals = (); + for my $key (@keys) { + my $madprop = $self->{mp}{$key}; + next unless defined $madprop; + if (ref $madprop eq 'PLXML::mad_op') { + if ($key eq 'b') { + push @vals, $madprop->blockast($self, @_); + } + else { + push @vals, $madprop->ast($self, @_); + } + next; + } + my $white; + if ($white = $self->{mp}{"_$key"}) { + push @vals, p5::junk->new($white); + } + my $type = $madtype{$key} || "p5::token"; + push @vals, $type->new($madprop); + if ($white = $self->{mp}{"#$key"}) { + push @vals, p5::junk->new($white); + } + } + @vals; +} + +sub blockast { + my $self = shift; + $self->ast(@_); +} + +sub ast { + my $self = shift; + + my @newkids; + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + return $self->newtype->new(Kids => [uc $self->key(), "(", @newkids, ")"]); +} + +sub op { + my $self = shift; + my $desc = $self->desc(); + if ($desc =~ /\((.*?)\)/) { + return $1; + } + else { + return " <<" . $self->key() . ">> "; + } +} + +sub mp { + my $self = shift; + return $self->{mp}; +} + +package PLXML::Characters; + +sub ast { die "oops" } +sub pair { die "oops" } + +package PLXML::madprops; + +sub ast { + die "oops madprops"; +} + +sub hash { + my $self = shift; + my @pairs; + my %hash = (); + my $firstthing = ''; + my $lastthing = ''; + + # We need to guarantee key uniqueness at this point. + for my $kid (@{$$self{Kids}}) { + my ($k,$v) = $kid->pair($self, @_); + $firstthing ||= $k; + if ($k =~ /^[_#]$/) { # rekey whitespace according to preceding entry + $k .= $lastthing; # (which is actually the token the whitespace is before) + } + else { + $k .= 'x' while exists $hash{$k}; + $lastthing = $k; + } + $hash{$k} = $v; + } + $hash{FIRST} = $firstthing; + $hash{LAST} = $lastthing; + return \%hash; +} + +package PLXML::mad_op; + +sub pair { + my $self = shift; + my $key = $$self{key}; + return $key,$self; +} + +sub ast { + my $self = shift; + $self->prepreproc(@_); + my @vals; + for my $kid (@{$$self{Kids}}) { + push @vals, $kid->ast($self, @_); + } + if (@vals == 1) { + return @vals; + } + else { + return P5AST::op_list->new(Kids => [@vals]); + } +} + +sub blockast { + my $self = shift; + $self->prepreproc(@_); + my @vals; + for my $kid (@{$$self{Kids}}) { + push @vals, $kid->blockast($self, @_); + } + if (@vals == 1) { + return @vals; + } + else { + return P5AST::op_lineseq->new(Kids => [@vals]); + } +} + +package PLXML::mad_pv; + +sub pair { + my $self = shift; + my $key = $$self{key}; + my $val = $$self{val}; + $val =~ s/STUPIDXML\(#x(\w+)\)/chr(hex $1)/eg; + return $key,$val; +} + +package PLXML::mad_sv; + +sub pair { + my $self = shift; + my $key = $$self{key}; + my $val = $$self{val}; + $val =~ s/STUPIDXML\(#x(\w+)\)/chr(hex $1)/eg; + return $key,$val; +} + +package PLXML::baseop; + +sub ast { + my $self = shift; + + my @retval; + my @newkids; + push @retval, $self->madness('M ox'); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + if (@newkids) { + push @retval, uc $self->key(), "(", @newkids , ")"; + } + else { + push @retval, $self->madness('o ( )'); + } + return $self->newtype->new(Kids => [@retval]); +} + +package PLXML::baseop_unop; + +sub ast { + my $self = shift; + my @newkids = $self->madness('d M ox o ('); + + if (exists $$self{Kids}) { + my $arg = $$self{Kids}[0]; + push @newkids, $arg->ast($self, @_) if defined $arg; + } + push @newkids, $self->madness(')'); + + return $self->newtype()->new(Kids => [@newkids]); +} + +package PLXML::binop; + +sub ast { + my $self = shift; + my @newkids; + + push @newkids, $self->madness('M ox'); + + my $left = $$self{Kids}[0]; + push @newkids, $left->ast($self, @_); + + push @newkids, $self->madness('o'); + + my $right = $$self{Kids}[1]; + if (defined $right) { + push @newkids, $right->ast($self, @_); + } + + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::cop; + +package PLXML::filestatop; + +sub ast { + my $self = shift; + + my @newkids = $self->madness('o ('); + + if (@{$$self{Kids}}) { + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + } + if ($$self{mp}{O}) { + push @newkids, $self->madness('O'); + } + push @newkids, $self->madness(')'); + + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::listop; + +sub ast { + my $self = shift; + + my @retval; + my @before; + my @after; + if (@before = $self->madness('M')) { + push @before, $self->madness('ox'); # o is the function name + } + if (@retval = $self->madness('X')) { + push @before, $self->madness('o x'); + return P5AST::listop->new(Kids => [@before,@retval]); + } + + push @retval, $self->madness('o ( [ {'); + + my @newkids; + for my $kid (@{$$self{Kids}}) { + next if ref $kid eq 'PLXML::op_pushmark'; + next if ref $kid eq 'PLXML::op_null' and + defined $$kid{was} and $$kid{was} eq 'pushmark'; + push @newkids, $kid->ast($self, @_); + } + + my $x = ""; + + if ($$self{mp}{S}) { + push @retval, $self->madness('S'); + } + push @retval, @newkids; + + push @retval, $self->madness('} ] )'); + return $self->newtype->new(Kids => [@before,@retval,@after]); +} + +package PLXML::logop; + +sub ast { + my $self = shift; + + my @newkids; + push @newkids, $self->madness('o ('); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + push @newkids, $self->madness(')'); + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::loop; + +package PLXML::loopexop; + +sub ast { + my $self = shift; + my @newkids = $self->madness('o ('); + + if ($$self{mp}{L} or not $$self{flags} =~ /\bSPECIAL\b/) { + my @label = $self->madness('L'); + if (@label) { + push @newkids, @label; + } + else { + my $arg = $$self{Kids}[0]; + push @newkids, $arg->ast($self, @_) if defined $arg; + } + } + push @newkids, $self->madness(')'); + + return $self->newtype->new(Kids => [@newkids]); +} + + +package PLXML::padop; + +package PLXML::padop_svop; + +package PLXML::pmop; + +sub ast { + my $self = shift; + + return P5AST::pmop->new(Kids => []) unless exists $$self{flags}; + + my $bits = $self->fetchbits($$self{flags},@_); + + my @newkids; + if ($bits->{binding}) { + push @newkids, $bits->{binding}; + push @newkids, $self->madness('~'); + } + if (exists $bits->{regcomp} and $bits->{regcomp}) { + my @front = $self->madness('q'); + my @back = $self->madness('Q'); + push @newkids, @front, $bits->{regcomp}, @back, + $self->madness('m'); + } + elsif ($$self{mp}{q}) { + push @newkids, $self->madness('q = Q m'); + } + elsif ($$self{mp}{X}) { + push @newkids, $self->madness('X m'); + } + else { + push @newkids, $self->madness('e m'); + } + + return $self->newtype->new(Kids => [@newkids]); +} + +sub innerpmop { + my $pmop = shift; + my $bits = shift; + for my $key (grep {!/^Kids/} keys %$pmop) { + $bits->{$key} = $pmop->{$key}; + } + + # Have to delete all the fake evals of the repl. This is a pain... + if (@{$$pmop{Kids}}) { + my $really = $$pmop{Kids}[0]{Kids}[0]; + if (ref $really eq 'PLXML::op_substcont') { + $really = $$really{Kids}[0]; + } + while ((ref $really) =~ /^PLXML::op_.*(null|entereval)/) { + if (exists $$really{was}) { + $bits->{repl} = $really->ast(@_); + return; + } + $really = $$really{Kids}[0]; + } + if (ref $really eq 'PLXML::op_scope' and + @{$$really{Kids}} == 1 and + ref $$really{Kids}[0] eq 'PLXML::op_null' and + not @{$$really{Kids}[0]{Kids}}) + { + $bits->{repl} = ''; + return; + } + if (ref $really eq 'PLXML::op_leave' and + @{$$really{Kids}} == 2 and + ref $$really{Kids}[1] eq 'PLXML::op_null' and + not @{$$really{Kids}[1]{Kids}}) + { + $bits->{repl} = ''; + return; + } + if ((ref $really) =~ /^PLXML::op_(scope|leave)/) { + # should be at inner do {...} here, so skip that fakery too + $bits->{repl} = $really->newtype->new(Kids => [$really->PLXML::op_lineseq::lineseq(@_)]); + # but retrieve the whitespace before fake '}' + if ($$really{mp}{'_}'}) { + push(@{$bits->{repl}->{Kids}}, p5::junk->new($$really{mp}{'_}'})); + } + } + else { # something else, padsv probably + $bits->{repl} = $really->ast(@_); + } + } +} + +sub fetchbits { + my $self = shift; + my $flags = shift || ''; + my %bits = %$self; + my @kids = @{$$self{Kids}}; + if (@kids) { + delete $bits{Kids}; + my $arg = shift @kids; + innerpmop($arg,\%bits, $self, @_); + if ($flags =~ /STACKED/) { + $arg = shift @kids; + $bits{binding} = $arg->ast($self, @_); + } + if ($bits{when} ne "COMP" and @kids) { + $arg = pop @kids; + $bits{regcomp} = $arg->ast($self, @_); + } + if (not exists $bits{repl} and @kids) { + $arg = shift @kids; + $bits{repl} = $arg->ast($self, @_); + } + } + return \%bits; +} + +package PLXML::pvop_svop; + +package PLXML::unop; + +sub ast { + my $self = shift; + my @newkids = $self->madness('o ('); + + if (exists $$self{Kids}) { + my $arg = $$self{Kids}[0]; + push @newkids, $arg->ast($self, @_) if defined $arg; + } + push @newkids, $self->madness(')'); + + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML; +package PLXML::Characters; +package PLXML::madprops; +package PLXML::mad_op; +package PLXML::mad_pv; +package PLXML::baseop; +package PLXML::baseop_unop; +package PLXML::binop; +package PLXML::cop; +package PLXML::filestatop; +package PLXML::listop; +package PLXML::logop; +package PLXML::loop; +package PLXML::loopexop; +package PLXML::padop; +package PLXML::padop_svop; +package PLXML::pmop; +package PLXML::pvop_svop; +package PLXML::unop; +package PLXML::op_null; + +# Null nodes typed by first madprop. + +my %astmad; + +BEGIN { + %astmad = ( + 'p' => sub { # peg for #! line, etc. + my $self = shift; + my @newkids; + push @newkids, $self->madness('p px'); + $::curstate = 0; + return P5AST::peg->new(Kids => [@newkids]) + }, + '(' => sub { # extra parens around the whole thing + my $self = shift; + my @newkids; + push @newkids, $self->madness('dx d o ('); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + push @newkids, $self->madness(')'); + return P5AST::parens->new(Kids => [@newkids]) + }, + '~' => sub { # binding operator + my $self = shift; + my @newkids; + push @newkids, $$self{Kids}[0]->ast($self,@_); + push @newkids, $self->madness('~'); + push @newkids, $$self{Kids}[1]->ast($self,@_); + return P5AST::bindop->new(Kids => [@newkids]) + }, + ';' => sub { # null statements/blocks + my $self = shift; + my @newkids; + push @newkids, $self->madness('{ ; }'); + $::curstate = 0; + return P5AST::nothing->new(Kids => [@newkids]) + }, + 'I' => sub { # if or unless statement keyword + my $self = shift; + my @newkids; + push @newkids, $self->madness('L I ('); + my @subkids; + for my $kid (@{$$self{Kids}}) { + push @subkids, $kid->ast($self, @_); + } + die "oops in op_null->new" unless @subkids == 1; + my $newself = $subkids[0]; + @subkids = @{$$newself{Kids}}; + + unshift @{$subkids[0]{Kids}}, @newkids; + push @{$subkids[0]{Kids}}, $self->madness(')'); + return bless($newself, 'P5AST::condstate'); + }, + 'U' => sub { # use + my $self = shift; + my @newkids; + my @module = $self->madness('U'); + my @args = $self->madness('A'); + my $module = $module[-1]{Kids}[-1]; + if ($module->uni eq 'bytes') { + $::curenc = ::encnum('iso-8859-1'); + } + elsif ($module->uni eq 'utf8') { + if ($$self{mp}{o} eq 'no') { + $::curenc = ::encnum('iso-8859-1'); + } + else { + $::curenc = ::encnum('utf-8'); + } + } + elsif ($module->uni eq 'encoding') { + if ($$self{mp}{o} eq 'no') { + $::curenc = ::encnum('iso-8859-1'); + } + else { + $::curenc = ::encnum(eval $args[0]->p5text); # XXX bletch + } + } + # (Surrounding {} ends up here if use is only thing in block.) + push @newkids, $self->madness('{ o'); + push @newkids, @module; + push @newkids, $self->madness('V'); + push @newkids, @args; + push @newkids, $self->madness('S ; }'); + $::curstate = 0; + return P5AST::use->new(Kids => [@newkids]) + }, + '?' => sub { # ternary + my $self = shift; + my @newkids; + my @subkids; + my @condkids = @{$$self{Kids}[0]{Kids}}; + + push @newkids, $condkids[0]->ast($self,@_), $self->madness('?'); + push @newkids, $condkids[1]->ast($self,@_), $self->madness(':'); + push @newkids, $condkids[2]->ast($self,@_); + return P5AST::ternary->new(Kids => [@newkids]) + }, + '&' => sub { # subroutine + my $self = shift; + my @newkids; + push @newkids, $self->madness('d n s a : { & } ;'); + $::curstate = 0; + return P5AST::sub->new(Kids => [@newkids]) + }, + 'i' => sub { # modifier if + my $self = shift; + my @newkids; + push @newkids, $self->madness('i'); + my $cond = $$self{Kids}[0]; + my @subkids; + for my $kid (@{$$cond{Kids}}) { + push @subkids, $kid->ast($self, @_); + } + push @newkids, shift @subkids; + unshift @newkids, @subkids; + return P5AST::condmod->new(Kids => [@newkids]) + }, + 'P' => sub { # package declaration + my $self = shift; + my @newkids; + push @newkids, $self->madness('o'); + push @newkids, $self->madness('P'); + push @newkids, $self->madness(';'); + $::curstate = 0; + return P5AST::package->new(Kids => [@newkids]) + }, + 'F' => sub { # format + my $self = shift; + my @newkids = $self->madness('F n b'); + $::curstate = 0; + return P5AST::format->new(Kids => [@newkids]) + }, + 'x' => sub { # qw literal + my $self = shift; + return P5AST::qwliteral->new(Kids => [$self->madness('x')]) + }, + 'q' => sub { # random quote + my $self = shift; + return P5AST::quote->new(Kids => [$self->madness('q = Q')]) + }, + 'X' => sub { # random literal + my $self = shift; + return P5AST::token->new(Kids => [$self->madness('X')]) + }, + ':' => sub { # attr list + my $self = shift; + return P5AST::attrlist->new(Kids => [$self->madness(':')]) + }, + ',' => sub { # "unary ," so to speak + my $self = shift; + my @newkids; + push @newkids, $self->madness(','); + push @newkids, $$self{Kids}[0]->ast($self,@_); + return P5AST::listelem->new(Kids => [@newkids]) + }, + 'C' => sub { # constant conditional + my $self = shift; + my @newkids; + push @newkids, $$self{Kids}[0]->ast($self,@_); + my @folded = $self->madness('C'); + if (@folded) { + my @t = $self->madness('t'); + my @e = $self->madness('e'); + if (@e) { + return P5AST::op_cond_expr->new( + Kids => [ + $self->madness('I ('), + @folded, + $self->madness(') ?'), + P5AST::op_cond_expr->new(Kids => [@newkids]), + $self->madness(':'), + @e + ] ); + } + else { + return P5AST::op_cond_expr->new( + Kids => [ + $self->madness('I ('), + @folded, + $self->madness(') ?'), + @t, + $self->madness(':'), + @newkids + ] ); + } + } + return P5AST::op_null->new(Kids => [@newkids]) + }, + '+' => sub { # unary + + my $self = shift; + my @newkids; + push @newkids, $self->madness('+'); + push @newkids, $$self{Kids}[0]->ast($self,@_); + return P5AST::preplus->new(Kids => [@newkids]) + }, + 'D' => sub { # do block + my $self = shift; + my @newkids; + push @newkids, $self->madness('D'); + push @newkids, $$self{Kids}[0]->ast($self,@_); + return P5AST::doblock->new(Kids => [@newkids]) + }, + '3' => sub { # C-style for loop + my $self = shift; + my @newkids; + + # What a mess! + my (undef, $init, $lineseq) = @{$$self{Kids}[0]{Kids}}; + my (undef, $leaveloop) = @{$$lineseq{Kids}}; + my (undef, $null) = @{$$leaveloop{Kids}}; + my $and; + my $cond; + my $lineseq2; + my $block; + my $cont; + if (exists $$null{was} and $$null{was} eq 'and') { + ($lineseq2) = @{$$null{Kids}}; + } + else { + ($and) = @{$$null{Kids}}; + ($cond, $lineseq2) = @{$$and{Kids}}; + } + if ($$lineseq2{mp}{'{'}) { + $block = $lineseq2; + } + else { + ($block, $cont) = @{$$lineseq2{Kids}}; + } + + push @newkids, $self->madness('L 3 ('); + push @newkids, $init->ast($self,@_); + push @newkids, $self->madness('1'); + if (defined $cond) { + push @newkids, $cond->ast($self,@_); + } + elsif (defined $null) { + push @newkids, $null->madness('1'); + } + push @newkids, $self->madness('2'); + if (defined $cont) { + push @newkids, $cont->ast($self,@_); + } + push @newkids, $self->madness(')'); + push @newkids, $block->blockast($self,@_); + $::curstate = 0; + return P5AST::cfor->new(Kids => [@newkids]) + }, + 'o' => sub { # random useless operator + my $self = shift; + my @newkids; + push @newkids, $self->madness('o'); + my $kind = $newkids[-1] || ''; + $kind = $kind->uni if ref $kind; + my @subkids; + for my $kid (@{$$self{Kids}}) { + push @subkids, $kid->ast($self, @_); + } + if ($kind eq '=') { # stealth readline + unshift(@newkids, shift(@subkids)); + push(@newkids, @subkids); + return P5AST::op_aassign->new(Kids => [@newkids]) + } + else { + my $newself = $subkids[0]; + splice(@{$newself->{Kids}}, 1, 0, + $self->madness('ox ('), + @newkids, + $self->madness(')') + ); + return $newself; + } + }, + ); +} + +# Null nodes are an untyped mess inside Perl. Instead of fixing it there, +# we derive an effective type either from the "was" field or the first madprop. +# (The individual routines select the actual new type.) + +sub ast { + my $self = shift; + my $was = $$self{was} || 'peg'; + my $mad = $$self{mp}{FIRST} || "unknown"; + + # First try for a "was". + my $meth = "PLXML::op_${was}::astnull"; + if (exists &{$meth}) { + return $self->$meth(@_); + } + + # Look at first madprop. + if (exists $astmad{$mad}) { + return $astmad{$mad}->($self); + } + warn "No mad $mad" unless $mad eq 'unknown'; + + # Do something generic. + my @newkids; + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + return $self->newtype->new(Kids => [@newkids]); +} + +sub blockast { + my $self = shift; + local $::curstate; + local $::curenc = $::curenc; + return $self->madness('{ ; }'); +} + +package PLXML::op_stub; + +sub ast { + my $self = shift; + return $self->newtype->new(Kids => [$self->madness(', x ( ) q = Q')]); +} + +package PLXML::op_scalar; + +sub ast { + my $self = shift; + + my @pre = $self->madness('o q'); + my $op = pop @pre; + if ($op->uni =~ /^<</) { + my @newkids; + my $opstub = bless { start => $op }, 'P5AST::heredoc'; + push @newkids, $opstub; + push @newkids, $self->madness('('); + + my @kids = @{$$self{Kids}}; + + my @divert; + for my $kid (@kids) { + next if ref $kid eq 'PLXML::op_pushmark'; + next if ref $kid eq 'PLXML::op_null' and + defined $$kid{was} and $$kid{was} eq 'pushmark'; + push @divert, $kid->ast($self, @_); + } + $opstub->{doc} = P5AST::op_list->new(Kids => [@divert]); + $opstub->{end} = ($self->madness('Q'))[-1]; + + push @newkids, $self->madness(')'); + + return $self->newtype->new(Kids => [@pre,@newkids]); + } + return $self->PLXML::baseop_unop::ast(); +} + +package PLXML::op_pushmark; + +sub ast { () } + +package PLXML::op_wantarray; +package PLXML::op_const; + +sub astnull { + my $self = shift; + my @newkids; + return unless $$self{mp}; + push @newkids, $self->madness('q = Q X : f O ( )'); + return P5AST::op_const->new(Kids => [@newkids]); +} + +sub ast { + my $self = shift; + return unless %{$$self{mp}}; + + my @before; + + my $const; + my @args = $self->madness('f'); + if (@args) { + } + elsif (exists $self->{mp}{q}) { + push @args, $self->madness('d q'); + if ($args[-1]->uni =~ /^<</) { + my $opstub = bless { start => pop(@args) }, 'P5AST::heredoc'; + $opstub->{doc} = P5AST::op_const->new(Kids => [$self->madness('=')]); + $opstub->{end} = ($self->madness('Q'))[-1]; + push @args, $opstub; + } + else { + push @args, $self->madness('= Q'); + } + } + elsif (exists $self->{mp}{X}) { + push @before, $self->madness('d'); # was local $[ probably + if (not $$self{mp}{O}) { + push @before, $self->madness('o'); # was unary + } + my @X = $self->madness(': X'); + if (exists $$self{private} and $$self{private} =~ /BARE/) { + return $self->newtype->new(Kids => [@X]); + } + my $X = pop @X; + push @before, @X; + @args = ( + $self->madness('x'), + $X); + if ($$self{mp}{O}) { + push @args, $self->madness('o O'); + } + } + elsif (exists $self->{mp}{O}) { + push @args, $self->madness('O'); + } + elsif ($$self{private} =~ /\bBARE\b/) { + @args = ($$self{PV}); + } + elsif (exists $$self{mp}{o}) { + @args = $self->madness('o'); + } + elsif (exists $$self{PV}) { + @args = ('"', $$self{PV}, '"'); + } + elsif (exists $$self{NV}) { + @args = $$self{NV}; + } + elsif (exists $$self{IV}) { + @args = $$self{IV}; + } + else { + @args = $self->SUPER::text(@_); + } + return $self->newtype->new(Kids => [@before, @args]); +} + + +package PLXML::op_gvsv; + +sub ast { + my $self = shift; + my @args; + my @retval; + for my $attr (qw/gv GV flags/) { + if (exists $$self{$attr}) { + push @args, $attr, $$self{$attr}; + } + } + push @retval, @args; + push @retval, $self->madness('X'); + return $self->newtype->new(Kids => [@retval]); +} + +package PLXML::op_gv; + +sub ast { + my $self = shift; + my @newkids; + push @newkids, $self->madness('X K'); + + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_gelem; + +sub ast { + my $self = shift; + + local $::curstate; # in case there are statements in subscript + local $::curenc = $::curenc; + my @newkids; + push @newkids, $self->madness('dx d'); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + splice @newkids, -1, 0, $self->madness('o {'); + push @newkids, $self->madness('}'); + + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_padsv; + +sub ast { + my $self = shift; + my @args; + push @args, $self->madness('dx d ( $ )'); + + return $self->newtype->new(Kids => [@args]); +} + +package PLXML::op_padav; + +sub astnull { ast(@_) } + +sub ast { + my $self = shift; + my @retval; + push @retval, $self->madness('dx d ('); + push @retval, $self->madness('$ @'); + push @retval, $self->madness(') o O'); + return $self->newtype->new(Kids => [@retval]); +} + +package PLXML::op_padhv; + +sub astnull { ast(@_) } + +sub ast { + my $self = shift; + my @retval; + push @retval, $self->madness('dx d ('); + push @retval, $self->madness('$ @ %'); + push @retval, $self->madness(') o O'); + return $self->newtype->new(Kids => [@retval]); +} + +package PLXML::op_padany; + +package PLXML::op_pushre; + +sub ast { + my $self = shift; + if ($$self{mp}{q}) { + return $self->madness('q = Q m'); + } + if ($$self{mp}{X}) { + return $self->madness('X m'); + } + if ($$self{mp}{e}) { + return $self->madness('e m'); + } + return $$self{Kids}[1]->ast($self,@_), $self->madness('m'); +} + +package PLXML::op_rv2gv; + +sub ast { + my $self = shift; + + my @newkids; + push @newkids, $self->madness('dx d ( * $'); + push @newkids, $$self{Kids}[0]->ast(); + push @newkids, $self->madness(')'); + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_rv2sv; + +sub astnull { + my $self = shift; + return P5AST::op_rv2sv->new(Kids => [$self->madness('O o dx d ( $ ) : a')]); +} + +sub ast { + my $self = shift; + + my @newkids; + push @newkids, $self->madness('dx d ( $'); + if (ref $$self{Kids}[0] ne "PLXML::op_gv") { + push @newkids, $$self{Kids}[0]->ast(); + } + push @newkids, $self->madness(') : a'); + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_av2arylen; + +sub ast { + my $self = shift; + + my @newkids; + push @newkids, $$self{Kids}[0]->madness('l'); + push @newkids, $$self{Kids}[0]->ast(); + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_rv2cv; + +sub astnull { + my $self = shift; + my @newkids; + push @newkids, $self->madness('X'); + return @newkids if @newkids; + if (exists $$self{mp}{'&'}) { + push @newkids, $self->madness('&'); + if (@{$$self{Kids}}) { + push @newkids, $$self{Kids}[0]->ast(@_); + } + } + else { + push @newkids, $$self{Kids}[0]->ast(@_); + } + return P5AST::op_rv2cv->new(Kids => [@newkids]); +} + +sub ast { + my $self = shift; + + my @newkids; + push @newkids, $self->madness('&'); + if (@{$$self{Kids}}) { + push @newkids, $$self{Kids}[0]->ast(); + } + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_anoncode; + +sub ast { + my $self = shift; + my $arg = $$self{Kids}[0]; + local $::curstate; # hide nested statements in sub + local $::curenc = $::curenc; + if (defined $arg) { + return $arg->ast(@_); + } + return ';'; # XXX literal ; should come through somewhere +} + +package PLXML::op_prototype; +package PLXML::op_refgen; + +sub ast { + my $self = shift; + my @newkids = $self->madness('o s a'); + + if (exists $$self{Kids}) { + my $arg = $$self{Kids}[0]; + push @newkids, $arg->ast($self, @_) if defined $arg; + } + + my $res = $self->newtype->new(Kids => [@newkids]); + return $res; +} + +package PLXML::op_srefgen; + +sub ast { + my @newkids; + my $self = shift; + if ($$self{mp}{FIRST} eq '{') { + local $::curstate; # this is officially a block, so hide it + local $::curenc = $::curenc; + push @newkids, $self->madness('{'); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + push @newkids, $self->madness('; }'); + return P5AST::op_stringify->new(Kids => [@newkids]); + } + else { + push @newkids, $self->madness('o ['); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + push @newkids, $self->madness(']'); + return P5AST::op_stringify->new(Kids => [@newkids]); + } +} + +package PLXML::op_ref; +package PLXML::op_bless; +package PLXML::op_backtick; + +sub ast { + my $self = shift; + my @args; + if (exists $self->{mp}{q}) { + push @args, $self->madness('q'); + if ($args[-1]->uni =~ /^<</) { + my $opstub = bless { start => $args[-1] }, 'P5AST::heredoc'; + $args[-1] = $opstub; + $opstub->{doc} = P5AST::op_const->new(Kids => [$self->madness('=')]); + $opstub->{end} = ($self->madness('Q'))[-1]; + } + else { + push @args, $self->madness('= Q'); + } + } + return $self->newtype->new(Kids => [@args]); +} + +package PLXML::op_glob; + +sub astnull { + my $self = shift; + my @retval = $self->madness('o q = Q'); + if (not @retval or $retval[-1]->uni eq 'glob') { + push @retval, $self->madness('('); + push @retval, $$self{Kids}[0]->ast($self,@_); + push @retval, $self->madness(')'); + } + return P5AST::op_glob->new(Kids => [@retval]); +} + +package PLXML::op_readline; + +sub astnull { + my $self = shift; + my @retval; + if (exists $$self{mp}{q}) { + @retval = $self->madness('q = Q'); + } + elsif (exists $$self{mp}{X}) { + @retval = $self->madness('X'); + } + return P5AST::op_readline->new(Kids => [@retval]); +} + +sub ast { + my $self = shift; + + my @retval; + + my @args; + my $const; + if (exists $$self{mp}{q}) { + @args = $self->madness('q = Q'); + } + elsif (exists $$self{mp}{X}) { + @args = $self->madness('X'); + } + elsif (exists $$self{GV}) { + @args = $$self{IV}; + } + elsif (@{$$self{Kids}}) { + @args = $self->PLXML::unop::ast(@_); + } + else { + @args = $self->SUPER::text(@_); + } + return $self->newtype->new(Kids => [@retval,@args]); +} + + +package PLXML::op_rcatline; +package PLXML::op_regcmaybe; +package PLXML::op_regcreset; +package PLXML::op_regcomp; + +sub ast { + my $self = shift; + $self->PLXML::unop::ast(@_); +} + +package PLXML::op_match; + +sub ast { + my $self = shift; + my $retval = $self->SUPER::ast(@_); + my $p5re; + if (not $p5re = $retval->p5text()) { + $retval = $self->newtype->new(Kids => [$self->madness('X q = Q m')]); + $p5re = $retval->p5text(); + } + if ($deinterpolate) { + $retval->{P5re} = P5re::qrparse($p5re); + } + return $retval; +} + +package PLXML::op_qr; + +sub ast { + my $self = shift; + my $retval; + if (exists $$self{flags}) { + $retval = $self->SUPER::ast(@_); + } + else { + $retval = $self->newtype->new(Kids => [$self->madness('X q = Q m')]); + } + if ($deinterpolate) { + my $p5re = $retval->p5text(); + $retval->{P5re} = P5re::qrparse($p5re); + } + return $retval; +} + +package PLXML::op_subst; + +sub ast { + my $self = shift; + + my $bits = $self->fetchbits($$self{flags},@_); + + my @newkids; + if ($bits->{binding}) { + push @newkids, $bits->{binding}; + push @newkids, $self->madness('~'); + } + my $X = p5::token->new($$self{mp}{X}); + my @lfirst = $self->madness('q'); + my @llast = $self->madness('Q'); + push @newkids, + @lfirst, + $self->madness('E'), # XXX s/b e probably + @llast; + my @rfirst = $self->madness('z'); + my @rlast = $self->madness('Z'); + my @mods = $self->madness('m'); + if ($rfirst[-1]->uni ne $llast[-1]->uni) { + push @newkids, @rfirst; + } + + push @newkids, $bits->{repl}, @rlast, @mods; + + my $retval = $self->newtype->new(Kids => [@newkids]); + if ($deinterpolate) { + my $p5re = $retval->p5text(); + $retval->{P5re} = P5re::qrparse($p5re); + } + return $retval; +} + +package PLXML::op_substcont; +package PLXML::op_trans; + +sub ast { + my $self = shift; + +# my $bits = $self->fetchbits($$self{flags},@_); +# + my @newkids; + my @lfirst = $self->madness('q'); + my @llast = $self->madness('Q'); + push @newkids, + @lfirst, + $self->madness('E'), + @llast; + my @rfirst = $self->madness('z'); + my @repl = $self->madness('R'); + my @rlast = $self->madness('Z'); + my @mods = $self->madness('m'); + if ($rfirst[-1]->uni ne $llast[-1]->uni) { + push @newkids, @rfirst; + } + + push @newkids, @repl, @rlast, @mods; + + my $res = $self->newtype->new(Kids => [@newkids]); + return $res; +} + +package PLXML::op_sassign; + +sub ast { + my $self = shift; + my @newkids; + + my $right = $$self{Kids}[1]; + eval { push @newkids, $right->ast($self, @_); }; + + push @newkids, $self->madness('o'); + + my $left = $$self{Kids}[0]; + push @newkids, $left->ast($self, @_); + + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_aassign; + +sub astnull { ast(@_) } + +sub ast { + my $self = shift; + my @newkids; + + my $right = $$self{Kids}[1]; + push @newkids, $right->ast($self, @_); + + push @newkids, $self->madness('o'); + + my $left = $$self{Kids}[0]; + push @newkids, $left->ast($self, @_); + + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_chop; +package PLXML::op_schop; +package PLXML::op_chomp; +package PLXML::op_schomp; +package PLXML::op_defined; +package PLXML::op_undef; +package PLXML::op_study; +package PLXML::op_pos; +package PLXML::op_preinc; + +sub ast { + my $self = shift; + if ($$self{targ}) { # stealth post inc or dec + return $self->PLXML::op_postinc::ast(@_); + } + return $self->SUPER::ast(@_); +} + +package PLXML::op_i_preinc; + +sub ast { my $self = shift; $self->PLXML::op_preinc::ast(@_); } + +package PLXML::op_predec; + +sub ast { my $self = shift; $self->PLXML::op_preinc::ast(@_); } + +package PLXML::op_i_predec; + +sub ast { my $self = shift; $self->PLXML::op_preinc::ast(@_); } + +package PLXML::op_postinc; + +sub ast { + my $self = shift; + my @newkids; + + if (exists $$self{Kids}) { + my $arg = $$self{Kids}[0]; + push @newkids, $arg->ast($self, @_) if defined $arg; + } + push @newkids, $self->madness('o'); + + my $res = $self->newtype->new(Kids => [@newkids]); + return $res; +} + +package PLXML::op_i_postinc; + +sub ast { my $self = shift; $self->PLXML::op_postinc::ast(@_); } + +package PLXML::op_postdec; + +sub ast { my $self = shift; $self->PLXML::op_postinc::ast(@_); } + +package PLXML::op_i_postdec; + +sub ast { my $self = shift; $self->PLXML::op_postinc::ast(@_); } + +package PLXML::op_pow; +package PLXML::op_multiply; +package PLXML::op_i_multiply; +package PLXML::op_divide; +package PLXML::op_i_divide; +package PLXML::op_modulo; +package PLXML::op_i_modulo; +package PLXML::op_repeat; + +sub ast { + my $self = shift; + return $self->SUPER::ast(@_) + unless exists $$self{private} and $$self{private} =~ /DOLIST/; + + my $newself = $$self{Kids}[0]->ast($self,@_); + splice @{$newself->{Kids}}, -1, 0, $self->madness('o'); + + return bless $newself, $self->newtype; # rebless the op_null +} + +package PLXML::op_add; +package PLXML::op_i_add; +package PLXML::op_subtract; +package PLXML::op_i_subtract; +package PLXML::op_concat; + +sub astnull { + my $self = shift; + my @newkids; + + my @before; + if (@before = $self->madness('M')) { + push @before, $self->madness('ox'); # o is the . + } + my @after; + my $left = $$self{Kids}[0]; + push @newkids, $left->ast($self, @_); + + push @newkids, $self->madness('o'); + + my $right = $$self{Kids}[1]; + push @newkids, $right->ast($self, @_); + return P5AST::op_concat->new(Kids => [@newkids]); +} + +sub ast { + my $self = shift; + my $parent = $_[0]; + my @newkids; + + my @before; + if (@before = $self->madness('M')) { + push @before, $self->madness('ox'); # o is the . + } + my @after; + my $left = $$self{Kids}[0]; + push @newkids, $left->ast($self, @_); + + push @newkids, $self->madness('o'); + + my $right = $$self{Kids}[1]; + push @newkids, $right->ast($self, @_); + + return $self->newtype->new(Kids => [@before, @newkids, @after]); +} + +package PLXML::op_stringify; + +sub astnull { + ast(@_); +} + +sub ast { + my $self = shift; + my @newkids; + my @front = $self->madness('q ('); + my @back = $self->madness(') Q'); + my @M = $self->madness('M'); + if (@M) { + push @newkids, $M[0], $self->madness('o'); + } + push @newkids, @front; + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + push @newkids, @back; + return P5AST::op_stringify->new(Kids => [@newkids]); +} + +package PLXML::op_left_shift; +package PLXML::op_right_shift; +package PLXML::op_lt; +package PLXML::op_i_lt; +package PLXML::op_gt; +package PLXML::op_i_gt; +package PLXML::op_le; +package PLXML::op_i_le; +package PLXML::op_ge; +package PLXML::op_i_ge; +package PLXML::op_eq; +package PLXML::op_i_eq; +package PLXML::op_ne; +package PLXML::op_i_ne; +package PLXML::op_ncmp; +package PLXML::op_i_ncmp; +package PLXML::op_slt; +package PLXML::op_sgt; +package PLXML::op_sle; +package PLXML::op_sge; +package PLXML::op_seq; +package PLXML::op_sne; +package PLXML::op_scmp; +package PLXML::op_bit_and; +package PLXML::op_bit_xor; +package PLXML::op_bit_or; +package PLXML::op_negate; +package PLXML::op_i_negate; +package PLXML::op_not; + +sub ast { + my $self = shift; + my @newkids = $self->madness('o ('); + my @swap; + if (@newkids and $newkids[-1]->uni eq '!~') { + @swap = @newkids; + @newkids = (); + } + + if (exists $$self{Kids}) { + my $arg = $$self{Kids}[0]; + push @newkids, $arg->ast($self, @_) if defined $arg; + } + if (@swap) { + splice @{$newkids[-1][0]{Kids}}, -2, 0, @swap; # XXX WAG + } + push @newkids, $self->madness(')'); + + my $res = $self->newtype->new(Kids => [@newkids]); + return $res; +} + +package PLXML::op_complement; +package PLXML::op_atan2; +package PLXML::op_sin; +package PLXML::op_cos; +package PLXML::op_rand; +package PLXML::op_srand; +package PLXML::op_exp; +package PLXML::op_log; +package PLXML::op_sqrt; +package PLXML::op_int; +package PLXML::op_hex; +package PLXML::op_oct; +package PLXML::op_abs; +package PLXML::op_length; +package PLXML::op_substr; +package PLXML::op_vec; +package PLXML::op_index; +package PLXML::op_rindex; +package PLXML::op_sprintf; +package PLXML::op_formline; +package PLXML::op_ord; +package PLXML::op_chr; +package PLXML::op_crypt; +package PLXML::op_ucfirst; + +sub ast { + my $self = shift; + return $self->PLXML::listop::ast(@_); +} + +package PLXML::op_lcfirst; + +sub ast { + my $self = shift; + return $self->PLXML::listop::ast(@_); +} + +package PLXML::op_uc; + +sub ast { + my $self = shift; + return $self->PLXML::listop::ast(@_); +} + +package PLXML::op_lc; + +sub ast { + my $self = shift; + return $self->PLXML::listop::ast(@_); +} + +package PLXML::op_quotemeta; + +sub ast { + my $self = shift; + return $self->PLXML::listop::ast(@_); +} + +package PLXML::op_rv2av; + +sub astnull { + my $self = shift; + return P5AST::op_rv2av->new(Kids => [$self->madness('$ @')]); +} + +sub ast { + my $self = shift; + + if (ref $$self{Kids}[0] eq 'PLXML::op_const' and $$self{mp}{'O'}) { + return $self->madness('O'); + } + + my @before; + push @before, $self->madness('dx d ('); + + my @newkids; + push @newkids, $self->madness('$ @ K'); + if (ref $$self{Kids}[0] ne "PLXML::op_gv") { + push @newkids, $$self{Kids}[0]->ast(); + } + my @after; + push @after, $self->madness(') a'); + return $self->newtype->new(Kids => [@before, @newkids, @after]); +} + +package PLXML::op_aelemfast; + +sub ast { + my $self = shift; + return $self->madness('$'); +} + +package PLXML::op_aelem; + +sub astnull { + my $self = shift; + my @newkids; + push @newkids, $self->madness('dx d'); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + splice @newkids, -1, 0, $self->madness('a ['); + push @newkids, $self->madness(']'); + return P5AST::op_aelem->new(Kids => [@newkids]); +} + +sub ast { + my $self = shift; + + my @before = $self->madness('dx d'); + my @newkids; + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast(@_); + } + splice @newkids, -1, 0, $self->madness('a ['); + push @newkids, $self->madness(']'); + + return $self->newtype->new(Kids => [@before, @newkids]); +} + +package PLXML::op_aslice; + +sub astnull { + my $self = shift; + my @newkids; + push @newkids, $self->madness('['); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast(@_); + } + unshift @newkids, pop @newkids; + unshift @newkids, $self->madness('dx d'); + push @newkids, $self->madness(']'); + return P5AST::op_aslice->new(Kids => [@newkids]); +} + +sub ast { + my $self = shift; + + my @newkids; + push @newkids, $self->madness('['); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast(@_); + } + unshift @newkids, pop @newkids; + unshift @newkids, $self->madness('dx d'); + push @newkids, $self->madness(']'); + + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_each; +package PLXML::op_values; +package PLXML::op_keys; +package PLXML::op_delete; +package PLXML::op_exists; +package PLXML::op_rv2hv; + +sub astnull { + my $self = shift; + return P5AST::op_rv2hv->new(Kids => [$self->madness('$')]); +} + +sub ast { + my $self = shift; + + my @before; + push @before, $self->madness('dx d ('); + + my @newkids; + push @newkids, $self->madness('$ @ % K'); + if (ref $$self{Kids}[0] ne "PLXML::op_gv") { + push @newkids, $$self{Kids}[0]->ast(); + } + my @after; + push @after, $self->madness(') a'); + return $self->newtype->new(Kids => [@before, @newkids, @after]); +} + +package PLXML::op_helem; + +sub astnull { + my $self = shift; + local $::curstate; # hash subscript potentially a lineseq + local $::curenc = $::curenc; + + my @newkids; + push @newkids, $self->madness('dx d'); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + splice @newkids, -1, 0, $self->madness('a {'); + push @newkids, $self->madness('}'); + return P5AST::op_helem->new(Kids => [@newkids]); +} + +sub ast { + my $self = shift; + local $::curstate; # hash subscript potentially a lineseq + local $::curenc = $::curenc; + + my @before = $self->madness('dx d'); + my @newkids; + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + splice @newkids, -1, 0, $self->madness('a {'); + push @newkids, $self->madness('}'); + + return $self->newtype->new(Kids => [@before, @newkids]); +} + + +package PLXML::op_hslice; + +sub astnull { + my $self = shift; + my @newkids; + push @newkids, $self->madness('{'); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast(@_); + } + unshift @newkids, pop @newkids; + unshift @newkids, $self->madness('dx d'); + push @newkids, $self->madness('}'); + return P5AST::op_hslice->new(Kids => [@newkids]); +} + +sub ast { + my $self = shift; + + my @newkids; + push @newkids, $self->madness('{'); + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast(@_); + } + unshift @newkids, pop @newkids; + unshift @newkids, $self->madness('dx d'); + push @newkids, $self->madness('}'); + + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_unpack; +package PLXML::op_pack; +package PLXML::op_split; + +sub ast { + my $self = shift; + my $results = $self->SUPER::ast(@_); + if (my @dest = $self->madness('R')) { + return PLXML::op_aassign->newtype->new(Kids => [@dest, $self->madness('ox'), $results]); + } + return $results; +} + +package PLXML::op_join; +package PLXML::op_list; + +sub astnull { + my $self = shift; + my @newkids; + my @retval; + my @before; + if (@retval = $self->madness('X')) { + push @before, $self->madness('x o'); + return @before,@retval; + } + my @kids = @{$$self{Kids}}; + for my $kid (@kids) { + next if ref $kid eq 'PLXML::op_pushmark'; + next if ref $kid eq 'PLXML::op_null' and + defined $$kid{was} and $$kid{was} eq 'pushmark'; + push @newkids, $kid->ast($self, @_); + } + + my $x = ""; + my @newnewkids = (); + push @newnewkids, $self->madness('dx d ('); + push @newnewkids, @newkids; + push @newnewkids, $self->madness(') :'); + return P5AST::op_list->new(Kids => [@newnewkids]); +} + +sub ast { + my $self = shift; + + my @retval; + my @before; + if (@retval = $self->madness('X')) { + push @before, $self->madness('o'); + return $self->newtype->new(Kids => [@before,@retval]); + } + push @retval, $self->madness('dx d ('); + + my @newkids; + for my $kid (@{$$self{Kids}}) { + push @newkids, $kid->ast($self, @_); + } + my $x = ""; + my @newnewkids = (); + push @newnewkids, @newkids; + @newkids = @newnewkids; + push @retval, @newkids; + push @retval, $self->madness(') :'); + return $self->newtype->new(Kids => [@retval]); +} + +package PLXML::op_lslice; + +sub ast { + my $self = shift; + my @newkids; + + if ($$self{mp}{q}) { + push @newkids, $self->madness('q = Q'); + } + elsif ($$self{mp}{x}) { + push @newkids, $self->madness('x'); + } + else { + push @newkids, $self->madness('('); + my $list = $$self{Kids}[1]; + push @newkids, $list->ast($self, @_); + push @newkids, $self->madness(')'); + } + + push @newkids, $self->madness('['); + + my $slice = $$self{Kids}[0]; + push @newkids, $slice->ast($self, @_); + push @newkids, $self->madness(']'); + + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_anonlist; +package PLXML::op_anonhash; +package PLXML::op_splice; +package PLXML::op_push; +package PLXML::op_pop; +package PLXML::op_shift; +package PLXML::op_unshift; +package PLXML::op_sort; +package PLXML::op_reverse; + +sub astnull { + my $self = shift; + $self->PLXML::listop::ast(@_); +} + +package PLXML::op_grepstart; +package PLXML::op_grepwhile; +package PLXML::op_mapstart; +package PLXML::op_mapwhile; +package PLXML::op_range; + +sub ast { + my $self = shift; + return $self->PLXML::binop::ast(@_); +} + +package PLXML::op_flip; +package PLXML::op_flop; +package PLXML::op_and; + +sub astnull { + my $self = shift; + my @newkids; + my @first = $self->madness('1'); + my @second = $self->madness('2'); + my @stuff = $$self{Kids}[0]->ast(); + if (my @I = $self->madness('I')) { + if (@second) { + push @newkids, @I; + push @newkids, $self->madness('('); + push @newkids, @stuff; + push @newkids, $self->madness(')'); + push @newkids, @second; + } + else { + push @newkids, @I; + push @newkids, $self->madness('('); + push @newkids, @first; + push @newkids, $self->madness(')'); + push @newkids, @stuff; + } + } + elsif (my @i = $self->madness('i')) { + if (@second) { + push @newkids, @second; + push @newkids, @i; + push @newkids, @stuff; + } + else { + push @newkids, @stuff; + push @newkids, @i; + push @newkids, @first; + } + } + elsif (my @o = $self->madness('o')) { + if (@second) { + push @newkids, @stuff; + push @newkids, @o; + push @newkids, @second; + } + else { + push @newkids, @first; + push @newkids, @o; + push @newkids, @stuff; + } + } + return P5AST::op_and->new(Kids => [@newkids]); +} + +package PLXML::op_or; + +sub astnull { + my $self = shift; + my @newkids; + my @first = $self->madness('1'); + my @second = $self->madness('2'); + my @i = $self->madness('i'); + my @stuff = $$self{Kids}[0]->ast(); + if (@second) { + if (@i) { + push @newkids, @second; + push @newkids, $self->madness('i'); + push @newkids, @stuff; + } + else { + push @newkids, @stuff; + push @newkids, $self->madness('o'); + push @newkids, @second; + } + } + else { + if (@i) { + push @newkids, @stuff; + push @newkids, $self->madness('i'); + push @newkids, @first; + } + else { + push @newkids, @first; + push @newkids, $self->madness('o'); + push @newkids, @stuff; + } + } + return "P5AST::op_$$self{was}"->new(Kids => [@newkids]); +} + + +package PLXML::op_xor; +package PLXML::op_cond_expr; +package PLXML::op_andassign; +package PLXML::op_orassign; +package PLXML::op_method; +package PLXML::op_entersub; + +sub ast { + my $self = shift; + + if ($$self{mp}{q}) { + return $self->madness('q = Q'); + } + if ($$self{mp}{X}) { # <FH> override? + return $self->madness('X'); + } + if ($$self{mp}{A}) { + return $self->astmethod(@_); + } + if ($$self{mp}{a}) { + return $self->astarrow(@_); + } + + my @retval; + + my @newkids; + my @kids = @{$$self{Kids}}; + if (@kids == 1 and ref $kids[0] eq 'PLXML::op_null' and $kids[0]{was} =~ /list/) { + @kids = @{$kids[0]{Kids}}; + } + my $dest = pop @kids; + my @dest = $dest->ast($self, @_); + + if (ref($dest) =~ /method/) { + my $invocant = shift @kids; + $invocant = shift @kids if ref($invocant) eq 'PLXML::op_pushmark'; + my @invocant = $invocant->ast($self, @_); + push @retval, @dest; + push @retval, @invocant; + } + elsif (exists $$self{mp}{o} and $$self{mp}{o} eq 'do') { + push @retval, $self->madness('o'); + push @retval, @dest; + } + else { + push @retval, $self->madness('o'); + push @retval, @dest; + } + while (@kids) { + my $kid = shift(@kids); + push @newkids, $kid->ast($self, @_); + } + + push @retval, $self->madness('('); + push @retval, @newkids; + push @retval, $self->madness(')'); + return $self->newtype->new(Kids => [@retval]); +} + +sub astmethod { + my $self = shift; + my @newkids; + my @kids; + for my $kid (@{$$self{Kids}}) { + next if ref $kid eq 'PLXML::op_pushmark'; + next if ref $kid eq 'PLXML::op_null' and + defined $$kid{was} and $$kid{was} eq 'pushmark'; + push @kids, $kid; + } + my @invocant; + if ($$self{flags} =~ /\bSTACKED\b/) { + push @invocant, shift(@kids)->ast($self, @_); + } + for my $kid (@kids) { + push @newkids, $kid->ast($self, @_); + } + my $dest = pop(@newkids); + if (ref $dest eq 'PLXML::op_rv2cv' and $$self{flags} =~ /\bMOD\b/) { + $dest = pop(@newkids); + } + my $x = ""; + my @retval; + push @retval, @invocant; + push @retval, $self->madness('A'); + push @retval, $dest; + push @retval, $self->madness('('); + push @retval, @newkids; + push @retval, $self->madness(')'); + return $self->newtype->new(Kids => [@retval]); +} + +sub astarrow { + my $self = shift; + my @newkids; + my @retval; + my @kids = @{$$self{Kids}}; + if (@kids == 1 and ref $kids[0] eq 'PLXML::op_null' and $kids[0]{was} =~ /list/) { + @kids = @{$kids[0]{Kids}}; + } + while (@kids > 1) { + my $kid = shift(@kids); + push @newkids, $kid->ast($self, @_); + } + my @dest = $kids[0]->ast($self, @_); + my $x = ""; + push @retval, @dest; + push @retval, $self->madness('a'); + push @retval, $self->madness('('); + push @retval, @newkids; + push @retval, $self->madness(')'); + return $self->newtype->new(Kids => [@retval]); +} + +package PLXML::op_leavesub; + +sub ast { + my $self = shift; + if (ref $$self{Kids}[0] eq "PLXML::op_null") { + return $$self{Kids}[0]->ast(@_); + } + return $$self{Kids}[0]->blockast($self, @_); +} + +package PLXML::op_leavesublv; + +sub ast { + my $self = shift; + + return $$self{Kids}[0]->blockast($self, @_); +} + +package PLXML::op_caller; +package PLXML::op_warn; +package PLXML::op_die; +package PLXML::op_reset; +package PLXML::op_lineseq; + +sub lineseq { + my $self = shift; + my @kids = @{$$self{Kids}}; + local $::curstate = 0; # (probably redundant, but that's okay) + local $::prevstate = 0; + local $::curenc = $::curenc; + my @retval; + my @newstuff; + my $newprev; + while (@kids) { + my $kid = shift @kids; + my $thing = $kid->ast($self, @_); + next unless defined $thing; + if ($::curstate ne $::prevstate) { + if ($::prevstate) { + push @newstuff, $::prevstate->madness(';'); + push @{$newprev->{Kids}}, @newstuff if $newprev; + @newstuff = (); + } + $::prevstate = $::curstate; + $newprev = $thing; + push @retval, $thing; + } + elsif ($::prevstate) { + push @newstuff, $thing; + } + else { + push @retval, $thing; + } + } + if ($::prevstate) { + push @newstuff, $::prevstate->madness(';'); + push @{$newprev->{Kids}}, @newstuff if $newprev; + @newstuff = (); + $::prevstate = 0; + } + return @retval; +} + +sub blockast { + my $self = shift; + local $::curstate; + + my @retval; + push @retval, $self->madness('{'); + + my @newkids = $self->PLXML::op_lineseq::lineseq(@_); + push @retval, @newkids; + + push @retval, $self->madness('; }'); + return $self->newtype->new(Kids => [@retval]); +} + +package PLXML::op_nextstate; + +sub newtype { return "P5AST::statement" } + +sub astnull { + my $self = shift; + my @newkids; + push @newkids, $self->madness('L'); + $::curstate = $self; + return P5AST::statement->new(Kids => [@newkids]); +} + +sub ast { + my $self = shift; + + my @newkids; + push @newkids, $self->madness('L'); + $::curstate = $self; + return $self->newtype->new(Kids => [@newkids]); +} + + +package PLXML::op_dbstate; +package PLXML::op_unstack; +package PLXML::op_enter; + +sub ast { () } + +package PLXML::op_leave; + +sub astnull { + ast(@_); +} + +sub ast { + my $self = shift; + + my $mad = $$self{mp}{FIRST} || "unknown"; + + my @retval; + if ($mad eq 'w') { + my @newkids; + my @tmpkids; + push @tmpkids, $self->{Kids}; + my $anddo = $$self{Kids}[-1]{Kids}[0]{Kids}; + eval { push @newkids, $anddo->[1]->ast($self,@_); }; + push @newkids, "[[[NOANDDO]]]" if $@; + push @newkids, $self->madness('w'); + push @newkids, $anddo->[0]->ast($self,@_); + + return $self->newtype->new(Kids => [@newkids]); + } + + local $::curstate; + push @retval, $self->madness('o {'); + + my @newkids = $self->PLXML::op_lineseq::lineseq(@_); + push @retval, @newkids; + push @retval, $self->madness(q/; }/); + my $retval = $self->newtype->new(Kids => [@retval]); + + if ($$self{mp}{C}) { + my @before; + my @after; + push @before, $self->madness('I ( C )'); + if ($$self{mp}{t}) { + push @before, $self->madness('t'); + } + elsif ($$self{mp}{e}) { + push @after, $self->madness('e'); + } + return P5AST::op_cond->new(Kids => [@before, $retval, @after]); + } + else { + return $retval; + } +} + +package PLXML::op_scope; + +sub ast { + my $self = shift; + local $::curstate; + + my @newkids; + push @newkids, $self->madness('o'); + + push @newkids, $self->madness('{'); + push @newkids, $self->PLXML::op_lineseq::lineseq(@_); + push @newkids, $self->madness('; }'); + + my @folded = $self->madness('C'); + if (@folded) { + my @t = $self->madness('t'); + my @e = $self->madness('e'); + if (@e) { + return $self->newtype->new( + Kids => [ + $self->madness('I ('), + @folded, + $self->madness(')'), + $self->newtype->new(Kids => [@newkids]), + @e + ] ); + } + else { + return $self->newtype->new( + Kids => [ + $self->madness('I ('), + @folded, + $self->madness(')'), + @t, + $self->newtype->new(Kids => [@newkids]) + ] ); + } + } + return $self->newtype->new(Kids => [@newkids]); +} + +package PLXML::op_enteriter; + +sub ast { + my $self = shift; + my (undef,$range,$var) = @{$self->{Kids}}; + my @retval; + push @retval, $self->madness('v'); + if (!@retval and defined $var) { + push @retval, $var->ast($self,@_); + } + else { + push @retval, ''; + } + if (ref $range eq 'PLXML::op_null' and $$self{flags} =~ /STACKED/) { + my (undef,$min,$max) = @{$range->{Kids}}; + push @retval, $min->ast($self,@_); + if (defined $max) { + if (exists $$range{mp}{O}) { # deeply buried .. operator + PLXML::prepreproc($$range{mp}{O}); + push @retval, + $$range{mp}{'O'}{Kids}[0]{Kids}[0]{Kids}[0]{Kids}[0]->madness('o') + } + else { + push @retval, '..'; # XXX missing whitespace + } + push @retval, $max->ast($self,@_); + } + } + else { + push @retval, $range->ast($self,@_); + } + return $self->newtype->new(Kids => [@retval]); +} + +package PLXML::op_iter; +package PLXML::op_enterloop; + +sub ast { +} + +package PLXML::op_leaveloop; + +sub ast { + my $self = shift; + + my @retval; + my @newkids; + my $enterloop = $$self{Kids}[0]; + my $nextthing = $$self{Kids}[1]; + + if ($$self{mp}{W}) { + push @retval, $self->madness('L'); + push @newkids, $self->madness('W d'); + + if (ref $enterloop eq 'PLXML::op_enteriter') { + my ($var,@rest) = @{$enterloop->ast($self,@_)->{Kids}}; + push @newkids, $var if $var; + push @newkids, $self->madness('q ( x = Q'); + push @newkids, @rest; + } + else { + push @newkids, $self->madness('('); + push @newkids, $enterloop->ast($self,@_); + } + } + my $andor; + + if (ref $nextthing eq 'PLXML::op_null') { + if ($$nextthing{mp}{'1'}) { + push @newkids, $nextthing->madness('1'); + push @newkids, $self->madness(')'); + push @newkids, $$nextthing{Kids}[0]->blockast($self,@_); + } + elsif ($$nextthing{mp}{'2'}) { + push @newkids, $$nextthing{Kids}[0]->ast($self,@_); + push @newkids, $self->madness(')'); + push @newkids, $$nextthing{mp}{'2'}->blockast($self,@_); + } + elsif ($$nextthing{mp}{'U'}) { + push @newkids, $nextthing->ast($self,@_); + } + else { + # bypass the op_null + $andor = $nextthing->{Kids}[0]; + eval { + push @newkids, $$andor{Kids}[0]->ast($self, @_); + }; + push @newkids, $self->madness(')'); + eval { + push @newkids, $$andor{Kids}[1]->blockast($self, @_); + }; + } + } + else { + $andor = $nextthing; + push @newkids, $nextthing->madness('O'); + push @newkids, $self->madness(')'); + push @newkids, $nextthing->blockast($self, @_); + } + if ($$self{mp}{w}) { + push @newkids, $self->madness('w'); + push @newkids, $enterloop->ast($self,@_); + } + + push @retval, @newkids; + + return $self->newtype->new(Kids => [@retval]); +} + +package PLXML::op_return; +package PLXML::op_last; +package PLXML::op_next; +package PLXML::op_redo; +package PLXML::op_dump; +package PLXML::op_goto; +package PLXML::op_exit; +package PLXML::op_open; +package PLXML::op_close; +package PLXML::op_pipe_op; +package PLXML::op_fileno; +package PLXML::op_umask; +package PLXML::op_binmode; +package PLXML::op_tie; +package PLXML::op_untie; +package PLXML::op_tied; +package PLXML::op_dbmopen; +package PLXML::op_dbmclose; +package PLXML::op_sselect; +package PLXML::op_select; +package PLXML::op_getc; +package PLXML::op_read; +package PLXML::op_enterwrite; +package PLXML::op_leavewrite; +package PLXML::op_prtf; +package PLXML::op_print; +package PLXML::op_sysopen; +package PLXML::op_sysseek; +package PLXML::op_sysread; +package PLXML::op_syswrite; +package PLXML::op_send; +package PLXML::op_recv; +package PLXML::op_eof; +package PLXML::op_tell; +package PLXML::op_seek; +package PLXML::op_truncate; +package PLXML::op_fcntl; +package PLXML::op_ioctl; +package PLXML::op_flock; +package PLXML::op_socket; +package PLXML::op_sockpair; +package PLXML::op_bind; +package PLXML::op_connect; +package PLXML::op_listen; +package PLXML::op_accept; +package PLXML::op_shutdown; +package PLXML::op_gsockopt; +package PLXML::op_ssockopt; +package PLXML::op_getsockname; +package PLXML::op_getpeername; +package PLXML::op_lstat; +package PLXML::op_stat; +package PLXML::op_ftrread; +package PLXML::op_ftrwrite; +package PLXML::op_ftrexec; +package PLXML::op_fteread; +package PLXML::op_ftewrite; +package PLXML::op_fteexec; +package PLXML::op_ftis; +package PLXML::op_fteowned; +package PLXML::op_ftrowned; +package PLXML::op_ftzero; +package PLXML::op_ftsize; +package PLXML::op_ftmtime; +package PLXML::op_ftatime; +package PLXML::op_ftctime; +package PLXML::op_ftsock; +package PLXML::op_ftchr; +package PLXML::op_ftblk; +package PLXML::op_ftfile; +package PLXML::op_ftdir; +package PLXML::op_ftpipe; +package PLXML::op_ftlink; +package PLXML::op_ftsuid; +package PLXML::op_ftsgid; +package PLXML::op_ftsvtx; +package PLXML::op_fttty; +package PLXML::op_fttext; +package PLXML::op_ftbinary; +package PLXML::op_chdir; +package PLXML::op_chown; +package PLXML::op_chroot; +package PLXML::op_unlink; +package PLXML::op_chmod; +package PLXML::op_utime; +package PLXML::op_rename; +package PLXML::op_link; +package PLXML::op_symlink; +package PLXML::op_readlink; +package PLXML::op_mkdir; +package PLXML::op_rmdir; +package PLXML::op_open_dir; +package PLXML::op_readdir; +package PLXML::op_telldir; +package PLXML::op_seekdir; +package PLXML::op_rewinddir; +package PLXML::op_closedir; +package PLXML::op_fork; +package PLXML::op_wait; +package PLXML::op_waitpid; +package PLXML::op_system; +package PLXML::op_exec; +package PLXML::op_kill; +package PLXML::op_getppid; +package PLXML::op_getpgrp; +package PLXML::op_setpgrp; +package PLXML::op_getpriority; +package PLXML::op_setpriority; +package PLXML::op_time; +package PLXML::op_tms; +package PLXML::op_localtime; +package PLXML::op_gmtime; +package PLXML::op_alarm; +package PLXML::op_sleep; +package PLXML::op_shmget; +package PLXML::op_shmctl; +package PLXML::op_shmread; +package PLXML::op_shmwrite; +package PLXML::op_msgget; +package PLXML::op_msgctl; +package PLXML::op_msgsnd; +package PLXML::op_msgrcv; +package PLXML::op_semget; +package PLXML::op_semctl; +package PLXML::op_semop; +package PLXML::op_require; +package PLXML::op_dofile; +package PLXML::op_entereval; + +sub ast { + my $self = shift; + local $::curstate; # eval {} has own statement sequence + return $self->SUPER::ast(@_); +} + +package PLXML::op_leaveeval; +package PLXML::op_entertry; +package PLXML::op_leavetry; + +sub ast { + my $self = shift; + + return $self->PLXML::op_leave::ast(@_); +} + +package PLXML::op_ghbyname; +package PLXML::op_ghbyaddr; +package PLXML::op_ghostent; +package PLXML::op_gnbyname; +package PLXML::op_gnbyaddr; +package PLXML::op_gnetent; +package PLXML::op_gpbyname; +package PLXML::op_gpbynumber; +package PLXML::op_gprotoent; +package PLXML::op_gsbyname; +package PLXML::op_gsbyport; +package PLXML::op_gservent; +package PLXML::op_shostent; +package PLXML::op_snetent; +package PLXML::op_sprotoent; +package PLXML::op_sservent; +package PLXML::op_ehostent; +package PLXML::op_enetent; +package PLXML::op_eprotoent; +package PLXML::op_eservent; +package PLXML::op_gpwnam; +package PLXML::op_gpwuid; +package PLXML::op_gpwent; +package PLXML::op_spwent; +package PLXML::op_epwent; +package PLXML::op_ggrnam; +package PLXML::op_ggrgid; +package PLXML::op_ggrent; +package PLXML::op_sgrent; +package PLXML::op_egrent; +package PLXML::op_getlogin; +package PLXML::op_syscall; +package PLXML::op_lock; +package PLXML::op_threadsv; +package PLXML::op_setstate; +package PLXML::op_method_named; + +sub ast { + my $self = shift; + return $self->madness('O'); +} + +package PLXML::op_dor; + +sub astnull { + my $self = shift; + $self->PLXML::op_or::astnull(@_); +} + +package PLXML::op_dorassign; +package PLXML::op_custom; + |