File Coverage

blib/lib/Lisp/Subr/Core.pm
Criterion Covered Total %
statement 26 26 100.0
branch 4 4 100.0
condition n/a
subroutine 10 10 100.0
pod 0 2 0.0
total 40 42 95.2


line stmt bran cond sub pod time code
1             package Lisp::Subr::Core;
2              
3             # implements the core subrs
4              
5 4     4   2002 use strict;
  4         7  
  4         142  
6 4     4   19 use vars qw($VERSION);
  4         5  
  4         284  
7              
8             $VERSION = sprintf("%d.%02d", q$Revision: 1.8 $ =~ /(\d+)\.(\d+)/);
9              
10 4     4   23 use Lisp::Symbol qw(symbol);
  4         6  
  4         188  
11 4     4   20 use Lisp::Special qw(make_special);
  4         6  
  4         187  
12 4     4   2268 use Lisp::Reader qw(lisp_read);
  4         9  
  4         278  
13 4     4   22 use Lisp::Printer qw(lisp_print);
  4         8  
  4         589  
14 4     4   23 use Lisp::Interpreter qw(lisp_eval);
  4         9  
  4         166  
15              
16 4     4   20 use Lisp::Cons qw(consp);
  4         7  
  4         10471  
17              
18             my $lambda = symbol("lambda");
19             my $nil = symbol("nil");
20             my $t = symbol("t");
21              
22 50 100   50 0 305 sub lisp_true { defined($_[0]) && $_[0] != $nil }
23              
24             symbol("list")->function(sub {[@_]});
25              
26             symbol("quote")->function(make_special(sub {$_[0]}));
27             symbol("set")->function(sub {$_[0]->value($_[1]); $_[1]} );
28             symbol("setq")->function(
29             make_special(sub{my $val = lisp_eval($_[1]); $_[0]->value($val); $val}));
30              
31             symbol("car")->function(sub {$_[0][0]});
32             symbol("cdr")->function(
33             sub {
34             my $obj = shift;
35             return $obj->[-1] if consp($obj);
36             die "wrong-argument-type" unless ref($obj) eq "ARRAY";
37              
38             #XXX The semantics is not really correct in this situation, because
39             # we will return a copy of the CDR. This matters if somebody modifies
40             # the original list or the CDR.
41             [ @{$obj}[1 .. @$obj - 1] ];
42             });
43              
44             symbol("print")->function(sub{lisp_print($_[0])});
45             symbol("read")->function(sub{lisp_read($_[0])});
46             symbol("eval")->function(sub{lisp_eval($_[0])});
47              
48             # Just some way to print out something
49             symbol("write")->function(sub{print join("\n", (map lisp_print($_), @_), "")});
50              
51             # control structues
52             symbol("progn")->function(sub {$_[-1]});
53             symbol("prog1")->function(sub {$_[0]});
54             symbol("prog2")->function(sub {$_[1]});
55              
56             symbol("if")->function(
57             make_special(
58             sub {
59             my $cond = shift;
60             $cond = lisp_eval($cond);
61             if (lisp_true(lisp_eval($cond))) {
62             return lisp_eval(shift); # then
63             }
64             shift; # skip then-form
65             my $res;
66             for (@_) { $res = lisp_eval($_) };
67             return $res;
68             }));
69              
70             symbol("cond")->function(
71             make_special(
72             sub {
73             my $res;
74             my $clause;
75             for $clause (@_) {
76             $res = lisp_eval($clause->[0]);
77             next unless lisp_true($res);
78             my $pc;
79             for ($pc = 1; $pc < @$clause; $pc++) {
80             $res = lisp_eval($clause->[$pc]);
81             }
82             return $res;
83             }
84             undef;
85             }));
86              
87              
88 17 100   17 0 38 sub lisp_not { lisp_true($_[0]) ? $nil : $t }
89              
90             symbol("not" )->function(\&lisp_not);
91             symbol("null")->function(\&lisp_not);
92              
93             symbol("and")->function(
94             make_special(
95             sub {
96             my $res;
97             for (@_) {
98             $res = lisp_eval($_);
99             return $res unless lisp_true($res);
100             }
101             $res;
102             }));
103              
104             symbol("or")->function(
105             make_special(
106             sub {
107             my $res;
108             for (@_) {
109             $res = lisp_eval($_);
110             return $res if lisp_true($res);
111             }
112             $res;
113             }));
114              
115             symbol("while")->function(
116             make_special(
117             sub {
118             my $condition = shift;
119             while (lisp_true(lisp_eval($condition))) {
120             # evaluate body
121             for (@_) { lisp_eval($_) }
122             }
123             undef;
124             }));
125              
126             # numeric functions
127             symbol("floatp")->function(sub {$_[0] =~ /^[-+]?(?:\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?$/ ? $t : $nil });
128             symbol("integerp")->function(sub {$_[0] =~ /^\d+$/ ? $t : $nil });
129             symbol("numberp")->function(symbol("floatp")->function);
130             symbol("zerop")->function(sub {$_[0] == 0 ? $t : $nil });
131              
132             symbol("=" )->function(sub {$_[0] == $_[1] ? $t : $nil });
133             symbol("/=")->function(sub {$_[0] != $_[1] ? $t : $nil });
134             symbol("<" )->function(sub {$_[0] < $_[1] ? $t : $nil });
135             symbol("<=")->function(sub {$_[0] <= $_[1] ? $t : $nil });
136             symbol(">" )->function(sub {$_[0] > $_[1] ? $t : $nil });
137             symbol(">=")->function(sub {$_[0] >= $_[1] ? $t : $nil });
138              
139              
140             symbol("1+")->function(sub { $_[0]+1} );
141             symbol("+")->function(sub { my $sum=shift; for (@_) {$sum+=$_} $sum });
142             symbol("1-")->function(sub { $_[0]-1} );
143             symbol("-")->function(
144             sub {
145             return 0 if $_ == 0;
146             return -$_[0] if @_ == 1;
147             my $sum = shift; for(@_) {$sum-=$_}
148             $sum
149             });
150             symbol("*")->function(sub { my $prod=1; for (@_){$prod*=$_} $prod});
151             symbol("/")->function(sub { my $div=shift; for (@_){ $div/=$_} $div});
152             symbol("%")->function(sub { $_[0] % $_[1]});
153              
154             symbol("max")->function(sub {my $max=shift;for(@_){$max=$_ if $_ > $max}$max});
155             symbol("min")->function(sub {my $min=shift;for(@_){$min=$_ if $_ < $min}$min});
156              
157              
158             # defining functions
159             symbol("fset")->function(sub {$_[0]->function($_[1]); $_[1]});
160             symbol("symbol-function")->function(sub {$_[0]->function});
161              
162             symbol("defun")->function(
163             make_special(
164             sub {
165             my $sym = shift;
166             $sym->function([$lambda, @_]);
167             $sym;
168             }));
169              
170             symbol("put")->function(sub{$_[0]->put($_[1] => $_[2])});
171             symbol("get")->function(sub{$_[0]->get($_[1])});
172              
173              
174             # dynamic scoping
175             symbol("let")->function(
176             make_special(
177             sub {
178             my $bindings = shift;
179             my @bindings = @$bindings; # make a copy
180              
181             # First evaluate all bindings as variables
182             for my $b (@bindings) {
183             if (symbolp($b)) {
184             $b = [$b, $nil];
185             } else {
186             my($sym, $val) = @$b;
187             $val = $val->value if $val && symbolp($val);
188             $b = [$sym, $val];
189             }
190             }
191            
192             # Then localize
193             require Lisp::Localize;
194             my $local = Lisp::Localize->new;
195             for my $b (@bindings) {
196             $local->save_and_set(@$b);
197             }
198              
199             my $res;
200             for (@_) {
201             $res = lisp_eval($_);
202             }
203             $res;
204             }));
205              
206              
207             symbol("let*")->function(
208             make_special(
209             sub {
210             my $bindings = shift;
211             require Lisp::Localize;
212             my $local = Lisp::Localize->new;
213              
214             # Evaluate and localize in the order given
215             for my $b (@$bindings) {
216             if (symbolp($b)) {
217             $local->save_and_set($b, $nil);
218             } else {
219             my($sym, $val) = @$b;
220             $val = $val->value if $val && symbolp($val);
221             $local->save_and_set($sym, $val);
222             }
223             }
224             my $res;
225             for (@_) {
226             $res = lisp_eval($_);
227             }
228             $res;
229             }));
230              
231             1;