rubylisp 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|