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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56bd360c4a30ba9dae003a18c922b150924fd0471fe74f1196e75967161ed767
4
- data.tar.gz: 90a2af34b4aa7b327656d7f889c94cead17d7a906d5db36e31d7a4ab3af5e920
3
+ metadata.gz: 4e35fb6742873b7c49a13e95be6143ae1a5cad7826f20aec0a02ba8dd98fa723
4
+ data.tar.gz: 7427071d91fa6578d37122bd953822e263f6eeba314d3d52bc5afd279052f08f
5
5
  SHA512:
6
- metadata.gz: 87827300a4e54068a2e885ef74b5aba42d21d3639a933cb4060b02b39f55b74cc15697098134ca341b1c1bceb6c027c67e1b113de9c10d4455f3b3fed0e0f009
7
- data.tar.gz: 3875d43e7c46826a7b6246f5ea07da250401281d54479bb933e0fe73b3da610ac43e1104bdacf975ad658d1ef2834a34a895b24142545cb201b59e028ad5aaa9
6
+ metadata.gz: 6f7229bba2d1cdffd83830124711b024452f82e4f3ba57219c476a4a6b07a67f3c84c13b7de2a22442f65ad82e7b414fcb429d3997047135f6e2105b2c42dece
7
+ data.tar.gz: 712805a13cff2128f340a0f75288ee81528e80114cac2815630e839c2e3c87c78efd5298a40bd47345edced3c597979a6be69b033db19478787da9f34a48af28
@@ -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, cond)
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:__
@@ -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
@@ -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 == 'set-car!' || identifier == 'set-cdr!'
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
@@ -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])
@@ -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)
@@ -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*, letrec, letrec*)
114
+ # Used to represent local binding constructs (let, let\*, letrec, letrec\*)
115
115
  class SkmBindingBlock < SkmUnaryExpression
116
116
  alias body child
117
117
 
@@ -35,6 +35,7 @@ module Skeem
35
35
  BEGIN
36
36
  COND
37
37
  DEFINE
38
+ DO
38
39
  ELSE
39
40
  IF
40
41
  LAMBDA
@@ -1,3 +1,3 @@
1
1
  module Skeem
2
- VERSION = '0.2.13'.freeze
2
+ VERSION = '0.2.14'.freeze
3
3
  end
@@ -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.13
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-22 00:00:00.000000000 Z
11
+ date: 2019-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley