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 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