skeem 0.2.00 → 0.2.01

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