skeem 0.2.00 → 0.2.01

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: 4f8a75ad0a0ead374dc7ec59e94abc9edd04826901be7f2e8230c9047c256845
4
- data.tar.gz: 854f4e2e64dff8224046420ee7ccd035b23cf409c016ecec667206c02a5aae87
3
+ metadata.gz: 5f5189dc1b13c7998cdf1ee98579ff1f70ae057493897f1e9bc64614ddb08a50
4
+ data.tar.gz: c302f6dce9b86a5ef7d5c644afbd164a8957d848ddaf5ab729e8f66a58b5bd55
5
5
  SHA512:
6
- metadata.gz: ea925e74fbbab68290d6b6cb13e7af3caa735e9f5709e5d9f50423410695d5db0a9c50d077e594e2683e16c7b4f6b85c02b1d72629d97dc6e9348f7a1e32533c
7
- data.tar.gz: 4930db824c351c76d56f006491f8838e88b64e2e2200fb13412c848c0bc90c6f9effa839983ac3e5bd926e0c0ab162bfb87e3a8217f8d2f14410ce35a4ff2d46
6
+ metadata.gz: b2e87e734659cff72352271a51ee76be8af918287ba2db9c267993774b03f04e3203aea62d130ee73678d8ad8011d4cca485ce3126116915685c33c6ac9ba326
7
+ data.tar.gz: 95a6027ac7ce681dbc4ab9dbe7a3f9ae96c8b19ff37bd61d4932ca869f2f1ab94495759c54d332fbf84772cfa0affb5a1dea610aa1002de48e0d64c61cb81228
data/CHANGELOG.md CHANGED
@@ -1,9 +1,10 @@
1
- ## [0.1.04] - 2019-01-19
1
+ ## [0.2.01] - 2019-04-19
2
2
  ### Added
3
- - Method `SkmDefinition#redefine`: a given variable can point to another expression.
3
+ - Skeem now supports 'let' local binding construct
4
4
 
5
- ### Fixed
6
- - Procedure `set!` caused infinite loops when redefinition involved a procedure call.
5
+
6
+ ## [0.2.00] - 2019-04-14
7
+ ### Major refactoring
7
8
 
8
9
  ## [0.1.03] - 2019-01-15
9
10
  ### Added
data/README.md CHANGED
@@ -161,6 +161,11 @@ __Purpose:__ Assign to an existing variable an expression/value to it.
161
161
  __Syntax:__
162
162
  * (set! <identifier\> <expression\>)
163
163
 
164
+ ### Derived expressions
165
+ #### let
166
+ __Purpose:__ Define one or more variable local to the block.
167
+ __Syntax:__
168
+ * (let (<binding_spec\*\>) <body\>)
164
169
 
165
170
 
166
171
  ### Standard library
@@ -106,6 +106,7 @@ module Skeem
106
106
  return aLiteral if aLiteral.kind_of?(SkmSimpleDatum)
107
107
  return list(aLiteral.members) if aLiteral.kind_of?(SkmList)
108
108
  return vector(aLiteral.members) if aLiteral.kind_of?(SkmVector)
109
+ return aLiteral if aLiteral.kind_of?(Primitive::PrimitiveProcedure)
109
110
 
110
111
  result = case aLiteral
111
112
  when Array
data/lib/skeem/grammar.rb CHANGED
@@ -19,7 +19,7 @@ module Skeem
19
19
  add_terminals('STRING_LIT', 'IDENTIFIER')
20
20
 
21
21
  # Keywords...
22
- add_terminals('DEFINE', 'IF', 'LAMBDA')
22
+ add_terminals('DEFINE', 'IF', 'LAMBDA', 'LET')
23
23
  add_terminals('QUOTE', 'QUASIQUOTE', 'SET!')
24
24
  add_terminals('UNQUOTE', 'UNQUOTE-SPLICING')
25
25
 
@@ -92,9 +92,13 @@ module Skeem
92
92
  rule 'number' => 'INTEGER'
93
93
  rule 'number' => 'REAL'
94
94
  rule('assignment' => 'LPAREN SET! IDENTIFIER expression RPAREN').as 'assignment'
95
+ rule('derived_expression' => 'LPAREN LET LPAREN binding_spec_star RPAREN body RPAREN').as 'short_let_form'
95
96
  rule 'derived_expression' => 'quasiquotation'
96
97
  rule('quasiquotation' => 'LPAREN QUASIQUOTE qq_template RPAREN').as 'quasiquotation'
97
98
  rule('quasiquotation' => 'GRAVE_ACCENT qq_template').as 'quasiquotation_short'
