skeem 0.0.24 → 0.0.25

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
  SHA1:
3
- metadata.gz: e1f6bf0ae4407a85eb404c02c2497964744c26b2
4
- data.tar.gz: f66450bf98cb129a7e40499bf589ef6454760c12
3
+ metadata.gz: bb979d01736d3b23101b56c2b7c21dff003eed46
4
+ data.tar.gz: 91dddadb24f3e6cc1aa146f7c5420d4d88708d56
5
5
  SHA512:
6
- metadata.gz: f07d638db941e45c54717ba99addfdb627ba9c76ace292905bb3fa3687888a42a633f51cc9dc6975d058f6995782e56f9a7439cc8e0a0086c1a4ba93be84040a
7
- data.tar.gz: 03b924927a3cf1e08780de16743403ab17ca68646e17f1f1b36bcfc58f3478cf403d09c2cf0626306f83dc60e6b06c4a9df57502500ca246361bbcc641833bc7
6
+ metadata.gz: 1a3db261dbca2bf57909b90de1db6897026eea3baa739e80a52c2ee045eee1be23d685d903757ed1fb1ca92daac80cbbcdc9fb015d7f6daeb7d275262f5952fe
7
+ data.tar.gz: 27f38b7d92bbe22f339de58945fd7dad7efc9b57ffc1257f626fd3d97b5bd063c3432eb124e28e75d67ff35f7bf75470af15ea8ddb633850d4b21b76e122012f
data/README.md CHANGED
@@ -129,6 +129,7 @@ Here are a few pointers for the Scheme programming language:
129
129
  - Lambda expressions
130
130
  - If conditionals
131
131
  - Definitions
132
+ - Assignments
132
133
 
133
134
  ### Standard syntactic forms
134
135
  #### define
@@ -155,6 +156,13 @@ __Syntax:__
155
156
  * (quote <datum\>)
156
157
  * '<datum\>
157
158
 
159
+ #### set!
160
+ __Purpose:__ Assign to an existing variable an expression/value to it.
161
+ __Syntax:__
162
+ * (set! <identifier\> <expression\>)
163
+
164
+
165
+
158
166
  ### Standard library
159
167
  This section lists the implemented standard procedures
160
168
 
@@ -170,10 +178,10 @@ This section lists the implemented standard procedures
170
178
  * `list?`, `null?`, `list`, `length`
171
179
 
172
180
  #### String procedures
173
- * `string?`, `string-append`, `string-length`, `string->symbol`,
181
+ * `string?`, `string=?`, `string-append`, `string-length`, `string->symbol`,
174
182
 
175
183
  #### Symbol procedures
176
- * `symbol?`
184
+ * `symbol?`, `symbol=?`
177
185
 
178
186
  #### Vector procedures
179
187
  * `vector?`, `vector`, `vector-length`, `vector-set!`
@@ -1,11 +1,13 @@
1
1
  require_relative 'primitive_procedure'
2
2
  require_relative '../datum_dsl'
3
+ # require_relative '../s_expr_nodes'
3
4
 
4
5
  module Skeem
5
6
  module Primitive
6
7
  module PrimitiveBuilder
7
8
  include DatumDSL
8
9
  def add_primitives(aRuntime)
10
+ add_binding(aRuntime)
9
11
  add_arithmetic(aRuntime)
10
12
  add_comparison(aRuntime)
11
13
  add_number_procedures(aRuntime)
@@ -40,6 +42,10 @@ module Skeem
40
42
  SkmArity.new(1, '*')
41
43
  end
42
44
 
45
+ def add_binding(aRuntime)
46
+ create_set!(aRuntime)
47
+ end
48
+
43
49
  def add_arithmetic(aRuntime)
44
50
  create_plus(aRuntime)
45
51
  create_minus(aRuntime)
@@ -72,6 +78,7 @@ module Skeem
72
78
 
73
79
  def add_string_procedures(aRuntime)
74
80
  create_object_predicate(aRuntime, 'string?')
81
+ create_string_equal(aRuntime)
75
82
  create_string_append(aRuntime)
76
83
  create_string_length(aRuntime)
77
84
  create_string2symbol(aRuntime)
@@ -102,6 +109,19 @@ module Skeem
102
109
  create_debug(aRuntime)
103
110
  end
