skeem 0.2.15 → 0.2.16

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