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.
- data/.gitignore +24 -0
- data/README +143 -0
- data/Rakefile +41 -0
- data/VERSION +1 -0
- data/lib/trxl.rb +5 -0
- data/lib/trxl/trxl.rb +585 -0
- data/lib/trxl/trxl_grammar.rb +8583 -0
- data/lib/trxl/trxl_grammar.treetop +1394 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/trxl/arithmetics_spec.rb +391 -0
- data/spec/trxl/arrays_spec.rb +163 -0
- data/spec/trxl/booleans_spec.rb +138 -0
- data/spec/trxl/builtins_spec.rb +268 -0
- data/spec/trxl/closures_spec.rb +244 -0
- data/spec/trxl/comments_spec.rb +35 -0
- data/spec/trxl/common_spec.rb +22 -0
- data/spec/trxl/conditionals_spec.rb +454 -0
- data/spec/trxl/constants_spec.rb +23 -0
- data/spec/trxl/environment_spec.rb +117 -0
- data/spec/trxl/hashes_spec.rb +62 -0
- data/spec/trxl/numbers_spec.rb +27 -0
- data/spec/trxl/ranges_spec.rb +81 -0
- data/spec/trxl/require_spec.rb +50 -0
- data/spec/trxl/stdlib_spec.rb +370 -0
- data/spec/trxl/strings_spec.rb +1 -0
- data/spec/trxl/variables_spec.rb +45 -0
- data/trxl.gemspec +90 -0
- metadata +119 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "For commenting, 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 single line comments" do
|
12
|
+
eval("# This is only a comment").should be_nil
|
13
|
+
eval("# This is only a comment\n").should be_nil
|
14
|
+
eval("# This is only a comment a = 5; a;").should be_nil
|
15
|
+
eval("a = 5 # This is only a comment").should == 5
|
16
|
+
eval("a = 5 # This is only a comment\n").should == 5
|
17
|
+
eval("a = 5; # This is only a comment").should == 5
|
18
|
+
eval("a = 5; # This is only a comment\n").should == 5
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should allow multi line comments" do
|
22
|
+
eval("/* This is a multiline comment */ a = 5; a;").should == 5
|
23
|
+
eval("a = 5; /* This is a multiline comment */ a;").should == 5
|
24
|
+
|
25
|
+
program = <<-PROGRAM
|
26
|
+
a = 1;
|
27
|
+
/*
|
28
|
+
* This is a multiline comment
|
29
|
+
*/
|
30
|
+
a * 2;
|
31
|
+
PROGRAM
|
32
|
+
eval(program).should == 2
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "The parser" do
|
4
|
+
|
5
|
+
include Trxl::SpecHelper
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
@parser = Trxl::Calculator.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return NULL for an empty string" do
|
12
|
+
program = ""
|
13
|
+
eval(program).should == nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should ignore multiple ';' characters (like ;;;)" do
|
17
|
+
eval(";").should == nil
|
18
|
+
eval(";;").should == nil
|
19
|
+
eval("1+1;;").should == 2
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,454 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "For conditional evaluation, the language" do
|
4
|
+
|
5
|
+
include Trxl::SpecHelper
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@parser = Trxl::Calculator.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should be able to evaluate conditional 'if' expressions without elsif and else branches" do
|
12
|
+
program = "test = fun(x) { if(x) TRUE end };"
|
13
|
+
eval(program + "test(TRUE)").should be_true
|
14
|
+
eval(program + "test(FALSE)").should be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be able to evaluate conditional 'if' expressions with only an else branch" do
|
18
|
+
program = <<-PROGRAM
|
19
|
+
if(TRUE)
|
20
|
+
TRUE
|
21
|
+
else
|
22
|
+
FALSE
|
23
|
+
end
|
24
|
+
PROGRAM
|
25
|
+
eval(program).should be_true
|
26
|
+
|
27
|
+
program = <<-PROGRAM
|
28
|
+
if(FALSE)
|
29
|
+
TRUE
|
30
|
+
else
|
31
|
+
FALSE
|
32
|
+
end
|
33
|
+
PROGRAM
|
34
|
+
eval(program).should be_false
|
35
|
+
|
36
|
+
program = <<-PROGRAM
|
37
|
+
if(NULL)
|
38
|
+
TRUE
|
39
|
+
else
|
40
|
+
FALSE
|
41
|
+
end
|
42
|
+
PROGRAM
|
43
|
+
eval(program).should be_false
|
44
|
+
|
45
|
+
program = <<-PROGRAM
|
46
|
+
if(NULL != NULL)
|
47
|
+
TRUE
|
48
|
+
else
|
49
|
+
FALSE
|
50
|
+
end
|
51
|
+
PROGRAM
|
52
|
+
eval(program).should be_false
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should be able to evaluate nested 'if' expressions" do
|
56
|
+
program = <<-PROGRAM
|
57
|
+
if(TRUE)
|
58
|
+
if(TRUE)
|
59
|
+
TRUE
|
60
|
+
else
|
61
|
+
FALSE
|
62
|
+
end
|
63
|
+
else
|
64
|
+
FALSE
|
65
|
+
end
|
66
|
+
PROGRAM
|
67
|
+
eval(program).should be_true
|
68
|
+
|
69
|
+
program = <<-PROGRAM
|
70
|
+
x = 1;
|
71
|
+
if(TRUE)
|
72
|
+
if(TRUE)
|
73
|
+
x
|
74
|
+
else
|
75
|
+
FALSE
|
76
|
+
end
|
77
|
+
else
|
78
|
+
FALSE
|
79
|
+
end
|
80
|
+
PROGRAM
|
81
|
+
eval(program).should == 1
|
82
|
+
|
83
|
+
program = <<-PROGRAM
|
84
|
+
foo = fun() {
|
85
|
+
if(TRUE)
|
86
|
+
if(TRUE)
|
87
|
+
TRUE
|
88
|
+
else
|
89
|
+
FALSE
|
90
|
+
end
|
91
|
+
else
|
92
|
+
FALSE
|
93
|
+
end
|
94
|
+
};
|
95
|
+
foo()
|
96
|
+
PROGRAM
|
97
|
+
eval(program).should be_true
|
98
|
+
|
99
|
+
program = <<-PROGRAM
|
100
|
+
foo = fun() {
|
101
|
+
if(TRUE)
|
102
|
+
if(TRUE)
|
103
|
+
"if branch"
|
104
|
+
else
|
105
|
+
FALSE
|
106
|
+
end
|
107
|
+
elsif(2 == 3)
|
108
|
+
FALSE
|
109
|
+
elsif(2 == 4)
|
110
|
+
FALSE
|
111
|
+
else
|
112
|
+
FALSE
|
113
|
+
end
|
114
|
+
};
|
115
|
+
foo()
|
116
|
+
PROGRAM
|
117
|
+
eval(program).should == "if branch"
|
118
|
+
|
119
|
+
program = <<-PROGRAM
|
120
|
+
foo = fun() {
|
121
|
+
if(FALSE)
|
122
|
+
if(TRUE)
|
123
|
+
TRUE
|
124
|
+
else
|
125
|
+
FALSE
|
126
|
+
end
|
127
|
+
elsif(TRUE)
|
128
|
+
if(TRUE)
|
129
|
+
"first elsif branch"
|
130
|
+
else
|
131
|
+
FALSE
|
132
|
+
end
|
133
|
+
elsif(2 == 4)
|
134
|
+
FALSE
|
135
|
+
else
|
136
|
+
FALSE
|
137
|
+
end
|
138
|
+
};
|
139
|
+
foo()
|
140
|
+
PROGRAM
|
141
|
+
eval(program).should == "first elsif branch"
|
142
|
+
|
143
|
+
program = <<-PROGRAM
|
144
|
+
foo = fun() {
|
145
|
+
if(FALSE)
|
146
|
+
if(TRUE)
|
147
|
+
TRUE
|
148
|
+
else
|
149
|
+
FALSE
|
150
|
+
end
|
151
|
+
elsif(FALSE)
|
152
|
+
if(TRUE)
|
153
|
+
"first elsif branch"
|
154
|
+
else
|
155
|
+
FALSE
|
156
|
+
end
|
157
|
+
elsif(TRUE)
|
158
|
+
if(TRUE)
|
159
|
+
"second elsif branch"
|
160
|
+
else
|
161
|
+
FALSE
|
162
|
+
end
|
163
|
+
else
|
164
|
+
FALSE
|
165
|
+
end
|
166
|
+
};
|
167
|
+
foo()
|
168
|
+
PROGRAM
|
169
|
+
eval(program).should == "second elsif branch"
|
170
|
+
|
171
|
+
program = <<-PROGRAM
|
172
|
+
foo = fun() {
|
173
|
+
if(FALSE)
|
174
|
+
if(TRUE)
|
175
|
+
TRUE
|
176
|
+
else
|
177
|
+
FALSE
|
178
|
+
end
|
179
|
+
elsif(FALSE)
|
180
|
+
if(TRUE)
|
181
|
+
"first elsif branch"
|
182
|
+
else
|
183
|
+
FALSE
|
184
|
+
end
|
185
|
+
elsif(FALSE)
|
186
|
+
if(TRUE)
|
187
|
+
"second elsif branch"
|
188
|
+
else
|
189
|
+
FALSE
|
190
|
+
end
|
191
|
+
else
|
192
|
+
if(TRUE)
|
193
|
+
"else branch"
|
194
|
+
else
|
195
|
+
FALSE
|
196
|
+
end
|
197
|
+
end
|
198
|
+
};
|
199
|
+
foo()
|
200
|
+
PROGRAM
|
201
|
+
eval(program).should == "else branch"
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should be able to evaluate conditional 'if' expressions with multiple elsif and an else branch" do
|
205
|
+
program = <<-PROGRAM
|
206
|
+
foo = fun() {
|
207
|
+
if(2 == 2)
|
208
|
+
0
|
209
|
+
elsif(2 == 3)
|
210
|
+
1
|
211
|
+
elsif(2 == 4)
|
212
|
+
2
|
213
|
+
else
|
214
|
+
3
|
215
|
+
end
|
216
|
+
};
|
217
|
+
foo();
|
218
|
+
PROGRAM
|
219
|
+
eval(program).should == 0
|
220
|
+
|
221
|
+
program = <<-PROGRAM
|
222
|
+
foo = fun() {
|
223
|
+
if(2 == 1)
|
224
|
+
0
|
225
|
+
elsif(2 == 2)
|
226
|
+
1
|
227
|
+
elsif(2 == 3)
|
228
|
+
2
|
229
|
+
else
|
230
|
+
3
|
231
|
+
end
|
232
|
+
};
|
233
|
+
foo();
|
234
|
+
PROGRAM
|
235
|
+
eval(program).should == 1
|
236
|
+
|
237
|
+
program = <<-PROGRAM
|
238
|
+
foo = fun() {
|
239
|
+
if(2 == 0)
|
240
|
+
0
|
241
|
+
elsif(2 == 1)
|
242
|
+
1
|
243
|
+
elsif(2 == 2)
|
244
|
+
2
|
245
|
+
else
|
246
|
+
3
|
247
|
+
end
|
248
|
+
};
|
249
|
+
foo();
|
250
|
+
PROGRAM
|
251
|
+
eval(program).should == 2
|
252
|
+
|
253
|
+
program = <<-PROGRAM
|
254
|
+
foo = fun() {
|
255
|
+
if(2 == 0)
|
256
|
+
0
|
257
|
+
elsif(2 == 1)
|
258
|
+
1
|
259
|
+
elsif(2 == 3)
|
260
|
+
2
|
261
|
+
else
|
262
|
+
3
|
263
|
+
end
|
264
|
+
};
|
265
|
+
foo();
|
266
|
+
PROGRAM
|
267
|
+
eval(program).should == 3
|
268
|
+
|
269
|
+
program = <<-PROGRAM
|
270
|
+
foo = fun(value) {
|
271
|
+
if(value <= 5000)
|
272
|
+
22.02
|
273
|
+
elsif(value <= 12000)
|
274
|
+
18.75
|
275
|
+
elsif(value <= 25000)
|
276
|
+
15.92
|
277
|
+
elsif(value <= 50000)
|
278
|
+
12.72
|
279
|
+
elsif(value > 50000)
|
280
|
+
10.32
|
281
|
+
else
|
282
|
+
NULL
|
283
|
+
end
|
284
|
+
};
|
285
|
+
foo(13000);
|
286
|
+
PROGRAM
|
287
|
+
eval(program).should == 15.92
|
288
|
+
end
|
289
|
+
|
290
|
+
it "should allow an arbitrary number of statements inside if/elsif/else expressions" do
|
291
|
+
program = <<-PROGRAM
|
292
|
+
foo = fun() {
|
293
|
+
if(2 == 2)
|
294
|
+
a = 0;
|
295
|
+
a
|
296
|
+
elsif(2 == 1)
|
297
|
+
b = 1;
|
298
|
+
b
|
299
|
+
elsif(2 == 3)
|
300
|
+
c = 2;
|
301
|
+
c
|
302
|
+
else
|
303
|
+
d = 3;
|
304
|
+
d
|
305
|
+
end
|
306
|
+
};
|
307
|
+
foo();
|
308
|
+
PROGRAM
|
309
|
+
eval(program).should == 0
|
310
|
+
|
311
|
+
program = <<-PROGRAM
|
312
|
+
foo = fun() {
|
313
|
+
if(2 == 0)
|
314
|
+
a = 0;
|
315
|
+
a
|
316
|
+
elsif(2 == 2)
|
317
|
+
b = 1;
|
318
|
+
b
|
319
|
+
elsif(2 == 3)
|
320
|
+
c = 2;
|
321
|
+
c
|
322
|
+
else
|
323
|
+
d = 3;
|
324
|
+
d
|
325
|
+
end
|
326
|
+
};
|
327
|
+
foo();
|
328
|
+
PROGRAM
|
329
|
+
eval(program).should == 1
|
330
|
+
|
331
|
+
program = <<-PROGRAM
|
332
|
+
foo = fun() {
|
333
|
+
if(2 == 0)
|
334
|
+
a = 0;
|
335
|
+
a
|
336
|
+
elsif(2 == 1)
|
337
|
+
b = 1;
|
338
|
+
b
|
339
|
+
elsif(2 == 2)
|
340
|
+
c = 2;
|
341
|
+
c
|
342
|
+
else
|
343
|
+
d = 3;
|
344
|
+
d
|
345
|
+
end
|
346
|
+
};
|
347
|
+
foo();
|
348
|
+
PROGRAM
|
349
|
+
eval(program).should == 2
|
350
|
+
|
351
|
+
program = <<-PROGRAM
|
352
|
+
foo = fun() {
|
353
|
+
if(2 == 0)
|
354
|
+
a = 0;
|
355
|
+
a
|
356
|
+
elsif(2 == 1)
|
357
|
+
b = 1;
|
358
|
+
b
|
359
|
+
elsif(2 == 3)
|
360
|
+
c = 2;
|
361
|
+
c
|
362
|
+
else
|
363
|
+
d = 3;
|
364
|
+
d
|
365
|
+
end
|
366
|
+
};
|
367
|
+
foo();
|
368
|
+
PROGRAM
|
369
|
+
eval(program).should == 3
|
370
|
+
end
|
371
|
+
|
372
|
+
it "should allow arbitrary expressions as conditional expression" do
|
373
|
+
program = "test = fun(x) {if(x == 0) TRUE else FALSE end};"
|
374
|
+
program << "test(0)"
|
375
|
+
eval(program).should be_true
|
376
|
+
program = "test = fun(x) {if(2*2 == 4) TRUE else FALSE end};"
|
377
|
+
program << "test(0)"
|
378
|
+
eval(program).should be_true
|
379
|
+
program = "test = fun(x) {if(TRUE) TRUE else FALSE end};"
|
380
|
+
program << "test(0)"
|
381
|
+
eval(program).should be_true
|
382
|
+
program = "test = fun(x) {if(x) TRUE else FALSE end};"
|
383
|
+
program << "test(TRUE)"
|
384
|
+
eval(program).should be_true
|
385
|
+
program = "test = fun(x) {if(x) TRUE else FALSE end};"
|
386
|
+
program << "test(FALSE)"
|
387
|
+
eval(program).should be_false
|
388
|
+
program = "x = TRUE;"
|
389
|
+
program << "test = fun(x) {if(x) TRUE else FALSE end};"
|
390
|
+
program << "test(x)"
|
391
|
+
eval(program).should be_true
|
392
|
+
program = "x = (4 == 4);"
|
393
|
+
program << "test = fun(x) {if(x) TRUE else FALSE end};"
|
394
|
+
program << "test(x)"
|
395
|
+
eval(program).should be_true
|
396
|
+
end
|
397
|
+
|
398
|
+
it "should allow 'case' expressions with multiple 'when' and one 'else' branch" do
|
399
|
+
program = <<-PROGRAM
|
400
|
+
foo = fun(x) {
|
401
|
+
case x
|
402
|
+
when 1 then "one"
|
403
|
+
when 2 then "two"
|
404
|
+
when 3 then "three"
|
405
|
+
else FALSE
|
406
|
+
end
|
407
|
+
};
|
408
|
+
foo(2);
|
409
|
+
PROGRAM
|
410
|
+
eval(program).should == "two"
|
411
|
+
|
412
|
+
program = <<-PROGRAM
|
413
|
+
foo = fun(x) {
|
414
|
+
case x
|
415
|
+
when "foo" then "yes"
|
416
|
+
when "bar" then "no"
|
417
|
+
else FALSE
|
418
|
+
end
|
419
|
+
};
|
420
|
+
foo("foo");
|
421
|
+
PROGRAM
|
422
|
+
eval(program).should == "yes"
|
423
|
+
|
424
|
+
program = <<-PROGRAM
|
425
|
+
foo = fun(x) {
|
426
|
+
case x
|
427
|
+
when "foo" then "yes"
|
428
|
+
when "bar" then "no"
|
429
|
+
else "something else"
|
430
|
+
end
|
431
|
+
};
|
432
|
+
foo("hello");
|
433
|
+
PROGRAM
|
434
|
+
eval(program).should == "something else"
|
435
|
+
end
|
436
|
+
|
437
|
+
it "should allow multiple statements in each branch of a 'case' expression" do
|
438
|
+
program = <<-PROGRAM
|
439
|
+
foo = fun(x) {
|
440
|
+
num = 0;
|
441
|
+
name = case x
|
442
|
+
when 1 then num = num + 1; "one"
|
443
|
+
when 2 then num = num + 2; "two"
|
444
|
+
when 3 then num = num + 3; "three"
|
445
|
+
else FALSE
|
446
|
+
end;
|
447
|
+
[ num, name ]
|
448
|
+
};
|
449
|
+
foo(1);
|
450
|
+
PROGRAM
|
451
|
+
eval(program).should == [ 1, "one" ]
|
452
|
+
end
|
453
|
+
|
454
|
+
end
|