skeem 0.2.15 → 0.2.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +17 -11
  3. data/CHANGELOG.md +5 -0
  4. data/Gemfile +2 -0
  5. data/README.md +3 -2
  6. data/Rakefile +2 -0
  7. data/appveyor.yml +3 -4
  8. data/bin/skeem +15 -15
  9. data/lib/skeem.rb +2 -0
  10. data/lib/skeem/datum_dsl.rb +12 -3
  11. data/lib/skeem/element_visitor.rb +5 -2
  12. data/lib/skeem/grammar.rb +86 -24
  13. data/lib/skeem/interpreter.rb +5 -3
  14. data/lib/skeem/parser.rb +6 -4
  15. data/lib/skeem/primitive/primitive_builder.rb +128 -115
  16. data/lib/skeem/primitive/primitive_procedure.rb +17 -20
  17. data/lib/skeem/runtime.rb +9 -5
  18. data/lib/skeem/s_expr_builder.rb +46 -104
  19. data/lib/skeem/s_expr_nodes.rb +116 -90
  20. data/lib/skeem/skeem_exception.rb +0 -0
  21. data/lib/skeem/skm_binding.rb +6 -7
  22. data/lib/skeem/skm_compound_datum.rb +8 -4
  23. data/lib/skeem/skm_element.rb +14 -12
  24. data/lib/skeem/skm_empty_list.rb +6 -4
  25. data/lib/skeem/skm_exception.rb +9 -0
  26. data/lib/skeem/skm_expression.rb +3 -1
  27. data/lib/skeem/skm_frame.rb +3 -2
  28. data/lib/skeem/skm_pair.rb +23 -18
  29. data/lib/skeem/skm_procedure_exec.rb +8 -6
  30. data/lib/skeem/skm_simple_datum.rb +13 -12
  31. data/lib/skeem/skm_unary_expression.rb +15 -17
  32. data/lib/skeem/tokenizer.rb +32 -25
  33. data/lib/skeem/version.rb +3 -1
  34. data/skeem.gemspec +6 -4
  35. data/spec/skeem/add4.skm +4 -0
  36. data/spec/skeem/datum_dsl_spec.rb +13 -12
  37. data/spec/skeem/element_visitor_spec.rb +12 -10
  38. data/spec/skeem/interpreter_spec.rb +74 -46
  39. data/spec/skeem/lambda_spec.rb +9 -7
  40. data/spec/skeem/parser_spec.rb +21 -19
  41. data/spec/skeem/primitive/primitive_builder_spec.rb +57 -48
  42. data/spec/skeem/primitive/primitive_procedure_spec.rb +15 -13
  43. data/spec/skeem/runtime_spec.rb +18 -16
  44. data/spec/skeem/s_expr_nodes_spec.rb +8 -6
  45. data/spec/skeem/skm_compound_datum_spec.rb +11 -9
  46. data/spec/skeem/skm_element_spec.rb +7 -5
  47. data/spec/skeem/skm_empty_list_spec.rb +7 -5
  48. data/spec/skeem/skm_frame_spec.rb +5 -4
  49. data/spec/skeem/skm_pair_spec.rb +4 -3
  50. data/spec/skeem/skm_procedure_exec_spec.rb +2 -0
  51. data/spec/skeem/skm_simple_datum_spec.rb +24 -22
  52. data/spec/skeem/skm_unary_expression_spec.rb +11 -9
  53. data/spec/skeem/tokenizer_spec.rb +53 -44
  54. data/spec/skeem_spec.rb +2 -0
  55. data/spec/spec_helper.rb +4 -2
  56. 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| } }.not_to raise_error
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
- result = subject.run('(define x 28)')
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
- checks = [
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
- result = subject.run(source)
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
- result = subject.run(source)
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
- result = subject.run(source)
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
- checks = [
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 =<<-SKEEM
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
- checks = [
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
- it 'should implement the truncate-quotient procedure' do
805
- checks = [
806
- ['(truncate-quotient 5 2)', 2],
807
- ['(truncate-quotient -5 2)', -2],
808
- ['(truncate-quotient 5 -2)', -2],
809
- ['(truncate-quotient -5 -2)', 2],
810
- ['(quotient 5 2)', 2],
811
- ['(quotient -5 2)', -2],
812
- ['(quotient 5 -2)', -2],
813
- ['(quotient -5 -2)', 2]
814
- ]
815
- compare_to_predicted(checks)
816
- end
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
- it 'should implement the truncate-remainder procedure' do
819
- checks = [
820
- ['(truncate-remainder 5 2)', 1],
821
- ['(truncate-remainder -5 2)', -1],
822
- ['(truncate-remainder 5 -2)', 1],
823
- ['(truncate-remainder -5 -2)', -1],
824
- ['(remainder 5 2)', 1],
825
- ['(remainder -5 2)', -1],
826
- ['(remainder 5 -2)', 1],
827
- ['(remainder -5 -2)', -1]
828
- ]
829
- compare_to_predicted(checks)
830
- end
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
- ["(test-equal (cons 1 2) (cons 1 2))", true]
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
@@ -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
- result = subject.run(source)
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
@@ -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() }.not_to raise_error
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
- ['#f', false],
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
- ['0', 0],
34
- ['3', 3],
35
- ['-3', -3],
36
- ['+12345', 12345],
37
- ['-12345', -12345]
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
- ['0.0', 0.0],
49
- ['3.14', 3.14],
50
- ['-3.14', -3.14],
51
- ['+123e+45', 123e+45],
52
- ['-123e-45', -123e-45]
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
- ['"Hello world!"', 'Hello world!']
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
- ['the-word-recursion-has-many-meanings', 'the-word-recursion-has-many-meanings']
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
- compare_to_predicted(checks)
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
- it 'should implement the string-length procedure' do
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
- it 'should implement the null? procedure' do
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(['a', 'b'])
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(['b', 'c', 'd'])
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
- ["(length '(a (b) (c d e)))", 3]
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(['a', 'b', 'c'])],
649
- ["(append '() '(a b c))", array2list_ids(['a', 'b', 'c'])],
650
- ["(append '(x) '(y))", array2list_ids(['x', 'y'])],
651
- ["(append '(a) '(b c d))", array2list_ids(['a', 'b', 'c', 'd'])],
652
- ["(append '(a b) '(c d))", array2list_ids(['a', 'b', 'c', 'd'])],
653
- ["(append '(a b) '(c) 'd)", array2list_ids(['a', 'b', 'c', 'd'])],
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
- SkmPair.create_from_a(array2list_ids(['b'])),
656
- SkmPair.create_from_a(array2list_ids(['c']))]],
657
- [ "(append '() 'a)", SkmIdentifier.create('a')]
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( SkmIdentifier.create('a'))
671
- expect(result.cdr.car).to eq( SkmIdentifier.create('b'))
672
- expect(result.cdr.cdr.car).to eq( SkmIdentifier.create('c'))
673
- expect(result.cdr.cdr.cdr).to eq( SkmIdentifier.create('d'))
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(['c', 'b', 'a'])],
681
- ["(reverse '((a) b c))", array2list_ids(['c', 'b']) << SkmPair.new(SkmIdentifier.create('a'), nil)]
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))", ['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 =<<-SKEEM
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 =<<-SKEEM
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))", ['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 =<<-SKEEM
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 =<<-SKEEM
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
- SkmPair.new(SkmString.create("Sue"), SkmPair.new(SkmString.create("Sue"), SkmEmptyList.instance)),
921
- SkmString.create("Anna") ]
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 =<<-SKEEM
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(['a', 'b', 'x', 'd', 'e']))
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
- ["(vector->list #())", []],
938
- ["(vector->list '#(a b c))", ['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
- ["(procedure? car)", true],
951
+ ['(procedure? car)', true],
950
952
  ["(procedure? 'car)", false],
951
- ["(procedure? (lambda (x) (* x x)))", true],
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)))", ['a', 'd', 'g']],
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