skeem 0.2.13 → 0.2.14
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 +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
|