skeem 0.0.17 → 0.0.18

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.
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