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,167 @@
1
+ # From rails (http://rubyonrails.com)
2
+ #
3
+ # Improved by murphy
4
+ class CodeStatistics
5
+
6
+ TEST_TYPES = /\btest/i
7
+
8
+ # Create a new Code Statistic.
9
+ #
10
+ # Rakefile Example:
11
+ #
12
+ # desc 'Report code statistics (LOC) from the application'
13
+ # task :stats => :copy_files do
14
+ # require 'rake_helpers/code_statistics'
15
+ # CodeStatistics.new(
16
+ # ["Main", "lib"],
17
+ # ["Tests", "test"],
18
+ # ["Demos", "demo"]
19
+ # ).to_s
20
+ # end
21
+ def initialize(*pairs)
22
+ @pairs = pairs
23
+ @statistics = calculate_statistics
24
+ @total = if pairs.empty? then nil else calculate_total end
25
+ end
26
+
27
+ # Print a textual table viewing the stats
28
+ #
29
+ # Intended for console output.
30
+ def print
31
+ print_header
32
+ @pairs.each { |name, path| print_line name, @statistics[name] }
33
+ print_splitter
34
+
35
+ if @total
36
+ print_line 'Total', @total
37
+ print_splitter
38
+ end
39
+
40
+ print_code_test_stats
41
+ end
42
+
43
+ private
44
+
45
+ DEFAULT_FILE_PATTERN = /\.rb$/
46
+
47
+ def calculate_statistics
48
+ @pairs.inject({}) do |stats, (name, path, pattern, is_ruby_code)|
49
+ pattern ||= DEFAULT_FILE_PATTERN
50
+ path = File.join path, '*.rb'
51
+ stats[name] = calculate_directory_statistics path, pattern, is_ruby_code
52
+ stats
53
+ end
54
+ end
55
+
56
+ def calculate_directory_statistics directory, pattern = DEFAULT_FILE_PATTERN, is_ruby_code = true
57
+ is_ruby_code = true if is_ruby_code.nil?
58
+ stats = Hash.new 0
59
+
60
+ Dir[directory].each do |file_name|
61
+ puts "Scanning #{file_name}..." if $DEBUG
62
+ next unless file_name =~ pattern
63
+
64
+ lines = codelines = classes = modules = methods = 0
65
+ empty_lines = comment_lines = 0
66
+ in_comment_block = false
67
+
68
+ File.readlines(file_name).each do |line|
69
+ lines += 1
70
+ if line[/^\s*$/]
71
+ empty_lines += 1
72
+ elsif is_ruby_code
73
+ case line
74
+ when /^=end\b/
75
+ comment_lines += 1
76
+ in_comment_block = false
77
+ when in_comment_block
78
+ comment_lines += 1
79
+ when /^\s*class\b/: classes += 1
80
+ when /^\s*module\b/: modules += 1
81
+ when /^\s*def\b/: methods += 1
82
+ when /^\s*#/: comment_lines += 1
83
+ when /^=begin\b/
84
+ in_comment_block = false
85
+ comment_lines += 1
86
+ when /^__END__$/
87
+ in_comment_block = true
88
+ end
89
+ end
90
+ end
91
+
92
+ codelines = lines - comment_lines - empty_lines
93
+
94
+ stats[:lines] += lines
95
+ stats[:comments] += comment_lines
96
+ stats[:codelines] += codelines
97
+ stats[:classes] += classes
98
+ stats[:modules] += modules
99
+ stats[:methods] += methods
100
+ stats[:files] += 1
101
+ end
102
+
103
+ stats
104
+ end
105
+
106
+ def calculate_total
107
+ total = Hash.new 0
108
+ @statistics.each_value { |pair| pair.each { |k, v| total[k] += v } }
109
+ total
110
+ end
111
+
112
+ def calculate_code
113
+ code_loc = 0
114
+ @statistics.each { |k, v| code_loc += v[:codelines] unless k[TEST_TYPES] }
115
+ code_loc
116
+ end
117
+
118
+ def calculate_tests
119
+ test_loc = 0
120
+ @statistics.each { |k, v| test_loc += v[:codelines] if k[TEST_TYPES] }
121
+ test_loc
122
+ end
123
+
124
+ def print_header
125
+ print_splitter
126
+ puts "| T=Test Name | Files | Lines | LOC | Comments | Classes | Modules | Methods | M/C | LOC/M |"
127
+ print_splitter
128
+ end
129
+
130
+ def print_splitter
131
+ puts "+---------------------------+-------+-------+-------+----------+---------+---------+---------+-----+-------+"
132
+ end
133
+
134
+ def print_line name, statistics
135
+ m_over_c = (statistics[:methods] / (statistics[:classes] + statistics[:modules])) rescue m_over_c = 0
136
+ loc_over_m = (statistics[:codelines] / statistics[:methods]) - 2 rescue loc_over_m = 0
137
+
138
+ if name[TEST_TYPES]
139
+ name = "T #{name}"
140
+ else
141
+ name = " #{name}"
142
+ end
143
+
144
+ line = "| %-25s | %5d | %5d | %5d | %8d | %7d | %7d | %7d | %3d | %5d |" % (
145
+ [name, *statistics.values_at(:files, :lines, :codelines, :comments, :classes, :modules, :methods)] +
146
+ [m_over_c, loc_over_m] )
147
+
148
+ puts line
149
+ end
150
+
151
+ def print_code_test_stats
152
+ code = calculate_code
153
+ tests = calculate_tests
154
+
155
+ puts " Code LOC = #{code} Test LOC = #{tests} Code:Test Ratio = [1 : #{sprintf("%.2f", tests.to_f/code)}]"
156
+ puts ""
157
+ end
158
+
159
+ end
160
+
161
+ # Run a test script.
162
+ if $0 == __FILE__
163
+ $VERBOSE = true
164
+ CodeStatistics.new(
165
+ ['This dir', File.dirname(__FILE__)]
166
+ ).print
167
+ end
@@ -59,6 +59,10 @@ module RVM
59
59
  @variables ||= {:self => self, }
