rVM 0.0.14 → 0.0.17

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 (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'