File Coverage

blib/lib/Lisp/Interpreter.pm
Criterion Covered Total %
statement 64 76 84.2
branch 28 38 73.6
condition 6 9 66.6
subroutine 8 8 100.0
pod 0 3 0.0
total 106 134 79.1


line stmt bran cond sub pod time code
1             package Lisp::Interpreter;
2              
3 4     4   2519 use strict;
  4         6  
  4         161  
4 4     4   20 use vars qw($DEBUG @EXPORT_OK $VERSION);
  4         7  
  4         480  
5              
6             $VERSION = sprintf("%d.%02d", q$Revision: 1.8 $ =~ /(\d+)\.(\d+)/);
7              
8 4     4   7874 use Lisp::Symbol qw(symbol symbolp);
  4         12  
  4         353  
9 4     4   4728 use Lisp::Printer qw(lisp_print);
  4         13  
  4         231  
10 4     4   2270 use Lisp::Special qw(specialp);
  4         10  
  4         4073  
11              
12             require Exporter;
13             *import = \&Exporter::import;
14             @EXPORT_OK = qw(lisp_eval lisp_read_eval_print);
15              
16             my $macro = symbol("macro");
17             my $lambda = symbol("lambda");
18             my $nil = symbol("nil");
19              
20             # symbols in the argument list
21             my $opt = symbol("&optional");
22             my $rest = symbol("&rest");
23              
24             my $evalno = 0;
25              
26             sub lisp_eval
27             {
28 539     539 0 648 my $form = shift;
29 539         607 my $no = ++$evalno;
30            
31 539 50       908 if ($DEBUG) {
32 0         0 print "lisp_eval $evalno ", lisp_print($form), "\n";
33             }
34              
35 539 100       1046 return $form unless ref($form); # a string or a number
36 518 100       1058 return $form->value if symbolp($form);
37              
38 512         1050 my @args = @$form;
39 512         616 my $func = shift(@args);
40              
41 512         1075 while (symbolp($func)) {
42 512 50       1420 if ($func == $macro) {
    50          
43 0         0 shift(@args);
44 0         0 last;
45             } elsif ($func == $lambda) {
46 0         0 last;
47             } else {
48 512         1252 $func = $func->function;
49             }
50             }
51              
52 512 100 66     1210 unless (specialp($func) || $func == $macro) {
53             # evaluate all arguments
54 448         686 for (@args) {
55 548 100       1646 if (ref($_)) {
56 360 100       721 if (symbolp($_)) {
    50          
57 66         209 $_ = $_->value;
58             } elsif (ref($_) eq "ARRAY") {
59 294         537 $_ = lisp_eval($_);
60             } else {
61             # leave it as it is
62             }
63             }
64             }
65             }
66              
67 512         685 my $res;
68 512 100       1130 if (UNIVERSAL::isa($func, "CODE")) {
    50          
69 510         5898 $res = &$func(@args);
70             } elsif (ref($func) eq "ARRAY") {
71 2 50       6 if ($func->[0] == $lambda) {
72 2         6 $res = lambda($func, \@args)
73             } else {
74 0         0 die "invalid-list-function (@{[lisp_print($func)]})";
  0         0  
75             }
76             } else {
77 0         0 die "invalid-function (@{[lisp_print($func)]})";
  0         0  
78             }
79 512 50       987 if ($DEBUG) {
80 0         0 print " $no ==> @{[lisp_print($res)]}\n";
  0         0  
81             }
82 512         1663 $res;
83             }
84              
85              
86             sub lambda # calling a lambda expression
87             {
88 2     2 0 4 my($lambda, $args) = @_;
89            
90             # set local variables
91 2         816 require Lisp::Localize;
92 2         11 my $local = Lisp::Localize->new;
93 2         4 my $localvar = $lambda->[1];
94              
95 2         2 my $do_opt;
96             my $do_rest;
97 2         2 my $i = 0;
98 2         5 for my $sym (@$localvar) {
99 6 100 66     33 if ($sym == $opt) {
    100          
    100          
    50          
100 1         3 $do_opt++;
101             } elsif ($sym == $rest) {
102 1         2 $do_rest++;
103             } elsif ($do_rest) {
104 1         3 $local->save_and_set($sym, [ @{$args}[$i .. @$args-1] ] );
  1         6  
105 1         2 last;
106             } elsif ($i < @$args || $do_opt) {
107 3         16 $local->save_and_set($sym, $args->[$i]);
108 3         9 $i++;
109             } else {
110 0         0 die "too-few-arguments";
111             }
112             }
113 2 50 66     11 if (!$do_rest && @$args > $i) {
114 0         0 die "too-many-arguments";
115             }
116              
117             # execute the function body
118 2         5 my $res = $nil;
119 2         3 my $pc = 2; # starting here (0=lambda, 1=local variables)
120 2         7 while ($pc < @$lambda) {
121 2         9 $res = lisp_eval($lambda->[$pc]);
122 2         6 $pc++;
123             }
124 2         11 $res;
125             }
126              
127              
128             sub lisp_read_eval_print
129             {
130 134     134 0 1247 require Lisp::Reader;
131 134         467 my $form = Lisp::Reader::lisp_read(join(" ", @_));
132 134 50       547 unshift(@$form, symbol("progn")) if ref($form->[0]) eq "ARRAY";
133 134         244 lisp_print(lisp_eval($form));
134             }
135              
136             1;