60
60
  end
61
61
 
62
+ def is_true?
63
+ true
64
+ end
65
+
62
66
  # This defines the type of the class, it defaults to :any
63
67
  # it is important for tying and type conversion, as long as it
64
68
  # behaves like a string, it can look like a sting ;)
@@ -59,6 +59,7 @@ module RVM
59
59
  end
60
60
 
61
61
  def + v
62
+ v = v.to_s if not v.is_a?(String)
62
63
  self.class.new(super(v))
63
64
  end
64
65
 
@@ -1,3 +1,6 @@
1
1
  Dir[File.dirname(__FILE__) + '/array/*.rb'].each do |c|
2
2
  require c
3
+ end
4
+ Dir[File.dirname(__FILE__) + '/collection/*.rb'].each do |c|
5
+ require c
3
6
  end
@@ -3,13 +3,9 @@ module RVM
3
3
  class SetAt < Function
4
4
  def SetAt.execute params, env
5
5
  if params.length == 3
6
- p params
7
6
  array = params.shift
8
7
  pos = params.shift
9
8
  value = params.shift
10
- p array
11
- p pos
12
- p value
13
9
  array[pos.to_i] = value
14
10
  else
15
11
  RVM::Classes[:error].new(1,"FUNCTION (#{self.class}) EXPECTS 3 ARGUMENTS BUT GOT #{params.length}")
@@ -7,12 +7,12 @@ module RVM
7
7
  RVM::Classes::Association
8
8
  ]
9
9
  def execute params, env
10
- if COLLECTION_CLASSES.include?(this = env.read_var_val(:self)) and params.empty?
10
+ if COLLECTION_CLASSES.include?((this = env.read_var_val(:self)).class) and params.empty?
11
11
  RVM::Classes[:number].new(this.size)
12
12
  elsif params.length == 1
13
13
  RVM::Classes[:number].new(params[0].size)
14
14
  else
15
- RVM::Classes[:error].new(1,"FUNCTION (#{self.class}) EXPECTS 2 ARGUMENTS BUT GOT #{params.length}")
15
+ RVM::Classes[:error].new(1,"FUNCTION (#{self}) EXPECTS 1 or 0 ARGUMENTS BUT GOT #{params.length}")
16
16
  end
