skeem 0.0.17 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
data/lib/skeem/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Skeem
2
- VERSION = '0.0.17'.freeze
2
+ VERSION = '0.0.18'.freeze
3
3
  end
@@ -20,6 +20,12 @@ module Skeem
20
20
  it 'should come with built-in functions' do
21
21
  expect(subject.runtime.environment).not_to be_empty
22
22
  end
23
+
24
+ it 'should implement base bindings' do
25
+ expect(subject.fetch('number?')).to be_kind_of(Primitive::PrimitiveProcedure)
26
+ expect(subject.fetch('abs')).to be_kind_of(SkmDefinition)
27
+ expect(subject.fetch('abs').expression).to be_kind_of(SkmLambda)
28
+ end
23
29
  end # context
24
30
 
25
31
  context 'Interpreting self-evaluating expressions' do
@@ -92,8 +98,9 @@ module Skeem
92
98
  x
93
99
  SKEEM
94
100
  result = subject.run(source)
95
- expect(result).to be_kind_of(SkmInteger)
96
- expect(result.value).to eq(28)
101
+ end_result = result.last
102
+ expect(end_result).to be_kind_of(SkmInteger)
103
+ expect(end_result.value).to eq(28)
97
104
  end
98
105
 
99
106
  it 'should implement the simple conditional form' do
@@ -129,11 +136,13 @@ SKEEM
129
136
  it 'should implement the lambda function with one arg' do
130
137
  source = <<-SKEEM
131
138
  ; Simplified 'abs' function implementation
