skeem 0.2.15 → 0.2.19
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +451 -195
- data/.travis.yml +27 -0
- data/CHANGELOG.md +26 -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/datum_dsl.rb +40 -30
- data/lib/skeem/element_visitor.rb +5 -2
- data/lib/skeem/grammar.rb +77 -54
- data/lib/skeem/interpreter.rb +9 -7
- data/lib/skeem/parser.rb +6 -4
- data/lib/skeem/primitive/primitive_builder.rb +130 -122
- data/lib/skeem/primitive/primitive_procedure.rb +23 -25
- data/lib/skeem/runtime.rb +17 -15
- data/lib/skeem/s_expr_builder.rb +39 -147
- data/lib/skeem/s_expr_nodes.rb +147 -132
- data/lib/skeem/skeem_exception.rb +1 -0
- data/lib/skeem/skm_binding.rb +9 -11
- data/lib/skeem/skm_compound_datum.rb +9 -6
- data/lib/skeem/skm_element.rb +15 -13
- 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 +26 -18
- data/lib/skeem/skm_procedure_exec.rb +11 -6
- data/lib/skeem/skm_simple_datum.rb +23 -20
- data/lib/skeem/skm_unary_expression.rb +34 -37
- data/lib/skeem/tokenizer.rb +40 -30
- data/lib/skeem/version.rb +3 -1
- data/lib/skeem.rb +2 -0
- data/skeem.gemspec +7 -5
- data/spec/skeem/add4.skm +4 -0
- data/spec/skeem/datum_dsl_spec.rb +13 -12
- data/spec/skeem/element_visitor_spec.rb +14 -10
- data/spec/skeem/interpreter_spec.rb +76 -46
- data/spec/skeem/lambda_spec.rb +13 -11
- data/spec/skeem/parser_spec.rb +23 -19
- data/spec/skeem/primitive/primitive_builder_spec.rb +55 -46
- data/spec/skeem/primitive/primitive_procedure_spec.rb +14 -12
- data/spec/skeem/runtime_spec.rb +20 -18
- data/spec/skeem/s_expr_nodes_spec.rb +8 -6
- data/spec/skeem/skm_compound_datum_spec.rb +12 -10
- 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 +9 -8
- 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 +54 -43
- data/spec/skeem_spec.rb +2 -0
- data/spec/spec_helper.rb +15 -10
- metadata +13 -9
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../spec_helper'
|
2
4
|
require_relative '../../lib/skeem/datum_dsl'
|
3
5
|
|
@@ -7,12 +9,14 @@ require_relative '../../lib/skeem/element_visitor'
|
|
7
9
|
module Skeem
|
8
10
|
describe SkmElementVisitor do
|
9
11
|
include DatumDSL
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
let(:simple_datum) { integer 42 }
|
13
|
+
let(:listener) do
|
14
|
+
fake = double('fake-subscriber')
|
15
|
+
fake.define_singleton_method(:accept_all) do
|
16
|
+
# Dummy block
|
17
|
+
end
|
18
|
+
fake
|
19
|
+
end
|
16
20
|
|
17
21
|
# Default instantiation rule
|
18
22
|
subject { SkmElementVisitor.new(simple_datum) }
|
@@ -122,7 +126,7 @@ module Skeem
|
|
122
126
|
end
|
123
127
|
|
124
128
|
it 'should allow the visit of a nested compound datum' do
|
125
|
-
nested_list = list [
|
129
|
+
nested_list = list %w[uno twei three']
|
126
130
|
vec = vector ['#false', 3, nested_list, 'foo']
|
127
131
|
instance = SkmElementVisitor.new(vec)
|
128
132
|
instance.subscribe(listener)
|
@@ -132,7 +136,7 @@ module Skeem
|
|
132
136
|
expect(listener).to receive(:after_simple_datum).with(runtime, vec.members[0]).ordered
|
133
137
|
expect(listener).to receive(:before_simple_datum).with(runtime, vec.members[1]).ordered
|
134
138
|
expect(listener).to receive(:after_simple_datum).with(runtime, vec.members[1]).ordered
|
135
|
-
|
139
|
+
|
136
140
|
expect(listener).to receive(:before_pair).with(runtime, nested_list).ordered
|
137
141
|
expect(listener).to receive(:before_car).with(runtime, nested_list, nested_list.car).ordered
|
138
142
|
expect(nested_list.car).to eq('uno')
|
@@ -159,7 +163,7 @@ module Skeem
|
|
159
163
|
expect(listener).to receive(:after_cdr).with(runtime, nested_list.cdr, nested_list.cdr.cdr).ordered
|
160
164
|
expect(listener).to receive(:after_pair).with(runtime, nested_list.cdr).ordered
|
161
165
|
expect(listener).to receive(:after_cdr).with(runtime, nested_list, nested_list.cdr).ordered
|
162
|
-
expect(listener).to receive(:after_pair).with(runtime, nested_list).ordered
|
166
|
+
expect(listener).to receive(:after_pair).with(runtime, nested_list).ordered
|
163
167
|
expect(listener).to receive(:before_simple_datum).with(runtime, vec.members[3]).ordered
|
164
168
|
expect(listener).to receive(:after_simple_datum).with(runtime, vec.members[3]).ordered
|
165
169
|
expect(listener).to receive(:after_children).with(runtime, vec, vec.members).ordered
|
@@ -168,4 +172,4 @@ module Skeem
|
|
168
172
|
end
|
169
173
|
end # context
|
170
174
|
end # describe
|
171
|
-
end # module
|
175
|
+
end # module
|
@@ -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
|
19
|
+
expect { Interpreter.new(&:runtime) }.not_to raise_error
|
18
20
|
end
|
19
21
|
|
20
22
|
it 'should have a parser' do
|
@@ -65,6 +67,7 @@ module Skeem
|
|
65
67
|
end
|
66
68
|
end
|
67
69
|
|
70
|
+
# rubocop: disable Style/ExponentialNotation
|
68
71
|
it 'should evaluate isolated real numbers' do
|
69
72
|
samples = [
|
70
73
|
['0.0', 0.0],
|
@@ -78,6 +81,7 @@ module Skeem
|
|
78
81
|
expect(result).to eq(predicted)
|
79
82
|
end
|
80
83
|
end
|
84
|
+
# rubocop: enable Style/ExponentialNotation
|
81
85
|
|
82
86
|
it 'should evaluate isolated strings' do
|
83
87
|
samples = [
|
@@ -90,6 +94,7 @@ module Skeem
|
|
90
94
|
end
|
91
95
|
|
92
96
|
it 'should evaluate vector of constants' do
|
97
|
+
require 'benchmark'
|
93
98
|
source = '#(2018 10 20 "Sat")'
|
94
99
|
result = subject.run(source)
|
95
100
|
expect(result).to be_kind_of(SkmVector)
|
@@ -108,7 +113,7 @@ module Skeem
|
|
108
113
|
|
109
114
|
context 'Built-in primitives' do
|
110
115
|
it 'should implement variable definition' do
|
111
|
-
|
116
|
+
subject.run('(define x 28)')
|
112
117
|
expect(subject.fetch('x')).to eq(28)
|
113
118
|
end
|
114
119
|
|
@@ -125,7 +130,7 @@ SKEEM
|
|
125
130
|
end
|
126
131
|
|
127
132
|
it 'should implement the simple conditional form' do
|
128
|
-
|
133
|
+
checks = [
|
129
134
|
['(if (> 3 2) "yes")', 'yes'],
|
130
135
|
['(if (> 2 3) "yes")', SkmUndefined.instance]
|
131
136
|
]
|
@@ -157,7 +162,7 @@ SKEEM
|
|
157
162
|
((< x 0) -1)
|
158
163
|
)))
|
159
164
|
SKEEM
|
160
|
-
|
165
|
+
subject.run(source)
|
161
166
|
checks = [
|
162
167
|
['(signum 3)', 1],
|
163
168
|
['(signum 0)', 0],
|
@@ -175,7 +180,7 @@ SKEEM
|
|
175
180
|
((< x 0) => -1)
|
176
181
|
)))
|
177
182
|
SKEEM
|
178
|
-
|
183
|
+
subject.run(source)
|
179
184
|
checks = [
|
180
185
|
['(signum 3)', 1],
|
181
186
|
['(signum 0)', 0],
|
@@ -193,7 +198,7 @@ SKEEM
|
|
193
198
|
(else -1)
|
194
199
|
)))
|
195
200
|
SKEEM
|
196
|
-
|
201
|
+
subject.run(source)
|
197
202
|
checks = [
|
198
203
|
['(signum 3)', 1],
|
199
204
|
['(signum 0)', 0],
|
@@ -211,7 +216,7 @@ SKEEM
|
|
211
216
|
end
|
212
217
|
|
213
218
|
it 'should implement the quotation of constant literals' do
|
214
|
-
|
219
|
+
checks = [
|
215
220
|
['(quote a)', 'a'],
|
216
221
|
['(quote 145932)', 145932],
|
217
222
|
['(quote "abc")', 'abc'],
|
@@ -367,8 +372,6 @@ SKEEM
|
|
367
372
|
result = subject.run(source)
|
368
373
|
expect(result.last.value).to eq(20)
|
369
374
|
end
|
370
|
-
|
371
|
-
|
372
375
|
end # context
|
373
376
|
|
374
377
|
context 'Binding constructs:' do
|
@@ -406,7 +409,7 @@ SKEEM
|
|
406
409
|
end
|
407
410
|
|
408
411
|
it 'should support the nesting of a lambda in a let expression' do
|
409
|
-
source
|
412
|
+
source = <<-SKEEM
|
410
413
|
(define make-counter
|
411
414
|
(lambda ()
|
412
415
|
(let ((count 0))
|
@@ -477,7 +480,7 @@ SKEEM
|
|
477
480
|
|
478
481
|
context 'Quasiquotation:' do
|
479
482
|
it 'should implement the quasiquotation of constant literals' do
|
480
|
-
|
483
|
+
checks = [
|
481
484
|
['(quasiquote a)', 'a'],
|
482
485
|
['(quasiquote 145932)', 145932],
|
483
486
|
['(quasiquote "abc")', 'abc'],
|
@@ -518,7 +521,7 @@ SKEEM
|
|
518
521
|
expect(result.members[index]).to eq(value)
|
519
522
|
end
|
520
523
|
|
521
|
-
source =
|
524
|
+
source = '`#()'
|
522
525
|
result = subject.run(source)
|
523
526
|
expect(result).to be_kind_of(SkmVector)
|
524
527
|
expect(result).to be_empty
|
@@ -555,7 +558,7 @@ SKEEM
|
|
555
558
|
result = result.cdr
|
556
559
|
end
|
557
560
|
|
558
|
-
source =
|
561
|
+
source = '`()'
|
559
562
|
result = subject.run(source)
|
560
563
|
expect(result).to be_kind_of(SkmEmptyList)
|
561
564
|
expect(result).to be_null
|
@@ -576,7 +579,7 @@ SKEEM
|
|
576
579
|
result = result.cdr
|
577
580
|
end
|
578
581
|
|
579
|
-
source =
|
582
|
+
source = '`()'
|
580
583
|
result = subject.run(source)
|
581
584
|
expect(result).to be_kind_of(SkmEmptyList)
|
582
585
|
expect(result).to be_null
|
@@ -801,46 +804,56 @@ SKEEM
|
|
801
804
|
compare_to_predicted(checks)
|
802
805
|
end
|
803
806
|
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
807
|
+
it 'should implement the truncate-quotient procedure' do
|
808
|
+
checks = [
|
809
|
+
['(truncate-quotient 5 2)', 2],
|
810
|
+
['(truncate-quotient -5 2)', -2],
|
811
|
+
['(truncate-quotient 5 -2)', -2],
|
812
|
+
['(truncate-quotient -5 -2)', 2],
|
813
|
+
['(quotient 5 2)', 2],
|
814
|
+
['(quotient -5 2)', -2],
|
815
|
+
['(quotient 5 -2)', -2],
|
816
|
+
['(quotient -5 -2)', 2]
|
817
|
+
]
|
818
|
+
compare_to_predicted(checks)
|
819
|
+
end
|
817
820
|
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
821
|
+
it 'should implement the truncate-remainder procedure' do
|
822
|
+
checks = [
|
823
|
+
['(truncate-remainder 5 2)', 1],
|
824
|
+
['(truncate-remainder -5 2)', -1],
|
825
|
+
['(truncate-remainder 5 -2)', 1],
|
826
|
+
['(truncate-remainder -5 -2)', -1],
|
827
|
+
['(remainder 5 2)', 1],
|
828
|
+
['(remainder -5 2)', -1],
|
829
|
+
['(remainder 5 -2)', 1],
|
830
|
+
['(remainder -5 -2)', -1]
|
831
|
+
]
|
832
|
+
compare_to_predicted(checks)
|
833
|
+
end
|
831
834
|
|
832
835
|
it 'should implement the test-equal procedure' do
|
833
836
|
checks = [
|
834
|
-
[
|
837
|
+
['(test-equal (cons 1 2) (cons 1 2))', true]
|
835
838
|
]
|
836
839
|
compare_to_predicted(checks)
|
837
840
|
end
|
838
841
|
end # context
|
839
|
-
|
842
|
+
|
840
843
|
context 'Input/output:' do
|
844
|
+
it 'should implement the include expression' do
|
845
|
+
initial_dir = Dir.pwd
|
846
|
+
filedir = File.dirname(__FILE__)
|
847
|
+
Dir.chdir(filedir)
|
848
|
+
source = '(include "add4.skm")' # Path is assumed to be relative to pwd
|
849
|
+
result = subject.run(source)
|
850
|
+
expect(result.last).to eq(10)
|
851
|
+
Dir.chdir(initial_dir)
|
852
|
+
end
|
853
|
+
|
841
854
|
it 'should implement the newline procedure' do
|
842
855
|
default_stdout = $stdout
|
843
|
-
$stdout = StringIO.new
|
856
|
+
$stdout = StringIO.new
|
844
857
|
subject.run('(newline) (newline) (newline)')
|
845
858
|
expect($stdout.string).to match(/\n\n\n$/)
|
846
859
|
$stdout = default_stdout
|
@@ -895,7 +908,7 @@ SKEEM
|
|
895
908
|
SKEEM
|
896
909
|
result = subject.run(source)
|
897
910
|
expect(result).to eq([0, 1, 2, 3, 4])
|
898
|
-
|
911
|
+
|
899
912
|
source = <<-SKEEM
|
900
913
|
(let ((x '(1 3 5 7 9)))
|
901
914
|
(do (
|
@@ -904,8 +917,25 @@ SKEEM
|
|
904
917
|
((null? x) sum))) ; => 25
|
905
918
|
SKEEM
|
906
919
|
result = subject.run(source)
|
907
|
-
expect(result).to eq(25)
|
920
|
+
expect(result).to eq(25)
|
908
921
|
end
|
909
922
|
end # context
|
923
|
+
|
924
|
+
context 'Macro processing:' do
|
925
|
+
# it 'should parse macro expressions' do
|
926
|
+
# source = <<-SKEEM
|
927
|
+
# (define-syntax while
|
928
|
+
# (syntax-rules ()
|
929
|
+
# ((while condition body ...)
|
930
|
+
# (let loop ()
|
931
|
+
# (if condition
|
932
|
+
# (begin
|
933
|
+
# body ...
|
934
|
+
# (loop))
|
935
|
+
# #f)))))
|
936
|
+
# SKEEM
|
937
|
+
# ptree = subject.parse(source)
|
938
|
+
# end
|
939
|
+
end
|
910
940
|
end # describe
|
911
|
-
end # module
|
941
|
+
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
|
@@ -29,7 +31,7 @@ SKEEM
|
|
29
31
|
|
30
32
|
context 'Defining compound procedures:' do
|
31
33
|
it 'should accept the definition of simple procedure with arity 1' do
|
32
|
-
source = definition_set
|
34
|
+
source = "#{definition_set}\nsquare"
|
33
35
|
result = subject.run(source)
|
34
36
|
|
35
37
|
square = result.last
|
@@ -39,7 +41,7 @@ SKEEM
|
|
39
41
|
end
|
40
42
|
|
41
43
|
it 'should accept the definition of simple procedure with arity 2' do
|
42
|
-
source = definition_set
|
44
|
+
source = "#{definition_set}\nsum-of-squares"
|
43
45
|
result = subject.run(source)
|
44
46
|
|
45
47
|
square = result.last
|
@@ -63,25 +65,25 @@ SKEEM
|
|
63
65
|
end
|
64
66
|
|
65
67
|
it 'should support the call to a simple procedure with arity 2' do
|
66
|
-
source = definition_set
|
68
|
+
source = "#{definition_set}\n(sum-of-squares 3 4)"
|
67
69
|
result = subject.run(source)
|
68
70
|
|
69
71
|
expect(result.last).to eq(25)
|
70
72
|
end
|
71
73
|
|
72
74
|
it 'should support the call to a nested lambda procedure' do
|
73
|
-
source = definition_set
|
75
|
+
source = "#{definition_set}\n(f 5)"
|
74
76
|
result = subject.run(source)
|
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)
|
@@ -43,25 +45,27 @@ module Skeem
|
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
48
|
+
# rubocop: disable Style/ExponentialNotation
|
46
49
|
it 'should parse isolated real numbers' do
|
47
50
|
samples = [
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
['0.0', 0.0],
|
52
|
+
['3.14', 3.14],
|
53
|
+
['-3.14', -3.14],
|
54
|
+
['+123e+45', 123e+45],
|
55
|
+
['-123e-45', -123e-45]
|
56
|
+
]
|
54
57
|
samples.each do |source, predicted|
|
55
58
|
ptree = subject.parse(source)
|
56
59
|
expect(ptree.root).to be_kind_of(SkmReal)
|
57
60
|
expect(ptree.root.value).to eq(predicted)
|
58
61
|
end
|
59
62
|
end
|
63
|
+
# rubocop: enable Style/ExponentialNotation
|
60
64
|
|
61
65
|
it 'should parse isolated strings' do
|
62
66
|
samples = [
|
63
|
-
|
64
|
-
|
67
|
+
['"Hello world!"', 'Hello world!']
|
68
|
+
]
|
65
69
|
samples.each do |source, predicted|
|
66
70
|
ptree = subject.parse(source)
|
67
71
|
expect(ptree.root).to be_kind_of(SkmString)
|
@@ -71,8 +75,8 @@ module Skeem
|
|
71
75
|
|
72
76
|
it 'should parse isolated identifiers' do
|
73
77
|
samples = [
|
74
|
-
|
75
|
-
|
78
|
+
%w[the-word-recursion-has-many-meanings the-word-recursion-has-many-meanings]
|
79
|
+
]
|
76
80
|
samples.each do |source, predicted|
|
77
81
|
ptree = subject.parse(source)
|
78
82
|
expect(ptree.root).to be_kind_of(SkmVariableReference)
|