17
17
  end
18
18
  def signature
@@ -6,7 +6,7 @@ module RVM
6
6
  def execute params, env
7
7
  result = true
8
8
  while result and not params.empty?
9
- result = result && params.shift.execute(env).is_true?
9
+ result = result && (v = params.shift) && v.execute(env).is_true?
10
10
  end
11
11
  result
12
12
  end
@@ -4,8 +4,8 @@ module RVM
4
4
  class << self
5
5
  def execute params, env
6
6
  params.each do |p|
7
- v = p.execute(env)
8
- return v if v.is_true?
7
+
8
+ return v if p && (v = p.execute(env)).is_true?
9
9
  end
10
10
  return RVM::Classes::Boolean.new(false)
11
11
  end
@@ -9,6 +9,13 @@ module RVM
9
9
  #
10
10
  module Interpreter
11
11
 
12
+
13
+ class Element
14
+ attr_accessor :pos
15
+ def initialize pos
16
+ @pos = pos
17
+ end
18
+ end
12
19
  # This is a helper fuctio to quickly generate a empty enviorment.
13
20
  def Interpreter.env aenv = {}
14
21
  RVM::debug "Interpreter.env" if $DEBUG
@@ -22,22 +29,8 @@ module RVM
22
29
  RVM::Interpreter::Constant.new(RVM::Classes[type].new(value), pos)
23
30
  end
24
31
 
25
-
26
- class VariableStorageCallback
27
- def initialize obj, var, writable = true
28
- @obj = obj
29
- @get = var.to_sym
30
- @set = "#{var}=".to_sym
31
- @writable = writable
32
- end
33
- def val= v
34
- @obj.send(@set,v) if @writable
35
- end
36
- def val
37
- @obj.send(@get)
38
- end
39
- end
40
-
32
+ # This class is used to store the variable content to allow chross refferencing
33
+ # and passing variables upwards through different scopes.
41
34
  class VariableStorage
42
35
  attr_accessor :val
43
36
  def initialize val = nil, writable = true, &block
@@ -50,6 +43,23 @@ module RVM
50
43
  @val = v if @writable
51
44
  @val
52
45
  end
46
+ end
47
+
48
+ # The callback storang is used to help publishing variables from a ruby
49
+ # class to the rVM, it will get and set the variables during runtime.
50
+ class VariableStorageCallback < VariableStorage
51
+ def initialize obj, var, writable = true
52
+ super(nil, writable)
53
+ @obj = obj
54
+ @get = var.to_sym
55
+ @set = "#{var}=".to_sym
56
+ end
57
+ def val= v
58
+ @obj.send(@set,v) if @writable
59
+ end
60
+ def val
61
+ @obj.send(@get)
62
+ end
53
63
  end
54
64
 
55
65
  # This class represents the enviroment, the memory so to say for the VM.
@@ -135,7 +145,7 @@ module RVM
135
145
  end
136
146
  # Defines a varialbe in the current scope, priviose variables are not
137
147
  # changed
138
- def define k, v
148
+ def declare k, v
139
149
  @data[:locals][k] = VariableStorage.new(v)
140
150
  end
141
151
 
@@ -182,18 +192,18 @@ module RVM
182
192
  # is set to the object in which context we are!
183
193
  #
184
194
  # The class is stred in :class
185
- class ObjectContext
195
+ class ObjectContext < Element
186
196
  def initialize object, code, pos = nil
197
+ super(pos)
187
198
  @object = object
188
199
  @code = code
189
- @pos = pos
190
200
  end
191
201
 
192
202
  def execute env
193
203
  #The new
194
204
  obj = @object.execute(env)
195
205
  new_env = Interpreter::Enviroment.new({:functions => obj.functions, :locals => obj.variables}, env)
196
- new_env.define(:self, obj)
206
+ new_env.declare(:self, obj)
197
207
  @code.execute(new_env)
198
208
  end
199
209
  end
@@ -202,12 +212,12 @@ module RVM
202
212
  #This sets a funciton on a Class (to be included in its objects)
