trxl 0.1.5

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.
@@ -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