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 +4 -4
- data/CHANGELOG.md +5 -4
- data/README.md +5 -0
- data/lib/skeem/datum_dsl.rb +1 -0
- data/lib/skeem/grammar.rb +5 -1
- data/lib/skeem/s_expr_builder.rb +25 -5
- data/lib/skeem/s_expr_nodes.rb +5 -1
- data/lib/skeem/skm_unary_expression.rb +32 -0
- data/lib/skeem/tokenizer.rb +2 -1
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/interpreter_spec.rb +39 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f5189dc1b13c7998cdf1ee98579ff1f70ae057493897f1e9bc64614ddb08a50
|
4
|
+
data.tar.gz: c302f6dce9b86a5ef7d5c644afbd164a8957d848ddaf5ab729e8f66a58b5bd55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2e87e734659cff72352271a51ee76be8af918287ba2db9c267993774b03f04e3203aea62d130ee73678d8ad8011d4cca485ce3126116915685c33c6ac9ba326
|
7
|
+
data.tar.gz: 95a6027ac7ce681dbc4ab9dbe7a3f9ae96c8b19ff37bd61d4932ca869f2f1ab94495759c54d332fbf84772cfa0affb5a1dea610aa1002de48e0d64c61cb81228
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
## [0.
|
1
|
+
## [0.2.01] - 2019-04-19
|
2
2
|
### Added
|
3
|
-
-
|
3
|
+
- Skeem now supports 'let' local binding construct
|
4
4
|
|
5
|
-
|
6
|
-
|
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
|
data/lib/skeem/datum_dsl.rb
CHANGED
@@ -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'
|
data/lib/skeem/s_expr_builder.rb
CHANGED
@@ -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])
|
data/lib/skeem/s_expr_nodes.rb
CHANGED
@@ -129,7 +129,11 @@ module Skeem
|
|
129
129
|
callee = operator
|
130
130
|
else
|
131
131
|
result = operator.evaluate(aRuntime)
|
132
|
-
|
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
|
data/lib/skeem/tokenizer.rb
CHANGED
@@ -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
@@ -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 '
|
664
|
-
it 'should implement lambda that calls second-order
|
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
|
-
|
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.
|
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-
|
11
|
+
date: 2019-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rley
|