skeem 0.2.14 → 0.2.18

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +451 -195
  3. data/.travis.yml +27 -0
  4. data/CHANGELOG.md +35 -1
  5. data/Gemfile +2 -0
  6. data/README.md +125 -56
  7. data/Rakefile +2 -0
  8. data/appveyor.yml +3 -4
  9. data/bin/cubic.skm +4 -0
  10. data/bin/hello-world.skm +1 -0
  11. data/bin/skeem +72 -0
  12. data/lib/skeem/datum_dsl.rb +40 -30
  13. data/lib/skeem/element_visitor.rb +5 -2
  14. data/lib/skeem/grammar.rb +88 -26
  15. data/lib/skeem/interpreter.rb +9 -7
  16. data/lib/skeem/parser.rb +6 -4
  17. data/lib/skeem/primitive/primitive_builder.rb +148 -122
  18. data/lib/skeem/primitive/primitive_procedure.rb +23 -25
  19. data/lib/skeem/runtime.rb +17 -15
  20. data/lib/skeem/s_expr_builder.rb +49 -117
  21. data/lib/skeem/s_expr_nodes.rb +147 -132
  22. data/lib/skeem/skeem_exception.rb +1 -0
  23. data/lib/skeem/skm_binding.rb +9 -11
  24. data/lib/skeem/skm_compound_datum.rb +9 -6
  25. data/lib/skeem/skm_element.rb +15 -13
  26. data/lib/skeem/skm_empty_list.rb +6 -4
  27. data/lib/skeem/skm_exception.rb +9 -0
  28. data/lib/skeem/skm_expression.rb +3 -1
  29. data/lib/skeem/skm_frame.rb +3 -2
  30. data/lib/skeem/skm_pair.rb +26 -18
  31. data/lib/skeem/skm_procedure_exec.rb +11 -6
  32. data/lib/skeem/skm_simple_datum.rb +23 -20
  33. data/lib/skeem/skm_unary_expression.rb +34 -37
  34. data/lib/skeem/standard/base.skm +4 -0
  35. data/lib/skeem/tokenizer.rb +38 -28
  36. data/lib/skeem/version.rb +3 -1
  37. data/lib/skeem.rb +2 -0
  38. data/skeem.gemspec +9 -6
  39. data/spec/skeem/add4.skm +4 -0
  40. data/spec/skeem/datum_dsl_spec.rb +13 -12
  41. data/spec/skeem/element_visitor_spec.rb +14 -10
  42. data/spec/skeem/interpreter_spec.rb +84 -44
  43. data/spec/skeem/lambda_spec.rb +13 -11
  44. data/spec/skeem/parser_spec.rb +23 -19
  45. data/spec/skeem/primitive/primitive_builder_spec.rb +65 -48
  46. data/spec/skeem/primitive/primitive_procedure_spec.rb +14 -12
  47. data/spec/skeem/runtime_spec.rb +20 -18
  48. data/spec/skeem/s_expr_nodes_spec.rb +8 -6
  49. data/spec/skeem/skm_compound_datum_spec.rb +12 -10
  50. data/spec/skeem/skm_element_spec.rb +7 -5
  51. data/spec/skeem/skm_empty_list_spec.rb +7 -5
  52. data/spec/skeem/skm_frame_spec.rb +5 -4
  53. data/spec/skeem/skm_pair_spec.rb +9 -8
  54. data/spec/skeem/skm_procedure_exec_spec.rb +2 -0
  55. data/spec/skeem/skm_simple_datum_spec.rb +24 -22
  56. data/spec/skeem/skm_unary_expression_spec.rb +11 -9
  57. data/spec/skeem/tokenizer_spec.rb +54 -43
  58. data/spec/skeem_spec.rb +2 -0
  59. data/spec/spec_helper.rb +15 -10
  60. metadata +18 -10
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'skm_expression'
2
4
 
3
5
  module Skeem
@@ -29,7 +31,7 @@ module Skeem
29
31
  super(nil, aDatum)
30
32
  end
31
33
 
32
- def evaluate(aRuntime)
34
+ def evaluate(_runtime)
33
35
  datum
34
36
  end
35
37
 