99
+ rule('binding_spec_star' => 'binding_spec_star binding_spec').as 'multiple_binding_specs'
100
+ rule('binding_spec_star' => []).as 'no_binding_spec_yet'
101
+ rule('binding_spec' => 'LPAREN IDENTIFIER expression RPAREN').as 'binding_spec'
98
102
  rule 'qq_template' => 'simple_datum'
99
103
  rule 'qq_template' => 'list_qq_template'
100
104
  rule 'qq_template' => 'vector_qq_template'
@@ -95,7 +95,7 @@ module Skeem
95
95
  theChildren[2]
96
96
  else
97
97
  SkmQuotation.new(theChildren[2])
98
- end
98
+ end
99
99
  end
100
100
 
101
101
  # rule('list' => 'LPAREN datum_star RPAREN').as 'list'
@@ -106,7 +106,7 @@ module Skeem
106
106
  end
107
107
  SkmPair.create_from_a(theChildren[1])
108
108
  end
109
-
109
+
110
110
  # rule('list' => 'LPAREN datum_plus PERIOD datum RPAREN').as 'dotted_list'
111
111
  def reduce_dotted_list(_production, _range, _tokens, theChildren)
112
112
  # if theChildren[1].kind_of?(Array)
@@ -118,9 +118,9 @@ module Skeem
118
118
  # else
119
119
  # car_arg = theChildren[1]
120
120
  # end
121
-
121
+
122
122
  SkmPair.new(theChildren[1], theChildren[3])
123
- end
123
+ end
124
124
 
125
125
  # rule('vector' => 'VECTOR_BEGIN datum_star RPAREN').as 'vector'
126
126
  def reduce_vector(_production, aRange, _tokens, theChildren)
@@ -246,12 +246,17 @@ module Skeem
246
246
  def reduce_conditional(_production, aRange, _tokens, theChildren)
247
247
  SkmCondition.new(aRange, theChildren[2], theChildren[3], theChildren[4])
248
248
  end
249
-
249
+
250
250
  # rule('assignment' => 'LPAREN SET! IDENTIFIER expression RPAREN').as 'assignment'
251
251
  def reduce_assignment(_production, _range, _tokens, theChildren)
252
252
  SkmUpdateBinding.new(theChildren[2], theChildren[3])
253
253
  end
254
254
 
255
+ # rule('derived_expression' => 'LPAREN LET LPAREN binding_spec_star RPAREN body RPAREN').as 'short_let_form'
256
+ def reduce_short_let_form(_production, aRange, _tokens, theChildren)
257
+ SkmBindingBlock.new(:let, theChildren[3], theChildren[5])
258
+ end
259
+
255
260
  # rule('quasiquotation' => 'LPAREN QUASIQUOTE qq_template RPAREN').as 'quasiquotation'
256
261
  def reduce_quasiquotation(_production, aRange, _tokens, theChildren)
257
262
  SkmQuasiquotation.new(theChildren[2])
@@ -262,6 +267,21 @@ module Skeem
262
267
  SkmQuasiquotation.new(theChildren[1])
263
268
  end
264
269
 
270
+ # rule('binding_spec_star' => 'binding_spec_star binding_spec').as 'multiple_binding_specs'
271
+ def reduce_multiple_binding_specs(_production, aRange, _tokens, theChildren)
272
+ theChildren[0] << theChildren[1]
273
+ end
274
+
275
+ # rule('binding_spec_star' => []).as 'no_binding_spec_yet'
276
+ def reduce_no_binding_spec_yet(_production, aRange, _tokens, _children)
277
+ []
278
+ end
279
+
280
+ # rule('binding_spec' => 'LPAREN IDENTIFIER expression RPAREN').as 'binding_spec'
281
+ def reduce_binding_spec(production, _range, _tokens, theChildren)
282
+ SkmBinding.new(theChildren[1], theChildren[2])
283
+ end
284
+
265
285
  # rule('list_qq_template' => 'LPAREN qq_template_or_splice_star RPAREN').as 'list_qq'
266
286
  def reduce_list_qq(_production, _range, _tokens, theChildren)
267
287
  SkmPair.create_from_a(theChildren[1])
@@ -129,7 +129,11 @@ module Skeem
129
129
  callee = operator
130
130
  else
131
131
  result = operator.evaluate(aRuntime)
132
- callee = fetch_callee(aRuntime, result)
132
+ if result.kind_of?(Primitive::PrimitiveProcedure)
133
+ callee = result
134
+ else
135
+ callee = fetch_callee(aRuntime, result)
136
+ end
133
137
  end
