skeem 0.2.15 → 0.2.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +17 -11
- data/CHANGELOG.md +5 -0
- data/Gemfile +2 -0
- data/README.md +3 -2
- data/Rakefile +2 -0
- data/appveyor.yml +3 -4
- data/bin/skeem +15 -15
- data/lib/skeem.rb +2 -0
- data/lib/skeem/datum_dsl.rb +12 -3
- data/lib/skeem/element_visitor.rb +5 -2
- data/lib/skeem/grammar.rb +86 -24
- data/lib/skeem/interpreter.rb +5 -3
- data/lib/skeem/parser.rb +6 -4
- data/lib/skeem/primitive/primitive_builder.rb +128 -115
- data/lib/skeem/primitive/primitive_procedure.rb +17 -20
- data/lib/skeem/runtime.rb +9 -5
- data/lib/skeem/s_expr_builder.rb +46 -104
- data/lib/skeem/s_expr_nodes.rb +116 -90
- data/lib/skeem/skeem_exception.rb +0 -0
- data/lib/skeem/skm_binding.rb +6 -7
- data/lib/skeem/skm_compound_datum.rb +8 -4
- data/lib/skeem/skm_element.rb +14 -12
- data/lib/skeem/skm_empty_list.rb +6 -4
- data/lib/skeem/skm_exception.rb +9 -0
- data/lib/skeem/skm_expression.rb +3 -1
- data/lib/skeem/skm_frame.rb +3 -2
- data/lib/skeem/skm_pair.rb +23 -18
- data/lib/skeem/skm_procedure_exec.rb +8 -6
- data/lib/skeem/skm_simple_datum.rb +13 -12
- data/lib/skeem/skm_unary_expression.rb +15 -17
- data/lib/skeem/tokenizer.rb +32 -25
- data/lib/skeem/version.rb +3 -1
- data/skeem.gemspec +6 -4
- data/spec/skeem/add4.skm +4 -0
- data/spec/skeem/datum_dsl_spec.rb +13 -12
- data/spec/skeem/element_visitor_spec.rb +12 -10
- data/spec/skeem/interpreter_spec.rb +74 -46
- data/spec/skeem/lambda_spec.rb +9 -7
- data/spec/skeem/parser_spec.rb +21 -19
- data/spec/skeem/primitive/primitive_builder_spec.rb +57 -48
- data/spec/skeem/primitive/primitive_procedure_spec.rb +15 -13
- data/spec/skeem/runtime_spec.rb +18 -16
- data/spec/skeem/s_expr_nodes_spec.rb +8 -6
- data/spec/skeem/skm_compound_datum_spec.rb +11 -9
- data/spec/skeem/skm_element_spec.rb +7 -5
- data/spec/skeem/skm_empty_list_spec.rb +7 -5
- data/spec/skeem/skm_frame_spec.rb +5 -4
- data/spec/skeem/skm_pair_spec.rb +4 -3
- data/spec/skeem/skm_procedure_exec_spec.rb +2 -0
- data/spec/skeem/skm_simple_datum_spec.rb +24 -22
- data/spec/skeem/skm_unary_expression_spec.rb +11 -9
- data/spec/skeem/tokenizer_spec.rb +53 -44
- data/spec/skeem_spec.rb +2 -0
- data/spec/spec_helper.rb +4 -2
- metadata +7 -4
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'stringio'
|
2
4
|
require_relative '../spec_helper' # Use the RSpec framework
|
3
5
|
require_relative '../../lib/skeem/datum_dsl'
|
@@ -14,7 +16,7 @@ module Skeem
|
|
14
16
|
end
|
15
17
|
|
16
18
|
it 'could be initialized with a block argument' do
|
17
|
-
expect { Interpreter.new { |interp| }
|
19
|
+
expect { Interpreter.new { |interp| } }.not_to raise_error
|
18
20
|
end
|
19
21
|
|
20
22
|
it 'should have a parser' do
|
@@ -90,6 +92,7 @@ module Skeem
|
|
90
92
|
end
|
91
93
|
|
92
94
|
it 'should evaluate vector of constants' do
|
95
|
+
require 'benchmark'
|
93
96
|
source = '#(2018 10 20 "Sat")'
|
94
97
|
result = subject.run(source)
|
95
98
|
expect(result).to be_kind_of(SkmVector)
|
@@ -108,7 +111,7 @@ module Skeem
|
|
108
111
|
|
109
112
|
context 'Built-in primitives' do
|
110
113
|
it 'should implement variable definition' do
|
111
|
-
|
114
|
+
subject.run('(define x 28)')
|
112
115
|
expect(subject.fetch('x')).to eq(28)
|
113
116
|
end
|
114
117
|
|
@@ -125,7 +128,7 @@ SKEEM
|
|
125
128
|
end
|
126
129
|
|
127
130
|
it 'should implement the simple conditional form' do
|
128
|
-
|
131
|
+
checks = [
|
129
132
|
['(if (> 3 2) "yes")', 'yes'],
|
130
133
|
['(if (> 2 3) "yes")', SkmUndefined.instance]
|
131
134
|
]
|
@@ -157,7 +160,7 @@ SKEEM
|
|
157
160
|
((< x 0) -1)
|
158
161
|
)))
|
159
162
|
SKEEM
|
160
|
-
|
163
|
+
subject.run(source)
|
161
164
|
checks = [
|
162
165
|
['(signum 3)', 1],
|
163
166
|
['(signum 0)', 0],
|
@@ -175,7 +178,7 @@ SKEEM
|
|
175
178
|
((< x 0) => -1)
|
176
179
|
)))
|
177
180
|
SKEEM
|
178
|
-
|
181
|
+
subject.run(source)
|
179
182
|
checks = [
|
180
183
|
['(signum 3)', 1],
|
181
184
|
['(signum 0)', 0],
|
@@ -193,7 +196,7 @@ SKEEM
|
|
193
196
|
(else -1)
|
194
197
|
)))
|
195
198
|
SKEEM
|
196
|
-
|
199
|
+
subject.run(source)
|
197
200
|
checks = [
|
198
201
|
['(signum 3)', 1],
|
199
202
|
['(signum 0)', 0],
|
@@ -211,7 +214,7 @@ SKEEM
|
|
211
214
|
end
|
212
215
|
|
213
216
|
it 'should implement the quotation of constant literals' do
|
214
|
-
|
217
|
+
checks = [
|
215
218
|
['(quote a)', 'a'],
|
216
219
|
['(quote 145932)', 145932],
|
217
220
|
['(quote "abc")', 'abc'],
|
@@ -367,8 +370,6 @@ SKEEM
|
|
367
370
|
result = subject.run(source)
|
368
371
|
expect(result.last.value).to eq(20)
|
369
372
|
end
|
370
|
-
|
371
|
-
|
372
373
|
end # context
|
373
374
|
|
374
375
|
context 'Binding constructs:' do
|
@@ -406,7 +407,7 @@ SKEEM
|
|
406
407
|
end
|
407
408
|
|
408
409
|
it 'should support the nesting of a lambda in a let expression' do
|
409
|
-
source
|
410
|
+
source = <<-SKEEM
|
410
411
|
(define make-counter
|
411
412
|
(lambda ()
|
412
413
|
(let ((count 0))
|
@@ -477,7 +478,7 @@ SKEEM
|
|
477
478
|
|
478
479
|
context 'Quasiquotation:' do
|
479
480
|
it 'should implement the quasiquotation of constant literals' do
|
480
|
-
|
481
|
+
checks = [
|
481
482
|
['(quasiquote a)', 'a'],
|
482
483
|
['(quasiquote 145932)', 145932],
|
483
484
|
['(quasiquote "abc")', 'abc'],
|
@@ -518,7 +519,7 @@ SKEEM
|
|
518
519
|
expect(result.members[index]).to eq(value)
|
519
520
|
end
|
520
521
|
|
521
|
-
source =
|
522
|
+
source = '`#()'
|
522
523
|
result = subject.run(source)
|
523
524
|
expect(result).to be_kind_of(SkmVector)
|
524
525
|
expect(result).to be_empty
|
@@ -555,7 +556,7 @@ SKEEM
|
|
555
556
|
result = result.cdr
|
556
557
|
end
|
557
558
|
|
558
|
-
source =
|
559
|
+
source = '`()'
|
559
560
|
result = subject.run(source)
|
560
561
|
expect(result).to be_kind_of(SkmEmptyList)
|
561
562
|
expect(result).to be_null
|
@@ -576,7 +577,7 @@ SKEEM
|
|
576
577
|
result = result.cdr
|
577
578
|
end
|
578
579
|
|
579
|
-
source =
|
580
|
+
source = '`()'
|
580
581
|
result = subject.run(source)
|
581
582
|
expect(result).to be_kind_of(SkmEmptyList)
|
582
583
|
expect(result).to be_null
|
@@ -801,46 +802,56 @@ SKEEM
|
|
801
802
|
compare_to_predicted(checks)
|
802
803
|
end
|
803
804
|
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
805
|
+
it 'should implement the truncate-quotient procedure' do
|
806
|
+
checks = [
|
807
|
+
['(truncate-quotient 5 2)', 2],
|
808
|
+
['(truncate-quotient -5 2)', -2],
|
809
|
+
['(truncate-quotient 5 -2)', -2],
|
810
|
+
['(truncate-quotient -5 -2)', 2],
|
811
|
+
['(quotient 5 2)', 2],
|
812
|
+
['(quotient -5 2)', -2],
|
813
|
+
['(quotient 5 -2)', -2],
|
814
|
+
['(quotient -5 -2)', 2]
|
815
|
+
]
|
816
|
+
compare_to_predicted(checks)
|
817
|
+
end
|
817
818
|
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
819
|
+
it 'should implement the truncate-remainder procedure' do
|
820
|
+
checks = [
|
821
|
+
['(truncate-remainder 5 2)', 1],
|
822
|
+
['(truncate-remainder -5 2)', -1],
|
823
|
+
['(truncate-remainder 5 -2)', 1],
|
824
|
+
['(truncate-remainder -5 -2)', -1],
|
825
|
+
['(remainder 5 2)', 1],
|
826
|
+
['(remainder -5 2)', -1],
|
827
|
+
['(remainder 5 -2)', 1],
|
828
|
+
['(remainder -5 -2)', -1]
|
829
|
+
]
|
830
|
+
compare_to_predicted(checks)
|
831
|
+
end
|
831
832
|
|
832
833
|
it 'should implement the test-equal procedure' do
|
833
834
|
checks = [
|
834
|
-
[
|
835
|
+
['(test-equal (cons 1 2) (cons 1 2))', true]
|
835
836
|
]
|
836
837
|
compare_to_predicted(checks)
|
837
838
|
end
|
838
839
|
end # context
|
839
|
-
|
840
|
+
|
840
841
|
context 'Input/output:' do
|
842
|
+
it 'should implement the include expression' do
|
843
|
+
initial_dir = Dir.pwd
|
844
|
+
filedir = File.dirname(__FILE__)
|
845
|
+
Dir.chdir(filedir)
|
846
|
+
source = '(include "add4.skm")' # Path is assumed to be relative to pwd
|
847
|
+
result = subject.run(source)
|
848
|
+
expect(result.last).to eq(10)
|
849
|
+
Dir.chdir(initial_dir)
|
850
|
+
end
|
851
|
+
|
841
852
|
it 'should implement the newline procedure' do
|
842
853
|
default_stdout = $stdout
|
843
|
-
$stdout = StringIO.new
|
854
|
+
$stdout = StringIO.new
|
844
855
|
subject.run('(newline) (newline) (newline)')
|
845
856
|
expect($stdout.string).to match(/\n\n\n$/)
|
846
857
|
$stdout = default_stdout
|
@@ -895,7 +906,7 @@ SKEEM
|
|
895
906
|
SKEEM
|
896
907
|
result = subject.run(source)
|
897
908
|
expect(result).to eq([0, 1, 2, 3, 4])
|
898
|
-
|
909
|
+
|
899
910
|
source = <<-SKEEM
|
900
911
|
(let ((x '(1 3 5 7 9)))
|
901
912
|
(do (
|
@@ -904,8 +915,25 @@ SKEEM
|
|
904
915
|
((null? x) sum))) ; => 25
|
905
916
|
SKEEM
|
906
917
|
result = subject.run(source)
|
907
|
-
expect(result).to eq(25)
|
918
|
+
expect(result).to eq(25)
|
908
919
|
end
|
909
920
|
end # context
|
921
|
+
|
922
|
+
context 'Macro processing:' do
|
923
|
+
# it 'should parse macro expressions' do
|
924
|
+
# source = <<-SKEEM
|
925
|
+
# (define-syntax while
|
926
|
+
# (syntax-rules ()
|
927
|
+
# ((while condition body ...)
|
928
|
+
# (let loop ()
|
929
|
+
# (if condition
|
930
|
+
# (begin
|
931
|
+
# body ...
|
932
|
+
# (loop))
|
933
|
+
# #f)))))
|
934
|
+
# SKEEM
|
935
|
+
# ptree = subject.parse(source)
|
936
|
+
# end
|
937
|
+
end
|
910
938
|
end # describe
|
911
|
-
end # module
|
939
|
+
end # module
|
data/spec/skeem/lambda_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../spec_helper' # Use the RSpec framework
|
2
4
|
|
3
5
|
# Load the class under test
|
@@ -75,13 +77,13 @@ SKEEM
|
|
75
77
|
|
76
78
|
expect(result.last).to eq(136)
|
77
79
|
end
|
78
|
-
|
80
|
+
|
79
81
|
it 'should accept calls to anonymous procedures' do
|
80
82
|
source = '((lambda (x) (+ x x)) 4)'
|
81
83
|
result = subject.run(source)
|
82
84
|
expect(result).to eq(8)
|
83
85
|
end
|
84
|
-
|
86
|
+
|
85
87
|
it 'should accept unary second-order lambdas' do
|
86
88
|
source = <<-SKEEM
|
87
89
|
(define add-with
|
@@ -94,10 +96,10 @@ SKEEM
|
|
94
96
|
expect(result).to eq(7)
|
95
97
|
end
|
96
98
|
end # context
|
97
|
-
|
99
|
+
|
98
100
|
context 'More advanced features:' do
|
99
101
|
subject { Interpreter.new }
|
100
|
-
|
102
|
+
|
101
103
|
it 'should implement binary second-order functions' do
|
102
104
|
source = <<-SKEEM
|
103
105
|
(define compose
|
@@ -105,10 +107,10 @@ SKEEM
|
|
105
107
|
(lambda (x)
|
106
108
|
(f (g x)))))
|
107
109
|
SKEEM
|
108
|
-
|
110
|
+
subject.run(source)
|
109
111
|
result = subject.run('((compose list square) 5)')
|
110
112
|
expect(result.last).to eq(25)
|
111
|
-
end
|
113
|
+
end
|
112
114
|
end # context
|
113
115
|
end # describe
|
114
|
-
end # module
|
116
|
+
end # module
|
data/spec/skeem/parser_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../spec_helper' # Use the RSpec framework
|
2
4
|
require_relative '../../lib/skeem/tokenizer' # Load the class under test
|
3
5
|
|
@@ -5,7 +7,7 @@ module Skeem
|
|
5
7
|
describe Parser do
|
6
8
|
context 'Initialization:' do
|
7
9
|
it 'should be initialized without argument' do
|
8
|
-
expect { Parser.new
|
10
|
+
expect { Parser.new }.not_to raise_error
|
9
11
|
end
|
10
12
|
|
11
13
|
it 'should have its parse engine initialized' do
|
@@ -16,11 +18,11 @@ module Skeem
|
|
16
18
|
context 'Parsing literals:' do
|
17
19
|
it 'should parse isolated booleans' do
|
18
20
|
samples = [
|
19
|
-
|
21
|
+
['#f', false]
|
20
22
|
# ['#false', false],
|
21
23
|
# ['#t', true],
|
22
24
|
# ['#true', true]
|
23
|
-
|
25
|
+
]
|
24
26
|
samples.each do |source, predicted|
|
25
27
|
ptree = subject.parse(source)
|
26
28
|
expect(ptree.root).to be_kind_of(SkmBoolean)
|
@@ -30,12 +32,12 @@ module Skeem
|
|
30
32
|
|
31
33
|
it 'should parse isolated integers' do
|
32
34
|
samples = [
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
['0', 0],
|
36
|
+
['3', 3],
|
37
|
+
['-3', -3],
|
38
|
+
['+12345', 12345],
|
39
|
+
['-12345', -12345]
|
40
|
+
]
|
39
41
|
samples.each do |source, predicted|
|
40
42
|
ptree = subject.parse(source)
|
41
43
|
expect(ptree.root).to be_kind_of(SkmInteger)
|
@@ -45,12 +47,12 @@ module Skeem
|
|
45
47
|
|
46
48
|
it 'should parse isolated real numbers' do
|
47
49
|
samples = [
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
['0.0', 0.0],
|
51
|
+
['3.14', 3.14],
|
52
|
+
['-3.14', -3.14],
|
53
|
+
['+123e+45', 123e+45],
|
54
|
+
['-123e-45', -123e-45]
|
55
|
+
]
|
54
56
|
samples.each do |source, predicted|
|
55
57
|
ptree = subject.parse(source)
|
56
58
|
expect(ptree.root).to be_kind_of(SkmReal)
|
@@ -60,8 +62,8 @@ module Skeem
|
|
60
62
|
|
61
63
|
it 'should parse isolated strings' do
|
62
64
|
samples = [
|
63
|
-
|
64
|
-
|
65
|
+
['"Hello world!"', 'Hello world!']
|
66
|
+
]
|
65
67
|
samples.each do |source, predicted|
|
66
68
|
ptree = subject.parse(source)
|
67
69
|
expect(ptree.root).to be_kind_of(SkmString)
|
@@ -71,8 +73,8 @@ module Skeem
|
|
71
73
|
|
72
74
|
it 'should parse isolated identifiers' do
|
73
75
|
samples = [
|
74
|
-
|
75
|
-
|
76
|
+
%w[the-word-recursion-has-many-meanings the-word-recursion-has-many-meanings]
|
77
|
+
]
|
76
78
|
samples.each do |source, predicted|
|
77
79
|
ptree = subject.parse(source)
|
78
80
|
expect(ptree.root).to be_kind_of(SkmVariableReference)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../../spec_helper' # Use the RSpec framework
|
2
4
|
|
3
5
|
# Load the class under test
|
@@ -41,8 +43,8 @@ SKEEM
|
|
41
43
|
['(+)', 0], # '+' as nullary operator. Example from section 6.2.6
|
42
44
|
['(+ -3)', -3], # '+' as unary operator
|
43
45
|
['(+ 3 4)', 7], # '+' as binary operator. Example from section 4.1.3
|
44
|
-
['(+ 1/2 2/3)', Rational(7,6)],
|
45
|
-
['(+ 1/2 3)', Rational(7,2)],
|
46
|
+
['(+ 1/2 2/3)', Rational(7, 6)],
|
47
|
+
['(+ 1/2 3)', Rational(7, 2)],
|
46
48
|
['(+ 2 2.34)', 4.34]
|
47
49
|
]
|
48
50
|
compare_to_predicted(checks)
|
@@ -219,7 +221,7 @@ SKEEM
|
|
219
221
|
["(equal? (make-vector 5 'a) (make-vector 5 'a))", true],
|
220
222
|
['(equal? car car)', true],
|
221
223
|
['(equal? car cdr)', false],
|
222
|
-
['(equal? (lambda (x) x) (lambda (y) y))', false]
|
224
|
+
['(equal? (lambda (x) x) (lambda (y) y))', false]
|
223
225
|
]
|
224
226
|
compare_to_predicted(checks) do |result, expectation|
|
225
227
|
if result.length > 1
|
@@ -355,7 +357,7 @@ SKEEM
|
|
355
357
|
['(integer? "3")', false],
|
356
358
|
['(integer? #t)', false]
|
357
359
|
]
|
358
|
-
|
360
|
+
compare_to_predicted(checks)
|
359
361
|
end
|
360
362
|
|
361
363
|
it 'should implement the number->string procedure' do
|
@@ -396,7 +398,7 @@ SKEEM
|
|
396
398
|
['(or)', false],
|
397
399
|
['(or #f)', false],
|
398
400
|
['(or #f #t)', true],
|
399
|
-
['(or #f #f #f)', false]
|
401
|
+
['(or #f #f #f)', false]
|
400
402
|
|
401
403
|
]
|
402
404
|
compare_to_predicted(checks)
|
@@ -485,11 +487,11 @@ SKEEM
|
|
485
487
|
compare_to_predicted(checks)
|
486
488
|
end
|
487
489
|
|
488
|
-
|
490
|
+
it 'should implement the string-length procedure' do
|
489
491
|
checks = [
|
490
492
|
['(string-length "abc")', 3],
|
491
493
|
['(string-length "")', 0],
|
492
|
-
['(string-length "hi there")', 8]
|
494
|
+
['(string-length "hi there")', 8]
|
493
495
|
]
|
494
496
|
compare_to_predicted(checks)
|
495
497
|
end
|
@@ -544,7 +546,7 @@ SKEEM
|
|
544
546
|
compare_to_predicted(checks)
|
545
547
|
end
|
546
548
|
|
547
|
-
|
549
|
+
it 'should implement the null? procedure' do
|
548
550
|
checks = [
|
549
551
|
['(null? #f)', false],
|
550
552
|
['(null? 1)', false],
|
@@ -591,7 +593,7 @@ SKEEM
|
|
591
593
|
example = "(cons '(a b) 'c)" # => ((a b) . c)
|
592
594
|
result = subject.run(example)
|
593
595
|
expect(result.car).to be_kind_of(SkmPair)
|
594
|
-
expect(result.car.to_a).to eq([
|
596
|
+
expect(result.car.to_a).to eq(%w[a b])
|
595
597
|
expect(result.cdr).to be_kind_of(SkmIdentifier)
|
596
598
|
expect(result.cdr).to eq('c')
|
597
599
|
end
|
@@ -616,21 +618,21 @@ SKEEM
|
|
616
618
|
result = subject.run(example)
|
617
619
|
expect(result).to be_list
|
618
620
|
expect(result.length).to eq(3)
|
619
|
-
expect(result.to_a).to eq([
|
621
|
+
expect(result.to_a).to eq(%w[b c d])
|
620
622
|
|
621
623
|
expect_expr("(cdr '(1 . 2))").to eq(2)
|
622
624
|
|
623
625
|
example = "(cdr '())" # => error
|
624
626
|
expect { subject.run(example) }.to raise_error(StandardError)
|
625
627
|
end
|
626
|
-
|
628
|
+
|
627
629
|
it 'should implement the length procedure' do
|
628
630
|
example = '(make-list 2 3)'
|
629
631
|
result = subject.run(example)
|
630
632
|
expect(result).to be_list
|
631
633
|
expect(result.length).to eq(2)
|
632
634
|
expect(result.to_a).to eq([3, 3])
|
633
|
-
end
|
635
|
+
end
|
634
636
|
|
635
637
|
it 'should implement the length procedure' do
|
636
638
|
checks = [
|
@@ -638,23 +640,23 @@ SKEEM
|
|
638
640
|
["(length '(1))", 1],
|
639
641
|
["(length '(1 2))", 2],
|
640
642
|
["(length '(1 2 3))", 3],
|
641
|
-
|
643
|
+
["(length '(a (b) (c d e)))", 3]
|
642
644
|
]
|
643
645
|
compare_to_predicted(checks)
|
644
646
|
end
|
645
647
|
|
646
648
|
it 'should implement the append procedure' do
|
647
649
|
checks = [
|
648
|
-
["(append '(a b c) '())", array2list_ids([
|
649
|
-
["(append '() '(a b c))", array2list_ids([
|
650
|
-
["(append '(x) '(y))", array2list_ids([
|
651
|
-
["(append '(a) '(b c d))", array2list_ids([
|
652
|
-
["(append '(a b) '(c d))", array2list_ids([
|
653
|
-
["(append '(a b) '(c) 'd)", array2list_ids([
|
650
|
+
["(append '(a b c) '())", array2list_ids(%w[a b c])],
|
651
|
+
["(append '() '(a b c))", array2list_ids(%w[a b c])],
|
652
|
+
["(append '(x) '(y))", array2list_ids(%w[x y])],
|
653
|
+
["(append '(a) '(b c d))", array2list_ids(%w[a b c d])],
|
654
|
+
["(append '(a b) '(c d))", array2list_ids(%w[a b c d])],
|
655
|
+
["(append '(a b) '(c) 'd)", array2list_ids(%w[a b c d])],
|
654
656
|
["(append '(a (b)) '((c)))", [SkmIdentifier.create('a'),
|
655
|
-
|
656
|
-
|
657
|
-
[
|
657
|
+
SkmPair.create_from_a(array2list_ids(['b'])),
|
658
|
+
SkmPair.create_from_a(array2list_ids(['c']))]],
|
659
|
+
["(append '() 'a)", SkmIdentifier.create('a')]
|
658
660
|
]
|
659
661
|
compare_to_predicted(checks) do |result, expectation|
|
660
662
|
if result.kind_of?(SkmPair)
|
@@ -667,18 +669,18 @@ SKEEM
|
|
667
669
|
|
668
670
|
it 'should implement the procedure for an improper list' do
|
669
671
|
result = subject.run("(append '(a b) '(c . d))")
|
670
|
-
expect(result.car).to eq(
|
671
|
-
expect(result.cdr.car).to eq(
|
672
|
-
expect(result.cdr.cdr.car).to eq(
|
673
|
-
expect(result.cdr.cdr.cdr).to eq(
|
672
|
+
expect(result.car).to eq(SkmIdentifier.create('a'))
|
673
|
+
expect(result.cdr.car).to eq(SkmIdentifier.create('b'))
|
674
|
+
expect(result.cdr.cdr.car).to eq(SkmIdentifier.create('c'))
|
675
|
+
expect(result.cdr.cdr.cdr).to eq(SkmIdentifier.create('d'))
|
674
676
|
end
|
675
677
|
|
676
678
|
|
677
679
|
it 'should implement the reverse procedure' do
|
678
680
|
checks = [
|
679
681
|
["(reverse '())", SkmEmptyList.instance],
|
680
|
-
["(reverse '(a b c))", array2list_ids([
|
681
|
-
["(reverse '((a) b c))", array2list_ids([
|
682
|
+
["(reverse '(a b c))", array2list_ids(%w[c b a])],
|
683
|
+
["(reverse '((a) b c))", array2list_ids(%w[c b]) << SkmPair.new(SkmIdentifier.create('a'), nil)]
|
682
684
|
]
|
683
685
|
compare_to_predicted(checks) do |result, expectation|
|
684
686
|
if result.kind_of?(SkmPair)
|
@@ -692,7 +694,7 @@ SKEEM
|
|
692
694
|
it 'should implement the list->vector procedure' do
|
693
695
|
checks = [
|
694
696
|
["(list->vector '())", []],
|
695
|
-
["(list->vector '(a b c))", [
|
697
|
+
["(list->vector '(a b c))", %w[a b c]]
|
696
698
|
]
|
697
699
|
compare_to_predicted(checks) do |result, expectation|
|
698
700
|
expect(result.to_a).to eq(expectation)
|
@@ -700,7 +702,7 @@ SKEEM
|
|
700
702
|
end
|
701
703
|
|
702
704
|
it 'should implement the set-car! procedure' do
|
703
|
-
source
|
705
|
+
source = <<-SKEEM
|
704
706
|
(define x '(a b c))
|
705
707
|
(set-car! x 1)
|
706
708
|
x
|
@@ -710,7 +712,7 @@ SKEEM
|
|
710
712
|
end
|
711
713
|
|
712
714
|
it 'should implement the set-cdr! procedure' do
|
713
|
-
source
|
715
|
+
source = <<-SKEEM
|
714
716
|
(define x '(a b c))
|
715
717
|
(set-cdr! x 1)
|
716
718
|
x
|
@@ -744,13 +746,13 @@ SKEEM
|
|
744
746
|
it 'should implement the list-copy procedure' do
|
745
747
|
checks = [
|
746
748
|
["(list-copy '())", []],
|
747
|
-
["(list-copy '(a b c))", [
|
749
|
+
["(list-copy '(a b c))", %w[a b c]]
|
748
750
|
]
|
749
751
|
compare_to_predicted(checks) do |result, expectation|
|
750
752
|
expect(result.to_a).to eq(expectation)
|
751
753
|
end
|
752
754
|
|
753
|
-
source
|
755
|
+
source = <<-SKEEM
|
754
756
|
(define a '(1 8 2 8)) ; a may be immutable
|
755
757
|
(define b (list-copy a))
|
756
758
|
(set-car! b 3) ; b is mutable
|
@@ -894,7 +896,7 @@ SKEEM
|
|
894
896
|
checks = [
|
895
897
|
['(vector-length (make-vector 0))', 0],
|
896
898
|
["(vector-length (make-vector 0 'a))", 0],
|
897
|
-
["(equal? (make-vector 5 'a) '#(a a a a a))", true]
|
899
|
+
["(equal? (make-vector 5 'a) '#(a a a a a))", true]
|
898
900
|
]
|
899
901
|
compare_to_predicted(checks)
|
900
902
|
end
|
@@ -907,21 +909,21 @@ SKEEM
|
|
907
909
|
end
|
908
910
|
|
909
911
|
it 'should implement the vector-set! procedure' do
|
910
|
-
source
|
912
|
+
source = <<-SKEEM
|
911
913
|
(let
|
912
914
|
((vec (vector 0 '(2 2 2 2) "Anna")))
|
913
915
|
(vector-set! vec 1 '("Sue" "Sue"))
|
914
916
|
vec)
|
915
917
|
SKEEM
|
916
|
-
#(0 ("Sue" "Sue") "Anna")
|
918
|
+
# (0 ("Sue" "Sue") "Anna")
|
917
919
|
result = subject.run(source)
|
918
920
|
expect(result).to be_kind_of(SkmVector)
|
919
921
|
expectation = [SkmInteger.create(0),
|
920
|
-
|
921
|
-
|
922
|
+
SkmPair.new(SkmString.create('Sue'), SkmPair.new(SkmString.create('Sue'), SkmEmptyList.instance)),
|
923
|
+
SkmString.create('Anna')]
|
922
924
|
expect(result).to eq(expectation)
|
923
925
|
|
924
|
-
source
|
926
|
+
source = <<-SKEEM
|
925
927
|
(let (
|
926
928
|
(v (vector 'a 'b 'c 'd 'e)))
|
927
929
|
(vector-set! v 2 'x)
|
@@ -929,13 +931,13 @@ SKEEM
|
|
929
931
|
SKEEM
|
930
932
|
result = subject.run(source)
|
931
933
|
expect(result).to be_kind_of(SkmVector)
|
932
|
-
expect(result).to eq(array2list_ids([
|
934
|
+
expect(result).to eq(array2list_ids(%w[a b x d e]))
|
933
935
|
end
|
934
936
|
|
935
937
|
it 'should implement the vector->list procedure' do
|
936
938
|
checks = [
|
937
|
-
[
|
938
|
-
["(vector->list '#(a b c))", [
|
939
|
+
['(vector->list #())', []],
|
940
|
+
["(vector->list '#(a b c))", %w[a b c]]
|
939
941
|
]
|
940
942
|
compare_to_predicted(checks) do |result, expectation|
|
941
943
|
expect(result.to_a).to eq(expectation)
|
@@ -946,9 +948,9 @@ SKEEM
|
|
946
948
|
context 'Control procedures:' do
|
947
949
|
it 'should implement the procedure? predicate' do
|
948
950
|
checks = [
|
949
|
-
[
|
951
|
+
['(procedure? car)', true],
|
950
952
|
["(procedure? 'car)", false],
|
951
|
-
[
|
953
|
+
['(procedure? (lambda (x) (* x x)))', true]
|
952
954
|
# ["(procedure? '(lambda (x) (* x x)))", false] # Parse fail: non-standard syntax
|
953
955
|
]
|
954
956
|
compare_to_predicted(checks)
|
@@ -963,7 +965,7 @@ SKEEM
|
|
963
965
|
|
964
966
|
it 'should implement the map procedure' do
|
965
967
|
checks = [
|
966
|
-
["(map car '((a b) (d e) (g h)))", [
|
968
|
+
["(map car '((a b) (d e) (g h)))", %w[a d g]],
|
967
969
|
["(map + '(1 2 3) '(4 5 6 7))", [5, 7, 9]]
|
968
970
|
]
|
969
971
|
compare_to_predicted(checks) do |result, expectation|
|
@@ -975,7 +977,7 @@ SKEEM
|
|
975
977
|
context 'IO procedures:' do
|
976
978
|
it 'should implement the display procedure' do
|
977
979
|
default_stdout = $stdout
|
978
|
-
$stdout = StringIO.new
|
980
|
+
$stdout = StringIO.new
|
979
981
|
subject.run('(display "Hello")')
|
980
982
|
expect($stdout.string).to eq('Hello')
|
981
983
|
$stdout = default_stdout
|
@@ -983,6 +985,13 @@ SKEEM
|
|
983
985
|
end # context
|
984
986
|
|
985
987
|
context 'Miscellaneous procedures' do
|
988
|
+
it 'should raise an exception with given error message' do
|
989
|
+
source = '(error "This is an error message")'
|
990
|
+
err = SkmError
|
991
|
+
msg = 'This is an error message'
|
992
|
+
expect { subject.run(source) }.to raise_error(err, msg)
|
993
|
+
end
|
994
|
+
|
986
995
|
it 'should return true when an assertion succeeds' do
|
987
996
|
source = <<-SKEEM
|
988
997
|
(define x 2)
|
@@ -1001,9 +1010,9 @@ SKEEM
|
|
1001
1010
|
err = StandardError
|
1002
1011
|
msg1 = 'Error: assertion failed on line 3, column 4'
|
1003
1012
|
msg2 = 'with <Skeem::SkmBoolean: false>'
|
1004
|
-
expect { subject.run(source) }.to raise_error(err, msg1 + ', '+ msg2)
|
1013
|
+
expect { subject.run(source) }.to raise_error(err, msg1 + ', ' + msg2)
|
1005
1014
|
end
|
1006
1015
|
end # context
|
1007
1016
|
end # describe
|
1008
1017
|
end # module
|
1009
|
-
end # module
|
1018
|
+
end # module
|