shen-ruby 0.1.0
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.
- 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
|