Re: [perl #32687] Encode::is_utf8 on tainted UTF8 string
[p5sagit/p5-mst-13.2.git] / mad / nomad
1 #!/usr/bin/perl
2
3 # Suboptimal things:
4 #       ast type info is generally still implicit
5 #       the combined madness calls are actually losing type information
6 #       brace madprops tend to be too low in the tree
7 #       could use about 18 more refactorings...
8 #       lots of unused cruft left around from previous refactorings
9
10 use strict;
11 use warnings;
12 use Carp;
13
14 use P5AST;
15 use P5re;
16
17 my $dowarn = 0;
18 my $YAML = 0;
19 my $deinterpolate;
20
21 while (@ARGV and $ARGV[0] =~ /^-./) {
22     my $switch = shift;
23     if ($switch eq '-w') {
24         $dowarn = 1;
25     }
26     elsif ($switch eq '-Y') {
27         $YAML = 1;
28     }
29     elsif ($switch eq '-d') {
30         $deinterpolate = 1;
31     }
32     else {
33         die "Unrecognized switch: -$switch";
34     }
35 }
36
37 @ARGV = ('foo.xml') unless @ARGV;
38 my $filename = shift;
39
40 $::curstate = 0;
41 $::prevstate = 0;
42 $::curenc = 1;          # start in iso-8859-1, sigh...
43
44 $::H = "HeredocHere000";
45 %::H = ();
46
47 my @enc = (
48     'utf-8',
49     'iso-8859-1',
50 );
51
52 my %enc = (
53     'utf-8' => 0,
54     'iso-8859-1' => 1,
55 );
56
57 my %madtype = (
58     '$' => 'p5::sigil',
59     '@' => 'p5::sigil',
60     '%' => 'p5::sigil',
61     '&' => 'p5::sigil',
62     '*' => 'p5::sigil',
63     'o' => 'p5::operator',
64     '~' => 'p5::operator',
65     '+' => 'p5::punct',
66     '?' => 'p5::punct',
67     ':' => 'p5::punct',
68     ',' => 'p5::punct',
69     ';' => 'p5::punct',
70     '#' => 'p5::punct',
71     '(' => 'p5::opener',
72     ')' => 'p5::closer',
73     '[' => 'p5::opener',
74     ']' => 'p5::closer',
75     '{' => 'p5::opener',
76     '}' => 'p5::closer',
77     '1' => 'p5::punct',
78     '2' => 'p5::punct',
79     'a' => 'p5::operator',
80     'A' => 'p5::operator',
81     'd' => 'p5::declarator',
82     'E' => 'p5::text',
83     'L' => 'p5::label',
84     'm' => 'p5::remod',
85 #    'n' => 'p5::name',
86     'q' => 'p5::openquote',
87     'Q' => 'p5::closequote',
88     '=' => 'p5::text',
89     'R' => 'p5::text',
90     's' => 'p5::text',
91     's' => 'p5::declarator',
92 #    'V' => 'p5::version',
93     'X' => 'p5::token',
94 );
95
96 $SIG{__DIE__} = sub {
97     my $e = shift;
98     $e =~ s/\n$/\n    [NODE $filename line $::prevstate->{line}]/ if $::prevstate;
99     confess $e;
100 };
101
102 use Data::Dumper;
103 $Data::Dumper::Indent = 1;
104 $Data::Dumper::Quotekeys = 0;
105
106 sub d {
107     my $text = Dumper(@_);
108     # doesn't scale well, alas
109     1 while $text =~ s/(.*)^([^\n]*)bless\( \{\n(.*?)^(\s*\}), '([^']*)' \)([^\n]*)/$1$2$5 {\n$3$4$6 # $5/ms;
110     $text =~ s/PLXML:://g;
111     if ($text) {
112         my ($package, $filename, $line) = caller;
113         my $subroutine = (caller(1))[3];
114         $text =~ s/\n?\z/, called from $subroutine, line $line\n/;
115         warn $text;
116     }
117 };
118
119 {
120
121     my %xmlrepl = (
122         '&' => '&',
123         "'" => ''',
124         '"' => '&dquo;',
125         '<' => '&lt;',
126         '>' => '&gt;',
127         "\n" => '&#10;',
128         "\t" => '&#9;',
129     );
130
131     sub x {
132         my $indent = 0;
133         if (@_ > 1) {
134             warn xdolist($indent,"LIST",@_);
135         }
136         else {
137             my $type = ref $_[0];
138             if ($type) {
139                 warn xdoitem($indent,$type,@_);
140             }
141             else {
142                 warn xdoitem($indent,"ITEM",@_);
143             }
144         }
145     }
146
147     sub xdolist {
148         my $indent = shift;
149         my $tag = shift;
150         my $in = ' ' x ($indent * 2);
151         my $result;
152         $result .= "$in<$tag>\n" if defined $tag;
153         for my $it (@_) {
154             my $itt = ref $it || "ITEM";
155             $itt =~ s/::/:/g;
156             $result .= xdoitem($indent+1,$itt,$it);
157         }
158         $result .= "$in</$tag>\n" if defined $tag;
159         return $result;
160     }
161
162     sub xdohash {
163         my $indent = shift;
164         my $tag = shift;
165         my $hash = shift;
166         my $in = ' ' x ($indent * 2);
167         my $result = "$in<$tag>\n";
168         my @keys = sort keys %$hash;
169         my $longest = 0;
170         for my $k (@keys) {
171             $longest = length($k) if length($k) > $longest;
172         }
173         my $K;
174         for my $k (@keys) {
175             my $tmp;
176             $K = $$hash{$k}, next if $k eq 'Kids';
177             my $sp = ' ' x ($longest - length($k));
178             if (ref $$hash{$k}) {
179                 $tmp = xdoitem($indent+1,"kv",$$hash{$k});
180                 $tmp =~ s!^ *<kv>\n *</kv>!$in  <kv/>!;
181             }
182             else {
183                 $tmp = xdoitem($indent+1,"kv",$$hash{$k});
184             }
185             $k =~ s/([\t\n'"<>&])/$xmlrepl{$1}/g;
186             $tmp =~ s/<kv/<kv k='$k'$sp/ or
187                 $tmp =~ s/^(.*)$/$in  <kv k='$k'>\n$in  $1$in  <\/kv>\n/s;
188             $result .= $tmp;
189         }
190         if ($K and @$K) {
191             $result .= xdolist($indent, undef, @$K);
192         }
193         $result .= "$in</$tag>\n";
194     }
195
196     sub xdoitem {
197         my $indent = shift;
198         my $tag = shift;
199         my $item = shift;
200         my $in = ' ' x ($indent * 2);
201         my $r = ref $item;
202         if (not $r) {
203             $item =~ s/([\t\n'"<>&])/$xmlrepl{$1}/g;
204             return "$in<$tag>$item</$tag>\n";
205         }
206         (my $newtag = $r) =~ s/::/:/g;
207         my $t = "$item";
208         if ($t =~ /\bARRAY\b/) {
209             if (@{$item}) {
210                 return xdolist($indent,$tag,@{$item});
211             }
212             else {
213                 return "$in<$tag />\n";
214             }
215         }
216         if ($t =~ /\bHASH\b/) {
217             return xdohash($indent,$tag,$item);
218         }
219         if ($r =~ /^p5::/) {
220             return "$in<$newtag>$$item</$newtag>\n";
221         }
222         else {
223             return "$in<$newtag type='$r'/>\n";
224         }
225     }
226
227     my %trepl = (
228         "'" => '\\\'',
229         '"' => '\\"',
230         "\n" => '\\n',
231         "\t" => '\\t',
232     );
233
234     sub t {
235         my $indent = 0;
236         if (@_ > 1) {
237             tdolist($indent,"LIST",@_);
238         }
239         else {
240             my $type = ref $_[0];
241             if ($type) {
242                 tdoitem($indent,$type,@_);
243             }
244             else {
245                 tdoitem($indent,"ITEM",@_);
246             }
247         }
248         print STDERR "\n";
249     }
250
251     sub tdolist {
252         my $indent = shift;
253         my $tag = shift || "ARRAY";
254         my $in = ' ' x ($indent * 2);
255         if (@_) {
256             print STDERR "[\n";
257             for my $it (@_) {
258                 my $itt = ref $it || "ITEM";
259                 print STDERR $in,"  ";
260                 tdoitem($indent+1,$itt,$it);
261                 print STDERR "\n";
262             }
263             print STDERR "$in]";
264         }
265         else {
266             print STDERR "[]";
267         }
268     }
269
270     sub tdohash {
271         my $indent = shift;
272         my $tag = shift;
273         my $hash = shift;
274         my $in = ' ' x ($indent * 2);
275
276         print STDERR "$tag => {\n";
277
278         my @keys = sort keys %$hash;
279         my $longest = 0;
280         for my $k (@keys) {
281             $longest = length($k) if length($k) > $longest;
282         }
283         my $K;
284         for my $k (@keys) {
285             my $sp = ' ' x ($longest - length($k));
286             print STDERR "$in  $k$sp => ";
287             tdoitem($indent+1,"",$$hash{$k});
288             if ($k eq 'Kids') {
289                 print STDERR " # Kids";
290             }
291             print STDERR "\n";
292         }
293         print STDERR "$in} # $tag";
294     }
295
296     sub tdoitem {
297         my $indent = shift;
298         my $tag = shift;
299         my $item = shift;
300         if (not defined $item) {
301             print STDERR "UNDEF";
302             return;
303         }
304 #       my $in = ' ' x ($indent * 2);
305         my $r = ref $item;
306         if (not $r) {
307             $item =~ s/([\t\n"])/$trepl{$1}/g;
308             print STDERR "\"$item\"";
309             return;
310         }
311         my $t = "$item";
312         if ($r =~ /^p5::/) {
313             my $str = $$item{uni};
314             my $enc = $enc[$$item{enc}] . ' ';
315             $enc =~ s/iso-8859-1 //;
316             $str =~ s/([\t\n"])/$trepl{$1}/g;
317             print STDERR "$r $enc\"$str\"";
318         }
319         elsif ($t =~ /\bARRAY\b/) {
320             tdolist($indent,$tag,@{$item});
321         }
322         elsif ($t =~ /\bHASH\b/) {
323             tdohash($indent,$tag,$item);
324         }
325         else {
326             print STDERR "$r type='$r'";
327         }
328     }
329 }
330
331 sub encnum {
332     my $encname = shift;
333     if (not exists $enc{$encname}) {
334         push @enc, $encname;
335         return $enc{$encname} = $#enc;
336     }
337     return $enc{$encname};
338 }
339
340 use PLXML;
341
342 use XML::Parser;
343 my $p1 = new XML::Parser(Style => 'Objects', Pkg => 'PLXML');
344 $p1->setHandlers('Char' => sub { warn "Chars $_[1]" if $_[1] =~ /\S/; });
345
346 # First slurp XML into tree of objects.
347
348 my $root = $p1->parsefile($filename);
349
350 # Now turn XML tree into something more like an AST.
351
352 PLXML::prepreproc($root->[0]);
353 my $ast = P5AST->new('Kids' => [$root->[0]->ast()]);
354 #::t($ast);
355
356 if ($YAML) {
357     require YAML::Syck;
358     print YAML::Syck::Dump($ast);
359     exit;
360 }
361
362 # Finally, walk AST to produce new program.
363
364 my $text = $ast->p5text();      # returns encoded, must output raw
365 print $text;
366
367 package p5::text;
368
369 use Encode;
370
371 sub new {
372     my $class = shift;
373     my $text = shift;
374     die "Too many args to new" if @_;
375     die "Attempt to bless non-text $text" if ref $text;
376     return bless( { uni => $text,
377                     enc => $::curenc,
378                   }, $class);
379 }
380
381 sub uni { my $self = shift; $$self{uni}; }      # internal stuff all in utf8
382
383 sub enc {
384     my $self = shift;
385     my $enc = $enc[$$self{enc} || 0];
386     return encode($enc, $$self{uni});
387 }
388
389 package p5::closequote; BEGIN { @p5::closequote::ISA = 'p5::punct'; }
390 package p5::closer;     BEGIN { @p5::closer::ISA = 'p5::punct'; }
391 package p5::declarator; BEGIN { @p5::declarator::ISA = 'p5::token'; }
392 package p5::junk;       BEGIN { @p5::junk::ISA = 'p5::text'; }
393 package p5::label;      BEGIN { @p5::label::ISA = 'p5::token'; }
394 #package p5::name;      BEGIN { @p5::name::ISA = 'p5::token'; }
395 package p5::opener;     BEGIN { @p5::opener::ISA = 'p5::punct'; }
396 package p5::openquote;  BEGIN { @p5::openquote::ISA = 'p5::punct'; }
397 package p5::operator;   BEGIN { @p5::operator::ISA = 'p5::token'; }
398 package p5::punct;      BEGIN { @p5::punct::ISA = 'p5::token'; }
399 package p5::remod;      BEGIN { @p5::remod::ISA = 'p5::token'; }
400 package p5::sigil;      BEGIN { @p5::sigil::ISA = 'p5::punct'; }
401 package p5::token;      BEGIN { @p5::token::ISA = 'p5::text'; }
402 #package p5::version;   BEGIN { @p5::version::ISA = 'p5::token'; }
403
404 ################################################################
405 # Routines to turn XML tree into an AST.  Mostly this amounts to hoisting
406 # misplaced nodes and flattening various things into lists.
407
408 package PLXML;
409
410 sub AUTOLOAD {
411     ::x("AUTOLOAD $PLXML::AUTOLOAD", @_);
412     return "[[[ $PLXML::AUTOLOAD ]]]";
413 }
414
415 sub prepreproc {
416     my $self = shift;
417     my $kids = $$self{Kids};
418     $self->{mp} = {};
419     if (defined $kids) {
420         my $i;
421         for ($i = 0; $i < @$kids; $i++) {
422             if (ref $kids->[$i] eq "PLXML::madprops") {
423                 $self->{mp} = splice(@$kids, $i, 1)->hash($self,@_);
424                 $i--;
425                 next;
426             }
427             else {
428                 prepreproc($kids->[$i], $self, @_);
429             }
430         }
431     }
432 }
433
434 sub preproc {
435     my $self = shift;
436     if (ref $self eq 'PLXML::op_null' and $$self{was}) {
437         return "PLXML::op_$$self{was}"->key();
438     }
439     else {
440         return $self->key();
441     }
442 }
443
444 sub newtype {
445     my $self = shift;
446     my $t = ref $self || $self;
447     $t = "PLXML::op_$$self{was}" if $t eq 'PLXML::op_null' and $$self{was};
448     $t =~ s/PLXML/P5AST/ or die "Bad type: $t";
449     return $t;
450 }
451
452 sub madness {
453     my $self = shift;
454     my @keys = split(' ', shift);
455     my @vals = ();
456     for my $key (@keys) {
457         my $madprop = $self->{mp}{$key};
458         next unless defined $madprop;
459         if (ref $madprop eq 'PLXML::mad_op') {
460             if ($key eq 'b') {
461                 push @vals, $madprop->blockast($self, @_);
462             }
463             else {
464                 push @vals, $madprop->ast($self, @_);
465             }
466             next;
467         }
468         my $white;
469         if ($white = $self->{mp}{"_$key"}) {
470             push @vals, p5::junk->new($white);
471         }
472         my $type = $madtype{$key} || "p5::token";
473         push @vals, $type->new($madprop);
474         if ($white = $self->{mp}{"#$key"}) {
475             push @vals, p5::junk->new($white);
476         }
477     }
478     @vals;
479 }
480
481 sub blockast {
482     my $self = shift;
483     $self->ast(@_);
484 }
485
486 sub ast {
487     my $self = shift;
488
489     my @newkids;
490     for my $kid (@{$$self{Kids}}) {
491         push @newkids, $kid->ast($self, @_);
492     }
493     return $self->newtype->new(Kids => [uc $self->key(), "(", @newkids, ")"]);
494 }
495
496 sub op {
497     my $self = shift;
498     my $desc = $self->desc();
499     if ($desc =~ /\((.*?)\)/) {
500         return $1;
501     }
502     else {
503         return " <<" . $self->key() . ">> ";
504     }
505 }
506
507 sub mp {
508     my $self = shift;
509     return $self->{mp};
510 }
511
512 package PLXML::Characters;
513
514 sub ast { die "oops" }
515 sub pair { die "oops" }
516
517 package PLXML::madprops;
518
519 sub ast {
520     die "oops madprops";
521 }
522
523 sub hash {
524     my $self = shift;
525     my @pairs;
526     my %hash = ();
527     my $firstthing = '';
528     my $lastthing = '';
529     
530     # We need to guarantee key uniqueness at this point.
531     for my $kid (@{$$self{Kids}}) {
532         my ($k,$v) = $kid->pair($self, @_);
533         $firstthing ||= $k;
534         if ($k =~ /^[_#]$/) {   # rekey whitespace according to preceding entry
535             $k .= $lastthing;   # (which is actually the token the whitespace is before)
536         }
537         else {
538             $k .= 'x' while exists $hash{$k};
539             $lastthing = $k;
540         }
541         $hash{$k} = $v;
542     }
543     $hash{FIRST} = $firstthing;
544     $hash{LAST} = $lastthing;
545     return \%hash;
546 }
547
548 package PLXML::mad_op;
549
550 sub pair {
551     my $self = shift;
552     my $key = $$self{key};
553     return $key,$self;
554 }
555
556 sub ast {
557     my $self = shift;
558     $self->prepreproc(@_);
559     my @vals;
560     for my $kid (@{$$self{Kids}}) {
561         push @vals, $kid->ast($self, @_);
562     }
563     if (@vals == 1) {
564         return @vals;
565     }
566     else {
567         return P5AST::op_list->new(Kids => [@vals]);
568     }
569 }
570
571 sub blockast {
572     my $self = shift;
573     $self->prepreproc(@_);
574     my @vals;
575     for my $kid (@{$$self{Kids}}) {
576         push @vals, $kid->blockast($self, @_);
577     }
578     if (@vals == 1) {
579         return @vals;
580     }
581     else {
582         return P5AST::op_lineseq->new(Kids => [@vals]);
583     }
584 }
585
586 package PLXML::mad_pv;
587
588 sub pair {
589     my $self = shift;
590     my $key = $$self{key};
591     my $val = $$self{val};
592     $val =~ s/STUPIDXML\(#x(\w+)\)/chr(hex $1)/eg;
593     return $key,$val;
594 }
595
596 package PLXML::mad_sv;
597
598 sub pair {
599     my $self = shift;
600     my $key = $$self{key};
601     my $val = $$self{val};
602     $val =~ s/STUPIDXML\(#x(\w+)\)/chr(hex $1)/eg;
603     return $key,$val;
604 }
605
606 package PLXML::baseop;
607
608 sub ast {
609     my $self = shift;
610
611     my @retval;
612     my @newkids;
613     push @retval, $self->madness('M ox');
614     for my $kid (@{$$self{Kids}}) {
615         push @newkids, $kid->ast($self, @_);
616     }
617     if (@newkids) {
618         push @retval, uc $self->key(), "(", @newkids , ")";
619     }
620     else {
621         push @retval, $self->madness('o ( )');
622     }
623     return $self->newtype->new(Kids => [@retval]);
624 }
625
626 package PLXML::baseop_unop;
627
628 sub ast {
629     my $self = shift;
630     my @newkids = $self->madness('d M ox o (');
631
632     if (exists $$self{Kids}) {
633         my $arg = $$self{Kids}[0];
634         push @newkids, $arg->ast($self, @_) if defined $arg;
635     }
636     push @newkids, $self->madness(')');
637
638     return $self->newtype()->new(Kids => [@newkids]);
639 }
640
641 package PLXML::binop;
642
643 sub ast {
644     my $self = shift;
645     my @newkids;
646
647     push @newkids, $self->madness('M ox');
648
649     my $left = $$self{Kids}[0];
650     push @newkids, $left->ast($self, @_);
651
652     push @newkids, $self->madness('o');
653
654     my $right = $$self{Kids}[1];
655     if (defined $right) {
656         push @newkids, $right->ast($self, @_);
657     }
658
659     return $self->newtype->new(Kids => [@newkids]);
660 }
661
662 package PLXML::cop;
663
664 package PLXML::filestatop;
665
666 sub ast {
667     my $self = shift;
668
669     my @newkids = $self->madness('o (');
670
671     if (@{$$self{Kids}}) {
672         for my $kid (@{$$self{Kids}}) {
673             push @newkids, $kid->ast($self, @_);
674         }
675     }
676     if ($$self{mp}{O}) {
677         push @newkids, $self->madness('O');
678     }
679     push @newkids, $self->madness(')');
680
681     return $self->newtype->new(Kids => [@newkids]);
682 }
683
684 package PLXML::listop;
685
686 sub ast {
687     my $self = shift;
688
689     my @retval;
690     my @before;
691     my @after;
692     if (@before = $self->madness('M')) {
693         push @before, $self->madness('ox');     # o is the function name
694     }
695     if (@retval = $self->madness('X')) {
696         push @before, $self->madness('o x');
697         return P5AST::listop->new(Kids => [@before,@retval]);
698     }
699
700     push @retval, $self->madness('o ( [ {');
701
702     my @newkids;
703     for my $kid (@{$$self{Kids}}) {
704         next if ref $kid eq 'PLXML::op_pushmark';
705         next if ref $kid eq 'PLXML::op_null' and
706                 defined $$kid{was} and $$kid{was} eq 'pushmark';
707         push @newkids, $kid->ast($self, @_);
708     }
709
710     my $x = "";
711
712     if ($$self{mp}{S}) {
713         push @retval, $self->madness('S');
714     }
715     push @retval, @newkids;
716
717     push @retval, $self->madness('} ] )');
718     return $self->newtype->new(Kids => [@before,@retval,@after]);
719 }
720
721 package PLXML::logop;
722
723 sub ast {
724     my $self = shift;
725
726     my @newkids;
727     push @newkids, $self->madness('o (');
728     for my $kid (@{$$self{Kids}}) {
729         push @newkids, $kid->ast($self, @_);
730     }
731     push @newkids, $self->madness(')');
732     return $self->newtype->new(Kids => [@newkids]);
733 }
734
735 package PLXML::loop;
736
737 package PLXML::loopexop;
738
739 sub ast {
740     my $self = shift;
741     my @newkids = $self->madness('o (');
742
743     if ($$self{mp}{L} or not $$self{flags} =~ /\bSPECIAL\b/) {
744         my @label = $self->madness('L');
745         if (@label) {
746             push @newkids, @label;
747         }
748         else {
749             my $arg = $$self{Kids}[0];
750             push @newkids, $arg->ast($self, @_) if defined $arg;
751         }
752     }
753     push @newkids, $self->madness(')');
754
755     return $self->newtype->new(Kids => [@newkids]);
756 }
757
758
759 package PLXML::padop;
760
761 package PLXML::padop_svop;
762
763 package PLXML::pmop;
764
765 sub ast {
766     my $self = shift;
767
768     return P5AST::pmop->new(Kids => []) unless exists $$self{flags};
769
770     my $bits = $self->fetchbits($$self{flags},@_);
771
772     my @newkids;
773     if ($bits->{binding}) {
774         push @newkids, $bits->{binding};
775         push @newkids, $self->madness('~');
776     }
777     if (exists $bits->{regcomp} and $bits->{regcomp}) {
778         my @front = $self->madness('q');
779         my @back = $self->madness('Q');
780         push @newkids, @front, $bits->{regcomp}, @back,
781                 $self->madness('m');
782     }
783     elsif ($$self{mp}{q}) {
784         push @newkids, $self->madness('q = Q m');
785     }
786     elsif ($$self{mp}{X}) {
787         push @newkids, $self->madness('X m');
788     }
789     else {
790         push @newkids, $self->madness('e m');
791     }
792
793     return $self->newtype->new(Kids => [@newkids]);
794 }
795
796 sub innerpmop {
797     my $pmop = shift;
798     my $bits = shift;
799     for my $key (grep {!/^Kids/} keys %$pmop) {
800         $bits->{$key} = $pmop->{$key};
801     }
802
803     # Have to delete all the fake evals of the repl.  This is a pain...
804     if (@{$$pmop{Kids}}) {
805         my $really = $$pmop{Kids}[0]{Kids}[0];
806         if (ref $really eq 'PLXML::op_substcont') {
807             $really = $$really{Kids}[0];
808         }
809         while ((ref $really) =~ /^PLXML::op_.*(null|entereval)/) {
810             if (exists $$really{was}) {
811                 $bits->{repl} = $really->ast(@_);
812                 return;
813             }
814             $really = $$really{Kids}[0];
815         }
816         if (ref $really eq 'PLXML::op_scope' and
817             @{$$really{Kids}} == 1 and
818             ref $$really{Kids}[0] eq 'PLXML::op_null' and
819             not @{$$really{Kids}[0]{Kids}})
820         {
821             $bits->{repl} = '';
822             return;
823         }
824         if (ref $really eq 'PLXML::op_leave' and
825             @{$$really{Kids}} == 2 and
826             ref $$really{Kids}[1] eq 'PLXML::op_null' and
827             not @{$$really{Kids}[1]{Kids}})
828         {
829             $bits->{repl} = '';
830             return;
831         }
832         if ((ref $really) =~ /^PLXML::op_(scope|leave)/) {
833             # should be at inner do {...} here, so skip that fakery too
834             $bits->{repl} = $really->newtype->new(Kids => [$really->PLXML::op_lineseq::lineseq(@_)]);
835             # but retrieve the whitespace before fake '}'
836             if ($$really{mp}{'_}'}) {
837                 push(@{$bits->{repl}->{Kids}}, p5::junk->new($$really{mp}{'_}'}));
838             }
839         }
840         else {  # something else, padsv probably
841             $bits->{repl} = $really->ast(@_);
842         }
843     }
844 }
845
846 sub fetchbits {
847     my $self = shift;
848     my $flags = shift || '';
849     my %bits = %$self;
850     my @kids = @{$$self{Kids}};
851     if (@kids) {
852         delete $bits{Kids};
853         my $arg = shift @kids;
854         innerpmop($arg,\%bits, $self, @_);
855         if ($flags =~ /STACKED/) {
856             $arg = shift @kids;
857             $bits{binding} = $arg->ast($self, @_);
858         }
859         if ($bits{when} ne "COMP" and @kids) {
860             $arg = pop @kids;
861             $bits{regcomp} = $arg->ast($self, @_);
862         }
863         if (not exists $bits{repl} and @kids) {
864             $arg = shift @kids;
865             $bits{repl} = $arg->ast($self, @_);
866         }
867     }
868     return \%bits;
869 }
870
871 package PLXML::pvop_svop;
872
873 package PLXML::unop;
874
875 sub ast {
876     my $self = shift;
877     my @newkids = $self->madness('o (');
878
879     if (exists $$self{Kids}) {
880         my $arg = $$self{Kids}[0];
881         push @newkids, $arg->ast($self, @_) if defined $arg;
882     }
883     push @newkids, $self->madness(')');
884
885     return $self->newtype->new(Kids => [@newkids]);
886 }
887
888 package PLXML;
889 package PLXML::Characters;
890 package PLXML::madprops;
891 package PLXML::mad_op;
892 package PLXML::mad_pv;
893 package PLXML::baseop;
894 package PLXML::baseop_unop;
895 package PLXML::binop;
896 package PLXML::cop;
897 package PLXML::filestatop;
898 package PLXML::listop;
899 package PLXML::logop;
900 package PLXML::loop;
901 package PLXML::loopexop;
902 package PLXML::padop;
903 package PLXML::padop_svop;
904 package PLXML::pmop;
905 package PLXML::pvop_svop;
906 package PLXML::unop;
907 package PLXML::op_null;
908
909 # Null nodes typed by first madprop.
910
911 my %astmad;
912
913 BEGIN {
914     %astmad = (
915         'p' => sub {            # peg for #! line, etc.
916             my $self = shift;
917             my @newkids;
918             push @newkids, $self->madness('p px');
919             $::curstate = 0;
920             return P5AST::peg->new(Kids => [@newkids])
921         },
922         '(' => sub {            # extra parens around the whole thing
923             my $self = shift;
924             my @newkids;
925             push @newkids, $self->madness('dx d o (');
926             for my $kid (@{$$self{Kids}}) {
927                 push @newkids, $kid->ast($self, @_);
928             }
929             push @newkids, $self->madness(')');
930             return P5AST::parens->new(Kids => [@newkids])
931         },
932         '~' => sub {                            # binding operator
933             my $self = shift;
934             my @newkids;
935             push @newkids, $$self{Kids}[0]->ast($self,@_);
936             push @newkids, $self->madness('~');
937             push @newkids, $$self{Kids}[1]->ast($self,@_);
938             return P5AST::bindop->new(Kids => [@newkids])
939         },
940         ';' => sub {            # null statements/blocks
941             my $self = shift;
942             my @newkids;
943             push @newkids, $self->madness('{ ; }');
944             $::curstate = 0;
945             return P5AST::nothing->new(Kids => [@newkids])
946         },
947         'I' => sub {            # if or unless statement keyword
948             my $self = shift;
949             my @newkids;
950             push @newkids, $self->madness('L I (');
951             my @subkids;
952             for my $kid (@{$$self{Kids}}) {
953                 push @subkids, $kid->ast($self, @_);
954             }
955             die "oops in op_null->new" unless @subkids == 1;
956             my $newself = $subkids[0];
957             @subkids = @{$$newself{Kids}};
958             
959             unshift @{$subkids[0]{Kids}}, @newkids;
960             push @{$subkids[0]{Kids}}, $self->madness(')');
961             return bless($newself, 'P5AST::condstate');
962         },
963         'U' => sub {                    # use
964             my $self = shift;
965             my @newkids;
966             my @module = $self->madness('U');
967             my @args = $self->madness('A');
968             my $module = $module[-1]{Kids}[-1];
969             if ($module->uni eq 'bytes') {
970                 $::curenc = ::encnum('iso-8859-1');
971             }
972             elsif ($module->uni eq 'utf8') {
973                 if ($$self{mp}{o} eq 'no') {
974                     $::curenc = ::encnum('iso-8859-1');
975                 }
976                 else {
977                     $::curenc = ::encnum('utf-8');
978                 }
979             }
980             elsif ($module->uni eq 'encoding') {
981                 if ($$self{mp}{o} eq 'no') {
982                     $::curenc = ::encnum('iso-8859-1');
983                 }
984                 else {
985                     $::curenc = ::encnum(eval $args[0]->p5text); # XXX bletch
986                 }
987             }
988             # (Surrounding {} ends up here if use is only thing in block.)
989             push @newkids, $self->madness('{ o');
990             push @newkids, @module;
991             push @newkids, $self->madness('V');
992             push @newkids, @args;
993             push @newkids, $self->madness('S ; }');
994             $::curstate = 0;
995             return P5AST::use->new(Kids => [@newkids])
996         },
997         '?' => sub {                    # ternary
998             my $self = shift;
999             my @newkids;
1000             my @subkids;
1001             my @condkids = @{$$self{Kids}[0]{Kids}};
1002             
1003             push @newkids, $condkids[0]->ast($self,@_), $self->madness('?');
1004             push @newkids, $condkids[1]->ast($self,@_), $self->madness(':');
1005             push @newkids, $condkids[2]->ast($self,@_);
1006             return P5AST::ternary->new(Kids => [@newkids])
1007         },
1008         '&' => sub {                    # subroutine
1009             my $self = shift;
1010             my @newkids;
1011             push @newkids, $self->madness('d n s a : { & } ;');
1012             $::curstate = 0;
1013             return P5AST::sub->new(Kids => [@newkids])
1014         },
1015         'i' => sub {                    # modifier if
1016             my $self = shift;
1017             my @newkids;
1018             push @newkids, $self->madness('i');
1019             my $cond = $$self{Kids}[0];
1020             my @subkids;
1021             for my $kid (@{$$cond{Kids}}) {
1022                 push @subkids, $kid->ast($self, @_);
1023             }
1024             push @newkids, shift @subkids;
1025             unshift @newkids, @subkids;
1026             return P5AST::condmod->new(Kids => [@newkids])
1027         },
1028         'P' => sub {                            # package declaration
1029             my $self = shift;
1030             my @newkids;
1031             push @newkids, $self->madness('o');
1032             push @newkids, $self->madness('P');
1033             push @newkids, $self->madness(';');
1034             $::curstate = 0;
1035             return P5AST::package->new(Kids => [@newkids])
1036         },
1037         'F' => sub {                            # format
1038             my $self = shift;
1039             my @newkids = $self->madness('F n b');
1040             $::curstate = 0;
1041             return P5AST::format->new(Kids => [@newkids])
1042         },
1043         'x' => sub {                            # qw literal
1044             my $self = shift;
1045             return P5AST::qwliteral->new(Kids => [$self->madness('x')])
1046         },
1047         'q' => sub {                            # random quote
1048             my $self = shift;
1049             return P5AST::quote->new(Kids => [$self->madness('q = Q')])
1050         },
1051         'X' => sub {                            # random literal
1052             my $self = shift;
1053             return P5AST::token->new(Kids => [$self->madness('X')])
1054         },
1055         ':' => sub {                            # attr list
1056             my $self = shift;
1057             return P5AST::attrlist->new(Kids => [$self->madness(':')])
1058         },
1059         ',' => sub {                            # "unary ," so to speak
1060             my $self = shift;
1061             my @newkids;
1062             push @newkids, $self->madness(',');
1063             push @newkids, $$self{Kids}[0]->ast($self,@_);
1064             return P5AST::listelem->new(Kids => [@newkids])
1065         },
1066         'C' => sub {                            # constant conditional
1067             my $self = shift;
1068             my @newkids;
1069             push @newkids, $$self{Kids}[0]->ast($self,@_);
1070             my @folded = $self->madness('C');
1071             if (@folded) {
1072                 my @t = $self->madness('t');
1073                 my @e = $self->madness('e');
1074                 if (@e) {
1075                     return P5AST::op_cond_expr->new(
1076                         Kids => [
1077                             $self->madness('I ('),
1078                             @folded,
1079                             $self->madness(') ?'),
1080                             P5AST::op_cond_expr->new(Kids => [@newkids]),
1081                             $self->madness(':'),
1082                             @e
1083                         ] );
1084                 }
1085                 else {
1086                     return P5AST::op_cond_expr->new(
1087                         Kids => [
1088                             $self->madness('I ('),
1089                             @folded,
1090                             $self->madness(') ?'),
1091                             @t,
1092                             $self->madness(':'),
1093                             @newkids
1094                         ] );
1095                 }
1096             }
1097             return P5AST::op_null->new(Kids => [@newkids])
1098         },
1099         '+' => sub {                            # unary +
1100             my $self = shift;
1101             my @newkids;
1102             push @newkids, $self->madness('+');
1103             push @newkids, $$self{Kids}[0]->ast($self,@_);
1104             return P5AST::preplus->new(Kids => [@newkids])
1105         },
1106         'D' => sub {                            # do block
1107             my $self = shift;
1108             my @newkids;
1109             push @newkids, $self->madness('D');
1110             push @newkids, $$self{Kids}[0]->ast($self,@_);
1111             return P5AST::doblock->new(Kids => [@newkids])
1112         },
1113         '3' => sub {                            # C-style for loop
1114             my $self = shift;
1115             my @newkids;
1116
1117             # What a mess!
1118             my (undef, $init, $lineseq) = @{$$self{Kids}[0]{Kids}};
1119             my (undef, $leaveloop) = @{$$lineseq{Kids}};
1120             my (undef, $null) = @{$$leaveloop{Kids}};
1121             my $and;
1122             my $cond;
1123             my $lineseq2;
1124             my $block;
1125             my $cont;
1126             if (exists $$null{was} and $$null{was} eq 'and') {
1127                 ($lineseq2) = @{$$null{Kids}};
1128             }
1129             else {
1130                 ($and) = @{$$null{Kids}};
1131                 ($cond, $lineseq2) = @{$$and{Kids}};
1132             }
1133             if ($$lineseq2{mp}{'{'}) {
1134                 $block = $lineseq2;
1135             }
1136             else {
1137                 ($block, $cont) = @{$$lineseq2{Kids}};
1138             }
1139
1140             push @newkids, $self->madness('L 3 (');
1141             push @newkids, $init->ast($self,@_);
1142             push @newkids, $self->madness('1');
1143             if (defined $cond) {
1144                 push @newkids, $cond->ast($self,@_);
1145             }
1146             elsif (defined $null) {
1147                 push @newkids, $null->madness('1');
1148             }
1149             push @newkids, $self->madness('2');
1150             if (defined $cont) {
1151                 push @newkids, $cont->ast($self,@_);
1152             }
1153             push @newkids, $self->madness(')');
1154             push @newkids, $block->blockast($self,@_);
1155             $::curstate = 0;
1156             return P5AST::cfor->new(Kids => [@newkids])
1157         },
1158         'o' => sub {                    # random useless operator
1159             my $self = shift;
1160             my @newkids;
1161             push @newkids, $self->madness('o');
1162             my $kind = $newkids[-1] || '';
1163             $kind = $kind->uni if ref $kind;
1164             my @subkids;
1165             for my $kid (@{$$self{Kids}}) {
1166                 push @subkids, $kid->ast($self, @_);
1167             }
1168             if ($kind eq '=') { # stealth readline
1169                 unshift(@newkids, shift(@subkids));
1170                 push(@newkids, @subkids);
1171                 return P5AST::op_aassign->new(Kids => [@newkids])
1172             }
1173             else {
1174                 my $newself = $subkids[0];
1175                 splice(@{$newself->{Kids}}, 1, 0,
1176                             $self->madness('ox ('),
1177                             @newkids,
1178                             $self->madness(')')
1179                 );
1180                 return $newself;
1181             }
1182         },
1183     );
1184 }
1185
1186 # Null nodes are an untyped mess inside Perl.  Instead of fixing it there,
1187 # we derive an effective type either from the "was" field or the first madprop.
1188 # (The individual routines select the actual new type.)
1189
1190 sub ast {
1191     my $self = shift;
1192     my $was = $$self{was} || 'peg';
1193     my $mad = $$self{mp}{FIRST} || "unknown";
1194
1195     # First try for a "was".
1196     my $meth = "PLXML::op_${was}::astnull";
1197     if (exists &{$meth}) {
1198         return $self->$meth(@_);
1199     }
1200
1201     # Look at first madprop.
1202     if (exists $astmad{$mad}) {
1203         return $astmad{$mad}->($self);
1204     }
1205     warn "No mad $mad" unless $mad eq 'unknown';
1206
1207     # Do something generic.
1208     my @newkids;
1209     for my $kid (@{$$self{Kids}}) {
1210         push @newkids, $kid->ast($self, @_);
1211     }
1212     return $self->newtype->new(Kids => [@newkids]);
1213 }
1214
1215 sub blockast {
1216     my $self = shift;
1217     local $::curstate;
1218     local $::curenc = $::curenc;
1219     return $self->madness('{ ; }');
1220 }
1221
1222 package PLXML::op_stub;
1223
1224 sub ast {
1225     my $self = shift;
1226     return $self->newtype->new(Kids => [$self->madness(', x ( ) q = Q')]);
1227 }
1228
1229 package PLXML::op_scalar;
1230
1231 sub ast {
1232     my $self = shift;
1233
1234     my @pre = $self->madness('o q');
1235     my $op = pop @pre;
1236     if ($op->uni =~ /^<</) {
1237         my @newkids;
1238         my $opstub = bless { start => $op }, 'P5AST::heredoc';
1239         push @newkids, $opstub;
1240         push @newkids, $self->madness('(');
1241
1242         my @kids = @{$$self{Kids}};
1243
1244         my @divert;
1245         for my $kid (@kids) {
1246             next if ref $kid eq 'PLXML::op_pushmark';
1247             next if ref $kid eq 'PLXML::op_null' and
1248                     defined $$kid{was} and $$kid{was} eq 'pushmark';
1249             push @divert, $kid->ast($self, @_);
1250         }
1251         $opstub->{doc} = P5AST::op_list->new(Kids => [@divert]);
1252         $opstub->{end} = ($self->madness('Q'))[-1];
1253
1254         push @newkids, $self->madness(')');
1255
1256         return $self->newtype->new(Kids => [@pre,@newkids]);
1257     }
1258     return $self->PLXML::baseop_unop::ast();
1259 }
1260
1261 package PLXML::op_pushmark;
1262
1263 sub ast { () }
1264
1265 package PLXML::op_wantarray;
1266 package PLXML::op_const;
1267
1268 sub astnull {
1269     my $self = shift;
1270     my @newkids;
1271     return unless $$self{mp};
1272     push @newkids, $self->madness('q = Q X : f O ( )');
1273     return P5AST::op_const->new(Kids => [@newkids]);
1274 }
1275
1276 sub ast {
1277     my $self = shift;
1278     return unless %{$$self{mp}};
1279
1280     my @before;
1281
1282     my $const;
1283     my @args = $self->madness('f');
1284     if (@args) {
1285     }
1286     elsif (exists $self->{mp}{q}) {
1287         push @args, $self->madness('d q');
1288         if ($args[-1]->uni =~ /^<</) {
1289             my $opstub = bless { start => pop(@args) }, 'P5AST::heredoc';
1290             $opstub->{doc} = P5AST::op_const->new(Kids => [$self->madness('=')]);
1291             $opstub->{end} = ($self->madness('Q'))[-1];
1292             push @args, $opstub;
1293         }
1294         else {
1295             push @args, $self->madness('= Q');
1296         }
1297     }
1298     elsif (exists $self->{mp}{X}) {
1299         push @before, $self->madness('d');      # was local $[ probably
1300         if (not $$self{mp}{O}) {
1301             push @before, $self->madness('o');  # was unary
1302         }
1303         my @X = $self->madness(': X');
1304         if (exists $$self{private} and $$self{private} =~ /BARE/) {
1305             return $self->newtype->new(Kids => [@X]);
1306         }
1307         my $X = pop @X;
1308         push @before, @X;
1309         @args = (
1310             $self->madness('x'),
1311             $X);
1312         if ($$self{mp}{O}) {
1313             push @args, $self->madness('o O');
1314         }
1315     }
1316     elsif (exists $self->{mp}{O}) {
1317         push @args, $self->madness('O');
1318     }
1319     elsif ($$self{private} =~ /\bBARE\b/) {
1320         @args = ($$self{PV});
1321     }
1322     elsif (exists $$self{mp}{o}) {
1323         @args = $self->madness('o');
1324     }
1325     elsif (exists $$self{PV}) {
1326         @args = ('"', $$self{PV}, '"');
1327     }
1328     elsif (exists $$self{NV}) {
1329         @args = $$self{NV};
1330     }
1331     elsif (exists $$self{IV}) {
1332         @args = $$self{IV};
1333     }
1334     else {
1335         @args = $self->SUPER::text(@_);
1336     }
1337     return $self->newtype->new(Kids => [@before, @args]);
1338 }
1339
1340
1341 package PLXML::op_gvsv;
1342
1343 sub ast {
1344     my $self = shift;
1345     my @args;
1346     my @retval;
1347     for my $attr (qw/gv GV flags/) {
1348         if (exists $$self{$attr}) {
1349             push @args, $attr, $$self{$attr};
1350         }
1351     }
1352     push @retval, @args;
1353     push @retval, $self->madness('X');
1354     return $self->newtype->new(Kids => [@retval]);
1355 }
1356
1357 package PLXML::op_gv;
1358
1359 sub ast {
1360     my $self = shift;
1361     my @newkids;
1362     push @newkids, $self->madness('X K');
1363
1364     return $self->newtype->new(Kids => [@newkids]);
1365 }
1366
1367 package PLXML::op_gelem;
1368
1369 sub ast {
1370     my $self = shift;
1371
1372     local $::curstate;  # in case there are statements in subscript
1373     local $::curenc = $::curenc;
1374     my @newkids;
1375     push @newkids, $self->madness('dx d');
1376     for my $kid (@{$$self{Kids}}) {
1377         push @newkids, $kid->ast($self, @_);
1378     }
1379     splice @newkids, -1, 0, $self->madness('o {');
1380     push @newkids, $self->madness('}');
1381
1382     return $self->newtype->new(Kids => [@newkids]);
1383 }
1384
1385 package PLXML::op_padsv;
1386
1387 sub ast {
1388     my $self = shift;
1389     my @args;
1390     push @args, $self->madness('dx d ( $ )');
1391
1392     return $self->newtype->new(Kids => [@args]);
1393 }
1394
1395 package PLXML::op_padav;
1396
1397 sub astnull { ast(@_) }
1398
1399 sub ast {
1400     my $self = shift;
1401     my @retval;
1402     push @retval, $self->madness('dx d (');
1403     push @retval, $self->madness('$ @');
1404     push @retval, $self->madness(') o O');
1405     return $self->newtype->new(Kids => [@retval]);
1406 }
1407
1408 package PLXML::op_padhv;
1409
1410 sub astnull { ast(@_) }
1411
1412 sub ast {
1413     my $self = shift;
1414     my @retval;
1415     push @retval, $self->madness('dx d (');
1416     push @retval, $self->madness('$ @ %');
1417     push @retval, $self->madness(') o O');
1418     return $self->newtype->new(Kids => [@retval]);
1419 }
1420
1421 package PLXML::op_padany;
1422
1423 package PLXML::op_pushre;
1424
1425 sub ast {
1426     my $self = shift;
1427     if ($$self{mp}{q}) {
1428         return $self->madness('q = Q m');
1429     }
1430     if ($$self{mp}{X}) {
1431         return $self->madness('X m');
1432     }
1433     if ($$self{mp}{e}) {
1434         return $self->madness('e m');
1435     }
1436     return $$self{Kids}[1]->ast($self,@_), $self->madness('m');
1437 }
1438
1439 package PLXML::op_rv2gv;
1440
1441 sub ast {
1442     my $self = shift;
1443
1444     my @newkids;
1445     push @newkids, $self->madness('dx d ( * $');
1446     push @newkids, $$self{Kids}[0]->ast();
1447     push @newkids, $self->madness(')');
1448     return $self->newtype->new(Kids => [@newkids]);
1449 }
1450
1451 package PLXML::op_rv2sv;
1452
1453 sub astnull {
1454     my $self = shift;
1455     return P5AST::op_rv2sv->new(Kids => [$self->madness('O o dx d ( $ ) : a')]);
1456 }
1457
1458 sub ast {
1459     my $self = shift;
1460
1461     my @newkids;
1462     push @newkids, $self->madness('dx d ( $');
1463     if (ref $$self{Kids}[0] ne "PLXML::op_gv") {
1464         push @newkids, $$self{Kids}[0]->ast();
1465     }
1466     push @newkids, $self->madness(') : a');
1467     return $self->newtype->new(Kids => [@newkids]);
1468 }
1469
1470 package PLXML::op_av2arylen;
1471
1472 sub ast {
1473     my $self = shift;
1474
1475     my @newkids;
1476     push @newkids, $$self{Kids}[0]->madness('l');
1477     push @newkids, $$self{Kids}[0]->ast();
1478     return $self->newtype->new(Kids => [@newkids]);
1479 }
1480
1481 package PLXML::op_rv2cv;
1482
1483 sub astnull {
1484     my $self = shift;
1485     my @newkids;
1486     push @newkids, $self->madness('X');
1487     return @newkids if @newkids;
1488     if (exists $$self{mp}{'&'}) {
1489         push @newkids, $self->madness('&');
1490         if (@{$$self{Kids}}) {
1491             push @newkids, $$self{Kids}[0]->ast(@_);
1492         }
1493     }
1494     else {
1495         push @newkids, $$self{Kids}[0]->ast(@_);
1496     }
1497     return P5AST::op_rv2cv->new(Kids => [@newkids]);
1498 }
1499
1500 sub ast {
1501     my $self = shift;
1502
1503     my @newkids;
1504     push @newkids, $self->madness('&');
1505     if (@{$$self{Kids}}) {
1506         push @newkids, $$self{Kids}[0]->ast();
1507     }
1508     return $self->newtype->new(Kids => [@newkids]);
1509 }
1510
1511 package PLXML::op_anoncode;
1512
1513 sub ast {
1514     my $self = shift;
1515     my $arg = $$self{Kids}[0];
1516     local $::curstate;          # hide nested statements in sub
1517     local $::curenc = $::curenc;
1518     if (defined $arg) {
1519         return $arg->ast(@_);
1520     }
1521     return ';';  # XXX literal ; should come through somewhere
1522 }
1523
1524 package PLXML::op_prototype;
1525 package PLXML::op_refgen;
1526
1527 sub ast {
1528     my $self = shift;
1529     my @newkids = $self->madness('o s a');
1530
1531     if (exists $$self{Kids}) {
1532         my $arg = $$self{Kids}[0];
1533         push @newkids, $arg->ast($self, @_) if defined $arg;
1534     }
1535
1536     my $res = $self->newtype->new(Kids => [@newkids]);
1537     return $res;
1538 }
1539
1540 package PLXML::op_srefgen;
1541
1542 sub ast {
1543     my @newkids;
1544     my $self = shift;
1545     if ($$self{mp}{FIRST} eq '{') {
1546         local $::curstate;      # this is officially a block, so hide it
1547         local $::curenc = $::curenc;
1548         push @newkids, $self->madness('{');
1549         for my $kid (@{$$self{Kids}}) {
1550             push @newkids, $kid->ast($self, @_);
1551         }
1552         push @newkids, $self->madness('; }');
1553         return P5AST::op_stringify->new(Kids => [@newkids]);
1554     }
1555     else {
1556         push @newkids, $self->madness('o [');
1557         for my $kid (@{$$self{Kids}}) {
1558             push @newkids, $kid->ast($self, @_);
1559         }
1560         push @newkids, $self->madness(']');
1561         return P5AST::op_stringify->new(Kids => [@newkids]);
1562     }
1563 }
1564
1565 package PLXML::op_ref;
1566 package PLXML::op_bless;
1567 package PLXML::op_backtick;
1568
1569 sub ast {
1570     my $self = shift;
1571     my @args;
1572     if (exists $self->{mp}{q}) {
1573         push @args, $self->madness('q');
1574         if ($args[-1]->uni =~ /^<</) {
1575             my $opstub = bless { start => $args[-1] }, 'P5AST::heredoc';
1576             $args[-1] = $opstub;
1577             $opstub->{doc} = P5AST::op_const->new(Kids => [$self->madness('=')]);
1578             $opstub->{end} = ($self->madness('Q'))[-1];
1579         }
1580         else {
1581             push @args, $self->madness('= Q');
1582         }
1583     }
1584     return $self->newtype->new(Kids => [@args]);
1585 }
1586
1587 package PLXML::op_glob;
1588
1589 sub astnull {
1590     my $self = shift;
1591     my @retval = $self->madness('o q = Q');
1592     if (not @retval or $retval[-1]->uni eq 'glob') {
1593         push @retval, $self->madness('(');
1594         push @retval, $$self{Kids}[0]->ast($self,@_);
1595         push @retval, $self->madness(')');
1596     }
1597     return P5AST::op_glob->new(Kids => [@retval]);
1598 }
1599
1600 package PLXML::op_readline;
1601
1602 sub astnull {
1603     my $self = shift;
1604     my @retval;
1605     if (exists $$self{mp}{q}) {
1606         @retval = $self->madness('q = Q');
1607     }
1608     elsif (exists $$self{mp}{X}) {
1609         @retval = $self->madness('X');
1610     }
1611     return P5AST::op_readline->new(Kids => [@retval]);
1612 }
1613
1614 sub ast {
1615     my $self = shift;
1616
1617     my @retval;
1618
1619     my @args;
1620     my $const;
1621     if (exists $$self{mp}{q}) {
1622         @args = $self->madness('q = Q');
1623     }
1624     elsif (exists $$self{mp}{X}) {
1625         @args = $self->madness('X');
1626     }
1627     elsif (exists $$self{GV}) {
1628         @args = $$self{IV};
1629     }
1630     elsif (@{$$self{Kids}}) {
1631         @args = $self->PLXML::unop::ast(@_);
1632     }
1633     else {
1634         @args = $self->SUPER::text(@_);
1635     }
1636     return $self->newtype->new(Kids => [@retval,@args]);
1637 }
1638
1639
1640 package PLXML::op_rcatline;
1641 package PLXML::op_regcmaybe;
1642 package PLXML::op_regcreset;
1643 package PLXML::op_regcomp;
1644
1645 sub ast {
1646     my $self = shift;
1647     $self->PLXML::unop::ast(@_);
1648 }
1649
1650 package PLXML::op_match;
1651
1652 sub ast {
1653     my $self = shift;
1654     my $retval = $self->SUPER::ast(@_);
1655     my $p5re;
1656     if (not $p5re = $retval->p5text()) {
1657         $retval = $self->newtype->new(Kids => [$self->madness('X q = Q m')]);
1658         $p5re = $retval->p5text();
1659     }
1660     if ($deinterpolate) {
1661         $retval->{P5re} = P5re::qrparse($p5re);
1662     }
1663     return $retval;
1664 }
1665
1666 package PLXML::op_qr;
1667
1668 sub ast {
1669     my $self = shift;
1670     my $retval;
1671     if (exists $$self{flags}) {
1672         $retval = $self->SUPER::ast(@_);
1673     }
1674     else {
1675         $retval = $self->newtype->new(Kids => [$self->madness('X q = Q m')]);
1676     }
1677     if ($deinterpolate) {
1678         my $p5re = $retval->p5text();
1679         $retval->{P5re} = P5re::qrparse($p5re);
1680     }
1681     return $retval;
1682 }
1683
1684 package PLXML::op_subst;
1685
1686 sub ast {
1687     my $self = shift;
1688
1689     my $bits = $self->fetchbits($$self{flags},@_);
1690
1691     my @newkids;
1692     if ($bits->{binding}) {
1693         push @newkids, $bits->{binding};
1694         push @newkids, $self->madness('~');
1695     }
1696     my $X = p5::token->new($$self{mp}{X});
1697     my @lfirst = $self->madness('q');
1698     my @llast = $self->madness('Q');
1699     push @newkids,
1700         @lfirst,
1701         $self->madness('E'),    # XXX s/b e probably
1702         @llast;
1703     my @rfirst = $self->madness('z');
1704     my @rlast = $self->madness('Z');
1705     my @mods = $self->madness('m');
1706     if ($rfirst[-1]->uni ne $llast[-1]->uni) {
1707         push @newkids, @rfirst;
1708     }
1709
1710     push @newkids, $bits->{repl}, @rlast, @mods;
1711
1712     my $retval = $self->newtype->new(Kids => [@newkids]);
1713     if ($deinterpolate) {
1714         my $p5re = $retval->p5text();
1715         $retval->{P5re} = P5re::qrparse($p5re);
1716     }
1717     return $retval;
1718 }
1719
1720 package PLXML::op_substcont;
1721 package PLXML::op_trans;
1722
1723 sub ast {
1724     my $self = shift;
1725
1726 #    my $bits = $self->fetchbits($$self{flags},@_);
1727 #
1728     my @newkids;
1729     my @lfirst = $self->madness('q');
1730     my @llast = $self->madness('Q');
1731     push @newkids,
1732         @lfirst,
1733         $self->madness('E'),
1734         @llast;
1735     my @rfirst = $self->madness('z');
1736     my @repl = $self->madness('R');
1737     my @rlast = $self->madness('Z');
1738     my @mods = $self->madness('m');
1739     if ($rfirst[-1]->uni ne $llast[-1]->uni) {
1740         push @newkids, @rfirst;
1741     }
1742
1743     push @newkids, @repl, @rlast, @mods;
1744
1745     my $res = $self->newtype->new(Kids => [@newkids]);
1746     return $res;
1747 }
1748
1749 package PLXML::op_sassign;
1750
1751 sub ast {
1752     my $self = shift;
1753     my @newkids;
1754
1755     my $right = $$self{Kids}[1];
1756     eval { push @newkids, $right->ast($self, @_); };
1757
1758     push @newkids, $self->madness('o');
1759
1760     my $left = $$self{Kids}[0];
1761     push @newkids, $left->ast($self, @_);
1762
1763     return $self->newtype->new(Kids => [@newkids]);
1764 }
1765
1766 package PLXML::op_aassign;
1767
1768 sub astnull { ast(@_) }
1769
1770 sub ast {
1771     my $self = shift;
1772     my @newkids;
1773
1774     my $right = $$self{Kids}[1];
1775     push @newkids, $right->ast($self, @_);
1776
1777     push @newkids, $self->madness('o');
1778
1779     my $left = $$self{Kids}[0];
1780     push @newkids, $left->ast($self, @_);
1781
1782     return $self->newtype->new(Kids => [@newkids]);
1783 }
1784
1785 package PLXML::op_chop;
1786 package PLXML::op_schop;
1787 package PLXML::op_chomp;
1788 package PLXML::op_schomp;
1789 package PLXML::op_defined;
1790 package PLXML::op_undef;
1791 package PLXML::op_study;
1792 package PLXML::op_pos;
1793 package PLXML::op_preinc;
1794
1795 sub ast {
1796     my $self = shift;
1797     if ($$self{targ}) {         # stealth post inc or dec
1798         return $self->PLXML::op_postinc::ast(@_);
1799     }
1800     return $self->SUPER::ast(@_);
1801 }
1802
1803 package PLXML::op_i_preinc;
1804
1805 sub ast { my $self = shift; $self->PLXML::op_preinc::ast(@_); }
1806
1807 package PLXML::op_predec;
1808
1809 sub ast { my $self = shift; $self->PLXML::op_preinc::ast(@_); }
1810
1811 package PLXML::op_i_predec;
1812
1813 sub ast { my $self = shift; $self->PLXML::op_preinc::ast(@_); }
1814
1815 package PLXML::op_postinc;
1816
1817 sub ast {
1818     my $self = shift;
1819     my @newkids;
1820
1821     if (exists $$self{Kids}) {
1822         my $arg = $$self{Kids}[0];
1823         push @newkids, $arg->ast($self, @_) if defined $arg;
1824     }
1825     push @newkids, $self->madness('o');
1826
1827     my $res = $self->newtype->new(Kids => [@newkids]);
1828     return $res;
1829 }
1830
1831 package PLXML::op_i_postinc;
1832
1833 sub ast { my $self = shift; $self->PLXML::op_postinc::ast(@_); }
1834
1835 package PLXML::op_postdec;
1836
1837 sub ast { my $self = shift; $self->PLXML::op_postinc::ast(@_); }
1838
1839 package PLXML::op_i_postdec;
1840
1841 sub ast { my $self = shift; $self->PLXML::op_postinc::ast(@_); }
1842
1843 package PLXML::op_pow;
1844 package PLXML::op_multiply;
1845 package PLXML::op_i_multiply;
1846 package PLXML::op_divide;
1847 package PLXML::op_i_divide;
1848 package PLXML::op_modulo;
1849 package PLXML::op_i_modulo;
1850 package PLXML::op_repeat;
1851
1852 sub ast {
1853     my $self = shift;
1854     return $self->SUPER::ast(@_)
1855         unless exists $$self{private} and $$self{private} =~ /DOLIST/;
1856
1857     my $newself = $$self{Kids}[0]->ast($self,@_);
1858     splice @{$newself->{Kids}}, -1, 0, $self->madness('o');
1859
1860     return bless $newself, $self->newtype;      # rebless the op_null
1861 }
1862
1863 package PLXML::op_add;
1864 package PLXML::op_i_add;
1865 package PLXML::op_subtract;
1866 package PLXML::op_i_subtract;
1867 package PLXML::op_concat;
1868
1869 sub astnull {
1870     my $self = shift;
1871     my @newkids;
1872
1873     my @before;
1874     if (@before = $self->madness('M')) {
1875         push @before, $self->madness('ox');     # o is the .
1876     }
1877     my @after;
1878     my $left = $$self{Kids}[0];
1879     push @newkids, $left->ast($self, @_);
1880
1881     push @newkids, $self->madness('o');
1882
1883     my $right = $$self{Kids}[1];
1884     push @newkids, $right->ast($self, @_);
1885     return P5AST::op_concat->new(Kids => [@newkids]);
1886 }
1887
1888 sub ast {
1889     my $self = shift;
1890     my $parent = $_[0];
1891     my @newkids;
1892
1893     my @before;
1894     if (@before = $self->madness('M')) {
1895         push @before, $self->madness('ox');     # o is the .
1896     }
1897     my @after;
1898     my $left = $$self{Kids}[0];
1899     push @newkids, $left->ast($self, @_);
1900
1901     push @newkids, $self->madness('o');
1902
1903     my $right = $$self{Kids}[1];
1904     push @newkids, $right->ast($self, @_);
1905
1906     return $self->newtype->new(Kids => [@before, @newkids, @after]);
1907 }
1908
1909 package PLXML::op_stringify;
1910
1911 sub astnull {
1912     ast(@_);
1913 }
1914
1915 sub ast {
1916     my $self = shift;
1917     my @newkids;
1918     my @front = $self->madness('q (');
1919     my @back = $self->madness(') Q');
1920     my @M = $self->madness('M');
1921     if (@M) {
1922         push @newkids, $M[0], $self->madness('o');
1923     }
1924     push @newkids, @front;
1925     for my $kid (@{$$self{Kids}}) {
1926         push @newkids, $kid->ast($self, @_);
1927     }
1928     push @newkids, @back;
1929     return P5AST::op_stringify->new(Kids => [@newkids]);
1930 }
1931
1932 package PLXML::op_left_shift;
1933 package PLXML::op_right_shift;
1934 package PLXML::op_lt;
1935 package PLXML::op_i_lt;
1936 package PLXML::op_gt;
1937 package PLXML::op_i_gt;
1938 package PLXML::op_le;
1939 package PLXML::op_i_le;
1940 package PLXML::op_ge;
1941 package PLXML::op_i_ge;
1942 package PLXML::op_eq;
1943 package PLXML::op_i_eq;
1944 package PLXML::op_ne;
1945 package PLXML::op_i_ne;
1946 package PLXML::op_ncmp;
1947 package PLXML::op_i_ncmp;
1948 package PLXML::op_slt;
1949 package PLXML::op_sgt;
1950 package PLXML::op_sle;
1951 package PLXML::op_sge;
1952 package PLXML::op_seq;
1953 package PLXML::op_sne;
1954 package PLXML::op_scmp;
1955 package PLXML::op_bit_and;
1956 package PLXML::op_bit_xor;
1957 package PLXML::op_bit_or;
1958 package PLXML::op_negate;
1959 package PLXML::op_i_negate;
1960 package PLXML::op_not;
1961
1962 sub ast {
1963     my $self = shift;
1964     my @newkids = $self->madness('o (');
1965     my @swap;
1966     if (@newkids and $newkids[-1]->uni eq '!~') {
1967         @swap = @newkids;
1968         @newkids = ();
1969     }
1970
1971     if (exists $$self{Kids}) {
1972         my $arg = $$self{Kids}[0];
1973         push @newkids, $arg->ast($self, @_) if defined $arg;
1974     }
1975     if (@swap) {
1976         splice @{$newkids[-1][0]{Kids}}, -2, 0, @swap;  # XXX WAG
1977     }
1978     push @newkids, $self->madness(')');
1979
1980     my $res = $self->newtype->new(Kids => [@newkids]);
1981     return $res;
1982 }
1983
1984 package PLXML::op_complement;
1985 package PLXML::op_atan2;
1986 package PLXML::op_sin;
1987 package PLXML::op_cos;
1988 package PLXML::op_rand;
1989 package PLXML::op_srand;
1990 package PLXML::op_exp;
1991 package PLXML::op_log;
1992 package PLXML::op_sqrt;
1993 package PLXML::op_int;
1994 package PLXML::op_hex;
1995 package PLXML::op_oct;
1996 package PLXML::op_abs;
1997 package PLXML::op_length;
1998 package PLXML::op_substr;
1999 package PLXML::op_vec;
2000 package PLXML::op_index;
2001 package PLXML::op_rindex;
2002 package PLXML::op_sprintf;
2003 package PLXML::op_formline;
2004 package PLXML::op_ord;
2005 package PLXML::op_chr;
2006 package PLXML::op_crypt;
2007 package PLXML::op_ucfirst;
2008
2009 sub ast {
2010     my $self = shift;
2011     return $self->PLXML::listop::ast(@_);
2012 }
2013
2014 package PLXML::op_lcfirst;
2015
2016 sub ast {
2017     my $self = shift;
2018     return $self->PLXML::listop::ast(@_);
2019 }
2020
2021 package PLXML::op_uc;
2022
2023 sub ast {
2024     my $self = shift;
2025     return $self->PLXML::listop::ast(@_);
2026 }
2027
2028 package PLXML::op_lc;
2029
2030 sub ast {
2031     my $self = shift;
2032     return $self->PLXML::listop::ast(@_);
2033 }
2034
2035 package PLXML::op_quotemeta;
2036
2037 sub ast {
2038     my $self = shift;
2039     return $self->PLXML::listop::ast(@_);
2040 }
2041
2042 package PLXML::op_rv2av;
2043
2044 sub astnull {
2045     my $self = shift;
2046     return P5AST::op_rv2av->new(Kids => [$self->madness('$ @')]);
2047 }
2048
2049 sub ast {
2050     my $self = shift;
2051
2052     if (ref $$self{Kids}[0] eq 'PLXML::op_const' and $$self{mp}{'O'}) {
2053         return $self->madness('O');
2054     }
2055
2056     my @before;
2057     push @before, $self->madness('dx d (');
2058
2059     my @newkids;
2060     push @newkids, $self->madness('$ @ K');
2061     if (ref $$self{Kids}[0] ne "PLXML::op_gv") {
2062         push @newkids, $$self{Kids}[0]->ast();
2063     }
2064     my @after;
2065     push @after, $self->madness(') a');
2066     return $self->newtype->new(Kids => [@before, @newkids, @after]);
2067 }
2068
2069 package PLXML::op_aelemfast;
2070
2071 sub ast {
2072     my $self = shift;
2073     return $self->madness('$');
2074 }
2075
2076 package PLXML::op_aelem;
2077
2078 sub astnull {
2079     my $self = shift;
2080     my @newkids;
2081     push @newkids, $self->madness('dx d');
2082     for my $kid (@{$$self{Kids}}) {
2083         push @newkids, $kid->ast($self, @_);
2084     }
2085     splice @newkids, -1, 0, $self->madness('a [');
2086     push @newkids, $self->madness(']');
2087     return P5AST::op_aelem->new(Kids => [@newkids]);
2088 }
2089
2090 sub ast {
2091     my $self = shift;
2092
2093     my @before = $self->madness('dx d');
2094     my @newkids;
2095     for my $kid (@{$$self{Kids}}) {
2096         push @newkids, $kid->ast(@_);
2097     }
2098     splice @newkids, -1, 0, $self->madness('a [');
2099     push @newkids, $self->madness(']');
2100
2101     return $self->newtype->new(Kids => [@before, @newkids]);
2102 }
2103
2104 package PLXML::op_aslice;
2105
2106 sub astnull {
2107     my $self = shift;
2108     my @newkids;
2109     push @newkids, $self->madness('[');
2110     for my $kid (@{$$self{Kids}}) {
2111         push @newkids, $kid->ast(@_);
2112     }
2113     unshift @newkids, pop @newkids;
2114     unshift @newkids, $self->madness('dx d');
2115     push @newkids, $self->madness(']');
2116     return P5AST::op_aslice->new(Kids => [@newkids]);
2117 }
2118
2119 sub ast {
2120     my $self = shift;
2121
2122     my @newkids;
2123     push @newkids, $self->madness('[');
2124     for my $kid (@{$$self{Kids}}) {
2125         push @newkids, $kid->ast(@_);
2126     }
2127     unshift @newkids, pop @newkids;
2128     unshift @newkids, $self->madness('dx d');
2129     push @newkids, $self->madness(']');
2130
2131     return $self->newtype->new(Kids => [@newkids]);
2132 }
2133
2134 package PLXML::op_each;
2135 package PLXML::op_values;
2136 package PLXML::op_keys;
2137 package PLXML::op_delete;
2138 package PLXML::op_exists;
2139 package PLXML::op_rv2hv;
2140
2141 sub astnull {
2142     my $self = shift;
2143     return P5AST::op_rv2hv->new(Kids => [$self->madness('$')]);
2144 }
2145
2146 sub ast {
2147     my $self = shift;
2148
2149     my @before;
2150     push @before, $self->madness('dx d (');
2151
2152     my @newkids;
2153     push @newkids, $self->madness('$ @ % K');
2154     if (ref $$self{Kids}[0] ne "PLXML::op_gv") {
2155         push @newkids, $$self{Kids}[0]->ast();
2156     }
2157     my @after;
2158     push @after, $self->madness(') a');
2159     return $self->newtype->new(Kids => [@before, @newkids, @after]);
2160 }
2161
2162 package PLXML::op_helem;
2163
2164 sub astnull {
2165     my $self = shift;
2166     local $::curstate;  # hash subscript potentially a lineseq
2167     local $::curenc = $::curenc;
2168
2169     my @newkids;
2170     push @newkids, $self->madness('dx d');
2171     for my $kid (@{$$self{Kids}}) {
2172         push @newkids, $kid->ast($self, @_);
2173     }
2174     splice @newkids, -1, 0, $self->madness('a {');
2175     push @newkids, $self->madness('}');
2176     return P5AST::op_helem->new(Kids => [@newkids]);
2177 }
2178
2179 sub ast {
2180     my $self = shift;
2181     local $::curstate;  # hash subscript potentially a lineseq
2182     local $::curenc = $::curenc;
2183
2184     my @before = $self->madness('dx d');
2185     my @newkids;
2186     for my $kid (@{$$self{Kids}}) {
2187         push @newkids, $kid->ast($self, @_);
2188     }
2189     splice @newkids, -1, 0, $self->madness('a {');
2190     push @newkids, $self->madness('}');
2191
2192     return $self->newtype->new(Kids => [@before, @newkids]);
2193 }
2194
2195
2196 package PLXML::op_hslice;
2197
2198 sub astnull {
2199     my $self = shift;
2200     my @newkids;
2201     push @newkids, $self->madness('{');
2202     for my $kid (@{$$self{Kids}}) {
2203         push @newkids, $kid->ast(@_);
2204     }
2205     unshift @newkids, pop @newkids;
2206     unshift @newkids, $self->madness('dx d'); 
2207     push @newkids, $self->madness('}');
2208     return P5AST::op_hslice->new(Kids => [@newkids]);
2209 }
2210
2211 sub ast {
2212     my $self = shift;
2213
2214     my @newkids;
2215     push @newkids, $self->madness('{');
2216     for my $kid (@{$$self{Kids}}) {
2217         push @newkids, $kid->ast(@_);
2218     }
2219     unshift @newkids, pop @newkids;
2220     unshift @newkids, $self->madness('dx d'); 
2221     push @newkids, $self->madness('}');
2222
2223     return $self->newtype->new(Kids => [@newkids]);
2224 }
2225
2226 package PLXML::op_unpack;
2227 package PLXML::op_pack;
2228 package PLXML::op_split;
2229
2230 sub ast {
2231     my $self = shift;
2232     my $results = $self->SUPER::ast(@_);
2233     if (my @dest = $self->madness('R')) {
2234         return PLXML::op_aassign->newtype->new(Kids => [@dest, $self->madness('ox'), $results]);
2235     }
2236     return $results;
2237 }
2238
2239 package PLXML::op_join;
2240 package PLXML::op_list;
2241
2242 sub astnull {
2243     my $self = shift;
2244     my @newkids;
2245     my @retval;
2246     my @before;
2247     if (@retval = $self->madness('X')) {
2248         push @before, $self->madness('x o');
2249         return @before,@retval;
2250     }
2251     my @kids = @{$$self{Kids}};
2252     for my $kid (@kids) {
2253         next if ref $kid eq 'PLXML::op_pushmark';
2254         next if ref $kid eq 'PLXML::op_null' and
2255                 defined $$kid{was} and $$kid{was} eq 'pushmark';
2256         push @newkids, $kid->ast($self, @_);
2257     }
2258
2259     my $x = "";
2260     my @newnewkids = ();
2261     push @newnewkids, $self->madness('dx d (');
2262     push @newnewkids, @newkids;
2263     push @newnewkids, $self->madness(') :');
2264     return P5AST::op_list->new(Kids => [@newnewkids]);
2265 }
2266
2267 sub ast {
2268     my $self = shift;
2269
2270     my @retval;
2271     my @before;
2272     if (@retval = $self->madness('X')) {
2273         push @before, $self->madness('o');
2274         return $self->newtype->new(Kids => [@before,@retval]);
2275     }
2276     push @retval, $self->madness('dx d (');
2277
2278     my @newkids;
2279     for my $kid (@{$$self{Kids}}) {
2280         push @newkids, $kid->ast($self, @_);
2281     }
2282     my $x = "";
2283     my @newnewkids = ();
2284     push @newnewkids, @newkids;
2285     @newkids = @newnewkids;
2286     push @retval, @newkids;
2287     push @retval, $self->madness(') :');
2288     return $self->newtype->new(Kids => [@retval]);
2289 }
2290
2291 package PLXML::op_lslice;
2292
2293 sub ast {
2294     my $self = shift;
2295     my @newkids;
2296
2297     if ($$self{mp}{q}) {
2298         push @newkids, $self->madness('q = Q');
2299     }
2300     elsif ($$self{mp}{x}) {
2301         push @newkids, $self->madness('x');
2302     }
2303     else {
2304         push @newkids, $self->madness('(');
2305         my $list = $$self{Kids}[1];
2306         push @newkids, $list->ast($self, @_);
2307         push @newkids, $self->madness(')');
2308     }
2309
2310     push @newkids, $self->madness('[');
2311
2312     my $slice = $$self{Kids}[0];
2313     push @newkids, $slice->ast($self, @_);
2314     push @newkids, $self->madness(']');
2315
2316     return $self->newtype->new(Kids => [@newkids]);
2317 }
2318
2319 package PLXML::op_anonlist;
2320 package PLXML::op_anonhash;
2321 package PLXML::op_splice;
2322 package PLXML::op_push;
2323 package PLXML::op_pop;
2324 package PLXML::op_shift;
2325 package PLXML::op_unshift;
2326 package PLXML::op_sort;
2327 package PLXML::op_reverse;
2328
2329 sub astnull {
2330     my $self = shift;
2331     $self->PLXML::listop::ast(@_);
2332 }
2333
2334 package PLXML::op_grepstart;
2335 package PLXML::op_grepwhile;
2336 package PLXML::op_mapstart;
2337 package PLXML::op_mapwhile;
2338 package PLXML::op_range;
2339
2340 sub ast {
2341     my $self = shift;
2342     return $self->PLXML::binop::ast(@_);
2343 }
2344
2345 package PLXML::op_flip;
2346 package PLXML::op_flop;
2347 package PLXML::op_and;
2348
2349 sub astnull {
2350     my $self = shift;
2351     my @newkids;
2352     my @first = $self->madness('1');
2353     my @second = $self->madness('2');
2354     my @stuff = $$self{Kids}[0]->ast();
2355     if (my @I = $self->madness('I')) {
2356         if (@second) {
2357             push @newkids, @I;
2358             push @newkids, $self->madness('(');
2359             push @newkids, @stuff;
2360             push @newkids, $self->madness(')');
2361             push @newkids, @second;
2362         }
2363         else {
2364             push @newkids, @I;
2365             push @newkids, $self->madness('(');
2366             push @newkids, @first;
2367             push @newkids, $self->madness(')');
2368             push @newkids, @stuff;
2369         }
2370     }
2371     elsif (my @i = $self->madness('i')) {
2372         if (@second) {
2373             push @newkids, @second;
2374             push @newkids, @i;
2375             push @newkids, @stuff;
2376         }
2377         else {
2378             push @newkids, @stuff;
2379             push @newkids, @i;
2380             push @newkids, @first;
2381         }
2382     }
2383     elsif (my @o = $self->madness('o')) {
2384         if (@second) {
2385             push @newkids, @stuff;
2386             push @newkids, @o;
2387             push @newkids, @second;
2388         }
2389         else {
2390             push @newkids, @first;
2391             push @newkids, @o;
2392             push @newkids, @stuff;
2393         }
2394     }
2395     return P5AST::op_and->new(Kids => [@newkids]);
2396 }
2397
2398 package PLXML::op_or;
2399
2400 sub astnull {
2401     my $self = shift;
2402     my @newkids;
2403     my @first = $self->madness('1');
2404     my @second = $self->madness('2');
2405     my @i = $self->madness('i');
2406     my @stuff = $$self{Kids}[0]->ast();
2407     if (@second) {
2408         if (@i) {
2409             push @newkids, @second;
2410             push @newkids, $self->madness('i');
2411             push @newkids, @stuff;
2412         }
2413         else {
2414             push @newkids, @stuff;
2415             push @newkids, $self->madness('o');
2416             push @newkids, @second;
2417         }
2418     }
2419     else {
2420         if (@i) {
2421             push @newkids, @stuff;
2422             push @newkids, $self->madness('i');
2423             push @newkids, @first;
2424         }
2425         else {
2426             push @newkids, @first;
2427             push @newkids, $self->madness('o');
2428             push @newkids, @stuff;
2429         }
2430     }
2431     return "P5AST::op_$$self{was}"->new(Kids => [@newkids]);
2432 }
2433
2434
2435 package PLXML::op_xor;
2436 package PLXML::op_cond_expr;
2437 package PLXML::op_andassign;
2438 package PLXML::op_orassign;
2439 package PLXML::op_method;
2440 package PLXML::op_entersub;
2441
2442 sub ast {
2443     my $self = shift;
2444
2445     if ($$self{mp}{q}) {
2446         return $self->madness('q = Q');
2447     }
2448     if ($$self{mp}{X}) {                # <FH> override?
2449         return $self->madness('X');
2450     }
2451     if ($$self{mp}{A}) {
2452         return $self->astmethod(@_);
2453     }
2454     if ($$self{mp}{a}) {
2455         return $self->astarrow(@_);
2456     }
2457
2458     my @retval;
2459
2460     my @newkids;
2461     my @kids = @{$$self{Kids}};
2462     if (@kids == 1 and ref $kids[0] eq 'PLXML::op_null' and $kids[0]{was} =~ /list/) {
2463         @kids = @{$kids[0]{Kids}};
2464     }
2465     my $dest = pop @kids;
2466     my @dest = $dest->ast($self, @_);
2467     
2468     if (ref($dest) =~ /method/) {
2469         my $invocant = shift @kids;
2470         $invocant = shift @kids if ref($invocant) eq 'PLXML::op_pushmark';
2471         my @invocant = $invocant->ast($self, @_);
2472         push @retval, @dest;
2473         push @retval, @invocant;
2474     }
2475     elsif (exists $$self{mp}{o} and $$self{mp}{o} eq 'do') {
2476         push @retval, $self->madness('o');
2477         push @retval, @dest;
2478     }
2479     else {
2480         push @retval, $self->madness('o');
2481         push @retval, @dest;
2482     }
2483     while (@kids) {
2484         my $kid = shift(@kids);
2485         push @newkids, $kid->ast($self, @_);
2486     }
2487
2488     push @retval, $self->madness('(');
2489     push @retval, @newkids;
2490     push @retval, $self->madness(')');
2491     return $self->newtype->new(Kids => [@retval]);
2492 }
2493
2494 sub astmethod {
2495     my $self = shift;
2496     my @newkids;
2497     my @kids;
2498     for my $kid (@{$$self{Kids}}) {
2499         next if ref $kid eq 'PLXML::op_pushmark';
2500         next if ref $kid eq 'PLXML::op_null' and
2501                 defined $$kid{was} and $$kid{was} eq 'pushmark';
2502         push @kids, $kid;
2503     }
2504     my @invocant;
2505     if ($$self{flags} =~ /\bSTACKED\b/) {
2506         push @invocant, shift(@kids)->ast($self, @_);
2507     }
2508     for my $kid (@kids) {
2509         push @newkids, $kid->ast($self, @_);
2510     }
2511     my $dest = pop(@newkids);
2512     if (ref $dest eq 'PLXML::op_rv2cv' and $$self{flags} =~ /\bMOD\b/) {
2513         $dest = pop(@newkids);
2514     }
2515     my $x = "";
2516     my @retval;
2517     push @retval, @invocant;
2518     push @retval, $self->madness('A');
2519     push @retval, $dest;
2520     push @retval, $self->madness('(');
2521     push @retval, @newkids;
2522     push @retval, $self->madness(')');
2523     return $self->newtype->new(Kids => [@retval]);
2524 }
2525
2526 sub astarrow {
2527     my $self = shift;
2528     my @newkids;
2529     my @retval;
2530     my @kids = @{$$self{Kids}};
2531     if (@kids == 1 and ref $kids[0] eq 'PLXML::op_null' and $kids[0]{was} =~ /list/) {
2532         @kids = @{$kids[0]{Kids}};
2533     }
2534     while (@kids > 1) {
2535         my $kid = shift(@kids);
2536         push @newkids, $kid->ast($self, @_);
2537     }
2538     my @dest = $kids[0]->ast($self, @_);
2539     my $x = "";
2540     push @retval, @dest;
2541     push @retval, $self->madness('a');
2542     push @retval, $self->madness('(');
2543     push @retval, @newkids;
2544     push @retval, $self->madness(')');
2545     return $self->newtype->new(Kids => [@retval]);
2546 }
2547
2548 package PLXML::op_leavesub;
2549
2550 sub ast {
2551     my $self = shift;
2552     if (ref $$self{Kids}[0] eq "PLXML::op_null") {
2553         return $$self{Kids}[0]->ast(@_);
2554     }
2555     return $$self{Kids}[0]->blockast($self, @_);
2556 }
2557
2558 package PLXML::op_leavesublv;
2559
2560 sub ast {
2561     my $self = shift;
2562
2563     return $$self{Kids}[0]->blockast($self, @_);
2564 }
2565
2566 package PLXML::op_caller;
2567 package PLXML::op_warn;
2568 package PLXML::op_die;
2569 package PLXML::op_reset;
2570 package PLXML::op_lineseq;
2571
2572 sub lineseq {
2573     my $self = shift;
2574     my @kids = @{$$self{Kids}};
2575     local $::curstate = 0;      # (probably redundant, but that's okay)
2576     local $::prevstate = 0;
2577     local $::curenc = $::curenc;
2578     my @retval;
2579     my @newstuff;
2580     my $newprev;
2581     while (@kids) {
2582         my $kid = shift @kids;
2583         my $thing = $kid->ast($self, @_);
2584         next unless defined $thing;
2585         if ($::curstate ne $::prevstate) {
2586             if ($::prevstate) {
2587                 push @newstuff, $::prevstate->madness(';');
2588                 push @{$newprev->{Kids}}, @newstuff if $newprev;
2589                 @newstuff = ();
2590             }
2591             $::prevstate = $::curstate;
2592             $newprev = $thing;
2593             push @retval, $thing;
2594         }
2595         elsif ($::prevstate) {
2596             push @newstuff, $thing;
2597         }
2598         else {
2599             push @retval, $thing;
2600         }
2601     }
2602     if ($::prevstate) {
2603         push @newstuff, $::prevstate->madness(';');
2604         push @{$newprev->{Kids}}, @newstuff if $newprev;
2605         @newstuff = ();
2606         $::prevstate = 0;
2607     }
2608     return @retval;
2609 }
2610
2611 sub blockast {
2612     my $self = shift;
2613     local $::curstate;
2614
2615     my @retval;
2616     push @retval, $self->madness('{');
2617  
2618     my @newkids = $self->PLXML::op_lineseq::lineseq(@_);
2619     push @retval, @newkids;
2620
2621     push @retval, $self->madness('; }');
2622     return $self->newtype->new(Kids => [@retval]);
2623 }
2624
2625 package PLXML::op_nextstate;
2626
2627 sub newtype { return "P5AST::statement" }
2628
2629 sub astnull {
2630     my $self = shift;
2631     my @newkids;
2632     push @newkids, $self->madness('L');
2633     $::curstate = $self;
2634     return P5AST::statement->new(Kids => [@newkids]);
2635 }
2636
2637 sub ast {
2638     my $self = shift;
2639
2640     my @newkids;
2641     push @newkids, $self->madness('L');
2642     $::curstate = $self;
2643     return $self->newtype->new(Kids => [@newkids]);
2644 }
2645
2646
2647 package PLXML::op_dbstate;
2648 package PLXML::op_unstack;
2649 package PLXML::op_enter;
2650
2651 sub ast { () }
2652
2653 package PLXML::op_leave;
2654
2655 sub astnull {
2656     ast(@_);
2657 }
2658
2659 sub ast {
2660     my $self = shift;
2661
2662     my $mad = $$self{mp}{FIRST} || "unknown";
2663
2664     my @retval;
2665     if ($mad eq 'w') {
2666         my @newkids;
2667         my @tmpkids;
2668         push @tmpkids, $self->{Kids};
2669         my $anddo = $$self{Kids}[-1]{Kids}[0]{Kids};
2670         eval { push @newkids, $anddo->[1]->ast($self,@_); };
2671         push @newkids, "[[[NOANDDO]]]" if $@;
2672         push @newkids, $self->madness('w');
2673         push @newkids, $anddo->[0]->ast($self,@_);
2674
2675         return $self->newtype->new(Kids => [@newkids]);
2676     }
2677
2678     local $::curstate;
2679     push @retval, $self->madness('o {');
2680
2681     my @newkids = $self->PLXML::op_lineseq::lineseq(@_);
2682     push @retval, @newkids;
2683     push @retval, $self->madness(q/; }/);
2684     my $retval = $self->newtype->new(Kids => [@retval]);
2685
2686     if ($$self{mp}{C}) {
2687         my @before;
2688         my @after;
2689         push @before, $self->madness('I ( C )');
2690         if ($$self{mp}{t}) {
2691             push @before, $self->madness('t');
2692         }
2693         elsif ($$self{mp}{e}) {
2694             push @after, $self->madness('e');
2695         }
2696         return P5AST::op_cond->new(Kids => [@before, $retval, @after]);
2697     }
2698     else {
2699         return $retval;
2700     }
2701 }
2702
2703 package PLXML::op_scope;
2704
2705 sub ast {
2706     my $self = shift;
2707     local $::curstate;
2708
2709     my @newkids;
2710     push @newkids, $self->madness('o');
2711
2712     push @newkids, $self->madness('{');
2713     push @newkids, $self->PLXML::op_lineseq::lineseq(@_);
2714     push @newkids, $self->madness('; }');
2715
2716     my @folded = $self->madness('C');
2717     if (@folded) {
2718         my @t = $self->madness('t');
2719         my @e = $self->madness('e');
2720         if (@e) {
2721             return $self->newtype->new(
2722                 Kids => [
2723                     $self->madness('I ('),
2724                     @folded,
2725                     $self->madness(')'),
2726                     $self->newtype->new(Kids => [@newkids]),
2727                     @e
2728                 ] );
2729         }
2730         else {
2731             return $self->newtype->new(
2732                 Kids => [
2733                     $self->madness('I ('),
2734                     @folded,
2735                     $self->madness(')'),
2736                     @t,
2737                     $self->newtype->new(Kids => [@newkids])
2738                 ] );
2739         }
2740     }
2741     return $self->newtype->new(Kids => [@newkids]);
2742 }
2743
2744 package PLXML::op_enteriter;
2745
2746 sub ast {
2747     my $self = shift;
2748     my (undef,$range,$var) = @{$self->{Kids}};
2749     my @retval;
2750     push @retval, $self->madness('v');
2751     if (!@retval and defined $var) {
2752         push @retval, $var->ast($self,@_);
2753     }
2754     else {
2755         push @retval, '';
2756     }
2757     if (ref $range eq 'PLXML::op_null' and $$self{flags} =~ /STACKED/) {
2758         my (undef,$min,$max) = @{$range->{Kids}};
2759         push @retval, $min->ast($self,@_);
2760         if (defined $max) {
2761             if (exists $$range{mp}{O}) {        # deeply buried .. operator
2762                 PLXML::prepreproc($$range{mp}{O});
2763                 push @retval,
2764                   $$range{mp}{'O'}{Kids}[0]{Kids}[0]{Kids}[0]{Kids}[0]->madness('o')
2765             }
2766             else {
2767                 push @retval, '..';             # XXX missing whitespace
2768             }
2769             push @retval, $max->ast($self,@_);
2770         }
2771     }
2772     else {
2773         push @retval, $range->ast($self,@_);
2774     }
2775     return $self->newtype->new(Kids => [@retval]);
2776 }
2777
2778 package PLXML::op_iter;
2779 package PLXML::op_enterloop;
2780
2781 sub ast {
2782 }
2783
2784 package PLXML::op_leaveloop;
2785
2786 sub ast {
2787     my $self = shift;
2788
2789     my @retval;
2790     my @newkids;
2791     my $enterloop = $$self{Kids}[0];
2792     my $nextthing = $$self{Kids}[1];
2793
2794     if ($$self{mp}{W}) {
2795         push @retval, $self->madness('L');
2796         push @newkids, $self->madness('W d');
2797
2798         if (ref $enterloop eq 'PLXML::op_enteriter') {
2799             my ($var,@rest) = @{$enterloop->ast($self,@_)->{Kids}};
2800             push @newkids, $var if $var;
2801             push @newkids, $self->madness('q ( x = Q');
2802             push @newkids, @rest;
2803         }
2804         else {
2805             push @newkids, $self->madness('(');
2806             push @newkids, $enterloop->ast($self,@_);
2807         }
2808     }
2809     my $andor;
2810
2811     if (ref $nextthing eq 'PLXML::op_null') {
2812         if ($$nextthing{mp}{'1'}) {
2813             push @newkids, $nextthing->madness('1');
2814             push @newkids, $self->madness(')');
2815             push @newkids, $$nextthing{Kids}[0]->blockast($self,@_);
2816         }
2817         elsif ($$nextthing{mp}{'2'}) {
2818             push @newkids, $$nextthing{Kids}[0]->ast($self,@_);
2819             push @newkids, $self->madness(')');
2820             push @newkids, $$nextthing{mp}{'2'}->blockast($self,@_);
2821         }
2822         elsif ($$nextthing{mp}{'U'}) {
2823             push @newkids, $nextthing->ast($self,@_);
2824         }
2825         else {
2826             # bypass the op_null
2827             $andor = $nextthing->{Kids}[0];
2828             eval {
2829                 push @newkids, $$andor{Kids}[0]->ast($self, @_);
2830             };
2831             push @newkids, $self->madness(')');
2832             eval {
2833                 push @newkids, $$andor{Kids}[1]->blockast($self, @_);
2834             };
2835         }
2836     }
2837     else {
2838         $andor = $nextthing;
2839         push @newkids, $nextthing->madness('O');
2840         push @newkids, $self->madness(')');
2841         push @newkids, $nextthing->blockast($self, @_);
2842     }
2843     if ($$self{mp}{w}) {
2844         push @newkids, $self->madness('w');
2845         push @newkids, $enterloop->ast($self,@_);
2846     }
2847
2848     push @retval, @newkids;
2849
2850     return $self->newtype->new(Kids => [@retval]);
2851 }
2852
2853 package PLXML::op_return;
2854 package PLXML::op_last;
2855 package PLXML::op_next;
2856 package PLXML::op_redo;
2857 package PLXML::op_dump;
2858 package PLXML::op_goto;
2859 package PLXML::op_exit;
2860 package PLXML::op_open;
2861 package PLXML::op_close;
2862 package PLXML::op_pipe_op;
2863 package PLXML::op_fileno;
2864 package PLXML::op_umask;
2865 package PLXML::op_binmode;
2866 package PLXML::op_tie;
2867 package PLXML::op_untie;
2868 package PLXML::op_tied;
2869 package PLXML::op_dbmopen;
2870 package PLXML::op_dbmclose;
2871 package PLXML::op_sselect;
2872 package PLXML::op_select;
2873 package PLXML::op_getc;
2874 package PLXML::op_read;
2875 package PLXML::op_enterwrite;
2876 package PLXML::op_leavewrite;
2877 package PLXML::op_prtf;
2878 package PLXML::op_print;
2879 package PLXML::op_sysopen;
2880 package PLXML::op_sysseek;
2881 package PLXML::op_sysread;
2882 package PLXML::op_syswrite;
2883 package PLXML::op_send;
2884 package PLXML::op_recv;
2885 package PLXML::op_eof;
2886 package PLXML::op_tell;
2887 package PLXML::op_seek;
2888 package PLXML::op_truncate;
2889 package PLXML::op_fcntl;
2890 package PLXML::op_ioctl;
2891 package PLXML::op_flock;
2892 package PLXML::op_socket;
2893 package PLXML::op_sockpair;
2894 package PLXML::op_bind;
2895 package PLXML::op_connect;
2896 package PLXML::op_listen;
2897 package PLXML::op_accept;
2898 package PLXML::op_shutdown;
2899 package PLXML::op_gsockopt;
2900 package PLXML::op_ssockopt;
2901 package PLXML::op_getsockname;
2902 package PLXML::op_getpeername;
2903 package PLXML::op_lstat;
2904 package PLXML::op_stat;
2905 package PLXML::op_ftrread;
2906 package PLXML::op_ftrwrite;
2907 package PLXML::op_ftrexec;
2908 package PLXML::op_fteread;
2909 package PLXML::op_ftewrite;
2910 package PLXML::op_fteexec;
2911 package PLXML::op_ftis;
2912 package PLXML::op_fteowned;
2913 package PLXML::op_ftrowned;
2914 package PLXML::op_ftzero;
2915 package PLXML::op_ftsize;
2916 package PLXML::op_ftmtime;
2917 package PLXML::op_ftatime;
2918 package PLXML::op_ftctime;
2919 package PLXML::op_ftsock;
2920 package PLXML::op_ftchr;
2921 package PLXML::op_ftblk;
2922 package PLXML::op_ftfile;
2923 package PLXML::op_ftdir;
2924 package PLXML::op_ftpipe;
2925 package PLXML::op_ftlink;
2926 package PLXML::op_ftsuid;
2927 package PLXML::op_ftsgid;
2928 package PLXML::op_ftsvtx;
2929 package PLXML::op_fttty;
2930 package PLXML::op_fttext;
2931 package PLXML::op_ftbinary;
2932 package PLXML::op_chdir;
2933 package PLXML::op_chown;
2934 package PLXML::op_chroot;
2935 package PLXML::op_unlink;
2936 package PLXML::op_chmod;
2937 package PLXML::op_utime;
2938 package PLXML::op_rename;
2939 package PLXML::op_link;
2940 package PLXML::op_symlink;
2941 package PLXML::op_readlink;
2942 package PLXML::op_mkdir;
2943 package PLXML::op_rmdir;
2944 package PLXML::op_open_dir;
2945 package PLXML::op_readdir;
2946 package PLXML::op_telldir;
2947 package PLXML::op_seekdir;
2948 package PLXML::op_rewinddir;
2949 package PLXML::op_closedir;
2950 package PLXML::op_fork;
2951 package PLXML::op_wait;
2952 package PLXML::op_waitpid;
2953 package PLXML::op_system;
2954 package PLXML::op_exec;
2955 package PLXML::op_kill;
2956 package PLXML::op_getppid;
2957 package PLXML::op_getpgrp;
2958 package PLXML::op_setpgrp;
2959 package PLXML::op_getpriority;
2960 package PLXML::op_setpriority;
2961 package PLXML::op_time;
2962 package PLXML::op_tms;
2963 package PLXML::op_localtime;
2964 package PLXML::op_gmtime;
2965 package PLXML::op_alarm;
2966 package PLXML::op_sleep;
2967 package PLXML::op_shmget;
2968 package PLXML::op_shmctl;
2969 package PLXML::op_shmread;
2970 package PLXML::op_shmwrite;
2971 package PLXML::op_msgget;
2972 package PLXML::op_msgctl;
2973 package PLXML::op_msgsnd;
2974 package PLXML::op_msgrcv;
2975 package PLXML::op_semget;
2976 package PLXML::op_semctl;
2977 package PLXML::op_semop;
2978 package PLXML::op_require;
2979 package PLXML::op_dofile;
2980 package PLXML::op_entereval;
2981
2982 sub ast {
2983     my $self = shift;
2984     local $::curstate;          # eval {} has own statement sequence
2985     return $self->SUPER::ast(@_);
2986 }
2987
2988 package PLXML::op_leaveeval;
2989 package PLXML::op_entertry;
2990 package PLXML::op_leavetry;
2991
2992 sub ast {
2993     my $self = shift;
2994
2995     return $self->PLXML::op_leave::ast(@_);
2996 }
2997
2998 package PLXML::op_ghbyname;
2999 package PLXML::op_ghbyaddr;
3000 package PLXML::op_ghostent;
3001 package PLXML::op_gnbyname;
3002 package PLXML::op_gnbyaddr;
3003 package PLXML::op_gnetent;
3004 package PLXML::op_gpbyname;
3005 package PLXML::op_gpbynumber;
3006 package PLXML::op_gprotoent;
3007 package PLXML::op_gsbyname;
3008 package PLXML::op_gsbyport;
3009 package PLXML::op_gservent;
3010 package PLXML::op_shostent;
3011 package PLXML::op_snetent;
3012 package PLXML::op_sprotoent;
3013 package PLXML::op_sservent;
3014 package PLXML::op_ehostent;
3015 package PLXML::op_enetent;
3016 package PLXML::op_eprotoent;
3017 package PLXML::op_eservent;
3018 package PLXML::op_gpwnam;
3019 package PLXML::op_gpwuid;
3020 package PLXML::op_gpwent;
3021 package PLXML::op_spwent;
3022 package PLXML::op_epwent;
3023 package PLXML::op_ggrnam;
3024 package PLXML::op_ggrgid;
3025 package PLXML::op_ggrent;
3026 package PLXML::op_sgrent;
3027 package PLXML::op_egrent;
3028 package PLXML::op_getlogin;
3029 package PLXML::op_syscall;
3030 package PLXML::op_lock;
3031 package PLXML::op_threadsv;
3032 package PLXML::op_setstate;
3033 package PLXML::op_method_named;
3034
3035 sub ast {
3036     my $self = shift;
3037     return $self->madness('O');
3038 }
3039
3040 package PLXML::op_dor;
3041
3042 sub astnull {
3043     my $self = shift;
3044     $self->PLXML::op_or::astnull(@_);
3045 }
3046
3047 package PLXML::op_dorassign;
3048 package PLXML::op_custom;
3049