104
111
 
112
+ def create_set!(aRuntime)
113
+ primitive = ->(runtime, var_ref, expr) do
114
+ if runtime.include?(var_ref.child)
115
+ redefinition = SkmDefinition.new(nil, var_ref.child, expr)
116
+ redefinition.evaluate(runtime)
117
+ else
118
+ raise StandardError, "Unbound variable: '#{var.value}'"
119
+ end
120
+ end
121
+
122
+ define_primitive_proc(aRuntime, 'set!', binary, primitive)
123
+ end
124
+
105
125
  def create_plus(aRuntime)
106
126
  # arglist should be a Ruby Array
107
127
  primitive = ->(runtime, arglist) do
@@ -338,6 +358,22 @@ module Skeem
338
358
  define_primitive_proc(aRuntime, 'or', zero_or_more, primitive)
339
359
  end
340
360
 
361
+ def create_string_equal(aRuntime)
362
+ primitive = ->(runtime, first_operand, arglist) do
363
+ first_one = first_operand.evaluate(runtime)
364
+ if arglist.empty?
365
+ boolean(true)
366
+ else
367
+ operands = evaluate_array(arglist, runtime)
368
+ first_value = first_one.value
369
+ all_equal = operands.all? { |elem| first_value == elem.value }
370
+ boolean(all_equal)
371
+ end
372
+ end
373
+
374
+ define_primitive_proc(aRuntime, 'string=?', one_or_more, primitive)
375
+ end
376
+
341
377
  def create_string_append(aRuntime)
342
378
  primitive = ->(runtime, arglist) do
343
379
  if arglist.empty?
data/lib/skeem/runtime.rb CHANGED
@@ -12,6 +12,11 @@ module Skeem
12
12
  def include?(anIdentifier)
13
13
  environment.include?(normalize_key(anIdentifier))
14
14
  end
15
+
16
+ def fetch(aKey)
17
+ key_value = normalize_key(aKey)
18
+ include?(key_value) ? environment.fetch(key_value) : nil
19
+ end
15
20
 
16
21
  def define(aKey, anEntry)
17
22
  environment.define(normalize_key(aKey), anEntry)
@@ -20,8 +25,15 @@ module Skeem
20
25
  def evaluate(aKey)
21
26
  key_value = normalize_key(aKey)
22
27
  if include?(key_value)
23
- definition = environment.fetch(key_value)
24
- definition.expression.evaluate(self)
28
+ entry = environment.fetch(key_value)
29
+ case entry
30
+ when Primitive::PrimitiveProcedure
31
+ entry
32
+ when SkmDefinition
33
+ entry.expression.evaluate(self)
34
+ else
35
+ raise StandardError, entry.inspect
36
+ end
25
37
  else
26
38
  err = StandardError
27
39
  key = aKey.kind_of?(SkmIdentifier) ? aKey.value : key_value
@@ -58,8 +58,16 @@ module Skeem
58
58
  when SkmVariableReference
59
59
  other_key = expression.variable.evaluate(aRuntime)
60
60
  if var_key.value != other_key.value
61
+ entry = aRuntime.fetch(other_key)
61
62
  result = expression.evaluate(aRuntime)
62
- else
63
+ if entry.kind_of?(Primitive::PrimitiveProcedure)
64
+ @expression = entry
65
+ elsif entry.kind_of?(SkmDefinition)
66
+ if entry.expression.kind_of?(SkmLambda)
67
+ @expression = entry.expression
68
+ end
69
+ end
70
+ else
63
71
  # INFINITE LOOP DANGER: definition of 'x' is a reference to 'x'!
64
72
  # Way out: the lookup for the reference should start from outer
65
73
  # environment.
@@ -88,7 +96,7 @@ module Skeem
88
96
 
89
97
  # call method should only invoked when the expression is a SkmLambda
90
98
  def call(aRuntime, aProcedureCall)
91
- unless expression.kind_of?(SkmLambda)
99
+ unless [SkmLambda, Primitive::PrimitiveProcedure].include?(expression.class)
92
100
  err_msg = "Expected a SkmLambda instead of #{expression.class}"
93
101
  raise StandardError, err_msg
94
102
  end
@@ -45,5 +45,7 @@
45
45
  (lambda (z)
46
46
  (* z z)))
