rVM 0.0.10 → 0.0.11

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