@@ -47,7 +49,6 @@ module Skeem
47
49
  def inspect_specific
48
50
  datum.inspect
49
51
  end
50
-
51
52
  end # class
52
53
 
53
54
  class SkmQuasiquotation < SkmQuotation
@@ -60,7 +61,6 @@ module Skeem
60
61
  def quasiquote(aRuntime)
61
62
  child.quasiquote(aRuntime)
62
63
  end
63
-
64
64
  end # class
65
65
 
66
66
  class SkmUnquotation < SkmUnaryExpression
@@ -76,8 +76,7 @@ module Skeem
76
76
  end
77
77
 
78
78
  def quasiquote(aRuntime)
79
- result = evaluate(aRuntime)
80
- result
79
+ evaluate(aRuntime)
81
80
  end
82
81
 
83
82
  protected
@@ -87,7 +86,7 @@ module Skeem
87
86
  end
88
87
  end # class
89
88
 
90
- class SkmVariableReference < SkmUnaryExpression
89
+ class SkmVariableReference < SkmUnaryExpression
91
90
  alias variable child
92
91
 
93
92
  def eqv?(other)
@@ -100,13 +99,13 @@ module Skeem
100
99
  aRuntime.evaluate(var_key)
101
100
  end
102
101
 
103
- def quasiquote(aRuntime)
102
+ def quasiquote(_runtime)
104
103
  self
105
104
  end
106
105
 
107
106
  # Confusing!
108
107
  # Value, here, means the value of the identifier (the variable's name).
109
- def value()
108
+ def value
110
109
  variable.value
111
110
  end
112
111
  end # class
@@ -115,7 +114,10 @@ module Skeem
115
114
  class SkmBindingBlock < SkmUnaryExpression
116
115
  alias body child
117
116
 
117
+ # @return [Symbol] One of: :let, :let_star
118
118
  attr_reader :kind
119
+
120
+ # @return [Array<SkmBinding>]
119
121
  attr_reader :bindings
120
122
 
121
123
  def initialize(theKind, theBindings, aBody)
@@ -126,14 +128,15 @@ module Skeem
126
128
 
127
129
  def evaluate(aRuntime)
128
130
  aRuntime.push(SkmFrame.new(aRuntime.environment))
129
- if kind == :let
131
+ case kind
132
+ when :let
130
133
  locals = bindings.map do |bnd|
131
134
  SkmBinding.new(bnd.variable, bnd.value.evaluate(aRuntime))
132
135
  end
133
136
  locals.each do |bnd|
134
137
  aRuntime.add_binding(bnd.variable.evaluate(aRuntime), bnd.value)
135
138
  end
136
- elsif kind == :let_star
139
+ when :let_star
137
140
  bindings.each do |bnd|
138
141
  val = bnd.value.evaluate(aRuntime)
139
142
  aRuntime.add_binding(bnd.variable.evaluate(aRuntime), val)
@@ -155,7 +158,6 @@ module Skeem
155
158
  # $stderr.puts "Result SkmBindingBlock#evaluate: " + result.inspect
156
159
  result
157
160
  end
158
-
159
161
  end # class
160
162
 
161
163
  # Sequencing construct
@@ -187,18 +189,16 @@ module Skeem
187
189
  def eval_pair(aRuntime)
188
190
  result = nil
189
191
  sequence.to_a.each do |cmd|
190
- begin
191
- if cmd.kind_of?(SkmLambda)
192
- result = cmd.dup_cond(aRuntime)
193
- else
194
- result = cmd.evaluate(aRuntime)
195
- end
196
- rescue NoMethodError => exc
197
- $stderr.puts self.inspect
198
- $stderr.puts sequence.inspect
199
- $stderr.puts cmd.inspect
200
- raise exc
192
+ if cmd.kind_of?(SkmLambda)
193
+ result = cmd.dup_cond(aRuntime)
194
+ else
195
+ result = cmd.evaluate(aRuntime)
201
196
  end
197
+ rescue NoMethodError => e
198
+ $stderr.puts inspect
199
+ $stderr.puts sequence.inspect
200
+ $stderr.puts cmd.inspect
201
+ raise e
202
202
  end
203
203
 
204
204
  result
