rVM 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/lib/rake/helpers/code_statistics.rb +167 -0
  2. data/lib/rvm/classes.rb +4 -0
  3. data/lib/rvm/classes/string.rb +1 -0
  4. data/lib/rvm/functions/array.rb +3 -0
  5. data/lib/rvm/functions/array/set_at.rb +0 -4
  6. data/lib/rvm/functions/collection/size.rb +2 -2
  7. data/lib/rvm/functions/logic/and.rb +1 -1
  8. data/lib/rvm/functions/logic/or.rb +2 -2
  9. data/lib/rvm/interpreter.rb +84 -44
  10. data/lib/rvm/languages/ecma.rb +581 -501
  11. data/spec/base/class_spec.rb +27 -0
  12. data/spec/base/function_spec.rb +25 -0
  13. data/spec/base/interpreter/assignment_spec.rb +22 -0
  14. data/spec/base/interpreter/condition_spec.rb +47 -0
  15. data/spec/base/interpreter/constant_spec.rb +31 -0
  16. data/spec/base/interpreter/enviroment_spec.rb +51 -0
  17. data/spec/base/interpreter/function_call_spec.rb +72 -0
  18. data/spec/base/interpreter/interpreter_spec.rb +11 -0
  19. data/spec/base/interpreter/parameter_spec.rb +24 -0
  20. data/spec/base/interpreter/sequence_spec.rb +20 -0
  21. data/spec/base/interpreter/variable_spec.rb +24 -0
  22. data/spec/base/plugin_spec.rb +10 -0
  23. data/spec/classes/atom/association_spec.rb +39 -0
  24. data/spec/classes/atom/block_spec.rb +27 -0
  25. data/spec/classes/atom/boolean_spec.rb +67 -0
  26. data/spec/classes/atom/error_spec.rb +43 -0
  27. data/spec/classes/atom/list_spec.rb +68 -0
  28. data/spec/classes/atom/number_spec.rb +132 -0
  29. data/spec/classes/atom/string_spec.rb +175 -0
  30. data/spec/functions/association/assoc_get_spec.rb +41 -0
  31. data/spec/functions/association/assoc_set_spec.rb +43 -0
  32. data/spec/functions/collection/get_spec.rb +12 -0
  33. data/spec/functions/collection/set_spec.rb +10 -0
  34. data/spec/functions/collection/size_spec.rb +10 -0
  35. data/spec/functions/list/split_spec.rb +47 -0
  36. data/spec/functions/string/ansi_spec.rb +44 -0
  37. data/spec/functions/string/capstr_spec.rb +42 -0
  38. data/spec/functions/string/center_spec.rb +49 -0
  39. data/spec/functions/string/ljust_spec.rb +49 -0
  40. data/spec/functions/string/regmatch_spec.rb +52 -0
  41. data/spec/functions/string/rjust_spec.rb +49 -0
  42. data/spec/languages/ecma_spec.rb +337 -0
  43. data/spec/languages/math/compiler_spec.rb +49 -0
  44. data/spec/languages/math/tokenizer_spec.rb +73 -0
  45. data/spec/languages/math/tree_spec.rb +153 -0
  46. metadata +42 -5
