5 viv - A retargettable Perl 6 metacompiler
9 C<viv> converts code, written in a subset of Perl 6, into code in Perl 5 (and
10 eventually several other languages). C<viv> is B<not a general compiler>; it
11 makes little to no attempt to provide faithful Perl 6 semantics, so code
12 intended to be run through viv needs to restrict itself to a "nice" subset of
13 Perl 6. Exactly what "nice" means hasn't been completely nailed down, but
14 multithreading, the MOP, augmenting system classes, and operator overloading
15 are all almost certainly out.
17 * First, viv reads your source code (which must be encoded in UTF-8). If the
18 --thaw option is provided, the source is expected to be in Storable format;
19 this eliminates parsing overhead and makes viv ~7 times faster. Useful for
20 experimenting with modifications to viv itself.
22 * Second, the source code is parsed into an object-oriented abstract syntax
23 tree using STD.pm6 and Actions. If --freeze is passed, the process stops
24 here and a Storable dump is generated.
26 * Translation of the parse tree into output code occurs in a single interleaved
27 pass, however it takes different paths for regex and non-regex code.
28 Non-regex code is mostly passed through, with targetted syntax-dependant
29 rewrites; as possible, we are changing this to generate DEEP. Regexes are
30 converted into a narrowed REgex AST format, which is translated into DEEP and
31 additionally dumped for post-translation processing by the LTM engine.
33 * The DEEP engine handles differences between output formats, taking advantage
34 of its much narrower form.
40 use warnings FATAL
=> 'all';
42 use List
::Util qw
/sum min/;
46 use YAML
::XS
; # An attempt to replace this with YAML::Syck passed the
47 # tests but produced a different output format that
48 # confused some calling programs. For example, anchors
49 # are usually numbers ascending from 1, and they became
50 # disjoint sets of descending numbers. Also, empty
51 # sequences shown as [] became followed by an empty line.
52 # See also: YAML::Syck in package VAST::package_def below.
54 use Scalar
::Util
'blessed', 'refaddr';
62 our $OPT_keep_going = 0;
63 our $OPT_output_file = undef;
70 # Let's say you have a tricky optimization that breaks the build. You want
71 # to know exactly which rewrite is culpable? Try bisecting with
72 # VIV_OPTLIMIT, after wrapping the rewrite in if (DARE_TO_OPTIMIZE).
73 my $optlimit = $ENV{VIV_OPTLIMIT
};
74 if (defined $optlimit) {
75 *DARE_TO_OPTIMIZE
= Sub
::Name
::subname
(DARE_TO_OPTIMIZE
=> sub {
79 constant
->import(DARE_TO_OPTIMIZE
=> 1);
85 # XXX STD Global trait tables simulate inheritence
87 local $::PROTOSIG
= {};
91 viv [switches] filename
92 where switches can be:
93 -e use following argument as program
94 -o send output to following argument instead of STDOUT
95 --yaml spit out a parsable abstract syntax tree
96 --concise spit out a short syntaxe tree (default)
97 --p5 spit out a Perl 5 representation
98 --p6 spit out a Perl 6 representation
99 --psq spit out a Perlesque representation (very incomplete)
100 --no-indent disable output indentation for faster parsing
101 --freeze generate a Storable representation
102 --thaw use existing Storable of AST from filename
103 --stab include the symbol table
104 --pos include position info in AST
105 --match include match tree info in AST
106 --log emit debugging info to standard error
107 --keep-going continue after output errors
116 $bits .= "\n" unless $bits ~~ /\n\z/;
117 if (defined $OPT_output_file) {
118 open my $out, ">", $OPT_output_file
119 or die "cannot open $OPT_output_file for writing: $!";
120 binmode $out, ":utf8";
121 print $out $bits or die "cannot write: $!";
122 close $out or die "cannot close: $!";
129 my $output = 'concise';
133 last unless $_[0] =~ /^-/;
134 my $switch = shift @_;
135 if ($switch eq '--eval' or $switch eq '-e') {
136 $PROG .= Encode
::decode_utf8
(shift(@_)) . "\n";
138 elsif ($switch eq '--output' or $switch eq '-o') {
139 $OPT_output_file = shift(@_);
141 elsif ($switch eq '--yaml' or $switch eq '-y') {
144 elsif ($switch eq '--concise' or $switch eq '-c') {
147 elsif ($switch eq '--p5' or $switch eq '-5') {
150 elsif ($switch eq '--p6' or $switch eq '-6') {
153 elsif ($switch eq '--psq') {
156 elsif ($switch eq '--freeze') {
159 elsif ($switch eq '--stab' or $switch eq '-s') {
162 elsif ($switch eq '--log' or $switch eq '-l') {
165 elsif ($switch eq '--pos' or $switch eq '-p') {
168 elsif ($switch eq '--no-indent') {
169 no warnings
'redefine';
170 *indent
= \
&no_indent
;
173 elsif ($switch eq '--match' or $switch eq '-m') {
174 $OPT_match = 1; # attach match object
176 elsif ($switch eq '--thaw') {
179 elsif ($switch eq '--keep-going' or $switch eq '-k') {
182 elsif ($switch eq '--help') {
186 # USAGE() unless -r $_[0];
189 my $raw = retrieve
($_[0]);
190 $ORIG = $raw->{ORIG
};
192 $STD::ALL
= $raw->{STABS
};
193 for my $cl (keys %{$raw->{GENCLASS
}}) {
194 Actions
::gen_class
($cl, $raw->{GENCLASS
}->{$cl});
197 elsif (@_ and -f
$_[0]) {
198 $r = STD
->parsefile($_[0], text_return
=> \
$ORIG,
199 actions
=> 'Actions')->{'_ast'};
208 $r = STD
->parse($PROG, actions
=> 'Actions')->{'_ast'};
215 $r->{stabs
} = $STD::ALL
;
217 if ($output eq 'yaml') {
219 # $x =~ s/\n.*: \[\]$//mg;
222 elsif ($output eq 'concise') {
223 spew concise
($r, 80);
225 elsif ($output eq 'p6') {
228 elsif ($output eq 'psq') {
231 elsif ($output eq 'p5') {
234 elsif ($output eq 'store') {
236 my $data = { AST
=> $r, GENCLASS
=> \
%Actions::GENCLASS
,
237 ORIG
=> $ORIG, STABS
=> $STD::ALL
};
238 defined($OPT_output_file) ? store
($data, $OPT_output_file)
239 : Storable
::store_fd
($data, \
*STDOUT
);
242 die "Unknown output mode";
246 sub no_indent
{ $_[0] }
249 my ($arg, $leader) = @_;
251 $arg =~ s/\n/\n$leader/g;
258 for my $i (0 .. $#_) {
259 $r .= ($i == $#_) ?
"\n└─" : "\n├─";
260 $r .= hang
($_[$i], $i == $#_ ?
" " : "│ ");
266 my ($first, $rest, $tx) = @_;
269 while (length $tx > $first) {
270 $out .= substr($tx, 0, $first);
272 $tx = substr($tx, $first);
280 my ($node, $width) = @_;
282 $width = 30 if $width < 30;
285 return defined($node) ? shred
($width, $width, "$node") : "undef";
286 } elsif (blessed
($node) && ref($node) =~ /^VAST/) {
288 ref($node->{"."}) eq 'ARRAY' ? @
{$node->{"."}} :
289 defined($node->{"."}) ?
$node->{"."} :
295 # don't list the same node twice
296 my %inpos = map { ref($_) ?
(refaddr
($_) , 1) : () } @pos;
298 @pos = map { concise
($_, $width-2) } @pos;
301 my $title = blessed
$node;
302 my $x = length($title);
303 for my $ch (sort keys %nam) {
304 next if $ch eq '_fate';
306 # hide named children that are just (lists of) positional children
307 if ($inpos{refaddr
($nam{$ch})}) { next }
308 if (ref($nam{$ch}) eq 'ARRAY') {
310 for (@
{$nam{$ch}}) { $all = 0 unless ref $_ && $inpos{refaddr
$_} }
315 my $repr = concise
($nam{$ch}, $width-4);
317 if ($repr !~ /\n/ && length $repr < 30) {
318 if ($x + length($ch) + length($repr) + 6 > $width) {
325 $title .= "$ch: $repr";
326 $x += length("$ch: $repr");
328 my $hang = " " x
(length($ch)+2);
329 push @oobnam, "$ch: " . hang
($repr, $hang);
333 $title = hang
($title, (@pos ?
"│ " : " ") . (@oobnam ?
"│ " : " "));
337 $result .= hang
(listify
(@oobnam), @pos ?
"│ " : " ");
338 $result .= listify
(@pos);
343 return substr($d, 4, length($d)-5);
347 # viv should likely be abstracted into a module instead of doing this hack... - pmurias
350 $OPT_match = $opt{match
};
351 $OPT_log = $opt{log};
356 return $text unless $text =~ /\n/;
357 my @text = split(/^/, $text);
361 $in_begin = $1 if /^=begin\s+(\w+)/;
362 $in_for = 1 if /^=for/;
363 $in_for = 0 if /^\s*$/;
364 my $docomment = $in_begin || $in_for;
365 $in_begin = 0 if /^=end\s+(\w+)/ and $1 eq $in_begin;
366 s/^/# / if $docomment;
371 # rules of thumb: a block (0 or more statements) is a chunk of text, use
372 # indent. for expressions, the overall philosophy is that the indentation
373 # of a line should be proportional to the number of outstanding syntactic
387 $out .= $1 if $in =~ s/^\\([\\'])//;
388 $out .= $1 if $in =~ s/^(.)//;
393 # XXX this is only used for backslash escapes in regexes
397 my %trans = ( 'n' => "\n" );
399 $out .= $trans{$1} // $1 if $in =~ s/^\\(.)//;
400 $out .= $1 if $in =~ s/^(.)//;
408 for my $ch (split //, $in) {
409 $out .= $ch eq "\n" ?
'\n' : quotemeta($ch);
414 ###################################################################
416 { package VAST
::Base
;
418 sub Str
{ my $self = shift;
419 my $b = $self->{BEG
};
420 my $e = $self->{END};
421 return '' if $b > length($ORIG);
422 substr($ORIG, $b, $e - $b);
425 sub kids
{ my $self = shift;
426 my $key = shift() // '.';
427 return () unless exists $self->{$key};
428 my $entry = $self->{$key};
429 return ref($entry) eq 'ARRAY' ? @
$entry : $entry;
432 sub emit_p6
{ my $self = shift;
434 if (exists $self->{'.'}) {
435 my $last = $self->{BEG
};
436 my $all = $self->{'.'};
438 for my $kid (ref($all) eq 'ARRAY' ? @
$all : $all) {
440 if (not defined $kid->{BEG
}) {
441 $kid->{BEG
} = $kid->{_from
} // next;
442 $kid->{END} = $kid->{_pos
};
446 for my $kid (sort { $a->{BEG
} <=> $b->{BEG
} } @kids) {
447 my $kb = $kid->{BEG
};
449 push @text, substr($ORIG, $last, $kb - $last);
451 if (ref($kid) eq 'HASH') {
452 print STDERR
::Dump
($self);
453 die "in a weird place";
455 push @text, scalar $kid->p6;
459 my $se = $self->{END};
461 push @text, substr($ORIG, $last, $se - $last);
465 # print STDERR "OOPS " . ref($self) . " $$self{TEXT}\n";
466 push @text, $self->{TEXT
};
468 wantarray ?
@text : join('', @text);
471 sub emit_p5
{ my $self = shift;
473 if (exists $self->{'.'}) {
474 my $last = $self->{BEG
};
475 my $all = $self->{'.'};
477 for my $kid (ref($all) eq 'ARRAY' ? @
$all : $all) {
479 if (not defined $kid->{BEG
}) {
480 $kid->{BEG
} = $kid->{_from
} // next;
481 $kid->{END} = $kid->{_pos
};
485 for my $kid (sort { $a->{BEG
} <=> $b->{BEG
} } @kids) {
486 my $kb = $kid->{BEG
};
488 push @text, substr($ORIG, $last, $kb - $last);
490 if (ref($kid) eq 'HASH') {
491 print STDERR
::Dump
($self);
492 die "in a weird place";
494 push @text, scalar $kid->p5;
498 my $se = $self->{END};
500 push @text, substr($ORIG, $last, $se - $last);
504 # print STDERR "OOPS " . ref($self) . " $$self{TEXT}\n";
505 push @text, $self->{TEXT
};
507 wantarray ?
@text : join('', @text);
511 my $tpl = <<'TEMPLATE';
512 sub VAST::Base::FORM { my $self = shift; my $lvl = @context;
514 say STDERR ' ' x $lvl, ref $self, " from ",$self->{BEG}," to ",$self->{END} if $OPT_log;
515 $context[$lvl] = $self;
516 # print STDERR "HERE " . ref($self) . "\n";
517 local $SIG{__DIE__} = sub {
519 $args[-1] =~ s/ at .*? line .*?\n$//s if $args[-1] =~ /\n$/s;
520 die Carp::longmess(@args);
522 my @bits = !$OPT_keep_going ? $self->emit_FORM(@_) : (::try {
523 $self->emit_FORM(@_);
525 my $char = $self->{BEG} // $self->{_from} // 0;
526 my $line = 1 + (substr($ORIG, 0, $char) =~ y/\n/\n/);
527 say STDERR "!!! FAILED at $char (L$line)";
531 my $val = join '', @bits;
532 my @c = map { ref $_ } @context;
535 say STDERR ' ' x ($lvl-1), "$c returns $val\n" if $OPT_log;
536 # Note that we may have skipped levels, so you can't just pop
537 splice(@context,$lvl);
538 wantarray ? @bits : $val;
541 for my $format (qw
/p5 p6 psq/) {
543 $t =~ s/FORM/$format/g;
548 sub gap
{ my $self = shift;
550 my $beg = $self->{END};
551 my $end = $after->{BEG
};
552 return '' unless $beg && $end;
553 return substr($ORIG, $beg, $end - $beg);
556 sub base_re_quantifier
{ my $self = shift; my $x = shift; my $min = shift;
557 my $qm = $self->{quantmod
}->Str;
559 $qm ||= $::RATCHET ?
':' : '!';
561 return [ $self->{SYM
}, $qm, $x, $min ];
565 { package VAST
::ViaDEEP
;
566 sub emit_psq
{ my $self = shift;
567 $self->_deep->psqexpr;
571 { package VAST
::InfixCall
;
572 sub emit_psq
{ my $self = shift;
573 return DEEP
::call
("infix:<" . $self->{infix
}{SYM
} . ">",
574 map { DEEP
::raw
($_->psq) } $self->kids('args'))->psqexpr;
578 { package VAST
::Str
; our @ISA = 'VAST::Base';
579 sub emit_p5
{ my $self = shift;
580 return $self->{TEXT
};
582 sub emit_p6
{ my $self = shift;
583 return $self->{TEXT
};
587 { package VAST
::Additive
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
588 sub emit_p5
{ my $self = shift;
589 my @t = $self->SUPER::emit_p5
;
590 if ($t[0] eq '*') { # *-1
597 { package VAST
::Adverb
; our @ISA = 'VAST::Base';
598 sub emit_p5
{ my $self = shift;
599 my @t = $self->SUPER::emit_p5
;
601 if ($adv eq ':delete' or $adv eq ':exists') {
603 unshift(@t, $adv . ' ');
610 { package VAST
::apostrophe
; our @ISA = 'VAST::Base';
614 { package VAST
::arglist
; our @ISA = 'VAST::Base';
618 { package VAST
::args
; our @ISA = 'VAST::Base';
619 sub deepn
{ my $self = shift;
620 my $al = $self->{arglist
}[0] // $self->{semiarglist
}{arglist
}[0];
622 $al = $al->{EXPR
} or return;
624 if ($al->isa('VAST::infix__S_Comma')) {
625 return map { DEEP
::raw
($_->psq) } $al->kids('args');
627 return DEEP
::raw
($al->psq);
633 { package VAST
::assertion
; our @ISA = 'VAST::Base';
637 { package VAST
::assertion__S_Bang
; our @ISA = 'VAST::Base';
638 sub re_ast
{ my $self = shift;
639 my $ast = $self->{assertion
} ?
$self->{assertion
}->re_ast
642 RE_assertion
->new(assert
=> '!', re
=> $ast);
647 { package VAST
::assertion__S_Bra
; our @ISA = 'VAST::Base';
648 sub re_ast
{ my $self = shift;
649 my $cclass = $self->Str;
650 $cclass =~ s/\\x([0-9a-fA-F]{3,4})/\\x\{$1\}/g;
651 RE_cclass
->new(text
=> $cclass);
655 { package VAST
::assertion__S_Minus
; our @ISA = 'VAST::assertion__S_Bra';
658 { package VAST
::assertion__S_Plus
; our @ISA = 'VAST::assertion__S_Bra';
662 { package VAST
::assertion__S_Cur_Ly
; our @ISA = 'VAST::Base';
663 sub re_ast
{ my $self = shift;
664 local $::NEEDMATCH
= 0;
665 my $text = $self->{embeddedblock
}{statementlist
}->p5;
666 $text = "my \$M = \$C;\n" . $text if $::NEEDMATCH
;
667 RE_block
->new(body
=> $text, context
=> 'bool');
672 { package VAST
::assertion__S_DotDotDot
; our @ISA = 'VAST::Base';
676 { package VAST
::assertion__S_method
; our @ISA = 'VAST::Base';
677 sub re_ast
{ my $self = shift;
678 my $ast = $self->{assertion
}->re_ast;
685 { package VAST
::assertion__S_name
; our @ISA = 'VAST::Base';
686 sub re_ast
{ my $self = shift;
687 my $name = $self->{longname
}->Str;
689 if ($self->{nibbler
}[0]) {
690 local $::DBA
= $::DBA
;
691 local $::RATCHET
= $::RATCHET
;
692 local $::SIGSPACE
= $::SIGSPACE
;
693 local $::IGNORECASE
= $::IGNORECASE
;
694 return RE_method_re
->new(name
=> $name,
695 re
=> $self->{nibbler
}[0]{"."}->re_ast);
698 if ($self->{assertion
}[0]) {
699 return RE_bindnamed
->new(var
=> $name,
700 atom
=> $self->{assertion
}[0]->re_ast);
703 if ($name eq 'sym' && defined $::ENDSYM
) {
704 return RE_sequence
->new(
705 RE_method
->new(name
=> $name, sym
=> $::SYM
),
706 RE_method
->new(name
=> $::ENDSYM
, nobind
=> 1));
709 my $al = $self->{arglist
}[0];
710 local $::NEEDMATCH
= 0;
711 $al = defined $al ?
"(" . $al->p5 . ")" : undef;
712 RE_method
->new(name
=> $name, ($name eq 'sym' ?
(sym
=> $::SYM
) : ()),
713 rest
=> $al, need_match
=> $::NEEDMATCH
);
718 { package VAST
::assertion__S_Question
; our @ISA = 'VAST::Base';
719 sub re_ast
{ my $self = shift;
720 my $ast = $self->{assertion
} ?
$self->{assertion
}->re_ast
723 RE_assertion
->new(assert
=> '?', re
=> $ast);
728 { package VAST
::atom
; our @ISA = 'VAST::Base';
729 sub re_ast
{ my $self = shift;
730 if (exists $self->{TEXT
}) {
731 RE_string
->new(text
=> $self->{TEXT
});
733 $self->{metachar
}->re_ast;
739 { package VAST
::Autoincrement
; our @ISA = 'VAST::Base';
743 { package VAST
::babble
; our @ISA = 'VAST::Base';
747 { package VAST
::backslash
; our @ISA = 'VAST::Base';
751 { package VAST
::backslash__S_Back
; our @ISA = 'VAST::Base';
755 { package VAST
::backslash__S_d
; our @ISA = 'VAST::Base';
759 { package VAST
::backslash__S_h
; our @ISA = 'VAST::Base';
763 { package VAST
::backslash__S_misc
; our @ISA = 'VAST::Base';
767 { package VAST
::backslash__S_n
; our @ISA = 'VAST::Base';
771 { package VAST
::backslash__S_s
; our @ISA = 'VAST::Base';
775 { package VAST
::backslash__S_stopper
; our @ISA = 'VAST::Base';
779 { package VAST
::backslash__S_t
; our @ISA = 'VAST::Base';
783 { package VAST
::backslash__S_v
; our @ISA = 'VAST::Base';
787 { package VAST
::backslash__S_w
; our @ISA = 'VAST::Base';
791 { package VAST
::backslash__S_x
; our @ISA = 'VAST::Base';
792 sub emit_p5
{ my $self = shift;
793 my @t = $self->SUPER::emit_p5
;
800 { package VAST
::before
; our @ISA = 'VAST::Base';
804 { package VAST
::block
; our @ISA = 'VAST::Base';
808 { package VAST
::blockoid
; our @ISA = 'VAST::Base';
809 sub emit_p5
{ my $self = shift;
810 "{\n" . ::indent
(scalar($self->{statementlist
}->p5), 1) . "}";
815 { package VAST
::capterm
; our @ISA = 'VAST::Base';
819 { package VAST
::cclass_elem
; our @ISA = 'VAST::Base';
823 { package VAST
::Chaining
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
827 { package VAST
::circumfix
; our @ISA = 'VAST::Base';
831 { package VAST
::circumfix__S_Bra_Ket
; our @ISA = 'VAST::Base';
835 { package VAST
::circumfix__S_Cur_Ly
; our @ISA = 'VAST::Base';
839 { package VAST
::circumfix__S_Paren_Thesis
; our @ISA = 'VAST::Base';
843 { package VAST
::circumfix__S_sigil
; our @ISA = 'VAST::Base';
847 { package VAST
::codeblock
; our @ISA = 'VAST::Base';
851 { package VAST
::colonpair
; our @ISA = 'VAST::Base';
852 sub adverbs
{ my $self = shift;
854 if (Scalar
::Util
::blessed
$self->{v
} &&
855 $self->{v
}->isa('VAST::coloncircumfix')) {
856 my $s = $self->{v
}->Str;
857 my $val = $s =~ /^<\s*(.*?)\s*>$/ ?
::unsingle
($1) :
858 $s =~ /^«\s*(.*?)\s*»$/ ?
::undouble
($1) :
859 $s =~ /^\['(.*)'\]$/ ?
::unsingle
($1) :
860 die "Unparsable coloncircumfix";
861 return $self->{k
} => $val;
862 } elsif ($self->{v
} == 1) {
863 return "sym" => $self->{k
};
865 die "Unsupported compile-time adverb " . $self->Str;
871 { package VAST
::Comma
; our @ISA = 'VAST::Base';
876 { package VAST
::comp_unit
; our @ISA = 'VAST::Base';
877 sub emit_p5
{ my $self = shift;
878 "use 5.010;\nuse utf8;\n" . $self->{statementlist
}->p5, "\n";
880 sub emit_p6
{ my $self = shift;
881 substr($ORIG, 0, $self->{statementlist
}{BEG
}),
882 $self->{statementlist
}->p5;
884 sub emit_psq
{ my $self = shift;
886 my $body = $self->{statementlist
}->psq;
887 for (sort keys %::PRELUDE
) {
890 $body = "use \"$fn.psq\";\n$body";
896 { package VAST
::Concatenation
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
900 { package VAST
::Conditional
; our @ISA = 'VAST::Base';
901 sub emit_p5
{ my $self = shift;
902 my @t = $self->SUPER::emit_p5
;
912 { package VAST
::CORE
; our @ISA = 'VAST::Base';
916 { package VAST
::declarator
; our @ISA = 'VAST::Base';
917 sub emit_p5
{ my $self = shift;
918 if ($self->{signature
}) {
919 return "(" . join(", ", map { $_->{param_var
}->Str }
920 $self->{signature
}->kids('parameter')) . ")";
922 return $self->SUPER::emit_p5
;
926 sub emit_psq
{ my $self = shift;
927 if ($self->{variable_declarator
}) {
928 $self->{variable_declarator
}->psq(@_);
929 } elsif ($self->{signature
}) {
930 $self->{signature
}->psq(@_, declaring
=> 1);
931 } elsif ($self->{routine_declarator
}) {
932 $self->{routine_declarator
}->psq(@_);
933 } elsif ($self->{regex_declarator
}) {
934 $self->{regex_declarator
}->psq(@_);
935 } elsif ($self->{type_declarator
}) {
936 $self->{type_declarator
}->psq(@_);
942 { package VAST
::default_value
; our @ISA = 'VAST::Base';
946 { package VAST
::deflongname
; our @ISA = 'VAST::Base';
947 sub adverbs
{ my $self = shift;
948 map { $_->adverbs } $self->kids('colonpair');
953 { package VAST
::def_module_name
; our @ISA = 'VAST::Base';
957 { package VAST
::desigilname
; our @ISA = 'VAST::Base';
961 { package VAST
::dotty
; our @ISA = 'VAST::Base';
965 { package VAST
::dotty__S_Dot
; our @ISA = 'VAST::Methodcall';
969 { package VAST
::SYM_dotty__S_Dot
; our @ISA = 'VAST::Base';
973 { package VAST
::dottyop
; our @ISA = 'VAST::Base';
977 { package VAST
::eat_terminator
; our @ISA = 'VAST::Base';
981 { package VAST
::escape
; our @ISA = 'VAST::Base';
985 { package VAST
::escape__S_At
; our @ISA = 'VAST::Base';
989 { package VAST
::escape__S_Back
; our @ISA = 'VAST::Base';
993 { package VAST
::escape__S_Dollar
; our @ISA = 'VAST::Base';
997 { package VAST
::EXPR
; our @ISA = 'VAST::Base';
1001 { package VAST
::fatarrow
; our @ISA = 'VAST::Base';
1005 { package VAST
::fulltypename
; our @ISA = 'VAST::Base';
1009 { package VAST
::hexint
; our @ISA = 'VAST::Base';
1013 { package VAST
::ident
; our @ISA = 'VAST::Base';
1017 { package VAST
::identifier
; our @ISA = 'VAST::Base';
1021 { package VAST
::index; our @ISA = 'VAST::Base';
1026 { package VAST
::infix
; our @ISA = 'VAST::Base';
1029 { package VAST
::infix_prefix_meta_operator__S_Bang
; our @ISA = 'VAST::Base';
1030 sub emit_p5
{ my $self = shift;
1031 my @t = $self->SUPER::emit_p5
;
1032 $t[1] = '~' if $t[1] eq '=~';
1033 $t[1] = '=' if $t[1] eq '==';
1034 @t = ('ne', '') if $t[1] eq 'eq';
1039 { package VAST
::SYM_infix__S_ColonEqual
; our @ISA = 'VAST::Item_assignment';
1040 sub emit_p5
{ my $self = shift;
1041 my @t = $self->SUPER::emit_p5
;
1042 $t[0] = '='; # XXX oversimplified
1047 { package VAST
::SYM_infix__S_ColonColonEqual
; our @ISA = 'VAST::Item_assignment';
1048 sub emit_p5
{ my $self = shift;
1049 my @t = $self->SUPER::emit_p5
;
1050 $t[0] = '='; # XXX oversimplified
1056 { package VAST
::infixish
; our @ISA = 'VAST::Base';
1060 { package VAST
::SYM_infix__S_PlusAmp
; our @ISA = 'VAST::Multiplicative';
1061 sub emit_p5
{ my $self = shift;
1062 my @t = $self->SUPER::emit_p5
;
1068 { package VAST
::SYM_infix__S_eqv
; our @ISA = 'VAST::Chaining';
1069 sub emit_p5
{ my $self = shift;
1070 my @t = $self->SUPER::emit_p5
;
1076 { package VAST
::SYM_infix__S_leg
; our @ISA = 'VAST::Structural_infix';
1077 sub emit_p5
{ my $self = shift;
1078 my @t = $self->SUPER::emit_p5
;
1084 { package VAST
::SYM_infix__S_EqualEqualEqual
; our @ISA = 'VAST::Chaining';
1085 sub emit_p5
{ my $self = shift;
1086 my @t = $self->SUPER::emit_p5
;
1087 $t[0] = '=='; # only correct for objects (and ints)
1092 { package VAST
::SYM_infix__S_orelse
; our @ISA = 'VAST::Loose_or';
1093 sub emit_p5
{ my $self = shift;
1094 my @t = $self->SUPER::emit_p5
;
1100 { package VAST
::SYM_infix__S_andthen
; our @ISA = 'VAST::Loose_and';
1101 sub emit_p5
{ my $self = shift;
1102 my @t = $self->SUPER::emit_p5
;
1108 { package VAST
::SYM_infix__S_PlusVert
; our @ISA = 'VAST::Additive';
1109 sub emit_p5
{ my $self = shift;
1110 my @t = $self->SUPER::emit_p5
;
1117 { package VAST
::SYM_infix__S_Tilde
; our @ISA = 'VAST::Concatenation';
1118 sub emit_p5
{ my $self = shift;
1119 my @t = $self->SUPER::emit_p5
;
1126 { package VAST
::SYM_infix__S_TildeTilde
; our @ISA = 'VAST::Chaining';
1127 sub emit_p5
{ my $self = shift;
1128 my @t = $self->SUPER::emit_p5
;
1134 { package VAST
::SYM_infix__S_TildeVert
; our @ISA = 'VAST::Additive';
1135 sub emit_p5
{ my $self = shift;
1136 my @t = $self->SUPER::emit_p5
;
1143 { package VAST
::integer
; our @ISA = 'VAST::Base';
1147 { package VAST
::Item_assignment
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
1151 { package VAST
::Junctive_or
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
1155 { package VAST
::label
; our @ISA = 'VAST::Base';
1159 { package VAST
::lambda
; our @ISA = 'VAST::Base';
1160 sub emit_p5
{ my $self = shift;
1161 my @t = $self->SUPER::emit_p5
;
1168 { package VAST
::left
; our @ISA = 'VAST::Base';
1172 { package VAST
::List_assignment
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
1176 { package VAST
::litchar
; our @ISA = 'VAST::Base';
1180 { package VAST
::longname
; our @ISA = 'VAST::Base';
1181 sub adverbs
{ my $self = shift;
1182 map { $_->adverbs } $self->kids('colonpair');
1187 { package VAST
::Loose_and
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
1191 { package VAST
::Loose_or
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
1195 { package VAST
::Loose_unary
; our @ISA = 'VAST::Base';
1199 { package VAST
::metachar
; our @ISA = 'VAST::Base';
1200 sub re_ast
{ my $self = shift;
1201 RE_meta
->new(text
=> $self->Str);
1206 { package VAST
::metachar__S_Back
; our @ISA = 'VAST::metachar';
1207 sub re_ast
{ my $self = shift;
1208 RE_meta
->new(text
=> $self->Str, min
=> 1);
1213 { package VAST
::metachar__S_Bra_Ket
; our @ISA = 'VAST::Base';
1214 sub re_ast
{ my $self = shift;
1215 local $::DBA
= $::DBA
;
1216 local $::RATCHET
= $::RATCHET
;
1217 local $::SIGSPACE
= $::SIGSPACE
;
1218 local $::IGNORECASE
= $::IGNORECASE
;
1221 my $bodyast = $self->{nibbler
}{"."}->re_ast;
1222 RE_bracket
->new(decl
=> \@
::DECLAST
, re
=> $bodyast);
1227 { package VAST
::metachar__S_Caret
; our @ISA = 'VAST::metachar';
1231 { package VAST
::metachar__S_CaretCaret
; our @ISA = 'VAST::metachar';
1234 { package VAST
::metachar__S_ColonColon
; our @ISA = 'VAST::metachar';
1237 { package VAST
::metachar__S_ColonColonColon
; our @ISA = 'VAST::metachar';
1240 { package VAST
::metachar__S_ColonColonKet
; our @ISA = 'VAST::metachar';
1244 { package VAST
::metachar__S_Cur_Ly
; our @ISA = 'VAST::Base';
1245 sub re_ast
{ my $self = shift;
1246 local $::NEEDMATCH
= 0;
1247 my $text = $self->{embeddedblock
}{statementlist
}->p5;
1248 $text = "my \$M = \$C;\n" . $text if $::NEEDMATCH
;
1249 RE_block
->new(body
=> $text, context
=> 'void');
1254 { package VAST
::metachar__S_Dollar
; our @ISA = 'VAST::metachar';
1258 { package VAST
::metachar__S_DollarDollar
; our @ISA = 'VAST::metachar';
1262 { package VAST
::metachar__S_Dot
; our @ISA = 'VAST::metachar';
1263 sub re_ast
{ my $self = shift;
1264 RE_meta
->new(text
=> $self->Str, min
=> 1);
1269 { package VAST
::metachar__S_Double_Double
; our @ISA = 'VAST::Base';
1270 sub re_ast
{ my $self = shift;
1271 my $text = ::undouble
($self->{quote
}{nibble
}->Str);
1272 RE_double
->new(text
=> $text);
1277 { package VAST
::metachar__S_Lt_Gt
; our @ISA = 'VAST::Base';
1278 sub re_ast
{ my $self = shift;
1279 $self->{assertion
}->re_ast;
1284 { package VAST
::metachar__S_mod
; our @ISA = 'VAST::Base';
1285 sub re_ast
{ my $self = shift;
1286 $self->{mod_internal
}->re_ast;
1291 { package VAST
::metachar__S_Nch
; our @ISA = 'VAST::metachar';
1295 { package VAST
::metachar__S_Paren_Thesis
; our @ISA = 'VAST::Base';
1296 sub re_ast
{ my $self = shift;
1297 local $::DBA
= $::DBA
;
1298 local $::RATCHET
= $::RATCHET
;
1299 local $::SIGSPACE
= $::SIGSPACE
;
1300 local $::IGNORECASE
= $::IGNORECASE
;
1303 my $bodyast = $self->{nibbler
}{"."}->re_ast;
1304 # XXX STD gimme5 disables binding to $0 in $<foo> = (bar)
1305 my $inner = RE_paren
->new(decl
=> \@
::DECLAST
, re
=> $bodyast);
1306 $::PARSENAME ?
$inner : RE_bindpos
->new(var
=> $::PAREN
++, atom
=> $inner)
1311 { package VAST
::metachar__S_qw
; our @ISA = 'VAST::Base';
1312 sub re_ast
{ my $self = shift;
1314 my @elems = split(' ', $self->{circumfix
}{nibble
}->Str);
1316 my $l = ::min
(1_000_000_000
, map { length } @elems);
1317 RE_qw
->new(min
=> $l, text
=> $self->Str);
1322 { package VAST
::metachar__S_sigwhite
; our @ISA = 'VAST::Base';
1323 sub re_ast
{ my $self = shift;
1325 RE_method
->new(name
=> 'ws', nobind
=> 1) :
1331 { package VAST
::metachar__S_Single_Single
; our @ISA = 'VAST::Base';
1332 sub re_ast
{ my $self = shift;
1333 my $text = ::unsingle
($self->{quote
}{nibble
}->Str);
1334 RE_string
->new(text
=> $text);
1339 { package VAST
::metachar__S_var
; our @ISA = 'VAST::Base';
1340 sub re_ast
{ my $self = shift;
1341 # We don't un6 because some things need to un6 specially - backrefs
1342 if ($self->{binding
}) {
1343 local $::PARSENAME
= 1;
1344 $self->{SYM
} =~ /^\$<(.*)>$/ or die "Can't bind backref to " . $self->{SYM
};
1345 RE_bindnamed
->new(var
=> $1, atom
=>
1346 $self->{binding
}{quantified_atom
}->re_ast);
1348 RE_var
->new(var
=> $self->{termish
}->p5);
1354 { package VAST
::Methodcall
; our @ISA = 'VAST::Base';
1355 sub emit_p5
{ my $self = shift;
1356 my @t = $self->SUPER::emit_p5
;
1358 my $first = shift @t;
1359 my $second = join '', @t;
1360 @t = ($first,$second);
1362 if ($t[1] eq '.pos') { $t[1] = '.<_pos>'; }
1363 $t[1] =~ s/^(\.?)<(.*)>$/$1\{'$2'\}/;
1364 if ($t[0] =~ /^[@%]/) {
1365 if ($t[1] =~ s/^\.?([[{])/$1/) {
1367 substr($t[0],0,1) = '@';
1370 substr($t[0],0,1) = '$';
1375 elsif ($t[1] =~ /^[[{]/) {
1376 $t[1] =~ s/^([[{])/.$1/;
1378 elsif ($t[0] =~ s/^&(\w+)/\$$1/) {
1379 $t[1] =~ s/^\(/->(/;
1382 my $t = join('', @t);
1383 $t =~ s/^(.*\S)\s*:(delete|exists)/$2 $1/;
1384 # print STDERR ::Dump(\@t);
1390 { package VAST
::method_def
; our @ISA = 'VAST::Base';
1391 sub emit_p5
{ my $self = shift;
1392 my $name = $self->{longname
} ?
$self->{longname
}->p5 . " " : "";
1393 my $sig = $self->{multisig
}[0] ?
$self->{multisig
}[0]->p5 : "";
1394 my $body = $self->{blockoid
}{statementlist
}->p5;
1396 if ($::MULTINESS
eq 'multi') {
1397 $::MULTIMETHODS
{$name} .= <<EOT
1400 return scalar do { # work around #38809
1403 . ::indent
($sig . $body, 2) . <<EOT
1411 # not quite right, this should be an expression
1412 ($name eq 'EXPR' ?
# XXX STD
1413 "sub EXPR__PEEK { \$_[0]->_AUTOLEXpeek(\'EXPR\',\$retree) }\n" : '').
1414 "sub " . $name . "{\n" .
1415 ::indent
("no warnings 'recursion';\nmy \$self = shift;\n" .
1422 { package VAST
::methodop
; our @ISA = 'VAST::Base';
1426 { package VAST
::modifier_expr
; our @ISA = 'VAST::Base';
1430 { package VAST
::mod_internal
; our @ISA = 'VAST::Base';
1434 { package VAST
::mod_internal__S_p6adv
; our @ISA = 'VAST::Base';
1435 sub re_ast
{ my $self = shift;
1436 my $key = $self->{quotepair
}{k
};
1438 if ($key eq 'dba') {
1439 $::DBA
= eval ($self->{quotepair
}{circumfix
}[0]->Str);
1440 } elsif ($key eq 'lang') {
1441 my $lang = $self->{quotepair
}{circumfix
}[0]->p5;
1442 return RE_decl
->new(body
=> <<BODY);
1443 my \$newlang = $lang;
1444 \$C = bless(\$C, (ref(\$newlang) || \$newlang));
1447 die "unhandled internal adverb $key";
1455 { package VAST
::mod_internal__S_ColonBangs
; our @ISA = 'VAST::Base';
1459 { package VAST
::mod_internal__S_Coloni
; our @ISA = 'VAST::Base';
1460 sub re_ast
{ my $self = shift;
1466 { package VAST
::mod_internal__S_Colonr
; our @ISA = 'VAST::Base';
1467 sub re_ast
{ my $self = shift;
1474 { package VAST
::mod_internal__S_Colonmy
; our @ISA = 'VAST::Base';
1475 sub re_ast
{ my $self = shift;
1476 local $::NEEDMATCH
= 0;
1477 my $text = $self->{statement
}->p5 . ";";
1478 $text = "my \$M = \$C;\n" . $text if $::NEEDMATCH
;
1480 push @
::DECLAST
, RE_decl
->new(body
=> $text);
1486 { package VAST
::mod_internal__S_Colons
; our @ISA = 'VAST::Base';
1487 sub re_ast
{ my $self = shift;
1494 { package VAST
::mod_internal__S_ColonBangs
; our @ISA = 'VAST::Base';
1495 sub re_ast
{ my $self = shift;
1502 { package VAST
::module_name
; our @ISA = 'VAST::Base';
1506 { package VAST
::module_name__S_normal
; our @ISA = 'VAST::Base';
1510 { package VAST
::morename
; our @ISA = 'VAST::Base';
1514 { package VAST
::multi_declarator
; our @ISA = 'VAST::Base';
1515 sub emit_psq
{ my $self = shift;
1516 if ($self->{declarator
}) {
1517 $self->{declarator
}->psq(@_, multiness
=> $self->{SYM
});
1519 $self->{routine_def
}->psq(@_, multiness
=> $self->{SYM
});
1525 { package VAST
::multi_declarator__S_multi
; our @ISA = 'VAST::multi_declarator';
1526 sub emit_p5
{ my $self = shift;
1527 local $::MULTINESS
= 'multi';
1533 { package VAST
::multi_declarator__S_null
; our @ISA = 'VAST::multi_declarator';
1537 { package VAST
::multi_declarator__S_proto
; our @ISA = 'VAST::multi_declarator';
1538 sub emit_p5
{ my $self = shift;
1539 local $::MULTINESS
= 'proto';
1545 { package VAST
::Multiplicative
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
1548 # We don't currently do MMD so no need for later sigs
1549 { package VAST
::multisig
; our @ISA = 'VAST::Base';
1550 sub emit_p5
{ my $self = shift;
1551 $self->{signature
}[0]->p5;
1556 { package VAST
::name
; our @ISA = 'VAST::Base';
1560 { package VAST
::named_param
; our @ISA = 'VAST::Base';
1564 { package VAST
::Named_unary
; our @ISA = 'VAST::Base';
1567 { package VAST
::nibbler
; our @ISA = 'VAST::Base';
1571 { package VAST
::nofun
; our @ISA = 'VAST::Base';
1575 { package VAST
::normspace
; our @ISA = 'VAST::Base';
1580 { package VAST
::nulltermish
; our @ISA = 'VAST::Base';
1584 { package VAST
::number
; our @ISA = 'VAST::Base';
1585 sub emit_psq
{ my $self = shift;
1586 die "unsupported literal format" unless $self->{integer
}{decint
};
1587 my $str = $self->{integer
}{decint
}->Str;
1594 { package VAST
::number__S_numish
; our @ISA = 'VAST::Base';
1598 { package VAST
::numish
; our @ISA = 'VAST::Base';
1602 { package VAST
::opener
; our @ISA = 'VAST::Base';
1606 { package VAST
::package_declarator
; our @ISA = 'VAST::Base';
1607 sub emit_psq
{ my $self = shift;
1608 local $::PKGDECL
= $self->{SYM
};
1609 $self->{package_def
}->psq;
1614 { package VAST
::package_declarator__S_class
; our @ISA = 'VAST::package_declarator';
1615 sub emit_p5
{ my $self = shift;
1616 local $::PKGDECL
= 'class';
1617 $self->{package_def
}->p5;
1622 { package VAST
::package_declarator__S_grammar
; our @ISA = 'VAST::package_declarator';
1623 sub emit_p5
{ my $self = shift;
1624 local $::PKGDECL
= 'grammar';
1625 $self->{package_def
}->p5;
1630 { package VAST
::package_declarator__S_role
; our @ISA = 'VAST::package_declarator';
1631 sub emit_p5
{ my $self = shift;
1632 local $::PKGDECL
= 'role';
1633 $self->{package_def
}->p5;
1637 { package VAST
::package_declarator__S_knowhow
; our @ISA = 'VAST::package_declarator';
1638 sub emit_p5
{ my $self = shift;
1639 local $::PKGDECL
= 'knowhow';
1640 $self->{package_def
}->p5;
1645 { package VAST
::package_def
; our @ISA = 'VAST::Base';
1646 sub module_name
{ my $self = shift;
1647 my $def_module_name = $self->{longname
}[0]{name
}->Str;
1648 if ($self->{decl
}{inpkg
}[0] =~ /GLOBAL::(.*)/) {
1650 for ($mod) { s/::::/::/g; s/^:://; s/::$//; } # XXX STD misparse?
1651 $::OUR
{$def_module_name} = "${mod}::$def_module_name";
1652 $def_module_name = "${mod}::$def_module_name";
1656 sub superclasses
{ my $self = shift;
1658 for (@
{$self->{trait
}}) {
1660 push(@extends, $t =~ /^is\s+(\S+)/);
1662 @extends = map { $::OUR
{$_} // $_ } @extends;
1663 @extends = 'Cursor' if $::PKGDECL
eq 'grammar' && !@extends;
1666 sub roles
{ my $self = shift;
1668 for (@
{$self->{trait
}}) {
1670 push(@does, $t =~ /^does\s+(\S+)/);
1672 @does = map { $::OUR
{$_} // $_ } @does;
1674 sub emit_p5_header
{ my $self = shift;
1678 my $meta = $::PKGDECL
eq 'role' ?
'Moose::Role' : 'Moose';
1681 use $meta ':all' => { -prefix => "moose_" };
1685 $header .= <<"END" for $self->superclasses;
1686 moose_extends('$_');
1689 $header .= <<"END" for $self->roles;
1693 if (! $self->roles) {
1694 $header .= "our \$ALLROLES = { '$::PKG', 1 };\n";
1697 $header .= "our \$REGEXES = {\n";
1698 $::PROTORX_HERE
{ALL
} = [ sort keys %::OVERRIDERX
];
1699 for my $p (sort keys %::PROTORX_HERE
) {
1700 $header .= " $p => [ qw/" . join(" ",
1701 @
{ $::PROTORX_HERE
{$p} }) . "/ ],\n";
1703 $header .= "};\n\n";
1707 no warnings 'qw', 'recursion';
1710 \$DB::deep = \$DB::deep = 1000; # suppress used-once warning
1714 \$SIG{__WARN__} = sub { die \@_," statement started at line ", 'Cursor'->lineof(\$::LASTSTATE), "\n" } if \$::DEBUG;
1720 sub emit_p5
{ my $self = shift;
1721 my $block = $self->{blockoid
}{statementlist
} // $self->{statementlist
};
1722 local $::RETREE
= {};
1723 local $::PKG
= $self->module_name;
1724 local $::MULTIRX_SEQUENCE
= 0;
1725 local %::PROTORX_HERE
;
1726 local %::OVERRIDERX
;
1727 local %::MULTIMETHODS
;
1728 my $body3 = $block->p5;
1729 my $body1 = $self->emit_p5_header;
1733 $body2 = "\$retree = YAML::XS::Load(Encode::encode_utf8(<<'RETREE_END'));\n" .
1734 Encode
::decode_utf8
(::Dump
($::RETREE
)) . "RETREE_END\n";
1736 my $body = $body1 . $body2 . $body3;
1739 if (my ($sig) = $self->kids('signature')) {
1740 my @parm = map { $_->Str } $sig->kids('parameter');
1741 my $plist = join ", ", @parm;
1743 $body = <<EOT . $body;
1745 require "mangle.pl";
1747 sub __instantiate__ { my \$self = shift;
1749 my \$mangle = ::mangle($plist);
1750 my \$mixin = "${name}::" . \$mangle;
1751 return \$mixin if \$INSTANTIATED{\$mixin}++;
1752 ::deb(" instantiating \$mixin") if \$::DEBUG & DEBUG::mixins;
1753 my \$eval = "package \$mixin" . q{;
1754 sub _PARAMS { { ${\ join(", ", map { "'$_' => $_" } @parm) } } }
1764 $body = "package $name;\n" . $body;
1767 my $finalmulti = '';
1769 for my $mm (sort keys %::MULTIMETHODS
) {
1770 $finalmulti .= "moose_around $mm => sub {\n my \$orig = shift;\n no warnings 'recursion';\n" .
1771 ::indent
($::MULTIMETHODS
{$mm}, 1) . <<EOFINAL
1779 "{ $body $finalmulti 1; }";
1782 sub psq_finish_multis
{ my $self = shift;
1783 die "multis not yet implemented for psq";
1786 sub psq_retree
{ my $self = shift;
1787 die "LTM not yet implemented for psq";
1790 sub psq_parameterized
{ my $self = shift;
1791 die "roles not yet implemented for psq";
1794 sub psq_plain
{ my $self = shift; my $body = shift;
1795 die "roles not yet implemented for psq"
1796 if $::PKGDECL
eq 'role' or $self->roles;
1797 die "multiple inheritance not available in psq"
1798 if $self->superclasses > 1;
1799 my ($is) = $self->superclasses;
1800 "class " . $::PKG
. " " . ($is ?
"is $is " : "") .
1801 "{\n" . ::indent
($body) . "\n}";
1804 sub emit_psq
{ my $self = shift;
1805 my $block = $self->{blockoid
}{statementlist
} // $self->{statementlist
};
1806 local $::RETREE
= {};
1807 local $::PKG
= $self->module_name;
1808 local $::MULTIRX_SEQUENCE
= 0;
1809 local %::MULTIMETHODS
;
1811 my $body = $block->psq;
1812 $body = $body . $self->psq_finish_multis
1814 $body = $self->psq_retree . $body
1817 if (my ($sig) = $self->kids('signature')) {
1818 $body = $self->psq_parameterized($body,
1819 map { $_->Str } $sig->kids('parameter'));
1821 $body = $self->psq_plain($body);
1828 # Perl5 invocations don't carry enough context for a proper binder; in
1829 # particular we can't distinguish named stuff from positionals
1830 { package VAST
::parameter
; our @ISA = 'VAST::Base';
1831 sub emit_p5
{ my $self = shift;
1832 my $pvar = $self->{param_var
};
1836 my $np = $self->{named_param
};
1838 $pvar = $np->{param_var
};
1839 push @names, $np->{name
} ?
$np->{name
}{TEXT
}
1840 : $np->{param_var
}{name
}[0]{TEXT
};
1841 $np = $np->{named_param
};
1843 $posit = 1 unless @names;
1844 my $pname = $pvar->{name
}[0]{TEXT
};
1845 my $sigil = $pvar->{sigil
}{SYM
};
1846 my $twigil = $pvar->{twigil
}[0] ?
$pvar->{twigil
}[0]{SYM
} : '';
1847 my ($dv) = $self->kids('default_value');
1851 if (($self->{quant
} eq '!' || $self->{quant
} eq '' && $posit) && !$dv) {
1852 $check .= $::MULTINESS
eq 'multi' ?
"last " :
1853 "die 'Required argument $pname omitted' ";
1854 $check .= $posit ?
'unless @_'
1855 : 'unless ' . join(" || ", map ("exists \$args{$_}", @names));
1860 my $value = "undef";
1862 $value = $dv->{"."}->p5;
1865 $value = '@_ ? shift() : ' . $value;
1867 for (reverse @names) {
1868 $value = "exists \$args{$_} ? delete \$args{$_} : $value";
1870 if ($self->{quant
} eq '*') {
1871 $value = ($sigil eq '%') ?
'%args' : '@_';
1872 $posit = 0 if $sigil eq '%';
1875 # Store it somewhere useful
1876 if ($twigil eq '*' && $pname eq 'endsym') {
1877 # XXX this optimization needs to be refactored, I think
1878 my ($dv) = $self->kids('default_value');
1879 $::ENDSYM
= $dv->{"."}->Str;
1880 $::ENDSYM
= substr($::ENDSYM
, 1, length($::ENDSYM
)-2);
1885 if ($twigil eq '*') {
1886 $assn = "local ${sigil}::${pname} = $value";
1888 $assn = "my ${sigil}${pname} = $value";
1891 (!$posit), ($check . $assn);
1896 { package VAST
::param_sep
; our @ISA = 'VAST::Base';
1900 { package VAST
::param_var
; our @ISA = 'VAST::Base';
1904 { package VAST
::pblock
; our @ISA = 'VAST::Base';
1908 { package VAST
::pod_comment
; our @ISA = 'VAST::Base';
1912 { package VAST
::POST
; our @ISA = 'VAST::Base';
1916 { package VAST
::postcircumfix
; our @ISA = 'VAST::Base';
1920 { package VAST
::SYM_postcircumfix__S_Lt_Gt
; our @ISA = 'VAST::Base';
1921 sub emit_p5
{ my $self = shift;
1922 my @t = $self->SUPER::emit_p5
;
1930 { package VAST
::postfix
; our @ISA = 'VAST::Base';
1934 { package VAST
::postop
; our @ISA = 'VAST::Base';
1938 { package VAST
::PRE
; our @ISA = 'VAST::Base';
1942 { package VAST
::prefix
; our @ISA = 'VAST::Base';
1946 { package VAST
::SYM_prefix__S_Plus
; our @ISA = 'VAST::Symbolic_unary';
1947 sub emit_p5
{ my $self = shift;
1948 my @t = $self->SUPER::emit_p5
;
1954 { package VAST
::SYM_prefix__S_Vert
; our @ISA = 'VAST::Symbolic_unary';
1955 sub emit_p5
{ my $self = shift;
1961 { package VAST
::prefix__S_temp
; our @ISA = 'VAST::Base';
1962 sub emit_p5
{ my $self = shift;
1963 my $arg = $self->{arg
}->p5;
1964 "local $arg = $arg";
1969 { package VAST
::quantified_atom
; our @ISA = 'VAST::Base';
1970 sub re_ast
{ my $self = shift;
1971 if (!@
{$self->{quantifier
}}) {
1972 return $self->{atom
}->re_ast;
1975 if ($self->{quantifier
}[0]{SYM
} eq '~') {
1976 return $self->_tilde;
1979 if ($self->{quantifier
}[0]{SYM
} eq ':') {
1980 my $ast = $self->{atom
}->re_ast;
1985 my $quant = $self->{quantifier
}[0]->re_quantifier;
1987 my $ast = $self->{atom
}->re_ast;
1989 my $r = RE_quantified_atom
->new(atom
=> $ast, quant
=> $quant);
1990 $r->{r
} = 0 if $quant->[1] ne ':';
1994 sub _tilde
{ my $self = shift;
1995 my $opener = $self->{atom
}->re_ast;
1996 my $closer = $self->{quantifier
}[0]{quantified_atom
}[0]->re_ast;
1997 my $inner = $self->{quantifier
}[0]{quantified_atom
}[1]->re_ast;
1999 my $strcloser = $closer->{text
}; #XXX
2002 local \$::GOAL = "${\ quotemeta $strcloser}";
2005 if ($strcloser !~ /^[])}]$/) {
2007 my \$newlang = \$C->unbalanced(\$::GOAL);
2008 \$C = bless(\$C, (ref(\$newlang) || \$newlang));
2013 push @expn, $opener;
2014 # XXX STD break LTM for gimme5 bug-compatibility
2015 push @expn, RE_block
->new(body
=> '', context
=> 'void');
2017 push @expn, RE_bracket
->new(decl
=> [], re
=> RE_first
->new(
2018 RE_string
->new(text
=> $strcloser),
2019 RE_method
->new(name
=> 'FAILGOAL', nobind
=> 1,
2020 rest
=> "(\$::GOAL, '$::DBA', \$goalpos)")));
2022 RE_bracket
->new(decl
=> [RE_decl
->new(body
=> $begin)], re
=>
2023 RE_sequence
->new(@expn));
2027 { package VAST
::quant_atom_list
; our @ISA = 'VAST::Base';
2028 sub re_ast
{ my $self = shift;
2029 my @kids = map { $_->re_ast } $self->kids("quantified_atom");
2030 RE_sequence
->new(@kids);
2035 { package VAST
::quantifier
; our @ISA = 'VAST::Base';
2039 { package VAST
::quantifier__S_Plus
; our @ISA = 'VAST::Base';
2040 sub re_quantifier
{ my $self = shift;
2041 $self->base_re_quantifier("", 1);
2046 { package VAST
::quantifier__S_Question
; our @ISA = 'VAST::Base';
2047 sub re_quantifier
{ my $self = shift;
2048 $self->base_re_quantifier("", 0);
2053 { package VAST
::quantifier__S_Star
; our @ISA = 'VAST::Base';
2054 sub re_quantifier
{ my $self = shift;
2055 $self->base_re_quantifier("", 0);
2060 { package VAST
::quantifier__S_StarStar
; our @ISA = 'VAST::Base';
2061 sub re_quantifier
{ my $self = shift;
2062 my ($range) = $self->Str =~ /.*(\d+\.\.\d+)$/;
2063 $self->base_re_quantifier($self->{embeddedblock
} //
2064 $range // $self->{quantified_atom
}->re_ast, 1);
2069 { package VAST
::quantmod
; our @ISA = 'VAST::Base';
2073 { package VAST
::quibble
; our @ISA = 'VAST::Base';
2078 { package VAST
::quote
; our @ISA = 'VAST::Base';
2079 sub emit_p5
{ my $self = shift;
2080 my @t = $self->SUPER::emit_p5
;
2082 # print STDERR ::Dump(\@t);
2087 { package VAST
::quote__S_Double_Double
; our @ISA = 'VAST::Base';
2091 { package VAST
::circumfix__S_Fre_Nch
; our @ISA = 'VAST::Base';
2092 sub emit_p5
{ my $self = shift;
2093 '[split(/ /, "' . $self->{nibble
}->p5 . '", -1)]'
2098 { package VAST
::quote__S_Lt_Gt
; our @ISA = 'VAST::Base';
2102 { package VAST
::quotepair
; our @ISA = 'VAST::Base';
2106 { package VAST
::quote__S_s
; our @ISA = 'VAST::Base';
2110 { package VAST
::quote__S_Single_Single
; our @ISA = 'VAST::Base';
2111 sub emit_psq
{ my $self = shift;
2112 my $str = $self->Str;
2118 { package VAST
::quote__S_Slash_Slash
; our @ISA = 'VAST::Base';
2122 { package VAST
::regex_block
; our @ISA = 'VAST::Base';
2126 { package VAST
::regex_declarator
; our @ISA = 'VAST::Base';
2130 { package VAST
::regex_declarator__S_regex
; our @ISA = 'VAST::Base';
2131 sub emit_p5
{ my $self = shift;
2132 local $::RATCHET
= 0;
2133 local $::SIGSPACE
= 0;
2134 local $::REGEX_DECLARATOR
= 'regex';
2135 my $comment = substr($ORIG, $self->{BEG
},100);
2136 $comment =~ s/\n.*//s;
2137 "## $comment\n" . $self->{regex_def
}->p5;
2142 { package VAST
::regex_declarator__S_rule
; our @ISA = 'VAST::Base';
2143 sub emit_p5
{ my $self = shift;
2144 local $::RATCHET
= 1;
2145 local $::SIGSPACE
= 1;
2146 local $::REGEX_DECLARATOR
= 'rule';
2147 my $comment = substr($ORIG, $self->{BEG
},100);
2148 $comment =~ s/\n.*//s;
2149 "## $comment\n" . $self->{regex_def
}->p5;
2154 { package VAST
::regex_declarator__S_token
; our @ISA = 'VAST::Base';
2155 sub emit_p5
{ my $self = shift;
2156 local $::RATCHET
= 1;
2157 local $::SIGSPACE
= 0;
2158 local $::REGEX_DECLARATOR
= 'token';
2159 my $comment = substr($ORIG, $self->{BEG
}, 100);
2160 $comment =~ s/\n.*//s;
2161 "## $comment\n" . $self->{regex_def
}->p5;
2165 { package VAST
::regex_def
; our @ISA = 'VAST::Base';
2166 sub re_ast
{ my $self = shift;
2167 RE_ast
->new(kind
=> $::REGEX_DECLARATOR
, decl
=> \@
::DECLAST
,
2168 re
=> $self->{regex_block
}{nibble
}{"."}->re_ast);
2170 sub protoregex
{ my $self = shift; my $name = shift;
2171 $::PROTO
->{$name} = 1;
2172 $::RETREE
->{$name . ":*"} = { dic
=> $::PKG
};
2173 $::PROTOSIG
->{$name} = ($self->kids("signature"))[0];
2175 sub ${name}__PEEK { \$_[0]->_AUTOLEXpeek('$name:*',\$retree); }
2180 local \$::CTX = \$self->callm() if \$::DEBUG & DEBUG::trace_call;
2182 my \$C = \$self->cursor_xact('RULE $name');
2183 my \$S = \$C->{'_pos'};
2190 if (my \$fate = \$C->{'_fate'}) {
2191 if (\$fate->[1] eq '$name') {
2192 \$C->deb("Fate passed to $name: ", ::fatestr(\$fate)) if \$::DEBUG & DEBUG::fates;
2193 (\$C->{'_fate'}, \$tag, \$try) = \@\$fate;
2198 \$x = 'ALTLTM $name';
2202 \$x = 'ALTLTM $name';
2204 my \$C = \$C->cursor_xact(\$x);
2205 my \$xact = \$C->{_xact};
2210 \$relex //= \$C->cursor_fate('$::PKG', '$name:*', \$retree);
2211 \@try = \$relex->(\$C) or last;
2213 \$try = shift(\@try) // next;
2216 (\$C->{'_fate'}, \$tag, \$try) = \@\$try; # next candidate fate
2219 \$C->deb("$name trying \$tag \$try") if \$::DEBUG & DEBUG::try_processing;
2220 push \@gather, \$C->\$try(\@_);
2222 last if \$xact->[-2]; # committed?
2224 \$self->_MATCHIFYr(\$S, "$name", \@gather);
2231 sub emit_p5
{ my $self = shift;
2232 my $name = $self->{deflongname
}[0]{name
}->Str;
2233 $::OVERRIDERX
{$name} = 1;
2234 if (defined $::MULTINESS
&& $::MULTINESS
eq 'proto') {
2235 return $self->protoregex($name);
2238 my %adv = $self->{deflongname
}[0]->adverbs;
2239 local $::SYM
= $adv{sym
};
2242 local $::PLURALITY
= 1;
2245 local $::NEEDORIGARGS
= 0;
2246 local $::IGNORECASE
= 0;
2250 my $spcsig = $self->kids('signature') ?
2251 (($self->kids('signature'))[0])->p5 : '';
2252 my $defsig = $::PROTO
&& $::PROTOSIG
->{$name}
2253 ?
$::PROTOSIG
->{$name}->p5 : '';
2254 if (defined $adv{sym
}) {
2255 $p5name = sprintf "%s__S_%03d%s", $name, $::MULTIRX_SEQUENCE
++,
2256 ::mangle
(split " ", $adv{sym
});
2257 push @
{$::PROTORX_HERE
{$name}}, $p5name . "__PEEK";
2259 local $::DBA
= $name;
2260 local $::DECL_CLASS
= $::PKG
;
2261 local $::NAME
= $p5name;
2263 my $ast = $self->re_ast->optimize;
2265 $::RETREE
->{$p5name} = $ast;
2267 my $urbody = $ast->walk;
2268 say STDERR
"<<< " . $urbody . ": " . $urbody->p5expr if $OPT_log;
2269 my ($body, $ratchet) = $urbody->uncut;
2270 say STDERR
"<<< " . $body . ": " . $body->p5expr if $OPT_log;
2271 $ast->{dba_needed
} = 1;
2275 sub ${p5name}__PEEK { \$_[0]->_AUTOLEXpeek('$p5name', \$retree) }
2279 no warnings 'recursion';
2283 . ($::NEEDORIGARGS ?
" my \@origargs = \@_;\n" : "")
2284 . ::indent
($defsig || $spcsig, 1)
2285 . ::indent
(join("", @
::DECL
), 1)
2288 local \$::CTX = \$self->callm() if \$::DEBUG & DEBUG::trace_call;
2290 my \$C = \$self->cursor_xact("RULE $p5name");
2291 my \$xact = \$C->xact;
2292 my \$S = \$C->{'_pos'};
2294 . join("", map { "\$C->{'$_'} = [];\n" }
2295 grep { $::BINDINGS
{$_} > 1 }
2296 sort keys %::BINDINGS
)
2297 . ($::SYM ?
'$C->{sym} = "' . ::rd
($::SYM
) . "\";\n" : '')
2299 \$self->_MATCHIFY$ratchet(\$S, "$p5name", ${\ $body->p5expr });
2306 { package VAST
::Replication
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
2310 { package VAST
::right
; our @ISA = 'VAST::Base';
2314 { package VAST
::routine_declarator
; our @ISA = 'VAST::Base';
2318 { package VAST
::routine_declarator__S_method
; our @ISA = 'VAST::Base';
2319 sub emit_p5
{ my $self = shift;
2320 my $comment = substr($ORIG, $self->{BEG
},100);
2321 $comment =~ s/\s*\{.*//s;
2322 "## $comment\n" . $self->{method_def
}->p5;
2327 { package VAST
::regex_infix
; our @ISA = 'VAST::Base';
2330 { package VAST
::regex_infix__S_Tilde
; our @ISA = 'VAST::Base';
2334 { package VAST
::regex_infix__S_Vert
; our @ISA = 'VAST::Base';
2335 sub re_ast
{ my $self = shift;
2336 my $altname = $::NAME
. "_" . $::ALT
++;
2338 RE_any
->new(altname
=> $altname,
2339 zyg
=> [map { $_->re_ast } $self->kids('args')]);
2344 { package VAST
::regex_infix__S_VertVert
; our @ISA = 'VAST::Base';
2345 sub re_ast
{ my $self = shift;
2346 RE_first
->new(map { $_->re_ast } $self->kids('args'));
2352 { package VAST
::scoped
; our @ISA = 'VAST::Base';
2353 sub emit_p5
{ my $self = shift;
2354 if (@
{$self->{typename
}}) {
2355 " " . $self->{multi_declarator
}->p5;
2357 $self->SUPER::emit_p5
;
2361 sub emit_psq
{ my $self = shift; my $scope = shift;
2362 if ($self->{multi_declarator
}) {
2363 $self->{multi_declarator
}->psq(scope
=> $scope,
2364 typename
=> $self->{typename
}[0]->psq);
2365 } elsif ($self->{regex_declarator
}) {
2366 $self->{regex_declarator
}->psq(scope
=> $scope);
2367 } elsif ($self->{package_declarator
}) {
2368 $self->{package_declarator
}->psq(scope
=> $scope);
2370 $self->{declarator
}->psq(scope
=> $scope);
2376 { package VAST
::scope_declarator
; our @ISA = 'VAST::Base';
2377 sub emit_psq
{ my $self = shift;
2378 $self->{scoped
}->psq($self->{SYM
});
2383 { package VAST
::scope_declarator__S_has
; our @ISA = 'VAST::scope_declarator';
2384 sub emit_p5
{ my $self = shift;
2385 my $scoped = $self->{scoped
};
2386 my $typename = $scoped->{typename
}[0];
2387 my $multi = $scoped->{multi_declarator
};
2388 my $decl = $scoped->{declarator
} // $multi->{declarator
};
2389 my $vdecl = $decl->{variable_declarator
};
2390 my $var = $vdecl->{variable
};
2391 "moose_has '" . $var->{desigilname
}->Str . "' => (" . join (", ",
2392 ($typename ?
("isa => '" . $typename->Str . "'") : ()),
2399 { package VAST
::scope_declarator__S_my
; our @ISA = 'VAST::scope_declarator';
2400 sub emit_p5
{ my $self = shift;
2401 my $t = $self->SUPER::emit_p5
;
2402 $t =~ s/my(\s+)&(\w+)/my$1\$$2/;
2403 $t =~ s/my(\s+)([\$@%])::(\w+)/local$1${2}::$3/;
2409 { package VAST
::scope_declarator__S_our
; our @ISA = 'VAST::scope_declarator';
2413 { package VAST
::semiarglist
; our @ISA = 'VAST::Base';
2417 { package VAST
::semilist
; our @ISA = 'VAST::Base';
2421 { package VAST
::sibble
; our @ISA = 'VAST::Base';
2425 { package VAST
::sigil
; our @ISA = 'VAST::Base';
2426 my %psq_hash = ( '$', 'S', '@', 'A', '%', 'H', '&', 'C' );
2427 sub psq_mangle
{ my $self = shift;
2428 return $psq_hash{$self->{SYM
}};
2433 { package VAST
::sigil__S_Amp
; our @ISA = 'VAST::sigil';
2437 { package VAST
::sigil__S_At
; our @ISA = 'VAST::sigil';
2441 { package VAST
::sigil__S_Dollar
; our @ISA = 'VAST::sigil';
2445 { package VAST
::sigil__S_Percent
; our @ISA = 'VAST::sigil';
2449 { package VAST
::sign
; our @ISA = 'VAST::Base';
2453 { package VAST
::signature
; our @ISA = 'VAST::Base';
2454 sub emit_p5
{ my $self = shift;
2455 for ($self->kids('param_sep')) {
2456 next if $_->{TEXT
} =~ /,/;
2457 die "Unusual parameter separators not yet supported";
2460 # signature stuff is just parsing code
2462 for my $pv ($self->kids('parameter')) {
2463 my ($named, $st) = $pv->p5;
2464 $seg[$named] .= $st . ";\n";
2467 if ($seg[1]) { $seg[1] = "my %args = \@_;\n" . $seg[1]; }
2474 { package VAST
::spacey
; our @ISA = 'VAST::Base';
2479 { package VAST
::special_variable
; our @ISA = 'VAST::Base';
2482 { package VAST
::special_variable__S_Dollar_a2_
; our @ISA = 'VAST::Base';
2483 sub emit_p5
{ my $self = shift;
2484 my @t = $self->SUPER::emit_p5
;
2491 { package VAST
::special_variable__S_DollarSlash
; our @ISA = 'VAST::Base';
2492 sub emit_p5
{ my $self = shift;
2493 my @t = $self->SUPER::emit_p5
;
2501 { package VAST
::statement
; our @ISA = 'VAST::Base';
2502 sub emit_psq
{ my $self = shift;
2503 if ($self->{label
}) {
2504 return $self->{label
}{identifier
}->Str . ":\n" .
2505 $self->{statement
}->psq;
2508 if ($self->{statement_control
}) {
2509 return $self->{statement_control
}->psq;
2512 return "" if !$self->{EXPR
};
2514 my $body = $self->{EXPR
}->psq . ";";
2515 for my $m ($self->kids('statement_mod_cond'),
2516 $self->kids('statement_mod_loop')) {
2517 $body = $m->psq . " {\n" . ::indent
($body) . "\n}";
2524 { package VAST
::statement_control
; our @ISA = 'VAST::Base';
2528 { package VAST
::statement_control__S_default
; our @ISA = 'VAST::Base';
2532 { package VAST
::statement_control__S_use
; our @ISA = 'VAST::Base';
2533 sub emit_psq
{ my $self = shift;
2534 $::PRELUDE
{$self->{module_name
}->Str} = 1;
2540 { package VAST
::statement_control__S_for
; our @ISA = 'VAST::Base';
2544 { package VAST
::statement_control__S_given
; our @ISA = 'VAST::Base';
2548 { package VAST
::statement_control__S_if
; our @ISA = 'VAST::Base';
2549 sub emit_p5
{ my $self = shift;
2550 join("\n", ("if " . $self->{xblock
}->p5)
2551 , (map { "elsif " .$_->p5 } @
{$self->{elsif}})
2552 , (map { "else " . $_->p5 } @
{$self->{else}}));
2557 { package VAST
::statement_control__S_loop
; our @ISA = 'VAST::Base';
2558 sub emit_p5
{ my $self = shift;
2559 my $t = $self->SUPER::emit_p5
;
2560 $t =~ s/^loop(\s+\()/for$1/;
2561 $t =~ s/^loop/for (;;)/;
2567 { package VAST
::statement_control__S_when
; our @ISA = 'VAST::Base';
2568 sub emit_p5
{ my $self = shift;
2569 my @t = $self->SUPER::emit_p5
;
2570 if ($t[1] =~ s/^\s*\(\s*\*\s*\)//) { $t[0] = 'default'; }
2576 { package VAST
::statement_control__S_while
; our @ISA = 'VAST::Base';
2580 { package VAST
::statementlist
; our @ISA = 'VAST::Base';
2581 sub emit_p5
{ my $self = shift;
2582 my @stmts = $self->kids('statement');
2583 # XXX mostly for the benefit of hashes
2585 return $stmts[0]->p5;
2587 join("", map { $_->p5 . ";\n" } @stmts);
2589 sub emit_psq
{ my $self = shift;
2590 my @stmts = $self->kids('statement');
2592 my $b = join("", map { $_->psq . "\n" } @stmts);
2593 join("", @
::PADVARS
, $b);
2598 { package VAST
::statement_mod_cond
; our @ISA = 'VAST::Base';
2602 { package VAST
::statement_mod_cond__S_if
; our @ISA = 'VAST::Base';
2606 { package VAST
::statement_mod_cond__S_unless
; our @ISA = 'VAST::Base';
2610 { package VAST
::statement_mod_loop
; our @ISA = 'VAST::Base';
2614 { package VAST
::statement_mod_loop__S_for
; our @ISA = 'VAST::Base';
2618 { package VAST
::statement_mod_loop__S_while
; our @ISA = 'VAST::Base';
2622 { package VAST
::statement_prefix
; our @ISA = 'VAST::Base';
2626 { package VAST
::statement_prefix__S_do
; our @ISA = 'VAST::Base';
2630 { package VAST
::statement_prefix__S_try
; our @ISA = 'VAST::Base';
2631 sub emit_p5
{ my $self = shift;
2632 my @t = $self->SUPER::emit_p5
;
2639 { package VAST
::stdstopper
; our @ISA = 'VAST::Base';
2643 { package VAST
::stopper
; our @ISA = 'VAST::Base';
2647 { package VAST
::Structural_infix
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
2651 { package VAST
::sublongname
; our @ISA = 'VAST::Base';
2655 { package VAST
::subshortname
; our @ISA = 'VAST::Base';
2659 { package VAST
::Symbolic_unary
; our @ISA = 'VAST::Base';
2663 { package VAST
::term
; our @ISA = 'VAST::Base';
2666 { package VAST
::term__S_capterm
; our @ISA = 'VAST::Base';
2670 { package VAST
::term__S_circumfix
; our @ISA = 'VAST::Base';
2674 { package VAST
::term__S_colonpair
; our @ISA = 'VAST::Base';
2675 sub emit_p5
{ my $self = shift;
2676 my $t = $self->SUPER::emit_p5
;
2678 if ($t =~ s/^:!//) {
2681 elsif ($t =~ s/^:(\d+)//) {
2688 if ($t =~ s/^(\w+)$/'$1'/) {
2692 my ($name,$rest) = $t =~ /^(\w+)(.*)$/s;
2693 $rest =~ s/^<([^\s']*)>/'$1'/ or
2694 $rest =~ s/^(<\S*>)/q$1/ or
2695 $rest =~ s/^(<\s*\S+\s*>)/qw$1/ or
2696 $rest =~ s/^(<.*>)/[qw$1]/; # p5's => isn't scalar context
2697 $t = "'$name' => $rest";
2705 { package VAST
::term__S_fatarrow
; our @ISA = 'VAST::Base';
2709 { package VAST
::term__S_identifier
; our @ISA = ('VAST::ViaDEEP', 'VAST::Base');
2710 sub emit_p5
{ my $self = shift;
2711 my @t = $self->SUPER::emit_p5
;
2712 if ($t[0] eq 'item') {
2716 if ($t[0] eq 'map' || $t[0] eq 'grep' || $t[0] eq 'sort') {
2717 # XXX this should be more robust, but it belongs in DEEP after
2718 # all arguments are collected anyway
2719 $t[1] =~ s/}\s*,/} /;
2721 if ($t[0] eq 'invert') {
2724 if ($t[0] eq 'chars') {
2727 if ($t[0] eq 'note') {
2728 $t[0] = 'print STDERR';
2730 if ($t[0] eq 'False') {
2733 if ($t[0] eq 'True') {
2736 if ($t[0] eq 'Nil') {
2742 sub _deep
{ my $self = shift;
2743 my $id = $self->{identifier
}->Str;
2744 my @args = $self->{args
}->deepn;
2746 DEEP
::call
($id, @args);
2751 { package VAST
::term__S_multi_declarator
; our @ISA = 'VAST::Base';
2755 { package VAST
::term__S_package_declarator
; our @ISA = 'VAST::Base';
2756 sub emit_psq
{ $_[0]{package_declarator
}->psq }
2760 { package VAST
::term__S_regex_declarator
; our @ISA = 'VAST::Base';
2761 sub emit_p5
{ my $self = shift;;
2762 $self->{regex_declarator
}->p5;
2767 { package VAST
::term__S_routine_declarator
; our @ISA = 'VAST::Base';
2771 { package VAST
::term__S_scope_declarator
; our @ISA = 'VAST::Base';
2772 sub emit_psq
{ my $self = shift;
2773 $self->{scope_declarator
}->psq;
2778 { package VAST
::term__S_statement_prefix
; our @ISA = 'VAST::Base';
2782 { package VAST
::term__S_term
; our @ISA = 'VAST::Base';
2786 { package VAST
::term__S_value
; our @ISA = 'VAST::Base';
2787 sub emit_psq
{ $_[0]{value
}->psq}
2791 { package VAST
::term__S_variable
; our @ISA = 'VAST::Base';
2795 { package VAST
::terminator
; our @ISA = 'VAST::Base';
2796 sub emit_p6
{ my $self = shift;
2797 my @t = $self->SUPER::emit_p6
;
2802 { package VAST
::terminator__S_BangBang
; our @ISA = 'VAST::terminator'; }
2804 { package VAST
::terminator__S_for
; our @ISA = 'VAST::terminator'; }
2806 { package VAST
::terminator__S_if
; our @ISA = 'VAST::terminator'; }
2808 { package VAST
::terminator__S_Ket
; our @ISA = 'VAST::terminator'; }
2810 { package VAST
::terminator__S_Ly
; our @ISA = 'VAST::terminator'; }
2812 { package VAST
::terminator__S_Semi
; our @ISA = 'VAST::terminator'; }
2814 { package VAST
::terminator__S_Thesis
; our @ISA = 'VAST::terminator'; }
2816 { package VAST
::terminator__S_unless
; our @ISA = 'VAST::terminator'; }
2818 { package VAST
::terminator__S_while
; our @ISA = 'VAST::terminator'; }
2820 { package VAST
::terminator__S_when
; our @ISA = 'VAST::terminator'; }
2823 { package VAST
::termish
; our @ISA = 'VAST::Base';
2828 { package VAST
::term
; our @ISA = 'VAST::Base';
2831 { package VAST
::term__S_name
; our @ISA = ('VAST::Base');
2832 sub emit_p5
{ my $self = shift;
2833 my @t = $self->SUPER::emit_p5
;
2834 if (my ($pkg) = ($t[0] =~ /^::(.*)/)) {
2835 $pkg = $::OUR
{$pkg} // $pkg;
2836 if (defined $t[1] && $t[1] =~ /^\s*\[/) {
2837 $t[1] =~ s/^\s*\[/->__instantiate__(/;
2838 $t[1] =~ s/\]\s*$/)/;
2849 { package VAST
::term__S_self
; our @ISA = 'VAST::Base';
2850 sub emit_p5
{ my $self = shift;
2851 my @t = $self->SUPER::emit_p5
;
2858 { package VAST
::term__S_Star
; our @ISA = 'VAST::Base';
2862 { package VAST
::term__S_undef
; our @ISA = 'VAST::Base';
2866 { package VAST
::Tight_or
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
2869 { package VAST
::Tight_and
; our @ISA = ('VAST::Base', 'VAST::InfixCall');
2873 { package VAST
::trait
; our @ISA = 'VAST::Base';
2877 { package VAST
::trait_auxiliary
; our @ISA = 'VAST::Base';
2881 { package VAST
::trait_auxiliary__S_does
; our @ISA = 'VAST::Base';
2885 { package VAST
::trait_auxiliary__S_is
; our @ISA = 'VAST::Base';
2890 { package VAST
::twigil
; our @ISA = 'VAST::Base';
2893 { package VAST
::twigil__S_Dot
; our @ISA = 'VAST::Base';
2894 sub emit_p5
{ my $self = shift;
2895 my @t = $self->SUPER::emit_p5
;
2896 $t[0] = 'self->'; # XXX
2902 { package VAST
::twigil__S_Star
; our @ISA = 'VAST::Base';
2903 sub emit_p5
{ my $self = shift;
2904 my @t = $self->SUPER::emit_p5
;
2910 { package VAST
::twigil__S_Caret
; our @ISA = 'VAST::Base';
2911 sub emit_p5
{ my $self = shift;
2912 my @t = $self->SUPER::emit_p5
;
2913 $t[0] = ''; #XXX only correct for sorts
2919 { package VAST
::type_constraint
; our @ISA = 'VAST::Base';
2922 { package VAST
::type_declarator__S_constant
; our @ISA = 'VAST::Base';
2923 sub emit_p5
{ my $self = shift;
2924 my $t = $self->SUPER::emit_p5
;
2925 $t =~ s/constant/our/;
2932 { package VAST
::typename
; our @ISA = 'VAST::Base';
2933 sub emit_p5
{ my $self = shift;
2935 if (ref $context[-1] ne 'VAST::scoped') {
2936 @t = $self->SUPER::emit_p5
;
2941 sub emit_psq
{ my $self = shift;
2943 $s eq 'Str' && return 'str';
2944 $s eq 'Int' && return 'int';
2950 { package VAST
::unitstopper
; our @ISA = 'VAST::Base';
2954 { package VAST
::unspacey
; our @ISA = 'VAST::Base';
2958 { package VAST
::unv
; our @ISA = 'VAST::Base';
2962 { package VAST
::val
; our @ISA = 'VAST::Base';
2966 { package VAST
::value
; our @ISA = 'VAST::Base';
2970 { package VAST
::value__S_number
; our @ISA = 'VAST::Base';
2971 sub emit_psq
{ $_[0]{number
}->psq}
2975 { package VAST
::value__S_quote
; our @ISA = 'VAST::Base';
2976 sub emit_psq
{ $_[0]{quote
}->psq}
2980 { package VAST
::variable
; our @ISA = 'VAST::Base';
2981 sub emit_p5
{ my $self = shift;
2982 my @t = $self->SUPER::emit_p5
;
2983 if (@t >= 2) { # $t[0] eq '$' but XXX STD uses %<O><prec> (erroneously?)
2984 if ($t[1] =~ /^\d+$/) {
2985 $t[1] = "M->{$t[1]}";
2987 } elsif ($t[1] =~ /^{/) {
2995 sub emit_psq
{ my $self = shift;
2996 return '$' . $self->{sigil
}->psq_mangle . '_' . $self->{desigilname
}->Str;
3001 { package VAST
::variable_declarator
; our @ISA = 'VAST::Base';
3002 sub emit_psq
{ my $self = shift; my %args = @_;
3003 my $scope = $args{scope
};
3004 my $type = $args{typename
};
3005 my $var = $self->{variable
}->psq;
3006 my $s = $self->{variable
}{sigil
}{SYM
};
3008 if ($scope eq 'my') {
3009 die "Variables in Perlesque *must* be typed" unless $type;
3010 push @
::PADVARS
, "my $type $var;\n" if $s eq '$';
3011 push @
::PADVARS
, "my List[$type] $var = List[$type].new();\n"
3013 push @
::PADVARS
, "my Dictionary[str,$type] $var = Dictionary[str,$type].new();\n" if $s eq '%';
3020 { package VAST
::vws
; our @ISA = 'VAST::Base';
3024 { package VAST
::ws
; our @ISA = 'VAST::Base';
3029 { package VAST
::xblock
; our @ISA = 'VAST::Base';
3030 sub emit_p5
{ my $self = shift;
3031 my @t = $self->SUPER::emit_p5
;
3032 $t[0] = '(' . $t[0] . ')';
3033 $t[0] =~ s/(\s+)\)$/)$1/;
3038 { package VAST
::XXX
; our @ISA = 'VAST::Base';
3045 my $dopp = bless { %$self }, ref($self);
3046 for my $dkid ($dopp->kids) {
3047 $$dkid = $$dkid->clone;
3051 sub new
{ my $class = shift;
3052 my $self = bless { a
=> 0, i
=> $::IGNORECASE ?
1 : 0,
3053 r
=> $::RATCHET ?
1 : 0, s
=> $::SIGSPACE ?
1 : 0,
3054 dba
=> $::DBA
, dic
=> $::DECL_CLASS
, @_ }, $class;
3058 sub optimize
{ my $self = shift;
3059 for my $kid ($self->kids) {
3060 $$kid = $$kid->optimize;
3065 sub clean
{ my $self = shift;
3066 for my $kid ($self->kids) {
3072 delete $self->{i
} unless $self->{i_needed
};
3073 delete $self->{i_needed
};
3074 delete $self->{dba
} unless $self->{dba_needed
};
3075 delete $self->{dic
} unless $self->{dba_needed
};
3076 delete $self->{dba_needed
};
3079 sub walk
{ my $self = shift;
3080 say STDERR
"--> $self" if $OPT_log;
3081 my $exp = $self->_walk;
3082 if ($self->{r
} && $exp->maybacktrack) {
3083 $exp = DEEP
::cut
($exp);
3085 say STDERR
"<-- $exp: ", $exp->p5expr if $OPT_log;
3093 foreach my $kid (@
{$$self{zyg
}}) {
3094 my $x = $kid->walk->p5;
3095 $result .= $x if defined $x;
3101 return DEEP
::raw
($result);
3104 sub bind { my $self = shift; my $re = shift;
3105 return $re unless @_;
3106 DEEP
::bind($re, @_);
3109 sub remove_leading_ws
{ } # this tree node not interested
3110 sub has_trailing_ws
{ 0 }
3113 { package RE_double
; use base
"REbase";
3116 my $text = $$self{text
};
3117 $$self{i_needed
} = 1;
3118 # XXX needs interpolation
3120 $text = $::REV ?
"(?<=" . ::rd
($text) . ")" : ::rd
($text);
3121 DEEP
::raw
('$C->_PATTERN(qr/\\G(?i:' . $text . ')/")', precut
=> 1);
3124 DEEP
::raw
("\$C->_EXACT(\"" . ::rd
($text) . "\")", precut
=> 1);
3129 { package RE_string
; use base
"REbase";
3132 $$self{i_needed
} = 1;
3133 my $text = ::rd
($$self{text
});
3134 $text = "(?<=$text)" if $::REV
;
3135 $text = "(?i:$text)" if $$self{i
};
3136 DEEP
::p5regex
($text, has_meta
=> ($::REV
|| $$self{i
}),
3137 needs_bracket
=> !($::REV
|| $$self{i
}) && (length($$self{text
}) != 1));
3141 { package RE_sequence
;
3143 my ($class, @zyg) = @_;
3144 $class->SUPER::new
(zyg
=> \
@zyg);
3148 my ($self, $outer, $inner) = @_;
3149 my ($out1, $outr) = $outer->uncut;
3151 DEEP
::ratchet
($inner, $out1);
3153 DEEP
::raw
(::hang
("LazyMap::lazymap(" . DEEP
::chunk
($inner)->p5expr .
3154 ",\n" . $outer->p5expr . ")", " "));
3163 my @kids = @
{$$self{zyg
}};
3166 while (@kids and ref $kids[0] eq 'RE_decl') {
3167 push @decl, shift(@kids)->walk->p5block;
3170 @kids = map { $_->walk } @kids;
3176 while (@kids && $kids[0]->isa('DEEP::p5regex')) {
3177 my $rk = shift(@kids);
3178 $rx .= $rk->cutre(0);
3179 $hm ||= $rk->{has_meta
};
3183 push @ckids, DEEP
::p5regex
($rx, needs_bracket
=> 1,
3188 push @ckids, shift(@kids);
3192 @ckids = reverse @ckids if $::REV
;
3195 my $result = pop @result;
3196 for (reverse @result) {
3197 $result = $self->wrapone($_,$result);
3200 DEEP
::raw
(join('', @decl, $result ?
$result->p5expr . "\n" : ''), isblock
=> 1) :
3201 $result // DEEP
::raw
('', isblock
=> 1);
3204 sub kids
{ my $self = shift; map { \
$_ } @
{$self->{zyg
}} }
3206 sub optimize
{ my $self = shift;
3210 for my $kid ($self->kids) {
3211 $$kid->remove_leading_ws if $afterspace;
3212 $afterspace = $$kid->has_trailing_ws($afterspace);
3215 $self = $self->SUPER::optimize
;
3217 for my $k (@
{$self->{zyg
}}) {
3218 next if $k->isa('RE_noop');
3219 if ($k->isa('RE_sequence')) {
3220 push @ok, @
{$k->{zyg
}};
3226 return RE_noop
->new if @ok == 0;
3227 return $ok[0] if @ok == 1;
3228 $self->{zyg
} = \
@ok;
3232 sub remove_leading_ws
{
3235 for my $kid ($self->kids) {
3236 my $l = $$kid->has_trailing_ws(1);
3237 $$kid->remove_leading_ws;
3242 sub has_trailing_ws
{
3246 for my $kid ($self->kids) {
3247 $before = $$kid->has_trailing_ws($before);
3254 { package RE_any
; use base
"REbase";
3259 my $altname = $self->{altname
};
3261 my %B = %::BINDINGS
;
3262 for my $kid (@
{$$self{zyg
}}) {
3265 for my $b (keys %::BINDINGS
) {
3266 $B{$b} = 2 if $::BINDINGS
{$b} > 1 or $B{$b};
3269 $kid->{alt
} = $altname . ' ' . $alt++;
3277 $::RETREE
->{$self->{altname
}} = $self;
3278 $self->{dba_needed
} = 1;
3279 my $result = <<"END";
3287 if (\$fate = \$C->{'_fate'} and \$fate->[1] eq '$altname') {
3288 \$C->deb("Fate passed to $altname: ", ::fatestr(\$fate)) if \$::DEBUG & DEBUG::fates;
3289 (\$C->{'_fate'}, \$tag, \$try) = \@\$fate;
3291 \$x = 'ALT $altname'; # some outer ltm is controlling us
3294 \$x = 'ALTLTM $altname'; # we are top level ltm
3296 my \$C = \$C->cursor_xact(\$x);
3297 my \$xact = \$C->{_xact};
3302 \$relex //= \$C->cursor_fate('$::PKG', '$altname', \$retree);
3303 \@try = \$relex->(\$C) or last;
3305 \$try = shift(\@try) // next;
3308 (\$C->{'_fate'}, \$tag, \$try) = \@\$try; # next candidate fate
3311 \$C->deb("$altname trying \$tag \$try") if \$::DEBUG & DEBUG::try_processing;
3314 for my $i (0 .. @result - 1) {
3315 $result .= ::indent
(DEEP
::chunk
($result[$i])->p5expr, 3);
3316 if ($i != @result - 1) {
3324 last if \$xact->[-2]; # committed?
3329 DEEP
::raw
($result, isblock
=> 1);
3333 sub kids
{ my $self = shift; map { \
$_ } @
{$self->{zyg
}} }
3335 sub optimize
{ my $self = shift()->SUPER::optimize
;
3338 for my $k (@
{$self->{zyg
}}) {
3339 if ($k->isa('RE_any')) {
3340 push @ok, @
{$k->{zyg
}};
3346 return $ok[0] if @ok == 1;
3347 $self->{zyg
} = \
@ok;
3351 # yes, this affects LTM, but S05 specs it
3352 sub remove_leading_ws
{
3354 for my $kid (@
{$$self{zyg
}}) {
3355 $kid->remove_leading_ws();
3359 sub has_trailing_ws
{
3364 for my $kid ($self->kids) {
3365 $after &&= $$kid->has_trailing_ws($before);
3372 { package RE_first
; use base
"REbase";
3374 my ($class, @zyg) = @_;
3375 $class->SUPER::new
(zyg
=> \
@zyg);
3382 my %B = %::BINDINGS
;
3383 foreach my $kid (@
{$$self{zyg
}}) {
3385 push @result, $kid->walk->p5expr;
3386 for my $b (keys %::BINDINGS
) {
3387 $B{$b} = 2 if $::BINDINGS
{$b} > 1 or $B{$b};
3393 DEEP
::raw
($result[0]);
3396 die("Can't reverse serial disjunction") if $::REV
;
3397 for (@result) { $_ = "do {\n" . ::indent
("push \@gather, $_\n") . "}"; }
3398 # We need to force the scope here because of the my $C
3399 my $result = "do {" . ::indent
(
3400 "my \$C = \$C->cursor_xact('ALT ||');\n" .
3401 "my \$xact = \$C->xact;\nmy \@gather;\n" .
3402 join("\nor \$xact->[-2] or\n", @result) . ";\n" .
3403 "\@gather;\n") . "}";
3408 sub kids
{ my $self = shift; map { \
$_ } @
{$self->{zyg
}} }
3410 sub remove_leading_ws
{
3412 for my $kid (@
{$$self{zyg
}}) {
3413 $kid->remove_leading_ws();
3417 sub has_trailing_ws
{
3422 for my $kid ($self->kids) {
3423 $after &&= $$kid->has_trailing_ws($before);
3430 { package RE_method
; use base
"REbase";
3431 sub clean
{ my $self = shift;
3432 $self->SUPER::clean
;
3433 delete $self->{nobind
};
3434 delete $self->{need_match
};
3435 $self->{rest
} = defined $self->{rest
};
3439 local $::NEEDMATCH
= 0;
3440 my $name = $$self{name
};
3441 die "Can't reverse $name" if $::REV
;
3444 if ($name eq "sym") {
3445 $$self{i_needed
} = 1;
3446 $$self{sym
} = $::SYM
;
3447 $$self{endsym
} = $::ENDSYM
if defined $::ENDSYM
;
3449 return DEEP
::p5regex
("(?i:" . ::rd
($::SYM
) . ")");
3452 return DEEP
::p5regex
(::rd
($::SYM
), has_meta
=> 0);
3455 elsif ($name eq "alpha") {
3456 return DEEP
::p5regex
("[_[:alpha:]]");
3458 elsif ($name eq "_ALNUM") {
3459 return DEEP
::p5regex
("\\w");
3461 elsif ($name eq "nextsame") {
3463 $re = '$self->SUPER::' . $::NAME
. '(@origargs)';
3465 elsif ($name =~ /^\w/) {
3466 my $al = $self->{rest
} // '';
3467 $re = '$C->' . $name . $al;
3470 my $al = $self->{rest
} // '';
3476 elsif (ref $name eq 'Regexp') {
3477 if (\$::ORIG =~ m/$name/gc) {
3478 \$C->cursor(\$+[0]);
3490 $re = "do {\n" . ::indent
("my \$M = \$C;\n$re") . "\n}" if $self->{need_match
};
3491 $re = DEEP
::raw
($re);
3492 if ($name =~ /^\w/ and not $self->{nobind
}) {
3493 $::BINDINGS
{$name} += $::PLURALITY
;
3494 $re = $self->bind($re, $name);
3499 sub has_trailing_ws
{
3501 return $self->{name
} eq 'ws';
3504 sub remove_leading_ws
{
3506 if ($self->{name
} eq 'ws' && $self->{nobind
}) {
3507 bless $self, 'RE_noop';
3512 { package RE_ast
; use base
"REbase";
3513 sub clean
{ my $self = shift;
3514 $self->SUPER::clean
;
3515 delete $self->{decl
};
3516 delete $self->{kind
};
3521 for my $decl (@
{$$self{decl
}}) {
3522 push @
::DECL
, $decl->walk->p5block;
3530 sub kids
{ my $self = shift; \
$self->{re
}, map { \
$_ } @
{$self->{decl
}}; }
3533 { package RE_quantified_atom
; use base
"REbase";
3534 # handles cutting itself
3535 sub clean
{ my $self = shift;
3536 $self->SUPER::clean
;
3537 splice @
{$self->{quant
}}, ($self->{quant
}[0] eq '**' ?
3 : 1);
3542 local $::PLURALITY
= 2;
3545 my $q = $$self{quant
};
3546 my $bind = $::BINDINSIDE
;
3547 undef $::BINDINSIDE
;
3548 my $atom = $$self{atom
}->walk;
3549 if ($bind) { #XXX STD
3550 $atom = $self->bind($atom, $bind);
3552 my $atom_is_cut = !$atom->maybacktrack;
3553 my ($qfer,$how,$rest) = @
{$$self{quant
}};
3554 my $hc = $how eq '!' ?
'g' :
3557 my $hr = $how eq '!' ?
'' :
3560 if ($atom->isa('DEEP::p5regex') && $hc eq 'r' && !$::REV
&& $qfer ne '**') {
3561 return DEEP
::p5regex
($atom->cutre(1) . "$qfer$hr", needs_bracket
=> 1);
3565 $quant = "\$C->_STAR$hc$::REV(";
3567 elsif ($qfer eq '+') {
3568 $quant = "\$C->_PLUS$hc$::REV(";
3570 elsif ($qfer eq '?') {
3571 $quant = "\$C->_OPT$hc$::REV(";
3573 elsif ($qfer eq '**') {
3575 if (ref $rest eq "RE_block") {
3576 $rep = "_REPINDIRECT$::REV";
3577 $rest = $rest->walk;
3580 $rep = "_REPSEP$::REV";
3581 $rest = DEEP
::chunk
($rest->walk)->p5expr;
3587 $quant = "\$C->$rep$hc( $rest, ";
3589 return DEEP
::raw
($quant . ::hang
(DEEP
::chunk
($atom)->p5expr, " ") . ")", precut
=> ($hc eq 'r'));
3592 sub kids
{ my $self = shift; \
$self->{atom
} }
3595 my $self = shift()->SUPER::optimize
;
3596 if ($self->{quant
}[0] eq '*' &&
3597 $self->{quant
}[1] ne ':' &&
3598 $self->{atom
}->isa('RE_meta') &&
3599 $self->{atom
}{text
} eq '.') {
3600 delete $self->{atom
};
3601 $self->{text
} = ($self->{quant
}[1] eq '?') ?
'.*?' : '.*';
3602 delete $self->{quant
};
3603 bless $self, 'RE_meta';
3609 { package RE_qw
; use base
"REbase";
3612 DEEP
::raw
("\$C->_ARRAY$::REV( qw$$self{text} )");
3616 { package RE_method_re
; use base
"REbase";
3619 my $re = $$self{re
};
3620 my $name = $$self{name
};
3621 die("Can't reverse $name") if $::REV
and $name ne 'before';
3622 local $::REV
= $name eq 'after' ?
'_rev' : '';
3625 $re = $re->walk->p5block;
3627 for my $binding ( keys %::BINDINGS
) {
3628 next unless $::BINDINGS
{$binding} > 1;
3629 $re = <<"END" . $re;
3630 \$C->{'$binding'} = [];
3637 $re = DEEP
::raw
('$C->' . $name . "(" . ::hang
(DEEP
::chunk
(DEEP
::raw
($re, isblock
=> 1))->p5expr, " ") . ")");
3638 if ($name =~ /^\w/ and not $self->{nobind
}) {
3639 $re = $self->bind($re, $name);
3640 $::BINDINGS
{$name} += $::PLURALITY
;
3645 sub kids
{ my $self = shift; \
$self->{re
} }
3648 { package RE_assertion
; use base
"REbase";
3651 if ($$self{assert
} eq '!') {
3652 my $re = $$self{re
}->walk;
3653 DEEP
::raw
("\$C->_NOTBEFORE(" . ::hang
(DEEP
::chunk
($re)->p5expr, " ") .")");
3656 my $re = $$self{re
}->walk;
3657 return $re if $re->p5expr =~ /^\$C->before/; #XXX
3658 DEEP
::raw
("\$C->before(" . ::hang
(DEEP
::chunk
($re)->p5expr, " ") . ")");
3661 # TODO: Investigate what the LTM engine is doing with assertions and
3664 sub has_trailing_ws
{
3668 $before; # Transparent
3671 sub remove_leading_ws
{
3674 $self->{re
}->remove_leading_ws;
3677 sub kids
{ my $self = shift; \
$self->{re
} }
3680 { package RE_meta
; use base
"REbase";
3683 my $text = $$self{text
};
3687 if ($text =~ /^(\\[A-Z])(.*)/) {
3688 $text = lc($1) . $2;
3691 # to return yourself, you must either be a symbol or handle $not
3694 return DEEP
::p5regex
("(?<=(?s:.)");
3697 $code = "\$C->cursor_incr()";
3700 elsif ($text eq '.*') {
3701 $code = "\$C->_SCANg$::REV()";
3704 elsif ($text eq '.*?') {
3705 $code = "\$C->_SCANf$::REV()";
3708 elsif ($text eq '^') {
3709 return DEEP
::p5regex
('\A');
3711 elsif ($text eq '^^') {
3712 return DEEP
::p5regex
('(?m:^)');
3714 elsif ($text eq '$') {
3715 return DEEP
::p5regex
('\z');
3717 elsif ($text eq '$$') {
3718 return DEEP
::p5regex
('(?m:$)');
3720 elsif ($text eq ':') {
3721 my $extra = $self->{extra
} || '';
3722 $code = "(($extra), \$C)[-1]";
3724 elsif ($text eq '::') {
3725 $code = "\$C->_COMMITLTM$::REV()";
3727 elsif ($text eq '::>') {
3728 $code = "\$C->_COMMITBRANCH$::REV()";
3730 elsif ($text eq ':::') {
3731 $code = "\$C->_COMMITRULE$::REV()";
3733 elsif ($text eq '\\d') {
3735 return DEEP
::p5regex
($not ?
'(?<=\D)' : '(?<=\d)');
3738 return DEEP
::p5regex
($not ?
'\D' : '\d');
3741 elsif ($text eq '\\w') {
3743 return DEEP
::p5regex
($not ?
'(?<=\W)' : '(?<=\w)');
3746 return DEEP
::p5regex
($not ?
'\W' : '\w');
3749 elsif ($text eq '\\s') {
3751 return DEEP
::p5regex
($not ?
'(?<=\W)' : '(?<=\w)');
3754 return DEEP
::p5regex
($not ?
'\S' : '\s');
3757 elsif ($text eq '\\h') {
3759 return DEEP
::p5regex
($not ?
'(?<=[^\x20\t\r])' : '(?<=[\x20\t\r])');
3762 return DEEP
::p5regex
($not ?
'[^\x20\t\r]' : '[\x20\t\r]');
3765 elsif ($text eq '\\v') {
3767 return DEEP
::p5regex
($not ?
'(?<=[^\n])' : '(?<=[\n])');
3770 return DEEP
::p5regex
($not ?
'[^\n]' : '\n');
3773 elsif ($text eq '»') {
3774 return DEEP
::p5regex
('\b');
3776 elsif ($text eq '«') {
3777 return DEEP
::p5regex
('\b');
3779 elsif ($text eq '>>') {
3780 $code = "\$C->_RIGHTWB$::REV()";
3782 elsif ($text eq '<<') {
3783 $code = "\$C->_LEFTWB$::REV()";
3785 elsif ($text eq '<(') {
3786 $code = "\$C->_LEFTRESULT$::REV()";
3788 elsif ($text eq ')>') {
3789 $code = "\$C->_RIGHTRESULT$::REV()";
3791 elsif ($text eq '<~~>') {
3792 $code = "\$C->$::NAME()";
3796 $code = "\$C->_EXACT$::REV(\"$text\")";
3798 if ($not) { # XXX or maybe just .NOT on the end...
3799 $code = "\$C->_NOTCHAR( sub { my \$C=shift;\n" . ::indent
($code) . "\n})";
3801 DEEP
::raw
($code, precut
=> !$bt);
3805 { package RE_cclass
; use base
"REbase";
3808 my $text = $$self{text
};
3809 $self->{i_needed
} = 1;
3810 $text =~ s!(\/|\\\/)!\\$1!g;
3812 $text =~ s/\.\./-/g;
3813 $text =~ s/^-\[/[^/;
3814 $text = "(?<=$text)" if $::REV
;
3816 DEEP
::p5regex
("(?i:$text)");
3819 DEEP
::p5regex
($text, needs_bracket
=> 1);
3824 { package RE_noop
; use base
"REbase";
3827 DEEP
::raw
('$C', precut
=> 1);
3830 sub has_trailing_ws
{
3838 { package RE_decl
; use base
"REbase";
3839 # because cutting one of these would be a disaster
3842 my $self = $class->SUPER::new
(@_);
3846 sub clean
{ my $self = shift;
3847 $self->SUPER::clean
;
3848 delete $self->{body
};
3852 DEEP
::raw
($$self{body
}, isblock
=> 1);
3855 sub has_trailing_ws
{
3863 { package RE_block
; use base
"REbase";
3864 sub clean
{ my $self = shift;
3865 $self->SUPER::clean
;
3866 delete $self->{context
};
3867 delete $self->{body
};
3871 my $ctx = $$self{context
};
3872 my $text = ::indent
($$self{body
});
3873 if ($ctx eq 'void') {
3874 return DEEP
::raw
("scalar(do {\n" . ::indent
($text) . "}, \$C)", precut
=> 1);
3876 elsif ($ctx eq 'bool') {
3877 return DEEP
::raw
("((\$C) x !!do {\n" . ::indent
($text) . "})", precut
=> 1);
3880 return DEEP
::raw
("sub {\n" . ::indent
("my \$C=shift;\n" . $text) . "}", precut
=> 1);
3884 sub has_trailing_ws
{
3892 { package RE_bracket
; use base
"REbase";
3893 sub clean
{ my $self = shift;
3894 $self->SUPER::clean
;
3895 delete $self->{decl
};
3899 my ($re, $r) = $$self{re
}->walk->uncut;
3900 my @decl = map { $_->walk } @
{$$self{decl
}};
3901 DEEP
::raw
("\$C->_BRACKET$r(" . ::hang
(DEEP
::chunk
($re, @decl)->p5expr, " ") . ")");
3904 sub kids
{ my $self = shift; \
$self->{re
} }
3906 sub remove_leading_ws
{
3908 my $re = $$self{re
};
3909 $re->remove_leading_ws();
3912 sub has_trailing_ws
{
3915 $$self{re
}->has_trailing_ws($before);
3919 { package RE_var
; use base
"REbase";
3922 my $var = $$self{var
};
3923 if ($var =~ /^\$/) {
3924 if ($var =~ /^\$M->{(.*)}/) {
3925 my $p = (substr($1,0,1) eq "'") ?
"n" : "p";
3926 DEEP
::raw
("\$C->_BACKREF$p$::REV($1)");
3929 DEEP
::raw
("\$C->_EXACT$::REV($var)");
3932 elsif ($var =~ /^\@/) {
3933 DEEP
::raw
("\$C->_ARRAY$::REV($var)");
3935 elsif ($var =~ /^\%/) {
3936 DEEP
::raw
("\$C->_HASH$::REV($var)");
3941 { package RE_paren
; use base
"REbase";
3942 sub clean
{ my $self = shift;
3943 $self->SUPER::clean
;
3944 delete $self->{decl
};
3951 $re = $$self{re
}->walk->p5block;
3953 for my $binding ( keys %::BINDINGS
) {
3954 next unless $::BINDINGS
{$binding} > 1;
3955 my $re = <<"END" . $re;
3956 \$C->{'$binding'} = [];
3961 $re = "\$C->_$::REV"."PAREN( " . ::hang
(DEEP
::chunk
(DEEP
::raw
($re))->p5expr, " ") . ")";
3965 sub kids
{ my $self = shift; \
$self->{re
} }
3967 # yes, () would capture the ws, but we're guaranteed to be past it already
3968 sub remove_leading_ws
{
3970 my $re = $$self{re
};
3971 $re->remove_leading_ws();
3974 sub has_trailing_ws
{
3977 $$self{re
}->has_trailing_ws($before);
3981 { package RE_bindpos
; use base
"REbase";
3982 sub clean
{ my $self = shift;
3983 $self->SUPER::clean
;
3984 delete $self->{var
};
3988 my $var = $$self{var
};
3989 $::BINDINGS
{$var} += $::PLURALITY
;
3990 my $re = $$self{atom
}->walk;
3991 $self->bind($re, $var);
3994 sub kids
{ my $self = shift; \
$self->{atom
} }
3996 sub remove_leading_ws
{
3998 my $re = $$self{atom
};
3999 $re->remove_leading_ws();
4002 sub has_trailing_ws
{
4005 $$self{atom
}->has_trailing_ws($before);
4009 { package RE_bindnamed
; use base
"REbase";
4010 sub clean
{ my $self = shift;
4011 $self->SUPER::clean
;
4012 delete $self->{var
};
4016 my $var = $$self{var
};
4017 # XXX STD for gimme5 bug-compatibility, names push inside quantifiers
4018 $::BINDINGS
{$var} += $::PLURALITY
;
4019 if ($$self{atom
}->isa('RE_quantified_atom')) {
4020 local $::BINDINSIDE
= $var;
4021 return $$self{atom
}->walk;
4023 my $re = $$self{atom
}->walk;
4024 $self->bind($re, $var);
4027 sub kids
{ my $self = shift; \
$self->{atom
} }
4029 sub remove_leading_ws
{
4031 my $re = $$self{atom
};
4032 $re->remove_leading_ws();
4035 sub has_trailing_ws
{
4038 $$self{atom
}->has_trailing_ws($before);
4042 # DEEP is the lowest level of desugaring used by viv, but it still keeps a tree
4043 # structure. Not all DEEP nodes are interchangable; some represent expression
4044 # bits, others statements with no sensible return value.
4049 sub maybacktrack
{ 1 }
4051 sub uncut
{ my $self = shift; $self, ($self->maybacktrack ?
'' : 'r') }
4053 # p5 should return (is a block?), text; takes arguments sh (can shadow $C?)
4054 # and ov (can overwrite $C?); non-block returns may not shadow
4055 sub p5expr
{ my $self = shift;
4056 my ($isbl, $text) = $self->p5(@_, sh
=> 1);
4057 $isbl ?
("do {\n" . ::indent
($text) . "\n}") : $text;
4060 sub p5block
{ my $self = shift;
4061 my ($isbl, $text) = $self->p5(@_);
4062 $isbl ?
$text : ($text . "\n");
4065 # psq returns the same as p5 for now
4066 sub psqexpr
{ my $self = shift;
4067 my ($isbl, $text) = $self->psq(@_, sh
=> 1);
4068 $isbl ?
("do {\n" . ::indent
($text) . "\n}") : $text;
4072 { package DEEP
::raw
; our @ISA = 'DEEPexpr';
4075 bless { text
=> $text, @_ }, "DEEP::raw";
4080 return !$self->{precut
};
4083 sub p5
{ my $self = shift;
4084 $self->{isblock
}, $self->{text
};
4087 sub psq
{ my $self = shift;
4088 $self->{isblock
}, $self->{text
};
4092 { package DEEP
::cut
; our @ISA = 'DEEPexpr';
4095 if (!$child->maybacktrack) {
4098 if ($child->isa('DEEP::bind')) {
4099 return DEEP
::bind(DEEP
::cut
($child->{child
}), @
{$child->{names
}});
4101 bless { child
=> $child }, "DEEP::cut";
4104 sub p5
{ my $self = shift;
4105 1, "if (my (\$C) = (" . ::hang
($self->{child
}->p5expr, " ") . ")) { (\$C) } else { () }\n";
4108 sub maybacktrack
{ 0 }
4112 my ($child_uncut) = $self->{child
}->uncut;
4117 { package DEEP
::bind; our @ISA = 'DEEPexpr';
4121 if ($child->isa('DEEP::bind')) {
4122 push @names, @
{$child->{names
}};
4123 $child = $child->{child
};
4125 bless { child
=> $child, names
=> \
@names }, "DEEP::bind";
4128 sub maybacktrack
{ $_[0]{child
}->maybacktrack }
4130 sub p5
{ my $self = shift;
4131 my ($chinner, $r) = $self->{child
}->uncut;
4132 0, "\$C->_SUBSUME$r([" .
4133 join(',', map {"'$_'"} @
{$self->{names
}}) .
4134 "], sub {\n" . ::indent
("my \$C = shift;\n" .
4135 $chinner->p5block(cl
=> 1, sh
=> 1)) . "})";
4139 { package DEEP
::ratchet
; our @ISA = 'DEEPexpr';
4143 if (::DARE_TO_OPTIMIZE
) {
4144 if ($child->isa('DEEP::ratchet')) {
4145 push @before, @
{$child->{before
}};
4146 $child = $child->{child
};
4148 my ($chinner, $chr) = $child->uncut;
4149 if ($chr && $chinner != $child) {
4150 push @before, $chinner;
4151 $child = DEEP
::raw
('$C', precut
=> 1);
4154 bless { child
=> $child, before
=> \
@before }, "DEEP::ratchet";
4157 sub maybacktrack
{ $_[0]{child
}->maybacktrack }
4159 sub p5
{ my $self = shift; my %a = @_;
4160 if (@
{$self->{before
}} == 1) {
4161 my $pre = $self->{before
}[0];
4162 return 1, "if (my (\$C) = (" . ::hang
($pre->p5expr, " " x
8). ")) {\n" .
4163 ::indent
($self->{child
}->p5block) . "} else { () }\n";
4165 my $conditional = join ::hang
("\nand ", " "),
4166 map { "(\$C) = (" . ::hang
($_->p5expr, " " x
8) . ")" }
4169 my $guts = ($conditional ?
4170 "if ($conditional) {\n" .
4171 ::indent
($self->{child
}->p5block) . "} else { () }\n"
4172 : $self->{child
}->p5block(cl
=> 1, sh
=> 1));
4174 $guts = "my \$C = \$C;\n" . $guts unless $a{cl
};
4175 $guts = "do {\n" . ::indent
($guts) . "};\n" unless $a{sh
};
4179 # NOT a regex bit, but a value
4180 { package DEEP
::chunk
; our @ISA = 'DEEPexpr';
4183 bless { child
=> $child, decl
=> \
@_ }, "DEEP::chunk";
4188 0, "sub {\n" . ::indent
(
4190 join("", map { $_->p5block } @
{ $self->{decl
} }) .
4191 $self->{child
}->p5block(cl
=> 1, sh
=> 1)) . "}";
4195 { package DEEP
::p5regex
; our @ISA = 'DEEPexpr';
4198 bless { text
=> $text, has_meta
=> 1, @_ }, "DEEP::p5regex";
4203 0, $self->{has_meta
} ?
4204 "\$C->_PATTERN(qr/\\G" . $self->{text} . "/)" :
4205 "\$C->_EXACT(\"" . $self->{text
} . "\")";
4211 $self->{needs_cut
} ?
"(?>" . $self->{text
} . ")"
4212 : ($btoo && $self->{needs_bracket
}
4213 ?
"(?:" . $self->{text
} . ")"
4217 sub maybacktrack
{ 0 }
4220 { package DEEP
::call
; our @ISA = 'DEEPexpr';
4222 my ($name, @args) = @_;
4223 bless { name
=> $name, args
=> \
@args }, "DEEP::call";
4227 'note', => "System.Console.Error.WriteLine"
4230 sub psq
{ my $self = shift;
4231 my $n = $self->{name
};
4232 my $np = $psq_map{$n};
4234 my $n2 = $psq_map{$n} // $n;
4235 if ($n2 =~ /infix:<(.*)>/) {
4237 $np = sub { my ($a1, $a2) = @_;
4238 "(" . $a1->psqexpr . $op . $a2->psqexpr . ")"; };
4240 elsif ($n2 =~ /prefix:<(.*)>/) {
4242 $np = sub { my ($a) = @_;
4243 "(" . $op . $a->psqexpr . ")"; };
4245 elsif ($n2 =~ /postfix:<(.*)>/) {
4247 $np = sub { my ($a) = @_;
4248 "(" . $a->psqexpr . $op . ")"; };
4251 $np = sub { $n2 . "(" . join(", ",
4252 map { $_->psqexpr } @_) . ")" };
4256 return 0, $np->(@
{$self->{args
}});
4260 if ($0 eq __FILE__
) {
4264 # vim: ts=8 sw=4 noexpandtab smarttab