rVM 0.0.14 → 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/README +4 -4
  2. data/bin/rvm +229 -0
  3. data/lib/rvm.rb +6 -6
  4. data/lib/rvm/acts_as_rvm_type.rb +26 -3
  5. data/lib/rvm/classes.rb +9 -15
  6. data/lib/rvm/classes/block.rb +8 -3
  7. data/lib/rvm/classes/class.rb +2 -2
  8. data/lib/rvm/classes/list.rb +1 -1
  9. data/lib/rvm/classes/null.rb +31 -0
  10. data/lib/rvm/classes/number.rb +4 -0
  11. data/lib/rvm/classes/object.rb +1 -1
  12. data/lib/rvm/classes/string.rb +6 -1
  13. data/lib/rvm/environment.rb +256 -0
  14. data/lib/rvm/functions.rb +9 -4
  15. data/lib/rvm/functions/array.rb +26 -2
  16. data/lib/rvm/functions/array/append.rb +31 -1
  17. data/lib/rvm/functions/array/at.rb +29 -1
  18. data/lib/rvm/functions/array/set_at.rb +29 -0
  19. data/lib/rvm/functions/association/assoc_get.rb +34 -0
  20. data/lib/rvm/functions/association/assoc_set.rb +32 -0
  21. data/lib/rvm/functions/bitwise.rb +3 -0
  22. data/lib/rvm/functions/bitwise/bitwise_and.rb +41 -0
  23. data/lib/rvm/functions/bitwise/bitwise_or.rb +41 -0
  24. data/lib/rvm/functions/bitwise/bitwise_xor.rb +41 -0
  25. data/lib/rvm/functions/collection/get.rb +37 -4
  26. data/lib/rvm/functions/collection/set.rb +37 -3
  27. data/lib/rvm/functions/collection/size.rb +33 -1
  28. data/lib/rvm/functions/general/cmp.rb +35 -7
  29. data/lib/rvm/functions/general/eq.rb +29 -0
  30. data/lib/rvm/functions/general/gt.rb +29 -0
  31. data/lib/rvm/functions/general/gte.rb +29 -0
  32. data/lib/rvm/functions/general/lt.rb +29 -0
  33. data/lib/rvm/functions/general/lte.rb +29 -0
  34. data/lib/rvm/functions/general/neq.rb +5 -0
  35. data/lib/rvm/functions/io/print.rb +38 -8
  36. data/lib/rvm/functions/list/align.rb +25 -1
  37. data/lib/rvm/functions/list/join.rb +27 -0
  38. data/lib/rvm/functions/list/map.rb +34 -0
  39. data/lib/rvm/functions/list/split.rb +31 -0
  40. data/lib/rvm/functions/logic/and.rb +36 -2
  41. data/lib/rvm/functions/logic/not.rb +27 -0
  42. data/lib/rvm/functions/logic/or.rb +32 -2
  43. data/lib/rvm/functions/math/add.rb +25 -0
  44. data/lib/rvm/functions/math/cos.rb +39 -0
  45. data/lib/rvm/functions/math/div.rb +25 -0
  46. data/lib/rvm/functions/math/mod.rb +41 -0
  47. data/lib/rvm/functions/math/mul.rb +25 -0
  48. data/lib/rvm/functions/math/neg.rb +25 -0
  49. data/lib/rvm/functions/math/power.rb +25 -0
  50. data/lib/rvm/functions/math/shl.rb +41 -0
  51. data/lib/rvm/functions/math/shr.rb +41 -0
  52. data/lib/rvm/functions/math/sin.rb +39 -0
  53. data/lib/rvm/functions/math/sub.rb +25 -0
  54. data/lib/rvm/functions/math/tan.rb +39 -0
  55. data/lib/rvm/functions/rails/print.rb +33 -3
  56. data/lib/rvm/interpreter.rb +405 -272
  57. data/lib/rvm/languages.rb +45 -11
  58. data/lib/rvm/languages/brainfuck.rb +15 -16
  59. data/lib/rvm/languages/ecma.rb +4 -1257
  60. data/lib/rvm/languages/ecma/compiler.rb +1353 -0
  61. data/lib/rvm/languages/ecma/core-math.js +84 -0
  62. data/lib/rvm/languages/math.rb +9 -16
  63. data/lib/rvm/languages/math/compiler.rb +9 -9
  64. data/lib/rvm/languages/math/tokenizer.rb +1 -1
  65. data/lib/rvm/languages/math/tree.rb +14 -14
  66. data/lib/rvm/library.rb +26 -18
  67. data/lib/rvm/optimisation.rb +109 -0
  68. data/lib/rvm/plugin.rb +109 -45
  69. data/lib/rvm/rails.rb +79 -54
  70. data/spec/classes/atom/association_spec.rb +8 -8
  71. data/spec/classes/atom/block_spec.rb +8 -5
  72. data/spec/classes/atom/boolean_spec.rb +1 -1
  73. data/spec/classes/atom/error_spec.rb +1 -1
  74. data/spec/classes/atom/list_spec.rb +1 -1
  75. data/spec/classes/atom/number_spec.rb +2 -2
  76. data/spec/classes/atom/string_spec.rb +1 -1
  77. data/spec/languages/ecma/ecma_spec.rb +94 -38
  78. data/spec/languages/ecma/json_spec.rb +4 -4
  79. data/spec/languages/math/compiler_spec.rb +5 -5
  80. data/spec/languages/math/tokenizer_spec.rb +1 -1
  81. data/spec/languages/math/tree_spec.rb +1 -1
  82. data/spec/{base → rvm}/class_spec.rb +2 -2
  83. data/spec/{base/interpreter → rvm}/enviroment_spec.rb +19 -9
  84. data/spec/{base → rvm}/function_spec.rb +2 -2
  85. data/spec/{functions → rvm/functions}/association/assoc_get_spec.rb +2 -2
  86. data/spec/{functions → rvm/functions}/association/assoc_set_spec.rb +2 -2
  87. data/spec/rvm/functions/collection/get_spec.rb +12 -0
  88. data/spec/rvm/functions/collection/set_spec.rb +10 -0
  89. data/spec/rvm/functions/collection/size_spec.rb +10 -0
  90. data/spec/{functions → rvm/functions}/list/split_spec.rb +3 -3
  91. data/spec/{functions → rvm/functions}/string/ansi_spec.rb +3 -3
  92. data/spec/{functions → rvm/functions}/string/capstr_spec.rb +3 -3
  93. data/spec/{functions → rvm/functions}/string/center_spec.rb +3 -3
  94. data/spec/{functions → rvm/functions}/string/ljust_spec.rb +3 -3
  95. data/spec/{functions → rvm/functions}/string/regmatch_spec.rb +3 -3
  96. data/spec/{functions → rvm/functions}/string/rjust_spec.rb +3 -3
  97. data/spec/{base → rvm}/interpreter/assignment_spec.rb +1 -1
  98. data/spec/rvm/interpreter/condition_spec.rb +103 -0
  99. data/spec/{base → rvm}/interpreter/constant_spec.rb +1 -1
  100. data/spec/rvm/interpreter/core_call_spec.rb +72 -0
  101. data/spec/{base → rvm}/interpreter/interpreter_spec.rb +1 -1
  102. data/spec/{base → rvm}/interpreter/parameter_spec.rb +1 -1
  103. data/spec/rvm/interpreter/sequence_spec.rb +47 -0
  104. data/spec/{base → rvm}/interpreter/variable_spec.rb +1 -1
  105. data/spec/{base → rvm}/plugin_spec.rb +2 -2
  106. metadata +66 -35
  107. data/lib/rake/helpers/code_statistics.rb +0 -167
  108. data/spec/base/interpreter/condition_spec.rb +0 -47
  109. data/spec/base/interpreter/function_call_spec.rb +0 -72
  110. data/spec/base/interpreter/sequence_spec.rb +0 -20
  111. data/spec/functions/collection/get_spec.rb +0 -12
  112. data/spec/functions/collection/set_spec.rb +0 -10
  113. data/spec/functions/collection/size_spec.rb +0 -10
