rubylisp 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +82 -0
- data/bin/rubylisp +6 -0
- data/lib/rubylisp/alist.rb +17 -17
- data/lib/rubylisp/assignment.rb +7 -7
- data/lib/rubylisp/builtins.rb +1 -0
- data/lib/rubylisp/character.rb +21 -20
- data/lib/rubylisp/cons_cell.rb +46 -3
- data/lib/rubylisp/debug.rb +238 -0
- data/lib/rubylisp/environment_frame.rb +47 -4
- data/lib/rubylisp/exception.rb +8 -8
- data/lib/rubylisp/ext.rb +4 -0
- data/lib/rubylisp/ffi_class.rb +10 -10
- data/lib/rubylisp/ffi_send.rb +3 -3
- data/lib/rubylisp/frame.rb +51 -31
- data/lib/rubylisp/function.rb +4 -3
- data/lib/rubylisp/io.rb +6 -6
- data/lib/rubylisp/list_support.rb +93 -94
- data/lib/rubylisp/logical.rb +3 -3
- data/lib/rubylisp/macro.rb +4 -2
- data/lib/rubylisp/math.rb +58 -56
- data/lib/rubylisp/object.rb +1 -1
- data/lib/rubylisp/parser.rb +5 -5
- data/lib/rubylisp/primitive.rb +1 -1
- data/lib/rubylisp/relational.rb +4 -4
- data/lib/rubylisp/special_forms.rb +29 -27
- data/lib/rubylisp/string.rb +75 -75
- data/lib/rubylisp/system.rb +3 -2
- data/lib/rubylisp/testing.rb +3 -3
- data/lib/rubylisp/type_checks.rb +10 -8
- data/lib/rubylisp/vector.rb +1 -1
- data/lib/rubylisp.rb +1 -0
- metadata +6 -4
data/lib/rubylisp/io.rb
CHANGED
@@ -13,9 +13,9 @@ module Lisp
|
|
13
13
|
|
14
14
|
|
15
15
|
def self.load_impl(args, env)
|
16
|
-
|
16
|
+
return Lisp::Debug.process_error("'load' requires 1 argument.", env) if args.empty?
|
17
17
|
fname = args.car.evaluate(env)
|
18
|
-
|
18
|
+
return Lisp::Debug.process_error("'load' requires a string argument.", env) unless fname.string?
|
19
19
|
filename = fname.value.end_with?(".lsp") ? fname.value : "#{fname.value}.lsp"
|
20
20
|
File.open(filename) do |f|
|
21
21
|
contents = f.read()
|
@@ -26,9 +26,9 @@ module Lisp
|
|
26
26
|
|
27
27
|
|
28
28
|
def self.load_library_impl(args, env)
|
29
|
-
|
29
|
+
return Lisp::Debug.process_error("'load-library' requires 1 argument.", env) if args.empty?
|
30
30
|
library_name = args.car.evaluate(env)
|
31
|
-
|
31
|
+
return Lisp::Debug.process_error("'load-library' requires a string or symbol argument.", env) unless library_name.string? || library_name.symbol?
|
32
32
|
Dir.chdir(File.join(App.documents_path, "libraries", "#{library_name}.lib")) do |d|
|
33
33
|
if File.exists?("load.lsp")
|
34
34
|
File.open("load.lsp") do |f|
|
@@ -49,9 +49,9 @@ module Lisp
|
|
49
49
|
|
50
50
|
|
51
51
|
def self.load_project_impl(args, env)
|
52
|
-
|
52
|
+
return Lisp::Debug.process_error("'load-project' requires 1 argument.", env) if args.empty?
|
53
53
|
project_name = args.car.evaluate(env)
|
54
|
-
|
54
|
+
return Lisp::Debug.process_error("'load-project' requires a string or symbol argument.", env) unless project_name.string? || project_name.symbol?
|
55
55
|
Dir.chdir(File.join(App.documents_path, "projects", "#{project_name}.prj")) do |d|
|
56
56
|
if File.exists?("load.lsp")
|
57
57
|
File.open("load.lsp") do |f|
|
@@ -59,7 +59,7 @@ module Lisp
|
|
59
59
|
|
60
60
|
|
61
61
|
def self.cons_impl(args, env)
|
62
|
-
|
62
|
+
return Lisp::Debug.process_error("cons requires two arguments.", env) unless args.length == 2
|
63
63
|
left = args.car.evaluate(env)
|
64
64
|
right = args.cadr.evaluate(env)
|
65
65
|
Lisp::ConsCell.cons(left, right)
|
@@ -85,9 +85,9 @@ module Lisp
|
|
85
85
|
|
86
86
|
|
87
87
|
def self.make_list_impl(args, env)
|
88
|
-
|
88
|
+
return Lisp::Debug.process_error("consmake-list requires one or two arguments.", env) unless args.length == 1 || args.length == 2
|
89
89
|
arg1 = args.car.evaluate(env)
|
90
|
-
|
90
|
+
return Lisp::Debug.process_error("make-list requires an integer for it's first argument, received: #{args.car}", env) unless arg1.integer?
|
91
91
|
count = arg1.value
|
92
92
|
val = if args.length == 1
|
93
93
|
nil
|
@@ -101,16 +101,16 @@ module Lisp
|
|
101
101
|
|
102
102
|
|
103
103
|
def self.iota_impl(args, env)
|
104
|
-
|
104
|
+
return Lisp::Debug.process_error("iota requires at least one argument.", env) unless args.length > 0
|
105
105
|
arg1 = args.car.evaluate(env)
|
106
|
-
|
106
|
+
return Lisp::Debug.process_error("iota requires an positive integer for it's first argument, received: #{args.car}", env) unless arg1.integer? && arg1.positive?
|
107
107
|
count = arg1.value
|
108
108
|
|
109
109
|
start = if args.length < 2
|
110
110
|
0
|
111
111
|
else
|
112
112
|
arg2 = args.cadr.evaluate(env)
|
113
|
-
|
113
|
+
return Lisp::Debug.process_error("iota requires an number for it's second argument, received: #{args.cadr}", env) unless arg2.number?
|
114
114
|
arg2.value
|
115
115
|
end
|
116
116
|
|
@@ -118,7 +118,7 @@ module Lisp
|
|
118
118
|
1
|
119
119
|
else
|
120
120
|
arg3 = args.caddr.evaluate(env)
|
121
|
-
|
121
|
+
return Lisp::Debug.process_error("iota requires an number for it's third argument, received: #{args.caddr}", env) unless arg3.number?
|
122
122
|
arg3.value
|
123
123
|
end
|
124
124
|
|
@@ -140,22 +140,22 @@ module Lisp
|
|
140
140
|
# in support of all the CxR functions
|
141
141
|
def self.ad_impl(args, env, f)
|
142
142
|
l = args.car.evaluate(env)
|
143
|
-
|
143
|
+
return Lisp::Debug.process_error("list required.", env) unless l.list?
|
144
144
|
l.send(f)
|
145
145
|
end
|
146
146
|
|
147
147
|
|
148
148
|
def self.first_impl(args, env)
|
149
149
|
l = args.car.evaluate(env)
|
150
|
-
|
151
|
-
|
150
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
151
|
+
return Lisp::Debug.process_error("list index out of bounds", env) unless l.length >= 1
|
152
152
|
l.nth(1)
|
153
153
|
end
|
154
154
|
|
155
155
|
|
156
156
|
def self.rest_impl(args, env)
|
157
157
|
l = args.car.evaluate(env)
|
158
|
-
|
158
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
159
159
|
if l.list?
|
160
160
|
l.cdr
|
161
161
|
else
|
@@ -166,82 +166,82 @@ module Lisp
|
|
166
166
|
|
167
167
|
def self.second_impl(args, env)
|
168
168
|
l = args.car.evaluate(env)
|
169
|
-
|
170
|
-
|
169
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
170
|
+
return Lisp::Debug.process_error("list index out of bounds", env) unless l.length >= 2
|
171
171
|
l.nth(2)
|
172
172
|
end
|
173
173
|
|
174
174
|
def self.third_impl(args, env)
|
175
175
|
l = args.car.evaluate(env)
|
176
|
-
|
177
|
-
|
176
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
177
|
+
return Lisp::Debug.process_error("list index out of bounds", env) unless l.length >= 3
|
178
178
|
l.nth(3)
|
179
179
|
end
|
180
180
|
|
181
181
|
|
182
182
|
def self.fourth_impl(args, env)
|
183
183
|
l = args.car.evaluate(env)
|
184
|
-
|
185
|
-
|
184
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
185
|
+
return Lisp::Debug.process_error("list index out of bounds", env) unless l.length >= 4
|
186
186
|
l.nth(4)
|
187
187
|
end
|
188
188
|
|
189
189
|
|
190
190
|
def self.fifth_impl(args, env)
|
191
191
|
l = args.car.evaluate(env)
|
192
|
-
|
193
|
-
|
192
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
193
|
+
return Lisp::Debug.process_error("list index out of bounds", env) unless l.length >= 5
|
194
194
|
l.nth(5)
|
195
195
|
end
|
196
196
|
|
197
197
|
|
198
198
|
def self.sixth_impl(args, env)
|
199
199
|
l = args.car.evaluate(env)
|
200
|
-
|
201
|
-
|
200
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
201
|
+
return Lisp::Debug.process_error("list index out of bounds", env) unless l.length >= 6
|
202
202
|
l.nth(6)
|
203
203
|
end
|
204
204
|
|
205
205
|
|
206
206
|
def self.seventh_impl(args, env)
|
207
207
|
l = args.car.evaluate(env)
|
208
|
-
|
209
|
-
|
208
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
209
|
+
return Lisp::Debug.process_error("list index out of bounds", env) unless l.length >= 7
|
210
210
|
l.nth(7)
|
211
211
|
end
|
212
212
|
|
213
213
|
|
214
214
|
def self.eighth_impl(args, env)
|
215
215
|
l = args.car.evaluate(env)
|
216
|
-
|
217
|
-
|
216
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
217
|
+
return Lisp::Debug.process_error("list index out of bounds", env) unless l.length >= 8
|
218
218
|
l.nth(8)
|
219
219
|
end
|
220
220
|
|
221
221
|
|
222
222
|
def self.ninth_impl(args, env)
|
223
223
|
l = args.car.evaluate(env)
|
224
|
-
|
225
|
-
|
224
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
225
|
+
return Lisp::Debug.process_error("list index out of bounds", env) unless l.length >= 9
|
226
226
|
l.nth(9)
|
227
227
|
end
|
228
228
|
|
229
229
|
|
230
230
|
def self.tenth_impl(args, env)
|
231
231
|
l = args.car.evaluate(env)
|
232
|
-
|
233
|
-
|
232
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
233
|
+
return Lisp::Debug.process_error("list index out of bounds", env) unless l.length >= 10
|
234
234
|
l.nth(10)
|
235
235
|
end
|
236
236
|
|
237
237
|
|
238
238
|
def self.nth_impl(args, env)
|
239
|
-
|
239
|
+
return Lisp::Debug.process_error("nth requires 2 arguments", env) unless args.length == 2
|
240
240
|
n = args.car.evaluate(env)
|
241
|
-
|
242
|
-
|
241
|
+
return Lisp::Debug.process_error("The first argument of nth has to be an number.", env) unless n.number?
|
242
|
+
return Lisp::Debug.process_error("The first argument of nth has to be positive.", env) unless n.value > 0
|
243
243
|
l = args.cadr.evaluate(env)
|
244
|
-
|
244
|
+
return Lisp::Debug.process_error("rest requires a list or vector.", env) unless l.list? || l.vector?
|
245
245
|
l.nth(n.value)
|
246
246
|
end
|
247
247
|
|
@@ -256,78 +256,77 @@ module Lisp
|
|
256
256
|
|
257
257
|
|
258
258
|
def self.sublist_impl(args, env)
|
259
|
-
|
259
|
+
return Lisp::Debug.process_error("sublist requires 3 arguments", env) unless args.length == 3
|
260
260
|
l = args.car.evaluate(env)
|
261
|
-
|
261
|
+
return Lisp::Debug.process_error("sublist requires it's first argument to be a list or vector, but received #{args.car}", env) unless l.list? || l.vector?
|
262
262
|
st = args.cadr.evaluate(env)
|
263
|
-
|
264
|
-
|
263
|
+
return Lisp::Debug.process_error("sublist requires it's second argument to be a positive integer, but received #{args.cadr}", env) unless st.number? && st.positive?
|
264
|
+
return Lisp::Debug.process_error("sublist requires it's second argument to be <= the list length", env) unless st.value <= l.length
|
265
265
|
en = args.caddr.evaluate(env)
|
266
|
-
|
267
|
-
|
268
|
-
|
266
|
+
return Lisp::Debug.process_error("sublist requires it's third argument to be a positive integer, but received #{args.caddr}", env) unless en.number? && en.positive?
|
267
|
+
return Lisp::Debug.process_error("sublist requires it's third argument to be <= the list length", env) unless en.value <= l.length
|
268
|
+
return Lisp::Debug.process_error("sublist requires it's second argument to be <= the third argument", env) unless st.value <= en.value
|
269
269
|
make_same_kind_as(l, l.to_a[(st.value - 1)...en.value])
|
270
270
|
end
|
271
271
|
|
272
272
|
|
273
273
|
def self.list_head_impl(args, env)
|
274
|
-
|
274
|
+
return Lisp::Debug.process_error("list_head requires 2 arguments", env) unless args.length == 2
|
275
275
|
l = args.car.evaluate(env)
|
276
|
-
|
276
|
+
return Lisp::Debug.process_error("list_head requires it's first argument to be a list, but received #{args.car}", env) unless l.list?
|
277
277
|
k = args.cadr.evaluate(env)
|
278
|
-
|
279
|
-
|
278
|
+
return Lisp::Debug.process_error("list_head requires it's second argument to be a positive integer, but received #{args.cadr}", env) unless k.number? && k.positive?
|
279
|
+
return Lisp::Debug.process_error("list_head requires it's second argument to be <= the list length", env) unless k.value <= l.length
|
280
280
|
Lisp::ConsCell.array_to_list(l.to_a[0...k.value])
|
281
281
|
end
|
282
282
|
|
283
283
|
|
284
284
|
def self.take_impl(args, env)
|
285
|
-
|
285
|
+
return Lisp::Debug.process_error("take requires 2 arguments", env) unless args.length == 2
|
286
286
|
k = args.car.evaluate(env)
|
287
|
-
|
287
|
+
return Lisp::Debug.process_error("take requires it's first argument to be an integer >= 0, but received #{args.car}", env) unless k.number? && !k.negative?
|
288
288
|
l = args.cadr.evaluate(env)
|
289
|
-
|
290
|
-
|
291
|
-
puts l
|
289
|
+
return Lisp::Debug.process_error("take requires it's second argument to be a list or vector, but received #{args.cadr}", env) unless l.list? || l.vector?
|
290
|
+
return Lisp::Debug.process_error("take requires it's first argument to be <= the list length", env) unless k.value <= l.length
|
292
291
|
make_same_kind_as(l, l.to_a[0...k.value])
|
293
292
|
end
|
294
293
|
|
295
294
|
|
296
295
|
def self.list_tail_impl(args, env)
|
297
|
-
|
296
|
+
return Lisp::Debug.process_error("list_head requires 2 arguments", env) unless args.length == 2
|
298
297
|
l = args.car.evaluate(env)
|
299
|
-
|
298
|
+
return Lisp::Debug.process_error("list_head requires it's first argument to be a list, but received #{args.car}", env) unless l.list?
|
300
299
|
k = args.cadr.evaluate(env)
|
301
|
-
|
302
|
-
|
300
|
+
return Lisp::Debug.process_error("list_head requires it's second argument to be a positive integer, but received #{args.cadr}", env) unless k.number? && k.positive?
|
301
|
+
return Lisp::Debug.process_error("list_head requires it's second argument to be <= the list length", env) unless k.value <= l.length
|
303
302
|
l.nth_tail(k.value + 1)
|
304
303
|
end
|
305
304
|
|
306
305
|
|
307
306
|
def self.drop_impl(args, env)
|
308
|
-
|
307
|
+
return Lisp::Debug.process_error("drop requires 2 arguments", env) unless args.length == 2
|
309
308
|
k = args.car.evaluate(env)
|
310
|
-
|
309
|
+
return Lisp::Debug.process_error("drop requires it's first argument to be an integer >= 0, but received #{args.car}", env) unless k.number? && !k.negative?
|
311
310
|
l = args.cadr.evaluate(env)
|
312
|
-
|
313
|
-
|
311
|
+
return Lisp::Debug.process_error("drop requires it's second argument to be a list or vector, but received #{args.cadr}", env) unless l.list? || l.vector?
|
312
|
+
return Lisp::Debug.process_error("drop requires it's first argument to be <= the list length", env) unless k.value <= l.length
|
314
313
|
l.nth_tail(k.value + 1)
|
315
314
|
end
|
316
315
|
|
317
316
|
|
318
317
|
def self.last_pair_impl(args, env)
|
319
|
-
|
318
|
+
return Lisp::Debug.process_error("last_pair requires 1 arguments", env) unless args.length == 1
|
320
319
|
l = args.car.evaluate(env)
|
321
|
-
|
320
|
+
return Lisp::Debug.process_error("last_pair requires it's argument to be a list, but received #{args.car}", env) unless l.list?
|
322
321
|
l.last
|
323
322
|
end
|
324
323
|
|
325
324
|
|
326
325
|
def self.memq_impl(args, env)
|
327
|
-
|
326
|
+
return Lisp::Debug.process_error("memq requires 2 arguments but received #{args.length}.", env) unless args.length == 2
|
328
327
|
item = args.car.evaluate(env)
|
329
328
|
collection = args.cadr.evaluate(env)
|
330
|
-
|
329
|
+
return Lisp::Debug.process_error("memq requires a list as it's second argument.", env) unless collection.list?
|
331
330
|
collection.length.times do |i|
|
332
331
|
if Lisp::Equivalence.eq_check(item, collection.nth(i + 1)).value
|
333
332
|
return collection.nth_tail(i + 1)
|
@@ -338,10 +337,10 @@ module Lisp
|
|
338
337
|
|
339
338
|
|
340
339
|
def self.memv_impl(args, env)
|
341
|
-
|
340
|
+
return Lisp::Debug.process_error("memv requires 2 arguments but received #{args.length}.", env) unless args.length == 2
|
342
341
|
item = args.car.evaluate(env)
|
343
342
|
collection = args.cadr.evaluate(env)
|
344
|
-
|
343
|
+
return Lisp::Debug.process_error("memv requires a list as it's second argument.", env) unless collection.list?
|
345
344
|
collection.length.times do |i|
|
346
345
|
if Lisp::Equivalence.eqv_check(item, collection.nth(i + 1)).value
|
347
346
|
return collection.nth_tail(i + 1)
|
@@ -352,10 +351,10 @@ module Lisp
|
|
352
351
|
|
353
352
|
|
354
353
|
def self.member_impl(args, env)
|
355
|
-
|
354
|
+
return Lisp::Debug.process_error("member requires 2 arguments but received #{args.length}.", env) unless args.length == 2
|
356
355
|
item = args.car.evaluate(env)
|
357
356
|
collection = args.cadr.evaluate(env)
|
358
|
-
|
357
|
+
return Lisp::Debug.process_error("member requires a list as it's second argument.", env) unless collection.list?
|
359
358
|
collection.length.times do |i|
|
360
359
|
if Lisp::Equivalence.equal_check(item, collection.nth(i + 1)).value
|
361
360
|
return collection.nth_tail(i + 1)
|
@@ -366,33 +365,33 @@ module Lisp
|
|
366
365
|
|
367
366
|
|
368
367
|
def self.filter_impl(args, env)
|
369
|
-
|
368
|
+
return Lisp::Debug.process_error("filter requires 2 arguments but received #{args.length}.", env) unless args.length == 2
|
370
369
|
f = args.car.evaluate(env)
|
371
|
-
|
370
|
+
return Lisp::Debug.process_error("filter requires a function as it's first argument but received #{args.car}.", env) unless f.function? || f.primitive?
|
372
371
|
collection = args.cadr.evaluate(env)
|
373
|
-
|
372
|
+
return Lisp::Debug.process_error("filter requires a list or vector as it's second argument but received #{args.cadr}.", env) unless collection.list? || collection.vector?
|
374
373
|
results = collection.to_a.select {|item| f.apply_to_without_evaluating(Lisp::ConsCell.cons(item, nil), env).value }
|
375
374
|
make_same_kind_as(collection, results)
|
376
375
|
end
|
377
376
|
|
378
377
|
|
379
378
|
def self.remove_impl(args, env)
|
380
|
-
|
379
|
+
return Lisp::Debug.process_error("remove requires 2 arguments but received #{args.length}.", env) unless args.length == 2
|
381
380
|
f = args.car.evaluate(env)
|
382
|
-
|
381
|
+
return Lisp::Debug.process_error("remove requires a function as it's first argument but received #{args.car}.", env) unless f.function? || f.primitive?
|
383
382
|
collection = args.cadr.evaluate(env)
|
384
|
-
|
383
|
+
return Lisp::Debug.process_error("remove requires a list or vector as it's second argument but received #{args.cadr}.", env) unless collection.list? || collection.vector?
|
385
384
|
results = collection.to_a.reject {|item| f.apply_to_without_evaluating(Lisp::ConsCell.cons(item, nil), env).value }
|
386
385
|
make_same_kind_as(collection, results)
|
387
386
|
end
|
388
387
|
|
389
388
|
|
390
389
|
def self.partition_impl(args, env)
|
391
|
-
|
390
|
+
return Lisp::Debug.process_error("partition requires 2 arguments but received #{args.length}.", env) unless args.length == 2
|
392
391
|
f = args.car.evaluate(env)
|
393
|
-
|
392
|
+
return Lisp::Debug.process_error("partition requires a function as it's first argument.", env) unless f.function? || f.primitive?
|
394
393
|
collection = args.cadr.evaluate(env)
|
395
|
-
|
394
|
+
return Lisp::Debug.process_error("partition requires a list as it's second argument.", env) unless collection.list? | collection.vector?
|
396
395
|
results = collection.to_a.partition {|item| f.apply_to_without_evaluating(Lisp::ConsCell.cons(item, nil), env).value }
|
397
396
|
matches = make_same_kind_as(collection, results[0])
|
398
397
|
non_matches = make_same_kind_as(collection, results[1])
|
@@ -401,11 +400,11 @@ module Lisp
|
|
401
400
|
|
402
401
|
|
403
402
|
def self.map_impl(args, env)
|
404
|
-
|
403
|
+
return Lisp::Debug.process_error("map requires at least 2 arguments but received #{args.length}.", env) if args.length < 2
|
405
404
|
f = args.car.evaluate(env)
|
406
|
-
|
405
|
+
return Lisp::Debug.process_error("map requires a function as it's first argument but received #{args.car}.", env) unless f.function? || f.primitive?
|
407
406
|
collections = args.cdr.to_a.collect {|a| a.evaluate(env)}
|
408
|
-
|
407
|
+
return Lisp::Debug.process_error("all requires all subsequent arguments to be lists or vectors", env) unless collections.all? {|l| l.list? || l.vector?}
|
409
408
|
all_vectors = collections.all? {|i| i.vector?}
|
410
409
|
lists = collections.collect {|l| l.to_a }
|
411
410
|
|
@@ -430,12 +429,12 @@ module Lisp
|
|
430
429
|
|
431
430
|
|
432
431
|
def self.reduce_left_impl(args, env)
|
433
|
-
|
432
|
+
return Lisp::Debug.process_error("reduce requires 3 arguments but received #{args.length}.", env) unless args.length == 3
|
434
433
|
f = args.car.evaluate(env)
|
435
|
-
|
434
|
+
return Lisp::Debug.process_error("map requires a function as it's first argument but received #{args.car}.", env) unless f.function? || f.primitive?
|
436
435
|
initial = args.cadr.evaluate(env)
|
437
436
|
collection = args.caddr.evaluate(env)
|
438
|
-
|
437
|
+
return Lisp::Debug.process_error("reduce requires a list or vector as it's third argument but received #{args.caddr}.", env) unless collection.list? || collection.vector?
|
439
438
|
return initial if collection.empty?
|
440
439
|
return collection.nth(1) if collection.length == 1
|
441
440
|
result = collection.to_a.inject do |acc, item|
|
@@ -446,11 +445,11 @@ module Lisp
|
|
446
445
|
|
447
446
|
|
448
447
|
def self.any_impl(args, env)
|
449
|
-
|
448
|
+
return Lisp::Debug.process_error("any requires at least two arguments", env) unless args.length >= 2
|
450
449
|
p = args.car.evaluate(env)
|
451
|
-
|
450
|
+
return Lisp::Debug.process_error("any requires a function as it's first argument", env) unless p.function? || p.primitive?
|
452
451
|
lists = args.cdr.to_a.collect {|a| a.evaluate(env)}
|
453
|
-
|
452
|
+
return Lisp::Debug.process_error("any requires all subsequent arguments to be lists or vectors", env) unless lists.all? {|l| l.list? || l.vector?}
|
454
453
|
|
455
454
|
while true
|
456
455
|
cars = lists.collect {|l| l.nth(1)}
|
@@ -463,11 +462,11 @@ module Lisp
|
|
463
462
|
|
464
463
|
|
465
464
|
def self.every_impl(args, env)
|
466
|
-
|
465
|
+
return Lisp::Debug.process_error("all requires at least two arguments", env) unless args.length >= 2
|
467
466
|
p = args.car.evaluate(env)
|
468
|
-
|
467
|
+
return Lisp::Debug.process_error("all requires a function as it's first argument", env) unless p.function? || p.primitive?
|
469
468
|
lists = args.cdr.to_a.collect {|a| a.evaluate(env)}
|
470
|
-
|
469
|
+
return Lisp::Debug.process_error("all requires all subsequent arguments to be lists or vectors", env) unless lists.all? {|l| l.list? || l.vector?}
|
471
470
|
|
472
471
|
while true
|
473
472
|
cars = lists.collect {|l| l.nth(1)}
|
@@ -480,17 +479,17 @@ module Lisp
|
|
480
479
|
|
481
480
|
|
482
481
|
def self.reverse_impl(args, env)
|
483
|
-
|
482
|
+
return Lisp::Debug.process_error("reverse requires a single argument.", env) unless args.length == 1
|
484
483
|
l = args.car.evaluate(env)
|
485
|
-
|
484
|
+
return Lisp::Debug.process_error("reverse requires a list or vector", env) unless l.list? || l.vector?
|
486
485
|
make_same_kind_as(l, l.to_a.reverse)
|
487
486
|
end
|
488
487
|
|
489
488
|
|
490
489
|
def self.append_impl(args, env)
|
491
|
-
|
490
|
+
return Lisp::Debug.process_error("append requires at least 1 argument.", env) unless args.length >= 1
|
492
491
|
l = args.map {|i| i.evaluate(env)}
|
493
|
-
|
492
|
+
return Lisp::Debug.process_error("append requires lists or vectors", env) unless l.all? {|i| i.list? || i.vector?}
|
494
493
|
all_vectors = l.all? {|i| i.vector?}
|
495
494
|
new_items = []
|
496
495
|
l.each do |sublist|
|
@@ -506,9 +505,9 @@ module Lisp
|
|
506
505
|
|
507
506
|
|
508
507
|
def self.appendbang_impl(args, env)
|
509
|
-
|
508
|
+
return Lisp::Debug.process_error("append! requires at least 1 argument.", env) unless args.length >= 1
|
510
509
|
arg_array = args.to_a.map {|i| i.evaluate(env)}
|
511
|
-
|
510
|
+
return Lisp::Debug.process_error("append! requires lists", env) unless arg_array.all? {|i| i.list?}
|
512
511
|
(0...(arg_array.length-1)). each do |i|
|
513
512
|
arg_array[i].last.set_cdr!(arg_array[i+1])
|
514
513
|
end
|
@@ -517,9 +516,9 @@ module Lisp
|
|
517
516
|
|
518
517
|
|
519
518
|
def self.flatten_impl(args, env)
|
520
|
-
|
519
|
+
return Lisp::Debug.process_error("flatten requires 1 argument.", env) unless args.length != 1
|
521
520
|
l = args.car.evaluate(env)
|
522
|
-
|
521
|
+
return Lisp::Debug.process_error("flatten requires a list argument", env) unless l.list?
|
523
522
|
l.flatten
|
524
523
|
end
|
525
524
|
|
data/lib/rubylisp/logical.rb
CHANGED
@@ -18,19 +18,19 @@ module Lisp
|
|
18
18
|
|
19
19
|
|
20
20
|
def self.or_impl(args, env)
|
21
|
-
|
21
|
+
return Lisp::Debug.process_error("or needs at least 2 arguments", env) unless args.length > 1
|
22
22
|
value = !!args.inject(false) {|acc, item| acc || item.evaluate(env).value}
|
23
23
|
return Lisp::Boolean.with_value(value)
|
24
24
|
end
|
25
25
|
|
26
26
|
def self.and_impl(args, env)
|
27
|
-
|
27
|
+
return Lisp::Debug.process_error("and needs at least 2 arguments", env) unless args.length > 1
|
28
28
|
value = !!args.inject(true) {|acc, item| acc && item.evaluate(env).value}
|
29
29
|
return Lisp::Boolean.with_value(value)
|
30
30
|
end
|
31
31
|
|
32
32
|
def self.not_impl(args, env)
|
33
|
-
|
33
|
+
return Lisp::Debug.process_error("not needs a single argument", env) unless args.length == 1
|
34
34
|
return Lisp::Boolean.with_value(!(args.car.evaluate(env).value))
|
35
35
|
end
|
36
36
|
|
data/lib/rubylisp/macro.rb
CHANGED
@@ -33,9 +33,11 @@ module Lisp
|
|
33
33
|
|
34
34
|
def expand(parameters, env, should_eval)
|
35
35
|
if @var_args
|
36
|
-
|
36
|
+
return Lisp::Debug.process_error("#{@name} expected at least
|
37
|
+
##{@required_argument_count} parameters, received #{parameters.length}.", env) if parameters.length < @required_argument_count
|
37
38
|
else
|
38
|
-
|
39
|
+
return Lisp::Debug.process_error("#{@name} expected
|
40
|
+
##{@required_argument_count} parameters, received #{parameters.length}.", env) unless parameters.length == @required_argument_count
|
39
41
|
end
|
40
42
|
|
41
43
|
local_env = EnvironmentFrame.extending(@env, env.frame)
|