134
138
 
135
139
  [:callee, callee]
@@ -110,4 +110,36 @@ module Skeem
110
110
  variable.value
111
111
  end
112
112
  end # class
113
+
114
+ # Used to represent local binding constructs (let, let*, letrec, letrec*)
115
+ class SkmBindingBlock < SkmUnaryExpression
116
+ alias body child
117
+
118
+ attr_reader :kind
119
+ attr_reader :bindings
120
+
121
+ def initialize(theKind, theBindings, aBody)
122
+ @kind = theKind
123
+ @bindings = theBindings
124
+ super(nil, aBody)
125
+ end
126
+
127
+ def evaluate(aRuntime)
128
+ if kind == :let
129
+ aRuntime.push(SkmFrame.new(aRuntime.environment))
130
+ locals = bindings.map do |bnd|
131
+ SkmBinding.new(bnd.variable, bnd.value.evaluate(aRuntime))
132
+ end
133
+ locals.each do |bnd|
134
+ aRuntime.add_binding(bnd.variable.evaluate(aRuntime), bnd.value)
135
+ end
136
+ end
137
+
138
+ result = body[:sequence].evaluate(aRuntime)
139
+ aRuntime.pop
140
+ result.kind_of?(SkmPair) ? result.last : result
141
+ end
142
+
143
+ end # class
144
+
113
145
  end # module
@@ -29,12 +29,13 @@ module Skeem
29
29
  '#(' => 'VECTOR_BEGIN'
30
30
  }.freeze
31
31
 
32
- # Here are all the Scheme keywords (in uppercase)
32
+ # Here are all the implemented Scheme keywords (in uppercase)
33
33
  @@keywords = %w[
34
34
  BEGIN
35
35
  DEFINE
36
36
  IF
37
37
  LAMBDA
38
+ LET
38
39
  QUASIQUOTE
39
40
  QUOTE
40
41
  SET!
data/lib/skeem/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Skeem
2
- VERSION = '0.2.00'.freeze
2
+ VERSION = '0.2.01'.freeze
3
3
  end
@@ -305,6 +305,42 @@ SKEEM
305
305
  expect(result.last.last.value).to eq(4)
306
306
  end
307
307
  end # context
308
+
309
+ context 'Binding constructs:' do
310
+ it 'should implement local bindings' do
311
+ source = <<-SKEEM
312
+ (let ((x 2)
313
+ (y 3))
314
+ (* x y))
315
+ SKEEM
316
+ result = subject.run(source)
317
+ expect(result).to eq(6)
318
+ end
319
+
320
+ it 'should implement precedence of local bindings' do
321
+ source = <<-SKEEM
322
+ (define x 23)
323
+ (define y 42)
324
+
325
+ ; local variable y in let block "shadows" the global one
326
+ (let ((y 43))
327
+ (+ x y))
328
+ SKEEM
329
+ result = subject.run(source)
330
+ expect(result.last).to eq(66)
331
+ end
332
+
333
+ it 'should support the nesting of local bindings' do
334
+ source = <<-SKEEM
335
+ (let ((x 2) (y 3))
336
+ (let ((x 7)
337
+ (z (+ x y)))
338
+ (* z x)))
339
+ SKEEM
340
+ result = subject.run(source)
341
+ expect(result).to eq(35)
342
+ end
343
+ end # context
308
344
 
309
345
  context 'Quasiquotation:' do
310
346
  it 'should implement the quasiquotation of constant literals' do
@@ -660,8 +696,8 @@ SKEEM
660
696
  end
661
697
  end # context
662
698
 
663
- context 'More advanced tests' do
664
- it 'should implement lambda that calls second-order functions' do
699
+ context 'Second-order functions' do
700
+ it 'should implement lambda that calls second-order function' do
665
701
  source = <<-SKEEM
666
702
  (define twice
667
703
  (lambda (x)
@@ -679,9 +715,7 @@ SKEEM
679
715
  expect(result.last).to eq(20)
680
716
  end
681
717
 
682
- #=begin
683
- it 'under construction' do
684
- # Fails
718
+ it 'should implement the composition of second-order functions' do
685
719
  source = <<-SKEEM
686
720
  (define twice
687
721
  (lambda (x)
@@ -698,7 +732,6 @@ SKEEM
698
732
  result = subject.run(source)
699
733
  expect(result.last).to eq(80)
700
734
  end
701
- #=end
702
735
  end # context
703
736
  end # describe
704
737
  end # module
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.00
4
+ version: 0.2.01
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-04-14 00:00:00.000000000 Z
11
+ date: 2019-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley