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