132
- (define abs
139
+ (define abs
133
140
  (lambda (x)
134
141
  (if (< x 0) (- x) x)))
135
142
  SKEEM
136
143
  subject.run(source)
144
+ procedure = subject.fetch('abs').expression
145
+ expect(procedure.arity).to eq(1)
137
146
  result = subject.run('(abs -3)')
138
147
  expect(result.value).to eq(3)
139
148
  result = subject.run('(abs 0)')
@@ -141,36 +150,65 @@ SKEEM
141
150
  result = subject.run('(abs 3)')
142
151
  expect(result.value).to eq(3)
143
152
  end
144
-
153
+
145
154
  it 'should implement the lambda function with two args' do
146
155
  source = <<-SKEEM
147
156
  ; Simplified 'min' function implementation
148
- (define min
157
+ (define min
149
158
  (lambda (x y)
150
159
  (if (< x y) x y)))
151
160
  SKEEM
152
161
  subject.run(source)
162
+ procedure = subject.fetch('min').expression
163
+ expect(procedure.arity).to eq(2)
153
164
  result = subject.run('(min 1 2)')
154
165
  expect(result.value).to eq(1)
155
166
  result = subject.run('(min 2 1)')
156
167
  expect(result.value).to eq(1)
157
168
  result = subject.run('(min 2 2)')
158
169
  expect(result.value).to eq(2)
159
- end
160
-
170
+ end
171
+
161
172
  it 'should implement recursive functions' do
162
173
  source = <<-SKEEM
163
174
  ; Example from R7RS section 4.1.5
164
- (define fact (lambda (n)
165
- (if (<= n 1)
166
- 1
175
+ (define fact (lambda (n)
176
+ (if (<= n 1)
177
+ 1
167
178
  (* n (fact (- n 1))))))
168
179
  (fact 10)
169
180
  SKEEM
170
181
  result = subject.run(source)
171
- expect(result.value).to eq(3628800)
182
+ expect(result.last.value).to eq(3628800)
183
+ end
184
+
185
+ it 'should accept calls to anonymous procedures' do
186
+ source = '((lambda (x) (+ x x)) 4)'
187
+ result = subject.run(source)
188
+ expect(result.value).to eq(8)
189
+ end
190
+
191
+
192
+ it 'should support procedures with variable number of arguments' do
193
+ # Example from R7RS section 4.1.4
194
+ source = '((lambda x x) 3 4 5 6)'
195
+ result = subject.run(source)
196
+ expect(result).to be_kind_of(SkmList)
197
+ expect(result.length).to eq(4)
172
198
  end
173
199
 
200
+ it 'should support procedures with dotted pair arguments' do
201
+ # Example from R7RS section 4.1.4
202
+ source = '((lambda (x y . z) z) 3 4 5 6)'
203
+ result = subject.run(source)
204
+ expect(result).to be_kind_of(SkmList)
205
+ expect(result.length).to eq(2)
206
+ expect(result.head.value).to eq(5)
207
+ expect(result.last.value).to eq(6)
208
+ end
209
+
210
+
211
+ =begin
174
212
  it 'should implement the compact define + lambda syntax' do
175
213
  source = <<-SKEEM
176
214
  ; Alternative syntax to: (define f (lambda x (+ x 42)))
@@ -179,254 +217,30 @@ SKEEM
179
217
  (f 23)
180
218
  SKEEM
181
219
  result = subject.run(source)
182
- expect(result.value).to eq(65)
183
- end
184
-
185
- it 'should call anonymous procedure' do
186
- source = '((lambda (x) (+ x x)) 4)'
187
- result = subject.run(source)
188
- expect(result.value).to eq(8)
220
+ expect(result.value).to eq(65)
189
221
  end
222
+ =end
190
223
  end # context
191
224
 
192
225
  context 'Built-in primitive procedures' do
193
- it 'should implement the addition of integers' do
194
- result = subject.run('(+ 2 2)')
195
- expect(result).to be_kind_of(SkmInteger)
196
- expect(result.value).to eq(4)
197
- end
198
-
199
- it 'should implement the addition of real numbers' do
200
- result = subject.run('(+ 2 2.34)')
201
- expect(result).to be_kind_of(SkmReal)
202
- expect(result.value).to eq(4.34)
203
- end
204
-
205
- it 'should implement the negation of integer' do
206
- result = subject.run('(- 3)')
207
- expect(result).to be_kind_of(SkmInteger)
208
- expect(result.value).to eq(-3)
209
- end
210
-
211
- it 'should implement the substraction of integers' do
212
- result = subject.run('(- 3 4)')
213
- expect(result).to be_kind_of(SkmInteger)
214
- expect(result.value).to eq(-1)
215
-
216
- result = subject.run('(- 3 4 5)')
217
- expect(result).to be_kind_of(SkmInteger)
218
- expect(result.value).to eq(-6)
219
- end
220
-
221
- it 'should implement the product of numbers' do
222
- checks = [
223
- ['(* 5 8)', 40],
224
- ['(* 2 3 4)', 24]
225
- ]
226
- checks.each do |(skeem_expr, expectation)|
227
- result = subject.run(skeem_expr)
228
- expect(result.value).to eq(expectation)
229
- end
230
- end
231
-
232
226
  it 'should implement the division of numbers' do
233
227
  result = subject.run('(/ 24 3)')
234
228
  expect(result).to be_kind_of(SkmInteger)
235
229
  expect(result.value).to eq(8)
236
230
  end
237
231
 
238
- it 'should implement the arithmetic expressions' do
232
+ it 'should handle arithmetic expressions' do
239
233
  result = subject.run('(+ (* 2 100) (* 1 10))')
240
234
  expect(result).to be_kind_of(SkmInteger)
241
235
  expect(result.value).to eq(210)
242
236
  end
243
-
244
- it 'should implement the floor-remainder (modulo) procedure' do
245
- checks = [
246
- ['(modulo 16 4)', 0],
247
- ['(modulo 5 2)', 1],
248
- ['(modulo -45.0 7)', 4.0],
249
- ['(modulo 10.0 -3.0)', -2.0],
250
- ['(modulo -17 -9)', -8]
251
- ]
252
- checks.each do |(skeem_expr, expectation)|
253
- result = subject.run(skeem_expr)
254
- expect(result.value).to eq(expectation)
255
- end
256
- end
257
-
258
- it 'should implement the equality operator' do
259
- checks = [
260
- ['(= 3 3)', true],
261
- ['(= 3 (+ 1 2) (- 4 1))', true],
262
- ['(= "foo" "foo")', true],
263
- ['(= 3 4)', false],
264
- ['(= "foo" "bar")', false]
265
- ]
266
- checks.each do |(skeem_expr, expectation)|
267
- result = subject.run(skeem_expr)
268
- expect(result.value).to eq(expectation)
269
- end
270
- end
271
-
272
- it 'should implement the less than operator' do
273
- checks = [
274
- ['(< 3 4)', true],
275
- ['(< 3 (+ 2 2) (+ 4 1))', true],
276
- ['(< 3 3)', false],
277
- ['(< 3 2)', false],
278
- ['(< 3 4 5 4)', false]
279
- ]
280
- checks.each do |(skeem_expr, expectation)|
281
- result = subject.run(skeem_expr)
282
- expect(result.value).to eq(expectation)
283
- end
284
- end
285
-
286
- it 'should implement the greater than operator' do
287
- checks = [
288
- ['(> 3 2)', true],
289
- ['(> 3 (- 4 2) (- 2 1))', true],
290
- ['(> 3 3)', false],
291
- ['(> 3 4)', false],
292
- ['(> 3 2 1 2)', false]
293
- ]
294
- checks.each do |(skeem_expr, expectation)|
295
- result = subject.run(skeem_expr)
296
- expect(result.value).to eq(expectation)
297
- end
298
- end
299
-
300
- it 'should implement the less or equal than operator' do
301
- checks = [
302
- ['(<= 3 4)', true],
303
- ['(<= 3 (+ 2 2) (+ 4 1))', true],
304
- ['(<= 3 3)', true],
305
- ['(<= 3 2)', false],
306
- ['(<= 3 4 5 4)', false],
307
- ['(<= 3 4 5 5)', true]
308
- ]
309
- checks.each do |(skeem_expr, expectation)|
310
- result = subject.run(skeem_expr)
311
- expect(result.value).to eq(expectation)
312
- end
313
- end
314
-
315
- it 'should implement the greater or equal than operator' do
316
- checks = [
317
- ['(>= 3 2)', true],
318
- ['(>= 3 (- 4 2) (- 2 1))', true],
319
- ['(>= 3 3)', true],
320
- ['(>= 3 4)', false],
321
- ['(>= 3 2 1 2)', false],
322
- ['(>= 3 2 1 1)', true]
323
- ]
324
- checks.each do |(skeem_expr, expectation)|
325
- result = subject.run(skeem_expr)
326
- expect(result.value).to eq(expectation)
327
- end
328
- end
329
-
330
- it 'should implement the number? predicate' do
331
- checks = [
332
- ['(number? 3.1)', true],
333
- ['(number? 3)', true],
334
- ['(number? "3")', false],
335
- ['(number? #t)', false]
336
- ]
337
- checks.each do |(skeem_expr, expectation)|
338
- result = subject.run(skeem_expr)
339
- expect(result.value).to eq(expectation)
340
- end
341
- end
342
-
343
- it 'should implement the real? predicate' do
344
- checks = [
345
- ['(real? 3.1)', true],
346
- ['(real? 3)', true],
347
- ['(real? "3")', false],
348
- ['(real? #t)', false]
349
- ]
350
- checks.each do |(skeem_expr, expectation)|
351
- result = subject.run(skeem_expr)
352
- expect(result.value).to eq(expectation)
353
- end
354
- end
355
-
356
- it 'should implement the integer? predicate' do
357
- checks = [
358
- ['(integer? 3.1)', false],
359
- # ['(integer? 3.0)', true], TODO: should pass when exact? will be implemented
360
- ['(integer? 3)', true],
361
- ['(integer? "3")', false],
362
- ['(integer? #t)', false]
363
- ]
364
- checks.each do |(skeem_expr, expectation)|
365
- result = subject.run(skeem_expr)
366
- expect(result.value).to eq(expectation)
367
- end
368
- end
369
-
370
- it 'should implement the not procedure' do
371
- checks = [
372
- ['(not #t)', false],
373
- ['(not 3)', false],
374
- ['(not #f)', true]
375
- ]
376
- checks.each do |(skeem_expr, expectation)|
377
- result = subject.run(skeem_expr)
378
- expect(result.value).to eq(expectation)
379
- end
380
- end
381
-
382
- it 'should implement the boolean? procedure' do
383
- checks = [
384
- ['(boolean? #f)', true],
385
- ['(boolean? 0)', false]
386
- ]
387
- checks.each do |(skeem_expr, expectation)|
388
- result = subject.run(skeem_expr)
389
- expect(result.value).to eq(expectation)
390
- end
391
- end
392
-
393
- it 'should implement the string? procedure' do
394
- checks = [
395
- ['(string? #f)', false],
396
- ['(string? 3)', false],
397
- ['(string? "hi")', true]
398
- ]
399
- checks.each do |(skeem_expr, expectation)|
400
- result = subject.run(skeem_expr)
401
- expect(result.value).to eq(expectation)
402
- end
403
- end
404
-
405
- it 'should implement the symbol? procedure' do
406
- checks = [
407
- ['(symbol? #f)', false],
408
- ['(symbol? "bar")', false]
409
- ]
410
- checks.each do |(skeem_expr, expectation)|
411
- result = subject.run(skeem_expr)
412
- expect(result.value).to eq(expectation)
413
- end
414
- end
415
-
416
- it 'should implement the newline procedure' do
417
- default_stdout = $stdout
418
- $stdout = StringIO.new()
419
- subject.run('(newline) (newline) (newline)')
420
- expect($stdout.string).to match(/\n\n\n$/)
421
- $stdout = default_stdout
422
- end
423
237
  end # context
424
-
238
+
425
239
  context 'Built-in standard procedures' do
426
240
  it 'should implement the zero? predicate' do
427
241
  checks = [
428
242
  ['(zero? 3.1)', false],
429
- ['(zero? -3.1)', false],
243
+ ['(zero? -3.1)', false],
430
244
  ['(zero? 0)', true],
431
245
  ['(zero? 0.0)', true],
432
246
  ['(zero? 3)', false],
@@ -438,10 +252,10 @@ SKEEM
438
252
  end
439
253
  end
440
254
 
441
- it 'should implement the positive? predicate' do
255
+ it 'should implement the positive? predicate' do
442
256
  checks = [
443
257
  ['(positive? 3.1)', true],
444
- ['(positive? -3.1)', false],
258
+ ['(positive? -3.1)', false],
445
259
  ['(positive? 0)', true],
446
260
  ['(positive? 0.0)', true],
447
261
  ['(positive? 3)', true],
@@ -453,10 +267,10 @@ SKEEM
453
267
  end
454
268
  end
455
269
 
456
- it 'should implement the positive? predicate' do
270
+ it 'should implement the positive? predicate' do
457
271
  checks = [
458
272
  ['(positive? 3.1)', true],
459
- ['(positive? -3.1)', false],
273
+ ['(positive? -3.1)', false],
460
274
  ['(positive? 0)', true],
461
275
  ['(positive? 0.0)', true],
462
276
  ['(positive? 3)', true],
@@ -468,10 +282,10 @@ SKEEM
468
282
  end
469
283
  end
470
284
 
471
- it 'should implement the negative? predicate' do
285
+ it 'should implement the negative? predicate' do
472
286
  checks = [
473
287
  ['(negative? 3.1)', false],
474
- ['(negative? -3.1)', true],
288
+ ['(negative? -3.1)', true],
475
289
  ['(negative? 0)', false],
476
290
  ['(negative? 0.0)', false],
477
291
  ['(negative? 3)', false],
@@ -483,10 +297,10 @@ SKEEM
483
297
  end
484
298
  end
485
299
 
486
- it 'should implement the even? predicate' do
300
+ it 'should implement the even? predicate' do
487
301
  checks = [
488
302
  ['(even? 0)', true],
489
- ['(even? 1)', false],
303
+ ['(even? 1)', false],
490
304
  ['(even? 2.0)', true],
491
305
  ['(even? -120762398465)', false]
492
306
  ]
@@ -496,10 +310,10 @@ SKEEM
496
310
  end
497
311
  end
498
312
 
499
- it 'should implement the odd? predicate' do
313
+ it 'should implement the odd? predicate' do
500
314
  checks = [
501
315
  ['(odd? 0)', false],
502
- ['(odd? 1)', true],
316
+ ['(odd? 1)', true],
503
317
  ['(odd? 2.0)', false],
504
318
  ['(odd? -120762398465)', true]
505
319
  ]
@@ -507,12 +321,12 @@ SKEEM
507
321
  result = subject.run(skeem_expr)
508
322
  expect(result.value).to eq(expectation)
509
323
  end
510
- end
324
+ end
511
325
 
512
- it 'should implement the abs function' do
326
+ it 'should implement the abs function' do
513
327
  checks = [
514
328
  ['(abs 3.1)', 3.1],
515
- ['(abs -3.1)', 3.1],
329
+ ['(abs -3.1)', 3.1],
516
330
  ['(abs 0)', 0],
517
331
  ['(abs 0.0)', 0],
518
332
  ['(abs 3)', 3],
@@ -524,16 +338,28 @@ SKEEM
524
338
  end
525
339
  end
526
340
 
527
- it 'should implement the square function' do
341
+ it 'should implement the square function' do
528
342
  checks = [
529
343
  ['(square 42)', 1764],
530
- ['(square 2.0)', 4.0],
344
+ ['(square 2.0)', 4.0],
531
345
  ['(square -7)', 49]
532
346
  ]
533
347
  checks.each do |(skeem_expr, expectation)|
534
348
  result = subject.run(skeem_expr)
535
349
  expect(result.value).to eq(expectation)
536
350
  end
351
+ end
352
+
353
+ it 'should implement the list procedure' do
354
+ checks = [
355
+ #['(list)', []],
356
+ ['(list 1)', [1]],
357
+ ['(list 1 2 3 4)', [1, 2, 3, 4]]
358
+ ]
359
+ checks.each do |(skeem_expr, expectation)|
360
+ result = subject.run(skeem_expr)
361
+ expect(result.members.map(&:value)).to eq(expectation)
362
+ end
537
363
  end
538
364
  end # context
539
365
  end # describe