@@ -1,5 +1,6 @@
1
- require File.dirname(__FILE__) + '/functions'
2
- require File.dirname(__FILE__) + '/classes'
1
+ require 'rvm/functions'
2
+ require 'rvm/classes'
3
+ require 'rvm/environment'
3
4
  module RVM
4
5
  # This Module hold all the VM classes that are used to execute and evaluate
5
6
  # code for the VM, so it is quite important to read and understand if you
@@ -17,6 +18,35 @@ module RVM
17
18
  module Interpreter
18
19
 
19
20
 
21
+ class RuntimeError < Exception
22
+ attr_accessor :total, :line, :char, :error_message
23
+ def initialize message, total = nil, line = nil, char = nil
24
+ super()
25
+ @line = line
26
+ @char = char
27
+ @total = total
28
+ @error_message = message
29
+ end
30
+
31
+ def to_s
32
+ res = "Runtime error"
33
+ if @total or @line
34
+ res << " at"
35
+ end
36
+ if @total
37
+ res << " character #{@total}"
38
+ end
39
+ if @line
40
+ res << " line #{@line}"
41
+ end
42
+ if @char
43
+ res << ":#{@char}"
44
+ end
45
+ res << ": #{@error_message}"
46
+ res
47
+ end
48
+ end
49
+
20
50
  # Helper class to be parented to other Interpreter calsses for checks and
21
51
  # including general behavior.
22
52
  class Element
@@ -28,6 +58,12 @@ module RVM
28
58
  def initialize pos
29
59
  @pos = pos
30
60
  end
61
+
62
+ #Placeholder for optimization
63
+ def optimize
64
+ RVM::debug "Optimizung #{self}" if $DEBUG
65
+ self
66
+ end
31
67
  end
32
68
 
33
69
  # This is a helper fuctio to quickly generate a empty enviorment.
@@ -37,7 +73,7 @@ module RVM
37
73
  # :functions can be a hash to hold functions defined in the the scope
38
74
  def Interpreter.env aenv = {}
39
75
  RVM::debug "Interpreter.env" if $DEBUG
40
- Enviroment.new aenv
76
+ Environment.new aenv
41
77
  end
42
78
 
43
79
  # This is a helper function that generates a constat of a simple constant,
@@ -47,234 +83,6 @@ module RVM
47
83
  RVM::Interpreter::Constant.new(RVM::Classes[type].new(value), pos)
48
84
  end
49
85
 
50
- # This class is used to store the variable content to allow chross
51
- # refferencing and passing variables upwards through different scopes.
52
- class VariableStorage
53
-
54
- # Lets the script read the value of the variable.
55
- attr_reader :val
56
-
57
- # The storage is initialized with two optional parameters:
58
- #
59
- # +val+:: which is the value to be stores.
60
- # +writable+:: which when set to false prevents the variable to be
61
- # written, which might be helpfull when trying to publish
62
- # some data to a script that is not supposed to be changed.
63
- def initialize val = nil, writable = true
64
- @writable = writable
65
- @val = val
66
- end
67
-
68
- # Used to write to the variable, if +writable+ was set to false this
69
- # will have no effect.
70
- #
71
- # It returns the new value set or, if +writable+ was false the old value.
72
- def val=v
73
- @val = v if @writable
74
- @val
75
- end
76
- end
77
-
78
- # The callback storang is used to help publishing variables from a ruby
79
- # class to the rVM, it will get and set the variables during runtime.
80
- #
81
- # It will link getter and setter methods and not the instance variable
82
- # itself, which means also computed attributes can be handled by this.
83
- #
84
- # This class is made if it is nessessary that a script always has access
85
- # to constantly chaning data within a object and not only deal with static
86
- # values set once.
87
- class VariableStorageCallback < VariableStorage
88
- # The construtor takes 3 parameters to specifie the object it shold
89
- # be linked with, the attribute to handle and +writable+ that will define
90
- # if the VariableStorage can be written too by the script.
91
- #
92
- # var is expected to by a Symbol equal the the function, the getter will
93
- # call obj.var and the setter will call obj.var=.
94
- #
95
- def initialize obj, var, writable = true
96
- super(nil, writable)
97
- @obj = obj
98
- @get = var.to_sym
99
- @set = "#{var}=".to_sym
100
- end
101
-
102
- # This methods sets the variable passed to the object by sending it to
103
- # the setter method.
104
- def val= v
105
- @obj.send(@set,v) if @writable
106
- @obj.send(@get)
107
- end
108
-
109
- # The getter will call the getter of the object to handle to get the
110
- # current value.
111
- def val
112
- @obj.send(@get)
113
- end
114
- end
115
-
116
- # This class represents the enviroment, the memory so to say for the VM.
117
- # The enviroment holds enviromental variables like who executes the
118
- # code, on what object it runs, what parameters where passed to the call
119
- # and as well, and perhaps most importantly the local variables.
120
- #
121
- # Some of the functions called will initialize new enviroments, as
122
- # for example function calls.
123
- class Enviroment
124
- # This creates a new enviroment enviroment, it generates a new env
125
- # default variables are set if not defined in +data+.
126
- #
127
- # If +oldenv+ is provided it will also fall back to see if not
128
- # existing variables
129
- #
130
- # +init_data+ is a hash that can be passed the following values:
131
- # :locals:: A hash with local variables mapped name => value
132
- # :functions:: A hash with functions for the scope.
133
- # :evaldeepth:: A fixnum that indicates how deep the evaluation is.
134
- # :params:: A array that holds local parameters for example for functions
135
- # or blocks.
136
- def initialize init_data = {}, oldenv=nil
137
-
138
- @data = {
139
- :locals => {},
140
- :functions => {},
141
- :evaldeepth => 0,
142
- :params => []
143
- }.merge(init_data)
144
-
145
-
146
- # Make sure that all locals that are passed, are actually in a variable
147
- # storage.
148
- if init_data[:locals]
149
- # For easy access we get us a link to the locals
150
- locals = @data[:locals]
151
- # Now we itterate through them
152
- init_data[:locals].each do |k,v|
153
- #For every variable that isn't already in a storage
154
- if not v.is_a?(VariableStorage)
155
- # We put it in a storage to assure the enviroment is propper.
156
- locals[k] = VariableStorage.new(v)
157
- end
158
- end
159
- end
160
-
161
- # We store the priviouse enviroment to look upwards through the scopes
162
- # for priviouse defined variables, if no old enviroment was given we
163
- # set the priviose scope to an empty hash.
164
- @prev = oldenv || {}
165
- RVM::debug "data: #{data}\noldenv:#{oldenv}" if $DEBUG
166
- RVM::debug "Creating new enviroment with: #{@data.inspect} as child" +
167
- " of #{@prev}" if $DEBUG
168
- end
169
-
170
- # Allows raw access to the data, it should not be used unless
171
- # somoene knows pretty exactly what they are doing.
172
- def data
173
- @data
174
- end
175
-
176
- # returns a parameter that was passed to the call. For function calls
177
- # this is especially important, it beginns with 0.
178
- #
179
- # If the current enviroment does not have the given paramenter it tries
180
- # it's 'oldenv' attrib to see if that had a object.
181
- def param i
182
- RVM::debug "Getting param #{i} (#{@data[:params][i]})" if $DEBUG
183
- @data[:params][i] || @prev.param(i)
184
- end
185
-
186
- # Returns a local variable with the given name.
187
- #
188
- # If the current enviroment does not have any local variables with
189
- # the given name it tries the privious enviroments.
190
- #
191
- # This returns the +VariableData+ object NOT the value of the variable.
192
- # Use +read_var_val+ if you want to read the value of a variable.
193
- def [] k
194
- r = @data[:locals][k] || @prev[k]
195
- RVM::debug "Getting variable #{k} (#{r})" if $DEBUG
196
- r
197
- end
198
-
199
- # Sets a local variable witin the enviroment.
200
- #
201
- # If the variable exists in a 'higher' enviroment the value is changed.
202
- #
203
- # If not it is newly created in the current enviroment and thus not
204
- # visible in upper enviroments.
205
- def []= name, value
206
- RVM::debug "Setting variable #{name} to #{value}" if $DEBUG
207
- # First we try to get the variable storage of the variable requested.
208
- # This will work if it was defined in this or a priviouse scope.
209
- if (res = self[name])
210
- # If we found the storage we'll change it's value and not define it
211
- # again.
212
- res.val = value
213
- else
214
- # If we didn't found a Variable storage, the variable wasn't defined
215
- # before so we make a new VariableStorage and save the variable in
216
- # it.
217
- @data[:locals][name] = VariableStorage.new(value)
218
- end
219
- value
220
- end
221
-
222
- # Defines a varialbe in the current scope, priviose variables are not
223
- # changed.
224
- # This is needed for local varialbe declarations that overwrite priviouse
225
- # globals.
226
- def declare name, value
227
- @data[:locals][name] = VariableStorage.new(value)
228
- end
229
-
230
- # Returns a function for the enviroment. If the current enviroment does
231
- # not hold a function with the requested name it checks through the
232
- # entire tree if a function can be found in the outer scopes.
233
- #
234
- # The result is to be execpted to be of the +RVM::Classes::Block+ class.
235
- def function name
236
- # Try to get the function in the local defintions.
237
- fun = @data[:functions][name]
238
- # if that fails and we have a previous enviroment check that
239
- fun = @prev.function(name) if fun.nil? and @prev.is_a? Enviroment
240
- RVM::debug "Getting functon #{name} (#{fun})" if $DEBUG
241
- # return what was found
242
- fun
243
- end
244
-
245
- # This defines a function within the enviroment and lets you call it later
246
- # on.
247
- #
248
- # It expects the body to be a RVM::Classes::Block so it can be executed.
249
- # The return value is the given block
250
- def def_function name, body
251
- if not body.is_a?(RVM::Classes::Block)
252
- raise(ArgumentError, "Function definitions must be of block class.")
253
- end
254
- @data[:functions][name] = body
255
- RVM::debug "Setting functon #{name} (#{body})" if $DEBUG
256
- body
257
- end
258
-
259
- # This functin is closely related to +[]+ with the difference that it
260
- # returns the value and not the VariableStorage object.
261
- # It is equivalent to [].val just that it also deals with nil ojects and
262
- # and returns a RVM::Classes::Error if the requested variable wasn't
263
- # found.
264
- def read_var_val name
265
-
266
- r = nil
267
- if (v = self[name])
268
- r = v.val
269
- else
270
- r = RVM::Classes[:error].new(0, "Variable #{name} is not defined.")
271
- end
272
- RVM::debug "Getting variable value #{name} (#{r})" if $DEBUG
273
- r
274
- end
275
- end
276
-
277
-
278
86
  # Jumps into object context (anther way beside using send).
279
87
  #
280
88
  # The special variable :self (attention, not to be mixed wiht 'self')
@@ -290,7 +98,6 @@ module RVM
290
98
  # This will execute my_code in a way pretty much equal to instance_eval in
291
99
  # ruby would do.
292
100
  class ObjectContext < Element
293
-
294
101
  # The constructor takes 3 arguments, the first beeing the object of which
295
102
  # the scope is taken, the second is the code to be executed in the objects
296
103
  # scope and the third is the position, to be set by the compiler.
@@ -303,17 +110,29 @@ module RVM
303
110
  @code = code
304
111
  end
305
112
 
306
- # Execute for this Interpreter element by creating a new enviroment,
113
+ def pretty_print(q)
114
+ q.group 1, "#{@object}.{", "}" do
115
+ q.pp @code
116
+ end
117
+ end
118
+
119
+ # Execute for this Interpreter element by creating a new environment ,
307
120
  # setting it's variables and functions to those definded by the object's
308
121
  # +functions+ and +variables+ methods. It also sets the :self variable in
309
- # the new enviroment to the object.
122
+ # the new environment to the object.
310
123
  def execute env
311
124
  #The new
312
125
  obj = @object.execute(env)
313
- new_env = Interpreter::Enviroment.new({:functions => obj.functions, :locals => obj.variables}, env)
126
+ new_env = Interpreter::Environment.new({:functions => obj.functions, :locals => obj.variables}, env)
314
127
  new_env.declare(:self, obj)
315
128
  @code.execute(new_env)
316
129
  end
130
+
131
+ def optimize
132
+ @object = @object.optimize
133
+ @code = @code.optimize
134
+ super
135
+ end
317
136
  end
318
137
 
319
138
 
@@ -337,6 +156,12 @@ module RVM
337
156
  @object.object_functions[@name.execute(env)] = @function
338
157
  @function
339
158
  end
159
+
160
+ def optimize
161
+ @object = @object.optimize
162
+ @function = @function.optimize
163
+ super
164
+ end
340
165
  end
341
166
 
342
167
  # A block localizes variables, do not mix this up with the
@@ -351,13 +176,25 @@ module RVM
351
176
  @content = content
352
177
  end
353
178
 
354
- # When executed a temporary enviroment is created with the passed
179
+ def pretty_print(q)
180
+ first = true
181
+ q.group 1, "{", "}" do
182
+ q.pp @content
183
+ end
184
+ end
185
+
186
+ # When executed a temporary environment is created with the passed
355
187
  # Enviroement as a parent to it.
356
- # This new enviroment is discaded after the execution.
188
+ # This new environment is discaded after the execution.
357
189
  def execute env
358
- tenv = Enviroment.new({}, env)
190
+ tenv = Environment.new({}, env)
359
191
  @content.execute tenv
360
192
  end
193
+
194
+ def optimize
195
+ @content = @content.optimize
196
+ super
197
+ end
361
198
  end
362
199
 
363
200
 
@@ -388,6 +225,18 @@ module RVM
388
225
  @override = override
389
226
  end
390
227
 
228
+ def pretty_print(q)
229
+ first = true
230
+ q.text "function "
231
+ if @name.is_a? Constant
232
+ q.text @name.value
233
+ else
234
+ q.pp @name
235
+ end
236
+ q.text "()"
237
+ q.pp @body
238
+ end
239
+
391
240
  # When executed the FunctionDefinition first checks if a function with the
392
241
  # same name is already defined. If it is and +override+ wasn't set to ture
393
242
  # it trows a Exception. Otherwise it defines the function, deleting the
@@ -396,11 +245,17 @@ module RVM
396
245
  # It returns the body of the newly defined function.
397
246
  def execute env
398
247
  if (not @override) and env.function(@name)
399
- raise "Function #{@name} already defined at #{@pos}!"
248
+ raise RuntimeError.new("Function #{@name} already defined", @pos[0], @pos[1], @pos[2])
400
249
  end
401
250
  env.def_function(@name.execute(env),@body)
402
251
  @body
403
252
  end
253
+
254
+ def optimize
255
+ @body = @body.optimize
256
+ @name = @name.optimize
257
+ super
258
+ end
404
259
  end
405
260
 
406
261
 
@@ -427,6 +282,14 @@ module RVM
427
282
  @body = body
428
283
  end
429
284
 
285
+ def pretty_print(q)
286
+ first = true
287
+ q.text "while ("
288
+ q.pp @condition
289
+ q.text ")"
290
+ q.pp @body
291
+ end
292
+
430
293
  # The loop will execute as long as the code passed as condition evaluates
431
294
  # to is_true?.
432
295
  # Once the loop stops executing the return value is the result of the last
@@ -440,6 +303,13 @@ module RVM
440
303
  end
441
304
  end
442
305
 
306
+ # Optimization of the loop
307
+ def optimize
308
+ @condition = @condition.optimize
309
+ @body = @body.optimize
310
+ super
311
+ end
312
+
443
313
 
444
314
  # A constant, it evaluates to thevalue given and end the evaluation.
445
315
  # Meaning that no further execution is done in this tree branch, so the
@@ -456,6 +326,10 @@ module RVM
456
326
  @value.data_type
457
327
  end
458
328
 
329
+ def pretty_print(q)
330
+ q.pp @value
331
+ end
332
+
459
333
  # Comparing a constant with something has two ways to go, if the object
460
334
  # it is compared to is a Constant the two values are compared. If not the
461
335
  # Constant compares the value with the passed object.
@@ -464,7 +338,6 @@ module RVM
464
338
  @value == v.value
465
339
  else
466
340
  @value == v
467
- false
468
341
  end
469
342
  end
470
343
 
@@ -517,6 +390,17 @@ module RVM
517
390
  @false_case = false_case
518
391
  end
519
392
 
393
+ def pretty_print(q)
394
+ first = true
395
+ q.text "if ("
396
+ q.pp @value
397
+ q.text ")"
398
+ q.pp @true_case
399
+ if (@false_case)
400
+ q.text "else"
401
+ q.pp @false_case
402
+ end
403
+ end
520
404
 
521
405
  # The data type of a condition is tried to evaluate by checking if the
522
406
  # type is the same for both conditions, if so the common type is returned,
@@ -546,6 +430,25 @@ module RVM
546
430
  @false_case.execute env
547
431
  end
548
432
  end
433
+
434
+ #Optimizes the condition (checks for trivial cases)
435
+ def optimize
436
+ @value = @value.optimize
437
+ @true_case = @true_case.optimize
438
+ @false_case = @false_case.optimize if @false_case
439
+ if @value.is_a? RVM::Interpreter::Constant
440
+ RVM::debug "Optimizing #{self}, with shortcuting a condition." if $DEBUG
441
+ if @value.value.is_true?
442
+ @true_case
443
+ elsif @false_case
444
+ @false_case
445
+ else
446
+ RVM::Interpreter::Sequence.new
447
+ end
448
+ else
449
+ super
450
+ end
451
+ end
549
452
  end
550
453
 
551
454
 
@@ -575,6 +478,16 @@ module RVM
575
478
  @value = value
576
479
  end
577
480
 
481
+ def pretty_print(q)
482
+ if @name.is_a? Constant
483
+ q.text @name.value
484
+ else
485
+ q.pp @name
486
+ end
487
+ q.text " = "
488
+ q.pp @value
489
+ end
490
+
578
491
  # The data type of a Assignment is the data type of it's value.
579
492
  def data_type
580
493
  @value.data_type
@@ -582,7 +495,7 @@ module RVM
582
495
 
583
496
  # When executed the assignment first evaluates the name of the assignment
584
497
  # then the value and stores the result of the executed value in the
585
- # enviroment under the name of the executed name.
498
+ # environment under the name of the executed name.
586
499
  #
587
500
  # The return value of the execution is the value that is assigned to the
588
501
  # variable.
@@ -590,13 +503,23 @@ module RVM
590
503
  RVM::debug "Executing Assignment at #{@pos}..." if $DEBUG
591
504
  env[@name.execute(env).to_s] = @value.execute env
592
505
  end
506
+ def optimize
507
+ @name = @name.optimize
508
+ @value = @value.optimize
509
+ if @name.is_a? RVM::Interpreter::Constant
510
+ RVM::debug "Optimizing #{self}, by making it simple" if $DEBUG
511
+ RVM::Interpreter::SimpleAssignment.new(@name.value, @value, @pos)
512
+ else
513
+ super
514
+ end
515
+ end
593
516
  end
594
517
 
595
518
  # A variable declarion that sets a local variable, it will redelcare
596
519
  # the variable if declared in a privouse scope.
597
520
  #
598
521
  # It is very closely related to the Assignment as it acts exactly alike if
599
- # the variable is not yet existing in the Enviroment.
522
+ # the variable is not yet existing in the Environment .
600
523
  #
601
524
  # Both the +name+ and the #value# are evaluated before the assignment
602
525
  # is done.
@@ -619,6 +542,16 @@ module RVM
619
542
  @value = value
620
543
  end
621
544
 
545
+ def pretty_print(q)
546
+ if @name.is_a? Constant
547
+ q.text @name.value
548
+ else
549
+ q.pp @name
550
+ end
551
+ q.text " !=! "
552
+ q.pp @value
553
+ end
554
+
622
555
  # The data type of a Assignment is the data type of it's value.
623
556
  def data_type
624
557
  @value.data_type
@@ -626,9 +559,9 @@ module RVM
626
559
 
627
560
  # When executed the assignment first evaluates the name of the assignment
628
561
  # then the value and stores the result of the executed value in the
629
- # enviroment under the name of the executed name.
562
+ # environment under the name of the executed name.
630
563
  #
631
- # If the variable was priviosely in a enviroment that lays above the
564
+ # If the variable was priviosely in a environment that lays above the
632
565
  # current one in the hearachy the old value will not be altered in any
633
566
  # way but a new variable declared.
634
567
  #
@@ -638,9 +571,20 @@ module RVM
638
571
  RVM::debug "Executing Assignment at #{@pos}..." if $DEBUG
639
572
  env.declare(@name.execute(env).to_s,@value.execute(env)).val
640
573
  end
641
- end
574
+
575
+ def optimize
576
+ @name = @name.optimize
577
+ @value = @value.optimize
578
+ if @name.is_a? RVM::Interpreter::Constant
579
+ RVM::debug "Optimizing #{self}, by making it simple" if $DEBUG
580
+ RVM::Interpreter::SimpleDeclaration.new(@name.value, @value, @pos)
581
+ else
582
+ super
583
+ end
584
+ end
585
+ end
642
586
 
643
- # Reads the value of a variable in the enviroment.
587
+ # Reads the value of a variable in the environment .
644
588
  #
645
589
  # The +name+ is evaluated before the variable is retrieved.
646
590
  class Variable < Element
@@ -657,6 +601,14 @@ module RVM
657
601
  @type = :any
658
602
  end
659
603
 
604
+ def pretty_print(q)
605
+ if @name.is_a? Constant
606
+ q.text @name.value
607
+ else
608
+ q.pp @name
609
+ end
610
+ end
611
+
660
612
  # The type can only be tretrieved when the name is aconstant
661
613
  # as it can be evaluated without sideffect.
662
614
  def data_type
@@ -666,16 +618,33 @@ module RVM
666
618
  # When the name is a symbol, the name isn't executed and treated as a
667
619
  # special variable.
668
620
  # Otherwise the name is executed and converted into a string to be passed
669
- # to the enviroment so it can go and collect the value.
621
+ # to the environment so it can go and collect the value.
670
622
  def execute env
671
623
  RVM::debug "Executing Variable at #{@pos}..." if $DEBUG
672
- n = @name
673
- if not @name.is_a?(Symbol)
674
- n = n.execute(env).to_s
624
+ begin
625
+ n = @name
626
+ if not @name.is_a?(Symbol)
627
+ n = n.execute(env).to_s
628
+ end
629
+ r = env.read_var_val(n)
630
+ @type = r.data_type if r.respond_to?(:data_type)
631
+ r
632
+ rescue Exception => e
633
+ raise RuntimeError.new("Failed to get Varialbe #{e}", @pos[0], @pos[1], @pos[2])
634
+ end
635
+ end
636
+
637
+ def optimize
638
+ @name = @name.optimize if not @name.is_a?(Symbol)
639
+ if @name.is_a?(Symbol)
640
+ RVM::debug "Optimizing #{self}, by making it simple" if $DEBUG
641
+ RVM::Interpreter::SimpleVariable.new(@name, @pos)
642
+ elsif @name.is_a?(RVM::Interpreter::Constant)
643
+ RVM::debug "Optimizing #{self}, by making it simple" if $DEBUG
644
+ RVM::Interpreter::SimpleVariable.new(@name.value, @pos)
645
+ else
646
+ super
675
647
  end
676
- r = env.read_var_val(n)
677
- @type = r.data_type if r.respond_to?(:data_type)
678
- r
679
648
  end
680
649
  end
681
650
 
@@ -696,6 +665,12 @@ module RVM
696
665
  @type = :any
697
666
  end
698
667
 
668
+ def pretty_print(q)
669
+ q.text "!!PARAMS["
670
+ q.pp @num
671
+ q.text "]"
672
+ end
673
+
699
674
  # The type can only be tretrieved when the num is aconstant
700
675
  # as it can be evaluated without sideffect.
701
676
  def data_type
@@ -703,23 +678,29 @@ module RVM
703
678
  end
704
679
 
705
680
  # When executed the Parameter evaluates the number, of the parameter and
706
- # then queries the enviroment to get the function parameter requested.
681
+ # then queries the environment to get the function parameter requested.
707
682
  #
708
683
  # After the first execution the parameter remembers the type of the value
709
684
  # it returns.
710
685
  def execute env
711
686
  RVM::debug "Executing Parameter at #{@pos}..." if $DEBUG
712
687
  r = env.param(@num.execute(env).to_i)
713
- @type = r.data_type if r
688
+ @type = r.data_type if r && r.respond_to?(:data_type)
714
689
  r
715
690
  end
691
+
692
+ def optimize
693
+ @num = @num.optimize
694
+ super
695
+ end
716
696
  end
717
697
 
718
698
  # A sequence is a list of commands that are executed one after
719
699
  # another.
720
700
  # The type of the squence is equal to the last element of the sequence.
721
- class Sequence < Array
701
+ class Sequence < Element
722
702
  attr_accessor :pos
703
+ attr_accessor :data
723
704
 
724
705
  # The Sequence is initialized wiht 1 to 2 parameters.
725
706
  #
@@ -729,27 +710,73 @@ module RVM
729
710
  # pos:: The position within the source code of the definition - for
730
711
  # deugging purpose.
731
712
  def initialize src=[], pos = nil
732
- super(src)
713
+ @data = src
733
714
  @pos = pos
734
715
  end
735
716
 
717
+ def pretty_print(q)
718
+ first = true
719
+ q.group 1, "{", "}" do
720
+ @data.each do |c|
721
+ if first
722
+ first = false
723
+ else
724
+ q.text ";"
725
+ end
726
+ q.breakable
727
+ q.pp c
728
+ end
729
+ q.breakable
730
+ end
731
+ end
732
+
736
733
  # When exeuted a sequence starts to execute every element in it starting
737
734
  # with the first element in the array.
738
735
  #
739
736
  # The result is the last element of the array executed.
740
737
  def execute env
741
738
  RVM::debug "Executing Sequence... #{inspect}" if $DEBUG
742
- r = nil
743
- self.map { |seq|
744
- r = seq.execute env
745
- }
739
+ for item in @data
740
+ r = item.execute env
741
+ end
746
742
  r
747
743
  end
748
744
 
749
745
  # When adding something to the Sequence a new Sequence will be created
750
746
  # with the result of the joined arrays.
751
747
  def + v
752
- Sequence.new(super)
748
+ v = v.data if v.is_a? RVM::Interpreter::Sequence
749
+ Sequence.new(@data + v)
750
+ end
751
+
752
+ def << v
753
+ @data << v
754
+ self
755
+ end
756
+
757
+ def unshift v
758
+ @data.unshift v
759
+ self
760
+ end
761
+
762
+ # Optimization for sequences
763
+ def optimize
764
+
765
+ if @data.size == 1
766
+ return @data.first.optimize
767
+ else
768
+ newdata = []
769
+ @data.each do |d|
770
+ d = d.optimize
771
+ if d.is_a? RVM::Interpreter::Sequence
772
+ newdata.concat(d.data)
773
+ else
774
+ newdata << d
775
+ end
776
+ end
777
+ @data = newdata
778
+ end
779
+ super
753
780
  end
754
781
 
755
782
  # The data type of the list is :any as it is unknown where the the
@@ -796,6 +823,11 @@ module RVM
796
823
  @val = val
797
824
  end
798
825
 
826
+ def pretty_print(q)
827
+ q.text "return "
828
+ q.pp @val
829
+ end
830
+
799
831
  # The data type of a return statement is any, as it does not return
800
832
  # anything at all, after all it jumps out of a block.
801
833
  def data_type
@@ -807,10 +839,15 @@ module RVM
807
839
  def execute env
808
840
  raise ReturnException.new(@val.execute(env))
809
841
  end