47
47
 
48
+ (define symbol=? string=?)
49
+
48
50
  (define list
49
51
  (lambda args args))
data/lib/skeem/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Skeem
2
- VERSION = '0.0.24'.freeze
2
+ VERSION = '0.0.25'.freeze
3
3
  end
@@ -1,9 +1,12 @@
1
1
  require 'stringio'
2
2
  require_relative '../spec_helper' # Use the RSpec framework
3
+ require_relative '../../lib/skeem/datum_dsl'
3
4
  require_relative '../../lib/skeem/interpreter' # Load the class under test
4
5
 
5
6
  module Skeem
6
7
  describe Interpreter do
8
+ include DatumDSL
9
+
7
10
  context 'Initialization:' do
8
11
  it 'should be initialized without argument' do
9
12
  expect { Interpreter.new() }.not_to raise_error
@@ -329,6 +332,41 @@ SKEEM
329
332
  expect(result.members[index]).to eq(value)
330
333
  end
331
334
  end
335
+
336
+ it 'should implement the unquote of vectors' do
337
+ source = '`#( ,(+ 1 2) 4)'
338
+ result = subject.run(source)
339
+ expect(result).to be_kind_of(SkmVector)
340
+ predictions = [
341
+ [SkmInteger, 3],
342
+ [SkmInteger, 4]
343
+ ]
344
+ predictions.each_with_index do |(type, value), index|
345
+ expect(result.members[index]).to be_kind_of(type)
346
+ expect(result.members[index]).to eq(value)
347
+ end
348
+
349
+ source = "`#()"
350
+ result = subject.run(source)
351
+ expect(result).to be_kind_of(SkmVector)
352
+ expect(result).to be_empty
353
+
354
+ # Nested vectors
355
+ source = '`#(a b #(,(+ 2 3) c) d)'
356
+ result = subject.run(source)
357
+ # expected: #(a b #(5 c) d)
358
+ expect(result).to be_kind_of(SkmVector)
359
+ predictions = [
360
+ [SkmIdentifier, 'a'],
361
+ [SkmIdentifier, 'b'],
362
+ [SkmVector, vector([integer(5), identifier('c')])],
363
+ [SkmIdentifier, 'd']
364
+ ]
365
+ predictions.each_with_index do |(type, value), index|
366
+ expect(result.members[index]).to be_kind_of(type)
367
+ expect(result.members[index]).to eq(value)
368
+ end
369
+ end
332
370
 
333
371
  it 'should implement the quasiquotation of lists' do
334
372
  source = '(quasiquote (+ 1 2))'
@@ -368,10 +406,25 @@ SKEEM
368
406
  result = subject.run(source)
369
407
  expect(result).to be_kind_of(SkmList)
370
408
  expect(result).to be_null
409
+
410
+ # nested lists
411
+ source = '`(a b (,(+ 2 3) c) d)'
412
+ result = subject.run(source)
413
+ # expected: (a b (5 c) d)
414
+ expect(result).to be_kind_of(SkmList)
415
+ predictions = [
416
+ [SkmIdentifier, 'a'],
417
+ [SkmIdentifier, 'b'],
418
+ [SkmList, list([integer(5), identifier('c')])],
419
+ [SkmIdentifier, 'd']
420
+ ]
421
+ predictions.each_with_index do |(type, value), index|
422
+ expect(result.members[index]).to be_kind_of(type)
423
+ expect(result.members[index]).to eq(value)
424
+ end
371
425
  end
372
426
  =begin
373
427
  `(+ 2 ,(* 3 4)) (+ 2 12)
374
- `(a b (,(+ 2 3) c) d) (a b (5 c) d)
375
428
  `(a b ,(reverse '(c d e)) f g) (a b (e d c) f g)
376
429
  (let ([a 1] [b 2])
377
430
  `(,a . ,b)) (1 . 2)
@@ -514,6 +567,18 @@ SKEEM
514
567
  expect(result).to eq(expectation)
515
568
  end
516
569
  end
570
+
571
+ it 'should implement the symbol=? procedure' do
572
+ checks = [
573
+ ["(symbol=? 'a 'a)", true],
574
+ ["(symbol=? 'a (string->symbol \"a\"))", true],
575
+ ["(symbol=? 'a 'b)", false]
576
+ ]
577
+ checks.each do |(skeem_expr, expectation)|
578
+ result = subject.run(skeem_expr)
579
+ expect(result).to eq(expectation)
580
+ end
581
+ end
517
582
 
