trxl 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+
3
+ describe "For writing boolean expressions, the language" do
4
+
5
+ include Trxl::SpecHelper
6
+
7
+ before(:each) do
8
+ @parser = Trxl::Calculator.new
9
+ end
10
+
11
+ it "should allow a logical AND operation by using '&&'" do
12
+ eval("TRUE && TRUE").should be_true
13
+ eval("FALSE && FALSE").should be_false
14
+ eval("TRUE && FALSE").should be_false
15
+ eval("FALSE && TRUE").should be_false
16
+
17
+ eval("TRUE && NULL").should be_false
18
+ eval("NULL && TRUE").should be_false
19
+ eval("NULL && NULL").should be_false
20
+
21
+ eval("(2 == 2) && (2 == 2)").should be_true
22
+
23
+ lambda { eval("TRUE && TRUE && TRUE") }.should_not raise_error
24
+ lambda { eval("TRUE && TRUE && FALSE") }.should_not raise_error
25
+ lambda { eval("(2 == 2) && (2 == 2) && (2 == 2)") }.should_not raise_error
26
+ lambda { eval("(2 == 2) && (2 == 2) && (2 == 3)") }.should_not raise_error
27
+ end
28
+
29
+ it "should allow a logical OR operation by using '||'" do
30
+ eval("TRUE || TRUE").should be_true
31
+ eval("TRUE || FALSE").should be_true
32
+ eval("FALSE || TRUE").should be_true
33
+ eval("FALSE || FALSE").should be_false
34
+ eval("(2 == 2) || (2 == 2)").should be_true
35
+ eval("(2 == 2) || (2 == 3)").should be_true
36
+ eval("(2 == 3) || (2 == 3)").should be_false
37
+ end
38
+
39
+ it "should allow a logical NOT operation by using '!'" do
40
+ eval("!TRUE").should be_false
41
+ eval("!FALSE").should be_true
42
+ eval("!1").should be_false
43
+ eval("!(1+1)").should be_false
44
+ eval("!(TRUE || FALSE)").should be_false
45
+ eval("!(TRUE && FALSE)").should be_true
46
+ eval("!(2 == 2)").should be_false
47
+ eval("!(2 == 3)").should be_true
48
+ eval("a = TRUE; !a").should be_false
49
+ end
50
+
51
+ end
52
+
53
+
54
+ describe "For comparing expressions, the language" do
55
+
56
+ include Trxl::SpecHelper
57
+
58
+ before(:each) do
59
+ @parser = Trxl::Calculator.new
60
+ end
61
+
62
+ it "should allow to test if two expressions are equal by using '=='" do
63
+ eval("(TRUE == TRUE)").should be_true
64
+ eval("(FALSE == FALSE)").should be_true
65
+ eval("(TRUE == FALSE)").should be_false
66
+ eval("(NULL == NULL)").should be_true
67
+
68
+ eval("2.0 == 1.999999999").should == (2.0 == 1.999999999)
69
+ eval("2.0 == 2.000000001").should == (2.0 == 2.000000001)
70
+ eval("1.333333333 == 1.333333333").should == (1.333333333 == 1.333333333)
71
+
72
+ eval("'foo' == 'foo'").should be_true
73
+ eval("'foo' == 'bar'").should be_false
74
+
75
+ eval("'foo' != 'foo'").should be_false
76
+ eval("'foo' != 'bar'").should be_true
77
+ end
78
+
79
+ it "should allow to test if two expressions are not equal by using '!='" do
80
+ eval("(TRUE != TRUE)").should be_false
81
+ eval("(TRUE != FALSE)").should be_true
82
+ eval("(FALSE != FALSE)").should be_false
83
+ eval("(NULL != NULL)").should be_false
84
+
85
+ eval("2.0 != 1.999999999").should == (2.0 != 1.999999999)
86
+ eval("2.0 != 2.000000001").should == (2.0 != 2.000000001)
87
+ eval("1.333333333 != 1.333333334").should == (1.333333333 != 1.333333334)
88
+ end
89
+
90
+ it "should allow to compare two expressions by using '<'" do
91
+ eval("(1 < 1)").should be_false
92
+ eval("(1 < 2)").should be_true
93
+ eval("(2 < 1)").should be_false
94
+
95
+ eval("2.0 < 1.999999999").should == (2.0 < 1.999999999)
96
+ eval("2.0 < 2.000000001").should == (2.0 < 2.000000001)
97
+ eval("1.333333333 < 1.333333332").should == (1.333333333 < 1.333333332)
98
+ eval("1.333333333 < 1.333333333").should == (1.333333333 < 1.333333333)
99
+ eval("1.333333333 < 1.333333334").should == (1.333333333 < 1.333333334)
100
+ end
101
+
102
+ it "should allow to compare two expressions by using '>'" do
103
+ eval("(1 > 1)").should be_false
104
+ eval("(2 > 1)").should be_true
105
+ eval("(1 > 2)").should be_false
106
+
107
+ eval("2.0 > 1.999999999").should == (2.0 > 1.999999999)
108
+ eval("2.0 > 2.000000001").should == (2.0 > 2.000000001)
109
+ eval("1.333333333 > 1.333333332").should == (1.333333333 > 1.333333332)
110
+ eval("1.333333333 > 1.333333333").should == (1.333333333 > 1.333333333)
111
+ eval("1.333333333 > 1.333333334").should == (1.333333333 > 1.333333334)
112
+ end
113
+
114
+ it "should allow to compare two expressions by using '<='" do
115
+ eval("(1 <= 1)").should be_true
116
+ eval("(1 <= 2)").should be_true
117
+ eval("(2 <= 1)").should be_false
118
+
119
+ eval("2.0 <= 1.999999999").should == (2.0 <= 1.999999999)
120
+ eval("2.0 <= 2.000000001").should == (2.0 <= 2.000000001)
121
+ eval("1.333333333 <= 1.333333332").should == (1.333333333 <= 1.333333332)
122
+ eval("1.333333333 <= 1.333333333").should == (1.333333333 <= 1.333333333)
123
+ eval("1.333333333 <= 1.333333334").should == (1.333333333 <= 1.333333334)
124
+ end
125
+
126
+ it "should allow to compare two expressions by using '>='" do
127
+ eval("(1 >= 1)").should be_true
128
+ eval("(2 >= 1)").should be_true
129
+ eval("(1 >= 2)").should be_false
130
+
131
+ eval("2.0 >= 1.999999999").should == (2.0 >= 1.999999999)
132
+ eval("2.0 >= 2.000000001").should == (2.0 >= 2.000000001)
133
+ eval("1.333333333 >= 1.333333332").should == (1.333333333 >= 1.333333332)
134
+ eval("1.333333333 >= 1.333333333").should == (1.333333333 >= 1.333333333)
135
+ eval("1.333333333 >= 1.333333334").should == (1.333333333 >= 1.333333334)
136
+ end
137
+
138
+ end
@@ -0,0 +1,268 @@
1
+ require 'spec_helper'
2
+
3
+ describe "The language" do
4
+
5
+ include Trxl::SpecHelper
6
+
7
+ before(:each) do
8
+ @parser = Trxl::Calculator.new
9
+ end
10
+
11
+ it "should allow to access the current environment by calling ENV" do
12
+ env = eval("ENV", {})
13
+ env.should be_kind_of(Trxl::Environment)
14
+ env.should be_empty
15
+
16
+ env = eval("ENV", { :a => 1, :b => 2 })
17
+ env.should be_kind_of(Trxl::Environment)
18
+ env.should have_key(:a)
19
+ env.should have_key(:b)
20
+ env[:a].should == 1
21
+ env[:b].should == 2
22
+ end
23
+
24
+ it "should allow to access variables by name by calling ENV['foo']" do
25
+ eval("ENV['a']", {}).should == nil
26
+ eval("ENV['a']", { :a => 1 }).should == 1
27
+ eval("ENV['a']", { :a => "yes" }).should == "yes"
28
+ eval("ENV['a']", { :a => [ 1, 2, 3 ] }).should == [ 1, 2, 3 ]
29
+ end
30
+
31
+ it "should allow to access ranges in the current environment by calling ENV['a'..'z']" do
32
+ eval("ENV['a'..'a']", { :a => 1, :b => 2, :c => 3 }).should == [ 1 ]
33
+ eval("ENV['a'..'b']", { :a => 1, :b => 2, :c => 3 }).should include(1)
34
+ eval("ENV['a'..'b']", { :a => 1, :b => 2, :c => 3 }).should include(2)
35
+ eval("ENV['a'..'c']", { :a => 1, :b => 2, :c => 3 }).should include(1)
36
+ eval("ENV['a'..'c']", { :a => 1, :b => 2, :c => 3 }).should include(2)
37
+ eval("ENV['a'..'c']", { :a => 1, :b => 2, :c => 3 }).should include(3)
38
+ end
39
+
40
+ it "should be able to PRINT and PRINT_LINE to STDOUT" do
41
+ eval("PRINT('- This is output from PRINT. ')").should be_nil
42
+ eval("PRINT_LINE('And this is output from PRINT_LINE')").should be_nil
43
+ end
44
+
45
+ it "should be able to split strings by calling SPLIT(some_string, split_char)" do
46
+ eval("SPLIT('foo/bar', '/')").should == [ 'foo', 'bar' ]
47
+ end
48
+
49
+ it "should be able to convert values into integers by calling TO_INT(alpha_numeric_string)" do
50
+ eval("TO_INT('1')").should == 1
51
+ end
52
+
53
+ it "should be able to convert values into floats by calling TO_FLOAT(alpha_numeric_string)" do
54
+ eval("TO_FLOAT('1.12')").should == 1.12
55
+ end
56
+
57
+ it "should be able to convert values into arrays by calling TO_ARRAY(some_value)" do
58
+ eval("TO_ARRAY(1)").should == [ 1 ]
59
+ eval("TO_ARRAY('1')").should == [ '1' ]
60
+ eval("TO_ARRAY([1])").should == [ 1 ]
61
+ eval("TO_ARRAY({ 1 => 2 })").should == [ [1, 2] ]
62
+ eval("TO_ARRAY({ 1 => 2, 3 => 4 })").should == [ [1, 2], [3, 4] ]
63
+ end
64
+
65
+ it "should be able to round numbers to a given number of decimal places by calling ROUND(num, digits)" do
66
+ program = "ROUND(1.2222,0)"
67
+ eval(program).should == 1
68
+ program = "ROUND(1.6666,0)"
69
+ eval(program).should == 2
70
+ program = "ROUND(1.2222,1)"
71
+ eval(program).should == 1.2
72
+ program = "ROUND(1.2222,2)"
73
+ eval(program).should == 1.22
74
+ program = "ROUND(1.2782,2)"
75
+ eval(program).should == 1.28
76
+ program = "ROUND(fun(){1.1234567}(),4)"
77
+ eval(program).should == 1.1235
78
+ program = "ROUND(NULL,2)"
79
+ eval(program).should be_nil
80
+ program = "ROUND(FALSE,2)"
81
+ eval(program).should be_nil
82
+ program = "ROUND(TRUE,2)"
83
+ eval(program).should be_nil
84
+ end
85
+
86
+ it "should be able to calculate SUM for an arbitrary number of argument expressions" do
87
+ program = "SUM()"
88
+ eval(program).should == 0
89
+ program = "SUM(NULL)"
90
+ eval(program).should == 0
91
+ program = "SUM(0)"
92
+ eval(program).should == 0
93
+ program = "SUM(1)"
94
+ eval(program).should == 1
95
+ program = "SUM(1,2,3,4)"
96
+ eval(program).should == 10
97
+ program = "SUM(1,2,3,NULL)"
98
+ eval(program).should == 6
99
+ program = "SUM(fun(){4}(),fun(x){x}(4),fun(x,y){x+y}(2,2))"
100
+ eval(program).should == 12
101
+ program = "SUM(x)"
102
+ eval(program, { :x => [ 1, 2, 3 ] }).should == 6
103
+
104
+ program = "SUM([2,2,2],[4,4,4],[3,3,3])"
105
+ eval(program).should == 27
106
+
107
+ program = "SUM([ [2,2,2], [4,4,4], [3,3,3] ])"
108
+ eval(program).should == 27
109
+ end
110
+
111
+ it "should be able to calculate MULT for an arbitrary number of argument expressions" do
112
+ program = "MULT()"
113
+ eval(program).should == 0
114
+ program = "MULT(NULL)"
115
+ eval(program).should == 0
116
+ program = "MULT(0)"
117
+ eval(program).should == 0
118
+ program = "MULT(1)"
119
+ eval(program).should == 1
120
+ program = "MULT(1,2,3,4)"
121
+ eval(program).should == 24
122
+ program = "MULT(1,2,3,NULL)"
123
+ eval(program).should == 6
124
+ program = "MULT(fun(){4}(),fun(x){x}(4),fun(x,y){x+y}(2,2))"
125
+ eval(program).should == 64
126
+ program = "MULT(x)"
127
+ eval(program, { :x => [ 1, 2, 3 ] }).should == 6
128
+ end
129
+
130
+ it "should be able to calculate AVG for an arbitrary number of argument expressions" do
131
+ program = "AVG()"
132
+ eval(program).should == 0
133
+ program = "AVG(NULL)"
134
+ eval(program).should be_nil
135
+ program = "AVG(0)"
136
+ eval(program).should == 0
137
+ program = "AVG(1)"
138
+ eval(program).should == 1
139
+ program = "AVG(3,3,3)"
140
+ eval(program).should == 3
141
+ program = "AVG(3,3,3)"
142
+ eval(program).should == 3
143
+ program = "AVG(3,5,0)"
144
+ eval(program).should be_close(2.66666666666, 0.01)
145
+ program = "AVG(FALSE, 3,5,0)"
146
+ eval(program).should == 4
147
+ program = "AVG(TRUE, 3,5,0)"
148
+ eval(program).should be_close(2.66666666666, 0.01)
149
+ program = "AVG(3,NULL,3)"
150
+ eval(program).should == 3
151
+ program = "AVG(3.3,3.3,3.3)"
152
+ eval(program).should be_close(3.3, 0.01)
153
+ program = "AVG(3,5,4)"
154
+ eval(program).should == 4
155
+ program = "AVG(fun(){4}(),fun(x){x}(4),fun(x,y){x+y}(2,2))"
156
+ eval(program).should == 4
157
+
158
+ program = "AVG([1,2,3],[4,4,4],[6,6,6])"
159
+ eval(program).should == 4
160
+ program = "AVG([2,2],[4,4,4],[6,6])"
161
+ eval(program).should == 4
162
+ end
163
+
164
+ it "should be able to calculate AVG_SUM for an arbitrary number of argument expressions" do
165
+ program = "AVG_SUM([1,2,3],[4,4,4],[6,6,6])"
166
+ eval(program).should == 12
167
+ program = "AVG_SUM([2,2],[4,4,4],[6,6])"
168
+ eval(program).should == 12
169
+
170
+ env = {
171
+ :ap => [138542.0, 136795.0, 134256.0], # 136531
172
+ :aq => [124580.0, 21458.0, 34560.0], # 60199.3333333333
173
+ :ar => [1200.0, 1200.0, 1200.0], # 1200
174
+ :as => [1235.0, 1265.0, 5620.0], # 2706.66666666667
175
+ :at => [5201.0, 4263.0, 8452.0], # 5972
176
+ :au => [250.0, 250.0, 250.0] # 250
177
+ # ------------------
178
+ # 206859
179
+
180
+ }
181
+ eval("AVG_SUM(ENV['ap'..'au'])", env).should == 206859
182
+
183
+ env = {
184
+ :ap => [138542.0, 136795.0, 134256.0], # 136531
185
+ :aq => [124580.0, 21458.0, 34560.0], # 60199.3333333333
186
+ :ar => [1200.0, 1200.0, 1200.0], # 1200
187
+ :as => [1235.0, 1265.0, 5620.0], # 2706.66666666667
188
+ :at => [5201.0, 4263.0, 8452.0], # 5972
189
+ :au => [0, 0, 0] # 0
190
+ # ------------------
191
+ # 206609
192
+
193
+ }
194
+ eval("AVG_SUM(ENV['ap'..'au'])", env).should == 206609
195
+
196
+ end
197
+
198
+ it "should be able to calculate MIN for an arbitrary number of argument expressions" do
199
+ program = "MIN()"
200
+ eval(program).should == 0
201
+ program = "MIN(0)"
202
+ eval(program).should == 0
203
+ program = "MIN(1)"
204
+ eval(program).should == 1
205
+ program = "MIN(1,2,3)"
206
+ eval(program).should == 1
207
+ program = "MIN(1.0, 2.0, 3.0)"
208
+ eval(program).should == 1.0
209
+ program = "MIN(fun(){4}(),fun(x){x}(4),fun(x,y){x+y}(2,2))"
210
+ eval(program).should == 4
211
+ end
212
+
213
+ it "should be able to calculate MAX for an arbitrary number of argument expressions" do
214
+ program = "MAX()"
215
+ eval(program).should == 0
216
+ program = "MAX(0)"
217
+ eval(program).should == 0
218
+ program = "MAX(1)"
219
+ eval(program).should == 1
220
+ program = "MAX(1,2,3)"
221
+ eval(program).should == 3
222
+ program = "MAX(1.0, 2.0, 3.0)"
223
+ eval(program).should == 3.0
224
+ program = "MAX(fun(){4}(),fun(x){x}(4),fun(x,y){x+y}(2,2))"
225
+ eval(program).should == 4
226
+ end
227
+
228
+ it "should be able to map all hash ids that match a given value by calling MATCHING_IDS" do
229
+ env = { :foo => { :a => "bar", :b => "bar", :c => "baz" } }
230
+ eval("MATCHING_IDS('bar', foo)", env).should include(:a)
231
+ eval("MATCHING_IDS('bar', foo)", env).should include(:b)
232
+ eval("MATCHING_IDS('baz', foo)", env).should == [ :c ]
233
+ eval("MATCHING_IDS('bam', foo)", env).should == []
234
+ end
235
+
236
+ it "should define a VALUES_OF_TYPE function" do
237
+ env = {
238
+ :all_types => { :a => "bar", :b => "bar", :c => "baz" },
239
+ :all_values => { :a => 100, :b => 200, :c => 300 }
240
+ }
241
+ eval("VALUES_OF_TYPE('bar', all_types, all_values)", env).should include(100)
242
+ eval("VALUES_OF_TYPE('bar', all_types, all_values)", env).should include(200)
243
+ eval("VALUES_OF_TYPE('baz', all_types, all_values)", env).should == [ 300 ]
244
+ eval("VALUES_OF_TYPE('bam', all_types, all_values)", env).should == []
245
+
246
+ env = {
247
+ :all_types => { :a => "bar", :b => "bar", :c => "baz" },
248
+ :all_values => { :a => [100,200,300], :b => [400,500,600], :c => [700,800,900] }
249
+ }
250
+ eval("VALUES_OF_TYPE('bar', all_types, all_values)", env).should include([100,200,300])
251
+ eval("VALUES_OF_TYPE('bar', all_types, all_values)", env).should include([400,500,600])
252
+ eval("VALUES_OF_TYPE('baz', all_types, all_values)", env).should == [ [700,800,900] ]
253
+ eval("VALUES_OF_TYPE('bam', all_types, all_values)", env).should == []
254
+
255
+ env = {
256
+ :all_types => { :a => "bar", :b => "bar", :c => "baz" },
257
+ :all_values => []
258
+ }
259
+ lambda { eval("VALUES_OF_TYPE('bar', all_types, all_values)", env) }.should raise_error(Trxl::InvalidArgumentException)
260
+
261
+ env = {
262
+ :all_types => [],
263
+ :all_values => { :a => [100,200,300], :b => [400,500,600], :c => [700,800,900] }
264
+ }
265
+ lambda { eval("VALUES_OF_TYPE('bar', all_types, all_values)", env) }.should raise_error(Trxl::InvalidArgumentException)
266
+ end
267
+
268
+ end
@@ -0,0 +1,244 @@
1
+ require 'spec_helper'
2
+
3
+ describe "For defining closures, the language" do
4
+
5
+ include Trxl::SpecHelper
6
+
7
+ before(:each) do
8
+ @parser = Trxl::Calculator.new
9
+ end
10
+
11
+ it "should parse lambdas with no parameters" do
12
+ parse("fun() {1}").eval.to_s.should == "fun() {1}"
13
+ end
14
+
15
+ it "should parse lambdas with one parameter" do
16
+ parse("fun(x) {x}").eval.to_s.should == "fun(x) {x}"
17
+ end
18
+
19
+ it "should parse lambdas with multiple parameters" do
20
+ parse("fun(x,y) {x + y}").eval.to_s.should == "fun(x,y) {x + y}"
21
+ end
22
+
23
+ it "should parse lambdas that return another lambda" do
24
+ program = "fun(x) {fun(y) {x + y}}(5)"
25
+ eval(program).to_s.should == "fun(y) {x + y}"
26
+ end
27
+
28
+
29
+ it "should be able to apply lambdas with no parameters" do
30
+ parse("fun() {2 * 2} ()").eval.should == 4
31
+ end
32
+
33
+ it "should be able to apply lambdas with one parameter" do
34
+ parse("fun(x) {x} (1)").eval.should == 1
35
+ end
36
+
37
+ it "should be able to apply lambdas with multiple parameters" do
38
+ parse("fun(x,y) {x + y} (5,5)").eval.should == 10
39
+ end
40
+
41
+ it "should be able to store lambdas in a variable and apply them later" do
42
+ eval("a = fun(x,y) {x + y}; a(5,5);").should == 10
43
+ end
44
+
45
+ it "should be able to return closures, store them in variables and apply them later" do
46
+ program = "foo = 2;"
47
+ program << "adder = fun(x) {fun(y) {x + y}}(5);"
48
+ program << "adder(2);"
49
+ eval(program).should == 7
50
+ end
51
+
52
+ it "should have read access to the enclosing scope in closures" do
53
+ program = "a = 1;"
54
+ program << "fun(){a}();"
55
+ eval(program).should == 1
56
+ end
57
+
58
+ it "should have write access to the enclosing scope in closures" do
59
+ program = "a = 0;"
60
+ program << "fun(x){a = x}(1);"
61
+ program << "a;"
62
+ eval(program).should == 1
63
+
64
+ program = <<-PROGRAM
65
+ foo = fun() {
66
+ a = 0;
67
+ fun(y) { a = y }(1);
68
+ a;
69
+ };
70
+ foo();
71
+ PROGRAM
72
+ eval(program).should == 1
73
+ end
74
+
75
+
76
+ it "should allow multiple statements in a function body" do
77
+ program = <<-PROGRAM
78
+ foo = fun(x) {
79
+ a = 3;
80
+ x + a;
81
+ };
82
+ foo(3)
83
+ PROGRAM
84
+ eval(program).should == 6
85
+ end
86
+
87
+ it "should be able to perform arithmetics in function bodies" do
88
+ eval("fun(x,y) {x+y} (5,5)").should == 10
89
+ eval("fun(x,y) {x-y} (5,5)").should == 0
90
+ eval("fun(x,y) {x*y} (5,5)").should == 25
91
+ eval("fun(x,y) {x/y} (10,5)").should == 2
92
+ eval("fun(x,y) {x%y} (10,2)").should == 0
93
+
94
+ eval("fun(x,y) {x+y*3} (5,5)").should == 20
95
+ eval("fun(x,y) {(x-y)*3} (5,5)").should == 0
96
+ eval("fun(x,y) {(x*y)+5} (5,5)").should == 30
97
+ eval("fun(x,y) {x/(y-3)} (10,5)").should == 5
98
+ eval("fun(x,y) {(x+y)%2} (10,2)").should == 0
99
+ end
100
+
101
+ it "should be able to perform recursive calls" do
102
+ program = <<-PROGRAM
103
+ fact = fun(x) { if(x == 0) 1 else fact(x - 1) * x end};
104
+ fact(5);
105
+ PROGRAM
106
+ eval(program).should == 5*4*3*2*1
107
+ end
108
+
109
+
110
+ it "should allow nested applications of recursive functions" do
111
+ program = <<-PROGRAM
112
+ require 'stdlib/inject';
113
+ inject(0, [[1,2],[3,4]], fun(m, arr) {
114
+ m + inject(0, arr, fun(sum, v) {
115
+ sum + v
116
+ })
117
+ })
118
+ PROGRAM
119
+ lambda { eval(program).should == 10 }.should_not raise_error
120
+ end
121
+
122
+ it "should evaluate actual parameters that are function applications" do
123
+ program = "a = 5;"
124
+ program << "b = 10;"
125
+ program << "sum = fun(x,y) {x + y};"
126
+ program << "div = fun(x,y) {x / y};"
127
+ program << "div(sum(a,b),a);"
128
+ eval(program).should == 3
129
+ end
130
+
131
+ it "should be able to apply previously defined closures inside function bodies" do
132
+ program = "a = 5;"
133
+ program << "b = 10;"
134
+ program << "sum = fun(x,y) {x + y};"
135
+ program << "foo = fun(x,y) {sum(x,y)};"
136
+ program << "foo(a,b);"
137
+ eval(program).should == 15
138
+ end
139
+
140
+ it "should perform left associative chained applications" do
141
+ program = "fun(x) {fun(y) {x + y}}(5)(5);"
142
+ eval(program).should == 10
143
+ program = "fun(a,b) {fun(c,d) {a * b + c * d}}(5,5)(5,5);"
144
+ eval(program).should == 50
145
+ program = "sum = fun(x,y) {x + y};"
146
+ program << "fun(a,b) {fun(c,d) {a * b + c * d}}(sum(5,5),sum(5,5))(5,5);"
147
+ eval(program).should == 125
148
+ program = "sum = fun(x,y) {x + y};"
149
+ program << "mult = fun(x,y) {x * y};"
150
+ program << "fun(a,b) {fun(c,d) {a * b + c * d}}(sum(mult(5,5),5),sum(5,5))(sum(5,5),mult(5,5));"
151
+ eval(program).should == 550
152
+ end
153
+
154
+ it "should be able to use function applications as left operand in binary operations" do
155
+ program = "sum = fun(x,y) {x + y};"
156
+ program << "sum(2,2) + 1"
157
+ eval(program).should == 5
158
+ end
159
+
160
+ it "should be able to use function applications as right operand in binary operations" do
161
+ program = "sum = fun(x,y) {x + y};"
162
+ program << "1 + sum(2,2);"
163
+ eval(program).should == 5
164
+ end
165
+
166
+ it "should be able to use function applications as operands in binary operations" do
167
+ program = "sum = fun(x,y) {x + y};"
168
+ program << "sum(1,2) + sum(3,4)"
169
+ eval(program).should == 10
170
+ end
171
+
172
+ it "should be able to use function applications as left operands in binary expressions inside function bodies" do
173
+ program = "sum = fun(x,y) {x + y};"
174
+ program << "foo = fun(x,y) {sum(x,y) + x};"
175
+ program << "foo(5,10);"
176
+ eval(program).should == 20
177
+ end
178
+
179
+ it "should be able to use function applications as right operands in binary expressions inside function bodies" do
180
+ program = "sum = fun(x,y) {x + y};"
181
+ program << "foo = fun(x,y) {x + sum(x,y)};"
182
+ program << "foo(5,10);"
183
+ eval(program).should == 20
184
+ end
185
+
186
+ it "should be able to use function applications as operands in binary expressions inside function bodies" do
187
+ program = "sum = fun(x,y) {x + y};"
188
+ program << "foo = fun(x,y) {sum(x,y) + sum(x,y)};"
189
+ program << "foo(5,10);"
190
+ eval(program).should == 30
191
+ end
192
+
193
+ it "should be able to use predefined function applications as operands in binary expressions" do
194
+ program = "AVG(10,15,20) / AVG(3,3,3)"
195
+ eval(program).should == 5
196
+ end
197
+
198
+ it "should be able to use predefined function applications as operands in binary expressions acting as actual parameters to another predefined function" do
199
+ program = "ROUND( AVG(10,15,20) / AVG(3,3,3) , 2 )"
200
+ eval(program).should == 5
201
+ end
202
+
203
+ it "should be able to use predefined and regular function applications as operands in binary expressions acting as a parameter to another predefined function" do
204
+ program = "ROUND( AVG(fun(x){x}(10),15,fun(x,y){x+y}(10,10)) / AVG(fun(x){x}(3),3,fun(x,y){x+y}(1,2)) , 2 )"
205
+ eval(program).should == 5
206
+ end
207
+
208
+ it "should have the arguments variable available in function bodies" do
209
+ program = <<-PROGRAM
210
+ require 'stdlib/inject';
211
+ sum = fun() { inject(0, arguments, fun(memo, i) { memo + i }); };
212
+ sum(1,2,3,4,5);
213
+ PROGRAM
214
+ eval(program).should == 15
215
+
216
+ program = <<-PROGRAM
217
+ require 'stdlib/inject';
218
+ sum = fun(x,y) { inject(0, arguments, fun(memo, i) { memo + i }); };
219
+ sum(1,2);
220
+ PROGRAM
221
+ eval(program).should == 3
222
+
223
+ program = <<-PROGRAM
224
+ require 'stdlib/inject';
225
+ sum = fun(x,y) { inject(0, arguments, fun(memo, i) { memo + i }); };
226
+ sum(1,2,3,4,5);
227
+ PROGRAM
228
+ eval(program).should == 15
229
+
230
+ program = <<-PROGRAM
231
+ require 'stdlib/inject';
232
+ sum = fun(x,y,z) { inject(0, arguments, fun(memo, i) { memo + i }); };
233
+ sum(1,2);
234
+ PROGRAM
235
+ lambda { eval(program) }.should raise_error(Trxl::WrongNumberOfArgumentsException)
236
+
237
+ begin
238
+ eval(program)
239
+ rescue Trxl::WrongNumberOfArgumentsException => e
240
+ e.message.should == "2 instead of 3"
241
+ end
242
+ end
243
+
244
+ end