@@ -216,27 +216,24 @@ module Skeem
216
216
 
217
217
  if sequence[:sequence].kind_of?(SkmPair)
218
218
  sequence[:sequence].to_a.each do |cmd|
219
- begin
220
- if cmd.kind_of?(SkmLambda)
221
- result = cmd.dup_cond(aRuntime)
222
- else
223
- result = cmd.evaluate(aRuntime)
224
- end
225
- rescue NoMethodError => exc
226
- $stderr.puts self.inspect
227
- $stderr.puts sequence[:sequence].inspect
228
- $stderr.puts cmd.inspect
229
- raise exc
219
+ if cmd.kind_of?(SkmLambda)
220
+ result = cmd.dup_cond(aRuntime)
221
+ else
222
+ result = cmd.evaluate(aRuntime)
230
223
  end
224
+ rescue NoMethodError => e
225
+ $stderr.puts inspect
226
+ $stderr.puts sequence[:sequence].inspect
227
+ $stderr.puts cmd.inspect
228
+ raise e
231
229
  end
232
- elsif
230
+ else
233
231
  result = sequence.evaluate(aRuntime)
234
232
  end
235
233
 
236
234
  aRuntime.pop
237
-
235
+
238
236
  result
239
237
  end
240
238
  end # class
241
-
242
- end # module
239
+ end # module
@@ -140,6 +140,10 @@
140
140
 
141
141
  (define symbol=? string=?)
142
142
 