842
+
843
+ def optimize
844
+ @val = @val.optimize
845
+ super
846
+ end
810
847
  end
811
848
 
812
849
  # A function call or a function or a block. The initialization of a new
813
- # enviroment is done by the function Class as it also sorts the arguments
850
+ # environment is done by the function Class as it also sorts the arguments
814
851
  # into it.
815
852
  #
816
853
  # Arguments are only executed when the function does return true for
@@ -822,12 +859,27 @@ module RVM
822
859
  # class.
823
860
  #
824
861
  # Arguments is a list of the arguments to the function.
825
- def initialize function, arguments, pos = nil
862
+ def initialize function, arguments, pos = [0,0,0]
826
863
  super(pos)
827
864
  @function = function
828
865
  @arguments = arguments
829
866
  end
830
867
 
868
+ def pretty_print(q)
869
+ first = true
870
+ q.pp @function
871
+ q.text "("
872
+ @arguments.each do |a|
873
+ if first
874
+ first = false
875
+ else
876
+ q.text ', '
877
+ end
878
+ q.pp a
879
+ end
880
+ q.text ")"
881
+ end
882
+
831
883
  # The data type of the FunctionCall is the return value of the function
832
884
  # that it calls.
833
885
  def data_type
@@ -844,6 +896,12 @@ module RVM
844
896
  end
845
897
  end
846
898
 
899
+ def optimize
900
+ @arguments.map!{ |a| a.optimize}
901
+ @function.optimize if @function.respond_to?(:optimize)
902
+ super
903
+ end
904
+
847
905
  # When executed the FunctionCall has four possible behaviours.
848
906
  #
849
907
  # 1) If the function is a block, so an anonymous function, the arguments
@@ -880,19 +938,94 @@ module RVM
880
938
  fun.call(args, env, @pos)
881
939
  # If nothing of the above the function must be a global function.
882
940
  else
883
- # Get the function from he globals
884
- fun = RVM::Functions[@function]
885
- # Test if the arguments should be executed
886
- if fun.execargs
887
- # The arges get executed
888
- args.map! do |arg|
889
- arg.execute env
941
+ raise RuntimeError.new("Function '#{@function}' Not found!", @pos[0], @pos[1], @pos[2])
942
+ end
943
+ end
944
+ end
945
+
946
+
947
+ # A core call is a call to the direct core functions and libraries RVM proides.
948
+ # this is used to write core libraries for different languages.
949
+ class CoreCall < Element
950
+ attr_reader :arguments
951
+ attr_reader :function
952
+ # The constructor. +function+ can either be a block object or a function
953
+ # class.
954
+ #
955
+ # Arguments is a list of the arguments to the function.
956
+ def initialize function, arguments, pos = nil
957
+ super(pos)
958
+ @function = function
959
+ @arguments = arguments
960
+ end
961
+
962
+ def pretty_print(q)
963
+ binary = {:sub => '-', :add => '+', :mul => '*', :div => '/', :mod => '%', :shl => '<<', :shr => '>>',
964
+ :cmp => '<=>', :eq => '==', :gt => '>', :gte => '>=', :lt => '<', :lte => '<=',
965
+ :bitwise_and => '&', :bitwise_or => '|', :bitwise_xor => '^',
966
+ :and => '&&', :or => '||', }
967
+ if binary.keys.include?(@function)
968
+ first = true
969
+ @arguments.each do |a|
970
+ if first
971
+ first = false
972
+ else
973
+ q.text " #{binary[@function]} "
890
974
  end
975
+ q.pp a
891
976
  end
892
- # Call the function
977
+ else
978
+ first = true
979
+ q.pp @function
980
+ q.text "!("
981
+ @arguments.each do |a|
982
+ if first
983
+ first = false
984
+ else
985
+ q.text ', '
986
+ end
987
+ q.pp a
988
+ end
989
+ q.text ")"
990
+ end
991
+ end
992
+
993
+ def optimize
994
+ @arguments.map!{ |a| a.optimize}
995
+ super
996
+ end
997
+
998
+ def data_type
999
+ RVM::Functions[@function] ? RVM::Functions[@function].data_type : :any
1000
+ end
1001
+
1002
+ # When executed the CoreCall it will call one of the RVM's library functions
1003
+ def execute env
1004
+ RVM::debug "Executing FunctionCall..." if $DEBUG
1005
+ args = @arguments.dup
1006
+ # The function is a anonymous function
1007
+
1008
+ # Get the function from he globals
1009
+
1010
+ if not fun = RVM::Functions[@function]
1011
+ raise RuntimeError.new("Function Not found!", @pos[0], @pos[1], @pos[2])
1012
+ end
1013
+ # Test if the arguments should be executed
1014
+ if fun.execargs
1015
+ # The arges get executed
1016
+ args.map! do |arg|
1017
+ arg.execute env
1018
+ end
1019
+ end
1020
+ # Call the function
1021
+ begin
893
1022
  fun.call(args, env, @pos)
1023
+ rescue Exception => e
1024
+ raise e
1025
+ raise RuntimeError.new("Function failed to execute: #{e}", @pos[0], @pos[1], @pos[2])
894
1026
  end
895
1027
  end
896
1028
  end
897
1029
  end
898
1030
  end
1031
+ require 'rvm/optimisation'