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