File Coverage

blib/lib/Language/LispPerl/Evaler.pm
Criterion Covered Total %
statement 361 502 71.9
branch 125 232 53.8
condition 65 117 55.5
subroutine 47 49 95.9
pod 13 34 38.2
total 611 934 65.4


line stmt bran cond sub pod time code
1             package Language::LispPerl::Evaler;
2             $Language::LispPerl::Evaler::VERSION = '0.005';
3 6     6   4261 use Moose;
  6         2553504  
  6         48  
4              
5 6     6   40453 use File::ShareDir;
  6         36917  
  6         427  
6 6     6   62 use File::Spec;
  6         10  
  6         153  
7 6     6   35 use File::Basename;
  6         12  
  6         449  
8              
9 6     6   3221 use Language::LispPerl::Reader;
  6         26  
  6         291  
10 6     6   4068 use Language::LispPerl::Var;
  6         26  
  6         288  
11 6     6   61 use Language::LispPerl::Printer;
  6         15  
  6         152  
12 6     6   4320 use Language::LispPerl::BuiltIns;
  6         310  
  6         285  
13              
14 6     6   49 use Log::Any qw/$log/;
  6         8  
  6         50  
15              
16             BEGIN{
17             # The test compatible File::Share
18 6     6   1648 eval{ require File::Share; File::Share->import('dist_dir'); };
  6         3913  
  6         4161  
19 6 50       33651 if( $@ ){
20             # The production only File::ShareDir
21 0         0 require File::ShareDir;
22 0         0 File::ShareDir->import('dist_dir');
23             }
24             };
25              
26              
27             our $namespace_key = "0namespace0";
28              
29             has 'scopes' => ( is => 'ro', default => sub{
30             return [ { $namespace_key => [] } ]
31             });
32             has 'loaded_files' => ( is => 'ro', default => sub{ {}; } );
33              
34             has 'file_stack' => ( is => 'ro', default => sub{ []; } );
35             has 'caller' => ( is => 'ro' , default => sub{ []; } );
36              
37             has 'quotation_scope' => ( is => 'ro', default => 0 );
38             has 'syntaxquotation_scope' => ( is => 'ro', default => 0 );
39              
40             has 'exception' => ( is => 'rw' );
41              
42             # The container for the builtin functions.
43             has 'builtins' => ( is => 'ro', lazy_build => 1 );
44              
45             sub _build_builtins{
46 8     8   16 my ($self) = @_;
47 8         367 return Language::LispPerl::BuiltIns->new({ evaler => $self });
48             }
49              
50             sub to_hash{
51 4     4 0 26 my ($self) = @_;
52             return {
53 4         171 'scopes' => Language::LispPerl::Printer::to_perl( $self->scopes() ),
54             'loaded_files' => Language::LispPerl::Printer::to_perl( $self->loaded_files() ),
55             'file_stack' => Language::LispPerl::Printer::to_perl( $self->file_stack() ),
56             'caller' => Language::LispPerl::Printer::to_perl( $self->caller() ),
57             'quotation_scope' => Language::LispPerl::Printer::to_perl( $self->quotation_scope() ),
58             'syntaxquotation_scope' => Language::LispPerl::Printer::to_perl( $self->syntaxquotation_scope() ),
59             'exception' => Language::LispPerl::Printer::to_perl( $self->exception() ),
60             __class => $self->blessed(),
61             };
62             }
63              
64             sub from_hash{
65 2     2 0 1894 my ($class, $hash) = @_;
66             return $class->new({
67 2         15 map { $_ => Language::LispPerl::Reader::from_perl( $hash->{$_} ) } keys %$hash
  16         43  
68             });
69             }
70              
71             =head2 new_instance
72              
73             Returns a new instance of this with the same builtins and everything else reset.
74              
75             Usage:
76              
77             my $other_evaler = $this->new_instance();
78              
79             =cut
80              
81             sub new_instance{
82 0     0 1 0 my ($self) = @_;
83 0         0 return ref($self)->new( { builtins => $self->builtins() } );
84             }
85              
86             sub clear_exception{
87 3     3 0 4 my ($self) = @_;
88 3         7 $self->{exception} = undef;
89             }
90              
91             sub push_scope {
92 56     56 0 77 my $self = shift;
93 56   33     146 my $context = shift // confess("Cannot push undef context");
94 56         64 my %c = %{$context};
  56         412  
95 56         118 my @ns = @{ $c{$namespace_key} };
  56         148  
96 56         114 $c{$namespace_key} = \@ns;
97 56         66 unshift @{ $self->scopes() }, \%c;
  56         1924  
98             }
99              
100             sub pop_scope {
101 56     56 0 78 my $self = shift;
102 56         71 shift @{ $self->scopes() };
  56         1813  
103             }
104              
105             sub current_scope {
106 1189     1189 0 983 my $self = shift;
107 1189         875 my $scope = @{ $self->scopes() }[0];
  1189         39945  
108 1189         1921 return $scope;
109             }
110              
111             sub push_caller {
112 56     56 0 75 my $self = shift;
113 56         70 my $ast = shift;
114 56         102 unshift @{ $self->caller() }, $ast;
  56         1835  
115             }
116              
117             sub pop_caller {
118 56     56 0 94 my $self = shift;
119 56         54 shift @{ $self->caller() };
  56         1843  
120             }
121              
122             sub caller_size {
123 6     6 0 8 my $self = shift;
124 6         6 scalar @{ $self->caller() };
  6         134  
125             }
126              
127             =head2 copy_caller
128              
129             Returns a shallow copy of this caller's stack.
130              
131             Usage:
132              
133             my $caller_stack = $this->copy_caller();
134              
135             =cut
136              
137             sub copy_caller{
138 4     4 1 5 my ($self) = @_;
139 4         8 return [ @{ $self->caller() } ];
  4         89  
140             }
141              
142             =head2 copy_current_scope
143              
144             Take a shallow copy of the current scope that
145             is adequate for function and macro contexts
146              
147             =cut
148              
149             sub copy_current_scope{
150 64     64 1 104 my ($self) = @_;
151             # Take a shallow copy of the current_scope
152 64         79 my %c = %{ $self->current_scope() };
  64         150  
153              
154             # Take a shallow copy of the namespace (keyed by namespace_key)
155 64         121 my @ns = @{ $c{$namespace_key} };
  64         170  
156 64         118 $c{$namespace_key} = \@ns;
157              
158 64         208 return \%c;
159             }
160              
161             sub push_namespace {
162 2     2 0 4 my $self = shift;
163 2         4 my $namespace = shift;
164 2         10 my $scope = $self->current_scope();
165 2         5 unshift @{ $scope->{$namespace_key} }, $namespace;
  2         11  
166             }
167              
168             sub pop_namespace {
169 2     2 0 5 my $self = shift;
170 2         7 my $scope = $self->current_scope();
171 2         6 shift @{ $scope->{$namespace_key} };
  2         8  
172             }
173              
174             sub current_namespace {
175 681     681 0 624 my $self = shift;
176 681         823 my $scope = $self->current_scope();
177 681         587 my $namespace = @{ $scope->{$namespace_key} }[0];
  681         1042  
178 681 100       3881 return "" if ( !defined $namespace );
179 42         232 return $namespace;
180             }
181              
182             =head2 new_var
183              
184             From a name and a value, creates a new L<Language::LispPerl::Var> under the
185             key 'name' in $this->current_scope();
186              
187             Usage:
188              
189             $this->new_var( 'bla' , 1 );
190              
191             =cut
192              
193             sub new_var {
194 180     180 1 200 my $self = shift;
195 180         199 my $name = shift;
196 180         163 my $value = shift;
197 180         296 my $scope = $self->current_scope();
198 180         318 $name = $self->current_namespace() . "#" . $name;
199 180         6546 $scope->{$name} = Language::LispPerl::Var->new({ name => $name, value => $value });
200             }
201              
202             =head2 var
203              
204             Lookup the L<Language::LispPerl::Var> by name in the current scope or in the current namespace.
205             Returns undef if no such variable is found.
206              
207             Usage:
208              
209             if( my $var = $this->var( 'blabla' ) ){
210             ...
211             }
212              
213             =cut
214              
215             sub var {
216 256     256 1 272 my $self = shift;
217 256         277 my $name = shift;
218 256         461 my $scope = $self->current_scope();
219 256 100       759 if ( exists $scope->{$name} ) {
    100          
    50          
220 4         11 return $scope->{$name};
221             }
222             elsif ( exists $scope->{ $self->current_namespace() . "#" . $name } ) {
223 247         428 return $scope->{ $self->current_namespace() . "#" . $name };
224             }
225             elsif ( exists $scope->{ "#" . $name } ) {
226 5         10 return $scope->{ "#" . $name };
227             }
228 0         0 return undef;
229             }
230              
231             =head2 current_file
232              
233             Returns the current file on the file_stack or '.' if no such thing
234             exists.
235              
236             =cut
237              
238             sub current_file {
239 0     0 1 0 my $self = shift;
240 0         0 my $sd = scalar @{ $self->{file_stack} };
  0         0  
241 0 0       0 if ( $sd == 0 ) {
242 0         0 return ".";
243             }
244             else {
245 0         0 return ${ $self->{file_stack} }[ $sd - 1 ];
  0         0  
246             }
247             }
248              
249             =head2 search_file
250              
251             Looks up the given file name (fully qualified, with clp extension or not)
252             in this package's share directory or in @INC.
253              
254             dies with an error if no file can be found.
255              
256             Usage:
257              
258             $this->search_file('core');
259              
260             =cut
261              
262             sub search_file {
263 6     6 1 12 my $self = shift;
264 6         11 my $file = shift;
265              
266 6         32 my $dist_dir = dist_dir( 'Language-LispPerl' );
267 6         1419 $log->debug("Using dist dir = $dist_dir");
268              
269 6         26 foreach my $ext ( '', '.clp' ) {
270 9 100       240 if ( -f "$file$ext" ) {
    100          
271 1         29 return "$file$ext";
272             }
273             elsif ( -f $dist_dir. "/lisp/$file$ext" ) {
274 5         111 return $dist_dir . "/lisp/$file$ext";
275             }
276 3         7 foreach my $p (@INC) {
277 33 50       568 if ( -f "$p/$file$ext" ) {
278 0         0 return "$p/$file$ext";
279             }
280             }
281             }
282 0         0 Language::LispPerl::Logger::error( "cannot find " . $file );
283             }
284              
285             =head2 load
286              
287             Reads a file once if it hasn't been read before, for loading
288             libraries in the global scope.
289              
290             Usage:
291              
292             $this->load(/path/to/file.clp');
293              
294             =cut
295              
296             sub load {
297 6     6 1 20 my $self = shift;
298 6         12 my $file = shift;
299              
300             Language::LispPerl::Logger::error(
301             "cannot require file " . $file . " in non-global scope" )
302 6 50       10 if scalar @{ $self->scopes() } > 1;
  6         192  
303              
304 6         29 $file = File::Spec->rel2abs( $self->search_file($file) );
305              
306 6 100       36 return 1 if exists $self->{loaded_files}->{$file};
307 5         20 $self->{loaded_files}->{$file} = 1;
308 5         8 push @{ $self->{file_stack} }, $file;
  5         14  
309 5         17 my $res = $self->read($file);
310 5         11 pop @{ $self->{file_stack} };
  5         16  
311 5         43 return $res;
312             }
313              
314             =head2 read
315              
316             Reads and evaluates in this evaler
317             all the expressions in the given filename
318             and returns the last evaluation result.
319              
320             Usage:
321              
322             $this->read('/path/to/file.clp');
323              
324             =cut
325              
326             sub read {
327 6     6 1 11 my $self = shift;
328 6         10 my $file = shift;
329 6         53 my $reader = Language::LispPerl::Reader->new();
330 6         29 $reader->read_file($file);
331 6         18 my $res = undef;
332 6     45   34 $reader->ast()->each( sub { $res = $self->_eval( $_[0] ) } );
  45         143  
333 6         289 return $res;
334             }
335              
336             our $empty_list = Language::LispPerl::Seq->new({ type => "list" });
337             our $true = Language::LispPerl::Atom->new({type => "bool", value => "true" });
338             our $false = Language::LispPerl::Atom->new({type => "bool", value => "false"});
339             our $nil = Language::LispPerl::Atom->new({type => "nil", value => "nil"});
340              
341 21     21 0 257 sub true{ return $true; }
342 11     11 0 160 sub false{ return $false; }
343 12     12 0 102 sub nil{ return $nil; }
344 1     1 0 5 sub empty_list{ return $empty_list; }
345              
346             =head2 eval
347              
348             Evaluates a string and returns the result of the latest expression (or dies
349             with an error).
350              
351             Return the nil/nil atom when the given string is empty.
352              
353             Usage:
354              
355             my $res = $this->eval(q|( - 1 1 ) ( + 1 2 )|);
356             # $res->value() is 3
357              
358             =cut
359              
360             sub eval {
361 100     100 1 14564 my ($self, $str) = @_;
362 100 100       458 unless( length( defined( $str ) ? $str : '' ) ){
    100          
363 1         53 return $nil;
364             }
365              
366 99         907 my $reader = Language::LispPerl::Reader->new();
367 99         363 $reader->read_string($str);
368 99         135 my $res = undef;
369 99     108   279 $reader->ast()->each( sub { $res = $self->_eval( $_[0] ) } );
  108         463  
370 97         4548 return $res;
371             }
372              
373              
374             =head2 bind
375              
376             Associate the current L<Language::LispPerl::Atom> or L<Language::LispPerl::Seq>
377             with the correct Perl/Lisp space values.
378              
379             =cut
380              
381             sub bind {
382 657     657 1 786 my $self = shift;
383 657         585 my $ast = shift;
384 657         19167 my $class = $ast->class();
385 657         18855 my $type = $ast->type();
386 657         18849 my $value = $ast->value();
387 657 100 100     10431 if ( $type eq "symbol" and $value eq "true" ) {
    100 100        
    100 100        
    50 66        
    50 100        
    100 66        
    100 66        
    50 66        
    100 66        
388 12         54 return $true;
389             }
390             elsif ( $type eq "symbol" and $value eq "false" ) {
391 7         27 return $false;
392             }
393             elsif ( $type eq "symbol" and $value eq "nil" ) {
394 1         8 return $nil;
395             }
396             elsif ( $type eq "accessor" ) {
397 0         0 return Language::LispPerl::Atom->new({ type => "accessor", value => $self->bind($value) } );
398             }
399             elsif ( $type eq "sender" ) {
400 0         0 return Language::LispPerl::Atom->new({ type => "sender", value => $self->bind($value) });
401             }
402             elsif ( $type eq "syntaxquotation" or $type eq "quotation" ) {
403 40 50       127 $self->{syntaxquotation_scope} += 1 if $type eq "syntaxquotation";
404 40 50       99 $self->{quotation_scope} += 1 if $type eq "quotation";
405 40         120 my $r = $self->bind($value);
406 40 50       128 $self->{syntaxquotation_scope} -= 1 if $type eq "syntaxquotation";
407 40 50       79 $self->{quotation_scope} -= 1 if $type eq "quotation";
408 40         123 return $r;
409             }
410             elsif (
411             (
412             $type eq "symbol" and $self->{syntaxquotation_scope} == 0
413             and $self->{quotation_scope} == 0
414             )
415             or ( $type eq "dequotation" and $self->{syntaxquotation_scope} > 0 )
416             )
417             {
418             $ast->error("dequotation should be in syntax quotation scope")
419 448 50 66     1157 if ( $type eq "dequotation" and $self->{syntaxquotation_scope} == 0 );
420 448         515 my $name = $value;
421 448 100 100     1111 if ( $type eq "dequotation" and $value =~ /^@(\S+)$/ ) {
422 33         66 $name = $1;
423             }
424 448 100       888 return $ast
425             if $self->word_is_reserved( $name );
426 192         446 my $var = $self->var($name);
427 192 50       354 $ast->error("unbound symbol '$var'") if !defined $var;
428 192         5964 return $var->value();
429             }
430             elsif ( $type eq "symbol"
431             and $self->{quotation_scope} > 0 )
432             {
433 0         0 my $q = Language::LispPerl::Atom->new({ type => "quotation", value => $value });
434 0         0 return $q;
435             }
436             elsif ( $class eq "Seq" ) {
437 69 50 66     259 return $empty_list if $type eq "list" and $ast->size() == 0;
438 69         2228 my $list = Language::LispPerl::Seq->new({ type => "list" });
439 69         2004 $list->type($type);
440 69         59 foreach my $i ( @{$value} ) {
  69         136  
441 203 100 100     6323 if ( $i->type() eq "dequotation" and $i->value() =~ /^@/ ) {
442 33         86 my $dl = $self->bind($i);
443 33 50       992 $i->error( "~@ should be given a list but got " . $dl->type() )
444             if $dl->type() ne "list";
445 33         43 foreach my $di ( @{ $dl->value() } ) {
  33         951  
446 49         115 $list->append($di);
447             }
448             }
449             else {
450 170         378 $list->append( $self->bind($i) );
451             }
452             }
453 69         163 return $list;
454             }
455 80         263 return $ast;
456             }
457              
458             sub _eval {
459 915     915   869 my $self = shift;
460 915         730 my $ast = shift;
461 915         29038 my $class = $ast->class();
462 915         27441 my $type = $ast->type();
463 915         27534 my $value = $ast->value();
464 915 100 100     4301 if ( $type eq "list" ) {
    50 100        
    50 66        
    100 66        
    100          
    50          
    100          
    100          
    100          
465 308         824 my $size = $ast->size();
466 308 50       629 if ( $size == 0 ) {
467 0         0 return $empty_list;
468             }
469 308         679 my $f = $self->_eval( $ast->first() );
470 308         9259 my $ftype = $f->type();
471 308         9016 my $fvalue = $f->value();
472 308 100       877 if ( $ftype eq "symbol" ) {
    50          
    50          
    100          
    50          
    50          
473 255         723 return $self->builtin( $f, $ast );
474             }
475             elsif ( $ftype eq "key accessor" ) {
476 0 0       0 $ast->error("key accessor expects >= 1 arguments") if $size == 1;
477 0         0 my $m = $self->_eval( $ast->second() );
478 0         0 my $mtype = $m->type();
479 0         0 my $mvalue = $m->value();
480 0 0 0     0 $ast->error(
481             "key accessor expects a map or meta as the first arguments but got "
482             . $mtype )
483             if $mtype ne "map" and $mtype ne "meta";
484 0 0       0 if ( $size == 2 ) {
    0          
485              
486             #$ast->error("key " . $fvalue . " does not exist")
487 0 0       0 return $nil if !exists $mvalue->{$fvalue};
488 0         0 return $mvalue->{$fvalue};
489             }
490             elsif ( $size == 3 ) {
491 0         0 my $v = $self->_eval( $ast->third() );
492 0 0       0 if ( $v->type() eq "nil" ) {
493 0         0 delete $mvalue->{$fvalue};
494 0         0 return $nil;
495             }
496             else {
497 0         0 $mvalue->{$fvalue} = $v;
498 0         0 return $mvalue->{$fvalue};
499             }
500             }
501             else {
502 0         0 $ast->error("key accessor expects <= 2 arguments");
503             }
504             }
505             elsif ( $ftype eq "index accessor" ) {
506 0 0       0 $ast->error("index accessor expects >= 1 arguments") if $size == 1;
507 0         0 my $v = $self->_eval( $ast->second() );
508 0         0 my $vtype = $v->type();
509 0         0 my $vvalue = $v->value();
510 0 0 0     0 $ast->error(
      0        
511             "index accessor expects a vector or list or xml as the first arguments but got "
512             . $vtype )
513             if $vtype ne "vector"
514             and $vtype ne "list"
515             and $vtype ne "xml";
516             $ast->error("index is bigger than size")
517 0 0       0 if $fvalue >= scalar @{$vvalue};
  0         0  
518 0 0       0 if ( $size == 2 ) {
    0          
519 0         0 return $vvalue->[$fvalue];
520             }
521             elsif ( $size == 3 ) {
522 0         0 $vvalue->[$fvalue] = $self->_eval( $ast->third() );
523 0         0 return $vvalue->[$fvalue];
524             }
525             else {
526 0         0 $ast->error("index accessor expects <= 2 arguments");
527             }
528             }
529             elsif ( $ftype eq "function" ) {
530             # Fallback to current scope if the function
531             # definition didnt shallow copy its current scope at the time of definition.
532             # This is the case when the evaler is persisted and then defrosted.
533 19   66     632 my $scope = $f->context() // $self->copy_current_scope();
534              
535 19         36 my $fn = $fvalue;
536 19         70 my $fargs = $fn->second();
537 19         95 my @rargs = $ast->slice( 1 .. $size - 1 );
538 19         40 my @rrargs = ();
539 19         47 foreach my $arg (@rargs) {
540 21         54 push @rrargs, $self->_eval($arg);
541             }
542 19         70 $self->push_scope($scope);
543 19         72 $self->push_caller($fn);
544 19         35 my $rest_args = undef;
545 19         29 my $i = 0;
546 19         655 my $fargsvalue = $fargs->value();
547 19         30 my $fargsn = scalar @{$fargsvalue};
  19         52  
548 19         34 my $rrargsn = scalar @rrargs;
549              
550 19         75 for ( $i = 0 ; $i < $fargsn ; $i++ ) {
551 21         740 my $name = $fargsvalue->[$i]->value();
552 21 50       62 if ( $name eq "&" ) {
553 0         0 $i++;
554 0         0 $name = $fargsvalue->[$i]->value();
555 0         0 $rest_args = Language::LispPerl::Seq->new({ type => "list" });
556 0         0 $self->new_var( $name, $rest_args );
557             }
558             else {
559 21 50       63 $ast->error("real arguments < formal arguments")
560             if $i >= $rrargsn;
561 21         63 $self->new_var( $name, $rrargs[$i] );
562             }
563             }
564 19 50       51 if ( defined $rest_args ) {
565 0         0 $i -= 2;
566 0         0 for ( ; $i < $rrargsn ; $i++ ) {
567 0         0 $rest_args->append( $rrargs[$i] );
568             }
569             }
570             else {
571 19 50       50 $ast->error("real arguments > formal arguments")
572             if $i < $rrargsn;
573             }
574 19         76 my @body = $fn->slice( 2 .. $fn->size() - 1 );
575 19         30 my $res;
576 19         46 foreach my $b (@body) {
577 19         56 $res = $self->_eval($b);
578             }
579 19         64 $self->pop_scope();
580 19         665 $self->pop_caller();
581 19         341 return $res;
582             }
583             elsif ( $ftype eq "perlfunction" ) {
584 0         0 my $meta = undef;
585 0 0 0     0 $meta = $self->_eval( $ast->second() )
586             if defined $ast->second()
587             and $ast->second()->type() eq "meta";
588 0         0 my $perl_func = \&{ $f->value() };
  0         0  
589 0 0       0 my @args = $ast->slice( ( defined $meta ? 2 : 1 ) .. $size - 1 );
590 0         0 return $self->perlfunc_call( $perl_func, $meta, \@args, $ast );
591             }
592             elsif ( $ftype eq "macro" ) {
593 34         64 my $scope = $f->{context};
594 34         44 my $fn = $fvalue;
595 34         107 my $fargs = $fn->third();
596 34         109 my @rargs = $ast->slice( 1 .. $ast->size() - 1 );
597 34         132 $self->push_scope($scope);
598 34         107 $self->push_caller($fn);
599 34         47 my $rest_args = undef;
600 34         41 my $i = 0;
601 34         1011 my $fargsvalue = $fargs->value();
602 34         44 my $fargsn = scalar @{$fargsvalue};
  34         54  
603 34         52 my $rargsn = scalar @rargs;
604              
605 34         113 for ( $i = 0 ; $i < $fargsn ; $i++ ) {
606 98         3088 my $name = $fargsvalue->[$i]->value();
607 98 100       190 if ( $name eq "&" ) {
608 33         45 $i++;
609 33         1000 $name = $fargsvalue->[$i]->value();
610 33         1128 $rest_args = Language::LispPerl::Seq->new({ type => "list" });
611 33         110 $self->new_var( $name, $rest_args );
612             }
613             else {
614 65 50       138 $ast->error("real arguments < formal arguments")
615             if $i >= $rargsn;
616 65         146 $self->new_var( $name, $rargs[$i] );
617             }
618             }
619 34 100       81 if ( defined $rest_args ) {
620 33         42 $i -= 2;
621 33         97 for ( ; $i < $rargsn ; $i++ ) {
622 49         175 $rest_args->append( $rargs[$i] );
623             }
624             }
625             else {
626 1 50       3 $ast->error("real arguments > formal arguments")
627             if $i < $rargsn;
628             }
629 34         111 my @body = $fn->slice( 3 .. $fn->size() - 1 );
630 34         53 my $res;
631 34         56 foreach my $b (@body) {
632 34         78 $res = $self->_eval($b);
633             }
634 34         110 $self->pop_scope();
635 34         1096 $self->pop_caller();
636 34         93 return $self->_eval($res);
637             }
638             else {
639 0         0 $ast->error("expect a function or function name or index/key accessor");
640             }
641             }
642             elsif ( $type eq "accessor" ) {
643 0         0 my $av = $self->_eval($value);
644 0         0 my $a = Language::LispPerl::Atom->new({ type => "unknown", value => $av->value() });
645 0         0 my $at = $av->type();
646 0 0 0     0 if ( $at eq "number" ) {
    0          
647 0         0 $a->type("index accessor");
648             }
649             elsif ( $at eq "string" or $at eq "keyword" ) {
650 0         0 $a->type("key accessor");
651             }
652             else {
653 0         0 $ast->error(
654             "unsupport type " . $at . " for accessor but got " . $at );
655             }
656 0         0 return $a;
657             }
658             elsif ( $type eq "sender" ) {
659 0         0 my $sn = $self->_eval($value);
660 0 0 0     0 $ast->error( "sender expects a string or keyword but got " . $type )
661             if $sn->type() ne "string"
662             and $sn->type() ne "keyword";
663 0         0 my $s = Language::LispPerl::Atom->new({ type => "symbol", value => $sn->value() });
664 0         0 return $self->bind($s);
665             }
666             elsif ( $type eq "symbol" ) {
667 370         1275 return $self->bind($ast);
668             }
669             elsif ( $type eq "syntaxquotation" ) {
670 40         103 return $self->bind($ast);
671             }
672             elsif ( $type eq "quotation" ) {
673 0         0 return $self->bind($ast);
674             }
675             elsif ( $class eq "Seq" and $type eq "vector" ) {
676 5         130 my $v = Language::LispPerl::Atom->new({ type => "vector" });
677 5         10 my @vv = ();
678 5         6 foreach my $i ( @{$value} ) {
  5         10  
679 12         20 push @vv, $self->_eval($i);
680             }
681 5         121 $v->value( \@vv );
682 5         16 return $v;
683             }
684             elsif ( $class eq "Seq" and ( $type eq "map" or $type eq "meta" ) ) {
685 13         453 my $m = Language::LispPerl::Atom->new({ type => "map" });
686 13         44 my %mv = ();
687 13         18 my $n = scalar @{$value};
  13         30  
688 13 50       54 $ast->error( $type . " should have even number of items" )
689             if ( $n % 2 ) != 0;
690 13         75 for ( my $i = 0 ; $i < $n ; $i += 2 ) {
691 14         73 my $k = $self->_eval( $value->[$i] );
692 14 50 33     506 $ast->error( $type
693             . " expects keyword or string as key but got "
694             . $k->type() )
695             if ( $k->type() ne "keyword"
696             and $k->type() ne "string" );
697 14         58 my $v = $self->_eval( $value->[ $i + 1 ] );
698 14         471 $mv{ $k->value() } = $v;
699             }
700 13         432 $m->value( \%mv );
701 13 100       366 $m->type("meta") if $type eq "meta";
702 13         45 return $m;
703             }
704             elsif ( $class eq "Seq" and $type eq "xml" ) {
705 10         25 my $size = $ast->size();
706 10 50       23 $ast->error("xml expects >= 1 arguments") if $size == 0;
707 10         22 my $first = $ast->first();
708 10         276 my $firsttype = $first->type();
709 10 50       24 if ( $firsttype ne "symbol" ) {
710 0         0 $first = $self->_eval($first);
711 0         0 $firsttype = $first->type();
712             }
713             $ast->error(
714 10 0 33     26 "xml expects a symbol or string or keyword as name but got "
      33        
715             . $firsttype )
716             if $firsttype ne "symbol"
717             and $firsttype ne "string"
718             and $firsttype ne "keyword";
719 10         17 my @items = ();
720 10         290 my $xml = Language::LispPerl::Atom->new({ type => "xml", value => \@items });
721 10         296 $xml->{name} = $first->value();
722 10         40 my @rest = $ast->slice( 1 .. $size - 1 );
723 10         18 foreach my $i (@rest) {
724 13         29 my $iv = $self->_eval($i);
725 13         382 my $it = $iv->type();
726 13 50 100     64 $ast->error(
      66        
      33        
727             "xml expects string or xml or meta or list as items but got "
728             . $it )
729             if $it ne "string"
730             and $it ne "xml"
731             and $it ne "meta"
732             and $it ne "list";
733 13 100       36 if ( $it eq "meta" ) {
    50          
734 2         97 $xml->meta_data($iv);
735             }
736             elsif ( $it eq "list" ) {
737 0         0 foreach my $i ( @{ $iv->value() } ) {
  0         0  
738 0         0 push @items, $i;
739             }
740             }
741             else {
742             ;
743 11         26 push @items, $iv;
744             }
745             }
746 10         27 return $xml;
747             }
748 169         457 return $ast;
749             }
750              
751             =head2 word_is_reserved
752              
753             Is the given word reserved?
754             Usage:
755              
756             if( $this->word_is_reserved('bla') ){
757             ...
758             }
759              
760             =cut
761              
762             sub word_is_reserved{
763 484     484 1 709 my ($self, $word ) = @_;
764 484         15958 return $self->builtins()->has_function( $word );
765             }
766              
767             sub builtin {
768 255     255 0 358 my ($self, $f , $ast) = @_;
769              
770 255         7323 my $fn = $f->value();
771              
772 255 50       7672 if( my $function = $self->builtins()->has_function( $fn ) ){
773 255         7875 return $self->builtins()->call_function( $function , $ast , $f );
774             }
775              
776 0         0 confess "Builtin function '$fn' is not implemented";
777             }
778              
779             sub perlfunc_call {
780 12     12 0 25 my $self = shift;
781 12         21 my $perl_func = shift;
782 12         30 my $meta = shift;
783 12         22 my $rargs = shift;
784 12         18 my $ast = shift;
785              
786 12         23 my $ret_type = "scalar";
787 12         25 my @fargtypes = ();
788 12 100       73 if ( defined $meta ) {
789 6 50       202 if ( exists $meta->value()->{"return"} ) {
790 6         189 my $rt = $meta->value()->{"return"};
791 6 50 33     190 $ast->error(
792             "return expects a string or keyword but got " . $rt->type() )
793             if $rt->type() ne "string"
794             and $rt->type() ne "keyword";
795 6         190 $ret_type = $rt->value();
796             }
797 6 50       204 if ( exists $meta->value()->{"arguments"} ) {
798 0         0 my $ats = $meta->value()->{"arguments"};
799 0 0       0 $ast->error( "arguments expect a vector but got " . $ats->type() )
800             if $ats->type() ne "vector";
801 0         0 foreach my $arg ( @{ $ats->value() } ) {
  0         0  
802 0 0 0     0 $ast->error(
803             "arguments expect a vector of string or keyword but got "
804             . $arg->type() )
805             if $arg->type() ne "string"
806             and $arg->type() ne "keyword";
807 0         0 push @fargtypes, $arg->value();
808             }
809             }
810             }
811 12         31 my @args = ();
812 12         25 my $i = 0;
813 12         16 foreach my $arg ( @{$rargs} ) {
  12         33  
814 14         49 my $pobj = $self->clj2perl( $self->_eval($arg) );
815 14 50       63 if ( $i < scalar @fargtypes ) {
816 0         0 my $ft = $fargtypes[$i];
817 0 0       0 if ( $ft eq "scalar" ) {
    0          
    0          
    0          
818 0         0 push @args, $pobj;
819             }
820             elsif ( $ft eq "array" ) {
821 0         0 push @args, @{$pobj};
  0         0  
822             }
823             elsif ( $ft eq "hash" ) {
824 0         0 push @args, %{$pobj};
  0         0  
825             }
826             elsif ( $ft eq "ref" ) {
827 0         0 push @args, \$pobj;
828             }
829             else {
830 0         0 push @args, $pobj;
831             }
832             }
833             else {
834 14 50       62 if ( ref($pobj) eq "ARRAY" ) {
    50          
835 0         0 push @args, @{$pobj};
  0         0  
836             }
837             elsif ( ref($pobj) eq "HASH" ) {
838 0         0 push @args, %{$pobj};
  0         0  
839             }
840             else {
841 14         25 push @args, $pobj;
842             }
843             }
844 14         34 $i++;
845             }
846              
847 12 100       74 if ( $ret_type eq "scalar" ) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
848 11         112 my $r = $perl_func->(@args);
849 11         62 return &wrap_perlobj($r);
850             }
851             elsif ( $ret_type eq "ref-scalar" ) {
852 0         0 my $r = $perl_func->(@args);
853 0         0 return &wrap_perlobj( \$r );
854             }
855             elsif ( $ret_type eq "array" ) {
856 0         0 my @r = $perl_func->(@args);
857 0         0 return &wrap_perlobj(@r);
858             }
859             elsif ( $ret_type eq "ref-array" ) {
860 0         0 my @r = $perl_func->(@args);
861 0         0 return &wrap_perlobj( \@r );
862             }
863             elsif ( $ret_type eq "hash" ) {
864 0         0 my %r = $perl_func->(@args);
865 0         0 return &wrap_perlobj(%r);
866             }
867             elsif ( $ret_type eq "ref-hash" ) {
868 0         0 my %r = $perl_func->(@args);
869 0         0 return &wrap_perlobj( \%r );
870             }
871             elsif ( $ret_type eq "nil" ) {
872 0         0 $perl_func->(@args);
873 0         0 return $nil;
874             }
875             elsif ( $ret_type eq 'raw' ) {
876              
877             # The perl function is expected to return a raw Language::LispPerl::Atom
878 1         6 return $perl_func->(@args);
879             }
880             else {
881 0         0 my $r = \$perl_func->(@args);
882 0         0 return &wrap_perlobj($r);
883             }
884              
885             }
886              
887             sub clj2perl {
888 16     16 0 24 my $self = shift;
889 16         22 my $ast = shift;
890 16         679 my $type = $ast->type();
891 16         596 my $value = $ast->value();
892 16 100 66     254 if ( $type eq "string"
    50 66        
    100 33        
    50 66        
    50 33        
    50          
893             or $type eq "number"
894             or $type eq "quotation"
895             or $type eq "keyword"
896             or $type eq "perlobject" )
897             {
898 13         83 return $value;
899             }
900             elsif ( $type eq "bool" ) {
901 0 0       0 if ( $value eq "true" ) {
902 0         0 return 1;
903             }
904             else {
905 0         0 return 0;
906             }
907             }
908             elsif ( $type eq "nil" ) {
909 1         47 return undef;
910             }
911             elsif ( $type eq "list" or $type eq "vector" ) {
912 0         0 my @r = ();
913 0         0 foreach my $i ( @{$value} ) {
  0         0  
914 0         0 push @r, $self->clj2perl($i);
915             }
916 0         0 return \@r;
917             }
918             elsif ( $type eq "map" ) {
919 0         0 my %r = ();
920 0         0 foreach my $k ( keys %{$value} ) {
  0         0  
921 0         0 $r{$k} = $self->clj2perl( $value->{$k} );
922             }
923 0         0 return \%r;
924             }
925             elsif ( $type eq "function" ) {
926             my $f = sub {
927 2     2   7 my @args = @_;
928 2         104 my $cljf = Language::LispPerl::Seq->new({ type => "list" });
929 2         13 $cljf->append($ast);
930 2         6 foreach my $arg (@args) {
931 2         10 $cljf->append( $self->perl2clj($arg) );
932             }
933 2         7 return $self->clj2perl( $self->_eval($cljf) );
934 2         15 };
935 2         7 return $f;
936             }
937             else {
938 0         0 $ast->error(
939             "unsupported type '" . $type . "' for clj2perl object conversion" );
940             }
941             }
942              
943             sub wrap_perlobj {
944 11     11 0 20 my $v = shift;
945 11         46 while ( ref($v) eq "REF" ) {
946 0         0 $v = ${$v};
  0         0  
947             }
948 11         495 return Language::LispPerl::Atom->new({ type => "perlobject", value => $v });
949             }
950              
951             =head2 perl2clj
952              
953             Turn a native perl Object into a new L<Language::LispPerl::Atom>
954              
955             Usage:
956              
957             my $new_atom = $evaler->perl2clj( .. perl object .. );
958              
959             =cut
960              
961             sub perl2clj {
962 3     3 1 6 my ($self, $v) = @_;
963 3 100 66     51 if ( !defined ref($v) or ref($v) eq "" ) {
    50          
    50          
    50          
    50          
964 1         41 return Language::LispPerl::Atom->new({ type => "string", value => $v });
965             }
966             elsif ( ref($v) eq "SCALAR" ) {
967 0         0 return Language::LispPerl::Atom->new({ type => "string", value => ${$v} });
  0         0  
968             }
969             elsif ( ref($v) eq "HASH" ) {
970 0         0 my %m = ();
971 0         0 foreach my $k ( keys %{$v} ) {
  0         0  
972 0         0 $m{$k} = $self->perl2clj( $v->{$k} );
973             }
974 0         0 return Language::LispPerl::Atom->new({ type => "map", value => \%m });
975             }
976             elsif ( ref($v) eq "ARRAY" ) {
977 0         0 my @a = ();
978 0         0 foreach my $i ( @{$v} ) {
  0         0  
979 0         0 push @a, $self->perl2clj($i);
980             }
981 0         0 return Language::LispPerl::Atom->new({ type => "vector", value => \@a });
982             }
983             elsif ( ref($v) eq "CODE" ) {
984 0         0 return Language::LispPerl::Atom->new({ type => "perlfunction", value => $v });
985             }
986             else {
987 2         97 return Language::LispPerl::Atom->new({ type => "perlobject", value => $v });
988              
989             #$ast->error("expect a reference of scalar or hash or array");
990             }
991             }
992              
993             sub trace_vars {
994 1     1 0 3 my $self = shift;
995 1         1 print @{ $self->scopes() } . "\n";
  1         24  
996 1         4 foreach my $vn ( keys %{ $self->current_scope() } ) {
  1         4  
997 17         1598 print
998             "$vn\n" # . Language::LispPerl::Printer::to_string(${$self->current_scope()}{$vn}->value()) . "\n";
999             }
1000             }
1001              
1002             __PACKAGE__->meta->make_immutable();
1003             1;