203
213
  #
204
214
  #To define class functions use ObjectContext and define the function normaly, nifty isn't it?
205
- class SetClassFunction
215
+ class SetClassFunction < Element
206
216
  def initialize obj, name, function, pos = nil
217
+ super(pos)
207
218
  @object = obj
208
219
  @name = name
209
220
  @function = function
210
- @pos = pos
211
221
  end
212
222
 
213
223
  def execute env
@@ -221,11 +231,11 @@ module RVM
221
231
  #
222
232
  # Blocks are mostly used to handle tasks as not interfeeing
223
233
  # With outer code.
224
- class Block
234
+ class Block < Element
225
235
  attr_reader :content
226
236
  def initialize content, pos = nil
237
+ super(pos)
227
238
  @content = content
228
- @pos = pos
229
239
  end
230
240
 
231
241
  # When executed a temporary enviroment is created with the passed
@@ -239,7 +249,7 @@ module RVM
239
249
 
240
250
  # This is a function definition used to write in the function libary
241
251
  #
242
- class FunctionDefinition
252
+ class FunctionDefinition < Element
243
253
 
244
254
  # Initializes a new function definition
245
255
  #
@@ -254,10 +264,10 @@ module RVM
254
264
  # replaced when it is called a second time.
255
265
  # When false a exception is thrown
256
266
  def initialize name, body, override = true, pos = nil
267
+ super(pos)
257
268
  @name = name
258
269
  @body = body
259
270
  @override = override
260
- @pos = pos
261
271
  end
262
272
 
263
273
  def execute env
@@ -265,14 +275,14 @@ module RVM
265
275
  raise "Function #{@name} already defined at #{@pos}!"
266
276
  end
267
277
  env.def_function(@name.execute(env),@body)
268
- nil
278
+ @body
269
279
  end
270
280
  end
271
281
 
272
282
 
273
283
  # This is a loop. It is executed over and over again as long as
274
284
  # the passed condition evaluates to a value that matches is_true?.
275
- class Loop
285
+ class Loop < Element
276
286
  # Initializes a new loop.
277
287
  #
278
288
  # condition:: is executed before each run of the loop. If it evaluates
@@ -280,15 +290,17 @@ module RVM
280
290
  # exection ends.
281
291
  # body:: For each itteration of the loop this is executed once.
282
292
  def initialize(condition, body, pos = nil)
293
+ super(pos)
283
294
  @condition = condition
284
295
  @body = body
285
- @pos = pos
286
296
  end
287
297
 
288
298
  def execute env
299
+ r = nil
289
300
  while @condition.execute(env).is_true?
290
- @body.execute(env)
301
+ r = @body.execute(env)
291
302
  end
303
+ r
292
304
  end
293
305
  end
294
306
 
@@ -296,11 +308,11 @@ module RVM
296
308
  # A constant, it evaluates to thevalue given and end the evaluation.
297
309
  # Meaning that no further execution is done in this tree branch, so the
298
310
  # value isn't evaluated.
299
- class Constant
311
+ class Constant < Element
300
312
  attr_reader :value
301
313
  def initialize value, pos = nil
314
+ super(pos)
302
315
  @value = value
303
- @pos = pos
304
316
  end
305
317
 
306
318
  def data_type
@@ -342,7 +354,7 @@ module RVM
342
354
  # * execute for the true case is called and it's result returned
343
355
  # * if the result is false or is_true? is false:
344
356
  # * execute is called for the false case and it's result is returned
345
- class Condition
357
+ class Condition < Element
346
358
  # Creates a new condition with the given parameters. The false_case can
347
359
  # be ommitted.
348
360
  #
@@ -351,10 +363,10 @@ module RVM
351
363
  # * true_case - is only executed if value evalutes to true (is_true?)
352
364
  # * false_case - is only executed if value evalutes to false (!is_true?)
353
365
  def initialize value, true_case, false_case = nil, pos = nil
366
+ super(pos)
354
367
  @value = value
355
368
  @true_case = true_case
356
369
  @false_case = false_case
357
- @pos = pos
358
370
  end