143
+ (define newline
144
+ (lambda ()
145
+ (display #\newline)))
146
+
143
147
  ;; Test the equivalence (with eqv? predicate) between an expected value and
144
148
  ;; an expression
145
149
  ;; (test-eqv expected test-expr)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # File: tokenizer.rb
2
4
  # Tokenizer for Skeem language (a small subset of Scheme)
3
5
  require 'strscan'
@@ -14,8 +16,13 @@ module Skeem
14
16
  # Delimiters: parentheses '(', ')'
15
17
  # Separators: comma
16
18
  class Tokenizer
19
+ # @return [StringScanner]
17
20
  attr_reader(:scanner)
21
+
22
+ # @return [Integer] Current line number
18
23
  attr_reader(:lineno)
24
+
25
+ # @return [Integer] Offset of start of current line
19
26
  attr_reader(:line_start)
20
27
 
21
28
  @@lexeme2name = {
@@ -25,9 +32,11 @@ module Skeem
25
32
  '(' => 'LPAREN',
26
33
  ')' => 'RPAREN',
27
34
  '.' => 'PERIOD',
35
+ '...' => 'ELLIPSIS',
28
36
  ',' => 'COMMA',
29
37
  ',@' => 'COMMA_AT_SIGN',
30
- '#(' => 'VECTOR_BEGIN'
38
+ '#(' => 'VECTOR_BEGIN',
39
+ '_' => 'UNDERSCORE'
31
40
  }.freeze
32
41
 
33
42
  # Here are all the implemented Scheme keywords (in uppercase)
@@ -35,18 +44,21 @@ module Skeem
35
44
  BEGIN
36
45
  COND
37
46
  DEFINE
47
+ DEFINE-SYNTAX
38
48
  DO
39
49
  ELSE
40
50
  IF
51
+ INCLUDE
41
52
  LAMBDA
42
53
  LET
43
54
  LET*
44
55
  QUASIQUOTE
45
56
  QUOTE
46
57
  SET!
58
+ SYNTAX-RULES
47
59
  UNQUOTE
48
60
  UNQUOTE-SPLICING
49
- ].map { |x| [x, x] } .to_h
61
+ ].map { |x| [x, x.sub(/\*$/, '_STAR')] }.to_h
50
62
 
51
63
  class ScanError < StandardError; end
52
64
 
@@ -57,7 +69,6 @@ module Skeem
57
69
  reinitialize(source)
58
70
  end
59
71
 
60
-
61
72
  # @param source [String] Skeem text to tokenize.
62
73
  def reinitialize(source)
63
74
  @scanner.string = source
@@ -88,9 +99,9 @@ module Skeem
88
99
  if "()'`".include? curr_ch
89
100
  # Delimiters, separators => single character token
90
101
  token = build_token(@@lexeme2name[curr_ch], scanner.getch)
91
- elsif (lexeme = scanner.scan(/(?:\.)(?=\s)/)) # Single char occurring alone
92
- token = build_token('PERIOD', lexeme)
93
- elsif (lexeme = scanner.scan(/(?:,@?)|(?:=>)/))
102
+ elsif (lexeme = scanner.scan(/(?:\.|_)(?=\s|\()/)) # Single char occurring alone
103
+ token = build_token(@@lexeme2name[curr_ch], scanner.getch)
104
+ elsif (lexeme = scanner.scan(/(?:,@?)|(?:=>)|(?:\.\.\.)/))
94
105
  token = build_token(@@lexeme2name[lexeme], lexeme)
95
106
  elsif (token = recognize_char_token)
96
107
  # Do nothing
@@ -99,17 +110,17 @@ module Skeem
99
110
  elsif (lexeme = scanner.scan(/(?:#[dD])?[+-]?[0-9]+(?:.0+)?(?=\s|[|()";]|$)/))
100
111
  token = build_token('INTEGER', lexeme) # Decimal radix
101
112
  elsif (lexeme = scanner.scan(/#[xX][+-]?[0-9a-fA-F]+(?=\s|[|()";]|$)/))
102
- token = build_token('INTEGER', lexeme) # Hexadecimal radix
113
+ token = build_token('INTEGER', lexeme) # Hexadecimal radix
103
114
  elsif (lexeme = scanner.scan(/[+-]?[0-9]+(?:\.[0-9]*)?(?:(?:e|E)[+-]?[0-9]+)?/))
104
115
  # Order dependency: must be tested after INTEGER case
105
116
  token = build_token('REAL', lexeme)
106
117
  elsif (lexeme = scanner.scan(/#(?:(?:true)|(?:false)|(?:u8)|[\\\(tfeiodx]|(?:\d+[=#]))/))
107
- token = cardinal_token(lexeme)
118
+ token = cardinal_token(lexeme)
108
119
  elsif (lexeme = scanner.scan(/"(?:\\"|[^"])*"/)) # Double quotes literal?
109
120
  token = build_token('STRING_LIT', lexeme)
110
121
  elsif (lexeme = scanner.scan(/[a-zA-Z!$%&*\/:<=>?@^_~][a-zA-Z0-9!$%&*+-.\/:<=>?@^_~+-]*/))
111
122
  keyw = @@keywords[lexeme.upcase]
112
- tok_type = keyw ? keyw : 'IDENTIFIER'
123
+ tok_type = keyw || 'IDENTIFIER'
113
124
  token = build_token(tok_type, lexeme)
114
125
  elsif (lexeme = scanner.scan(/\|(?:[^|])*\|/)) # Vertical bar delimited
115
126
  token = build_token('IDENTIFIER', lexeme)
@@ -151,17 +162,16 @@ other literal data (section 2.4).
151
162
  return token
152
163
  end
153
164
 
154
- def recognize_char_token()
165
+ def recognize_char_token
155
166
  token = nil
156
- if lexeme = scanner.scan(/#\\/)
157
- if lexeme = scanner.scan(/(?:alarm|backspace|delete|escape|newline|null|return|space|tab)/)
167
+ if (lexeme = scanner.scan(/#\\/))
168
+ if (lexeme = scanner.scan(/(?:alarm|backspace|delete|escape|newline|null|return|space|tab)/))
158
169
  token = build_token('CHAR', lexeme, :name)
159
- elsif lexeme = scanner.scan(/[^x]/)
160
- token = build_token('CHAR', lexeme, :escaped)
161
- elsif lexeme = scanner.scan(/x[0-9a-fA-F]+/)
170
+ elsif (lexeme = scanner.scan(/x[0-9a-fA-F]+/))
162
171
  token = build_token('CHAR', lexeme, :hex_value)
163
- elsif lexeme = scanner.scan(/x/)
164
- token = build_token('CHAR', lexeme, :escaped)
172
+ else
173
+ lexeme = scanner.getch
174
+ token = build_token('CHAR', lexeme, :escaped)
165
175
  end
166
176
  end
167
177
 
@@ -174,9 +184,9 @@ other literal data (section 2.4).
174
184
  col = scanner.pos - aLexeme.size - @line_start + 1
175
185
  pos = Rley::Lexical::Position.new(@lineno, col)
176
186
  token = Rley::Lexical::Token.new(value, symb, pos)
177
- rescue StandardError => exc
187
+ rescue StandardError => e
178
188
  puts "Failing with '#{aSymbolName}' and '#{aLexeme}'"
179
- raise exc
189
+ raise e
180
190
  end
181
191
 
182
192
  return token
@@ -207,11 +217,11 @@ other literal data (section 2.4).
207
217
  return [value, symb]
208
218
  end
209
219
 
210
- def to_boolean(aLexeme, aFormat)
211
- result = (aLexeme =~ /^#t/) ? true : false
220
+ def to_boolean(aLexeme, _format)
221
+ (aLexeme =~ /^#t/) ? true : false
212
222
  end
213
223
 
214
- def to_integer(aLexeme, aFormat)
224
+ def to_integer(aLexeme, _format)
215
225
  literal = aLexeme.downcase
216
226
  prefix_pattern = /^#[dx]/
217
227
  matching = literal.match(prefix_pattern)
@@ -226,7 +236,7 @@ other literal data (section 2.4).
226
236
  else
227
237
  format = :default
228
238
  end
229
-
239
+
230
240
  case format
231
241
  when :default, :base10
232
242
  value = literal.to_i
@@ -303,11 +313,11 @@ other literal data (section 2.4).
303
313
 
304
314
  name2char[name]
305
315
  end
306
-
316
+
307
317
  def escaped_char(aLexeme)
308
318
  aLexeme.chr
309
319
  end
310
-
320
+
311
321
  def hex_value_char(aLexeme)
312
322
  hex_literal = aLexeme.sub(/^x/, '')
313
323
  hex_value = hex_literal.to_i(16)
@@ -338,15 +348,14 @@ other literal data (section 2.4).
338
348
  skip_block_comment
339
349
  next
340
350
  end
341
- break unless ws_found or cmt_found
351
+ break unless ws_found || cmt_found
342
352
  end
343
353
 
344
354
  curr_pos = scanner.pos
345
355
  return if curr_pos == pre_pos
346
356
  end
347
357
 
348
- def skip_block_comment()
349
- # require 'debug'
358
+ def skip_block_comment
350
359
  scanner.skip(/#\|/)
351
360
  nesting_level = 1
352
361
  loop do
@@ -354,6 +363,7 @@ other literal data (section 2.4).
354
363
  unless comment_part
355
364
  raise ScanError, "Unterminated '#| ... |#' comment on line #{lineno}"
356
365
  end
366
+
357
367
  case scanner.matched
358
368
  when /(?:(?:\r\n)|\r|\n)/
359
369
  next_line
data/lib/skeem/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Skeem
2
- VERSION = '0.2.14'.freeze
4
+ VERSION = '0.2.18'
3
5
  end
data/lib/skeem.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # File: skeem.rb
2
4
  # This file acts as a jumping-off point for loading dependencies expected
3
5
  # for a Skeem client.
data/skeem.gemspec CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path('../lib', __FILE__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
  require 'skeem/version'
@@ -8,6 +10,7 @@ module PkgExtending
8
10
  file_list = Dir[
9
11
  '.rubocop.yml',
10
12
  '.rspec',
13
+ '.travis.yml',
11
14
  '.yardopts',
12
15
  'appveyor.yml',
13
16
  'Gemfile',
@@ -16,11 +19,13 @@ module PkgExtending
16
19
  'LICENSE.txt',
17
20
  'README.md',
18
21
  'skeem.gemspec',
19
- 'bin/*.rb',
22
+ 'bin/*.*',
20
23
  'lib/*.*',
21
24
  'lib/**/*.rb',
22
25
  'lib/**/*.skm',
23
26
  'spec/**/*.rb',
27
+ 'spec/**/*.skm',
28
+ 'spec/**/*.yml'
24
29
  ]
25
30
  aPackage.files = file_list
26
31
  aPackage.test_files = Dir['spec/**/*_spec.rb']
@@ -49,20 +54,18 @@ DESCR
49
54
  SUMMARY
50
55
  spec.homepage = 'https://github.com/famished-tiger/Skeem'
51
56
  spec.license = 'MIT'
57
+ spec.required_ruby_version = '>= 2.5.0'
52
58
 
53
59
  spec.bindir = 'bin'
60
+ spec.executables << 'skeem'
54
61
  spec.require_paths = ['lib']
55
62
  PkgExtending.pkg_files(spec)
56
63
  PkgExtending.pkg_documentation(spec)
57
64
  # Runtime dependencies
58
- spec.add_dependency 'rley', '~> 0.7'
65
+ spec.add_dependency 'rley', '~> 0.8.03'
59
66
 
60
67
  # Development dependencies
61
- if RUBY_VERSION <= '2.2'
62
- spec.add_development_dependency 'bundler', '~> 1.16'
63
- else
64
68
  spec.add_development_dependency 'bundler', '~> 2.0'
65
- end
66
69
  spec.add_development_dependency 'rake', '~> 12.0'
67
70
  spec.add_development_dependency 'rspec', '~> 3.0'
68
71
  end
@@ -0,0 +1,4 @@
1
+ (define add4
2
+ (let ((x 4))
3
+ (lambda (y) (+ x y))))
4
+ (add4 6) ; => 10
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../spec_helper'
2
4
 
3
5
 
@@ -35,15 +37,15 @@ module Skeem
35
37
  ['+456', 456]
36
38
  ]
37
39
  end
38
-
40
+
39
41
  let(:rational_tests) do
40
42
  [
41
- [-Rational(2,3), -Rational(2, 3)],
43
+ [-Rational(2, 3), -Rational(2, 3)],
42
44
  [Rational(22, 7), Rational(22, 7)],
43
45
  ['-2/3', -Rational(2, 3)],
44
46
  ['+22/7', Rational(22, 7)]
45
47
  ]
46
- end
48
+ end
47
49
 
48
50
  let(:real_tests) do
49
51
  [
@@ -60,13 +62,13 @@ module Skeem
60
62
 
61
63
  let(:string_tests) do
62
64
  [
63
- ['hello', 'hello']
65
+ %w[hello hello]
64
66
  ]
65
67
  end
66
68
 
67
69
  let(:identifier_tests) do
68
70
  [
69
- ['define', 'define'],
71
+ %w[define define],
70
72
  [SkmString.create('positive?'), 'positive?']
71
73
  ]
72
74
  end
@@ -76,7 +78,7 @@ module Skeem
76
78
  ['#t', SkmBoolean.create(true)],
77
79
  [-1, SkmInteger.create(-1)],
78
80
  [1.41, 1.41],
79
- ['foo', 'foo']
81
+ %w[foo foo]
80
82
  ]
81
83
  end
82
84
 
@@ -92,12 +94,12 @@ module Skeem
92
94
  expect(subject.integer(literal)).to eq(predicted)
93
95
  end
94
96
  end
95
-
97
+
96
98
  it 'should convert rational literals' do
97
99
  rational_tests.each do |(literal, predicted)|
98
100
  expect(subject.rational(literal)).to eq(predicted)
99
101
  end
100
- end
102
+ end
101
103
 
102
104
  it 'should convert real number literals' do
103
105
  real_tests.each do |(literal, predicted)|
@@ -178,12 +180,12 @@ module Skeem
178
180
  expect(subject.to_datum(literal)).to eq(predicted)
179
181
  end
180
182
  end
181
-
183
+
182
184
  it 'should recognize & convert rational literals' do
183
185
  rational_tests.each do |(literal, predicted)|
184
186
  expect(subject.to_datum(literal)).to eq(predicted)
185
187
  end
186
- end
188
+ end
187
189
 
188
190
  it 'should recognize & convert real number literals' do
189
191
  real_tests.each do |(literal, predicted)|
@@ -219,6 +221,5 @@ module Skeem
219
221
  # $stderr.puts duplicate.inspect
220
222
  expect(duplicate.to_a).to eq([f, g])
221
223
  end
222
-
223
224
  end # describe
224
- end # module
225
+ end # module