skeem 0.0.28 → 0.1.00
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/CHANGELOG.md +24 -1
- data/README.md +3 -3
- data/lib/skeem/datum_dsl.rb +11 -6
- data/lib/skeem/element_visitor.rb +26 -0
- data/lib/skeem/grammar.rb +1 -1
- data/lib/skeem/primitive/primitive_builder.rb +111 -33
- data/lib/skeem/primitive/primitive_procedure.rb +6 -5
- data/lib/skeem/runtime.rb +5 -5
- data/lib/skeem/s_expr_builder.rb +28 -12
- data/lib/skeem/s_expr_nodes.rb +39 -9
- data/lib/skeem/skm_compound_datum.rb +3 -2
- data/lib/skeem/skm_element.rb +4 -0
- data/lib/skeem/skm_empty_list.rb +60 -0
- data/lib/skeem/skm_pair.rb +126 -0
- data/lib/skeem/skm_simple_datum.rb +1 -2
- data/lib/skeem/standard/base.skm +24 -0
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/datum_dsl_spec.rb +45 -33
- data/spec/skeem/element_visitor_spec.rb +54 -53
- data/spec/skeem/interpreter_spec.rb +29 -25
- data/spec/skeem/parser_spec.rb +3 -3
- data/spec/skeem/primitive/primitive_builder_spec.rb +121 -12
- data/spec/skeem/s_expr_nodes_spec.rb +10 -10
- data/spec/skeem/skm_element_spec.rb +1 -0
- data/spec/skeem/skm_empty_list_spec.rb +44 -0
- data/spec/skeem/skm_pair_spec.rb +140 -0
- metadata +8 -2
@@ -187,20 +187,21 @@ SKEEM
|
|
187
187
|
it 'should implement the quotation of lists' do
|
188
188
|
source = '(quote (+ 1 2))'
|
189
189
|
result = subject.run(source)
|
190
|
-
expect(result).to be_kind_of(
|
190
|
+
expect(result).to be_kind_of(SkmPair)
|
191
191
|
predictions = [
|
192
192
|
[SkmIdentifier, '+'],
|
193
193
|
[SkmInteger, 1],
|
194
194
|
[SkmInteger, 2]
|
195
195
|
]
|
196
|
+
members = result.to_a
|
196
197
|
predictions.each_with_index do |(type, value), index|
|
197
|
-
expect(
|
198
|
-
expect(
|
198
|
+
expect(members[index]).to be_kind_of(type)
|
199
|
+
expect(members[index]).to eq(value)
|
199
200
|
end
|
200
201
|
|
201
202
|
source = "'()"
|
202
203
|
result = subject.run(source)
|
203
|
-
expect(result).to be_kind_of(
|
204
|
+
expect(result).to be_kind_of(SkmEmptyList)
|
204
205
|
expect(result).to be_null
|
205
206
|
end
|
206
207
|
|
@@ -263,7 +264,7 @@ SKEEM
|
|
263
264
|
# Example from R7RS section 4.1.4
|
264
265
|
source = '((lambda x x) 3 4 5 6)'
|
265
266
|
result = subject.run(source)
|
266
|
-
expect(result).to be_kind_of(
|
267
|
+
expect(result).to be_kind_of(SkmPair)
|
267
268
|
expect(result.length).to eq(4)
|
268
269
|
end
|
269
270
|
|
@@ -271,9 +272,9 @@ SKEEM
|
|
271
272
|
# Example from R7RS section 4.1.4
|
272
273
|
source = '((lambda (x y . z) z) 3 4 5 6)'
|
273
274
|
result = subject.run(source)
|
274
|
-
expect(result).to be_kind_of(
|
275
|
+
expect(result).to be_kind_of(SkmPair)
|
275
276
|
expect(result.length).to eq(2)
|
276
|
-
expect(result.
|
277
|
+
expect(result.first).to eq(5)
|
277
278
|
expect(result.last).to eq(6)
|
278
279
|
end
|
279
280
|
|
@@ -371,56 +372,59 @@ SKEEM
|
|
371
372
|
it 'should implement the quasiquotation of lists' do
|
372
373
|
source = '(quasiquote (+ 1 2))'
|
373
374
|
result = subject.run(source)
|
374
|
-
expect(result).to be_kind_of(
|
375
|
+
expect(result).to be_kind_of(SkmPair)
|
375
376
|
predictions = [
|
376
377
|
[SkmIdentifier, '+'],
|
377
378
|
[SkmInteger, 1],
|
378
379
|
[SkmInteger, 2]
|
379
380
|
]
|
380
|
-
predictions.
|
381
|
-
expect(result.
|
382
|
-
expect(result.
|
381
|
+
predictions.each do |(type, value)|
|
382
|
+
expect(result.car).to be_kind_of(type)
|
383
|
+
expect(result.car).to eq(value)
|
384
|
+
result = result.cdr
|
383
385
|
end
|
384
386
|
|
385
387
|
source = "`()"
|
386
388
|
result = subject.run(source)
|
387
|
-
expect(result).to be_kind_of(
|
389
|
+
expect(result).to be_kind_of(SkmEmptyList)
|
388
390
|
expect(result).to be_null
|
389
391
|
end
|
390
392
|
|
391
393
|
it 'should implement the unquote of lists' do
|
392
394
|
source = '`(list ,(+ 1 2) 4)'
|
393
395
|
result = subject.run(source)
|
394
|
-
expect(result).to be_kind_of(
|
396
|
+
expect(result).to be_kind_of(SkmPair)
|
395
397
|
predictions = [
|
396
398
|
[SkmIdentifier, 'list'],
|
397
399
|
[SkmInteger, 3],
|
398
400
|
[SkmInteger, 4]
|
399
401
|
]
|
400
|
-
predictions.
|
401
|
-
expect(result.
|
402
|
-
expect(result.
|
402
|
+
predictions.each do |(type, value)|
|
403
|
+
expect(result.car).to be_kind_of(type)
|
404
|
+
expect(result.car).to eq(value)
|
405
|
+
result = result.cdr
|
403
406
|
end
|
404
407
|
|
405
408
|
source = "`()"
|
406
409
|
result = subject.run(source)
|
407
|
-
expect(result).to be_kind_of(
|
410
|
+
expect(result).to be_kind_of(SkmEmptyList)
|
408
411
|
expect(result).to be_null
|
409
412
|
|
410
413
|
# nested lists
|
411
414
|
source = '`(a b (,(+ 2 3) c) d)'
|
412
415
|
result = subject.run(source)
|
413
416
|
# expected: (a b (5 c) d)
|
414
|
-
expect(result).to be_kind_of(
|
417
|
+
expect(result).to be_kind_of(SkmPair)
|
415
418
|
predictions = [
|
416
419
|
[SkmIdentifier, 'a'],
|
417
420
|
[SkmIdentifier, 'b'],
|
418
|
-
[
|
421
|
+
[SkmPair, list([integer(5), identifier('c')])],
|
419
422
|
[SkmIdentifier, 'd']
|
420
423
|
]
|
421
|
-
predictions.
|
422
|
-
expect(result.
|
423
|
-
expect(result.
|
424
|
+
predictions.each do |(type, value)|
|
425
|
+
expect(result.car).to be_kind_of(type)
|
426
|
+
expect(result.car).to eq(value)
|
427
|
+
result = result.cdr
|
424
428
|
end
|
425
429
|
end
|
426
430
|
=begin
|
@@ -592,7 +596,7 @@ SKEEM
|
|
592
596
|
]
|
593
597
|
checks.each do |(skeem_expr, expectation)|
|
594
598
|
result = subject.run(skeem_expr)
|
595
|
-
expect(result.
|
599
|
+
expect(result.to_a).to eq(expectation)
|
596
600
|
end
|
597
601
|
end
|
598
602
|
|
@@ -619,7 +623,7 @@ SKEEM
|
|
619
623
|
((compose list square) 5)
|
620
624
|
SKEEM
|
621
625
|
result = subject.run(source)
|
622
|
-
expect(result.last.
|
626
|
+
expect(result.last.car).to eq(25)
|
623
627
|
end
|
624
628
|
|
625
629
|
it 'should implement lambda that calls second-order functions' do
|
@@ -637,7 +641,7 @@ SKEEM
|
|
637
641
|
((repeat twice) 5)
|
638
642
|
SKEEM
|
639
643
|
result = subject.run(source)
|
640
|
-
expect(result.
|
644
|
+
expect(result.last).to eq(20)
|
641
645
|
end
|
642
646
|
end # context
|
643
647
|
end # describe
|
data/spec/skeem/parser_spec.rb
CHANGED
@@ -17,9 +17,9 @@ module Skeem
|
|
17
17
|
it 'should parse isolated booleans' do
|
18
18
|
samples = [
|
19
19
|
['#f', false],
|
20
|
-
['#false', false],
|
21
|
-
['#t', true],
|
22
|
-
['#true', true]
|
20
|
+
# ['#false', false],
|
21
|
+
# ['#t', true],
|
22
|
+
# ['#true', true]
|
23
23
|
]
|
24
24
|
samples.each do |source, predicted|
|
25
25
|
ptree = subject.parse(source)
|
@@ -7,7 +7,7 @@ module Skeem
|
|
7
7
|
module Primitive
|
8
8
|
describe 'Testing primitive procedures' do
|
9
9
|
subject { Interpreter.new }
|
10
|
-
|
10
|
+
|
11
11
|
context 'Arithmetic operators:' do
|
12
12
|
it 'should implement the set! form' do
|
13
13
|
skeem1 = <<-SKEEM
|
@@ -22,7 +22,7 @@ SKEEM
|
|
22
22
|
SKEEM
|
23
23
|
result = subject.run(skeem2)
|
24
24
|
expect(result.last).to eq(5) # x is now bound to value 4
|
25
|
-
end
|
25
|
+
end
|
26
26
|
end # context
|
27
27
|
|
28
28
|
context 'Arithmetic operators:' do
|
@@ -105,9 +105,9 @@ SKEEM
|
|
105
105
|
checks.each do |(skeem_expr, expectation)|
|
106
106
|
result = subject.run(skeem_expr)
|
107
107
|
expect(result).to eq(expectation)
|
108
|
-
end
|
108
|
+
end
|
109
109
|
end
|
110
|
-
|
110
|
+
|
111
111
|
it 'should implement the equality operator' do
|
112
112
|
checks = [
|
113
113
|
['(= 3)', true], # '=' as unary operator
|
@@ -257,9 +257,10 @@ SKEEM
|
|
257
257
|
# the values of the last expression are returned.
|
258
258
|
source = "(and 1 2 'c '(f g))"
|
259
259
|
result = subject.run(source)
|
260
|
-
expect(result).to be_kind_of(
|
261
|
-
expect(result.
|
262
|
-
expect(result.
|
260
|
+
expect(result).to be_kind_of(SkmPair)
|
261
|
+
expect(result.car).to eq('f')
|
262
|
+
expect(result.cdr).to be_kind_of(SkmPair)
|
263
|
+
expect(result.cdr.car).to eq('g')
|
263
264
|
end
|
264
265
|
|
265
266
|
it 'should implement the or procedure' do
|
@@ -370,10 +371,23 @@ SKEEM
|
|
370
371
|
result = subject.run(skeem_expr)
|
371
372
|
expect(result).to eq(expectation)
|
372
373
|
end
|
373
|
-
end
|
374
|
+
end
|
374
375
|
end # context
|
375
376
|
|
376
377
|
context 'List procedures:' do
|
378
|
+
it 'should implement the pair? procedure' do
|
379
|
+
checks = [
|
380
|
+
["(pair? '(a . b))", true],
|
381
|
+
["(pair? '(a b c))", true],
|
382
|
+
["(pair? '())", false],
|
383
|
+
["(pair? '#(a b))", false]
|
384
|
+
]
|
385
|
+
checks.each do |(skeem_expr, expectation)|
|
386
|
+
result = subject.run(skeem_expr)
|
387
|
+
expect(result).to eq(expectation)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
377
391
|
it 'should implement the list? procedure' do
|
378
392
|
checks = [
|
379
393
|
['(list? #f)', false],
|
@@ -404,6 +418,79 @@ SKEEM
|
|
404
418
|
end
|
405
419
|
end
|
406
420
|
|
421
|
+
it 'should implement the cons procedure' do
|
422
|
+
example = "(cons 'a '())" # => (a)
|
423
|
+
result = subject.run(example)
|
424
|
+
expect(result).to be_list
|
425
|
+
expect(result.car).to eq('a')
|
426
|
+
|
427
|
+
example = "(cons '(a) '(b c d))" # => ((a) b c d)
|
428
|
+
result = subject.run(example)
|
429
|
+
expect(result).to be_list
|
430
|
+
members = result.to_a
|
431
|
+
expect(members[0]).to be_list
|
432
|
+
expect(members[0].car).to eq('a')
|
433
|
+
expect(members[1]).to eq('b')
|
434
|
+
expect(members[2]).to eq('c')
|
435
|
+
expect(members[3]).to eq('d')
|
436
|
+
|
437
|
+
example = "(cons \"a\" '(b c))" # => ("a" b c)
|
438
|
+
result = subject.run(example)
|
439
|
+
expect(result).to be_list
|
440
|
+
expect(result.car).to be_kind_of(SkmString)
|
441
|
+
expect(result.car).to eq('a')
|
442
|
+
expect(result.cdr.car).to be_kind_of(SkmIdentifier)
|
443
|
+
expect(result.cdr.car).to eq('b')
|
444
|
+
expect(result.cdr.cdr.car).to be_kind_of(SkmIdentifier)
|
445
|
+
expect(result.cdr.cdr.car).to eq('c')
|
446
|
+
|
447
|
+
example = "(cons 'a 3)" # => (a . 3)
|
448
|
+
result = subject.run(example)
|
449
|
+
expect(result.car).to eq('a')
|
450
|
+
expect(result.cdr).to eq(3)
|
451
|
+
|
452
|
+
example = "(cons '(a b) 'c)" # => ((a b) . c)
|
453
|
+
result = subject.run(example)
|
454
|
+
expect(result.car).to be_kind_of(SkmPair)
|
455
|
+
expect(result.car.to_a).to eq(['a', 'b'])
|
456
|
+
expect(result.cdr).to be_kind_of(SkmIdentifier)
|
457
|
+
expect(result.cdr).to eq('c')
|
458
|
+
end
|
459
|
+
|
460
|
+
it 'should implement the car procedure' do
|
461
|
+
example = "(car '(a b c))" # => a
|
462
|
+
result = subject.run(example)
|
463
|
+
expect(result).to eq('a')
|
464
|
+
|
465
|
+
example = "(car '((a) b c d))" # => (a)
|
466
|
+
result = subject.run(example)
|
467
|
+
expect(result).to be_list
|
468
|
+
expect(result.length).to eq(1)
|
469
|
+
expect(result.car).to eq('a')
|
470
|
+
|
471
|
+
# example = "(car '(1 . 2))" # => 1 # FAILURE
|
472
|
+
# result = subject.run(example)
|
473
|
+
# expect(result.car).to eq(1)
|
474
|
+
|
475
|
+
example = "(car '())" # => error
|
476
|
+
expect { subject.run(example) }.to raise_error(StandardError)
|
477
|
+
end
|
478
|
+
|
479
|
+
it 'should implement the cdr procedure' do
|
480
|
+
example = "(cdr '((a) b c d))" # => (b c d)
|
481
|
+
result = subject.run(example)
|
482
|
+
expect(result).to be_list
|
483
|
+
expect(result.length).to eq(3)
|
484
|
+
expect(result.to_a).to eq(['b', 'c', 'd'])
|
485
|
+
|
486
|
+
# example = "(cdr '(1 . 2))" # => 2 # PARSER FAILURE
|
487
|
+
# result = subject.run(example)
|
488
|
+
# expect(result.cdr).to eq(2)
|
489
|
+
|
490
|
+
example = "(cdr '())" # => error
|
491
|
+
expect { subject.run(example) }.to raise_error(StandardError)
|
492
|
+
end
|
493
|
+
|
407
494
|
it 'should implement the length procedure' do
|
408
495
|
checks = [
|
409
496
|
['(length (list))', 0],
|
@@ -416,6 +503,17 @@ SKEEM
|
|
416
503
|
expect(result).to eq(expectation)
|
417
504
|
end
|
418
505
|
end
|
506
|
+
|
507
|
+
it 'should implement the list->vector procedure' do
|
508
|
+
checks = [
|
509
|
+
["(list->vector '())", []],
|
510
|
+
["(list->vector '(a b c))", ['a', 'b', 'c']]
|
511
|
+
]
|
512
|
+
checks.each do |(skeem_expr, expectation)|
|
513
|
+
result = subject.run(skeem_expr)
|
514
|
+
expect(result.to_a).to eq(expectation)
|
515
|
+
end
|
516
|
+
end
|
419
517
|
end # context
|
420
518
|
|
421
519
|
context 'Vector procedures:' do
|
@@ -467,6 +565,17 @@ SKEEM
|
|
467
565
|
expect(result).to be_kind_of(SkmInteger)
|
468
566
|
expect(result).to eq(8)
|
469
567
|
end
|
568
|
+
|
569
|
+
it 'should implement the vector-> procedure' do
|
570
|
+
checks = [
|
571
|
+
["(vector->list #())", []],
|
572
|
+
["(vector->list '#(a b c))", ['a', 'b', 'c']]
|
573
|
+
]
|
574
|
+
checks.each do |(skeem_expr, expectation)|
|
575
|
+
result = subject.run(skeem_expr)
|
576
|
+
expect(result.to_a).to eq(expectation)
|
577
|
+
end
|
578
|
+
end
|
470
579
|
end # context
|
471
580
|
|
472
581
|
context 'IO procedures:' do
|
@@ -478,7 +587,7 @@ SKEEM
|
|
478
587
|
$stdout = default_stdout
|
479
588
|
end
|
480
589
|
end # context
|
481
|
-
|
590
|
+
|
482
591
|
context 'Miscellaneous procedures' do
|
483
592
|
it 'should return true when an assertion succeeds' do
|
484
593
|
source = <<-SKEEM
|
@@ -487,8 +596,8 @@ SKEEM
|
|
487
596
|
(assert (> x y))
|
488
597
|
SKEEM
|
489
598
|
expect(subject.run(source).last).to eq(true)
|
490
|
-
end
|
491
|
-
|
599
|
+
end
|
600
|
+
|
492
601
|
it 'should raise an error when an assertion fails' do
|
493
602
|
source = <<-SKEEM
|
494
603
|
(define x 1)
|
@@ -498,7 +607,7 @@ SKEEM
|
|
498
607
|
err = StandardError
|
499
608
|
msg = 'Error: assertion failed on line 3, column 4'
|
500
609
|
expect { subject.run(source) }.to raise_error(err, msg)
|
501
|
-
end
|
610
|
+
end
|
502
611
|
end # context
|
503
612
|
end # describe
|
504
613
|
end # module
|
@@ -28,7 +28,7 @@ module Skeem
|
|
28
28
|
|
29
29
|
context 'Provided services:' do
|
30
30
|
include Primitive::PrimitiveBuilder
|
31
|
-
|
31
|
+
|
32
32
|
let(:runtime) { Runtime.new(Environment.new) }
|
33
33
|
|
34
34
|
it 'should create an entry when evaluating' do
|
@@ -36,7 +36,7 @@ module Skeem
|
|
36
36
|
subject.evaluate(runtime)
|
37
37
|
expect(runtime).to include(sample_symbol)
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
it 'should optimize an entry that aliases a primitive proc' do
|
41
41
|
add_primitives(runtime)
|
42
42
|
identifier = SkmIdentifier.create('plus')
|
@@ -57,22 +57,22 @@ module Skeem
|
|
57
57
|
id = SkmIdentifier.create('some-lambda')
|
58
58
|
def1 = SkmDefinition.new(nil, id, lbd)
|
59
59
|
def1.evaluate(runtime)
|
60
|
-
|
60
|
+
|
61
61
|
# Let's create an alias to the lambda
|
62
62
|
other_name = SkmIdentifier.create('aliased-lambda')
|
63
63
|
var_ref = SkmVariableReference.new(nil, id)
|
64
|
-
|
64
|
+
|
65
65
|
# (define aliased-lambda some-lambda)
|
66
|
-
def2 = SkmDefinition.new(nil, other_name, var_ref)
|
66
|
+
def2 = SkmDefinition.new(nil, other_name, var_ref)
|
67
67
|
expect(def2.expression).to eq(var_ref)
|
68
68
|
def2.evaluate(runtime)
|
69
69
|
# Optimization by getting rid of indirection
|
70
70
|
expect(def2.expression).to eq(lbd)
|
71
|
-
end
|
72
|
-
|
71
|
+
end
|
72
|
+
|
73
73
|
it 'should quasiquote its variable and expression' do
|
74
74
|
alter_ego = subject.quasiquote(runtime)
|
75
|
-
expect(alter_ego).to eq(subject)
|
75
|
+
expect(alter_ego).to eq(subject)
|
76
76
|
end
|
77
77
|
|
78
78
|
it 'should return its text representation' do
|
@@ -100,14 +100,14 @@ module Skeem
|
|
100
100
|
end
|
101
101
|
|
102
102
|
it 'should know its operands' do
|
103
|
-
expect(subject.operands.inspect).to eq('<Skeem::
|
103
|
+
expect(subject.operands.inspect).to eq('<Skeem::SkmPair: 1, 2, 3>')
|
104
104
|
end
|
105
105
|
end # context
|
106
106
|
|
107
107
|
context 'Provided services:' do
|
108
108
|
it 'should return its text representation' do
|
109
109
|
txt1 = '<Skeem::ProcedureCall: <Skeem::SkmIdentifier: +>, '
|
110
|
-
txt2 = '@operands <Skeem::
|
110
|
+
txt2 = '@operands <Skeem::SkmPair: 1, 2, 3>>'
|
111
111
|
expect(subject.inspect).to eq(txt1 + txt2)
|
112
112
|
end
|
113
113
|
end # context
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
2
|
+
require_relative '../../lib/skeem/skm_empty_list' # Load the class under test
|
3
|
+
|
4
|
+
module Skeem
|
5
|
+
describe SkmEmptyList do
|
6
|
+
subject { SkmEmptyList.instance }
|
7
|
+
|
8
|
+
context 'Initialization:' do
|
9
|
+
it 'should be initialized without argument' do
|
10
|
+
expect { SkmEmptyList.instance }.not_to raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
# Default (overridable) behavior of SkmElement
|
14
|
+
it 'should react by default to predicates' do
|
15
|
+
expect(subject).to be_list
|
16
|
+
expect(subject).to be_null
|
17
|
+
expect(subject).not_to be_pair
|
18
|
+
end
|
19
|
+
end # context
|
20
|
+
|
21
|
+
context 'Provided services:' do
|
22
|
+
let(:runtime) { double('fake-runtime') }
|
23
|
+
|
24
|
+
it "should return itself when receiving 'evaluate' message" do
|
25
|
+
expect(subject.evaluate(runtime)).to eq(subject)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return itself receiving 'quasiquote' message" do
|
29
|
+
expect(subject.quasiquote(runtime)).to eq(subject)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should reply to visitor's 'accept' message" do
|
33
|
+
visitor = double('fake-visitor')
|
34
|
+
expect(visitor).to receive(:visit_empty_list).with(subject)
|
35
|
+
expect { subject.accept(visitor) }.not_to raise_error
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should return its representation upon inspection' do
|
39
|
+
predicted = '<Skeem::SkmEmptyList: ()>'
|
40
|
+
expect(subject.inspect).to eq(predicted)
|
41
|
+
end
|
42
|
+
end # context
|
43
|
+
end # describe
|
44
|
+
end # module
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require_relative '../spec_helper' # Use the RSpec framework
|
2
|
+
require_relative '../../lib/skeem/datum_dsl'
|
3
|
+
require_relative '../../lib/skeem/runtime'
|
4
|
+
require_relative '../../lib/skeem/skm_pair' # Load the class under test
|
5
|
+
|
6
|
+
module Skeem
|
7
|
+
describe SkmPair do
|
8
|
+
include DatumDSL
|
9
|
+
let(:sample_car) { integer(3) }
|
10
|
+
let(:sample_cdr) { SkmEmptyList.instance }
|
11
|
+
|
12
|
+
# Default instance is proper list of length 1
|
13
|
+
subject { SkmPair.new(sample_car, sample_cdr) }
|
14
|
+
|
15
|
+
context 'Initialization:' do
|
16
|
+
it 'should be initialized with two arguments' do
|
17
|
+
expect { SkmPair.new(sample_car, sample_cdr) }.not_to raise_error
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should know its 'car' field" do
|
21
|
+
expect(subject.car).to eq(sample_car)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should know its 'cdr' field" do
|
25
|
+
expect(subject.cdr).to eq(sample_cdr)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Default (overridable) behavior of SkmElement
|
29
|
+
it 'should react by default to predicates' do
|
30
|
+
expect(subject).to be_list
|
31
|
+
expect(subject).not_to be_null
|
32
|
+
expect(subject).to be_pair
|
33
|
+
end
|
34
|
+
end # context
|
35
|
+
|
36
|
+
context 'Provided services:' do
|
37
|
+
let(:runtime) { Runtime.new(Environment.new) }
|
38
|
+
let(:list_length_2) { SkmPair.new(integer(10), subject) }
|
39
|
+
let(:quirk_element) { double('three') }
|
40
|
+
let(:quirk_members) { [integer(10), quirk_element] }
|
41
|
+
|
42
|
+
it 'should know its length' do
|
43
|
+
expect(subject.length).to eq(1)
|
44
|
+
|
45
|
+
# Use a list of length 2
|
46
|
+
expect(list_length_2.length).to eq(2)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should convert itself into an array' do
|
50
|
+
expect(subject.to_a).to eq([sample_car])
|
51
|
+
|
52
|
+
# Use a list of length 2
|
53
|
+
expect(list_length_2.to_a).to eq([integer(10), sample_car])
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should return the last element of a list' do
|
57
|
+
expect(subject.last).to eq(sample_car)
|
58
|
+
expect(list_length_2.last).to eq(sample_car)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should append a new element to a list' do
|
62
|
+
subject.append(integer(4))
|
63
|
+
expect(subject.length).to eq(2)
|
64
|
+
expect(subject.to_a).to eq([3, 4])
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should create a list from an array' do
|
68
|
+
# List of length 0
|
69
|
+
array0 = []
|
70
|
+
list = SkmPair.create_from_a(array0)
|
71
|
+
expect(list).to be_list # It's a proper list...
|
72
|
+
expect(list.length).to eq(0)
|
73
|
+
expect(list.to_a).to eq(array0)
|
74
|
+
|
75
|
+
# List of length 1
|
76
|
+
array1 = [boolean(false)]
|
77
|
+
list = SkmPair.create_from_a(array1)
|
78
|
+
expect(list).to be_list # It's a proper list...
|
79
|
+
expect(list.length).to eq(1)
|
80
|
+
expect(list.to_a).to eq(array1)
|
81
|
+
|
82
|
+
# List of length 2
|
83
|
+
array2 = [identifier('f'), identifier('g')]
|
84
|
+
list = SkmPair.create_from_a(array2)
|
85
|
+
expect(list).to be_list # It's a proper list...
|
86
|
+
expect(list.length).to eq(2)
|
87
|
+
expect(list.to_a).to eq(array2)
|
88
|
+
|
89
|
+
# List of length 3
|
90
|
+
array3 = [integer(4), integer(5), integer(6)]
|
91
|
+
list = SkmPair.create_from_a(array3)
|
92
|
+
expect(list).to be_list # It's a proper list...
|
93
|
+
expect(list.length).to eq(3)
|
94
|
+
expect(list.to_a).to eq([4, 5, 6])
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should support the each method' do
|
98
|
+
my_list = SkmPair.new('w', SkmPair.new('o', SkmPair.new('w', SkmEmptyList.instance)))
|
99
|
+
text = ''
|
100
|
+
my_list.each { |ch| text << ch.upcase }
|
101
|
+
expect(text).to eq('WOW')
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should evaluate its members' do
|
105
|
+
# subject contains simple literals
|
106
|
+
expect(subject.evaluate(runtime)).to eq(subject)
|
107
|
+
|
108
|
+
# Check that members receive the 'evaluate' message
|
109
|
+
expect(quirk_element).to receive(:evaluate).with(runtime).and_return(integer(3))
|
110
|
+
instance = SkmPair.create_from_a(quirk_members)
|
111
|
+
expect { instance.evaluate(runtime) }.not_to raise_error
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should quasiquote its members' do
|
115
|
+
# subject contains simple literals
|
116
|
+
expect(subject.quasiquote(runtime)).to eq(subject)
|
117
|
+
|
118
|
+
# Check that members receive the 'quasiquote' message
|
119
|
+
expect(quirk_element).to receive(:quasiquote).with(runtime).and_return(integer(3))
|
120
|
+
instance = SkmPair.create_from_a(quirk_members)
|
121
|
+
expect { instance.quasiquote(runtime) }.not_to raise_error
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should reply to visitor's 'accept' message" do
|
125
|
+
visitor = double('fake-visitor')
|
126
|
+
expect(visitor).to receive(:visit_pair).with(subject)
|
127
|
+
expect { subject.accept(visitor) }.not_to raise_error
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should return its representation upon inspection' do
|
131
|
+
predicted = '<Skeem::SkmPair: <Skeem::SkmInteger: 3>>'
|
132
|
+
expect(subject.inspect).to eq(predicted)
|
133
|
+
|
134
|
+
predicted = '<Skeem::SkmPair: <Skeem::SkmInteger: 10>, <Skeem::SkmInteger: 3>>'
|
135
|
+
expect(list_length_2.inspect).to eq(predicted)
|
136
|
+
end
|
137
|
+
end # context
|
138
|
+
|
139
|
+
end # describe
|
140
|
+
end # module
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: skeem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.00
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-12-
|
11
|
+
date: 2018-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|
@@ -98,7 +98,9 @@ files:
|
|
98
98
|
- lib/skeem/s_expr_nodes.rb
|
99
99
|
- lib/skeem/skm_compound_datum.rb
|
100
100
|
- lib/skeem/skm_element.rb
|
101
|
+
- lib/skeem/skm_empty_list.rb
|
101
102
|
- lib/skeem/skm_expression.rb
|
103
|
+
- lib/skeem/skm_pair.rb
|
102
104
|
- lib/skeem/skm_simple_datum.rb
|
103
105
|
- lib/skeem/skm_unary_expression.rb
|
104
106
|
- lib/skeem/standard/base.skm
|
@@ -116,6 +118,8 @@ files:
|
|
116
118
|
- spec/skeem/s_expr_nodes_spec.rb
|
117
119
|
- spec/skeem/skm_compound_datum_spec.rb
|
118
120
|
- spec/skeem/skm_element_spec.rb
|
121
|
+
- spec/skeem/skm_empty_list_spec.rb
|
122
|
+
- spec/skeem/skm_pair_spec.rb
|
119
123
|
- spec/skeem/skm_simple_datum_spec.rb
|
120
124
|
- spec/skeem/skm_unary_expression_spec.rb
|
121
125
|
- spec/skeem/tokenizer_spec.rb
|
@@ -158,6 +162,8 @@ test_files:
|
|
158
162
|
- spec/skeem/runtime_spec.rb
|
159
163
|
- spec/skeem/skm_compound_datum_spec.rb
|
160
164
|
- spec/skeem/skm_element_spec.rb
|
165
|
+
- spec/skeem/skm_empty_list_spec.rb
|
166
|
+
- spec/skeem/skm_pair_spec.rb
|
161
167
|
- spec/skeem/skm_simple_datum_spec.rb
|
162
168
|
- spec/skeem/skm_unary_expression_spec.rb
|
163
169
|
- spec/skeem/s_expr_nodes_spec.rb
|