3 # The start of a gimme5 replacement based on STD parsing.
7 use warnings FATAL
=> 'all';
9 use List
::Util qw
/sum min/;
13 use YAML
::XS
; # An attempt to replace this with YAML::Syck passed the
14 # tests but produced a different output format that
15 # confused some calling programs. For example, anchors
16 # are usually numbers ascending from 1, and they became
17 # disjoint sets of descending numbers. Also, empty
18 # sequences shown as [] became followed by an empty line.
19 # See also: YAML::Syck in package VAST::package_def below.
21 use JSON
-convert_blessed_universally
;
22 use Scalar
::Util
'blessed', 'refaddr';
38 viv [switches] filename
39 where switches can be:
40 -e use following argument as program
41 --yaml spit out a parsable abstract syntax tree
42 --concise spit out a short syntaxe tree (default)
43 --p5 spit out a Perl 5 representation (partially impl)
44 --p6 spit out a Perl 6 representation
45 --freeze generate a Storable representation
46 --thaw use existing Storable of AST from filename
47 --stab include the symbol table
48 --pos include position info in AST
49 --match include match tree info in AST
50 --log emit debugging info to standard error
58 my $output = 'concise';
62 last unless $_[0] =~ /^-/;
63 my $switch = shift @_;
64 if ($switch eq '--eval' or $switch eq '-e') {
65 $PROG .= Encode
::decode_utf8
(shift(@_)) . "\n";
67 elsif ($switch eq '--yaml' or $switch eq '-y') {
70 elsif ($switch eq '--concise' or $switch eq '-c') {
73 elsif ($switch eq '--p5' or $switch eq '-5') {
76 elsif ($switch eq '--p6' or $switch eq '-6') {
79 elsif ($switch eq '--freeze') {
82 elsif ($switch eq '--stab' or $switch eq '-s') {
85 elsif ($switch eq '--log' or $switch eq '-l') {
88 elsif ($switch eq '--pos' or $switch eq '-p') {
91 elsif ($switch eq '--match' or $switch eq '-m') {
92 $OPT_match = 1; # attach match object
94 elsif ($switch eq '--thaw') {
97 elsif ($switch eq '--help') {
101 # USAGE() unless -r $_[0];
104 my $raw = retrieve
($_[0]);
105 $::ORIG
= $raw->{ORIG
};
107 for my $cl (keys %{$raw->{GENCLASS
}}) {
108 Actions
::gen_class
($cl, $raw->{GENCLASS
}->{$cl});
111 elsif (@_ and -f
$_[0]) {
112 $r = STD
->parsefile($_[0], actions
=> 'Actions')->{'_ast'};
120 $r = STD
->parse($PROG, actions
=> 'Actions')->{'_ast'};
123 $::ORIG
=~ s/\n;\z//;
126 $r->{stabs
} = $STD::ALL
;
129 if ($output eq 'yaml') {
131 # $x =~ s/\n.*: \[\]$//mg;
134 elsif ($output eq 'concise') {
137 elsif ($output eq 'p6') {
140 elsif ($output eq 'p5') {
141 print fixpod
($r->p5);
143 elsif ($output eq 'store') {
144 Storable
::store_fd
({ AST
=> $r, GENCLASS
=> \
%Actions::GENCLASS
,
145 ORIG
=> $::ORIG
}, \
*STDOUT
);
148 die "Unknown output mode";
153 my ($leader, $arg) = @_;
155 $arg =~ s/\n/\n$leader/g;
162 for my $i (0 .. $#_) {
163 $r .= ($i == $#_) ?
"\n└─" : "\n├─";
164 $r .= hang
($i == $#_ ?
" " : "│ ", $_[$i]);
170 my ($first, $rest, $tx) = @_;
173 while (length $tx > $first) {
174 $out .= substr($tx, 0, $first);
176 $tx = substr($tx, $first);
184 my ($node, $width) = @_;
186 $width = 30 if $width < 30;
189 return defined($node) ? shred
($width, $width, "$node") : "undef";
190 } elsif (blessed
($node) && ref($node) =~ /^VAST/) {
192 ref($node->{"."}) eq 'ARRAY' ? @
{$node->{"."}} :
193 defined($node->{"."}) ?
$node->{"."} :
199 # don't list the same node twice
200 my %inpos = map { ref($_) ?
(refaddr
($_) , 1) : () } @pos;
202 @pos = map { concise
($_, $width-2) } @pos;
205 my $title = blessed
$node;
206 my $x = length($title);
207 for my $ch (sort keys %nam) {
208 next if $ch eq '_fate';
210 # hide named children that are just (lists of) positional children
211 if ($inpos{refaddr
($nam{$ch})}) { next }
212 if (ref($nam{$ch}) eq 'ARRAY') {
214 for (@
{$nam{$ch}}) { $all = 0 unless ref $_ && $inpos{refaddr
$_} }
219 my $repr = concise
($nam{$ch}, $width-4);
221 if ($repr !~ /\n/ && length $repr < 30) {
222 if ($x + length($ch) + length($repr) + 6 > $width) {
229 $title .= "$ch: $repr";
230 $x += length("$ch: $repr");
232 my $hang = " " x
(length($ch)+2);
233 push @oobnam, "$ch: " . hang
($hang, $repr);
237 $title = hang
((@pos ?
"│ " : " ") . (@oobnam ?
"│ " : " "), $title);
241 $result .= hang
(@pos ?
"│ " : " ", listify
(@oobnam));
242 $result .= listify
(@pos);
247 return substr($d, 4, length($d)-5);
251 # viv should likely be abstracted into a module instead of doing this hack... - pmurias
254 $OPT_match = $opt{match
};
255 $OPT_log = $opt{log};
260 return $text unless $text =~ /\n/;
261 my @text = split(/^/, $text);
265 $in_begin = $1 if /^=begin\s+(\w+)/;
266 $in_for = 1 if /^=for/;
267 $in_for = 0 if /^\s*$/;
268 my $docomment = $in_begin || $in_for;
269 $in_begin = 0 if /^=end\s+(\w+)/ and $1 eq $in_begin;
270 s/^/# / if $docomment;
287 $out .= $1 if $in =~ s/^\\([\\'])//;
288 $out .= $1 if $in =~ s/^(.)//;
293 # XXX this is only used for backslash escapes in regexes
297 my %trans = ( 'n' => "\n" );
299 $out .= $trans{$1} // $1 if $in =~ s/^\\(.)//;
300 $out .= $1 if $in =~ s/^(.)//;
308 for my $ch (split //, $in) {
309 $out .= $ch eq "\n" ?
'\n' : quotemeta($ch);
314 ###################################################################
316 { package VAST
::Base
;
318 sub Str
{ my $self = shift;
319 my $b = $self->{BEG
};
320 my $e = $self->{END};
321 return '' if $b > length($::ORIG
);
322 substr($::ORIG
, $b, $e - $b);
325 sub kids
{ my $self = shift;
326 my $key = shift() // '.';
327 return () unless exists $self->{$key};
328 my $entry = $self->{$key};
329 return ref($entry) eq 'ARRAY' ? @
$entry : $entry;
332 sub emit_p6
{ my $self = shift;
334 if (exists $self->{'.'}) {
335 my $last = $self->{BEG
};
336 my $all = $self->{'.'};
338 for my $kid (ref($all) eq 'ARRAY' ? @
$all : $all) {
340 if (not defined $kid->{BEG
}) {
341 $kid->{BEG
} = $kid->{_from
} // next;
342 $kid->{END} = $kid->{_pos
};
346 for my $kid (sort { $a->{BEG
} <=> $b->{BEG
} } @kids) {
347 my $kb = $kid->{BEG
};
349 push @text, substr($::ORIG
, $last, $kb - $last);
351 if (ref($kid) eq 'HASH') {
352 print STDERR
::Dump
($self);
353 die "in a weird place";
355 push @text, scalar $kid->p6;
359 my $se = $self->{END};
361 push @text, substr($::ORIG
, $last, $se - $last);
365 # print STDERR "OOPS " . ref($self) . " $$self{TEXT}\n";
366 push @text, $self->{TEXT
};
368 wantarray ?
@text : join('', @text);
371 sub p6
{ my $self = shift; my $lvl = @context;
373 say STDERR
' ' x
$lvl, ref $self, " from ",$self->{BEG
}," to ",$self->{END} if $OPT_log;
374 $context[$lvl] = $self;
375 # print STDERR "HERE " . ref($self) . "\n";
376 splice(@context,$lvl);
377 my @bits = $self->emit_p6;
378 my $val = join '', @bits;
379 my @c = map { ref $_ } @context;
380 my $c = "@c " . ref($self);
382 print STDERR
' ' x
($lvl-1), "$c returns $val\n" if $OPT_log;
383 wantarray ?
@bits : $val;
386 sub emit_p5
{ my $self = shift;
388 if (exists $self->{'.'}) {
389 my $last = $self->{BEG
};
390 my $all = $self->{'.'};
392 for my $kid (ref($all) eq 'ARRAY' ? @
$all : $all) {
394 if (not defined $kid->{BEG
}) {
395 $kid->{BEG
} = $kid->{_from
} // next;
396 $kid->{END} = $kid->{_pos
};
400 for my $kid (sort { $a->{BEG
} <=> $b->{BEG
} } @kids) {
401 my $kb = $kid->{BEG
};
403 push @text, substr($::ORIG
, $last, $kb - $last);
405 if (ref($kid) eq 'HASH') {
406 print STDERR
::Dump
($self);
407 die "in a weird place";
409 push @text, scalar $kid->p5;
413 my $se = $self->{END};
415 push @text, substr($::ORIG
, $last, $se - $last);
419 # print STDERR "OOPS " . ref($self) . " $$self{TEXT}\n";
420 push @text, $self->{TEXT
};
422 wantarray ?
@text : join('', @text);
425 sub p5
{ my $self = shift; my $lvl = @context;
427 say STDERR
' ' x
$lvl, ref $self, " from ",$self->{BEG
}," to ",$self->{END} if $OPT_log;
428 $context[$lvl] = $self;
429 # print STDERR "HERE " . ref($self) . "\n";
431 local $SIG{__DIE__
} = sub {
433 $args[-1] =~ s/ at .*? line .*?\n$//s if $args[-1] =~ /\n$/s;
434 die Carp
::longmess
(@args);
438 my $char = $self->{BEG
} // $self->{_from
} // 0;
439 my $line = 1 + (substr($::ORIG
, 0, $char) =~ y/\n/\n/);
440 say STDERR
"!!! FAILED at $char (L$line)";
444 my $val = join '', @bits;
445 my @c = map { ref $_ } @context;
448 say STDERR
' ' x
($lvl-1), "$c returns $val\n" if $OPT_log;
449 # Note that we may have skipped levels, so you can't just pop
450 splice(@context,$lvl);
451 wantarray ?
@bits : $val;
454 sub gap
{ my $self = shift;
456 my $beg = $self->{END};
457 my $end = $after->{BEG
};
458 return '' unless $beg && $end;
459 return substr($::ORIG
, $beg, $end - $beg);
462 sub base_re_quantifier
{ my $self = shift; my $x = shift; my $min = shift;
463 my $qm = $self->{quantmod
}->Str;
465 $qm ||= $::RATCHET ?
':' : '!';
467 return [ $self->{SYM
}, $qm, $x, $min ];
471 { package VAST
::Str
; our @ISA = 'VAST::Base';
472 sub emit_p5
{ my $self = shift;
473 return $self->{TEXT
};
475 sub emit_p6
{ my $self = shift;
476 return $self->{TEXT
};
480 { package VAST
::Additive
; our @ISA = 'VAST::Base';
481 sub emit_p5
{ my $self = shift;
482 my @t = $self->SUPER::emit_p5
;
483 if ($t[0] eq '*') { # *-1
490 { package VAST
::Adverb
; our @ISA = 'VAST::Base';
491 sub emit_p5
{ my $self = shift;
492 my @t = $self->SUPER::emit_p5
;
494 if ($adv eq ':delete' or $adv eq ':exists') {
496 unshift(@t, $adv . ' ');
503 { package VAST
::apostrophe
; our @ISA = 'VAST::Base';
507 { package VAST
::arglist
; our @ISA = 'VAST::Base';
511 { package VAST
::args
; our @ISA = 'VAST::Base';
515 { package VAST
::assertion
; our @ISA = 'VAST::Base';
519 { package VAST
::assertion__S_Bang
; our @ISA = 'VAST::Base';
520 sub re_ast
{ my $self = shift;
521 my $ast = $self->{assertion
} ?
$self->{assertion
}->re_ast
524 RE_assertion
->new(assert
=> '!', re
=> $ast);
529 { package VAST
::assertion__S_Bra
; our @ISA = 'VAST::Base';
530 sub re_ast
{ my $self = shift;
531 my $cclass = $self->Str;
532 $cclass =~ s/\\x([0-9a-fA-F]{3,4})/\\x\{$1\}/g;
533 RE_cclass
->new(text
=> $cclass);
537 { package VAST
::assertion__S_Minus
; our @ISA = 'VAST::assertion__S_Bra';
540 { package VAST
::assertion__S_Plus
; our @ISA = 'VAST::assertion__S_Bra';
544 { package VAST
::assertion__S_Cur_Ly
; our @ISA = 'VAST::Base';
545 sub re_ast
{ my $self = shift;
546 local $::NEEDMATCH
= 0;
547 my $text = $self->{embeddedblock
}{statementlist
}->p5;
548 $text = "my \$M = \$C;\n" . $text if $::NEEDMATCH
;
549 RE_block
->new(body
=> $text, context
=> 'bool');
554 { package VAST
::assertion__S_DotDotDot
; our @ISA = 'VAST::Base';
558 { package VAST
::assertion__S_method
; our @ISA = 'VAST::Base';
559 sub re_ast
{ my $self = shift;
560 my $ast = $self->{assertion
}->re_ast;
567 { package VAST
::assertion__S_name
; our @ISA = 'VAST::Base';
568 sub re_ast
{ my $self = shift;
569 my $name = $self->{longname
}->Str;
571 if ($self->{nibbler
}[0]) {
572 return RE_method_re
->new(name
=> $name,
573 re
=> $self->{nibbler
}[0]{"."}->re_ast);
576 if ($self->{assertion
}[0]) {
577 return RE_bindnamed
->new(var
=> $name,
578 atom
=> $self->{assertion
}[0]->re_ast);
581 if ($name eq 'sym' && defined $::ENDSYM
) {
582 return RE_sequence
->new(
583 RE_method
->new(name
=> $name, sym
=> $::SYM
),
584 RE_method
->new(name
=> $::ENDSYM
, nobind
=> 1));
587 my $al = $self->{arglist
}[0];
588 local $::NEEDMATCH
= 0;
589 $al = defined $al ?
"(" . $al->p5 . ")" : undef;
590 RE_method
->new(name
=> $name, ($name eq 'sym' ?
(sym
=> $::SYM
) : ()),
591 rest
=> $al, need_match
=> $::NEEDMATCH
);
596 { package VAST
::assertion__S_Question
; our @ISA = 'VAST::Base';
597 sub re_ast
{ my $self = shift;
598 my $ast = $self->{assertion
} ?
$self->{assertion
}->re_ast
601 RE_assertion
->new(assert
=> '?', re
=> $ast);
606 { package VAST
::atom
; our @ISA = 'VAST::Base';
607 sub re_ast
{ my $self = shift;
608 if (exists $self->{TEXT
}) {
609 RE_string
->new(text
=> $self->{TEXT
});
611 $self->{metachar
}->re_ast;
617 { package VAST
::Autoincrement
; our @ISA = 'VAST::Base';
621 { package VAST
::babble
; our @ISA = 'VAST::Base';
625 { package VAST
::backslash
; our @ISA = 'VAST::Base';
629 { package VAST
::backslash__S_Back
; our @ISA = 'VAST::Base';
633 { package VAST
::backslash__S_d
; our @ISA = 'VAST::Base';
637 { package VAST
::backslash__S_h
; our @ISA = 'VAST::Base';
641 { package VAST
::backslash__S_misc
; our @ISA = 'VAST::Base';
645 { package VAST
::backslash__S_n
; our @ISA = 'VAST::Base';
649 { package VAST
::backslash__S_s
; our @ISA = 'VAST::Base';
653 { package VAST
::backslash__S_stopper
; our @ISA = 'VAST::Base';
657 { package VAST
::backslash__S_t
; our @ISA = 'VAST::Base';
661 { package VAST
::backslash__S_v
; our @ISA = 'VAST::Base';
665 { package VAST
::backslash__S_w
; our @ISA = 'VAST::Base';
669 { package VAST
::backslash__S_x
; our @ISA = 'VAST::Base';
673 { package VAST
::before
; our @ISA = 'VAST::Base';
677 { package VAST
::block
; our @ISA = 'VAST::Base';
681 { package VAST
::blockoid
; our @ISA = 'VAST::Base';
682 sub emit_p5
{ my $self = shift;
683 "{\n" . ::indent
(scalar($self->{statementlist
}->p5), 1) . "}";
688 { package VAST
::capterm
; our @ISA = 'VAST::Base';
692 { package VAST
::cclass_elem
; our @ISA = 'VAST::Base';
696 { package VAST
::Chaining
; our @ISA = 'VAST::Base';
700 { package VAST
::circumfix
; our @ISA = 'VAST::Base';
704 { package VAST
::circumfix__S_Bra_Ket
; our @ISA = 'VAST::Base';
708 { package VAST
::circumfix__S_Cur_Ly
; our @ISA = 'VAST::Base';
712 { package VAST
::circumfix__S_Paren_Thesis
; our @ISA = 'VAST::Base';
716 { package VAST
::circumfix__S_sigil
; our @ISA = 'VAST::Base';
720 { package VAST
::codeblock
; our @ISA = 'VAST::Base';
724 { package VAST
::colonpair
; our @ISA = 'VAST::Base';
725 sub adverbs
{ my $self = shift;
727 if (Scalar
::Util
::blessed
$self->{v
} &&
728 $self->{v
}->isa('VAST::coloncircumfix')) {
729 my $s = $self->{v
}->Str;
730 my $val = $s =~ /^<(.*)>$/ ?
::unsingle
($1) :
731 $s =~ /^«(.*)»$/ ?
::undouble
($1) :
732 $s =~ /^\['(.*)'\]$/ ?
::unsingle
($1) :
733 die "Unparsable coloncircumfix";
734 return $self->{k
} => $val;
735 } elsif ($self->{v
} == 1) {
736 return "sym" => $self->{k
};
738 die "Unsupported compile-time adverb " . $self->Str;
744 { package VAST
::Comma
; our @ISA = 'VAST::Base';
749 { package VAST
::comp_unit
; our @ISA = 'VAST::Base';
750 sub emit_p5
{ my $self = shift;
751 "use 5.010;\nuse utf8;\n" . $self->{statementlist
}->p5, "\n";
753 sub emit_p6
{ my $self = shift;
754 substr($::ORIG
, 0, $self->{statementlist
}{BEG
}),
755 $self->{statementlist
}->p5;
760 { package VAST
::Concatenation
; our @ISA = 'VAST::Base';
764 { package VAST
::Conditional
; our @ISA = 'VAST::Base';
765 sub emit_p5
{ my $self = shift;
766 my @t = $self->SUPER::emit_p5
;
776 { package VAST
::CORE
; our @ISA = 'VAST::Base';
780 { package VAST
::declarator
; our @ISA = 'VAST::Base';
781 sub emit_p5
{ my $self = shift;
782 if ($self->{signature
}) {
783 return "(" . join(", ", map { $_->{param_var
}->Str }
784 $self->{signature
}->kids('parameter')) . ")";
786 return $self->SUPER::emit_p5
;
792 { package VAST
::default_value
; our @ISA = 'VAST::Base';
796 { package VAST
::deflongname
; our @ISA = 'VAST::Base';
797 sub adverbs
{ my $self = shift;
798 map { $_->adverbs } $self->kids('colonpair');
803 { package VAST
::def_module_name
; our @ISA = 'VAST::Base';
807 { package VAST
::desigilname
; our @ISA = 'VAST::Base';
811 { package VAST
::dotty
; our @ISA = 'VAST::Base';
815 { package VAST
::dotty__S_Dot
; our @ISA = 'VAST::Methodcall';
819 { package VAST
::SYM_dotty__S_Dot
; our @ISA = 'VAST::Base';
823 { package VAST
::dottyop
; our @ISA = 'VAST::Base';
827 { package VAST
::eat_terminator
; our @ISA = 'VAST::Base';
831 { package VAST
::escape
; our @ISA = 'VAST::Base';
835 { package VAST
::escape__S_At
; our @ISA = 'VAST::Base';
839 { package VAST
::escape__S_Back
; our @ISA = 'VAST::Base';
843 { package VAST
::escape__S_Dollar
; our @ISA = 'VAST::Base';
847 { package VAST
::EXPR
; our @ISA = 'VAST::Base';
851 { package VAST
::fatarrow
; our @ISA = 'VAST::Base';
855 { package VAST
::fulltypename
; our @ISA = 'VAST::Base';
859 { package VAST
::hexint
; our @ISA = 'VAST::Base';
863 { package VAST
::ident
; our @ISA = 'VAST::Base';
867 { package VAST
::identifier
; our @ISA = 'VAST::Base';
871 { package VAST
::index; our @ISA = 'VAST::Base';
876 { package VAST
::infix
; our @ISA = 'VAST::Base';
879 { package VAST
::infix_prefix_meta_operator__S_Bang
; our @ISA = 'VAST::Base';
880 sub emit_p5
{ my $self = shift;
881 my @t = $self->SUPER::emit_p5
;
882 $t[1] = '~' if $t[1] eq '=~';
883 $t[1] = '=' if $t[1] eq '==';
884 @t = ('ne', '') if $t[1] eq 'eq';
889 { package VAST
::SYM_infix__S_ColonEqual
; our @ISA = 'VAST::Item_assignment';
890 sub emit_p5
{ my $self = shift;
891 my @t = $self->SUPER::emit_p5
;
892 $t[0] = '='; # XXX oversimplified
897 { package VAST
::SYM_infix__S_ColonColonEqual
; our @ISA = 'VAST::Item_assignment';
898 sub emit_p5
{ my $self = shift;
899 my @t = $self->SUPER::emit_p5
;
900 $t[0] = '='; # XXX oversimplified
906 { package VAST
::infixish
; our @ISA = 'VAST::Base';
910 { package VAST
::SYM_infix__S_PlusAmp
; our @ISA = 'VAST::Multiplicative';
911 sub emit_p5
{ my $self = shift;
912 my @t = $self->SUPER::emit_p5
;
918 { package VAST
::SYM_infix__S_eqv
; our @ISA = 'VAST::Chaining';
919 sub emit_p5
{ my $self = shift;
920 my @t = $self->SUPER::emit_p5
;
926 { package VAST
::SYM_infix__S_leg
; our @ISA = 'VAST::Structural_infix';
927 sub emit_p5
{ my $self = shift;
928 my @t = $self->SUPER::emit_p5
;
934 { package VAST
::SYM_infix__S_EqualEqualEqual
; our @ISA = 'VAST::Chaining';
935 sub emit_p5
{ my $self = shift;
936 my @t = $self->SUPER::emit_p5
;
937 $t[0] = '=='; # only correct for objects (and ints)
942 { package VAST
::SYM_infix__S_orelse
; our @ISA = 'VAST::Loose_or';
943 sub emit_p5
{ my $self = shift;
944 my @t = $self->SUPER::emit_p5
;
950 { package VAST
::SYM_infix__S_andthen
; our @ISA = 'VAST::Loose_and';
951 sub emit_p5
{ my $self = shift;
952 my @t = $self->SUPER::emit_p5
;
958 { package VAST
::SYM_infix__S_PlusVert
; our @ISA = 'VAST::Additive';
959 sub emit_p5
{ my $self = shift;
960 my @t = $self->SUPER::emit_p5
;
967 { package VAST
::SYM_infix__S_Tilde
; our @ISA = 'VAST::Concatenation';
968 sub emit_p5
{ my $self = shift;
969 my @t = $self->SUPER::emit_p5
;
976 { package VAST
::SYM_infix__S_TildeTilde
; our @ISA = 'VAST::Chaining';
977 sub emit_p5
{ my $self = shift;
978 my @t = $self->SUPER::emit_p5
;
984 { package VAST
::SYM_infix__S_TildeVert
; our @ISA = 'VAST::Additive';
985 sub emit_p5
{ my $self = shift;
986 my @t = $self->SUPER::emit_p5
;
993 { package VAST
::integer
; our @ISA = 'VAST::Base';
997 { package VAST
::Item_assignment
; our @ISA = 'VAST::Base';
1001 { package VAST
::Junctive_or
; our @ISA = 'VAST::Base';
1005 { package VAST
::label
; our @ISA = 'VAST::Base';
1009 { package VAST
::lambda
; our @ISA = 'VAST::Base';
1010 sub emit_p5
{ my $self = shift;
1011 my @t = $self->SUPER::emit_p5
;
1018 { package VAST
::left
; our @ISA = 'VAST::Base';
1022 { package VAST
::List_assignment
; our @ISA = 'VAST::Base';
1026 { package VAST
::litchar
; our @ISA = 'VAST::Base';
1030 { package VAST
::longname
; our @ISA = 'VAST::Base';
1031 sub adverbs
{ my $self = shift;
1032 map { $_->adverbs } $self->kids('colonpair');
1037 { package VAST
::Loose_and
; our @ISA = 'VAST::Base';
1041 { package VAST
::Loose_or
; our @ISA = 'VAST::Base';
1045 { package VAST
::Loose_unary
; our @ISA = 'VAST::Base';
1049 { package VAST
::metachar
; our @ISA = 'VAST::Base';
1050 sub re_ast
{ my $self = shift;
1051 RE_meta
->new(text
=> $self->Str);
1056 { package VAST
::metachar__S_Back
; our @ISA = 'VAST::metachar';
1057 sub re_ast
{ my $self = shift;
1058 RE_meta
->new(text
=> $self->Str, min
=> 1);
1063 { package VAST
::metachar__S_Bra_Ket
; our @ISA = 'VAST::Base';
1064 sub re_ast
{ my $self = shift;
1065 local $::DBA
= $::DBA
;
1066 local $::RATCHET
= $::RATCHET
;
1067 local $::SIGSPACE
= $::SIGSPACE
;
1068 local $::IGNORECASE
= $::IGNORECASE
;
1071 my $bodyast = $self->{nibbler
}{"."}->re_ast;
1072 RE_bracket
->new(decl
=> \@
::DECLAST
, re
=> $bodyast);
1077 { package VAST
::metachar__S_Caret
; our @ISA = 'VAST::metachar';
1081 { package VAST
::metachar__S_CaretCaret
; our @ISA = 'VAST::metachar';
1084 { package VAST
::metachar__S_ColonColon
; our @ISA = 'VAST::metachar';
1087 { package VAST
::metachar__S_ColonColonColon
; our @ISA = 'VAST::metachar';
1090 { package VAST
::metachar__S_ColonColonKet
; our @ISA = 'VAST::metachar';
1094 { package VAST
::metachar__S_Cur_Ly
; our @ISA = 'VAST::Base';
1095 sub re_ast
{ my $self = shift;
1096 local $::NEEDMATCH
= 0;
1097 my $text = $self->{embeddedblock
}{statementlist
}->p5;
1098 $text = "my \$M = \$C;\n" . $text if $::NEEDMATCH
;
1099 RE_block
->new(body
=> $text, context
=> 'void');
1104 { package VAST
::metachar__S_Dollar
; our @ISA = 'VAST::metachar';
1108 { package VAST
::metachar__S_DollarDollar
; our @ISA = 'VAST::metachar';
1112 { package VAST
::metachar__S_Dot
; our @ISA = 'VAST::metachar';
1113 sub re_ast
{ my $self = shift;
1114 RE_meta
->new(text
=> $self->Str, min
=> 1);
1119 { package VAST
::metachar__S_Double_Double
; our @ISA = 'VAST::Base';
1120 sub re_ast
{ my $self = shift;
1121 my $text = ::undouble
($self->{quote
}{nibble
}->Str);
1122 RE_double
->new(text
=> $text);
1127 { package VAST
::metachar__S_Lt_Gt
; our @ISA = 'VAST::Base';
1128 sub re_ast
{ my $self = shift;
1129 $self->{assertion
}->re_ast;
1134 { package VAST
::metachar__S_mod
; our @ISA = 'VAST::Base';
1135 sub re_ast
{ my $self = shift;
1136 $self->{mod_internal
}->re_ast;
1141 { package VAST
::metachar__S_Nch
; our @ISA = 'VAST::metachar';
1145 { package VAST
::metachar__S_Paren_Thesis
; our @ISA = 'VAST::Base';
1146 sub re_ast
{ my $self = shift;
1147 local $::DBA
= $::DBA
;
1148 local $::RATCHET
= $::RATCHET
;
1149 local $::SIGSPACE
= $::SIGSPACE
;
1150 local $::IGNORECASE
= $::IGNORECASE
;
1153 my $bodyast = $self->{nibbler
}{"."}->re_ast;
1154 RE_bindpos
->new(var
=> $::PAREN
++,
1155 atom
=> RE_paren
->new(decl
=> \@
::DECLAST
, re
=> $bodyast));
1160 { package VAST
::metachar__S_qw
; our @ISA = 'VAST::Base';
1161 sub re_ast
{ my $self = shift;
1163 my @elems = split(' ', $self->{circumfix
}{nibble
}->Str);
1165 my $l = ::min
(1_000_000_000
, map { length } @elems);
1166 RE_qw
->new(min
=> $l, text
=> $self->Str);
1171 { package VAST
::metachar__S_sigwhite
; our @ISA = 'VAST::Base';
1172 sub re_ast
{ my $self = shift;
1173 RE_method
->new(name
=> 'ws', nobind
=> 1);
1178 { package VAST
::metachar__S_Single_Single
; our @ISA = 'VAST::Base';
1179 sub re_ast
{ my $self = shift;
1180 my $text = ::unsingle
($self->{quote
}{nibble
}->Str);
1181 RE_string
->new(text
=> $text);
1186 { package VAST
::metachar__S_var
; our @ISA = 'VAST::Base';
1187 sub re_ast
{ my $self = shift;
1188 # We don't un6 because some things need to un6 specially - backrefs
1189 if ($self->{binding
}) {
1190 $self->{SYM
} =~ /^\$<(.*)>$/ or die "Can't bind backref to " . $self->{SYM
};
1191 RE_bindnamed
->new(var
=> $1, atom
=>
1192 $self->{binding
}{quantified_atom
}->re_ast);
1194 RE_var
->new(var
=> $self->{termish
}->p5);
1200 { package VAST
::Methodcall
; our @ISA = 'VAST::Base';
1201 sub emit_p5
{ my $self = shift;
1202 my @t = $self->SUPER::emit_p5
;
1204 my $first = shift @t;
1205 my $second = join '', @t;
1206 @t = ($first,$second);
1208 if ($t[1] eq '.pos') { $t[1] = '.<_pos>'; }
1209 $t[1] =~ s/^(\.?)<(.*)>$/$1\{'$2'\}/;
1210 if ($t[0] =~ /^[@%]/) {
1211 if ($t[1] =~ s/^\.?([[{])/$1/) {
1213 substr($t[0],0,1) = '@';
1216 substr($t[0],0,1) = '$';
1221 elsif ($t[1] =~ /^[[{]/) {
1222 $t[1] =~ s/^([[{])/.$1/;
1224 elsif ($t[0] =~ s/^&(\w+)/\$$1/) {
1225 $t[1] =~ s/^\(/->(/;
1228 my $t = join('', @t);
1229 $t =~ s/^(.*\S)\s*:(delete|exists)/$2 $1/;
1230 # print STDERR ::Dump(\@t);
1236 { package VAST
::method_def
; our @ISA = 'VAST::Base';
1237 sub emit_p5
{ my $self = shift;
1238 my $name = $self->{longname
} ?
$self->{longname
}->p5 . " " : "";
1239 my $sig = $self->{multisig
}[0] ?
$self->{multisig
}[0]->p5 : "";
1240 my $body = $self->{blockoid
}{statementlist
}->p5;
1242 if ($::MULTINESS
eq 'multi') {
1243 $::MULTIMETHODS
{$name} .= <<EOT
1249 . ::indent
($sig . $body, 2) . <<EOT
1257 # not quite right, this should be an expression
1258 "sub " . $name . "{\n" .
1259 ::indent
("no warnings 'recursion';\nmy \$self = shift;\n" .
1266 { package VAST
::methodop
; our @ISA = 'VAST::Base';
1270 { package VAST
::modifier_expr
; our @ISA = 'VAST::Base';
1274 { package VAST
::mod_internal
; our @ISA = 'VAST::Base';
1278 { package VAST
::mod_internal__S_p6adv
; our @ISA = 'VAST::Base';
1279 sub re_ast
{ my $self = shift;
1280 my $key = $self->{quotepair
}{k
};
1282 if ($key eq 'dba') {
1283 $::DBA
= eval ($self->{quotepair
}{circumfix
}[0]->Str);
1284 } elsif ($key eq 'lang') {
1285 my $lang = $self->{quotepair
}{circumfix
}[0]->p5;
1286 return RE_decl
->new(body
=> <<BODY);
1287 my \$newlang = $lang;
1288 \$C = bless(\$C, (ref(\$newlang) || \$newlang));
1291 die "unhandled internal adverb $key";
1299 { package VAST
::mod_internal__S_ColonBangs
; our @ISA = 'VAST::Base';
1303 { package VAST
::mod_internal__S_Coloni
; our @ISA = 'VAST::Base';
1304 sub re_ast
{ my $self = shift;
1310 { package VAST
::mod_internal__S_Colonr
; our @ISA = 'VAST::Base';
1311 sub re_ast
{ my $self = shift;
1318 { package VAST
::mod_internal__S_Colonmy
; our @ISA = 'VAST::Base';
1319 sub re_ast
{ my $self = shift;
1320 local $::NEEDMATCH
= 0;
1321 my $text = $self->{statement
}->p5;
1322 $text = 'my $M = $C; ' . $text if $::NEEDMATCH
;
1324 push @
::DECLAST
, RE_decl
->new(body
=> $text);
1330 { package VAST
::mod_internal__S_Colons
; our @ISA = 'VAST::Base';
1331 # note that most of this is handled in the parser
1332 sub re_ast
{ my $self = shift;
1339 { package VAST
::mod_internal__S_ColonBangs
; our @ISA = 'VAST::Base';
1340 # note that most of this is handled in the parser
1341 sub re_ast
{ my $self = shift;
1348 { package VAST
::module_name
; our @ISA = 'VAST::Base';
1352 { package VAST
::module_name__S_normal
; our @ISA = 'VAST::Base';
1356 { package VAST
::morename
; our @ISA = 'VAST::Base';
1360 { package VAST
::multi_declarator
; our @ISA = 'VAST::Base';
1364 { package VAST
::multi_declarator__S_multi
; our @ISA = 'VAST::Base';
1365 sub emit_p5
{ my $self = shift;
1366 local $::MULTINESS
= 'multi';
1372 { package VAST
::multi_declarator__S_null
; our @ISA = 'VAST::Base';
1376 { package VAST
::multi_declarator__S_proto
; our @ISA = 'VAST::Base';
1377 sub emit_p5
{ my $self = shift;
1378 local $::MULTINESS
= 'proto';
1384 { package VAST
::Multiplicative
; our @ISA = 'VAST::Base';
1387 # We don't currently do MMD so no need for later sigs
1388 { package VAST
::multisig
; our @ISA = 'VAST::Base';
1389 sub emit_p5
{ my $self = shift;
1390 $self->{signature
}[0]->p5;
1395 { package VAST
::name
; our @ISA = 'VAST::Base';
1399 { package VAST
::named_param
; our @ISA = 'VAST::Base';
1403 { package VAST
::Named_unary
; our @ISA = 'VAST::Base';
1406 { package VAST
::nibbler
; our @ISA = 'VAST::Base';
1410 { package VAST
::nofun
; our @ISA = 'VAST::Base';
1414 { package VAST
::normspace
; our @ISA = 'VAST::Base';
1419 { package VAST
::nulltermish
; our @ISA = 'VAST::Base';
1423 { package VAST
::number
; our @ISA = 'VAST::Base';
1427 { package VAST
::number__S_numish
; our @ISA = 'VAST::Base';
1431 { package VAST
::numish
; our @ISA = 'VAST::Base';
1435 { package VAST
::opener
; our @ISA = 'VAST::Base';
1439 { package VAST
::package_declarator
; our @ISA = 'VAST::Base';
1443 { package VAST
::package_declarator__S_class
; our @ISA = 'VAST::package_declarator';
1444 sub emit_p5
{ my $self = shift;
1445 local $::PKGDECL
= 'class';
1446 $self->{package_def
}->p5;
1451 { package VAST
::package_declarator__S_grammar
; our @ISA = 'VAST::package_declarator';
1452 sub emit_p5
{ my $self = shift;
1453 local $::PKGDECL
= 'grammar';
1454 $self->{package_def
}->p5;
1459 { package VAST
::package_declarator__S_role
; our @ISA = 'VAST::package_declarator';
1460 sub emit_p5
{ my $self = shift;
1461 local $::PKGDECL
= 'role';
1462 $self->{package_def
}->p5;
1466 { package VAST
::package_declarator__S_knowhow
; our @ISA = 'VAST::package_declarator';
1467 sub emit_p5
{ my $self = shift;
1468 local $::PKGDECL
= 'knowhow';
1469 $self->{package_def
}->p5;
1474 { package VAST
::package_def
; our @ISA = 'VAST::Base';
1475 sub p5_module_name
{ my $self = shift;
1476 my $def_module_name = $self->{longname
}[0]{name
}->Str;
1477 if ($self->{decl
}{inpkg
}[0] =~ /GLOBAL::(.*)/) {
1478 $::OUR
{$def_module_name} = "$1::$def_module_name";
1479 $def_module_name = "$1::$def_module_name";
1483 sub emit_p5_header
{ my $self = shift;
1488 for (@
{$self->{trait
}}) {
1490 push(@extends, $t =~ /^is\s+(\S+)/);
1491 push(@does, $t =~ /^does\s+(\S+)/);
1493 @extends = 'Cursor' if $::PKGDECL
eq 'grammar' && !@extends;
1495 my $meta = $::PKGDECL
eq 'role' ?
'Moose::Role' : 'Moose';
1498 use $meta ':all' => { -prefix => "moose_" };
1499 use Cursor; # for DEBUG::, etc
1502 $header .= <<"END" for @extends;
1503 moose_extends('$_');
1506 $header .= <<"END" for @does;
1512 no warnings 'qw', 'recursion';
1515 \$DB::deep = \$DB::deep = 1000; # suppress used-once warning
1519 \$SIG{__WARN__} = sub { die \@_," statement started at line ", 'STD'->lineof(\$::LASTSTATE), "\n" } if \$::DEBUG;
1525 sub emit_p5
{ my $self = shift;
1526 my $block = $self->{blockoid
}{statementlist
} // $self->{statementlist
};
1527 local $::RETREE
= {};
1528 local $::PROTO
= {};
1529 local $::PROTOSIG
= {};
1530 local $::PKG
= $self->p5_module_name;
1531 local $::MULTIRX_SEQUENCE
= 0;
1532 local %::MULTIMETHODS
;
1533 my $body1 = $self->emit_p5_header;
1534 my $body3 = $block->p5;
1538 $body2 = "\$retree = YAML::XS::Load(Encode::encode_utf8(<<'RETREE_END'));\n" .
1539 Encode
::decode_utf8
(::Dump
($::RETREE
)) . "RETREE_END\n";
1541 my $body = $body1 . $body2 . $body3;
1544 if (my ($sig) = $self->kids('signature')) {
1545 my @parm = map { $_->Str } $sig->kids('parameter');
1546 my $plist = join ", ", @parm;
1548 $body = <<EOT . $body;
1550 require "mangle.pl";
1552 sub __instantiate__ { my \$self = shift;
1554 my \$mangle = ::mangle($plist);
1555 my \$mixin = "${name}::" . \$mangle;
1556 return \$mixin if \$INSTANTIATED{\$mixin}++;
1557 ::deb(" instantiating \$mixin") if \$::DEBUG & DEBUG::mixins;
1558 my \$eval = "package \$mixin" . q{;
1567 $body = "package $name;\n" . $body;
1570 my $finalmulti = '';
1572 for my $mm (sort keys %::MULTIMETHODS
) {
1573 $finalmulti .= "moose_around $mm => sub {\n my \$orig = shift;\n no warnings 'recursion';\n" .
1574 ::indent
($::MULTIMETHODS
{$mm}, 1) . <<EOFINAL
1582 "{ $body $finalmulti 1; }";
1586 # Perl5 invocations don't carry enough context for a proper binder; in
1587 # particular we can't distinguish named stuff from positionals
1588 { package VAST
::parameter
; our @ISA = 'VAST::Base';
1589 sub emit_p5
{ my $self = shift;
1590 my $pvar = $self->{param_var
};
1594 my $np = $self->{named_param
};
1596 $pvar = $np->{param_var
};
1597 push @names, $np->{name
} ?
$np->{name
}{TEXT
}
1598 : $np->{param_var
}{name
}[0]{TEXT
};
1599 $np = $np->{named_param
};
1601 $posit = 1 unless @names;
1602 my $pname = $pvar->{name
}[0]{TEXT
};
1603 my $sigil = $pvar->{sigil
}{SYM
};
1604 my $twigil = $pvar->{twigil
}[0] ?
$pvar->{twigil
}[0]{SYM
} : '';
1605 my ($dv) = $self->kids('default_value');
1609 if (($self->{quant
} eq '!' || $self->{quant
} eq '' && $posit) && !$dv) {
1610 # XXX STD/gimme5 doesn't use ? correctly; will be fixed after
1612 $check .= $::MULTINESS
eq 'multi' ?
"last " :
1613 "1"; #"die 'Required argument $pname omitted' ";
1614 $check .= $posit ?
'unless @_'
1615 : 'unless ' . join(" || ", map ("exists \$args{$_}", @names));
1620 my $value = "undef";
1622 $value = $dv->{"."}->p5;
1625 $value = '@_ ? shift() : ' . $value;
1627 for (reverse @names) {
1628 $value = "exists \$args{$_} ? delete \$args{$_} : $value";
1630 if ($self->{quant
} eq '*') {
1631 $value = ($sigil eq '%') ?
'%args' : '@_';
1632 $posit = 0 if $sigil eq '%';
1635 # Store it somewhere useful
1636 if ($twigil eq '*' && $pname eq 'endsym') {
1637 # XXX this optimization needs to be refactored, I think
1638 my ($dv) = $self->kids('default_value');
1639 $::ENDSYM
= $dv->{"."}->Str;
1640 $::ENDSYM
= substr($::ENDSYM
, 1, length($::ENDSYM
)-2);
1645 if ($twigil eq '*') {
1646 $assn = "local ${sigil}::${pname} = $value";
1648 $assn = "my ${sigil}${pname} = $value";
1651 (!$posit), ($check . $assn);
1656 { package VAST
::param_sep
; our @ISA = 'VAST::Base';
1660 { package VAST
::param_var
; our @ISA = 'VAST::Base';
1664 { package VAST
::pblock
; our @ISA = 'VAST::Base';
1668 { package VAST
::pod_comment
; our @ISA = 'VAST::Base';
1672 { package VAST
::POST
; our @ISA = 'VAST::Base';
1676 { package VAST
::postcircumfix
; our @ISA = 'VAST::Base';
1680 { package VAST
::SYM_postcircumfix__S_Lt_Gt
; our @ISA = 'VAST::Base';
1681 sub emit_p5
{ my $self = shift;
1682 my @t = $self->SUPER::emit_p5
;
1690 { package VAST
::postfix
; our @ISA = 'VAST::Base';
1694 { package VAST
::postop
; our @ISA = 'VAST::Base';
1698 { package VAST
::PRE
; our @ISA = 'VAST::Base';
1702 { package VAST
::prefix
; our @ISA = 'VAST::Base';
1706 { package VAST
::SYM_prefix__S_Plus
; our @ISA = 'VAST::Symbolic_unary';
1707 sub emit_p5
{ my $self = shift;
1708 my @t = $self->SUPER::emit_p5
;
1714 { package VAST
::SYM_prefix__S_Vert
; our @ISA = 'VAST::Symbolic_unary';
1715 sub emit_p5
{ my $self = shift;
1721 { package VAST
::prefix__S_temp
; our @ISA = 'VAST::Base';
1722 sub emit_p5
{ my $self = shift;
1723 my $arg = $self->{arg
}->p5;
1724 "local $arg = $arg";
1729 { package VAST
::quantified_atom
; our @ISA = 'VAST::Base';
1730 sub re_ast
{ my $self = shift;
1731 if (!@
{$self->{quantifier
}}) {
1732 return $self->{atom
}->re_ast;
1735 if ($self->{quantifier
}[0]{SYM
} eq ':') {
1736 my $ast = $self->{atom
}->re_ast;
1741 my $quant = $self->{quantifier
}[0]->re_quantifier;
1743 my $ast = $self->{atom
}->re_ast;
1745 RE_quantified_atom
->new(atom
=> $ast, quant
=> $quant);
1749 { package VAST
::quant_atom_list
; our @ISA = 'VAST::Base';
1750 sub re_ast
{ my $self = shift;
1751 my @kids = map { $_->re_ast } $self->kids("quantified_atom");
1752 # XXX STD work around misparsing of whitespace near quantifiers
1753 for my $i (0 .. @kids - 2) {
1754 if ($kids[$i+1]->isa('RE_quantified_atom')
1755 && $kids[$i+1]{atom
}->isa('RE_method')
1756 && $kids[$i+1]{atom
}{name
} eq 'ws') {
1757 $kids[$i+1]{atom
} = $kids[$i];
1758 $kids[$i] = RE_noop
->new;
1761 RE_sequence
->new(@kids);
1766 { package VAST
::quantifier
; our @ISA = 'VAST::Base';
1770 { package VAST
::quantifier__S_Plus
; our @ISA = 'VAST::Base';
1771 sub re_quantifier
{ my $self = shift;
1772 $self->base_re_quantifier("", 1);
1777 { package VAST
::quantifier__S_Question
; our @ISA = 'VAST::Base';
1778 sub re_quantifier
{ my $self = shift;
1779 $self->base_re_quantifier("", 0);
1784 { package VAST
::quantifier__S_Star
; our @ISA = 'VAST::Base';
1785 sub re_quantifier
{ my $self = shift;
1786 $self->base_re_quantifier("", 0);
1791 { package VAST
::quantifier__S_StarStar
; our @ISA = 'VAST::Base';
1792 sub re_quantifier
{ my $self = shift;
1793 my ($range) = $self->Str =~ /.*(\d+\.\.\d+)$/;
1794 $self->base_re_quantifier($self->{embeddedblock
} //
1795 $range // $self->{quantified_atom
}->re_ast, 1);
1800 { package VAST
::quantmod
; our @ISA = 'VAST::Base';
1804 { package VAST
::quibble
; our @ISA = 'VAST::Base';
1809 { package VAST
::quote
; our @ISA = 'VAST::Base';
1810 sub emit_p5
{ my $self = shift;
1811 my @t = $self->SUPER::emit_p5
;
1813 # print STDERR ::Dump(\@t);
1818 { package VAST
::quote__S_Double_Double
; our @ISA = 'VAST::Base';
1822 { package VAST
::circumfix__S_Fre_Nch
; our @ISA = 'VAST::Base';
1823 sub emit_p5
{ my $self = shift;
1824 'split(/ /, "' . $self->{nibble
}->p5 . '", -1)'
1829 { package VAST
::quote__S_Lt_Gt
; our @ISA = 'VAST::Base';
1833 { package VAST
::quotepair
; our @ISA = 'VAST::Base';
1837 { package VAST
::quote__S_s
; our @ISA = 'VAST::Base';
1841 { package VAST
::quote__S_Single_Single
; our @ISA = 'VAST::Base';
1845 { package VAST
::quote__S_Slash_Slash
; our @ISA = 'VAST::Base';
1849 { package VAST
::regex_block
; our @ISA = 'VAST::Base';
1853 { package VAST
::regex_declarator
; our @ISA = 'VAST::Base';
1857 { package VAST
::regex_declarator__S_regex
; our @ISA = 'VAST::Base';
1858 sub emit_p5
{ my $self = shift;
1859 local $::RATCHET
= 0;
1860 local $::SIGSPACE
= 0;
1861 local $::REGEX_DECLARATOR
= 'regex';
1862 my $comment = substr($::ORIG
, $self->{BEG
},100);
1863 $comment =~ s/\n.*//s;
1864 "## $comment\n" . $self->{regex_def
}->p5;
1869 { package VAST
::regex_declarator__S_rule
; our @ISA = 'VAST::Base';
1870 sub emit_p5
{ my $self = shift;
1871 local $::RATCHET
= 1;
1872 local $::SIGSPACE
= 1;
1873 local $::REGEX_DECLARATOR
= 'rule';
1874 my $comment = substr($::ORIG
, $self->{BEG
},100);
1875 $comment =~ s/\n.*//s;
1876 "## $comment\n" . $self->{regex_def
}->p5;
1881 { package VAST
::regex_declarator__S_token
; our @ISA = 'VAST::Base';
1882 sub emit_p5
{ my $self = shift;
1883 local $::RATCHET
= 1;
1884 local $::SIGSPACE
= 0;
1885 local $::REGEX_DECLARATOR
= 'token';
1886 my $comment = substr($::ORIG
, $self->{BEG
}, 100);
1887 $comment =~ s/\n.*//s;
1888 "## $comment\n" . $self->{regex_def
}->p5;
1892 { package VAST
::regex_def
; our @ISA = 'VAST::Base';
1893 sub re_ast
{ my $self = shift;
1894 RE_ast
->new(kind
=> $::REGEX_DECLARATOR
, decl
=> \@
::DECLAST
,
1895 re
=> $self->{regex_block
}{nibble
}{"."}->re_ast);
1897 sub protoregex
{ my $self = shift; my $name = shift;
1898 $::PROTO
->{$name} = 1;
1899 $::PROTOSIG
->{$name} = ($self->kids("signature"))[0];
1901 sub ${name}__PEEK { \$_[0]->_AUTOLEXpeek('$name:*',\$retree); }
1906 local \$::CTX = \$self->callm() if \$::DEBUG & DEBUG::trace_call;
1908 my \$C = \$self->cursor_xact('RULE $name');
1909 my \$S = \$C->{'_pos'};
1916 if (my \$fate = \$C->{'_fate'}) {
1917 if (\$fate->[1] eq '$name') {
1918 \$C->deb("Fate passed to $name: ", ::fatestr(\$fate)) if \$::DEBUG & DEBUG::fates;
1919 (\$C->{'_fate'}, \$tag, \$try) = \@\$fate;
1924 \$x = 'ALTLTM $name';
1928 \$x = 'ALTLTM $name';
1930 my \$C = \$C->cursor_xact(\$x);
1931 my \$xact = \$C->{_xact};
1936 \$relex //= \$C->cursor_fate('$::PKG', '$name:*', \$retree);
1937 \@try = \$relex->(\$C) or last;
1939 \$try = shift(\@try) // next;
1942 (\$C->{'_fate'}, \$tag, \$try) = \@\$try; # next candidate fate
1945 \$C->deb("$name trying \$tag \$try") if \$::DEBUG & DEBUG::try_processing;
1946 push \@gather, \$C->\$try(\@_);
1948 last if \$xact->[-2]; # committed?
1950 \$self->_MATCHIFYr(\$S, "$name", \@gather);
1957 sub emit_p5
{ my $self = shift;
1958 my $name = $self->{deflongname
}[0]{name
}->Str;
1959 if (defined $::MULTINESS
&& $::MULTINESS
eq 'proto') {
1960 return $self->protoregex($name);
1963 my %adv = $self->{deflongname
}[0]->adverbs;
1964 local $::SYM
= $adv{sym
};
1967 local $::PLURALITY
= 1;
1970 local $::NEEDORIGARGS
= 0;
1971 local $::IGNORECASE
= 0;
1975 my $spcsig = $self->kids('signature') ?
1976 (($self->kids('signature'))[0])->p5 : '';
1977 my $defsig = $::PROTO
&& $::PROTOSIG
->{$name}
1978 ?
$::PROTOSIG
->{$name}->p5 : '';
1979 if (defined $adv{sym
}) {
1980 $p5name = sprintf "%s__S_%03d%s", $name, $::MULTIRX_SEQUENCE
++,
1981 ::mangle
(split " ", $adv{sym
});
1983 local $::DBA
= $name;
1984 local $::NAME
= $p5name;
1986 my $ast = $self->re_ast->optimize;
1988 $::RETREE
->{$p5name} = $ast;
1990 my $urbody = $ast->walk;
1991 say STDERR
"<<< " . $urbody . ": " . $urbody->p5 if $OPT_log;
1992 my ($body, $ratchet) = $urbody->uncut;
1993 say STDERR
"<<< " . $body . ": " . $body->p5 if $OPT_log;
1994 $ast->{dba_needed
} = 1;
1998 sub ${p5name}__PEEK { \$_[0]->_AUTOLEXpeek('$p5name', \$retree) }
2000 no warnings 'recursion';
2004 . ($::NEEDORIGARGS ?
" my \@origargs = \@_;\n" : "")
2005 . ::indent
($defsig . $spcsig, 1)
2006 . ::indent
(join("", @
::DECL
), 1)
2009 local \$::CTX = \$self->callm() if \$::DEBUG & DEBUG::trace_call;
2011 my \$C = \$self->cursor_xact("RULE $p5name");
2012 my \$xact = \$C->xact;
2013 my \$S = \$C->{'_pos'};
2015 . join("", map { " \$C->{'$_'} = [];\n" }
2016 grep { $::BINDINGS
{$_} > 1 }
2017 sort keys %::BINDINGS
)
2018 . ($::SYM ?
'$C->{sym} = "' . quotemeta($::SYM
) . '";' : '')
2020 \$self->_MATCHIFY$ratchet(\$S, "$p5name", ${\ $body->p5 });
2028 { package VAST
::Replication
; our @ISA = 'VAST::Base';
2032 { package VAST
::right
; our @ISA = 'VAST::Base';
2036 { package VAST
::routine_declarator
; our @ISA = 'VAST::Base';
2040 { package VAST
::routine_declarator__S_method
; our @ISA = 'VAST::Base';
2041 sub emit_p5
{ my $self = shift;
2042 my $comment = substr($::ORIG
, $self->{BEG
},100);
2043 $comment =~ s/\s*\{.*//s;
2044 "## $comment\n" . $self->{method_def
}->p5;
2049 { package VAST
::regex_infix
; our @ISA = 'VAST::Base';
2052 # This is really a tight ternary op, but XXX STD parses it as a loose infix,
2053 # so we need to reassociate. Also, the backend handling is very "fossily"
2054 { package VAST
::regex_infix__S_Tilde
; our @ISA = 'VAST::Base';
2055 sub re_ast
{ my $self = shift;
2056 my ($left, $right) = map { $_->re_ast } $self->kids('args');
2057 die "internal error: erroneous optimization"
2058 unless $left->isa("RE_sequence") && $right->isa("RE_sequence");
2059 my @lefts = @
{ $left->{zyg
} };
2060 my @rights = @
{ $right->{zyg
} };
2062 pop @lefts while $lefts[-1]->isa('RE_method') && $lefts[-1]{name
} eq 'ws';
2063 shift @rights while $rights[0]->isa('RE_method') && $rights[0]{name
} eq 'ws';
2064 splice @rights, 1, 1 while $rights[1]->isa('RE_method') && $rights[1]{name
} eq 'ws';
2066 my $opener = pop @lefts;
2067 my ($closer, $inner) = splice @rights, 0, 2;
2071 my $strcloser = $closer->{text
}; #XXX
2074 local \$::GOAL = "${\ quotemeta $strcloser}";
2077 if ($strcloser !~ /^[])}]$/) {
2079 my \$newlang = \$C->unbalanced(\$::GOAL);
2080 \$C = bless(\$C, (ref(\$newlang) || \$newlang))
2084 push @middle, $opener;
2085 push @middle, $inner;
2086 push @middle, RE_bracket
->new(decl
=> [], re
=> RE_first
->new(
2087 RE_string
->new(text
=> $strcloser),
2088 RE_method
->new(name
=> 'FAILGOAL', nobind
=> 1,
2089 rest
=> "(\$::GOAL, '$::DBA', \$goalpos)")));
2091 my $middle = RE_bracket
->new(decl
=> [RE_decl
->new(body
=> $begin)], re
=>
2092 RE_sequence
->new(@middle));
2094 RE_sequence
->new(@lefts, $middle, @rights);
2099 { package VAST
::regex_infix__S_Vert
; our @ISA = 'VAST::Base';
2100 sub re_ast
{ my $self = shift;
2101 my $altname = $::NAME
. "_" . $::ALT
++;
2103 RE_any
->new(altname
=> $altname,
2104 zyg
=> [map { $_->re_ast } $self->kids('args')]);
2109 { package VAST
::regex_infix__S_VertVert
; our @ISA = 'VAST::Base';
2110 sub re_ast
{ my $self = shift;
2111 RE_first
->new(map { $_->re_ast } $self->kids('args'));
2117 { package VAST
::scoped
; our @ISA = 'VAST::Base';
2118 sub emit_p5
{ my $self = shift;
2119 if (@
{$self->{typename
}}) {
2120 " " . $self->{multi_declarator
}->p5;
2122 $self->SUPER::emit_p5
;
2128 { package VAST
::scope_declarator
; our @ISA = 'VAST::Base';
2132 { package VAST
::scope_declarator__S_has
; our @ISA = 'VAST::Base';
2133 sub emit_p5
{ my $self = shift;
2134 my $scoped = $self->{scoped
};
2135 my $typename = $scoped->{typename
}[0];
2136 my $multi = $scoped->{multi_declarator
};
2137 my $decl = $scoped->{declarator
} // $multi->{declarator
};
2138 my $vdecl = $decl->{variable_declarator
};
2139 my $var = $vdecl->{variable
};
2140 "moose_has '" . $var->{desigilname
}->Str . "' => (" . join (", ",
2141 ($typename ?
("isa => '" . $typename->Str . "'") : ()),
2148 { package VAST
::scope_declarator__S_my
; our @ISA = 'VAST::Base';
2149 sub emit_p5
{ my $self = shift;
2150 my $t = $self->SUPER::emit_p5
;
2151 $t =~ s/my(\s+)&(\w+)/my$1\$$2/;
2152 $t =~ s/my(\s+)([\$@%])::(\w+)/local$1${2}::$3/;
2158 { package VAST
::scope_declarator__S_our
; our @ISA = 'VAST::Base';
2162 { package VAST
::semiarglist
; our @ISA = 'VAST::Base';
2166 { package VAST
::semilist
; our @ISA = 'VAST::Base';
2170 { package VAST
::sibble
; our @ISA = 'VAST::Base';
2174 { package VAST
::sigil
; our @ISA = 'VAST::Base';
2178 { package VAST
::sigil__S_Amp
; our @ISA = 'VAST::Base';
2182 { package VAST
::sigil__S_At
; our @ISA = 'VAST::Base';
2186 { package VAST
::sigil__S_Dollar
; our @ISA = 'VAST::Base';
2190 { package VAST
::sigil__S_Percent
; our @ISA = 'VAST::Base';
2194 { package VAST
::sign
; our @ISA = 'VAST::Base';
2198 { package VAST
::signature
; our @ISA = 'VAST::Base';
2199 sub emit_p5
{ my $self = shift;
2200 for ($self->kids('param_sep')) {
2201 next if $_->{TEXT
} =~ /,/;
2202 die "Unusual parameter separators not yet supported";
2205 # signature stuff is just parsing code
2207 for my $pv ($self->kids('parameter')) {
2208 my ($named, $st) = $pv->p5;
2209 $seg[$named] .= $st . ";\n";
2212 if ($seg[1]) { $seg[1] = "my %args = \@_;\n" . $seg[1]; }
2219 { package VAST
::spacey
; our @ISA = 'VAST::Base';
2224 { package VAST
::special_variable
; our @ISA = 'VAST::Base';
2227 { package VAST
::special_variable__S_Dollar_a2_
; our @ISA = 'VAST::Base';
2228 sub emit_p5
{ my $self = shift;
2229 my @t = $self->SUPER::emit_p5
;
2236 { package VAST
::special_variable__S_DollarSlash
; our @ISA = 'VAST::Base';
2237 sub emit_p5
{ my $self = shift;
2238 my @t = $self->SUPER::emit_p5
;
2246 { package VAST
::statement
; our @ISA = 'VAST::Base';
2250 { package VAST
::statement_control
; our @ISA = 'VAST::Base';
2254 { package VAST
::statement_control__S_default
; our @ISA = 'VAST::Base';
2258 { package VAST
::statement_control__S_for
; our @ISA = 'VAST::Base';
2262 { package VAST
::statement_control__S_given
; our @ISA = 'VAST::Base';
2266 { package VAST
::statement_control__S_if
; our @ISA = 'VAST::Base';
2267 sub emit_p5
{ my $self = shift;
2268 join("\n", ("if " . $self->{xblock
}->p5)
2269 , (map { "elsif " .$_->p5 } @
{$self->{elsif}})
2270 , (map { "else " . $_->p5 } @
{$self->{else}}));
2275 { package VAST
::statement_control__S_loop
; our @ISA = 'VAST::Base';
2276 sub emit_p5
{ my $self = shift;
2277 my $t = $self->SUPER::emit_p5
;
2278 $t =~ s/^loop(\s+\()/for$1/;
2279 $t =~ s/^loop/for (;;)/;
2285 { package VAST
::statement_control__S_when
; our @ISA = 'VAST::Base';
2286 sub emit_p5
{ my $self = shift;
2287 my @t = $self->SUPER::emit_p5
;
2288 if ($t[1] =~ s/^\s*\(\s*\*\s*\)//) { $t[0] = 'default'; }
2294 { package VAST
::statement_control__S_while
; our @ISA = 'VAST::Base';
2298 { package VAST
::statementlist
; our @ISA = 'VAST::Base';
2299 sub emit_p5
{ my $self = shift;
2300 my @stmts = $self->kids('statement');
2301 # XXX mostly for the benefit of hashes
2303 return $stmts[0]->p5;
2305 join("", map { $_->p5 . ";\n" } @stmts);
2310 { package VAST
::statement_mod_cond
; our @ISA = 'VAST::Base';
2314 { package VAST
::statement_mod_cond__S_if
; our @ISA = 'VAST::Base';
2318 { package VAST
::statement_mod_cond__S_unless
; our @ISA = 'VAST::Base';
2322 { package VAST
::statement_mod_loop
; our @ISA = 'VAST::Base';
2326 { package VAST
::statement_mod_loop__S_for
; our @ISA = 'VAST::Base';
2330 { package VAST
::statement_mod_loop__S_while
; our @ISA = 'VAST::Base';
2334 { package VAST
::statement_prefix
; our @ISA = 'VAST::Base';
2338 { package VAST
::statement_prefix__S_do
; our @ISA = 'VAST::Base';
2342 { package VAST
::statement_prefix__S_try
; our @ISA = 'VAST::Base';
2343 sub emit_p5
{ my $self = shift;
2344 my @t = $self->SUPER::emit_p5
;
2351 { package VAST
::stdstopper
; our @ISA = 'VAST::Base';
2355 { package VAST
::stopper
; our @ISA = 'VAST::Base';
2359 { package VAST
::Structural_infix
; our @ISA = 'VAST::Base';
2363 { package VAST
::sublongname
; our @ISA = 'VAST::Base';
2367 { package VAST
::subshortname
; our @ISA = 'VAST::Base';
2371 { package VAST
::Symbolic_unary
; our @ISA = 'VAST::Base';
2375 { package VAST
::term
; our @ISA = 'VAST::Base';
2378 { package VAST
::term__S_capterm
; our @ISA = 'VAST::Base';
2382 { package VAST
::term__S_circumfix
; our @ISA = 'VAST::Base';
2386 { package VAST
::term__S_colonpair
; our @ISA = 'VAST::Base';
2387 sub emit_p5
{ my $self = shift;
2388 my $t = $self->SUPER::emit_p5
;
2390 if ($t =~ s/^:!//) {
2393 elsif ($t =~ s/^:(\d+)//) {
2400 if ($t =~ s/^(\w+)$/'$1'/) {
2404 my ($name,$rest) = $t =~ /^(\w+)(.*)$/s;
2405 $rest =~ s/^<([^\s']*)>/'$1'/ or
2406 $rest =~ s/^(<\S*>)/q$1/ or
2407 $rest =~ s/^(<\s*\S+\s*>)/qw$1/ or
2408 $rest =~ s/^(<.*>)/[qw$1]/; # p5's => isn't scalar context
2409 $t = "'$name' => $rest";
2417 { package VAST
::term__S_fatarrow
; our @ISA = 'VAST::Base';
2421 { package VAST
::term__S_identifier
; our @ISA = 'VAST::Base';
2422 sub emit_p5
{ my $self = shift;
2423 my @t = $self->SUPER::emit_p5
;
2424 if ($t[0] eq 'item') {
2428 if ($t[0] eq 'map' || $t[0] eq 'grep' || $t[0] eq 'sort') {
2429 # XXX this should be more robust, but it belongs in DEEP after
2430 # all arguments are collected anyway
2431 $t[1] =~ s/}\s*,/} /;
2433 if ($t[0] eq 'invert') {
2436 if ($t[0] eq 'chars') {
2439 if ($t[0] eq 'note') {
2440 $t[0] = 'print STDERR';
2442 if ($t[0] eq 'False') {
2445 if ($t[0] eq 'True') {
2448 if ($t[0] eq 'Nil') {
2456 { package VAST
::term__S_multi_declarator
; our @ISA = 'VAST::Base';
2460 { package VAST
::term__S_package_declarator
; our @ISA = 'VAST::Base';
2464 { package VAST
::term__S_regex_declarator
; our @ISA = 'VAST::Base';
2465 sub emit_p5
{ my $self = shift;;
2466 $self->{regex_declarator
}->p5;
2471 { package VAST
::term__S_routine_declarator
; our @ISA = 'VAST::Base';
2475 { package VAST
::term__S_scope_declarator
; our @ISA = 'VAST::Base';
2479 { package VAST
::term__S_statement_prefix
; our @ISA = 'VAST::Base';
2483 { package VAST
::term__S_term
; our @ISA = 'VAST::Base';
2487 { package VAST
::term__S_value
; our @ISA = 'VAST::Base';
2491 { package VAST
::term__S_variable
; our @ISA = 'VAST::Base';
2495 { package VAST
::terminator
; our @ISA = 'VAST::Base';
2496 sub emit_p6
{ my $self = shift;
2497 my @t = $self->SUPER::emit_p6
;
2502 { package VAST
::terminator__S_BangBang
; our @ISA = 'VAST::terminator'; }
2504 { package VAST
::terminator__S_for
; our @ISA = 'VAST::terminator'; }
2506 { package VAST
::terminator__S_if
; our @ISA = 'VAST::terminator'; }
2508 { package VAST
::terminator__S_Ket
; our @ISA = 'VAST::terminator'; }
2510 { package VAST
::terminator__S_Ly
; our @ISA = 'VAST::terminator'; }
2512 { package VAST
::terminator__S_Semi
; our @ISA = 'VAST::terminator'; }
2514 { package VAST
::terminator__S_Thesis
; our @ISA = 'VAST::terminator'; }
2516 { package VAST
::terminator__S_unless
; our @ISA = 'VAST::terminator'; }
2518 { package VAST
::terminator__S_while
; our @ISA = 'VAST::terminator'; }
2520 { package VAST
::terminator__S_when
; our @ISA = 'VAST::terminator'; }
2523 { package VAST
::termish
; our @ISA = 'VAST::Base';
2528 { package VAST
::term
; our @ISA = 'VAST::Base';
2531 { package VAST
::term__S_name
; our @ISA = 'VAST::Base';
2532 sub emit_p5
{ my $self = shift;
2533 my @t = $self->SUPER::emit_p5
;
2534 if (my ($pkg) = ($t[0] =~ /^::(.*)/)) {
2535 $pkg = $::OUR
{$pkg} // $pkg;
2536 if (defined $t[1] && $t[1] =~ /^\s*\[/) {
2537 $t[1] =~ s/^\s*\[/->__instantiate__(/;
2538 $t[1] =~ s/\]\s*$/)/;
2549 { package VAST
::term__S_self
; our @ISA = 'VAST::Base';
2550 sub emit_p5
{ my $self = shift;
2551 my @t = $self->SUPER::emit_p5
;
2558 { package VAST
::term__S_Star
; our @ISA = 'VAST::Base';
2562 { package VAST
::term__S_undef
; our @ISA = 'VAST::Base';
2566 { package VAST
::Tight_or
; our @ISA = 'VAST::Base';
2569 { package VAST
::Tight_and
; our @ISA = 'VAST::Base';
2573 { package VAST
::trait
; our @ISA = 'VAST::Base';
2577 { package VAST
::trait_auxiliary
; our @ISA = 'VAST::Base';
2581 { package VAST
::trait_auxiliary__S_does
; our @ISA = 'VAST::Base';
2585 { package VAST
::trait_auxiliary__S_is
; our @ISA = 'VAST::Base';
2590 { package VAST
::twigil
; our @ISA = 'VAST::Base';
2593 { package VAST
::twigil__S_Dot
; our @ISA = 'VAST::Base';
2594 sub emit_p5
{ my $self = shift;
2595 my @t = $self->SUPER::emit_p5
;
2596 $t[0] = 'self->'; # XXX
2602 { package VAST
::twigil__S_Star
; our @ISA = 'VAST::Base';
2603 sub emit_p5
{ my $self = shift;
2604 my @t = $self->SUPER::emit_p5
;
2610 { package VAST
::twigil__S_Caret
; our @ISA = 'VAST::Base';
2611 sub emit_p5
{ my $self = shift;
2612 my @t = $self->SUPER::emit_p5
;
2613 $t[0] = ''; #XXX only correct for sorts
2619 { package VAST
::type_constraint
; our @ISA = 'VAST::Base';
2622 { package VAST
::type_declarator__S_constant
; our @ISA = 'VAST::Base';
2623 sub emit_p5
{ my $self = shift;
2624 my $t = $self->SUPER::emit_p5
;
2625 $t =~ s/constant/our/;
2632 { package VAST
::typename
; our @ISA = 'VAST::Base';
2633 sub emit_p5
{ my $self = shift;
2635 if (ref $context[-1] ne 'VAST::scoped') {
2636 @t = $self->SUPER::emit_p5
;
2643 { package VAST
::unitstopper
; our @ISA = 'VAST::Base';
2647 { package VAST
::unspacey
; our @ISA = 'VAST::Base';
2651 { package VAST
::unv
; our @ISA = 'VAST::Base';
2655 { package VAST
::val
; our @ISA = 'VAST::Base';
2659 { package VAST
::value
; our @ISA = 'VAST::Base';
2663 { package VAST
::value__S_number
; our @ISA = 'VAST::Base';
2667 { package VAST
::value__S_quote
; our @ISA = 'VAST::Base';
2671 { package VAST
::variable
; our @ISA = 'VAST::Base';
2672 sub emit_p5
{ my $self = shift;
2673 my @t = $self->SUPER::emit_p5
;
2674 if (@t >= 2 && $t[0] eq '$') {
2675 if ($t[1] =~ /^\d+$/) {
2676 $t[1] = "M->{$t[1]}";
2678 } elsif ($t[1] =~ /^{/) {
2688 { package VAST
::variable_declarator
; our @ISA = 'VAST::Base';
2692 { package VAST
::vws
; our @ISA = 'VAST::Base';
2696 { package VAST
::ws
; our @ISA = 'VAST::Base';
2701 { package VAST
::xblock
; our @ISA = 'VAST::Base';
2702 sub emit_p5
{ my $self = shift;
2703 my @t = $self->SUPER::emit_p5
;
2704 $t[0] = '(' . $t[0] . ')';
2705 $t[0] =~ s/(\s+)\)$/)$1/;
2710 { package VAST
::XXX
; our @ISA = 'VAST::Base';
2717 my $dopp = bless { %$self }, ref($self);
2718 for my $dkid ($dopp->kids) {
2719 $$dkid = $$dkid->clone;
2723 sub new
{ my $class = shift;
2724 my $self = bless { a
=> 0, i
=> $::IGNORECASE ?
1 : 0,
2725 r
=> $::RATCHET ?
1 : 0, s
=> $::SIGSPACE ?
1 : 0,
2726 dba
=> $::DBA
, @_ }, $class;
2727 $self->{min
} //= $self->calc_min;
2731 sub optimize
{ my $self = shift;
2732 for my $kid ($self->kids) {
2733 $$kid = $$kid->optimize;
2738 sub clean
{ my $self = shift;
2739 for my $kid ($self->kids) {
2745 delete $self->{i
} unless $self->{i_needed
};
2746 delete $self->{i_needed
};
2747 delete $self->{dba
} unless $self->{dba_needed
};
2748 delete $self->{dba_needed
};
2753 sub walk
{ my $self = shift;
2754 say STDERR
"--> $self" if $OPT_log;
2755 my $exp = $self->_walk;
2756 say STDERR
"<-- $exp: ", $exp->p5 if $OPT_log;
2758 return DEEP
::cut
($exp);
2768 foreach my $kid (@
{$$self{zyg
}}) {
2769 my $x = $kid->walk->p5;
2770 $result .= $x if defined $x;
2776 return DEEP
::raw
($result);
2779 sub bind { my $self = shift; my $re = shift;
2780 return $re unless @_;
2781 # SUBSUMEr if we can prove single return
2783 $re = "\$C->_SUBSUME([" .
2784 join(',', map {"'$_'"} @_) .
2785 "], sub {\n" . ::indent
("my \$C = shift;\n" . $re, 2) . "\n })";
2789 sub remove_leading_ws
{ } # this tree node not interested
2790 sub has_trailing_ws
{ 0 }
2793 { package RE_double
; use base
"REbase";
2794 sub calc_min
{ length $_[0]{text
} }
2797 my $text = $$self{text
};
2798 $$self{i_needed
} = 1;
2799 # XXX needs interpolation
2801 $text = $::REV ?
"(?<=" . ::rd
($text) . ")" : ::rd
($text);
2802 DEEP
::raw
('$C->_PATTERN(qr/\\G(?i:' . $text . ')/")');
2805 DEEP
::raw
("\$C->_EXACT(\"" . ::rd
($text) . "\")");
2810 { package RE_string
; use base
"REbase";
2811 sub calc_min
{ length $_[0]->{text
} }
2814 $$self{i_needed
} = 1;
2816 my $text = quotemeta($$self{text
});
2817 $text = "(?<=$text)" if $::REV
;
2818 DEEP
::raw
("\$C->_PATTERN(qr/\\G(?i:" . ::rd($text) . ")/)");
2821 my $text = $$self{text
};
2822 $text =~ s/([\\'])/\\$1/g;
2823 DEEP
::raw
("\$C->_EXACT$::REV('$text')");
2828 { package RE_sequence
;
2829 sub calc_min
{ my $self = shift;
2830 ::sum
(0, map { $_->{min
} } @
{ $self->{zyg
} });
2834 my ($class, @zyg) = @_;
2835 $class->SUPER::new
(zyg
=> \
@zyg);
2839 my ($self, $outer, $inner) = @_;
2840 my ($out1, $outr) = $outer->uncut;
2842 DEEP
::raw
("if (my (\$C) = (" . $out1->p5 . ")) { " . $inner->p5block . " } else { () }", isblock
=> 1, precut
=> !$inner->maybacktrack);
2844 DEEP
::raw
("Cursor::lazymap(sub {\n my \$C=\$_[0];\n" .
2845 ::indent
($inner->p5) .
2846 "\n}, ${\ $outer->p5 })");
2855 my @kids = @
{$$self{zyg
}};
2857 while (@kids and ref $kids[0] eq 'RE_decl') {
2858 push @decl, shift(@kids)->walk->p5block;
2861 @kids = reverse @kids if $::REV
;
2862 foreach my $kid (@kids) {
2867 my $result = pop @result;
2868 for (reverse @result) {
2869 $result = $self->wrapone($_,$result);
2872 DEEP
::raw
(join('', @decl, $result ?
$result->p5 : ''), isblock
=> 1) :
2873 $result // DEEP
::raw
('');
2876 sub kids
{ my $self = shift; map { \
$_ } @
{$self->{zyg
}} }
2878 sub optimize
{ my $self = shift;
2882 for my $kid ($self->kids) {
2883 $$kid->remove_leading_ws if $afterspace;
2884 $afterspace = $$kid->has_trailing_ws($afterspace);
2887 $self = $self->SUPER::optimize
;
2889 for my $k (@
{$self->{zyg
}}) {
2890 next if $k->isa('RE_noop');
2891 if ($k->isa('RE_sequence')) {
2892 push @ok, @
{$k->{zyg
}};
2898 return RE_noop
->new if @ok == 0;
2899 return $ok[0] if @ok == 1;
2900 $self->{zyg
} = \
@ok;
2904 sub remove_leading_ws
{
2907 for my $kid ($self->kids) {
2908 my $l = $$kid->has_trailing_ws(1);
2909 $$kid->remove_leading_ws;
2914 sub has_trailing_ws
{
2918 for my $kid ($self->kids) {
2919 $before = $$kid->has_trailing_ws($before);
2926 { package RE_any
; use base
"REbase";
2927 sub calc_min
{ ::min
(1_000_000_000
, map { $_->{min
} } @
{$_[0]{zyg
}}) }
2932 my $altname = $self->{altname
};
2934 my %B = %::BINDINGS
;
2935 for my $kid (@
{$$self{zyg
}}) {
2938 for my $b (keys %::BINDINGS
) {
2939 $B{$b} = 2 if $::BINDINGS
{$b} > 1 or $B{$b};
2942 $kid->{alt
} = $altname . ' ' . $alt++;
2950 for (@result) { $_ = DEEP
::chunk
($_)->p5; }
2951 $::RETREE
->{$self->{altname
}} = $self;
2952 $self->{dba_needed
} = 1;
2953 my $result = <<"END";
2962 if (\$fate = \$C->{'_fate'} and \$fate->[1] eq '$altname') {
2963 \$C->deb("Fate passed to $altname: ", ::fatestr(\$fate)) if \$::DEBUG & DEBUG::fates;
2964 (\$C->{'_fate'}, \$tag, \$try) = \@\$fate;
2966 \$x = 'ALT $altname'; # some outer ltm is controlling us
2969 \$x = 'ALTLTM $altname'; # we are top level ltm
2971 my \$C = \$C->cursor_xact(\$x);
2972 my \$xact = \$C->{_xact};
2977 \$relex //= \$C->cursor_fate('$::PKG', '$altname', \$retree);
2978 \@try = \$relex->(\$C) or last;
2980 \$try = shift(\@try) // next;
2983 (\$C->{'_fate'}, \$tag, \$try) = \@\$try; # next candidate fate
2986 \$C->deb("$altname trying \$tag \$try") if \$::DEBUG & DEBUG::try_processing;
2988 @{[ ::indent(join(",\n", @result),3) ]}
2994 last if $xact->[-2]; # committed?
3005 sub kids
{ my $self = shift; map { \
$_ } @
{$self->{zyg
}} }
3007 sub optimize
{ my $self = shift()->SUPER::optimize
;
3010 for my $k (@
{$self->{zyg
}}) {
3011 if ($k->isa('RE_any')) {
3012 push @ok, @
{$k->{zyg
}};
3018 return $ok[0] if @ok == 1;
3019 $self->{zyg
} = \
@ok;
3023 # yes, this affects LTM, but S05 specs it
3024 sub remove_leading_ws
{
3026 for my $kid (@
{$$self{zyg
}}) {
3027 $kid->remove_leading_ws();
3031 sub has_trailing_ws
{
3036 for my $kid ($self->kids) {
3037 $after &&= $$kid->has_trailing_ws($before);
3044 { package RE_first
; use base
"REbase";
3045 sub calc_min
{ ::min
(1_000_000_000
, map { $_->{min
} } @
{$_[0]{zyg
}}) }
3048 my ($class, @zyg) = @_;
3049 $class->SUPER::new
(zyg
=> \
@zyg);
3056 my %B = %::BINDINGS
;
3057 foreach my $kid (@
{$$self{zyg
}}) {
3059 push @result, $kid->walk->p5;
3060 for my $b (keys %::BINDINGS
) {
3061 $B{$b} = 2 if $::BINDINGS
{$b} > 1 or $B{$b};
3067 DEEP
::raw
($result[0]);
3070 die("Can't reverse serial disjunction") if $::REV
;
3071 for (@result) { $_ = ::indent
($_); s/^ */do {\n push \@gather, /; }
3072 my $result = "do {\n my \$C = \$C->cursor_xact('ALT ||');\n my \$xact = \$C->xact;\n my \@gather;\n" .
3073 ::indent
(join("\n}\nor \$xact->[-2] or\n", @result)) .
3074 "};\n \@gather;\n}";
3079 sub kids
{ my $self = shift; map { \
$_ } @
{$self->{zyg
}} }
3081 sub remove_leading_ws
{
3083 for my $kid (@
{$$self{zyg
}}) {
3084 $kid->remove_leading_ws();
3088 sub has_trailing_ws
{
3093 for my $kid ($self->kids) {
3094 $after &&= $$kid->has_trailing_ws($before);
3101 { package RE_method
; use base
"REbase";
3102 sub calc_min
{ 12345 }
3103 sub clean
{ my $self = shift;
3104 $self->SUPER::clean
;
3105 delete $self->{nobind
};
3106 delete $self->{need_match
};
3107 $self->{rest
} = defined $self->{rest
};
3111 local $::NEEDMATCH
= 0;
3112 my $name = $$self{name
};
3113 die "Can't reverse $name" if $::REV
;
3116 if ($name eq "sym") {
3117 $$self{i_needed
} = 1;
3118 $$self{sym
} = $::SYM
;
3119 $$self{endsym
} = $::ENDSYM
if defined $::ENDSYM
;
3121 return DEEP
::raw
("\$C->_PATTERN(qr/\\G(?i:" . ::rd($::SYM) . ")/)");
3124 return DEEP
::raw
("\$C->_PATTERN(qr/\\G" . ::rd($::SYM) . "/)");
3127 elsif ($name eq "alpha") {
3128 return DEEP
::raw
("\$C->_PATTERN(qr/\\G[_[:alpha:]]/)");
3130 elsif ($name eq "_ALNUM") {
3131 return DEEP
::raw
("\$C->_PATTERN(qr/\\G\\w/)");
3133 elsif ($name eq "nextsame") {
3135 $re = '$self->SUPER::' . $::NAME
. '(@origargs)';
3137 elsif ($name =~ /^\w/) {
3138 my $al = $self->{rest
} // '';
3139 $re = '$C->' . $name . $al;
3142 my $al = $self->{rest
} // '';
3148 elsif (ref $name eq 'Regexp') {
3149 if (\$::ORIG =~ m/$name/gc) {
3150 \$C->cursor(\$+[0]);
3162 if ($name =~ /^\w/ and not $self->{nobind
}) {
3163 $::BINDINGS
{$name} += $::PLURALITY
;
3164 $re = $self->bind(DEEP
::raw
($re), $name)->p5;
3166 $re = 'do { my $M = $C;' . "\n" . ::indent
($re) . "\n; }" if $self->{need_match
};
3170 sub has_trailing_ws
{
3172 return $self->{name
} eq 'ws';
3175 sub remove_leading_ws
{
3177 if ($self->{name
} eq 'ws' && $self->{nobind
}) {
3178 bless $self, 'RE_noop';
3183 { package RE_ast
; use base
"REbase";
3184 sub calc_min
{ $_[0]{re
}{min
} }
3185 sub clean
{ my $self = shift;
3186 $self->SUPER::clean
;
3187 delete $self->{decl
};
3188 delete $self->{kind
};
3193 for my $decl (@
{$$self{decl
}}) {
3194 push @
::DECL
, $decl->walk->p5;
3202 sub kids
{ my $self = shift; \
$self->{re
}, map { \
$_ } @
{$self->{decl
}}; }
3205 { package RE_quantified_atom
; use base
"REbase";
3206 sub calc_min
{ $_[0]{quant
}[3] * $_[0]{atom
}{min
} }
3207 # handles cutting itself
3208 sub clean
{ my $self = shift;
3209 $self->SUPER::clean
;
3210 splice @
{$self->{quant
}}, ($self->{quant
}[0] eq '**' ?
3 : 1);
3214 my $self = $class->SUPER::new
(@_);
3221 local $::PLURALITY
= 2;
3222 if (ref $$self{atom
}) {
3225 my $q = $$self{quant
};
3226 my $atom = $$self{atom
}->walk->p5;
3228 if ($atom =~ m{ ^ \$C->_PATTERN\(qr/\\G(.*?)/\) $ }sx ) {
3230 my ($qfer,$how,$rest) = @
{$$self{quant
}};
3231 my $h = $how eq '!' ?
'' :
3234 if ($how eq '?' or $::REV
) {
3237 elsif ($qfer eq '**') {
3238 $h = $how eq '!' ?
'g' :
3242 if (ref $rest eq "RE_block") {
3243 $rep = "_REPINDIRECT$::REV";
3244 $rest = $rest->walk->p5;
3247 $rep = "_REPSEP$::REV";
3248 $rest = DEEP
::chunk
($rest->walk)->p5;
3254 $quant = "\$C->$rep$h( $rest, ";
3255 return DEEP
::raw
($quant .
3256 DEEP
::chunk
(DEEP
::raw
($atom))->p5 . ")");
3259 return DEEP
::raw
("\$C->_PATTERN\(qr/\\G($a$qfer$h)/\)");
3263 my ($qfer,$how,$rest) = @
{$$self{quant
}};
3264 my $h = $how eq '!' ?
'g' :
3268 $quant = "\$C->_STAR$h$::REV(";
3270 elsif ($qfer eq '+') {
3271 $quant = "\$C->_PLUS$h$::REV(";
3273 elsif ($qfer eq '?') {
3274 $quant = "\$C->_OPT$h$::REV(";
3276 elsif ($qfer eq '**') {
3278 if (ref $rest eq "RE_block") {
3279 $rep = "_REPINDIRECT$::REV";
3280 $rest = $rest->walk;
3283 $rep = "_REPSEP$::REV";
3284 $rest = DEEP
::chunk
($rest->walk)->p5;
3290 $quant = "\$C->$rep$h( $rest, ";
3292 return DEEP
::raw
($quant . DEEP
::chunk
(DEEP
::raw
($atom))->p5 . ")");
3295 return DEEP
::raw
($atom);
3299 return DEEP
::raw
('"' . $$self{atom
} . '"');
3304 sub kids
{ my $self = shift; \
$self->{atom
} }
3307 { package RE_qw
; use base
"REbase";
3310 DEEP
::raw
("\$C->_ARRAY$::REV( qw$$self{text} )");
3314 { package RE_method_re
; use base
"REbase";
3315 sub calc_min
{ 12345 } # "many"
3318 my $re = $$self{re
};
3319 my $name = $$self{name
};
3320 die("Can't reverse $name") if $::REV
and $name ne 'before';
3321 local $::REV
= $name eq 'after' ?
'_rev' : '';
3324 $re = ::indent
($re->walk->p5block);
3326 for my $binding ( keys %::BINDINGS
) {
3327 next unless $::BINDINGS
{$binding} > 1;
3328 $re = <<"END" . $re;
3329 \$C->{'$binding'} = [];
3336 $re = DEEP
::raw
('$C->' . $name . "(" . DEEP
::chunk
(DEEP
::raw
($re, isblock
=> 1))->p5 . ")");
3337 if ($name =~ /^\w/ and not $self->{nobind
}) {
3338 $re = $self->bind($re, $name);
3339 $::BINDINGS
{$name} += $::PLURALITY
;
3344 sub kids
{ my $self = shift; \
$self->{re
} }
3347 { package RE_assertion
; use base
"REbase";
3350 if ($$self{assert
} eq '!') {
3351 my $re = $$self{re
}->walk;
3352 DEEP
::raw
("\$C->_NOTBEFORE( " . DEEP
::chunk
($re)->p5 .")");
3355 my $re = $$self{re
}->walk;
3356 return $re if $re->p5 =~ /^\$C->before/; #XXX
3357 DEEP
::raw
("\$C->before( " . DEEP
::chunk
($re)->p5 . ")");
3360 # TODO: Investigate what the LTM engine is doing with assertions and
3363 sub has_trailing_ws
{
3367 $before; # Transparent
3370 sub remove_leading_ws
{
3373 $self->{re
}->remove_leading_ws;
3376 sub kids
{ my $self = shift; \
$self->{re
} }
3379 { package RE_meta
; use base
"REbase";
3382 my $text = $$self{text
};
3385 if ($text =~ /^(\\[A-Z])(.*)/) {
3386 $text = lc($1) . $2;
3391 $code = "\$C->_PATTERN(qr/\\G(?<=(?s:.))/)";
3394 $code = "\$C->cursor_incr()";
3397 elsif ($text eq '.*') {
3398 $code = "\$C->_SCANg$::REV()";
3400 elsif ($text eq '.*?') {
3401 $code = "\$C->_SCANf$::REV()";
3403 elsif ($text eq '^') {
3404 $code = "\$C->_PATTERN(qr/\\G\\A/)";
3406 elsif ($text eq '^^') {
3407 $code = "\$C->_PATTERN(qr/\\G(?m:^)/)";
3409 elsif ($text eq '$') {
3410 $code = "\$C->_PATTERN(qr/\\G\\z/)";
3412 elsif ($text eq '$$') {
3413 $code = "\$C->_PATTERN(qr/\\G(?m:\$)/)";
3415 elsif ($text eq ':') {
3416 my $extra = $self->{extra
} || '';
3417 $code = "(($extra), \$C)[-1]";
3419 elsif ($text eq '::') {
3420 $code = "\$C->_COMMITLTM$::REV()";
3422 elsif ($text eq '::>') {
3423 $code = "\$C->_COMMITBRANCH$::REV()";
3425 elsif ($text eq ':::') {
3426 $code = "\$C->_COMMITRULE$::REV()";
3428 elsif ($text eq '\\d') {
3430 $code = "\$C->_PATTERN(qr/\\G(?<=\\d)/)";
3433 $code = "\$C->_PATTERN(qr/\\G\\d/)";
3436 elsif ($text eq '\\w') {
3438 $code = "\$C->_PATTERN(qr/\\G(?<=\\w)/)";
3441 $code = "\$C->_PATTERN(qr/\\G\\w/)";
3444 elsif ($text eq '\\s') {
3446 $code = "\$C->_PATTERN(qr/\\G(?<=\\s)/)";
3449 $code = "\$C->_PATTERN(qr/\\G\\s/)";
3452 elsif ($text eq '\\h') {
3454 $code = "\$C->_PATTERN(qr/\\G(?<=[\\x20\\t\\r])/)";
3457 $code = "\$C->_PATTERN(qr/\\G[\\x20\\t\\r]/)";
3460 elsif ($text eq '\\v') {
3462 $code = "\$C->_PATTERN(qr/\\G(?<=[\\n])/)";
3465 $code = "\$C->_PATTERN(qr/\\G[\\n]/)";
3468 elsif ($text eq '»') {
3469 $code = "\$C->_PATTERN(qr/\\G\\b/)";
3471 elsif ($text eq '«') {
3472 $code = "\$C->_PATTERN(qr/\\G\\b/)";
3474 elsif ($text eq '>>') {
3475 $code = "\$C->_RIGHTWB$::REV()";
3477 elsif ($text eq '<<') {
3478 $code = "\$C->_LEFTWB$::REV()";
3480 elsif ($text eq '<(') {
3481 $code = "\$C->_LEFTRESULT$::REV()";
3483 elsif ($text eq ')>') {
3484 $code = "\$C->_RIGHTRESULT$::REV()";
3486 elsif ($text eq '<~~>') {
3487 $code = "\$C->$::NAME()";
3490 $code = "\$C->_EXACT$::REV(\"$text\")";
3492 if ($not) { # XXX or maybe just .NOT on the end...
3493 $code = "\$C->_NOTCHAR( sub { my \$C=shift;\n" . ::indent
($code) . "\n})";
3499 { package RE_cclass
; use base
"REbase";
3503 my $text = $$self{text
};
3504 $self->{i_needed
} = 1;
3505 $text =~ s!(\/|\\\/)!\\$1!g;
3507 $text =~ s/\.\./-/g;
3508 $text =~ s/^-\[/[^/;
3509 $text = "(?<=$text)" if $::REV
;
3511 DEEP
::raw
("\$C->_PATTERN(qr/\\G(?i:$text)/)");
3514 DEEP
::raw
("\$C->_PATTERN(qr/\\G$text/)");
3519 { package RE_noop
; use base
"REbase";
3525 sub has_trailing_ws
{
3533 { package RE_decl
; use base
"REbase";
3534 # because cutting one of these would be a disaster
3537 my $self = $class->SUPER::new
(@_);
3541 sub clean
{ my $self = shift;
3542 $self->SUPER::clean
;
3543 delete $self->{body
};
3547 DEEP
::raw
($$self{body
} . ";\n");
3550 sub has_trailing_ws
{
3558 { package RE_block
; use base
"REbase";
3559 sub clean
{ my $self = shift;
3560 $self->SUPER::clean
;
3561 delete $self->{context
};
3562 delete $self->{body
};
3566 my $ctx = $$self{context
};
3567 my $text = ::indent
($$self{body
});
3568 if ($ctx eq 'void') {
3569 return DEEP
::raw
("scalar(do {\n$text\n}, \$C)");
3571 elsif ($ctx eq 'bool') {
3572 return DEEP
::raw
("((\$C) x !!do {\n$text\n})");
3575 return DEEP
::raw
(" sub { my \$C=shift;\n$text\n}");
3579 sub has_trailing_ws
{
3587 { package RE_bracket
; use base
"REbase";
3588 sub calc_min
{ $_[0]->{re
}->{min
} }
3589 sub clean
{ my $self = shift;
3590 $self->SUPER::clean
;
3591 delete $self->{decl
};
3595 my ($re, $r) = $$self{re
}->walk->uncut;
3596 my @decl = map { $_->walk } @
{$$self{decl
}};
3597 DEEP
::raw
("\$C->_BRACKET$r(" . DEEP
::chunk
($re, @decl)->p5 . ")");
3600 sub kids
{ my $self = shift; \
$self->{re
} }
3602 sub remove_leading_ws
{
3604 my $re = $$self{re
};
3605 $re->remove_leading_ws();
3608 sub has_trailing_ws
{
3611 $$self{re
}->has_trailing_ws($before);
3615 { package RE_var
; use base
"REbase";
3618 my $var = $$self{var
};
3619 if ($var =~ /^\$/) {
3620 if ($var =~ /^\$M->{(.*)}/) {
3621 my $p = (substr($1,0,1) eq "'") ?
"n" : "p";
3622 DEEP
::raw
("\$C->_BACKREF$p$::REV($1)");
3625 DEEP
::raw
("\$C->_EXACT$::REV($var)");
3628 elsif ($var =~ /^\@/) {
3629 DEEP
::raw
("\$C->_ARRAY$::REV($var)");
3631 elsif ($var =~ /^\%/) {
3632 DEEP
::raw
("\$C->_HASH$::REV($var)");
3637 { package RE_paren
; use base
"REbase";
3638 sub calc_min
{ $_[0]{re
}{min
} }
3639 sub clean
{ my $self = shift;
3640 $self->SUPER::clean
;
3641 delete $self->{decl
};
3648 $re = ::indent
($$self{re
}->walk->p5block);
3650 for my $binding ( keys %::BINDINGS
) {
3651 next unless $::BINDINGS
{$binding} > 1;
3652 my $re = <<"END" . $re;
3653 \$C->{'$binding'} = [];
3658 $re = "\$C->_$::REV"."PAREN( " . DEEP
::chunk
(DEEP
::raw
($re))->p5 . ")";
3662 sub kids
{ my $self = shift; \
$self->{re
} }
3664 # yes, () would capture the ws, but we're guaranteed to be past it already
3665 sub remove_leading_ws
{
3667 my $re = $$self{re
};
3668 $re->remove_leading_ws();
3671 sub has_trailing_ws
{
3674 $$self{re
}->has_trailing_ws($before);
3678 { package RE_bindpos
; use base
"REbase";
3679 sub calc_min
{ $_[0]{atom
}{min
} }
3680 sub clean
{ my $self = shift;
3681 $self->SUPER::clean
;
3682 delete $self->{var
};
3686 my $var = $$self{var
};
3687 $::BINDINGS
{$var} += $::PLURALITY
;
3688 my $re = $$self{atom
}->walk;
3689 $self->bind($re, $var);
3692 sub kids
{ my $self = shift; \
$self->{atom
} }
3694 sub remove_leading_ws
{
3696 my $re = $$self{atom
};
3697 $re->remove_leading_ws();
3700 sub has_trailing_ws
{
3703 $$self{atom
}->has_trailing_ws($before);
3707 { package RE_bindnamed
; use base
"REbase";
3708 sub calc_min
{ $_[0]{atom
}{min
} }
3709 sub clean
{ my $self = shift;
3710 $self->SUPER::clean
;
3711 delete $self->{var
};
3715 my $var = $$self{var
};
3716 $::BINDINGS
{$var} += $::PLURALITY
;
3717 my $re = $$self{atom
}->walk;
3718 $self->bind($re, $var);
3721 sub kids
{ my $self = shift; \
$self->{atom
} }
3723 sub remove_leading_ws
{
3725 my $re = $$self{atom
};
3726 $re->remove_leading_ws();
3729 sub has_trailing_ws
{
3732 $$self{atom
}->has_trailing_ws($before);
3737 sub maybacktrack
{ 1 }
3739 sub uncut
{ my $self = shift; $self, ($self->maybacktrack ?
'' : 'r') }
3741 sub p5block
{ shift()->p5 }
3744 { package DEEP
::raw
; our @ISA = 'DEEPbase';
3747 bless { text
=> $text, @_ }, "DEEP::raw";
3752 return !$self->{precut
};
3755 sub p5
{ my $self = shift;
3756 $self->{isblock
} ?
("do {\n" . ::indent
($self->{text
}) . "\n}")
3760 sub p5block
{ my $self = shift; $self->{text
} }
3763 { package DEEPblockbase
; our @ISA = 'DEEPbase';
3764 sub p5
{ my $self = shift;
3765 "do {\n" . ::indent
($self->p5block) . "\n}";
3769 { package DEEP
::cut
; our @ISA = 'DEEPblockbase';
3772 bless { child
=> $child }, "DEEP::cut";
3775 sub p5block
{ my $self = shift;
3776 "if (my (\$C) = (" . $self->{child
}->p5 . ")) { (\$C) } else { () }";
3781 my ($child_uncut) = $self->{child
}->uncut;
3786 # NOT a regex bit, but a value
3787 { package DEEP
::chunk
; our @ISA = 'DEEPbase';
3790 bless { child
=> $child, decl
=> \
@_ }, "DEEP::chunk";
3795 " sub { my \$C=shift;\n"
3796 . ::indent
(join("", map { $_->p5block . ";\n" } @
{ $self->{decl
} }))
3797 . ::indent
($self->{child
}->p5block) . "\n}";
3801 if ($0 eq __FILE__
) {
3805 # vim: ts=8 sw=4 noexpandtab smarttab