skeem 0.2.13 → 0.2.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +13 -1
- data/lib/skeem/datum_dsl.rb +2 -0
- data/lib/skeem/grammar.rb +15 -1
- data/lib/skeem/primitive/primitive_builder.rb +19 -1
- data/lib/skeem/primitive/primitive_procedure.rb +1 -1
- data/lib/skeem/s_expr_builder.rb +42 -2
- data/lib/skeem/s_expr_nodes.rb +171 -8
- data/lib/skeem/skm_binding.rb +30 -44
- data/lib/skeem/skm_unary_expression.rb +1 -1
- data/lib/skeem/tokenizer.rb +1 -0
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/interpreter_spec.rb +24 -1
- data/spec/skeem/primitive/primitive_builder_spec.rb +30 -4
- 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: 4e35fb6742873b7c49a13e95be6143ae1a5cad7826f20aec0a02ba8dd98fa723
|
4
|
+
data.tar.gz: 7427071d91fa6578d37122bd953822e263f6eeba314d3d52bc5afd279052f08f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f7229bba2d1cdffd83830124711b024452f82e4f3ba57219c476a4a6b07a67f3c84c13b7de2a22442f65ad82e7b414fcb429d3997047135f6e2105b2c42dece
|
7
|
+
data.tar.gz: 712805a13cff2128f340a0f75288ee81528e80114cac2815630e839c2e3c87c78efd5298a40bd47345edced3c597979a6be69b033db19478787da9f34a48af28
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
## [0.2.14] - 2019-06-29
|
2
|
+
- Added derived expression ´do´ as an imperative iteration form.
|
3
|
+
- Added procedures: `vector-set!`
|
4
|
+
|
5
|
+
### Added
|
6
|
+
- Class `DoExpression` for the representation of the do loop expression
|
7
|
+
- Class `SkmDelayedUpdateBinding` for implementation delayed updates of bindings
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- File `tokenizer.rb` Added new keyword `do`
|
11
|
+
- File `grammar.rb` Added rules for the `do` expression syntax
|
12
|
+
- File `primitive_builder.rb` Implementation primitive procedure `vector-set!`
|
13
|
+
- File `README.md` Updated to reflect additions.
|
14
|
+
|
15
|
+
### Fixed
|
16
|
+
- Method `DatumDSL#to_datum` now supports an `SkmUndefined` input argument.
|
17
|
+
|
1
18
|
## [0.2.13] - 2019-06-22
|
2
19
|
- Skeem now accepts integers in hexadecimal notation
|
3
20
|
- Added procedures: `char->integer`, `integer->char`, `char=?`, `char<?`, `char>?`, `char<=?`, `char>=?`
|
data/README.md
CHANGED
@@ -189,9 +189,10 @@ Here are a few pointers for the Scheme programming language:
|
|
189
189
|
- Variable references
|
190
190
|
- Procedure calls
|
191
191
|
- Lambda expressions
|
192
|
-
- Conditionals (if
|
192
|
+
- Conditionals (`if`, `cond`)
|
193
193
|
- Definitions
|
194
194
|
- Assignments
|
195
|
+
- Iteration (`do`)
|
195
196
|
- Control procedures
|
196
197
|
|
197
198
|
### Standard syntactic forms
|
@@ -231,6 +232,17 @@ __Syntax:__
|
|
231
232
|
* (cond (<test\> <consequent\>)\+)
|
232
233
|
* (cond (<test\><consequent\>)* (else <alternate\>))
|
233
234
|
|
235
|
+
#### do
|
236
|
+
__Purpose:__ Sequential iteration
|
237
|
+
__Example__
|
238
|
+
```scheme
|
239
|
+
(do (
|
240
|
+
(vec (make-vector 5))
|
241
|
+
(i 0 (+ i 1)))
|
242
|
+
((= i 5) vec)
|
243
|
+
(vector-set! vec i i)) ; => #(0 1 2 3 4)
|
244
|
+
```
|
245
|
+
|
234
246
|
#### let
|
235
247
|
__Purpose:__ Define one or more variable local to the block.
|
236
248
|
__Syntax:__
|
data/lib/skeem/datum_dsl.rb
CHANGED
@@ -153,6 +153,8 @@ module Skeem
|
|
153
153
|
when SkmPair # Special case: not a PORO literal
|
154
154
|
# One assumes that a Skeem list contains only Skeem datum objects
|
155
155
|
SkmPair.create_from_a(aLiteral.to_a)
|
156
|
+
when SkmUndefined
|
157
|
+
aLiteral
|
156
158
|
else
|
157
159
|
raise StandardError, aLiteral.inspect
|
158
160
|
end
|
data/lib/skeem/grammar.rb
CHANGED
@@ -19,7 +19,7 @@ module Skeem
|
|
19
19
|
add_terminals('CHAR', 'STRING_LIT', 'IDENTIFIER')
|
20
20
|
|
21
21
|
# Keywords...
|
22
|
-
add_terminals('BEGIN', 'COND', 'DEFINE', 'ELSE')
|
22
|
+
add_terminals('BEGIN', 'COND', 'DEFINE', 'DO', 'ELSE')
|
23
23
|
add_terminals('IF', 'LAMBDA', 'LET', 'LET*')
|
24
24
|
add_terminals('QUOTE', 'QUASIQUOTE', 'SET!')
|
25
25
|
add_terminals('UNQUOTE', 'UNQUOTE-SPLICING')
|
@@ -106,6 +106,12 @@ module Skeem
|
|
106
106
|
# As the R7RS grammar is too restrictive,
|
107
107
|
# the next rule was made more general than its standard counterpart
|
108
108
|
rule('derived_expression' => 'LPAREN BEGIN body RPAREN').as 'begin_expression'
|
109
|
+
do_syntax = <<-END_SYNTAX
|
110
|
+
LPAREN DO LPAREN iteration_spec_star RPAREN
|
111
|
+
LPAREN test do_result RPAREN
|
112
|
+
command_star RPAREN
|
113
|
+
END_SYNTAX
|
114
|
+
rule('derived_expression' => do_syntax).as 'do_expression'
|
109
115
|
rule 'derived_expression' => 'quasiquotation'
|
110
116
|
rule('cond_clause_plus' => 'cond_clause_plus cond_clause').as 'multiple_cond_clauses'
|
111
117
|
rule('cond_clause_plus' => 'cond_clause').as 'last_cond_clauses'
|
@@ -120,6 +126,14 @@ module Skeem
|
|
120
126
|
rule('binding_spec_star' => 'binding_spec_star binding_spec').as 'multiple_binding_specs'
|
121
127
|
rule('binding_spec_star' => []).as 'no_binding_spec_yet'
|
122
128
|
rule('binding_spec' => 'LPAREN IDENTIFIER expression RPAREN').as 'binding_spec'
|
129
|
+
rule('iteration_spec_star' => 'iteration_spec_star iteration_spec').as 'multiple_iter_specs'
|
130
|
+
rule('iteration_spec_star' => []).as 'no_iter_spec_yet'
|
131
|
+
rule('iteration_spec' => 'LPAREN IDENTIFIER init step RPAREN').as 'iteration_spec_long'
|
132
|
+
rule('iteration_spec' => 'LPAREN IDENTIFIER init RPAREN').as 'iteration_spec_short'
|
133
|
+
rule('init' => 'expression')
|
134
|
+
rule('step' => 'expression')
|
135
|
+
rule 'do_result' => 'sequence'
|
136
|
+
rule('do_result' => []).as 'empty_do_result'
|
123
137
|
rule 'qq_template' => 'simple_datum'
|
124
138
|
rule 'qq_template' => 'list_qq_template'
|
125
139
|
rule 'qq_template' => 'vector_qq_template'
|
@@ -34,6 +34,10 @@ module Skeem
|
|
34
34
|
def binary
|
35
35
|
SkmArity.new(2, 2)
|
36
36
|
end
|
37
|
+
|
38
|
+
def ternary
|
39
|
+
SkmArity.new(3, 3)
|
40
|
+
end
|
37
41
|
|
38
42
|
def zero_or_more
|
39
43
|
SkmArity.new(0, '*')
|
@@ -143,6 +147,7 @@ module Skeem
|
|
143
147
|
create_vector_length(aRuntime)
|
144
148
|
create_make_vector(aRuntime)
|
145
149
|
create_vector_ref(aRuntime)
|
150
|
+
create_vector_set(aRuntime)
|
146
151
|
create_vector2list(aRuntime)
|
147
152
|
end
|
148
153
|
|
@@ -999,7 +1004,6 @@ module Skeem
|
|
999
1004
|
filler = arglist.first.evaluate(runtime)
|
1000
1005
|
end
|
1001
1006
|
elements = Array.new(count.value, filler)
|
1002
|
-
|
1003
1007
|
vector(elements)
|
1004
1008
|
end
|
1005
1009
|
|
@@ -1018,6 +1022,20 @@ module Skeem
|
|
1018
1022
|
|
1019
1023
|
define_primitive_proc(aRuntime, 'vector-ref', binary, primitive)
|
1020
1024
|
end
|
1025
|
+
|
1026
|
+
def create_vector_set(aRuntime)
|
1027
|
+
# Arguments aren't evaluated yet!...
|
1028
|
+
primitive = ->(runtime, vector, k, object) do
|
1029
|
+
index = k.evaluate(runtime)
|
1030
|
+
check_argtype(vector, SkmVector, 'vector', 'vector-set!')
|
1031
|
+
check_argtype(index, SkmInteger, 'integer', 'vector-set!')
|
1032
|
+
# TODO: index checking
|
1033
|
+
vector.members[index.value] = object
|
1034
|
+
vector
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
define_primitive_proc(aRuntime, 'vector-set!', ternary, primitive)
|
1038
|
+
end
|
1021
1039
|
|
1022
1040
|
def create_vector2list(aRuntime)
|
1023
1041
|
primitive = ->(runtime, arg_evaluated) do
|
@@ -135,7 +135,7 @@ module Skeem
|
|
135
135
|
result = code.send(:call, aRuntime, *args)
|
136
136
|
end
|
137
137
|
else # Fixed arity...
|
138
|
-
if identifier
|
138
|
+
if identifier.value =~ /^set-[a-zA-Z]+!/ || identifier.value =~ /[a-zA-Z]+-set!/
|
139
139
|
# Defer evaluation inside the primitive
|
140
140
|
result = code.send(:call, aRuntime, *operands)
|
141
141
|
else
|
data/lib/skeem/s_expr_builder.rb
CHANGED
@@ -88,7 +88,7 @@ module Skeem
|
|
88
88
|
# rule('expression' => 'IDENTIFIER').as 'variable_reference'
|
89
89
|
def reduce_variable_reference(_production, aRange, _tokens, theChildren)
|
90
90
|
SkmVariableReference.new(aRange, theChildren[0])
|
91
|
-
end
|
91
|
+
end
|
92
92
|
|
93
93
|
# rule('quotation' => 'APOSTROPHE datum').as 'quotation_short'
|
94
94
|
def reduce_quotation_short(_production, _range, _tokens, theChildren)
|
@@ -300,6 +300,21 @@ module Skeem
|
|
300
300
|
SkmSequencingBlock.new(theChildren[2])
|
301
301
|
end
|
302
302
|
|
303
|
+
# LPAREN DO LPAREN iteration_spec_star RPAREN
|
304
|
+
# LPAREN test do_result RPAREN
|
305
|
+
# command_star RPAREN
|
306
|
+
# rule('derived_expression' => do_syntax).as 'do_expression'
|
307
|
+
def reduce_do_expression(_production, _range, _tokens, theChildren)
|
308
|
+
# 3 => iteration_spec_star, 6 => test, 7 => do_result, 9 => command_star
|
309
|
+
|
310
|
+
# We reky on utility 'builder' object
|
311
|
+
worker = SkmDoExprBuilder.new(theChildren[3], theChildren[6],
|
312
|
+
theChildren[7], theChildren[9])
|
313
|
+
do_expression = worker.do_expression
|
314
|
+
body = { :defs => [], :sequence => do_expression }
|
315
|
+
SkmBindingBlock.new(:let_star, worker.bindings, body)
|
316
|
+
end
|
317
|
+
|
303
318
|
# rule('cond_clause_plus' => 'cond_clause_plus cond_clause').as 'multiple_cond_clauses'
|
304
319
|
def reduce_multiple_cond_clauses(_production, _range, _tokens, theChildren)
|
305
320
|
theChildren[0] << theChildren[1]
|
@@ -324,7 +339,7 @@ module Skeem
|
|
324
339
|
def reduce_cond_clause(_production, _range, _tokens, theChildren)
|
325
340
|
[theChildren[1], SkmSequencingBlock.new(SkmPair.create_from_a(theChildren[2]))]
|
326
341
|
end
|
327
|
-
|
342
|
+
|
328
343
|
# rule('cond_clause' => 'LPAREN test ARROW recipient RPAREN').as 'cond_arrow_clause'
|
329
344
|
def reduce_cond_arrow_clause(_production, _range, _tokens, theChildren)
|
330
345
|
[theChildren[1], theChildren[3]]
|
@@ -355,6 +370,31 @@ module Skeem
|
|
355
370
|
SkmBinding.new(theChildren[1], theChildren[2])
|
356
371
|
end
|
357
372
|
|
373
|
+
# rule('iteration_spec_star' => 'iteration_spec_star iteration_spec').as 'multiple_iter_specs'
|
374
|
+
def reduce_multiple_iter_specs(_production, _range, _tokens, theChildren)
|
375
|
+
theChildren[0] << theChildren[1]
|
376
|
+
end
|
377
|
+
|
378
|
+
# rule('iteration_spec_star' => []).as 'no_iter_spec_yet'
|
379
|
+
def reduce_no_iter_spec_yet(_production, _range, _tokens, _children)
|
380
|
+
[]
|
381
|
+
end
|
382
|
+
|
383
|
+
# rule('iteration_spec' => 'LPAREN IDENTIFIER init step RPAREN').as 'iteration_spec_long'
|
384
|
+
def reduce_iteration_spec_long(_production, _range, _tokens, theChildren)
|
385
|
+
SkmIterationSpec.new(theChildren[1], theChildren[2], theChildren[3])
|
386
|
+
end
|
387
|
+
|
388
|
+
# rule('iteration_spec' => 'LPAREN IDENTIFIER init RPAREN').as 'iteration_spec_short'
|
389
|
+
def reduce_iteration_spec_short(_production, _range, _tokens, theChildren)
|
390
|
+
SkmIterationSpec.new(theChildren[1], theChildren[2], nil)
|
391
|
+
end
|
392
|
+
|
393
|
+
# rule('do_result' => []).as 'empty_do_result'
|
394
|
+
def reduce_empty_do_result(_production, _range, _tokens, theChildren)
|
395
|
+
SkmEmptyList.instance
|
396
|
+
end
|
397
|
+
|
358
398
|
# rule('list_qq_template' => 'LPAREN qq_template_or_splice_star RPAREN').as 'list_qq'
|
359
399
|
def reduce_list_qq(_production, _range, _tokens, theChildren)
|
360
400
|
SkmPair.create_from_a(theChildren[1])
|
data/lib/skeem/s_expr_nodes.rb
CHANGED
@@ -264,7 +264,7 @@ module Skeem
|
|
264
264
|
|
265
265
|
result
|
266
266
|
end
|
267
|
-
|
267
|
+
|
268
268
|
def quasiquote(aRuntime)
|
269
269
|
quasi_clauses = clauses.map do |(test, consequent)|
|
270
270
|
test_qq = test.quasiquote(aRuntime)
|
@@ -272,21 +272,21 @@ module Skeem
|
|
272
272
|
[test_qq, consequent_qq]
|
273
273
|
end
|
274
274
|
quasi_alternate = alternate ? alternate.quasiquote(aRuntime) : nil
|
275
|
-
|
275
|
+
|
276
276
|
self.class.new(position, quasi_clauses, quasi_alternate)
|
277
277
|
end
|
278
278
|
|
279
279
|
def inspect
|
280
280
|
result = inspect_prefix + '@test ' + test.inspect + ', '
|
281
|
-
result << "@clauses \n"
|
281
|
+
result << "@clauses \n"
|
282
282
|
clauses.each do |(test, consequent)|
|
283
283
|
result << ' ' << test.inspect << ' ' << consequent.inspect << "\n"
|
284
284
|
end
|
285
285
|
result << '@alternate ' + alternate.inspect + inspect_suffix
|
286
286
|
result
|
287
|
-
end
|
287
|
+
end
|
288
288
|
end # class
|
289
|
-
|
289
|
+
|
290
290
|
SkmArity = Struct.new(:low, :high) do
|
291
291
|
def nullary?
|
292
292
|
low.zero? && high == 0
|
@@ -313,6 +313,169 @@ module Skeem
|
|
313
313
|
end
|
314
314
|
end
|
315
315
|
|
316
|
+
class SkmIterationSpec
|
317
|
+
attr_reader :variable
|
318
|
+
attr_reader :init_expr
|
319
|
+
attr_reader :step_expr
|
320
|
+
|
321
|
+
def initialize(anIdentifier, anInitialization, aStep)
|
322
|
+
@variable = anIdentifier
|
323
|
+
@init_expr = anInitialization
|
324
|
+
@step_expr = aStep
|
325
|
+
end
|
326
|
+
end # class
|
327
|
+
|
328
|
+
class SkmDoExprBuilder
|
329
|
+
attr_reader :bindings
|
330
|
+
attr_reader :update_steps
|
331
|
+
attr_reader :test
|
332
|
+
attr_reader :do_result
|
333
|
+
attr_reader :commands
|
334
|
+
|
335
|
+
# 3 => iteration_spec_star, 6 => test, 7 => do_result, 9 => command_star
|
336
|
+
|
337
|
+
def initialize(iterSpecs, aTest, doResult, theCommands)
|
338
|
+
iteration_specs_set(iterSpecs)
|
339
|
+
@test = aTest
|
340
|
+
@do_result = doResult
|
341
|
+
commands_set(theCommands)
|
342
|
+
end
|
343
|
+
|
344
|
+
def do_expression
|
345
|
+
DoExpression.new(test, do_result, commands, update_steps)
|
346
|
+
end
|
347
|
+
|
348
|
+
private
|
349
|
+
|
350
|
+
def iteration_specs_set(iterSpecs)
|
351
|
+
@bindings = iterSpecs.map do |iter_spec|
|
352
|
+
var = iter_spec.variable
|
353
|
+
val = iter_spec.init_expr
|
354
|
+
SkmBinding.new(var, val)
|
355
|
+
end
|
356
|
+
|
357
|
+
to_update = iterSpecs.select { |iter_spec| iter_spec.step_expr }
|
358
|
+
if to_update
|
359
|
+
steps = to_update.map do |iter_spec|
|
360
|
+
SkmDelayedUpdateBinding.new(iter_spec.variable, iter_spec.step_expr)
|
361
|
+
end
|
362
|
+
if steps.size == 1
|
363
|
+
@update_steps = steps[0]
|
364
|
+
else
|
365
|
+
@update_steps = SkmPair.create_from_a(steps)
|
366
|
+
end
|
367
|
+
else
|
368
|
+
@update_steps = SkmEmptyList.instance
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def commands_set(theCommands)
|
373
|
+
case theCommands.size
|
374
|
+
when 0
|
375
|
+
@commands = SkmEmptyList.instance
|
376
|
+
when 1
|
377
|
+
@commands = theCommands[0]
|
378
|
+
else
|
379
|
+
@commands = SkmSequencingBlock.new(SkmPair.create_from_a(theCommands))
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end # class
|
383
|
+
|
384
|
+
# Syntax outline:
|
385
|
+
# LPAREN DO LPAREN iteration_spec_star RPAREN
|
386
|
+
# LPAREN test do_result RPAREN
|
387
|
+
# command_star RPAREN
|
388
|
+
# Semantics:
|
389
|
+
# Initialization:
|
390
|
+
# Set of variables is initialized (each with its init expression)
|
391
|
+
# Iteration:
|
392
|
+
# test expression is evaluation
|
393
|
+
# if false:
|
394
|
+
# command expressions are executed in order
|
395
|
+
# step expressions are executed and bound to the respective variable
|
396
|
+
# iteration resumes
|
397
|
+
# if true:
|
398
|
+
# the do_result expressions are excuted
|
399
|
+
# value of last expression is returned
|
400
|
+
# ; (do ((vec (make-vector 5))
|
401
|
+
# ; (i 0 (+ i 1)))
|
402
|
+
# ; ((= i 5) vec)
|
403
|
+
# ; (vector-set! vec i i))
|
404
|
+
# Can be transformed into:
|
405
|
+
# (let* (
|
406
|
+
# ;; Variable init
|
407
|
+
# (vec (make-vector 5))
|
408
|
+
# (i 0)
|
409
|
+
# ;; Utility procedures
|
410
|
+
# (update-step (lambda ()
|
411
|
+
# (begin
|
412
|
+
# (set! i (+ i 1))
|
413
|
+
# )))
|
414
|
+
# (do-results (lambda ()
|
415
|
+
# (begin
|
416
|
+
# vec
|
417
|
+
# )))
|
418
|
+
# (do-commands (lambda ()
|
419
|
+
# (begin
|
420
|
+
# (vector-set! vec i i)
|
421
|
+
# ))))
|
422
|
+
# (begin
|
423
|
+
# (define do-iteration (lambda ()
|
424
|
+
# (if (= i 5)
|
425
|
+
# (do-results)
|
426
|
+
# (begin
|
427
|
+
# (do-commands)
|
428
|
+
# (update-step)
|
429
|
+
# (do-iteration))))))
|
430
|
+
# (do-iteration))
|
431
|
+
class DoExpression < SkmMultiExpression
|
432
|
+
# iterate until the test expression becomes true
|
433
|
+
attr_reader :test
|
434
|
+
|
435
|
+
# expression to execute in each iteration
|
436
|
+
attr_reader :commands
|
437
|
+
|
438
|
+
# expression to execute before return
|
439
|
+
attr_reader :do_result
|
440
|
+
|
441
|
+
# Update variables
|
442
|
+
attr_reader :update_steps
|
443
|
+
|
444
|
+
def initialize(aTest, doResult, theCommands, theUpdates)
|
445
|
+
@test = aTest
|
446
|
+
@do_result = doResult
|
447
|
+
@commands = theCommands
|
448
|
+
@update_steps = theUpdates
|
449
|
+
end
|
450
|
+
|
451
|
+
def evaluate(aRuntime)
|
452
|
+
# require 'debug'
|
453
|
+
loop do
|
454
|
+
test_result = test.evaluate(aRuntime)
|
455
|
+
if test_result.boolean? && test_result.value == false
|
456
|
+
# Only #f is considered as false, everything else is true
|
457
|
+
commands.evaluate(aRuntime) if commands
|
458
|
+
if update_steps
|
459
|
+
update_steps.evaluate(aRuntime)
|
460
|
+
case update_steps
|
461
|
+
when SkmEmptyList.instance
|
462
|
+
; Do nothing
|
463
|
+
when SkmPair
|
464
|
+
arr = update_steps.to_a
|
465
|
+
arr.each { |delayed_binding| delayed_binding.do_it!(aRuntime) }
|
466
|
+
else
|
467
|
+
update_steps.do_it!(aRuntime)
|
468
|
+
end
|
469
|
+
end
|
470
|
+
else
|
471
|
+
break
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
do_result ? do_result.evaluate(aRuntime) : SkmUndefined.instance
|
476
|
+
end
|
477
|
+
end # class
|
478
|
+
|
316
479
|
class SkmFormals
|
317
480
|
attr_reader :formals
|
318
481
|
attr_reader :arity
|
@@ -384,7 +547,7 @@ module Skeem
|
|
384
547
|
def callable?
|
385
548
|
true
|
386
549
|
end
|
387
|
-
|
550
|
+
|
388
551
|
def procedure?
|
389
552
|
true
|
390
553
|
end
|
@@ -540,10 +703,10 @@ require_relative 'skm_procedure_exec'
|
|
540
703
|
def callable?
|
541
704
|
true
|
542
705
|
end
|
543
|
-
|
706
|
+
|
544
707
|
def procedure?
|
545
708
|
true
|
546
|
-
end
|
709
|
+
end
|
547
710
|
=begin
|
548
711
|
TODO
|
549
712
|
def quasiquote(aRuntime)
|
data/lib/skeem/skm_binding.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
require_relative 'skm_element'
|
2
2
|
|
3
3
|
module Skeem
|
4
|
-
|
4
|
+
|
5
5
|
# An identifier that is not a syntactic keyword can be used as a variable.
|
6
6
|
# A variable may give a name to value that is bound (i.e. associated)
|
7
7
|
# to that variable.
|
8
8
|
class SkmBinding < SkmElement
|
9
9
|
# @return [SkmIdentifier] The identifier that is bound the value.
|
10
10
|
attr_reader(:variable)
|
11
|
-
|
11
|
+
|
12
12
|
# @return [SkmElement] The Skeem object that is associated with the variable.
|
13
13
|
attr_reader(:value)
|
14
|
-
|
14
|
+
|
15
15
|
# Constructor
|
16
16
|
# @param anIdentifier [SkmIdentifier] The variable name
|
17
17
|
# @param aValue [SkmElement] The value to bind to the variable.
|
@@ -19,7 +19,7 @@ module Skeem
|
|
19
19
|
@variable = anIdentifier
|
20
20
|
@value = aValue
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def evaluate(aRuntime)
|
24
24
|
name = variable.evaluate(aRuntime)
|
25
25
|
|
@@ -38,44 +38,12 @@ module Skeem
|
|
38
38
|
else
|
39
39
|
result = value.evaluate(aRuntime)
|
40
40
|
end
|
41
|
-
|
42
|
-
=begin
|
43
|
-
aRuntime.add_binding(var_key, self)
|
44
|
-
case expression
|
45
|
-
when SkmLambda
|
46
|
-
result = expression.evaluate(aRuntime)
|
47
|
-
|
48
|
-
when SkmVariableReference
|
49
|
-
other_key = expression.variable.evaluate(aRuntime)
|
50
|
-
if var_key.value != other_key.value
|
51
|
-
entry = aRuntime.fetch(other_key)
|
52
|
-
result = expression.evaluate(aRuntime)
|
53
|
-
if entry.kind_of?(Primitive::PrimitiveProcedure)
|
54
|
-
@expression = entry
|
55
|
-
elsif entry.kind_of?(SkmDefinition)
|
56
|
-
if entry.expression.kind_of?(SkmLambda)
|
57
|
-
@expression = entry.expression
|
58
|
-
end
|
59
|
-
end
|
60
|
-
else
|
61
|
-
# INFINITE LOOP DANGER: definition of 'x' has a reference to 'x'!
|
62
|
-
# Way out: the lookup for the reference should start from outer
|
63
|
-
# environment.
|
64
|
-
env = aRuntime.pop
|
65
|
-
@expression = expression.evaluate(aRuntime)
|
66
|
-
aRuntime.push(env)
|
67
|
-
result = expression
|
68
|
-
end
|
69
|
-
else
|
70
|
-
result = self
|
71
|
-
end
|
72
|
-
=end
|
73
41
|
binding_action(aRuntime, name, result)
|
74
42
|
result
|
75
43
|
end
|
76
|
-
|
44
|
+
|
77
45
|
protected
|
78
|
-
|
46
|
+
|
79
47
|
def binding_action(aRuntime, anIdentifier, anExpression)
|
80
48
|
aRuntime.add_binding(anIdentifier, anExpression)
|
81
49
|
end
|
@@ -87,17 +55,35 @@ module Skeem
|
|
87
55
|
end
|
88
56
|
|
89
57
|
result
|
90
|
-
end
|
91
|
-
|
58
|
+
end
|
59
|
+
|
92
60
|
end # class
|
93
|
-
|
61
|
+
|
94
62
|
|
95
63
|
class SkmUpdateBinding < SkmBinding
|
96
|
-
|
64
|
+
|
97
65
|
protected
|
98
|
-
|
66
|
+
|
99
67
|
def binding_action(aRuntime, anIdentifier, anExpression)
|
100
68
|
aRuntime.update_binding(anIdentifier, anExpression)
|
101
|
-
end
|
69
|
+
end
|
102
70
|
end # class
|
71
|
+
|
72
|
+
class SkmDelayedUpdateBinding < SkmBinding
|
73
|
+
attr_reader :new_val
|
74
|
+
|
75
|
+
def initialize(anIdentifier, aValue)
|
76
|
+
super(anIdentifier, aValue)
|
77
|
+
end
|
78
|
+
|
79
|
+
def do_it!(aRuntime)
|
80
|
+
aRuntime.update_binding(variable, new_val)
|
81
|
+
end
|
82
|
+
|
83
|
+
protected
|
84
|
+
|
85
|
+
def binding_action(_runtime, _identifier, anExpression)
|
86
|
+
@new_val = anExpression
|
87
|
+
end
|
88
|
+
end # class
|
103
89
|
end # module
|
@@ -111,7 +111,7 @@ module Skeem
|
|
111
111
|
end
|
112
112
|
end # class
|
113
113
|
|
114
|
-
# Used to represent local binding constructs (let, let
|
114
|
+
# Used to represent local binding constructs (let, let\*, letrec, letrec\*)
|
115
115
|
class SkmBindingBlock < SkmUnaryExpression
|
116
116
|
alias body child
|
117
117
|
|
data/lib/skeem/tokenizer.rb
CHANGED
data/lib/skeem/version.rb
CHANGED
@@ -718,7 +718,7 @@ SKEEM
|
|
718
718
|
["(not 'nil)", false]
|
719
719
|
]
|
720
720
|
compare_to_predicted(checks)
|
721
|
-
end
|
721
|
+
end
|
722
722
|
|
723
723
|
it 'should implement the list procedure' do
|
724
724
|
checks = [
|
@@ -874,5 +874,28 @@ SKEEM
|
|
874
874
|
expect(result.last).to eq(80)
|
875
875
|
end
|
876
876
|
end # context
|
877
|
+
|
878
|
+
context 'Derived expressions' do
|
879
|
+
it 'should implement the do form' do
|
880
|
+
source = <<-SKEEM
|
881
|
+
(do ((vec (make-vector 5))
|
882
|
+
(i 0 (+ i 1)))
|
883
|
+
((= i 5) vec)
|
884
|
+
(vector-set! vec i i)) ; => #(0 1 2 3 4)
|
885
|
+
SKEEM
|
886
|
+
result = subject.run(source)
|
887
|
+
expect(result).to eq([0, 1, 2, 3, 4])
|
888
|
+
|
889
|
+
source = <<-SKEEM
|
890
|
+
(let ((x '(1 3 5 7 9)))
|
891
|
+
(do (
|
892
|
+
(x x (cdr x))
|
893
|
+
(sum 0 (+ sum (car x))))
|
894
|
+
((null? x) sum))) ; => 25
|
895
|
+
SKEEM
|
896
|
+
result = subject.run(source)
|
897
|
+
expect(result).to eq(25)
|
898
|
+
end
|
899
|
+
end # context
|
877
900
|
end # describe
|
878
901
|
end # module
|
@@ -13,6 +13,10 @@ module Skeem
|
|
13
13
|
Interpreter.new { |interp| interp.add_primitives(interp.runtime) }
|
14
14
|
end
|
15
15
|
|
16
|
+
def array2list_ids(arr)
|
17
|
+
arr.map { |elem| SkmIdentifier.create(elem) }
|
18
|
+
end
|
19
|
+
|
16
20
|
context 'Arithmetic operators:' do
|
17
21
|
it 'should implement the set! form' do
|
18
22
|
skeem1 = <<-SKEEM
|
@@ -631,10 +635,6 @@ SKEEM
|
|
631
635
|
compare_to_predicted(checks)
|
632
636
|
end
|
633
637
|
|
634
|
-
def array2list_ids(arr)
|
635
|
-
arr.map { |elem| SkmIdentifier.create(elem) }
|
636
|
-
end
|
637
|
-
|
638
638
|
it 'should implement the append procedure' do
|
639
639
|
checks = [
|
640
640
|
["(append '(a b c) '())", array2list_ids(['a', 'b', 'c'])],
|
@@ -898,6 +898,32 @@ SKEEM
|
|
898
898
|
expect(result).to eq(8)
|
899
899
|
end
|
900
900
|
|
901
|
+
it 'should implement the vector-set! procedure' do
|
902
|
+
source =<<-SKEEM
|
903
|
+
(let
|
904
|
+
((vec (vector 0 '(2 2 2 2) "Anna")))
|
905
|
+
(vector-set! vec 1 '("Sue" "Sue"))
|
906
|
+
vec)
|
907
|
+
SKEEM
|
908
|
+
#(0 ("Sue" "Sue") "Anna")
|
909
|
+
result = subject.run(source)
|
910
|
+
expect(result).to be_kind_of(SkmVector)
|
911
|
+
expectation = [SkmInteger.create(0),
|
912
|
+
SkmPair.new(SkmString.create("Sue"), SkmPair.new(SkmString.create("Sue"), SkmEmptyList.instance)),
|
913
|
+
SkmString.create("Anna") ]
|
914
|
+
expect(result).to eq(expectation)
|
915
|
+
|
916
|
+
source =<<-SKEEM
|
917
|
+
(let (
|
918
|
+
(v (vector 'a 'b 'c 'd 'e)))
|
919
|
+
(vector-set! v 2 'x)
|
920
|
+
v)
|
921
|
+
SKEEM
|
922
|
+
result = subject.run(source)
|
923
|
+
expect(result).to be_kind_of(SkmVector)
|
924
|
+
expect(result).to eq(array2list_ids(['a', 'b', 'x', 'd', 'e']))
|
925
|
+
end
|
926
|
+
|
901
927
|
it 'should implement the vector->list procedure' do
|
902
928
|
checks = [
|
903
929
|
["(vector->list #())", []],
|
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.14
|
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-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|