518
583
  it 'should implement the list procedure' do
519
584
  checks = [
@@ -6,8 +6,26 @@ require_relative '../../../lib/skeem/interpreter'
6
6
  module Skeem
7
7
  module Primitive
8
8
  describe 'Testing primitive procedures' do
9
- subject { Interpreter.new }
10
- context 'Arithmetic operators:' do
9
+ subject { Interpreter.new }
10
+
11
+ context 'Arithmetic operators:' do
12
+ it 'should implement the set! form' do
13
+ skeem1 = <<-SKEEM
14
+ (define x 2)
15
+ (+ x 1)
16
+ SKEEM
17
+ result = subject.run(skeem1)
18
+ expect(result.last).to eq(3) # x is bound to value 2
19
+ skeem2 = <<-SKEEM
20
+ (set! x 4)
21
+ (+ x 1)
22
+ SKEEM
23
+ result = subject.run(skeem2)
24
+ expect(result.last).to eq(5) # x is now bound to value 4
25
+ end
26
+ end # context
27
+
28
+ context 'Arithmetic operators:' do
11
29
  it 'should implement the addition operator' do
12
30
  [
13
31
  ['(+)', 0], # '+' as nullary operator. Example from section 6.2.6
@@ -294,6 +312,18 @@ module Skeem
294
312
  end
295
313
  end
296
314
 
315
+ it 'should implement the string=? procedure' do
316
+ checks = [
317
+ ['(string=? "Mom" "Mom")', true],
318
+ ['(string=? "Mom" "Mum")', false],
319
+ ['(string=? "Mom" "Dad")', false]
320
+ ]
321
+ checks.each do |(skeem_expr, expectation)|
322
+ result = subject.run(skeem_expr)
323
+ expect(result).to eq(expectation)
324
+ end
325
+ end
326
+
297
327
  it 'should implement the string-append procedure' do
298
328
  checks = [
299
329
  ['(string-append)', ''],
@@ -323,22 +353,24 @@ module Skeem
323
353
  it 'should implement the symbol? procedure' do
324
354
  checks = [
325
355
  ['(symbol? #f)', false],
326
- ['(symbol? "bar")', false]
356
+ ['(symbol? "bar")', false],
357
+ ["(symbol? '())", false],
358
+ ["(symbol? 'foo)", true],
327
359
  ]
328
360
  checks.each do |(skeem_expr, expectation)|
329
361
  result = subject.run(skeem_expr)
330
362
  expect(result).to eq(expectation)
331
363
  end
332
- end
364
+ end
333
365
  end # context
334
366
 
335
367
  context 'List procedures:' do
336
368
  it 'should implement the list? procedure' do
337
369
  checks = [
338
- #['(list? #f)', false],
339
- #['(list? 1)', false],
340
- #['(list? "bar")', false],
341
- #['(list? (list 1 2 3))', true],
370
+ ['(list? #f)', false],
371
+ ['(list? 1)', false],
372
+ ['(list? "bar")', false],
373
+ ['(list? (list 1 2 3))', true],
342
374
  ['(list? (list))', true]
343
375
  ]
344
376
  checks.each do |(skeem_expr, expectation)|
@@ -39,14 +39,14 @@ module Skeem
39
39
  context 'Evaluation:' do
40
40
  include Primitive::PrimitiveBuilder
41
41
 
42
- it 'should evaluate a given entry' do
43
- entry = double('three')
44
- result = double('fake-procedure')
45
- expect(entry).to receive(:expression).and_return(result)
46
- expect(result).to receive(:evaluate).with(subject).and_return(integer(3))
47
- subject.define('three', entry)
48
- expect(subject.evaluate('three')).to eq(3)
49
- end
42
+ # it 'should evaluate a given entry' do
43
+ # entry = integer(3)
44
+ # result = double('fake-procedure')
45
+ # expect(entry).to receive(:expression).and_return(result)
46
+ # expect(result).to receive(:evaluate).with(subject).and_return(integer(3))
47
+ # subject.define('three', entry)
48
+ # expect(subject.evaluate('three')).to eq(3)
49
+ # end
50
50
 
51
51
  it 'should evaluate a given list' do
52
52
  add_primitives(subject)
@@ -1,6 +1,7 @@
1
1
  require 'ostruct'
2
2
  require_relative '../spec_helper' # Use the RSpec framework
3
3
  require_relative '../../lib/skeem/runtime'
4
+ require_relative '../../lib/skeem/primitive/primitive_builder'
4
5
  require_relative '../../lib/skeem/s_expr_nodes' # Load the classes under test
5
6
 
6
7
  module Skeem
@@ -26,6 +27,8 @@ module Skeem
26
27
  end # context
27
28
 
28
29
  context 'Provided services:' do
30
+ include Primitive::PrimitiveBuilder
31
+
29
32
  let(:runtime) { Runtime.new(Environment.new) }
30
33
 
31
34
  it 'should create an entry when evaluating' do
@@ -34,6 +37,39 @@ module Skeem
34
37
  expect(runtime).to include(sample_symbol)
35
38
  end
36
39
 
40
+ it 'should optimize an entry that aliases a primitive proc' do
41
+ add_primitives(runtime)
42
+ identifier = SkmIdentifier.create('plus')
43
+ proc_name = SkmIdentifier.create('+')
44
+ var_ref = SkmVariableReference.new(nil, proc_name)
45
+ instance = SkmDefinition.new(nil, identifier, var_ref) # (define plus +)
46
+ expect(instance.expression).to eq(var_ref)
47
+ instance.evaluate(runtime)
48
+ # Optimization by getting rid of indirection
49
+ expect(instance.expression).to be_kind_of(Primitive::PrimitiveProcedure)
50
+ end
51
+
52
+ it 'should optimize an entry that aliases a lambda proc' do
53
+ # Let's define a (dummy) lambda
54
+ formals = SkmFormals.new([], :fixed)
55
+ dummy_body = { :defs => [], :sequence => [SkmInteger.create(3)]}
56
+ lbd = SkmLambda.new(nil, formals, dummy_body)
57
+ id = SkmIdentifier.create('some-lambda')
58
+ def1 = SkmDefinition.new(nil, id, lbd)
59
+ def1.evaluate(runtime)
60
+
61
+ # Let's create an alias to the lambda
62
+ other_name = SkmIdentifier.create('aliased-lambda')
63
+ var_ref = SkmVariableReference.new(nil, id)
64
+
65
+ # (define aliased-lambda some-lambda)
66
+ def2 = SkmDefinition.new(nil, other_name, var_ref)
67
+ expect(def2.expression).to eq(var_ref)
68
+ def2.evaluate(runtime)
69
+ # Optimization by getting rid of indirection
70
+ expect(def2.expression).to eq(lbd)
71
+ end
72
+
37
73
  it 'should quasiquote its variable and expression' do
38
74
  alter_ego = subject.quasiquote(runtime)
39
75
  expect(alter_ego).to eq(subject)
@@ -1,6 +1,7 @@
1
1
  require_relative '../spec_helper' # Use the RSpec framework
2
2
  require_relative '../../lib/skeem/datum_dsl'
3
3
  require_relative '../../lib/skeem/environment'
4
+ require_relative '../../lib/skeem/s_expr_nodes'
4
5
  require_relative '../../lib/skeem/skm_unary_expression' # Load the classes under test
5
6
 
6
7
  module Skeem
@@ -176,15 +177,14 @@ module Skeem
176
177
  end # context
177
178
 
178
179
  context 'Provided services:' do
179
- let(:dummy_def) { double('fake-definition') }
180
+ let(:sample_def) { SkmDefinition.new(nil, identifier('three'), integer(3)) }
180
181
  let(:runtime) { Runtime.new(Environment.new) }
181
182
 
182
183
  before(:each) do
183
- runtime.define('three', dummy_def)
184
+ runtime.define('three', sample_def)
184
185
  end
185
186
 
186
187
  it "should return the variable's value at evaluation" do
187
- expect(dummy_def).to receive(:expression).and_return(integer(3))
188
188
  expect(subject.evaluate(runtime)).to eq(3)
189
189
  end
190
190
 
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.0.24
4
+ version: 0.0.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-08 00:00:00.000000000 Z
11
+ date: 2018-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley