File Coverage

blib/lib/Seis/Compiler.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


line stmt bran cond sub pod time code
1             package Seis::Compiler;
2 25     25   740654 use strict;
  25         67  
  25         832  
3 25     25   140 use warnings;
  25         51  
  25         647  
4 25     25   321 use utf8;
  25         53  
  25         141  
5 25     25   1055 use 5.010_001;
  25         96  
  25         1116  
6              
7 25     25   13119 use Perl6::PVIP 0.07;
  0            
  0            
8             use Carp ();
9             use Data::Dumper ();
10             use Encode ();
11             use Seis::Runtime;
12              
13             use constant {
14             G_VOID => 1,
15             G_SCALAR => 2,
16             G_ARRAY => 3,
17             };
18              
19             # `no warnings 'misc'` suppress `"our" variable $x redeclared` message
20             # in `our $x; { my $x; { our $x}}`
21             our $HEADER = <<'...';
22             package # Hide from PAUSE
23             Main;
24             use strict;
25             use 5.018_000;
26             use utf8;
27             no warnings "experimental::smartmatch";
28             no warnings "experimental::lexical_subs";
29             use feature "lexical_subs";
30             use Seis::Autobox;
31             use List::Util qw(min max);
32             use Seis::Runtime;
33             use POSIX qw(floor);
34             no warnings 'misc', 'void';
35             BEGIN {
36             *gcd = *Seis::BuiltinFunctions::gcd;
37             *Int = *Seis::Runtime::Int;
38             *Mu = *Seis::Runtime::Mu;
39             *Array = *Seis::Runtime::Array;
40             *True = *Bool::True;
41             }
42              
43             ...
44              
45             sub new {
46             my $class = shift;
47             return bless {}, $class;
48             }
49              
50             sub compile {
51             my ($self, $src, $filename) = @_;
52             $filename //= '-e';
53             local $self->{filename} = $filename;
54             local $self->{line_number} = 0;
55             my $parser = Perl6::PVIP->new();
56             my $node = $parser->parse_string($src)
57             or Seis::Exception::ParsingError->throw("Can't parse $filename:\n" . $parser->errstr);
58             return join('',
59             $HEADER,
60             qq{#line 1 "$filename"\n},
61             $self->do_compile($node)
62             );
63             }
64              
65             sub do_compile {
66             my ($self, $node, $gimme) = @_;
67             $gimme //= G_SCALAR;
68             Carp::confess "Invalid node" unless ref $node;
69              
70             my $v = $node->value;
71             my $type = $node->type;
72              
73             if ($type == PVIP_NODE_STATEMENTS) {
74             my $ret;
75             for (my $i=0; $i<@$v; $i++) {
76             next if $v->[$i]->type == PVIP_NODE_NOP;
77             # $ret .= sprintf("# NODE:%d SELF:%d\n", $v->[$i]->line_number, $self->{line_number});
78             while ($self->{line_number} < $v->[$i]->line_number) {
79             $ret .= "\n";
80             $self->{line_number}++;
81             }
82             my $stmt = $self->do_compile($v->[$i], $i==@$v-1 ? G_SCALAR : G_VOID);
83             if ($stmt =~ /\n\z/ && $i!=@$v-1) {
84             $ret .= $stmt;
85             } else {
86             $ret .= "$stmt;\n";
87             $self->{line_number}++;
88             }
89             }
90             $ret;
91             } elsif ($type == PVIP_NODE_UNDEF) {
92             undef;
93             } elsif ($type == PVIP_NODE_RANGE) {
94             if ($gimme == G_ARRAY) {
95             $self->do_compile($v->[0]) . '..' . $self->do_compile($v->[1]);
96             } else {
97             '[' . $self->do_compile($v->[0]) . '..' . $self->do_compile($v->[1]) .']';
98             }
99             } elsif ($type == PVIP_NODE_REDUCE) {
100             my $body;
101             if ($v->[0]->value =~ /[a-z]/) {
102             $body = sprintf '$seis_reduce_ret = %s($seis_reduce_ret, $seis_reduce_stuff)', $v->[0]->value;
103             } else {
104             $body = sprintf '$seis_reduce_ret %s= $seis_reduce_stuff', $v->[0]->value;
105             }
106             # XXX I should care the other cases?
107             my $initial = $v->[0]->value eq '*' ? 1 : 0;
108             sprintf('do { my @seis_reduce_ary = %s; my $seis_reduce_ret = @seis_reduce_ary==0 ? %s : shift @seis_reduce_ary; for my $seis_reduce_stuff (@seis_reduce_ary) { %s } $seis_reduce_ret; }', $self->do_compile($v->[1], G_ARRAY), $initial, $body);
109             } elsif ($type == PVIP_NODE_INT) {
110             $node->value;
111             } elsif ($type == PVIP_NODE_NUMBER) {
112             $node->value;
113             } elsif ($type == PVIP_NODE_DIV) {
114             '(' . $self->do_compile($v->[0]) . ')/(' . $self->do_compile($v->[1]) . ')';
115             } elsif ($type == PVIP_NODE_MUL) {
116             '(' . $self->do_compile($v->[0]) . ')*(' . $self->do_compile($v->[1]) . ')';
117             } elsif ($type == PVIP_NODE_ADD) {
118             '(' . $self->do_compile($v->[0]) . ')+(' . $self->do_compile($v->[1]) . ')';
119             } elsif ($type == PVIP_NODE_SUB) {
120             '(' . $self->do_compile($v->[0]) . ')-(' . $self->do_compile($v->[1]) . ')';
121             } elsif ($type == PVIP_NODE_IDENT) {
122             if ($v eq '::Array') {
123             'Seis::Class->_new(name => "Array")'
124             } elsif ($v eq 'self') {
125             '$self'
126             } elsif ($v eq '::Hash') {
127             'Seis::Class->_new(name => "Hash")'
128             } elsif ($v eq 'Buf') {
129             'Buf::'
130             } elsif ($v eq 'Exception') {
131             'Seis::Class->_new(name => "Exception")'
132             } elsif ($v eq 'Real') {
133             'Seis::Real::'
134             } elsif ($v eq 'Duration') {
135             'Seis::Duration::'
136             } elsif ($v eq 'Pair') {
137             'Pair::'
138             } elsif ($v eq 'Instant') {
139             'Seis::Instant::'
140             } elsif ($v eq 'IO::Handle') {
141             'IO::Handle::'
142             } elsif ($v eq 'Bool::False') {
143             'Bool::False()'
144             } elsif ($v eq 'Bool::True') {
145             'Bool::True()'
146             } elsif ($v eq 'True') {
147             'Bool::True()'
148             } elsif ($v eq 'False') {
149             'Bool::False()'
150             } elsif ($v eq 'IO::Path::Cygwin') {
151             'IO::Path::Cygwin::'
152             } else {
153             $v;
154             }
155             } elsif ($type == PVIP_NODE_FUNCALL) {
156             if ($v->[0]->type == PVIP_NODE_IDENT) {
157             # builtin functions
158             if ($v->[0]->value eq 'shift' || $v->[0]->value eq 'pop') {
159             # shift(@array)
160             local $self->{args_list} = 1;
161             sprintf('%s(%s)',
162             $self->do_compile($v->[0]),
163             $self->do_compile($v->[1]),
164             );
165             } elsif ($v->[0]->value eq 'elems') {
166             # TODO You may optimize this function... elems(3) can be caluculate while compilation time.
167             sprintf('Seis::Runtime::builtin_elems(%s)',
168             $self->do_compile($v->[1]),
169             );
170             } elsif ($v->[0]->value eq 'eval') {
171             my $is_perl5 = do {
172             my @args = @{$v->[1]->value};
173             if (@args==2) {
174             my $pair = $args[1];
175             if (
176             $pair->type == PVIP_NODE_PAIR
177             && $pair->value->[0]->value eq 'lang'
178             && $pair->value->[1]->value eq 'perl5'
179             ) {
180             1;
181             }
182             } else {
183             0;
184             }
185             };
186             if ($is_perl5) {
187             sprintf('CORE::eval(%s)',
188             $self->do_compile($v->[1]->value->[0]),
189             );
190             } else {
191             join('',
192             'do {',
193             'my $__rg_compiler = Seis::Compiler->new();',
194             'my $__rg_compiled = $__rg_compiler->compile(',
195             $self->do_compile($v->[1]),
196             ');',
197             'my $__rg_ret = eval $__rg_compiled;',
198             'if ($@) {',
199             'Seis::Exception::CompilationFailed->throw("$@");',
200             '}',
201             '$__rg_ret;}',
202             );
203             }
204             } elsif ($v->[0]->value eq 'now') {
205             'Seis::BuiltinFunctions::now()';
206             } elsif ($v->[0]->value eq 'kv') {
207             sprintf('(%s)->kv',
208             $self->do_compile($v->[1]),
209             );
210             } elsif ($v->[0]->value eq 'list') {
211             sprintf('List->new(%s)',
212             $self->do_compile($v->[1]),
213             );
214             } elsif ($v->[0]->value eq 'copy') {
215             sprintf('Seis::BuiltinFunctions::copy(%s)',
216             $self->do_compile($v->[1]),
217             );
218             } elsif ($v->[0]->value eq 'reduce') {
219             sprintf('Seis::BuiltinFunctions::reduce(%s)',
220             $self->do_compile($v->[1]),
221             );
222             } elsif ($v->[0]->value eq 'gcd') {
223             sprintf('Seis::BuiltinFunctions::gcd(%s)',
224             $self->do_compile($v->[1]),
225             );
226             } elsif ($v->[0]->value eq 'chdir') {
227             if (@{$v->[1]->value} == 0) {
228             Seis::Exception::CompilationFailed->throw(
229             'You need pass 1 argument for chdir function'
230             );
231             }
232             sprintf('CORE::chdir(%s)',
233             $self->do_compile($v->[1]),
234             );
235             } elsif ($v->[0]->value eq 'connect') {
236             sprintf('Seis::BuiltinFunctions::connect(%s)',
237             $self->do_compile($v->[1]),
238             );
239             } elsif ($v->[0]->value eq 'any') {
240             sprintf('Seis::BuiltinFunctions::any(%s)',
241             $self->do_compile($v->[1]),
242             );
243             } elsif ($v->[0]->value eq 'get') {
244             sprintf('Seis::BuiltinFunctions::get(%s)',
245             $self->do_compile($v->[1]),
246             );
247             } elsif ($v->[0]->value eq 'sign') {
248             sprintf('(%s)->sign',
249             $self->do_compile($v->[1]),
250             );
251             } elsif ($v->[0]->value eq 'ords') {
252             sprintf('Seis::BuiltinFunctions::ords(%s)',
253             $self->do_compile($v->[1]),
254             );
255             } elsif ($v->[0]->value eq 'is-prime') {
256             sprintf('Seis::BuiltinFunctions::is_prime(%s)',
257             $self->do_compile($v->[1]),
258             );
259             } elsif ($v->[0]->value eq 'open') {
260             sprintf('Seis::BuiltinFunctions::open(%s)',
261             $self->do_compile($v->[1]),
262             );
263             } elsif ($v->[0]->value eq 'end') {
264             # TODO support the 'list' style.
265             sprintf('Seis::BuiltinFunctions::end(%s)',
266             $self->do_compile($v->[1]),
267             );
268             } elsif ($v->[0]->value eq 'lines') {
269             sprintf('Str::lines(%s)',
270             $self->do_compile($v->[1]),
271             );
272             } elsif ($v->[0]->value eq 'slurp') {
273             sprintf('Seis::BuiltinFunctions::slurp(%s)',
274             $self->do_compile($v->[1]),
275             );
276             } elsif ($v->[0]->value eq 'hash') {
277             sprintf('+{%s}',
278             $self->do_compile($v->[1]),
279             );
280             } elsif ($v->[0]->value eq 'push') {
281             # (funcall (ident "push") (args (variable "@a") (string "e")))
282             if (
283             $v->[1]->type == PVIP_NODE_ARGS && @{$v->[1]->value}==2 && $v->[1]->value->[0]->type == PVIP_NODE_VARIABLE && $v->[1]->value->[0]->value =~ /\A\@/) {
284             sprintf('CORE::push(%s,%s)',
285             $self->do_compile($v->[1]->value->[0], G_ARRAY),
286             $self->do_compile($v->[1]->value->[1]),
287             );
288             } else {
289             sprintf('CORE::push(%s)',
290             $self->do_compile($v->[1]),
291             );
292             }
293             } elsif ($v->[0]->value eq 'values') {
294             # (args (variable "@array"))
295             if (
296             $v->[1]->type == PVIP_NODE_ARGS && @{$v->[1]->value}==1 && $v->[1]->value->[0]->type == PVIP_NODE_VARIABLE && $v->[1]->value->[0]->value =~ /\A\@/) {
297             # values(@a)
298             if ($gimme == G_ARRAY) {
299             sprintf('CORE::values(%s)',
300             $self->do_compile($v->[1]->value->[0], G_ARRAY),
301             );
302             } else {
303             sprintf('[CORE::values(%s)]',
304             $self->do_compile($v->[1]->value->[0], G_ARRAY),
305             );
306             }
307             } else {
308             sprintf('CORE::values(%s)',
309             $self->do_compile($v->[1]),
310             );
311             }
312             } elsif ($v->[0]->value eq 'keys') {
313             # (args (variable "@array"))
314             if (
315             $v->[1]->type == PVIP_NODE_ARGS && @{$v->[1]->value}==1 && $v->[1]->value->[0]->type == PVIP_NODE_VARIABLE && $v->[1]->value->[0]->value =~ /\A\@/) {
316             # keys(@a)
317             if ($gimme == G_ARRAY) {
318             sprintf('CORE::keys(%s)',
319             $self->do_compile($v->[1]->value->[0], G_ARRAY),
320             );
321             } else {
322             sprintf('[CORE::keys(%s)]',
323             $self->do_compile($v->[1]->value->[0], G_ARRAY),
324             );
325             }
326             } else {
327             sprintf('CORE::keys(%s)',
328             $self->do_compile($v->[1]),
329             );
330             }
331             } elsif ($v->[0]->value eq 'getc') {
332             sprintf('Seis::BuiltinFunctions::getc(%s)',
333             $self->do_compile($v->[1]),
334             );
335             } elsif ($v->[0]->value eq 'close') {
336             sprintf('Seis::BuiltinFunctions::close(%s)',
337             $self->do_compile($v->[1]),
338             );
339             } else {
340             sprintf('%s(%s)',
341             $self->do_compile($v->[0]),
342             $self->do_compile($v->[1]),
343             );
344             }
345             } else {
346             sprintf('(%s)->(%s)',
347             $self->do_compile($v->[0]),
348             $self->do_compile($v->[1]),
349             );
350             }
351             } elsif ($type == PVIP_NODE_ARGS) {
352             my @args = map {
353             if ($_->type == PVIP_NODE_IDENT && $_->value eq 'Hash') {
354             'Seis::Hash::'
355             } elsif ($_->type == PVIP_NODE_IDENT && $_->value eq 'Array') {
356             'Array::'
357             } elsif ($_->type == PVIP_NODE_IDENT && $_->value eq 'IO::Path') {
358             'IO::Path::'
359             } elsif ($_->type == PVIP_NODE_IDENT && $_->value eq 'True') {
360             'Bool::True()'
361             } elsif ($_->type == PVIP_NODE_IDENT && $_->value eq 'False') {
362             'Bool::False()'
363             } elsif ($_->type == PVIP_NODE_IDENT) {
364             my $v = $_->value;
365             $v =~ s/\A:://;
366             sprintf('Seis::Class->_new(name => %s)', $self->compile_string($v));
367             } elsif ($_->type == PVIP_NODE_VARIABLE && $_->value =~ /\A\@/) {
368             my $v = $_->value;
369             $v =~ s/−/ー/g;
370             "\\$v";
371             } else {
372             $self->do_compile($_)
373             }
374             } @$v;
375             if ($self->{args_list}) {
376             join(",", map { "$_" } @args);
377             } else {
378             join(",", map { "scalar($_)" } @args);
379             }
380             } elsif ($type == PVIP_NODE_STRING) {
381             $self->compile_string($v);
382             } elsif ($type == PVIP_NODE_MOD) {
383             sprintf('(%s)%%(%s)',
384             $self->do_compile($v->[0]),
385             $self->do_compile($v->[1]),
386             );
387             } elsif ($type == PVIP_NODE_VARIABLE) {
388             $v =~ s!-!ー!g;
389             $v;
390             } elsif ($type == PVIP_NODE_MY) {
391             if (@$v==1) {
392             # (my (list (variable "$a") (variable "$b") (variable "$c")))
393             if ($v->[0]->type == PVIP_NODE_LIST) {
394             sprintf('my (%s)',
395             join(',', map { $self->do_compile($_) } @{$v->[0]->value})
396             );
397             } else {
398             die "NYI: (1)" . $node->as_sexp
399             }
400             } else {
401             my ($type, $vars) = @$v;
402             if ($vars->type == PVIP_NODE_VARIABLE) {
403             # (my (nop) (variable "$i"))
404             sprintf('my %s',
405             $self->do_compile($vars)
406             );
407             } elsif ($vars->type == PVIP_NODE_FUNC) {
408             # (my (nop) (func (ident "vtest") (params (param (nop) (variable "$cmp") (nop)) (param (vargs (variable "@v")))) (nop) (block (statements (list_assignment (my (nop) (variable "$x")) (funcall (ident "shift") (args (variable "@v")))) (while (variable "@v") (block (statements (list_assignment (my (nop) (variable "$y")) (funcall (ident "shift") (args (variable "@v")))) (funcall (ident "is") (args (cmp (methodcall (ident "Version") (ident "new") (args (variable "$x"))) (methodcall (ident "Version") (ident "new") (args (variable "$y")))) (variable "$cmp") (string_concat (string_concat (string_concat (string_concat (string_concat (string "") (variable "$x")) (string " cmp ")) (variable "$y")) (string " is ")) (variable "$cmp")))) (list_assignment (variable "$x") (variable "$y")))))))))
409             sprintf('my %s', $self->do_compile($vars));
410             } elsif ($vars->type == PVIP_NODE_LIST) {
411             # my ($a, $b);
412             sprintf('my %s', $self->do_compile($vars, G_ARRAY));
413             } else {
414             die "NYI: " . $node->as_sexp
415             }
416             }
417             } elsif ($type == PVIP_NODE_OUR) {
418             my @vars = map { $self->do_compile($_) } @$v;
419             sprintf('our (%s)',
420             join(',', map { "($_)" } @vars)
421             );
422             } elsif ($type == PVIP_NODE_BIND) {
423             # TODO: This may not compatible with Perl6.
424             sprintf('%s=(%s)',
425             $self->do_compile($v->[0], G_ARRAY),
426             $self->do_compile($v->[1], G_ARRAY),
427             );
428             } elsif ($type == PVIP_NODE_LIST_ASSIGNMENT) {
429             sprintf('%s=(%s)',
430             $self->do_compile($v->[0], G_ARRAY),
431             $self->do_compile($v->[1],
432             $self->is_list_lvalue($v->[0]) ? G_ARRAY : G_SCALAR
433             ),
434             );
435             } elsif ($type == PVIP_NODE_STRING_CONCAT) {
436             sprintf('(%s).(%s)',
437             $v->[0]->type == PVIP_NODE_STATEMENTS ? $self->do_compile($v->[0]->value->[0]) : $self->do_compile($v->[0]),
438             $v->[1]->type == PVIP_NODE_STATEMENTS ? $self->do_compile($v->[1]->value->[0]) : $self->do_compile($v->[1]),
439             );
440             } elsif ($type == PVIP_NODE_IF) {
441             # (if (int 1) (statements (int 5)) (else (int 4)))
442             my $ret = 'if (' . $self->do_compile($v->[0]) . ') {' . $self->do_compile($v->[1]) . '}';
443             shift @$v; shift @$v;
444             while (@$v) {
445             $ret .= $self->do_compile(shift @$v);
446             }
447             $ret;
448             } elsif ($type == PVIP_NODE_EQV) {
449             Seis::Exception::NotImplemented->throw("PVIP_NODE_EQV is not implemented")
450             } elsif ($type == PVIP_NODE_ARRAY) {
451             sprintf('[%s]',
452             join(',', map { "($_)" } map { $self->do_compile($_, G_ARRAY) } @$v)
453             );
454             } elsif ($type == PVIP_NODE_ATPOS) {
455             my $invocant = $self->do_compile($v->[0]);
456             my $pos = $self->do_compile($v->[1]);
457             if (
458             ($v->[0]->type == PVIP_NODE_VARIABLE && $v->[0]->value =~ /\A@/)
459             ) {
460             # @a[0]
461             sprintf('%s[(%s)]',
462             $invocant,
463             $pos,
464             );
465             } else {
466             # $a[0]
467             sprintf('(%s)->[(%s)]',
468             $invocant,
469             $pos,
470             );
471             }
472             } elsif ($type == PVIP_NODE_METHODCALL) {
473             my $invocant = $self->do_compile($v->[0]);
474             if ($v->[0]->type != PVIP_NODE_IDENT) {
475             $invocant = "($invocant)";
476             }
477              
478             my $method = $self->do_compile($v->[1]);
479             my $params = defined($v->[2]) ? $self->do_compile($v->[2]) : '';
480              
481             $method =~ s!-!ー!g;
482              
483             if ($v->[0]->type == PVIP_NODE_WHATEVER) {
484             return sprintf('(sub { shift->%s(%s) })',
485             $method,
486             $params
487             );
488             }
489              
490             if ($v->[1]->type == PVIP_NODE_STRING || $v->[1]->type == PVIP_NODE_STRING_CONCAT) {
491             sprintf('%s->${\(%s)}(%s)',
492             $invocant,
493             $method,
494             $params,
495             );
496             } else {
497             sprintf('%s->%s(%s)',
498             $invocant,
499             $method,
500             $params,
501             );
502             }
503             } elsif ($type == PVIP_NODE_FUNC) {
504             my $name = $self->do_compile($v->[0]);
505             my $exportable = $v->[2]->type == PVIP_NODE_EXPORT;
506              
507             my $ret = '';
508             $ret .= "sub $name {";
509             $ret .= "\n"; $self->{line_number}++;
510             $ret .= $self->do_compile($v->[1]);
511             $ret .= $self->do_compile($v->[3]);
512             $ret .= "}\n"; $self->{line_number}++;
513             if ($exportable) {
514             $ret .= sprintf("push \@__RG_EXPORT, %s;", $self->compile_string($name));
515             }
516             $ret;
517             } elsif ($type == PVIP_NODE_PARAMS) {
518             # (params (param (nop) (variable "$n") (nop)))
519             # (params (param (ident "Int") (variable "$n") (nop) (int 0)))
520             my $ret = '';
521             my $is_vargs = 0;
522             my $min_args = 0;
523             my $max_args = 0;
524             for my $param (@$v) {
525             $ret .= $self->do_compile($param) . ";";
526             if ($param->value->[1]->type == PVIP_NODE_VARGS) {
527             $is_vargs++;
528             } else {
529             if ($param->value->[2] == PVIP_NODE_NOP) {
530             # no default value.
531             $min_args++;
532             $max_args++;
533             } else {
534             # has default value.
535             $max_args++;
536             }
537             if ($param->value->[0]->type == PVIP_NODE_IDENT) {
538             my $type = $self->compile_string($param->value->[0]->value);
539             $ret .= sprintf('Seis::Exception::ArgumentType->throw("invalid argument type(expected %s)") unless %s->isa(%s);', $param->value->[0]->value, $param->value->[1]->value, $type);
540             }
541             }
542             }
543             unless ($is_vargs) {
544             $ret .= sprintf('Seis::Exception::ArgumentCount->throw("Invalid argument count(Expected %d to %d but " . (0+@_) . ")") unless %d <= @_ && @_<=%d;', $min_args, $max_args, $min_args, $max_args);
545             }
546             $ret .= "undef;";
547             } elsif ($type == PVIP_NODE_PARAM) {
548             # (params (param (nop) (variable "$n") (nop)))
549             # (param (nop) (vargs (variable "@a")) (nop) (int 0))
550             if (@$v==4) {
551             if ($v->[1]->type == PVIP_NODE_VARGS) {
552             sprintf('%s;', $self->do_compile($v->[1]));
553             } elsif ($v->[1]->value =~ /\A\@/) {
554             # (param (ident "Int") (variable "$x") (nop))
555             sprintf('my %s=@_;', $self->do_compile($v->[1]));
556             } else {
557             sprintf('my %s=shift;', $self->do_compile($v->[1]));
558             }
559             } else {
560             die "Should not reach here : " . $node->as_sexp;
561             }
562             } elsif ($type == PVIP_NODE_RETURN) {
563             'return (' . join(',', map { "($_)" } map {$self->do_compile($_)} @$v) . ')';
564             } elsif ($type == PVIP_NODE_ELSE) {
565             'else { ' . join(';', map { $self->do_compile($_) } @$v) . '}';
566             } elsif ($type == PVIP_NODE_WHILE) {
567             sprintf("while (%s) %s",
568             $self->do_compile($v->[0]),
569             $self->maybe_block($v->[1]));
570             } elsif ($type == PVIP_NODE_UNTIL) {
571             sprintf("until (%s) %s",
572             $self->do_compile($v->[0]),
573             $self->maybe_block($v->[1]));
574             } elsif ($type == PVIP_NODE_DIE) {
575             sprintf('die (%s)', $self->do_compile($v->[0]));
576             } elsif ($type == PVIP_NODE_ELSIF) {
577             sprintf('elsif (%s) { %s }', $self->do_compile($v->[0]), $self->do_compile($v->[1]));
578             } elsif ($type == PVIP_NODE_NOW) {
579             'Seis::BuiltinFunctions::now()'
580             } elsif ($type == PVIP_NODE_RAND) {
581             'rand()'
582             } elsif ($type == PVIP_NODE_TIME) {
583             'time()'
584             } elsif ($type == PVIP_NODE_LIST) {
585             if ($gimme == G_SCALAR) {
586             # In scalar context, create arrayref automatically.
587             sprintf('[%s]',
588             join(',', map { "($_)" } map { $self->do_compile($_) } @$v)
589             );
590             } else {
591             sprintf('(%s)',
592             join(',', map { "($_)" } map { $self->do_compile($_, G_ARRAY) } @$v)
593             );
594             }
595             } elsif ($type == PVIP_NODE_FOR) {
596             my $iteratee = $self->do_compile($v->[0], G_ARRAY);
597             if ($v->[1]->type == PVIP_NODE_LAMBDA) {
598             # (for (list (int 1) (int 2) (int 3)) (lambda (params (param (nop) (variable "$x") (nop))) (statements (inplace_add (variable "$i") (variable "$x")))))
599             # (for (variable "@list") (lambda (params) (block (statements (funcall (ident "isnt") (args (variable "$_") (string "a") (string "$_ does not get set implicitly if a pointy is given")))))))
600             my $varname = $v->[1]->value->[0]->value->[0]->value->[1]->value;
601             sprintf('for my %s (%s) %s',
602             $varname,
603             $iteratee,
604             $self->maybe_block($v->[1]->value->[1])
605             );
606             } else {
607             sprintf('for (%s) %s',
608             $iteratee,
609             $self->maybe_block($v->[1])
610             );
611             }
612             } elsif ($type == PVIP_NODE_UNLESS) {
613             my $ret = 'unless (' . $self->do_compile($v->[0]) . ') {' . $self->do_compile($v->[1]) . '}';
614             shift @$v; shift @$v;
615             while (@$v) {
616             $ret .= $self->do_compile(shift @$v);
617             }
618             $ret;
619             } elsif ($type == PVIP_NODE_NOT) {
620             if ($self->is_array_variable($v->[0])) {
621             sprintf('!(0+%s)',
622             $self->do_compile($v->[0]->value)
623             );
624             } else {
625             # I want to do this with PL_check hack.
626             sprintf('Seis::Runtime::_not(%s)',
627             $self->do_compile($v->[0])
628             );
629             }
630             } elsif ($type == PVIP_NODE_CONDITIONAL) {
631             sprintf('(%s)?(%s):(%s)',
632             $self->do_compile($v->[0]),
633             $self->do_compile($v->[1]),
634             $self->do_compile($v->[2]),
635             );
636             } elsif ($type == PVIP_NODE_NOP) {
637             return "()";
638             } elsif ($type == PVIP_NODE_POW) {
639             sprintf('(%s)**(%s)',
640             $self->do_compile($v->[0]),
641             $self->do_compile($v->[1]),
642             );
643             } elsif ($type == PVIP_NODE_CLARGS) {
644             Seis::Exception::NotImplemented->throw("PVIP_NODE_CLARGS is not implemented")
645             } elsif ($type == PVIP_NODE_HASH) {
646             if ($gimme == G_ARRAY) {
647             '(' . join(',', map { $self->do_compile($_, G_ARRAY) } @$v) . ')';
648             } else {
649             '{' . join(',', map { $self->do_compile($_, G_ARRAY) } @$v) . '}';
650             }
651             } elsif ($type == PVIP_NODE_PAIR) {
652             if ($gimme == G_SCALAR) {
653             sprintf('Pair->_new(scalar(%s),scalar(%s))',
654             $v->[0]->type == PVIP_NODE_IDENT ? $self->compile_string($v->[0]) : $self->do_compile($v->[0]),
655             $self->do_compile($v->[1]),
656             );
657             } else {
658             my $key = $v->[0]->type == PVIP_NODE_IDENT
659             ? $self->compile_string($v->[0]->value)
660             : $self->do_compile($v->[0]);
661             sprintf('(%s)=>scalar(%s)',
662             $key,
663             $self->do_compile($v->[1]),
664             );
665             }
666             } elsif ($type == PVIP_NODE_ATKEY) {
667             if ($v->[0]->type == PVIP_NODE_VARIABLE && $v->[0]->value =~ /\A%/) {
668             my $target = $self->do_compile($v->[0]);
669             $target =~ s/\A%/\$/;
670             sprintf('%s{(%s)}',
671             $target,
672             $self->do_compile($v->[1]),
673             );
674             } elsif ($v->[0]->type == PVIP_NODE_VARIABLE && $v->[0]->value =~ /\A\$/) {
675             sprintf('(%s)->{(%s)}',
676             $self->do_compile($v->[0]),
677             $self->do_compile($v->[1]),
678             );
679             } elsif ($v->[0]->type == PVIP_NODE_TW_ENV || ($v->[0]->type == PVIP_NODE_VARIABLE && $v->[0]->value =~ /\A$/)) {
680             sprintf('(%s)->{(%s)}',
681             $self->do_compile($v->[0]),
682             $self->do_compile($v->[1]),
683             );
684             } else {
685             sprintf('(%s){(%s)}',
686             $self->do_compile($v->[0]),
687             $self->do_compile($v->[1]),
688             );
689             }
690             } elsif ($type == PVIP_NODE_LOGICAL_AND) {
691             sprintf('(%s)&&(%s)',
692             $self->do_compile($v->[0]),
693             $self->do_compile($v->[1]),
694             );
695             } elsif ($type == PVIP_NODE_LOGICAL_OR) {
696             sprintf('(%s)||(%s)',
697             $self->do_compile($v->[0]),
698             $self->do_compile($v->[1]),
699             );
700             } elsif ($type == PVIP_NODE_LOGICAL_XOR) {
701             sprintf('do { my $a = (%s); my $b = (%s); if ($a) { $b ? !!0 : $a } else { $b ? $b : !!0 } }',
702             $self->do_compile($v->[0]),
703             $self->do_compile($v->[1]),
704             );
705             } elsif ($type == PVIP_NODE_BIN_AND) {
706             sprintf('(%s)&(%s)',
707             $self->do_compile($v->[0]),
708             $self->do_compile($v->[1]),
709             );
710             } elsif ($type == PVIP_NODE_BIN_OR) {
711             sprintf('(%s)|(%s)',
712             $self->do_compile($v->[0]),
713             $self->do_compile($v->[1]),
714             );
715             } elsif ($type == PVIP_NODE_BIN_XOR) {
716             sprintf('(%s)^(%s)',
717             $self->do_compile($v->[0]),
718             $self->do_compile($v->[1]),
719             );
720             } elsif ($type == PVIP_NODE_BLOCK) {
721             my $ret = '';
722             # $ret .= sprintf("# %d %d\n", $node->line_number, $self->{line_number});
723             if (@$v) {
724             $ret .= '{' . $self->do_compile($v->[0]) . '}';
725             } else {
726             $ret .= '{ }';
727             }
728             $ret;
729             } elsif ($type == PVIP_NODE_LAMBDA) {
730             # (lambda (params (param (nop) (variable "$n") (nop))) (statements (mul (variable "$n") (int 2))))
731             # (lambda (block (statements (logical_or (chain (mod (variable "$_") (int 3)) (eq (int 0))) (chain (mod (variable "$_") (int 5)) (eq (int 0)))))))
732             if (@$v==1) {
733             if ($v->[0]->type == PVIP_NODE_BLOCK) {
734             my $ret = 'sub ';
735             $ret .= $self->do_compile($v->[0]);
736             $ret;
737             } elsif ($v->[0]->type == PVIP_NODE_HASH) {
738             # (lambda (hash (pair (ident "out") (string "(IO)\n"))))
739             my $ret = 'sub ';
740             $ret .= $self->do_compile($v->[0]);
741             $ret;
742             } else {
743             ...
744             }
745             } else {
746             my $ret = 'sub {';
747             $ret .= $self->do_compile($v->[0]);
748             $ret .= $self->do_compile($v->[1]);
749             $ret .= "}";
750             $ret;
751             }
752             } elsif ($type == PVIP_NODE_USE) {
753             if ($v->[0]->value eq 'v6') {
754             $self->{line_number}++;
755             "# use v6;\n";
756             } else {
757             'use ' . $self->do_compile($v->[0]);
758             }
759             } elsif ($type == PVIP_NODE_MODULE) {
760             sprintf('package %s; our @__RG_EXPORT; use parent qw(Seis::Exporter);', $v->[0]->value);
761             } elsif ($type == PVIP_NODE_CLASS) {
762             # (class (ident "Foo7") (nop) (statements (method (ident "bar") (nop) (statements (int 5963)))))
763             # (class (ident "Foo8") (list (is (ident "Foo7"))) (statements))
764             state $ANON_CLASS = 0;
765             my $pkg = $v->[0]->type == PVIP_NODE_NOP ? "Seis::_AnonClass" . $ANON_CLASS++ : $self->do_compile($v->[0]);
766             my $retval = $gimme == G_VOID ? '' : "Seis::Class->_new(name => '$pkg')";
767             my $body = $self->do_compile($v->[2]);
768             if ($body eq '{ }') {
769             $body = '';
770             }
771             sprintf(q!do {
772             package %s;
773             BEGIN {
774             our @ISA;
775             unshift @ISA, "Seis::Object";
776             %s;
777             }
778             %s;
779             %s
780             }!, $pkg, join(";\n", map { $self->do_compile($_) } @{$v->[1]->value}), $body, $retval);
781             } elsif ($type == PVIP_NODE_METHOD) {
782             # (method (ident "bar") (nop) (statements))
783             # TODO: support arguments
784             # (method (ident "bar") (params (param (nop) (variable "$n") (nop))) (statements (mul (variable "$n") (int 3))))
785             my $name = $self->do_compile($v->[0]);
786             join('',
787             'sub ' . $name . ' {',
788             'my $self=shift;',
789             $self->do_compile($v->[1]),
790             ';undef;',
791             $self->do_compile($v->[2]),
792             ';}'
793             );
794             } elsif ($type == PVIP_NODE_UNARY_PLUS) {
795             if ($v->[0]->type == PVIP_NODE_LIST) {
796             sprintf('0+@{[%s]}', $self->do_compile($v->[0], G_ARRAY));
797             } else {
798             sprintf('(%s)->Int()', $self->do_compile($v->[0]));
799             }
800             } elsif ($type == PVIP_NODE_UNARY_MINUS) {
801             sprintf('-(%s)', $self->do_compile($v->[0]));
802             } elsif ($type == PVIP_NODE_IT_METHODCALL) {
803             sprintf('$_->%s(%s)',
804             $self->do_compile($v->[0]),
805             defined($v->[1]) ? $self->do_compile($v->[1]) : '',
806             );
807             } elsif ($type == PVIP_NODE_LAST) {
808             'last';
809             } elsif ($type == PVIP_NODE_NEXT) {
810             'next';
811             } elsif ($type == PVIP_NODE_REDO) {
812             'redo';
813             } elsif ($type == PVIP_NODE_POSTINC) {
814             sprintf('(%s)++',
815             $self->do_compile($v->[0]),
816             );
817             } elsif ($type == PVIP_NODE_POSTDEC) {
818             sprintf('(%s)--',
819             $self->do_compile($v->[0]),
820             );
821             } elsif ($type == PVIP_NODE_PREINC) {
822             sprintf('++(%s)',
823             $self->do_compile($v->[0]),
824             );
825             } elsif ($type == PVIP_NODE_PREDEC) {
826             sprintf('--(%s)',
827             $self->do_compile($v->[0]),
828             );
829             } elsif ($type == PVIP_NODE_UNARY_BITWISE_NEGATION) {
830             sprintf('~(%s)',
831             $self->do_compile($v->[0]),
832             );
833             } elsif ($type == PVIP_NODE_BRSHIFT) {
834             sprintf('(%s)>>(%s)',
835             $self->do_compile($v->[0]),
836             $self->do_compile($v->[1]),
837             );
838             } elsif ($type == PVIP_NODE_BLSHIFT) {
839             sprintf('(%s)<<(%s)',
840             $self->do_compile($v->[0]),
841             $self->do_compile($v->[1]),
842             );
843             } elsif ($type == PVIP_NODE_CHAIN) {
844             my $compile = sub {
845             my ($lhs, $type, $rhs) = @_;
846             my $op = +{
847             PVIP_NODE_EQ() => '==',
848             PVIP_NODE_NE() => '!=',
849             PVIP_NODE_LT() => '<',
850             PVIP_NODE_LE() => '<=',
851             PVIP_NODE_GT() => '>',
852             PVIP_NODE_GE() => '>=',
853             PVIP_NODE_STREQ() => 'eq',
854             PVIP_NODE_STRNE() => 'ne',
855             PVIP_NODE_STRNE() => 'ne',
856             PVIP_NODE_STRGT() => 'gt',
857             PVIP_NODE_STRGE() => 'ge',
858             PVIP_NODE_STRLT() => 'lt',
859             PVIP_NODE_STRLE() => 'le',
860             PVIP_NODE_EQV() => 'eq', # TODO
861             PVIP_NODE_SMART_MATCH() => '~~',
862             }->{$type};
863             if ($type == PVIP_NODE_NOT_SMART_MATCH) {
864             # Perl5 does not support `!~~` operator!
865             sprintf("(!((%s)~~(%s)))", $lhs, $rhs);
866             } else {
867             unless ($op) {
868             Seis::Exception::NotImplemented->throw(sprintf "PVIP_NODE_%s is not implemented in chaning", $type)
869             }
870             sprintf("(%s)%s(%s)", $lhs, $op, $rhs);
871             }
872             };
873             if (@$v == 1) {
874             return $self->do_compile($v->[0]);
875             } elsif (@$v == 2) {
876             # optimized for simple case
877             $compile->(
878             $self->do_compile($v->[0]),
879             $v->[1]->type,
880             $self->do_compile($v->[1]->value->[0]),
881             );
882             } else {
883             my $ret = 'do { my $_rg_chain_ret = 1; my $_rg_chain_rhs; my $_rg_chain_lhs = ';
884             $ret .= $self->do_compile(shift @$v);
885             $ret .= ';';
886              
887             while (my $rhs_node = shift @$v) {
888             $ret .= sprintf('$_rg_chain_rhs=%s;', $self->do_compile($rhs_node->value->[0]));
889             $ret .= sprintf('unless (%s) { $_rg_chain_ret=0; goto _RG_CHAIN_END; }', $compile->('$_rg_chain_lhs', $rhs_node->type, '$_rg_chain_rhs'));
890             $ret .= '$_rg_chain_lhs=$_rg_chain_rhs;';
891             }
892             $ret .= '_RG_CHAIN_END: $_rg_chain_ret; }';
893             return $ret;
894             }
895             } elsif ($type == PVIP_NODE_INPLACE_ADD) {
896             '(' . $self->do_compile($v->[0]) . ')+=(' . $self->do_compile($v->[1]) . ')';
897             } elsif ($type == PVIP_NODE_INPLACE_SUB) {
898             '(' . $self->do_compile($v->[0]) . ')-=(' . $self->do_compile($v->[1]) . ')';
899             } elsif ($type == PVIP_NODE_INPLACE_MUL) {
900             '(' . $self->do_compile($v->[0]) . ')*=(' . $self->do_compile($v->[1]) . ')';
901             } elsif ($type == PVIP_NODE_INPLACE_DIV) {
902             '(' . $self->do_compile($v->[0]) . ')/=(' . $self->do_compile($v->[1]) . ')';
903             } elsif ($type == PVIP_NODE_INPLACE_POW) {
904             '(' . $self->do_compile($v->[0]) . ')**=(' . $self->do_compile($v->[1]) . ')';
905             } elsif ($type == PVIP_NODE_INPLACE_MOD) {
906             '(' . $self->do_compile($v->[0]) . ')%=(' . $self->do_compile($v->[1]) . ')';
907             } elsif ($type == PVIP_NODE_INPLACE_BIN_OR) {
908             sprintf('(%s)|=(%s)',
909             $self->do_compile($v->[0]),
910             $self->do_compile($v->[1]),
911             );
912             } elsif ($type == PVIP_NODE_INPLACE_BIN_AND) {
913             sprintf('(%s)&=(%s)',
914             $self->do_compile($v->[0]),
915             $self->do_compile($v->[1]),
916             );
917             } elsif ($type == PVIP_NODE_INPLACE_BIN_XOR) {
918             sprintf('(%s)^=(%s)',
919             $self->do_compile($v->[0]),
920             $self->do_compile($v->[1]),
921             );
922             } elsif ($type == PVIP_NODE_INPLACE_BLSHIFT) {
923             sprintf('(%s)<<=(%s)',
924             $self->do_compile($v->[0]),
925             $self->do_compile($v->[1]),
926             );
927             } elsif ($type == PVIP_NODE_INPLACE_BRSHIFT) {
928             sprintf('(%s)>>=(%s)',
929             $self->do_compile($v->[0]),
930             $self->do_compile($v->[1]),
931             );
932             } elsif ($type == PVIP_NODE_INPLACE_CONCAT_S) {
933             '(' . $self->do_compile($v->[0]) . ').=(' . $self->do_compile($v->[1]) . ')';
934             } elsif ($type == PVIP_NODE_REPEAT_S) {
935             '(' . $self->do_compile($v->[0]) . ')x(' . $self->do_compile($v->[1]) . ')';
936             } elsif ($type == PVIP_NODE_INPLACE_REPEAT_S) {
937             '(' . $self->do_compile($v->[0]) . ')x=(' . $self->do_compile($v->[1]) . ')';
938             } elsif ($type == PVIP_NODE_STRINGIFY) {
939             # STRINGIFY, stringification
940             if ($self->is_array_variable($v->[0]) || $v->[0]->type == PVIP_NODE_LIST) {
941             sprintf(q{join(' ', (%s))}, $self->do_compile($v->[0], G_ARRAY));
942             } else {
943             sprintf(q{(%s)->Str()}, $self->do_compile($v->[0]));
944             }
945             } elsif ($type == PVIP_NODE_TRY) {
946             "eval " . $self->do_compile($v->[0]);
947             } elsif ($type == PVIP_NODE_REF) {
948             sprintf(q{\(%s)}, $self->do_compile($v->[0]));
949             } elsif ($type == PVIP_NODE_MULTI) {
950             Seis::Exception::NotImplemented->throw("PVIP_NODE_MULTI is not implemented")
951             } elsif ($type == PVIP_NODE_UNARY_BOOLEAN) {
952             sprintf 'Seis::Runtime::boolean(%s)', $self->do_compile($v->[0]);
953             } elsif ($type == PVIP_NODE_UNARY_UPTO) {
954             Seis::Exception::NotImplemented->throw("PVIP_NODE_UNARY_UPTO is not implemented")
955             } elsif ($type == PVIP_NODE_ARRAY_DEREF) {
956             '@{' . $self->do_compile($v->[0]) . '}';
957             } elsif ($type == PVIP_NODE_STDOUT) {
958             '*STDOUT'
959             } elsif ($type == PVIP_NODE_STDERR) {
960             '*STDERR'
961             } elsif ($type == PVIP_NODE_SCALAR_DEREF) {
962             '${' . $self->do_compile($v->[0]) . '}';
963             } elsif ($type == PVIP_NODE_TW_ENV) {
964             '(\%ENV)'
965             } elsif ($type == PVIP_NODE_TW_TMPDIR) {
966             'IO::Path->new(File::Spec->tmpdir())'
967             } elsif ($type == PVIP_NODE_TW_INC) {
968             if ($gimme == G_SCALAR) {
969             '\\@Seis::INC';
970             } else {
971             '@Seis::INC';
972             }
973             } elsif ($type == PVIP_NODE_META_METHOD_CALL) {
974             # (meta_method_call (class (nop) (nop) (statements)) (ident "methods") (nop))
975             sprintf('(%s)->meta()->%s(%s)',
976             $self->do_compile($v->[0]),
977             $self->do_compile($v->[1]),
978             $self->do_compile($v->[2]),
979             );
980             } elsif ($type == PVIP_NODE_REGEXP) {
981             $self->compile_regexp($v);
982             } elsif ($type == PVIP_NODE_SMART_MATCH) {
983             Seis::Exception::NotImplemented->throw("PVIP_NODE_SMART_MATCH is not implemented")
984             } elsif ($type == PVIP_NODE_NOT_SMART_MATCH) {
985             Seis::Exception::NotImplemented->throw("PVIP_NODE_NOT_SMART_MATCH is not implemented")
986             } elsif ($type == PVIP_NODE_PERL5_REGEXP) {
987             sprintf('qr!%s!', $v);
988             } elsif ($type == PVIP_NODE_FALSE) {
989             '(Bool::false())'
990             } elsif ($type == PVIP_NODE_TRUE) {
991             '(Bool::True())'
992             } elsif ($type == PVIP_NODE_TW_VM) {
993             Seis::Exception::NotImplemented->throw("PVIP_NODE_TW_VM is not implemented")
994             } elsif ($type == PVIP_NODE_HAS) {
995             # (has (public_attribute "x"))
996             # support private variable
997             if ($v->[0]->type == PVIP_NODE_ATTRIBUTE_VARIABLE) {
998             sprintf(q!__PACKAGE__->meta->add_attribute(%s)!, $self->compile_string($v->[0]->value));
999             } else {
1000             die "Should not reach here";
1001             }
1002             } elsif ($type == PVIP_NODE_ATTRIBUTE_VARIABLE) {
1003             # (public_attribute "x")
1004             sprintf('$self->{%s}', $self->compile_string($v));
1005             } elsif ($type == PVIP_NODE_FUNCREF) {
1006             sprintf('\&%s', $self->do_compile($v->[0]));
1007             } elsif ($type == PVIP_NODE_PATH) {
1008             sprintf('IO::Path->new(%s)',
1009             $self->compile_string($node)
1010             );
1011             } elsif ($type == PVIP_NODE_TW_PACKAGE) {
1012             Seis::Exception::NotImplemented->throw("PVIP_NODE_TW_PACKAGE is not implemented")
1013             } elsif ($type == PVIP_NODE_TW_CLASS) {
1014             'Seis::MetaClass->new(name => __PACKAGE__)'
1015             } elsif ($type == PVIP_NODE_TW_MODULE) {
1016             Seis::Exception::NotImplemented->throw("PVIP_NODE_TW_MODULE is not implemented")
1017             } elsif ($type == PVIP_NODE_TW_OS) {
1018             '($^O)';
1019             } elsif ($type == PVIP_NODE_E) {
1020             '(exp(1))';
1021             } elsif ($type == PVIP_NODE_TW_PID) {
1022             '($$)';
1023             } elsif ($type == PVIP_NODE_TW_PERLVER) {
1024             '6'
1025             } elsif ($type == PVIP_NODE_TW_OSVER) {
1026             'do {require Config; $Config::Config{osvers} }';
1027             } elsif ($type == PVIP_NODE_TW_CWD) {
1028             '(IO::Path->new(Cwd::getcwd()))'
1029             } elsif ($type == PVIP_NODE_TW_EXECUTABLE_NAME) {
1030             '($0)'
1031             } elsif ($type == PVIP_NODE_TW_ROUTINE) {
1032             'Sub->_new(__SUB__)';
1033             } elsif ($type == PVIP_NODE_SLANGS) {
1034             Seis::Exception::NotImplemented->throw("PVIP_NODE_SLANGS is not implemented")
1035             } elsif ($type == PVIP_NODE_LOGICAL_ANDTHEN) {
1036             Seis::Exception::NotImplemented->throw("PVIP_NODE_LOGICAL_ANDTHEN is not implemented")
1037             } elsif ($type == PVIP_NODE_VALUE_IDENTITY) {
1038             Seis::Exception::NotImplemented->throw("PVIP_NODE_VALUE_IDENTITY is not implemented")
1039             } elsif ($type == PVIP_NODE_CMP) {
1040             sprintf('(%s)cmp(%s)',
1041             $self->do_compile($v->[0]),
1042             $self->do_compile($v->[1]),
1043             );
1044             } elsif ($type == PVIP_NODE_SPECIAL_VARIABLE_REGEXP_MATCH) {
1045             '@Seis::Runtime::REGEXP_MATCH'
1046             } elsif ($type == PVIP_NODE_SPECIAL_VARIABLE_EXCEPTIONS) {
1047             # Perl5's $@ contains "" if there is no errors.
1048             # It's incompatible with Perl6.
1049             '($@ ? $@ : undef)';
1050             } elsif ($type == PVIP_NODE_ENUM) {
1051             Seis::Exception::NotImplemented->throw("PVIP_NODE_ENUM is not implemented")
1052             } elsif ($type == PVIP_NODE_NUM_CMP) {
1053             sprintf('(%s)<=>(%s)',
1054             $self->do_compile($v->[0]),
1055             $self->do_compile($v->[1]),
1056             );
1057             } elsif ($type == PVIP_NODE_UNARY_FLATTEN_OBJECT) {
1058             Seis::Exception::NotImplemented->throw("PVIP_NODE_UNARY_FLATTEN_OBJECT is not implemented")
1059             } elsif ($type == PVIP_NODE_COMPLEX) {
1060             sprintf('Seis::Complex->_new(%s)', $self->compile_string($v));
1061             } elsif ($type == PVIP_NODE_ROLE) {
1062             Seis::Exception::NotImplemented->throw("PVIP_NODE_ROLE is not implemented")
1063             } elsif ($type == PVIP_NODE_IS) {
1064             # (is (ident "Foo7"))
1065             sprintf q!push @ISA, '%s'!, $self->do_compile($v->[0]);
1066             } elsif ($type == PVIP_NODE_DOES) {
1067             Seis::Exception::NotImplemented->throw("PVIP_NODE_DOES is not implemented")
1068             } elsif ($type == PVIP_NODE_JUNCTIVE_AND) {
1069             Seis::Exception::NotImplemented->throw("PVIP_NODE_JUNCTIVE_AND is not implemented")
1070             } elsif ($type == PVIP_NODE_JUNCTIVE_SAND) {
1071             Seis::Exception::NotImplemented->throw("PVIP_NODE_JUNCTIVE_SAND is not implemented")
1072             } elsif ($type == PVIP_NODE_JUNCTIVE_OR) {
1073             Seis::Exception::NotImplemented->throw("PVIP_NODE_JUNCTIVE_OR is not implemented")
1074             } elsif ($type == PVIP_NODE_UNICODE_CHAR) {
1075             sprintf(q!"\N{%s}"!, $v);
1076             } elsif ($type == PVIP_NODE_STUB) {
1077             '...';
1078             } elsif ($type == PVIP_NODE_EXPORT) {
1079             Seis::Exception::NotImplemented->throw("PVIP_NODE_EXPORTABLE is not implemented")
1080             } elsif ($type == PVIP_NODE_BITWISE_OR) {
1081             Seis::Exception::NotImplemented->throw("PVIP_NODE_BITWISE_OR is not implemented")
1082             } elsif ($type == PVIP_NODE_BITWISE_AND) {
1083             sprintf('(%s)&(%s)',
1084             $self->do_compile($v->[0]),
1085             $self->do_compile($v->[1]),
1086             );
1087             } elsif ($type == PVIP_NODE_BITWISE_XOR) {
1088             Seis::Exception::NotImplemented->throw("PVIP_NODE_BITWISE_XOR is not implemented")
1089             } elsif ($type == PVIP_NODE_VARGS) {
1090             # (vargs (variable "@a"))
1091             sprintf('my %s = @_;', $self->do_compile($v->[0]));
1092             } elsif ($type == PVIP_NODE_TW_A) {
1093             '($Seis::Runtime::TW_A)';
1094             } elsif ($type == PVIP_NODE_TW_B) {
1095             '($Seis::Runtime::TW_B)';
1096             } elsif ($type == PVIP_NODE_TW_C) {
1097             '($Seis::Runtime::TW_C)';
1098             } elsif ($type == PVIP_NODE_WHATEVER) {
1099             '(Seis::Whatever->new())';
1100             } elsif ($type == PVIP_NODE_NEED) {
1101             sprintf("BEGIN { require %s }", $self->do_compile($v->[0]));
1102             } elsif ($type == PVIP_NODE_END) {
1103             "END " . $self->do_compile($v->[0]);
1104             } elsif ($type == PVIP_NODE_GCD) {
1105             sprintf('Seis::BuiltinFunctions::gcd(%s, %s)',
1106             $self->do_compile($v->[0]),
1107             $self->do_compile($v->[1]),
1108             );
1109             } elsif ($type == PVIP_NODE_BEGIN) {
1110             "BEGIN " . $self->do_compile($v->[0]);
1111             } elsif ($type == PVIP_NODE_PACKAGE) {
1112             sprintf('package %s %s',
1113             $self->do_compile($v->[0]),
1114             $self->do_compile($v->[1])
1115             );
1116             } else {
1117             Seis::Exception::UnknownNode->throw(
1118             ("Unknown node: PVIP_NODE_" . uc($node->name))
1119             );
1120             }
1121             }
1122              
1123             sub binop {
1124             my ($self, $op, $v) = @_;
1125             sprintf('(%s)%s(%s)',
1126             $self->do_compile($v->[0]),
1127             $op,
1128             $v,
1129             $self->do_compile($v->[1]),
1130             );
1131             }
1132              
1133             sub maybe_block {
1134             my ($self, $node) = @_;
1135             if ($node->type == PVIP_NODE_BLOCK) {
1136             return $self->do_compile($node);
1137             } else {
1138             return '{' . $self->do_compile($node) . "}";
1139             }
1140             }
1141              
1142             sub compile_string{
1143             my ($self, $v) = @_;
1144              
1145             local $Data::Dumper::Terse = 1;
1146             local $Data::Dumper::Useqq = 1;
1147             local $Data::Dumper::Purity = 1;
1148             local $Data::Dumper::Indent = 0;
1149             Data::Dumper::Dumper(Encode::decode_utf8($v));
1150             }
1151              
1152             sub is_list_lvalue {
1153             my ($self, $node) = @_;
1154             my $is_list_var = sub {
1155             my $c = shift;
1156             return $c->type == PVIP_NODE_VARIABLE && $c->value =~ /\A[%@]/;
1157             };
1158             if ($node->type == PVIP_NODE_MY) {
1159             # my, nop, list
1160             # my, nop, var
1161             if (@{$node->value}==2) {
1162             my $c = $node->value->[1];
1163             if ($is_list_var->($c)) {
1164             # my @x = ...
1165             1
1166             } elsif ($c->type == PVIP_NODE_LIST) {
1167             # my ($x, $y) = ...
1168             1
1169             } elsif ($c->type == PVIP_NODE_TW_INC) {
1170             1; # @*INC
1171             } else {
1172             # my $x = ...
1173             0
1174             }
1175             } elsif (@{$node->value}==1) {
1176             my $c = $node->value->[0];
1177             if ($c->type == PVIP_NODE_LIST) {
1178             1
1179             } elsif ($c->type == PVIP_NODE_TW_INC) {
1180             1; # @*INC
1181             } else {
1182             0;
1183             }
1184             } else {
1185             0;
1186             }
1187             } else {
1188             # @x = ...
1189             if ($is_list_var->($node)) {
1190             # my @x = ...
1191             1
1192             } elsif ($node->type == PVIP_NODE_TW_INC) {
1193             1; # @*INC
1194             } else {
1195             # my $x = ...
1196             0
1197             }
1198             }
1199             }
1200              
1201             sub compile_regexp {
1202             my ($class, $regexp) = @_;
1203             my $ret = '';
1204             while (length($regexp)) {
1205             if ($regexp =~ s/\A//) {
1206             $ret .= '\p{PosixAlpha}';
1207             } elsif ($regexp =~ s/\A +//) {
1208             next;
1209             } elsif ($regexp =~ s/\A!//) {
1210             $ret .= '\!';
1211             } elsif ($regexp =~ s/\A(.)//s) {
1212             $ret .= $1;
1213             } else {
1214             die "Should not reache here: " . Data::Dumper::Dumper($regexp);
1215             }
1216             }
1217             sprintf('qr!%s!sxp', $ret);
1218             }
1219              
1220             sub is_array_variable {
1221             my ($self, $node) = @_;
1222             return $node->type == PVIP_NODE_VARIABLE && $node->value =~ /\A\@/;
1223             }
1224              
1225             1;
1226