359
371
 
360
372
  def data_type
@@ -382,11 +394,11 @@ module RVM
382
394
  #
383
395
  # Both the *name* and the *value* are evaluated before the assignment
384
396
  # is done.
385
- class Assignment
397
+ class Assignment < Element
386
398
  def initialize name, value, pos = nil
399
+ super(pos)
387
400
  @name = name
388
401
  @value = value
389
- @pos = pos
390
402
  end
391
403
 
392
404
  def data_type
@@ -399,14 +411,36 @@ module RVM
399
411
  end
400
412
  end
401
413
 
414
+ # A variable declarion that sets a local variable, it will redelcare
415
+ # the variable if declared in a privouse scope.
416
+ #
417
+ # Both the *name* and the *value* are evaluated before the assignment
418
+ # is done.
419
+ class Declaration < Element
420
+ def initialize name, value, pos = nil
421
+ super(pos)
422
+ @name = name
423
+ @value = value
424
+ end
425
+
426
+ def data_type
427
+ @value.data_type
428
+ end
429
+
430
+ def execute env
431
+ RVM::debug "Executing Assignment at #{@pos}..." if $DEBUG
432
+ env.declare(@name.execute(env).to_s,@value.execute(env)).val
433
+ end
434
+ end
435
+
402
436
  # Reads the value of a variable in the enviroment.
403
437
  #
404
438
  # The *name* is evaluated before the variable is retrieved.
405
- class Variable
439
+ class Variable < Element
406
440
  def initialize name, pos = nil
441
+ super(pos)
407
442
  @name = name
408
443
  @type = :any
409
- @pos = pos
410
444
  end
411
445
 
412
446
  # The type can only be tretrieved when the name is aconstant
@@ -429,11 +463,11 @@ module RVM
429
463
 
430
464
  # This evauates to the parameter passed to the function call.
431
465
  # The number of it is evaluated and typecasted to an interger.
432
- class Parameter
466
+ class Parameter < Element
433
467
  def initialize num, pos = nil
468
+ super(pos)
434
469
  @num = num
435
470
  @type = :any
436
- @pos = pos
437
471
  end
438
472
 
439
473
  # The type can only be tretrieved when the num is aconstant
@@ -454,6 +488,11 @@ module RVM
454
488
  # another.
455
489
  # The type of the squence is equal to the last element of the sequence.
456
490
  class Sequence < Array
491
+ attr_accessor :pos
492
+ def initialize src=[], pos = nil
493
+ super(src)
494
+ @pos = pos
495
+ end
457
496
  def execute env
458
497
  RVM::debug "Executing Sequence... #{inspect}" if $DEBUG
459
498
  r = nil
@@ -478,6 +517,7 @@ module RVM
478
517
  # The catching is handled bythe +RVM::Classes::Block+ class.
479
518
  class ReturnException < Exception
480
519
  attr_reader :val
520
+ attr_reader :pos
481
521
  def initialize val, pos = nil
482
522
  super()
483
523
  @val = val
@@ -488,10 +528,10 @@ module RVM
488
528
  # Represents the return statement, it throws a
489
529
  # +ReturnException+ which can be caught to have the function
490
530
  # or block return what they wish.
491
- class Return
531
+ class Return < Element
492
532
  def initialize val, pos = nil
533
+ super(pos)
493
534
  @val = val
494
- @pos = pos
495
535
  end
496
536
 
497
537
  def data_type
@@ -509,7 +549,7 @@ module RVM
509
549
  #
510
550
  # Arguments are only executed when the function does return true for
511
551
  # execargs.
512
- class FunctionCall
552
+ class FunctionCall < Element
513
553
  attr_reader :arguments
514
554
  attr_reader :function
515
555
  # The constructor. *function* can either be a block object or a function
@@ -517,9 +557,9 @@ module RVM
517
557
  #
518
558
  # Arguments is a list of the arguments to the function.
519
559
  def initialize function, arguments, pos = nil
560
+ super(pos)
520
561
  @function = function
521
562
  @arguments = arguments
522
- @pos = pos
523
563
  end
524
564
 
525
565
  def data_type