shen-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.rspec +0 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +20 -0
- data/MIT_LICENSE.txt +26 -0
- data/README.md +94 -0
- data/bin/shen_test_suite.rb +9 -0
- data/bin/srrepl +23 -0
- data/lib/kl.rb +7 -0
- data/lib/kl/absvector.rb +12 -0
- data/lib/kl/compiler.rb +253 -0
- data/lib/kl/cons.rb +51 -0
- data/lib/kl/empty_list.rb +12 -0
- data/lib/kl/environment.rb +123 -0
- data/lib/kl/error.rb +4 -0
- data/lib/kl/internal_error.rb +7 -0
- data/lib/kl/lexer.rb +186 -0
- data/lib/kl/primitives/arithmetic.rb +60 -0
- data/lib/kl/primitives/assignments.rb +18 -0
- data/lib/kl/primitives/booleans.rb +17 -0
- data/lib/kl/primitives/error_handling.rb +13 -0
- data/lib/kl/primitives/generic_functions.rb +22 -0
- data/lib/kl/primitives/lists.rb +21 -0
- data/lib/kl/primitives/streams.rb +38 -0
- data/lib/kl/primitives/strings.rb +55 -0
- data/lib/kl/primitives/symbols.rb +17 -0
- data/lib/kl/primitives/time.rb +17 -0
- data/lib/kl/primitives/vectors.rb +30 -0
- data/lib/kl/reader.rb +40 -0
- data/lib/kl/trampoline.rb +14 -0
- data/lib/shen_ruby.rb +7 -0
- data/lib/shen_ruby/version.rb +3 -0
- data/shen-ruby.gemspec +26 -0
- data/shen/README.txt +17 -0
- data/shen/lib/shen_ruby/shen.rb +124 -0
- data/shen/license.txt +34 -0
- data/shen/release/benchmarks/N_queens.shen +45 -0
- data/shen/release/benchmarks/README.shen +14 -0
- data/shen/release/benchmarks/benchmarks.shen +56 -0
- data/shen/release/benchmarks/bigprog +2173 -0
- data/shen/release/benchmarks/br.shen +13 -0
- data/shen/release/benchmarks/einstein.shen +33 -0
- data/shen/release/benchmarks/heatwave.gif +0 -0
- data/shen/release/benchmarks/interpreter.shen +219 -0
- data/shen/release/benchmarks/picture.jpg +0 -0
- data/shen/release/benchmarks/plato.jpg +0 -0
- data/shen/release/benchmarks/powerset.shen +10 -0
- data/shen/release/benchmarks/prime.shen +10 -0
- data/shen/release/benchmarks/short.shen +129 -0
- data/shen/release/benchmarks/text.txt +68 -0
- data/shen/release/k_lambda/core.kl +1002 -0
- data/shen/release/k_lambda/declarations.kl +1021 -0
- data/shen/release/k_lambda/load.kl +94 -0
- data/shen/release/k_lambda/macros.kl +479 -0
- data/shen/release/k_lambda/prolog.kl +1309 -0
- data/shen/release/k_lambda/reader.kl +1058 -0
- data/shen/release/k_lambda/sequent.kl +556 -0
- data/shen/release/k_lambda/sys.kl +582 -0
- data/shen/release/k_lambda/t-star.kl +3493 -0
- data/shen/release/k_lambda/toplevel.kl +223 -0
- data/shen/release/k_lambda/track.kl +208 -0
- data/shen/release/k_lambda/types.kl +455 -0
- data/shen/release/k_lambda/writer.kl +108 -0
- data/shen/release/k_lambda/yacc.kl +280 -0
- data/shen/release/test_programs/Chap13/problems.txt +26 -0
- data/shen/release/test_programs/README.shen +53 -0
- data/shen/release/test_programs/TinyLispFunctions.txt +16 -0
- data/shen/release/test_programs/TinyTypes.shen +55 -0
- data/shen/release/test_programs/binary.shen +24 -0
- data/shen/release/test_programs/bubble_version_1.shen +28 -0
- data/shen/release/test_programs/bubble_version_2.shen +22 -0
- data/shen/release/test_programs/calculator.shen +21 -0
- data/shen/release/test_programs/cartprod.shen +23 -0
- data/shen/release/test_programs/change.shen +25 -0
- data/shen/release/test_programs/classes-defaults.shen +94 -0
- data/shen/release/test_programs/classes-inheritance.shen +100 -0
- data/shen/release/test_programs/classes-typed.shen +74 -0
- data/shen/release/test_programs/classes-untyped.shen +46 -0
- data/shen/release/test_programs/depth_.shen +14 -0
- data/shen/release/test_programs/einstein.shen +33 -0
- data/shen/release/test_programs/fruit_machine.shen +46 -0
- data/shen/release/test_programs/interpreter.shen +219 -0
- data/shen/release/test_programs/metaprog.shen +85 -0
- data/shen/release/test_programs/minim.shen +193 -0
- data/shen/release/test_programs/mutual.shen +11 -0
- data/shen/release/test_programs/n_queens.shen +45 -0
- data/shen/release/test_programs/newton_version_1.shen +33 -0
- data/shen/release/test_programs/newton_version_2.shen +24 -0
- data/shen/release/test_programs/parse.prl +14 -0
- data/shen/release/test_programs/parser.shen +52 -0
- data/shen/release/test_programs/powerset.shen +10 -0
- data/shen/release/test_programs/prime.shen +10 -0
- data/shen/release/test_programs/proof_assistant.shen +81 -0
- data/shen/release/test_programs/proplog_version_1.shen +25 -0
- data/shen/release/test_programs/proplog_version_2.shen +27 -0
- data/shen/release/test_programs/qmachine.shen +67 -0
- data/shen/release/test_programs/red-black.shen +55 -0
- data/shen/release/test_programs/search.shen +56 -0
- data/shen/release/test_programs/semantic_net.shen +44 -0
- data/shen/release/test_programs/spreadsheet.shen +35 -0
- data/shen/release/test_programs/stack.shen +27 -0
- data/shen/release/test_programs/streams.shen +20 -0
- data/shen/release/test_programs/strings.shen +59 -0
- data/shen/release/test_programs/structures-typed.shen +71 -0
- data/shen/release/test_programs/structures-untyped.shen +42 -0
- data/shen/release/test_programs/tests.shen +294 -0
- data/shen/release/test_programs/types.shen +11 -0
- data/shen/release/test_programs/whist.shen +240 -0
- data/shen/release/test_programs/yacc.shen +136 -0
- data/spec/kl/cons_spec.rb +12 -0
- data/spec/kl/environment_spec.rb +306 -0
- data/spec/kl/lexer_spec.rb +149 -0
- data/spec/kl/primitives/generic_functions_spec.rb +29 -0
- data/spec/kl/primitives/symbols_spec.rb +21 -0
- data/spec/kl/reader_spec.rb +36 -0
- data/spec/spec_helper.rb +2 -0
- metadata +189 -0
@@ -0,0 +1,136 @@
|
|
1
|
+
(defcc <sent>
|
2
|
+
<np> <vp>;)
|
3
|
+
|
4
|
+
(defcc <det>
|
5
|
+
the; a;)
|
6
|
+
|
7
|
+
(defcc <np>
|
8
|
+
<det> <n>;
|
9
|
+
<name1>;)
|
10
|
+
|
11
|
+
(defcc <n>
|
12
|
+
cat; dog;)
|
13
|
+
|
14
|
+
(defcc <name1>
|
15
|
+
-*- := (if (element? -*- [(protect Bill) (protect Ben)]) -*- (fail));)
|
16
|
+
|
17
|
+
(defcc <vp>
|
18
|
+
<vtrans> <np>;)
|
19
|
+
|
20
|
+
(defcc <vtrans>
|
21
|
+
likes; chases;)
|
22
|
+
|
23
|
+
(defcc <des>
|
24
|
+
[<ds>] [<es>] := (append <ds> <es>);)
|
25
|
+
|
26
|
+
(defcc <ds>
|
27
|
+
d <ds>;
|
28
|
+
d;)
|
29
|
+
|
30
|
+
(defcc <es>
|
31
|
+
e <es>;
|
32
|
+
e;)
|
33
|
+
|
34
|
+
(defcc <sent'>
|
35
|
+
<np> <vp> := (question <np> <vp>);)
|
36
|
+
|
37
|
+
(define question
|
38
|
+
NP VP -> (append [is it true that your father] VP [?]))
|
39
|
+
|
40
|
+
(defcc <as->bs>
|
41
|
+
a <a->bs> := [b | <a->bs>];
|
42
|
+
a := [b];)
|
43
|
+
|
44
|
+
(defcc <find-digit>
|
45
|
+
<digit> <morestuff> := <digit>;
|
46
|
+
<digit> := <digit>;
|
47
|
+
-*- <find-digit> := <find-digit>;)
|
48
|
+
|
49
|
+
(defcc <morestuff>
|
50
|
+
-*- <morestuff>;
|
51
|
+
-*-;)
|
52
|
+
|
53
|
+
(defcc <digit>
|
54
|
+
0; 1; 2; 3; 4; 5; 6; 7; 8; 9;)
|
55
|
+
|
56
|
+
(defcc <find-digit'>
|
57
|
+
<digit> <morestuff> := -s-;
|
58
|
+
<digit> := -s-;
|
59
|
+
-*- <find-digit'> := <find-digit'>;)
|
60
|
+
|
61
|
+
(defcc <asbscs>
|
62
|
+
<as> <bs> <cs>;)
|
63
|
+
|
64
|
+
(defcc <as>
|
65
|
+
a <as>;
|
66
|
+
a;)
|
67
|
+
|
68
|
+
(defcc <bs>
|
69
|
+
b <bs>;
|
70
|
+
b;
|
71
|
+
<e>;)
|
72
|
+
|
73
|
+
(defcc <cs>
|
74
|
+
c <cs>;
|
75
|
+
c;)
|
76
|
+
|
77
|
+
(defcc <asbs'cs>
|
78
|
+
<as> <bs'> <cs>;)
|
79
|
+
|
80
|
+
(defcc <bs'>
|
81
|
+
b <bs'>;
|
82
|
+
b;
|
83
|
+
<e>;)
|
84
|
+
|
85
|
+
(defcc <find-digit''>
|
86
|
+
<digit''> <morestuff> := <digit''>;
|
87
|
+
<digit''> := <digit''>;
|
88
|
+
-*- <find-digit''> := <find-digit''>;)
|
89
|
+
|
90
|
+
(defcc <digit''>
|
91
|
+
-*- := (one_of -*- [0 1 2 3 4 5 6 7 8 9]);)
|
92
|
+
|
93
|
+
(define one_of
|
94
|
+
X Y -> (if (element? X Y) X (fail)))
|
95
|
+
|
96
|
+
(defcc <anbncn>
|
97
|
+
<as> <bs> <cs> := (if (equal-length? [<as> <bs> <cs>])
|
98
|
+
(appendall [<as> <bs> <cs>])
|
99
|
+
(fail));)
|
100
|
+
|
101
|
+
(defcc <as>
|
102
|
+
a <as>;
|
103
|
+
a;)
|
104
|
+
|
105
|
+
(defcc <bs>
|
106
|
+
b <bs>;
|
107
|
+
b;)
|
108
|
+
|
109
|
+
(defcc <cs>
|
110
|
+
c <cs>;
|
111
|
+
c;)
|
112
|
+
|
113
|
+
(define equal-length?
|
114
|
+
[] -> true
|
115
|
+
[L] -> true
|
116
|
+
[L1 L2 | Ls] -> (and (= (length L1) (length L2)) (equal-length? [L2 | Ls])))
|
117
|
+
|
118
|
+
(define appendall
|
119
|
+
[] -> []
|
120
|
+
[L | Ls] -> (append L (appendall Ls)))
|
121
|
+
|
122
|
+
(defcc <a*s>
|
123
|
+
[a] := a;)
|
124
|
+
|
125
|
+
(defcc <b*>
|
126
|
+
[b] b;)
|
127
|
+
|
128
|
+
(defcc <c*>
|
129
|
+
[<c*>] := [<c*>];
|
130
|
+
c;)
|
131
|
+
|
132
|
+
(defcc <d*>
|
133
|
+
[<d*>] <d*> := [[<d*>] | <d*>];
|
134
|
+
d <d*> := [d | <d*>];
|
135
|
+
d := [d];)
|
136
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kl::Cons, '.list' do
|
4
|
+
it 'returns Kl::EmptyList for an empty array' do
|
5
|
+
Kl::Cons.list([]).should be_kind_of Kl::EmptyList
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'constructs a nil-terminated list from a non-empty array' do
|
9
|
+
Kl::Cons.list([1, 2, 3]).should ==
|
10
|
+
Kl::Cons.new(1, Kl::Cons.new(2, Kl::Cons.new(3, Kl::EmptyList.instance)))
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,306 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Kl::Environment do
|
4
|
+
def eval_str(str)
|
5
|
+
form = Kl::Reader.new(StringIO.new(str)).next
|
6
|
+
@env.__eval(form)
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
@env = Kl::Environment.new
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'evaluation of atoms' do
|
14
|
+
it 'evaluates symbols to themselves' do
|
15
|
+
eval_str('foo').should == :foo
|
16
|
+
eval_str('foo-bar-<baz>').should == "foo-bar-<baz>".to_sym
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'evaluates strings to themselves' do
|
20
|
+
eval_str('"foo"').should == 'foo'
|
21
|
+
eval_str('"foo #{bar} \'baz"').should == 'foo #{bar} \'baz'
|
22
|
+
eval_str('"\\"').should == '\\'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'evaluates numbers to themselves' do
|
26
|
+
eval_str('1').should == 1
|
27
|
+
eval_str('-1.7').should == -1.7
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'evaluates booleans to themselves' do
|
31
|
+
eval_str('true').should == true
|
32
|
+
eval_str('false').should == false
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'evaluations empty strings to themselves' do
|
36
|
+
eval_str('()').should == Kl::EmptyList.instance
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'evaluation of non-special forms' do
|
41
|
+
it 'evaluates simple function application' do
|
42
|
+
eval_str('(+ 1 2)').should == 3
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'evaluates function arguments before application' do
|
46
|
+
eval_str('(* (+ 1 2) (- 6 1))').should == 15
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'evaluation of lambda special form' do
|
51
|
+
it 'evaluates them to proc objects' do
|
52
|
+
eval_str('(lambda X X)').should be_kind_of Proc
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'allows them to be applied' do
|
56
|
+
eval_str('((lambda X X) 37)').should == 37
|
57
|
+
eval_str('((lambda X 42) ignore-me)').should == 42
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'maintains lexical scoping' do
|
61
|
+
# (let X 1
|
62
|
+
# (let Y 3
|
63
|
+
# (let X 7
|
64
|
+
# (+ X Y))))
|
65
|
+
eval_str('((lambda X
|
66
|
+
((lambda Y
|
67
|
+
((lambda X (+ X Y))
|
68
|
+
7))
|
69
|
+
3))
|
70
|
+
1)').should == 10
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'creates closures' do
|
74
|
+
eval_str('((let X 37 (lambda IGNORE X)) ignore-me)').should == 37
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe 'evaluation of let special form' do
|
79
|
+
it 'binds its var' do
|
80
|
+
eval_str('(let X 37 X)').should == 37
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'maintains lexical scoping' do
|
84
|
+
eval_str('(let X 1
|
85
|
+
(let Y 3
|
86
|
+
(let X 7
|
87
|
+
(+ X Y))))').should == 10
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'evaluation of defun special form' do
|
92
|
+
it 'adds a new function to the environment' do
|
93
|
+
eval_str('(defun my-add (A B) (+ A B))').should == "my-add".to_sym
|
94
|
+
eval_str('(my-add 17 20)').should == 37
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'exposes the function for use in Ruby' do
|
98
|
+
pending "a clean way to handle trampolines when calling from outside"
|
99
|
+
eval_str('(defun add7 (X) (+ X 7))')
|
100
|
+
@env.add7(30).should == 37
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'redefines existing functions' do
|
104
|
+
eval_str('(defun my-fun () first-version)')
|
105
|
+
eval_str('(my-fun)').should == :"first-version"
|
106
|
+
eval_str('(defun my-fun () second-version)')
|
107
|
+
eval_str('(my-fun)').should == :"second-version"
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'adds a top-level function even when not executed at the top-level' do
|
111
|
+
eval_str('((lambda X
|
112
|
+
(defun return-X () X)) 7)').should == :"return-X"
|
113
|
+
eval_str('(return-X)').should == 7
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe 'evaluation of boolean special forms' do
|
118
|
+
describe "if" do
|
119
|
+
before(:each) do
|
120
|
+
eval_str('(defun one () 1)')
|
121
|
+
eval_str('(defun two () 2)')
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'evaluates and returns the true clause when given true' do
|
125
|
+
@env.should_receive(:one).and_return(1)
|
126
|
+
@env.should_not_receive(:two)
|
127
|
+
eval_str('(if true (one) (two))').should == 1
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'evaluates and returns the false clause when given false' do
|
131
|
+
@env.should_not_receive(:one)
|
132
|
+
@env.should_receive(:two).and_return(2)
|
133
|
+
eval_str('(if false (one) (two))').should == 2
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "and" do
|
138
|
+
before(:each) do
|
139
|
+
eval_str('(defun tr () true)')
|
140
|
+
eval_str('(defun fa () false)')
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'returns false and does not evaluate second form if first is false' do
|
144
|
+
@env.should_not_receive(:tr)
|
145
|
+
eval_str('(and (fa) (tr))').should == false
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'returns false when first is true and second is false' do
|
149
|
+
eval_str('(and (tr) (fa))').should == false
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'returns true when both expressions evaluate to true' do
|
153
|
+
@env.should_receive(:tr).twice.and_return(true)
|
154
|
+
eval_str('(and (tr) (tr))').should == true
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'may be passed as an argument to higher order functions' do
|
158
|
+
eval_str('((lambda Op (Op true true)) and)').should == true
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "or" do
|
163
|
+
before(:each) do
|
164
|
+
eval_str('(defun tr () true)')
|
165
|
+
eval_str('(defun fa () false)')
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'returns true and does not evaluate second form if first is true' do
|
169
|
+
@env.should_not_receive(:fa)
|
170
|
+
eval_str('(or (tr) (fa))').should == true
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'returns true when first is false and second is true' do
|
174
|
+
eval_str('(or (fa) (tr))').should == true
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'returns false when both expressions evaluate to false' do
|
178
|
+
@env.should_receive(:fa).twice.and_return(false)
|
179
|
+
eval_str('(or (fa) (fa))').should == false
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'may be passed as an argument to higher order functions' do
|
183
|
+
eval_str('((lambda Op (Op false false)) or)').should == false
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
describe "cond" do
|
189
|
+
before(:each) do
|
190
|
+
eval_str('(defun tr () true)')
|
191
|
+
eval_str('(defun fa () false)')
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'returns the value of the expression associate with the first true' do
|
195
|
+
@env.should_not_receive(:tr)
|
196
|
+
eval_str('(cond (false (tr))
|
197
|
+
((fa) 37)
|
198
|
+
(true 42)
|
199
|
+
(true (tr)))').should == 42
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'raises an error upon falling off the end' do
|
203
|
+
expect {
|
204
|
+
eval_str('(cond (false 37) ((fa) 42))')
|
205
|
+
}.to raise_error(Kl::Error, 'condition failure')
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe "error handling" do
|
211
|
+
it 'raises uncaught errors' do
|
212
|
+
expect {
|
213
|
+
eval_str('(simple-error "boom!")')
|
214
|
+
}.to raise_error(Kl::Error, 'boom!')
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'moves past caught errors' do
|
218
|
+
eval_str('(trap-error
|
219
|
+
(simple-error "boom!")
|
220
|
+
(lambda E 37))').should == 37
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'treats undefined functions as simple errors' do
|
224
|
+
expect {
|
225
|
+
eval_str('(foo)')
|
226
|
+
}.to raise_error(Kl::Error, 'The function foo is undefined')
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe "setting values" do
|
231
|
+
it 'returns the value set' do
|
232
|
+
eval_str('(set foo 37)').should == 37
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'previously set values are retrievable' do
|
236
|
+
eval_str('(set foo 37)')
|
237
|
+
eval_str('(value foo)').should == 37
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe "evaluation of freeze" do
|
242
|
+
it 'delays computation' do
|
243
|
+
eval_str('(defun one () 1)')
|
244
|
+
@env.should_not_receive(:one)
|
245
|
+
eval_str('(freeze (one))').should be_kind_of Proc
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'is thawable later' do
|
249
|
+
eval_str('(defun one () 1)')
|
250
|
+
eval_str('((freeze (one)))').should == 1
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe 'evaulation of type' do
|
255
|
+
it 'evaluates the expression and ignores the type information' do
|
256
|
+
eval_str('(type (+ 1 2) number)').should == 3
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe 'evaluation of eval-kl' do
|
261
|
+
it 'evals as expected' do
|
262
|
+
eval_str('(eval-kl (+ 1 2))').should == 3
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe 'currying' do
|
267
|
+
it 'supports partial application of primitives' do
|
268
|
+
eval_str('((+ 1) 2)').should == 3
|
269
|
+
eval_str('(((+) 1) 2)').should == 3
|
270
|
+
end
|
271
|
+
|
272
|
+
it 'supports partial application of user-defined functions' do
|
273
|
+
eval_str('(defun adder (X Y) (+ X Y))')
|
274
|
+
eval_str('((adder 1) 2)').should == 3
|
275
|
+
eval_str('(((adder) 1) 2)').should == 3
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'supports uncurrying of nested lambdas' do
|
279
|
+
eval_str('((lambda X (lambda Y (* X Y))) 6 7)').should == 42
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'supports uncurrying of higher-order functions' do
|
283
|
+
eval_str('(defun adder (X) (lambda Y (+ X Y)))')
|
284
|
+
eval_str('(adder 1 2)').should == 3
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe 'tail recursion' do
|
289
|
+
it 'does not blow the stack' do
|
290
|
+
eval_str('(defun count-down (X)
|
291
|
+
(if (= X 0)
|
292
|
+
success
|
293
|
+
(count-down (- X 1))))')
|
294
|
+
eval_str('(count-down 100000)').should == :success
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
describe 'stack overflow' do
|
299
|
+
it 'is translated into a Shen simple-error' do
|
300
|
+
eval_str('(defun boom () (+ 1 (boom)))')
|
301
|
+
expect {
|
302
|
+
eval_str('(boom)')
|
303
|
+
}.to raise_error(Kl::Error, 'maximum stack depth exceeded')
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|