@@ -0,0 +1,337 @@
1
+ require File.dirname(__FILE__) +'/../../lib/rvm'
2
+ require File.dirname(__FILE__) +'/../../lib/rvm/languages'
3
+ require File.dirname(__FILE__) +'/../../lib/rvm/languages/ecma'
4
+
5
+ describe RVM::Languages::ECMA do
6
+ def exec code
7
+ @compiler.compile(code).execute(@env)
8
+ end
9
+
10
+ before(:each) do
11
+ @env = RVM::Interpreter.env
12
+ @compiler = RVM::Languages::ECMA.new
13
+ end
14
+
15
+ describe "literals" do
16
+ describe "strings" do
17
+ it "should handle string literals" do
18
+ res = exec <<-EOC
19
+ "Hallo!"
20
+ EOC
21
+ res.should == "Hallo!"
22
+ end
23
+
24
+ it "should handle newline replacements" do
25
+ res = exec <<-EOC
26
+ "\n"
27
+ EOC
28
+ res.should == "\n"
29
+ end
30
+
31
+ it "should handle newline replacements" do
32
+ res = exec <<-EOC
33
+ "\t"
34
+ EOC
35
+ res.should == "\t"
36
+ end
37
+ it "should handle newline replacements" do
38
+ res = exec <<-EOC
39
+ "\n"
40
+ EOC
41
+ res.should == "\n"
42
+ end
43
+
44
+ it "should handle double escapes" do
45
+ res = exec <<-EOC
46
+ "\\t"
47
+ EOC
48
+ res.should == "\\t"
49
+ end
50
+
51
+ it "should handle double escapes followed by single escapes" do
52
+ res = exec <<-EOC
53
+ "\\\t"
54
+ EOC
55
+ res.should == "\\\t"
56
+ end
57
+ end
58
+
59
+ it "should handle number literals" do
60
+ res = exec <<-EOC
61
+ 42
62
+ EOC
63
+ res.should == 42
64
+ end
65
+
66
+ it "should handle array literals" do
67
+ res = exec <<-EOC
68
+ [42, "Kekse!"]
69
+ EOC
70
+ res.should == [42, "Kekse!"]
71
+ end
72
+
73
+ it "should handle true literals" do
74
+ res = exec <<-EOC
75
+ true
76
+ EOC
77
+ res.should be_is_true
78
+ end
79
+
80
+ it "should handle false literals" do
81
+ res = exec <<-EOC
82
+ false
83
+ EOC
84
+ res.should_not be_is_true
85
+ end
86
+ end
87
+
88
+ describe "array" do
89
+
90
+ it "should allow accessing elements" do
91
+ @env['a'] = RVM::Classes::List.new([1,2,3])
92
+ res = exec <<-EOC
93
+ a[0]
94
+ EOC
95
+ res.should == 1
96
+ end
97
+
98
+ it "should allow accessing the length" do
99
+ @env['a'] = RVM::Classes::List.new([1,2,3])
100
+ res = exec <<-EOC
101
+ a.length()
102
+ EOC
103
+ res.should == 3
104
+ end
105
+
106
+ end
107
+
108
+ describe "variables" do
109
+ it "should recognize simple assignments" do
110
+ res = exec <<-EOC
111
+ variable = 'value';
112
+ EOC
113
+ res.should == 'value'
114
+ @env['variable'].val.should == 'value'
115
+ end
116
+
117
+ it "should recognize local assignments" do
118
+ res = exec <<-EOC
119
+ var variable = 'value';
120
+ EOC
121
+ res.should == 'value'
122
+ @env['variable'].val.should == 'value'
123
+ end
124
+
125
+ it "should scope local assignments correctly" do
126
+ res = exec <<-EOC
127
+ variable = 'outer scope';
128
+ {
129
+ var variable = 'inner scope';
130
+ }
131
+ EOC
132
+ res.should == 'inner scope'
133
+ @env['variable'].val.should == 'outer scope'
134
+ end
135
+ end
136
+
137
+ describe "conditions" do
138
+ describe "true condition" do
139
+ describe "without blocks" do
140
+
141
+ it "should handle loops without else" do
142
+ res = exec <<-EOC
143
+ if (true)
144
+ 42
145
+ EOC
146
+ res.should == 42
147
+ end
148
+
149
+ it "should handle loops with else" do
150
+ res = exec <<-EOC
151
+ if (true)
152
+ 42
153
+ else
154
+ 23
155
+ EOC
156
+ res.should == 42
157
+ end
158
+
159
+ end
160
+
161
+ describe "with blocks" do
162
+ it "should handle loops without else" do
163
+ res = exec <<-EOC
164
+ if (true) {
165
+ 42
166
+ }
167
+ EOC
168
+ res.should == 42
169
+ end
170
+ it "should handle loops with else" do
171
+ res = exec <<-EOC
172
+ if (true) {
173
+ 42
174
+ } else {
175
+ 23
176
+ }
177
+ EOC
178
+ res.should == 42
179
+ end
180
+ end
181
+ end
182
+ describe "false condition" do
183
+ describe "without blocks" do
184
+ it "should handle loops without else" do
185
+ res = exec <<-EOC
186
+ if (false)
187
+ 42
188
+ EOC
189
+ res.should be_nil
190
+ end
191
+ it "should handle loops with else" do
192
+ res = exec <<-EOC
193
+ if (false)
194
+ 42
195
+ else
196
+ 23
197
+ EOC
198
+ res.should == 23
199
+ end
200
+ end
201
+ describe "with blocks" do
202
+ it "should handle loops without else" do
203
+ res = exec <<-EOC
204
+ if (false) {
205
+ 42
206
+ }
207
+ EOC
208
+ res.should be_nil
209
+ end
210
+ it "should handle loops with else" do
211
+ res = exec <<-EOC
212
+ if (false) {
213
+ 42
214
+ } else {
215
+ 23
216
+ }
217
+ EOC
218
+ res.should == 23
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ describe "loops" do
225
+ it "should handle for loops" do
226
+ res = exec <<-EOC
227
+ variable = "";
228
+ for (i = 0; i < 3; i = i + 1) {
229
+ variable = variable + i;
230
+ }
231
+ EOC
232
+ res.should == 3
233
+ @env['variable'].val.should == '012'
234
+ end
235
+
236
+ it "should handle while loops" do
237
+ res = exec <<-EOC
238
+ variable = "";
239
+ i = 0;
240
+ while (i < 3) {
241
+ i = i + 1;
242
+ variable = variable + i;
243
+ }
244
+ EOC
245
+ res.should == '123'
246
+ @env['variable'].val.should == '123'
247
+ end
248
+
249
+ it "should handle do while loops" do
250
+ res = exec <<-EOC
251
+ variable = "";
252
+ i = 0;
253
+ do {
254
+ i = i + 1;
255
+ variable = variable + i;
256
+ } while (i < 3)
257
+ EOC
258
+ res.should == '123'
259
+ @env['variable'].val.should == '123'
260
+ end
261
+ end
262
+ it "should execute do while loops at least once" do
263
+ res = exec <<-EOC
264
+ variable = "";
265
+ i = 0;
266
+ do {
267
+ i = i + 1;
268
+ variable = variable + i;
269
+ } while (i < 0)
270
+ EOC
271
+ res.should be_nil
272
+ @env['variable'].val.should == '1'
273
+ end
274
+
275
+
276
+
277
+ describe "functions" do
278
+ it "should handle function definitions without variables" do
279
+ res = exec <<-EOC
280
+ function f() {
281
+ 42;
282
+ }
283
+ EOC
284
+ res.class.should == RVM::Classes::Block
285
+ @env.function('f').should be
286
+ end
287
+
288
+ it "should handle function definitions with variables" do
289
+ res = exec <<-EOC
290
+ function g(x) {
291
+ 42 + x;
292
+ }
293
+ EOC
294
+ res.class.should == RVM::Classes::Block
295
+ @env.function('g').should be
296
+ end
297
+ end
298
+
299
+ describe "objects" do
300
+ it "should handle object variables" do
301
+ obj = mock('object mock')
302
+ varialbes = mock('variables')
303
+ obj.should_receive(:variables).once.and_return(varialbes)
304
+ obj.should_receive(:functions).once.and_return({})
305
+ varialbes.should_receive(:each)
306
+ varialbes.should_receive(:[]=)
307
+ varialbes.should_receive(:[]).with('test').and_return(RVM::Interpreter::VariableStorage.new('ok'))
308
+ @env['obj'] = obj
309
+ res = exec <<-EOC
310
+ obj.test;
311
+ EOC
312
+
313
+ res.should == 'ok'
314
+ end
315
+
316
+ it "should handle object functions" do
317
+ obj = mock('object mock')
318
+ functions = mock('variables mock')
319
+ function = mock('function mock')
320
+ obj.should_receive(:variables).once.and_return({})
321
+ obj.should_receive(:functions).once.and_return(functions)
322
+
323
+ functions.should_receive(:[]).with('test').and_return(function)
324
+ function.should_receive(:call).and_return 'ok'
325
+
326
+ @env['obj'] = obj
327
+ res = exec <<-EOC
328
+ obj.test();
329
+ EOC
330
+
331
+ res.should == 'ok'
332
+ end
333
+ end
334
+
335
+ describe "condition"
336
+
337
+ end
@@ -0,0 +1,49 @@
1
+ require File.join(File.dirname(__FILE__), '/../../../lib/rvm/interpreter')
2
+ require File.join(File.dirname(__FILE__), '/../../../lib/rvm/classes/number')
3
+ require File.join(File.dirname(__FILE__), '/../../../lib/rvm/languages/math/compiler')
4
+ describe RVM::Languages::Math::Compiler do
5
+ before do
6
+ @c = RVM::Languages::Math::Compiler
7
+ end
8
+
9
+ it "should compile numbers to constants" do
10
+ @c.compile({:type=>:number, :number=>"5"}).should be_instance_of(RVM::Interpreter::Constant);
11
+ end
12
+
13
+ it "should ignore arrays" do
14
+ @c.compile([{:type=>:number, :number=>"5"}]).should be_instance_of(RVM::Interpreter::Constant);
15
+ end
16
+
17
+ it "should compile it ident to variables" do
18
+ @c.compile({:type => :ident, :ident => "x"}).should be_instance_of(RVM::Interpreter::Variable);
19
+ end
20
+
21
+ it "should compile functions" do
22
+ @c.compile({:type => :function, :op => "x", :params => []}).should be_instance_of(RVM::Interpreter::FunctionCall);
23
+ @c.compile({:type => :function, :op => "-", :params => []}).should be_instance_of(RVM::Interpreter::FunctionCall);
24
+ end
25
+
26
+ it "should compile mathematical ooperators to function calls" do
27
+ @c.compile({:type => :op, :op => "+", :left => {:type=>:number, :number=>"5"}, :right => {:type=>:number, :number=>"5"}}).should be_instance_of(RVM::Interpreter::FunctionCall);
28
+ end
29
+
30
+ it "should compile = operators to assignments if left side is a ident" do
31
+ @c.compile({:type => :op, :op => "=", :left => {:type => :ident, :ident=>"x"}, :right => {:type=>:number, :number=>"5"}}).should be_instance_of(RVM::Interpreter::Assignment);
32
+ end
33
+
34
+ it "should compile = operators to function declaratins if left side is a function" do
35
+ @c.compile({:type => :op, :op => "=", :left => {:type => :function, :op => "x", :params => []}, :right => {:type=>:number, :number=>"5"}}).should be_instance_of(RVM::Interpreter::FunctionDefinition);
36
+ @c.compile({:type => :op, :op => "=", :left => {:type => :function, :op => "x", :params => [{:type => :ident, :ident=>"x"}]}, :right => {:type=>:number, :number=>"5"}}).should be_instance_of(RVM::Interpreter::FunctionDefinition);
37
+ end
38
+
39
+ it "should raise an error of the = operators is used with a number on the left" do
40
+ lambda {
41
+ @c.compile({:type => :op, :op => "=", :left => {:type => :number, :ident=>"5"}, :right => {:type=>:number, :number=>"5"}})
42
+ }.should raise_error
43
+ end
44
+
45
+ it "should compile ; to sepperators of sequences" do
46
+ @c.compile({:type => :op, :op => ";", :left => {:type => :ident, :ident=>"x"}, :right => {:type=>:number, :number=>"5"}}).should be_instance_of(RVM::Interpreter::Sequence);
47
+ @c.compile({:type => :op, :op => ";", :left => {:type => :op, :op => ";", :left => {:type => :ident, :ident=>"x"}, :right => {:type=>:number, :number=>"5"}}, :right => {:type => :op, :op => ";", :left => {:type => :ident, :ident=>"x"}, :right => {:type=>:number, :number=>"5"}}}).should be_instance_of(RVM::Interpreter::Sequence);
48
+ end
49
+ end
@@ -0,0 +1,73 @@
1
+ require File.join(File.dirname(__FILE__), '/../../../lib/rvm/languages/math/tokenizer')
2
+ describe RVM::Languages::Math::Tokenizer do
3
+ before do
4
+ @t = RVM::Languages::Math::Tokenizer
5
+ end
6
+
7
+ it "should tokenize numbers in it's forms" do
8
+ @t.tokenize("5").should == [['5', :number]]
9
+ @t.tokenize("42").should == [['42', :number]]
10
+ @t.tokenize("4.2").should == [['4.2', :number]]
11
+ @t.tokenize(".2").should == [['.2', :number]]
12
+ @t.tokenize("4.2e10").should == [['4.2e10', :number]]
13
+ @t.tokenize("4.2e-10").should == [['4.2e-10', :number]]
14
+ end
15
+
16
+ it "should tokenize idents" do
17
+ @t.tokenize("x").should == [['x', :ident]]
18
+ @t.tokenize("xy").should == [['xy', :ident]]
19
+ @t.tokenize("x42").should == [['x42', :ident]]
20
+ @t.tokenize("_x").should == [['_x', :ident]]
21
+ @t.tokenize("_x_").should == [['_x_', :ident]]
22
+ @t.tokenize("really_freaking_long_IdentWithA11KindOfOddStuff").should == [['really_freaking_long_IdentWithA11KindOfOddStuff', :ident]]
23
+ end
24
+
25
+ it "should ignore spaces between tokens" do
26
+ @t.tokenize("23 + 19").should == [['23', :number],['+', :opperator],['19', :number]]
27
+ end
28
+
29
+ it "should recognize mathematical opperators (+,-,*,/,^)" do
30
+ @t.tokenize("23+19").should == [['23', :number], ['+', :opperator], ['19', :number]]
31
+ @t.tokenize("43-1").should == [['43', :number], ['-', :opperator], ['1', :number]]
32
+ @t.tokenize("21*2").should == [['21', :number], ['*', :opperator], ['2', :number]]
33
+ @t.tokenize("84/2").should == [['84', :number], ['/', :opperator], ['2', :number]]
34
+ end
35
+
36
+ it "recognizes unary - and ü" do
37
+ @t.tokenize("+5").should == [['5', :number]]
38
+ @t.tokenize("++5").should == [['5', :number]]
39
+ @t.tokenize("-5").should == [['-', :function], ['5', :number]]
40
+ @t.tokenize("- 5").should == [['-', :function], ['5', :number]]
41
+ @t.tokenize("- - 5").should == [['-', :function], ['-', :function], ['5', :number]]
42
+ @t.tokenize("3 + - - 5").should == [['3', :number], ['+', :opperator], ['-', :function], ['-', :function], ['5', :number]]
43
+ end
44
+
45
+ it "should recognize functions" do
46
+ @t.tokenize("f(x)").should == [['f', :function], ['x', :ident], [')', :paren_close]]
47
+ @t.tokenize("f(x, y)").should == [['f', :function], ['x', :ident], [',', :function_sep], ['y', :ident], [')', :paren_close]]
48
+ @t.tokenize("f()").should == [['f', :function], [")", :paren_close]]
49
+ end
50
+
51
+ it "should recognize parentheethes" do
52
+ @t.tokenize("(42)").should == [["(", :paren_open], ["42", :number], [")", :paren_close]]
53
+ @t.tokenize("(f(x))").should == [["(", :paren_open], ['f', :function], ['x', :ident], [')', :paren_close], [")", :paren_close]]
54
+ @t.tokenize("(19+23)").should == [["(", :paren_open], ['19', :number], ['+', :opperator], ['23', :number], [")", :paren_close]]
55
+ end
56
+
57
+ it "should recognize semicolons" do
58
+ @t.tokenize("42;42").should == [["42", :number], [";", :opperator], ["42", :number]]
59
+ end
60
+
61
+ it "should not alow semicolons within brackets" do
62
+ lambda{@t.tokenize("(42;42)")}.should raise_error
63
+ end
64
+
65
+ it "should throw exeptions on unknown literals where numbers are expected" do
66
+ lambda{@t.tokenize("42that_is_not_valid!")}.should raise_error
67
+ end
68
+
69
+ it "should throw exeptions on unknown literals" do
70
+ lambda{@t.tokenize("42that_is_not_valid!")}.should raise_error
71
+ lambda{@t.tokenize("?")}.should raise_error
72
+ end
73
+ end