skeem 0.2.08 → 0.2.09
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/README.md +6 -1
- data/lib/skeem/primitive/primitive_builder.rb +87 -152
- data/lib/skeem/primitive/primitive_procedure.rb +23 -7
- data/lib/skeem/skm_simple_datum.rb +8 -0
- data/lib/skeem/standard/base.skm +12 -5
- data/lib/skeem/tokenizer.rb +40 -18
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/interpreter_spec.rb +2 -17
- data/spec/skeem/primitive/primitive_builder_spec.rb +1 -1
- data/spec/skeem/primitive/primitive_procedure_spec.rb +2 -1
- data/spec/skeem/tokenizer_spec.rb +28 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a85fc0a12d54eedba56c28e18d728d00ff35044c029e1a256d4381a98c6310a8
|
4
|
+
data.tar.gz: 934cc810162a891fdddffdbfb16466ed7d7c71da8d7c5cb77670c010b5bf83fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6dcdf9eb8d85abdcd4d2f416b9e9fa6ed1d9b399b92c9921ff59fb8dc6d6f047e5064fd7ccffde3ae000771079a0a7d9f64643e0585ba0c39b0566b345a5b994
|
7
|
+
data.tar.gz: 60347248374f6723c91edc3699b1306056b02bfc7a91a52e9dcfa15690f72294bf89cfd1ef8551218a6e67751bdde59f972c6ec1ea0e42733436d7caa5b26bac
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,26 @@
|
|
1
|
+
## [0.2.09] - 2019-06-10
|
2
|
+
- New procedures: `complex?`, `exact-integer?`
|
3
|
+
- Support for `#| ... |#` block comments (including nesting)
|
4
|
+
|
5
|
+
### Added
|
6
|
+
- File `base.skm`: Added integer number predicate `exact-integer?`
|
7
|
+
- File `primitive_builder.rb`: Added numeric type predicate `complex?`
|
8
|
+
- New method `Tokenizer#skip_block_comment` to handle "| ... |#" comments (including their nesting)
|
9
|
+
- New folder `test_skeem` containing a test suite in `Skeem`
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
- Method 'PrimitiveProcedure#do_call' whenever possible, the arguments are evaluated before executing the primitive.
|
13
|
+
- File `primitive_builder.rb`: Lambda expression refactoring as most argument evaluations became redundant.
|
14
|
+
- Method `Tokenizer#_next_token` numeric literals with only zero(es) in their fractional part are implicitly converted to integers `3.0` => 3
|
15
|
+
- Method `Tokenizer#skip_whitespaces` refactoring & detection of block comments
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
- File `base.skm`: predicate `positive?` returned #t when argument was zero. Now: (positive? 0) returns #f as expected.
|
19
|
+
|
20
|
+
### Removed
|
21
|
+
- Empty method `PrimitiveBuilder#add_binding` removed.
|
22
|
+
|
23
|
+
|
1
24
|
## [0.2.08] - 2019-06-02
|
2
25
|
- New standard procedures implemented: `assq`, `assv`
|
3
26
|
|
data/README.md
CHANGED
@@ -166,6 +166,10 @@ Here are a few pointers for the Scheme programming language:
|
|
166
166
|
|
167
167
|
|
168
168
|
## Currently implemented R7RS features
|
169
|
+
### Comments
|
170
|
+
- Semi-colon delimited comments: `; This comment stops at the end of line`
|
171
|
+
- Block `#| ... |#` comments
|
172
|
+
|
169
173
|
### Data type literals
|
170
174
|
- Booleans: `#t`, `#true`, `#f`, `#false`
|
171
175
|
- Of the number hierarchy:
|
@@ -246,7 +250,8 @@ This section lists the implemented standard procedures
|
|
246
250
|
* `boolean?`, `and`, `or`, `not`
|
247
251
|
|
248
252
|
#### Numerical operations
|
249
|
-
* Number-level: `number?`, `real?`, `integer?`, `zero?`, `+`, `-`, `*`, `/`,
|
253
|
+
* Number-level: `number?`, `complex?`, `real?`, `integer?`, `zero?`, `exact?`, `inexact?`, `exact-integer?` , `+`, `-`, `*`, `/`,
|
254
|
+
`=`, `square`, `number->string`
|
250
255
|
* Real-level: `positive?`, `negative?`, `<`, `>`, `<=`, `>=`, `abs`, `floor-remainder`
|
251
256
|
* Integer-level: `even?`, `odd?`
|
252
257
|
|
@@ -1,14 +1,12 @@
|
|
1
1
|
require_relative 'primitive_procedure'
|
2
2
|
require_relative '../datum_dsl'
|
3
3
|
require_relative '../skm_pair'
|
4
|
-
# require_relative '../s_expr_nodes'
|
5
4
|
|
6
5
|
module Skeem
|
7
6
|
module Primitive
|
8
7
|
module PrimitiveBuilder
|
9
8
|
include DatumDSL
|
10
9
|
def add_primitives(aRuntime)
|
11
|
-
add_binding(aRuntime)
|
12
10
|
add_arithmetic(aRuntime)
|
13
11
|
add_comparison(aRuntime)
|
14
12
|
add_number_procedures(aRuntime)
|
@@ -48,9 +46,6 @@ module Skeem
|
|
48
46
|
SkmArity.new(1, '*')
|
49
47
|
end
|
50
48
|
|
51
|
-
def add_binding(aRuntime)
|
52
|
-
end
|
53
|
-
|
54
49
|
def add_arithmetic(aRuntime)
|
55
50
|
create_plus(aRuntime)
|
56
51
|
create_minus(aRuntime)
|
@@ -72,6 +67,7 @@ module Skeem
|
|
72
67
|
|
73
68
|
def add_number_procedures(aRuntime)
|
74
69
|
create_object_predicate(aRuntime, 'number?')
|
70
|
+
create_object_predicate(aRuntime, 'complex?')
|
75
71
|
create_object_predicate(aRuntime, 'real?')
|
76
72
|
create_object_predicate(aRuntime, 'integer?')
|
77
73
|
create_object_predicate(aRuntime, 'exact?')
|
@@ -141,14 +137,13 @@ module Skeem
|
|
141
137
|
|
142
138
|
def create_plus(aRuntime)
|
143
139
|
# arglist should be a Ruby Array
|
144
|
-
primitive = ->(
|
140
|
+
primitive = ->(_runtime, arglist) do
|
145
141
|
if arglist.empty?
|
146
142
|
integer(0)
|
147
143
|
else
|
148
|
-
first_one = arglist.
|
144
|
+
first_one = arglist.shift
|
149
145
|
raw_result = first_one.value
|
150
|
-
|
151
|
-
operands.each { |elem| raw_result += elem.value }
|
146
|
+
arglist.each { |elem| raw_result += elem.value }
|
152
147
|
to_datum(raw_result)
|
153
148
|
end
|
154
149
|
end
|
@@ -156,14 +151,12 @@ module Skeem
|
|
156
151
|
end
|
157
152
|
|
158
153
|
def create_minus(aRuntime)
|
159
|
-
primitive = ->(
|
160
|
-
|
161
|
-
raw_result = first_one.value
|
154
|
+
primitive = ->(_runtime, first_operand, arglist) do
|
155
|
+
raw_result = first_operand.value
|
162
156
|
if arglist.empty?
|
163
157
|
raw_result = -raw_result
|
164
158
|
else
|
165
|
-
|
166
|
-
operands.each { |elem| raw_result -= elem.value }
|
159
|
+
arglist.each { |elem| raw_result -= elem.value }
|
167
160
|
end
|
168
161
|
to_datum(raw_result)
|
169
162
|
end
|
@@ -172,14 +165,13 @@ module Skeem
|
|
172
165
|
end
|
173
166
|
|
174
167
|
def create_multiply(aRuntime)
|
175
|
-
primitive = ->(
|
168
|
+
primitive = ->(_runtime, arglist) do
|
176
169
|
if arglist.empty?
|
177
170
|
integer(1)
|
178
171
|
else
|
179
|
-
first_one = arglist.
|
172
|
+
first_one = arglist.shift
|
180
173
|
raw_result = first_one.value
|
181
|
-
|
182
|
-
operands.each { |elem| raw_result *= elem.value }
|
174
|
+
arglist.each { |elem| raw_result *= elem.value }
|
183
175
|
to_datum(raw_result)
|
184
176
|
end
|
185
177
|
end
|
@@ -188,14 +180,12 @@ module Skeem
|
|
188
180
|
|
189
181
|
|
190
182
|
def create_divide(aRuntime)
|
191
|
-
primitive = ->(
|
192
|
-
|
193
|
-
raw_result = first_one.value
|
183
|
+
primitive = ->(_runtime, first_operand, arglist) do
|
184
|
+
raw_result = first_operand.value
|
194
185
|
if arglist.empty?
|
195
186
|
raw_result = 1 / raw_result.to_f
|
196
187
|
else
|
197
|
-
|
198
|
-
operands.each do |elem|
|
188
|
+
arglist.each do |elem|
|
199
189
|
if raw_result > elem.value && raw_result.modulo(elem.value).zero?
|
200
190
|
raw_result /= elem.value
|
201
191
|
else
|
@@ -211,9 +201,7 @@ module Skeem
|
|
211
201
|
end
|
212
202
|
|
213
203
|
def create_modulo(aRuntime)
|
214
|
-
primitive = ->(
|
215
|
-
operand_1 = argument1.evaluate(runtime)
|
216
|
-
operand_2 = argument2.evaluate(runtime)
|
204
|
+
primitive = ->(_runtime, operand_1, operand_2) do
|
217
205
|
raw_result = operand_1.value.modulo(operand_2.value)
|
218
206
|
to_datum(raw_result)
|
219
207
|
end
|
@@ -227,9 +215,7 @@ module Skeem
|
|
227
215
|
end
|
228
216
|
|
229
217
|
def create_eqv?(aRuntime)
|
230
|
-
primitive = ->(runtime,
|
231
|
-
operand_1 = argument1.evaluate(runtime)
|
232
|
-
operand_2 = argument2.evaluate(runtime)
|
218
|
+
primitive = ->(runtime, operand_1, operand_2) do
|
233
219
|
core_eqv?(operand_1, operand_2)
|
234
220
|
end
|
235
221
|
|
@@ -242,9 +228,7 @@ module Skeem
|
|
242
228
|
end
|
243
229
|
|
244
230
|
def create_eq?(aRuntime)
|
245
|
-
primitive = ->(
|
246
|
-
operand_1 = argument1.evaluate(runtime)
|
247
|
-
operand_2 = argument2.evaluate(runtime)
|
231
|
+
primitive = ->(_runtime, operand_1, operand_2) do
|
248
232
|
core_eq?(operand1, operand2)
|
249
233
|
end
|
250
234
|
|
@@ -252,9 +236,7 @@ module Skeem
|
|
252
236
|
end
|
253
237
|
|
254
238
|
def create_equal?(aRuntime)
|
255
|
-
primitive = ->(
|
256
|
-
operand_1 = argument1.evaluate(runtime)
|
257
|
-
operand_2 = argument2.evaluate(runtime)
|
239
|
+
primitive = ->(_runtime, operand_1, operand_2) do
|
258
240
|
raw_result = operand_1.skm_equal?(operand_2)
|
259
241
|
boolean(raw_result)
|
260
242
|
end
|
@@ -263,14 +245,12 @@ module Skeem
|
|
263
245
|
end
|
264
246
|
|
265
247
|
def create_equal(aRuntime)
|
266
|
-
primitive = ->(
|
267
|
-
first_one = first_operand.evaluate(runtime)
|
248
|
+
primitive = ->(_runtime, first_operand, arglist) do
|
268
249
|
if arglist.empty?
|
269
250
|
boolean(true)
|
270
251
|
else
|
271
|
-
|
272
|
-
|
273
|
-
all_equal = operands.all? { |elem| first_value == elem.value }
|
252
|
+
first_value = first_operand.value
|
253
|
+
all_equal = arglist.all? { |elem| first_value == elem.value }
|
274
254
|
boolean(all_equal)
|
275
255
|
end
|
276
256
|
end
|
@@ -279,82 +259,70 @@ module Skeem
|
|
279
259
|
end
|
280
260
|
|
281
261
|
def create_lt(aRuntime)
|
282
|
-
primitive = ->(
|
262
|
+
primitive = ->(_runtime, first_operand, arglist) do
|
283
263
|
if arglist.empty?
|
284
|
-
|
264
|
+
result = false
|
285
265
|
else
|
286
|
-
|
287
|
-
operands.concat(arglist.evaluate(runtime).to_a)
|
288
|
-
result = true
|
289
|
-
operands.each_cons(2) do |(elem1, elem2)|
|
290
|
-
result &&= elem1.value < elem2.value
|
291
|
-
end
|
292
|
-
boolean(result)
|
266
|
+
result = primitive_comparison(:<, _runtime, first_operand, arglist)
|
293
267
|
end
|
268
|
+
boolean(result)
|
294
269
|
end
|
295
270
|
|
296
271
|
define_primitive_proc(aRuntime, '<', one_or_more, primitive)
|
297
272
|
end
|
298
273
|
|
299
274
|
def create_gt(aRuntime)
|
300
|
-
primitive = ->(
|
275
|
+
primitive = ->(_runtime, first_operand, arglist) do
|
301
276
|
if arglist.empty?
|
302
|
-
|
277
|
+
result = false
|
303
278
|
else
|
304
|
-
|
305
|
-
operands.concat(arglist.evaluate(runtime).to_a)
|
306
|
-
result = true
|
307
|
-
operands.each_cons(2) do |(elem1, elem2)|
|
308
|
-
result &&= elem1.value > elem2.value
|
309
|
-
end
|
310
|
-
boolean(result)
|
279
|
+
result = primitive_comparison(:>, _runtime, first_operand, arglist)
|
311
280
|
end
|
281
|
+
boolean(result)
|
312
282
|
end
|
313
283
|
|
314
284
|
define_primitive_proc(aRuntime, '>', one_or_more, primitive)
|
315
285
|
end
|
316
286
|
|
317
287
|
def create_lte(aRuntime)
|
318
|
-
primitive = ->(
|
288
|
+
primitive = ->(_runtime, first_operand, arglist) do
|
319
289
|
if arglist.empty?
|
320
|
-
boolean(true)
|
321
|
-
else
|
322
|
-
operands = [first_operand.evaluate(runtime)]
|
323
|
-
operands.concat(arglist.evaluate(runtime).to_a)
|
324
290
|
result = true
|
325
|
-
|
326
|
-
|
327
|
-
end
|
328
|
-
boolean(result)
|
291
|
+
else
|
292
|
+
result = primitive_comparison(:<=, _runtime, first_operand, arglist)
|
329
293
|
end
|
294
|
+
boolean(result)
|
330
295
|
end
|
331
296
|
|
332
297
|
define_primitive_proc(aRuntime, '<=', one_or_more, primitive)
|
333
298
|
end
|
334
299
|
|
335
300
|
def create_gte(aRuntime)
|
336
|
-
primitive = ->(
|
301
|
+
primitive = ->(_runtime, first_operand, arglist) do
|
337
302
|
if arglist.empty?
|
338
|
-
boolean(true)
|
339
|
-
else
|
340
|
-
operands = [first_operand.evaluate(runtime)]
|
341
|
-
operands.concat(arglist.evaluate(runtime).to_a)
|
342
303
|
result = true
|
343
|
-
|
344
|
-
|
345
|
-
end
|
346
|
-
|
347
|
-
boolean(result)
|
304
|
+
else
|
305
|
+
result = primitive_comparison(:>=, _runtime, first_operand, arglist)
|
348
306
|
end
|
307
|
+
boolean(result)
|
349
308
|
end
|
350
309
|
|
351
310
|
define_primitive_proc(aRuntime, '>=', one_or_more, primitive)
|
352
311
|
end
|
312
|
+
|
313
|
+
def primitive_comparison(operator, _runtime, first_operand, arglist)
|
314
|
+
operands = [first_operand].concat(arglist)
|
315
|
+
result = true
|
316
|
+
operands.each_cons(2) do |(elem1, elem2)|
|
317
|
+
result &&= elem1.value.send(operator, elem2.value)
|
318
|
+
end
|
319
|
+
|
320
|
+
boolean(result)
|
321
|
+
end
|
353
322
|
|
354
323
|
def create_number2string(aRuntime)
|
355
324
|
# TODO: add support for radix argument
|
356
|
-
primitive = ->(
|
357
|
-
arg_evaluated = arg.evaluate(runtime)
|
325
|
+
primitive = ->(_runtime, arg_evaluated) do
|
358
326
|
check_argtype(arg_evaluated, SkmNumber, 'number', 'number->string')
|
359
327
|
string(arg_evaluated.value)
|
360
328
|
end
|
@@ -364,6 +332,7 @@ module Skeem
|
|
364
332
|
|
365
333
|
def create_and(aRuntime)
|
366
334
|
# arglist should be a Ruby Array
|
335
|
+
# Arguments aren't evaluated yet!...
|
367
336
|
primitive = ->(runtime, arglist) do
|
368
337
|
if arglist.empty?
|
369
338
|
boolean(true) # in conformance with 4.2.1
|
@@ -389,6 +358,7 @@ module Skeem
|
|
389
358
|
|
390
359
|
def create_or(aRuntime)
|
391
360
|
# arglist should be a Ruby Array
|
361
|
+
# Arguments aren't evaluated yet!...
|
392
362
|
primitive = ->(runtime, arglist) do
|
393
363
|
if arglist.empty?
|
394
364
|
boolean(false) # in conformance with 4.2.1
|
@@ -409,14 +379,12 @@ module Skeem
|
|
409
379
|
end
|
410
380
|
|
411
381
|
def create_string_equal(aRuntime)
|
412
|
-
primitive = ->(
|
413
|
-
first_one = first_operand.evaluate(runtime)
|
382
|
+
primitive = ->(_runtime, first_operand, arglist) do
|
414
383
|
if arglist.empty?
|
415
384
|
boolean(true)
|
416
385
|
else
|
417
|
-
|
418
|
-
|
419
|
-
all_equal = operands.all? { |elem| first_value == elem.value }
|
386
|
+
first_value = first_operand.value
|
387
|
+
all_equal = arglist.all? { |elem| first_value == elem.value }
|
420
388
|
boolean(all_equal)
|
421
389
|
end
|
422
390
|
end
|
@@ -425,12 +393,11 @@ module Skeem
|
|
425
393
|
end
|
426
394
|
|
427
395
|
def create_string_append(aRuntime)
|
428
|
-
primitive = ->(
|
396
|
+
primitive = ->(_runtime, arglist) do
|
429
397
|
if arglist.empty?
|
430
398
|
value = ''
|
431
399
|
else
|
432
|
-
|
433
|
-
value = parts.reduce('') { |interim, substr| interim << substr.value }
|
400
|
+
value = arglist.reduce('') { |interim, substr| interim << substr.value }
|
434
401
|
end
|
435
402
|
|
436
403
|
string(value)
|
@@ -440,8 +407,7 @@ module Skeem
|
|
440
407
|
end
|
441
408
|
|
442
409
|
def create_string_length(aRuntime)
|
443
|
-
primitive = ->(runtime,
|
444
|
-
arg_evaluated = arg.evaluate(runtime)
|
410
|
+
primitive = ->(runtime, arg_evaluated) do
|
445
411
|
check_argtype(arg_evaluated, SkmString, 'string', 'string-length')
|
446
412
|
integer(arg_evaluated.length)
|
447
413
|
end
|
@@ -450,8 +416,7 @@ module Skeem
|
|
450
416
|
end
|
451
417
|
|
452
418
|
def create_string2symbol(aRuntime)
|
453
|
-
primitive = ->(runtime,
|
454
|
-
arg_evaluated = arg.evaluate(runtime)
|
419
|
+
primitive = ->(runtime, arg_evaluated) do
|
455
420
|
check_argtype(arg_evaluated, SkmString, 'string', 'string->symbol')
|
456
421
|
identifier(arg_evaluated)
|
457
422
|
end
|
@@ -460,8 +425,7 @@ module Skeem
|
|
460
425
|
end
|
461
426
|
|
462
427
|
def create_symbol2string(aRuntime)
|
463
|
-
primitive = ->(runtime,
|
464
|
-
arg_evaluated = arg.evaluate(runtime)
|
428
|
+
primitive = ->(runtime, arg_evaluated) do
|
465
429
|
check_argtype(arg_evaluated, SkmIdentifier, 'symbol', 'symbol->string')
|
466
430
|
string(arg_evaluated)
|
467
431
|
end
|
@@ -470,8 +434,7 @@ module Skeem
|
|
470
434
|
end
|
471
435
|
|
472
436
|
def create_car(aRuntime)
|
473
|
-
primitive = ->(runtime,
|
474
|
-
arg_evaluated = arg.evaluate(runtime)
|
437
|
+
primitive = ->(runtime, arg_evaluated) do
|
475
438
|
check_argtype(arg_evaluated, SkmPair, 'pair', 'car')
|
476
439
|
arg_evaluated.car
|
477
440
|
end
|
@@ -480,8 +443,7 @@ module Skeem
|
|
480
443
|
end
|
481
444
|
|
482
445
|
def create_cdr(aRuntime)
|
483
|
-
primitive = ->(
|
484
|
-
arg_evaluated = arg.evaluate(runtime)
|
446
|
+
primitive = ->(_runtime, arg_evaluated) do
|
485
447
|
check_argtype(arg_evaluated, SkmPair, 'pair', 'cdr')
|
486
448
|
arg_evaluated.cdr
|
487
449
|
end
|
@@ -490,16 +452,15 @@ module Skeem
|
|
490
452
|
end
|
491
453
|
|
492
454
|
def create_cons(aRuntime)
|
493
|
-
primitive = ->(
|
494
|
-
SkmPair.new(obj1
|
455
|
+
primitive = ->(_runtime, obj1, obj2) do
|
456
|
+
SkmPair.new(obj1, obj2)
|
495
457
|
end
|
496
458
|
|
497
459
|
define_primitive_proc(aRuntime, 'cons', binary, primitive)
|
498
460
|
end
|
499
461
|
|
500
462
|
def create_length(aRuntime)
|
501
|
-
primitive = ->(
|
502
|
-
arg_evaluated = arg.evaluate(runtime)
|
463
|
+
primitive = ->(_runtime, arg_evaluated) do
|
503
464
|
check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'length')
|
504
465
|
integer(arg_evaluated.length)
|
505
466
|
end
|
@@ -508,8 +469,7 @@ module Skeem
|
|
508
469
|
end
|
509
470
|
|
510
471
|
def create_list2vector(aRuntime)
|
511
|
-
primitive = ->(
|
512
|
-
arg_evaluated = arg.evaluate(runtime)
|
472
|
+
primitive = ->(_runtime, arg_evaluated) do
|
513
473
|
check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'list->vector')
|
514
474
|
vector(arg_evaluated.to_a)
|
515
475
|
end
|
@@ -555,6 +515,7 @@ module Skeem
|
|
555
515
|
end
|
556
516
|
|
557
517
|
def create_append(aRuntime)
|
518
|
+
# Arguments aren't evaluated yet!...
|
558
519
|
primitive = ->(runtime, arglist) do
|
559
520
|
if arglist.size > 1
|
560
521
|
arguments = evaluate_arguments(arglist, aRuntime)
|
@@ -569,6 +530,7 @@ module Skeem
|
|
569
530
|
end
|
570
531
|
|
571
532
|
def create_setcar(aRuntime)
|
533
|
+
# Arguments aren't evaluated yet!...
|
572
534
|
primitive = ->(runtime, pair_arg, obj_arg) do
|
573
535
|
case pair_arg
|
574
536
|
when SkmPair
|
@@ -593,6 +555,7 @@ module Skeem
|
|
593
555
|
end
|
594
556
|
|
595
557
|
def create_setcdr(aRuntime)
|
558
|
+
# Arguments aren't evaluated yet!...
|
596
559
|
primitive = ->(runtime, pair_arg, obj_arg) do
|
597
560
|
case pair_arg
|
598
561
|
when SkmPair
|
@@ -620,7 +583,7 @@ module Skeem
|
|
620
583
|
primitive = ->(runtime, obj_arg, alist_arg) do
|
621
584
|
assoc_list = alist_arg.evaluate(runtime)
|
622
585
|
check_assoc_list(assoc_list, 'assq')
|
623
|
-
obj = obj_arg.evaluate(runtime)
|
586
|
+
obj = obj_arg.evaluate(runtime)
|
624
587
|
result = boolean(false)
|
625
588
|
unless assoc_list.empty?
|
626
589
|
pair = assoc_list
|
@@ -638,12 +601,10 @@ module Skeem
|
|
638
601
|
end
|
639
602
|
define_primitive_proc(aRuntime, 'assq', binary, primitive)
|
640
603
|
end
|
641
|
-
|
604
|
+
|
642
605
|
def create_assv(aRuntime)
|
643
|
-
primitive = ->(runtime,
|
644
|
-
assoc_list = alist_arg.evaluate(runtime)
|
606
|
+
primitive = ->(runtime, obj, assoc_list) do
|
645
607
|
check_assoc_list(assoc_list, 'assq')
|
646
|
-
obj = obj_arg.evaluate(runtime)
|
647
608
|
result = boolean(false)
|
648
609
|
unless assoc_list.empty?
|
649
610
|
pair = assoc_list
|
@@ -659,8 +620,8 @@ module Skeem
|
|
659
620
|
|
660
621
|
result
|
661
622
|
end
|
662
|
-
define_primitive_proc(aRuntime, 'assv', binary, primitive)
|
663
|
-
end
|
623
|
+
define_primitive_proc(aRuntime, 'assv', binary, primitive)
|
624
|
+
end
|
664
625
|
|
665
626
|
def check_assoc_list(alist, proc_name)
|
666
627
|
check_argtype(alist, [SkmPair, SkmEmptyList], 'association list', proc_name)
|
@@ -675,24 +636,16 @@ module Skeem
|
|
675
636
|
end
|
676
637
|
|
677
638
|
def create_list_copy(aRuntime)
|
678
|
-
primitive = ->(runtime,
|
679
|
-
arg_evaluated = arg.evaluate(runtime)
|
639
|
+
primitive = ->(runtime, arg_evaluated) do
|
680
640
|
check_argtype(arg_evaluated, [SkmPair, SkmEmptyList], 'list', 'list-copy')
|
681
|
-
arg.klone
|
641
|
+
arg_evaluated.klone # Previously: arg.klone
|
682
642
|
end
|
683
643
|
|
684
644
|
define_primitive_proc(aRuntime, 'list-copy', unary, primitive)
|
685
645
|
end
|
686
646
|
|
687
|
-
|
688
647
|
def create_vector(aRuntime)
|
689
|
-
primitive = ->(
|
690
|
-
if arglist.empty?
|
691
|
-
elements = []
|
692
|
-
else
|
693
|
-
elements = evaluate_arguments(arglist, aRuntime)
|
694
|
-
end
|
695
|
-
|
648
|
+
primitive = ->(_runtime, elements) do
|
696
649
|
vector(elements)
|
697
650
|
end
|
698
651
|
|
@@ -700,8 +653,7 @@ module Skeem
|
|
700
653
|
end
|
701
654
|
|
702
655
|
def create_vector_length(aRuntime)
|
703
|
-
primitive = ->(
|
704
|
-
arg_evaluated = arg.evaluate(runtime)
|
656
|
+
primitive = ->(_runtime, arg_evaluated) do
|
705
657
|
check_argtype(arg_evaluated, SkmVector, 'vector', 'vector-length')
|
706
658
|
integer(arg_evaluated.length)
|
707
659
|
end
|
@@ -716,7 +668,7 @@ module Skeem
|
|
716
668
|
if arglist.empty?
|
717
669
|
filler = SkmUndefined.instance
|
718
670
|
else
|
719
|
-
filler = arglist.
|
671
|
+
filler = arglist.first.evaluate(runtime)
|
720
672
|
end
|
721
673
|
elements = Array.new(count.value, filler)
|
722
674
|
|
@@ -728,10 +680,8 @@ module Skeem
|
|
728
680
|
|
729
681
|
def create_vector_ref(aRuntime)
|
730
682
|
# argument 1: a vector, argument 2: an index(integer)
|
731
|
-
primitive = ->(runtime,
|
732
|
-
vector = aVector.evaluate(runtime)
|
683
|
+
primitive = ->(runtime, vector, index) do
|
733
684
|
check_argtype(vector, SkmVector, 'vector', 'vector-ref')
|
734
|
-
index = anIndex.evaluate(runtime)
|
735
685
|
check_argtype(index, SkmInteger, 'integer', 'vector-ref')
|
736
686
|
# TODO: index checking
|
737
687
|
raw_result = vector.members[index.value]
|
@@ -742,8 +692,7 @@ module Skeem
|
|
742
692
|
end
|
743
693
|
|
744
694
|
def create_vector2list(aRuntime)
|
745
|
-
primitive = ->(runtime,
|
746
|
-
arg_evaluated = arg.evaluate(runtime)
|
695
|
+
primitive = ->(runtime, arg_evaluated) do
|
747
696
|
check_argtype(arg_evaluated, SkmVector, 'vector', 'vector->list')
|
748
697
|
SkmPair.create_from_a(arg_evaluated.members)
|
749
698
|
end
|
@@ -752,13 +701,11 @@ module Skeem
|
|
752
701
|
end
|
753
702
|
|
754
703
|
def create_apply(aRuntime)
|
755
|
-
primitive = ->(runtime,
|
756
|
-
proc_arg = first_operand.evaluate(runtime)
|
704
|
+
primitive = ->(runtime, proc_arg, arglist) do
|
757
705
|
if arglist.empty?
|
758
706
|
result = SkmEmptyList.instance
|
759
707
|
else
|
760
|
-
|
761
|
-
single_list = append_core(arguments)
|
708
|
+
single_list = append_core(arglist)
|
762
709
|
invoke = ProcedureCall.new(nil, proc_arg, single_list.to_a)
|
763
710
|
result = invoke.evaluate(runtime)
|
764
711
|
end
|
@@ -768,13 +715,11 @@ module Skeem
|
|
768
715
|
end
|
769
716
|
|
770
717
|
def create_map(aRuntime)
|
771
|
-
primitive = ->(runtime,
|
772
|
-
|
773
|
-
if list_of_lists.empty?
|
718
|
+
primitive = ->(runtime, proc_arg, arglist) do
|
719
|
+
if arglist.empty?
|
774
720
|
result = SkmEmptyList.instance
|
775
721
|
else
|
776
|
-
|
777
|
-
curr_cells = arguments.to_a
|
722
|
+
curr_cells = arglist
|
778
723
|
arity = curr_cells.size
|
779
724
|
initial_result = nil
|
780
725
|
curr_result = nil
|
@@ -813,14 +758,13 @@ module Skeem
|
|
813
758
|
end
|
814
759
|
|
815
760
|
def create_test_assert(aRuntime)
|
816
|
-
primitive = ->(runtime,
|
817
|
-
arg_evaluated = arg.evaluate(runtime)
|
761
|
+
primitive = ->(runtime, arg_evaluated) do
|
818
762
|
if arg_evaluated.boolean? && arg_evaluated.value == false
|
819
763
|
assert_call = aRuntime.caller
|
820
764
|
pos = assert_call.call_site
|
821
765
|
# Error: assertion failed: (> 1 2)
|
822
766
|
msg1 = "assertion failed on line #{pos.line}, column #{pos.column}"
|
823
|
-
msg2 = ", with #{
|
767
|
+
msg2 = ", with #{arg_evaluated.inspect}"
|
824
768
|
raise StandardError, 'Error: ' + msg1 + msg2
|
825
769
|
else
|
826
770
|
boolean(true)
|
@@ -843,8 +787,7 @@ module Skeem
|
|
843
787
|
# DON'T USE IT
|
844
788
|
# Non-standard procedure reserved for internal testing/debugging purposes.
|
845
789
|
def create_inspect(aRuntime)
|
846
|
-
primitive = ->(runtime,
|
847
|
-
arg_evaluated = arg.evaluate(runtime)
|
790
|
+
primitive = ->(runtime, arg_evaluated) do
|
848
791
|
$stderr.puts 'INSPECT>' + arg_evaluated.inspect
|
849
792
|
Skeem::SkmUndefined.instance
|
850
793
|
end
|
@@ -853,21 +796,13 @@ module Skeem
|
|
853
796
|
|
854
797
|
def create_object_predicate(aRuntime, predicate_name, msg_name = nil)
|
855
798
|
msg_name = predicate_name if msg_name.nil?
|
856
|
-
primitive = ->(runtime,
|
857
|
-
arg_evaluated = arg.evaluate(runtime)
|
799
|
+
primitive = ->(runtime, arg_evaluated) do
|
858
800
|
to_datum(arg_evaluated.send(msg_name))
|
859
801
|
end
|
860
802
|
|
861
803
|
define_primitive_proc(aRuntime, predicate_name, unary, primitive)
|
862
804
|
end
|
863
805
|
|
864
|
-
# def def_procedure(aRuntime, pairs)
|
865
|
-
# pairs.each_slice(2) do |(name, code)|
|
866
|
-
# func = PrimitiveProcedure.new(name, code)
|
867
|
-
# define(aRuntime, func.identifier, func)
|
868
|
-
# end
|
869
|
-
# end
|
870
|
-
|
871
806
|
def define_primitive_proc(aRuntime, anIdentifier, anArity, aRubyLambda)
|
872
807
|
primitive = PrimitiveProcedure.new(anIdentifier, anArity, aRubyLambda)
|
873
808
|
@primitive_map = {} unless @primitives_map
|
@@ -114,19 +114,35 @@ module Skeem
|
|
114
114
|
result = code.call(aRuntime)
|
115
115
|
elsif arity.variadic? || (arity.low < arity.high)
|
116
116
|
if arity.low.zero?
|
117
|
-
|
117
|
+
if ['and', 'or', 'append'].include? identifier
|
118
|
+
# Defer the evaluation of arguments to the primitive
|
119
|
+
result = code.call(aRuntime, operands)
|
120
|
+
else
|
121
|
+
evaluated_args = operands.map {|opernd| opernd.evaluate(aRuntime) }
|
122
|
+
result = code.call(aRuntime, evaluated_args)
|
123
|
+
end
|
118
124
|
else
|
119
|
-
|
120
|
-
|
125
|
+
# require 'debug'
|
126
|
+
args = operands.take(arity.low)
|
127
|
+
args.map! { |arg| arg.evaluate(aRuntime) } unless args.empty?
|
121
128
|
count_delta = operands.size - arity.low
|
122
|
-
|
129
|
+
remaining = operands.slice(-count_delta, count_delta).map do |arg|
|
130
|
+
arg.evaluate(aRuntime)
|
131
|
+
end
|
132
|
+
args << remaining.flatten
|
123
133
|
# p operands.size
|
124
134
|
# p count_delta
|
125
|
-
# p
|
126
|
-
result = code.send(:call, aRuntime, *
|
135
|
+
# p args.inspect
|
136
|
+
result = code.send(:call, aRuntime, *args)
|
127
137
|
end
|
128
138
|
else # Fixed arity...
|
129
|
-
|
139
|
+
if identifier == 'set-car!' || identifier == 'set-cdr!'
|
140
|
+
# Defer evaluation inside the primitive
|
141
|
+
result = code.send(:call, aRuntime, *operands)
|
142
|
+
else
|
143
|
+
evaluated_args = operands.map {|opernd| opernd.evaluate(aRuntime) }
|
144
|
+
result = code.send(:call, aRuntime, *evaluated_args)
|
145
|
+
end
|
130
146
|
end
|
131
147
|
|
132
148
|
result
|
@@ -97,6 +97,10 @@ module Skeem
|
|
97
97
|
def number?
|
98
98
|
true
|
99
99
|
end
|
100
|
+
|
101
|
+
def complex?
|
102
|
+
false
|
103
|
+
end
|
100
104
|
|
101
105
|
def eqv?(other)
|
102
106
|
return true if self.equal?(other)
|
@@ -119,6 +123,10 @@ module Skeem
|
|
119
123
|
def real?
|
120
124
|
true
|
121
125
|
end
|
126
|
+
|
127
|
+
def complex?
|
128
|
+
true
|
129
|
+
end
|
122
130
|
|
123
131
|
def exact?
|
124
132
|
false
|
data/lib/skeem/standard/base.skm
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
; Standard R7RS procedures from section 6.2.6
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
;; (exact-integer? z)
|
4
|
+
(define exact-integer?
|
5
|
+
(lambda (z)
|
6
|
+
(and
|
7
|
+
(exact? z)
|
8
|
+
(integer? z))))
|
9
|
+
|
10
|
+
;; (zero? z)
|
11
|
+
;; Returns true iff z is zero
|
5
12
|
(define zero?
|
6
13
|
(lambda (z)
|
7
14
|
(if (= z 0)
|
@@ -9,10 +16,10 @@
|
|
9
16
|
#f)))
|
10
17
|
|
11
18
|
; (positive? x)
|
12
|
-
; Return true if x greater
|
19
|
+
; Return true if x greater than zero; false otherwise
|
13
20
|
(define positive?
|
14
21
|
(lambda (x)
|
15
|
-
(if (
|
22
|
+
(if (> x 0)
|
16
23
|
#t
|
17
24
|
#f)))
|
18
25
|
|
@@ -105,7 +112,7 @@
|
|
105
112
|
;; (test-eqv expected test-expr)
|
106
113
|
(define test-eqv
|
107
114
|
(lambda (x y)
|
108
|
-
(test-assert (
|
115
|
+
(test-assert (eqv? x y))))
|
109
116
|
|
110
117
|
;; Test the equality (with equal? predicate) between an expected value and
|
111
118
|
;; an expression
|
data/lib/skeem/tokenizer.rb
CHANGED
@@ -92,10 +92,10 @@ module Skeem
|
|
92
92
|
elsif (lexeme = scanner.scan(/(?:,@?)|(?:=>)/))
|
93
93
|
token = build_token(@@lexeme2name[lexeme], lexeme)
|
94
94
|
elsif (lexeme = scanner.scan(/#(?:(?:true)|(?:false)|(?:u8)|[\\\(tfeiodx]|(?:\d+[=#]))/))
|
95
|
-
token = cardinal_token(lexeme)
|
96
|
-
elsif (lexeme = scanner.scan(/[+-]?[0-9]+(?=\s|[|()";]|$)/))
|
95
|
+
token = cardinal_token(lexeme)
|
96
|
+
elsif (lexeme = scanner.scan(/[+-]?[0-9]+(?:.0+)?(?=\s|[|()";]|$)/))
|
97
97
|
token = build_token('INTEGER', lexeme) # Decimal radix
|
98
|
-
elsif (lexeme = scanner.scan(/[+-]?[0-9]+(?:\.[0-9]
|
98
|
+
elsif (lexeme = scanner.scan(/[+-]?[0-9]+(?:\.[0-9]*)?(?:(?:e|E)[+-]?[0-9]+)?/))
|
99
99
|
# Order dependency: must be tested after INTEGER case
|
100
100
|
token = build_token('REAL', lexeme)
|
101
101
|
elsif (lexeme = scanner.scan(/"(?:\\"|[^"])*"/)) # Double quotes literal?
|
@@ -124,7 +124,7 @@ module Skeem
|
|
124
124
|
|
125
125
|
return token
|
126
126
|
end
|
127
|
-
|
127
|
+
|
128
128
|
=begin
|
129
129
|
#t #f These are the boolean constants (section 6.3), along
|
130
130
|
with the alternatives #true and #false.
|
@@ -138,7 +138,7 @@ numbers (section 6.2.5).
|
|
138
138
|
#<n>= #<n># These are used for labeling and referencing
|
139
139
|
other literal data (section 2.4).
|
140
140
|
# token = build_token('BOOLEAN', lexeme)
|
141
|
-
=end
|
141
|
+
=end
|
142
142
|
def cardinal_token(aLexeme)
|
143
143
|
case aLexeme
|
144
144
|
when /^#true|false|t|f$/
|
@@ -146,7 +146,7 @@ other literal data (section 2.4).
|
|
146
146
|
when '#('
|
147
147
|
token = build_token(@@lexeme2name[aLexeme], aLexeme)
|
148
148
|
end
|
149
|
-
|
149
|
+
|
150
150
|
return token
|
151
151
|
end
|
152
152
|
|
@@ -175,7 +175,7 @@ other literal data (section 2.4).
|
|
175
175
|
when 'STRING_LIT'
|
176
176
|
value = to_string(aLexeme, aFormat)
|
177
177
|
when 'IDENTIFIER'
|
178
|
-
value = to_identifier(aLexeme, aFormat)
|
178
|
+
value = to_identifier(aLexeme, aFormat)
|
179
179
|
else
|
180
180
|
value = aLexeme
|
181
181
|
end
|
@@ -204,7 +204,7 @@ other literal data (section 2.4).
|
|
204
204
|
|
205
205
|
return value
|
206
206
|
end
|
207
|
-
|
207
|
+
|
208
208
|
def to_string(aLexeme, aFormat)
|
209
209
|
case aFormat
|
210
210
|
when :default
|
@@ -212,7 +212,7 @@ other literal data (section 2.4).
|
|
212
212
|
end
|
213
213
|
|
214
214
|
return value
|
215
|
-
end
|
215
|
+
end
|
216
216
|
|
217
217
|
def to_identifier(aLexeme, aFormat)
|
218
218
|
case aFormat
|
@@ -221,26 +221,27 @@ other literal data (section 2.4).
|
|
221
221
|
end
|
222
222
|
|
223
223
|
return value
|
224
|
-
end
|
225
|
-
|
224
|
+
end
|
225
|
+
|
226
226
|
def skip_whitespaces
|
227
227
|
pre_pos = scanner.pos
|
228
228
|
|
229
229
|
loop do
|
230
|
-
ws_found = false
|
231
|
-
|
232
|
-
|
233
|
-
ws_found = true if found
|
234
|
-
found = scanner.skip(/(?:\r\n)|\r|\n/)
|
235
|
-
if found
|
230
|
+
ws_found = scanner.skip(/[ \t\f]+/) ? true : false
|
231
|
+
nl_found = scanner.skip(/(?:\r\n)|\r|\n/)
|
232
|
+
if nl_found
|
236
233
|
ws_found = true
|
237
234
|
next_line
|
238
235
|
end
|
236
|
+
cmt_found = false
|
239
237
|
next_ch = scanner.peek(1)
|
240
238
|
if next_ch == ';'
|
241
239
|
cmt_found = true
|
242
240
|
scanner.skip(/;[^\r\n]*(?:(?:\r\n)|\r|\n)?/)
|
243
241
|
next_line
|
242
|
+
elsif scanner.peek(2) == '#|'
|
243
|
+
skip_block_comment
|
244
|
+
next
|
244
245
|
end
|
245
246
|
break unless ws_found or cmt_found
|
246
247
|
end
|
@@ -248,7 +249,28 @@ other literal data (section 2.4).
|
|
248
249
|
curr_pos = scanner.pos
|
249
250
|
return if curr_pos == pre_pos
|
250
251
|
end
|
251
|
-
|
252
|
+
|
253
|
+
def skip_block_comment()
|
254
|
+
# require 'debug'
|
255
|
+
scanner.skip(/#\|/)
|
256
|
+
nesting_level = 1
|
257
|
+
loop do
|
258
|
+
comment_part = scanner.scan_until(/(?:\|\#)|(?:\#\|)|(?:(?:\r\n)|\r|\n)/)
|
259
|
+
unless comment_part
|
260
|
+
raise ScanError, "Unterminated '#| ... |#' comment on line #{lineno}"
|
261
|
+
end
|
262
|
+
case scanner.matched
|
263
|
+
when /(?:(?:\r\n)|\r|\n)/
|
264
|
+
next_line
|
265
|
+
when '|#'
|
266
|
+
nesting_level -= 1
|
267
|
+
break if nesting_level.zero?
|
268
|
+
when '#|'
|
269
|
+
nesting_level += 1
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
252
274
|
def next_line
|
253
275
|
@lineno += 1
|
254
276
|
@line_start = scanner.pos
|
data/lib/skeem/version.rb
CHANGED
@@ -664,23 +664,8 @@ SKEEM
|
|
664
664
|
checks = [
|
665
665
|
['(positive? 3.1)', true],
|
666
666
|
['(positive? -3.1)', false],
|
667
|
-
['(positive? 0)',
|
668
|
-
['(positive? 0.0)',
|
669
|
-
['(positive? 3)', true],
|
670
|
-
['(positive? -3)', false]
|
671
|
-
]
|
672
|
-
checks.each do |(skeem_expr, expectation)|
|
673
|
-
result = subject.run(skeem_expr)
|
674
|
-
expect(result).to eq(expectation)
|
675
|
-
end
|
676
|
-
end
|
677
|
-
|
678
|
-
it 'should implement the positive? predicate' do
|
679
|
-
checks = [
|
680
|
-
['(positive? 3.1)', true],
|
681
|
-
['(positive? -3.1)', false],
|
682
|
-
['(positive? 0)', true],
|
683
|
-
['(positive? 0.0)', true],
|
667
|
+
['(positive? 0)', false],
|
668
|
+
['(positive? 0.0)', false],
|
684
669
|
['(positive? 3)', true],
|
685
670
|
['(positive? -3)', false]
|
686
671
|
]
|
@@ -146,7 +146,8 @@ module Skeem
|
|
146
146
|
no_arg = []
|
147
147
|
expect(pproc.call(rtime, no_arg)).to eq(0)
|
148
148
|
|
149
|
-
many = ['foo', 'bar',
|
149
|
+
many = [SkmString.create('foo'), SkmString.create('bar'),
|
150
|
+
SkmString.create('quux')]
|
150
151
|
expect( pproc.call(rtime, many)).to eq(3)
|
151
152
|
end
|
152
153
|
end # context
|
@@ -69,6 +69,7 @@ module Skeem
|
|
69
69
|
[' 3', 3],
|
70
70
|
['+3 ', +3],
|
71
71
|
['-3', -3],
|
72
|
+
['-3.0', -3],
|
72
73
|
['-1234', -1234]
|
73
74
|
]
|
74
75
|
|
@@ -167,7 +168,7 @@ module Skeem
|
|
167
168
|
end
|
168
169
|
end
|
169
170
|
|
170
|
-
context '
|
171
|
+
context 'Comments:' do
|
171
172
|
it 'should skip heading comments' do
|
172
173
|
input = "; Starting comment\n \"Some text\""
|
173
174
|
subject.reinitialize(input)
|
@@ -197,6 +198,32 @@ module Skeem
|
|
197
198
|
expect(token.terminal).to eq('STRING_LIT')
|
198
199
|
expect(token.lexeme).to eq('Second text')
|
199
200
|
end
|
201
|
+
|
202
|
+
it 'should skip block comments' do
|
203
|
+
input = '"First text" #| Middle comment |# "Second text"'
|
204
|
+
subject.reinitialize(input)
|
205
|
+
tokens = subject.tokens
|
206
|
+
expect(tokens.size).to eq(2)
|
207
|
+
token = tokens[0]
|
208
|
+
expect(token.terminal).to eq('STRING_LIT')
|
209
|
+
expect(token.lexeme).to eq('First text')
|
210
|
+
token = tokens[1]
|
211
|
+
expect(token.terminal).to eq('STRING_LIT')
|
212
|
+
expect(token.lexeme).to eq('Second text')
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'should cope with nested block comments' do
|
216
|
+
input = '"First text" #| One #| Two |# comment #| Three |# |# "Second text"'
|
217
|
+
subject.reinitialize(input)
|
218
|
+
tokens = subject.tokens
|
219
|
+
expect(tokens.size).to eq(2)
|
220
|
+
token = tokens[0]
|
221
|
+
expect(token.terminal).to eq('STRING_LIT')
|
222
|
+
expect(token.lexeme).to eq('First text')
|
223
|
+
token = tokens[1]
|
224
|
+
expect(token.terminal).to eq('STRING_LIT')
|
225
|
+
expect(token.lexeme).to eq('Second text')
|
226
|
+
end
|
200
227
|
end
|
201
228
|
|
202
229
|
context 'Scanning Scheme sample code' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: skeem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.09
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|