rVM 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ module RVM
2
+ module Functions
3
+ class Not < RVM::Functions::Function
4
+ class << self
5
+ def execute params, env
6
+ RVM::Classes::Boolean.new(! params[0].is_true?)
7
+ end
8
+
9
+ def signature
10
+ [:any] # adjust the signature here
11
+ end
12
+
13
+ end
14
+ register_for :not
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ module RVM
2
+ module Functions
3
+ class Or < RVM::Functions::Function
4
+ class << self
5
+ def execute params, env
6
+ while not result and not params.empty?
7
+ v = params.shift.execute(env)
8
+ return v if v.is_true?
9
+ end
10
+ return RVM::Classes::Boolean.new(false)
11
+ end
12
+
13
+ def signature
14
+ [:any] # adjust the signature here
15
+ end
16
+
17
+ def execargs
18
+ false
19
+ end
20
+ end
21
+ register_for :or
22
+ end
23
+ end
24
+ end
@@ -2,15 +2,15 @@ module RVM
2
2
  module Functions
3
3
  class Add < Function
4
4
  def Add.execute params, env
5
- a = RVM::Classes[:number].new 0
6
- params.each do |p|
5
+ a = params.shift
6
+ params.each do |p|
7
7
  a += p
8
8
  end
9
9
  a
10
10
  end
11
11
 
12
12
  def Add.signature
13
- [:number, :number]
13
+ [:any]
14
14
  end
15
15
  register_for :add
16
16
  end
@@ -2,18 +2,16 @@ module RVM
2
2
  module Functions
3
3
  class Div < Function
4
4
  def Div.execute params, env
5
- a = RVM::Classes[:number].new params.shift
6
- params.each do |p|
7
- if p == 0
8
- return RVM::Classes[:error].new(1,"DIVISION BY ZERO")
9
- end
5
+ a = params.shift
6
+
7
+ params.each do |p|
10
8
  a /= p
11
9
  end
12
10
  a
13
11
  end
14
12
 
15
13
  def Div.signature
16
- [:number, :number]
14
+ [:any]
17
15
  end
18
16
  register_for :div
19
17
  end
@@ -2,7 +2,7 @@ module RVM
2
2
  module Functions
3
3
  class Mul < Function
4
4
  def Mul.execute params, env
5
- a = RVM::Classes[:number].new params.shift
5
+ a = params.shift
6
6
  params.each do |p|
7
7
  a *= p
8
8
  end
@@ -2,7 +2,7 @@ module RVM
2
2
  module Functions
3
3
  class Sub < Function
4
4
  def Sub.execute params, env
5
- a = RVM::Classes[:number].new params.shift
5
+ a = params.shift
6
6
  params.each do |p|
7
7
  a -= p
8
8
  end
@@ -0,0 +1,22 @@
1
+ module RVM
2
+ module Functions
3
+ class Send < RVM::Functions::Function
4
+ class << self
5
+ def execute params, env
6
+ obj = params.shift
7
+ method = params.shift
8
+ if obj and method
9
+ obj.obj_send(method, params, env)
10
+ else
11
+
12
+ end
13
+ end
14
+
15
+ def signature
16
+ [:any, :string, :any]
17
+ end
18
+ end
19
+ register_for :send
20
+ end
21
+ end
22
+ end
@@ -22,6 +22,19 @@ module RVM
22
22
  RVM::Interpreter::Constant.new(RVM::Classes[type].new(value))
23
23
  end
24
24
 
25
+ class VariableStorage
26
+ attr_accessor :val
27
+ def initialize val, writable = true
28
+ @writable = writable
29
+ @val = val
30
+ end
31
+
32
+ def val=v
33
+ @val = v if @writable
34
+ @val
35
+ end
36
+ end
37
+
25
38
  # This class represents the enviroment, the memory so to say for the VM.
26
39
  # The enviroment holds enviromental variables like who executes the
27
40
  # code, on what object it runs, what parameters where passed to the call
@@ -35,17 +48,22 @@ module RVM
35
48
  #
36
49
  # If *oldenv* is provided it will also fall back to see if not
37
50
  # existing variables
38
- def initialize data = {}, oldenv=nil
39
- RVM::debug "data: #{data}\noldenv:#{oldenv}"
51
+ def initialize init_data = {}, oldenv=nil
52
+
40
53
  @data = {
41
54
  :locals => {},
42
55
  :functions => {},
43
56
  :evaldeepth => 0,
44
57
  :params => []
45
- }.merge(data)
58
+ }.merge(init_data)
46
59
  @prev = oldenv || {}
60
+ RVM::debug "data: #{data}\noldenv:#{oldenv}"
47
61
  RVM::debug "Creating new enviroment with: #{@data.inspect} as child of #{@prev}"
48
-
62
+ end
63
+
64
+ #allows raw access to the data, be carefull!
65
+ def data
66
+ @data
49
67
  end
50
68
 
51
69
  # returns a parameter that was passed to the call. For function calls
@@ -55,45 +73,143 @@ module RVM
55
73
  # it's 'oldenv' attrib to see if that had a object.
56
74
  def param i
57
75
  RVM::debug "Getting param #{i} (#{@data[:params][i]})"
58
- @data[:params][i]
76
+ @data[:params][i] || @prev.param(i)
59
77
  end
60
78
 
61
79
  # Returns a local variable with the given name.
62
80
  #
63
81
  # If the current enviroment does not have any local variables with
64
82
  # the given name it tries the privious enviroments.
83
+ #
84
+ # This returns the +VariableData+ object NOT the value of the variable.
85
+ # Use +read_var_val+ if you want to read the value of a variable.
65
86
  def [] k
66
87
  r = @data[:locals][k] || @prev[k]
67
88
  RVM::debug "Getting variable #{k} (#{r})"
68
89
  r
69
90
  end
70
91
 
71
- #Sets a local variable witin the enviroment.
92
+ # Sets a local variable witin the enviroment.
93
+ #
94
+ # If the variable exists in a 'higher' enviroment the value is changed.
95
+ #
96
+ # If not it is newly created in the current enviroment and thus not visible
97
+ # in upper enviroments.
72
98
  def []= k, v
73
99
  #TODO: add capability to have the privious env variables changed
74
100
  RVM::debug "Setting variable #{k} to #{v}"
75
- @data[:locals][k] = v
101
+ if (self[:locals] and r = self[:locals][k])
102
+ r.val = v
103
+ else
104
+ @data[:locals][k] = VariableStorage.new(v)
105
+ end
106
+ v
76
107
  end
77
108
 
78
- #Returns a function for the current enviroment
109
+ # Returns a function for the current enviroment.
110
+ # The result is to be execpted to be of the +RVM::Classes::Block+ class.
79
111
  def function k
80
112
  r = @data[:functions][k]
81
113
  if not r and @prev.is_a? Enviroment
82
- r = @prev.function(k)
114
+ r = @prev.function(k)
83
115
  end
84
116
  RVM::debug "Getting functon #{k} (#{r})"
85
117
  r
86
118
  end
87
119
 
88
- #Returns a function for the current enviroment
120
+ # This defines a function within the enviroment and lets you call it later on.
121
+ #
122
+ # It also checks if the given block is truely a +RVM::Classes::Block+ object.
89
123
  def def_function k, b
124
+ rise(ArgumentError, "Function definitions must be of block class.")if not b.is_a?(RVM::Classes::Block)
90
125
  @data[:functions][k] = b
91
126
  RVM::debug "Setting functon #{k} (#{b})"
92
127
  nil
93
128
  end
129
+
130
+ # This functin is closely related to +[]+ with the difference that it returns the value
131
+ # And not the VariableData object.
132
+ def read_var_val name
133
+ if (v = self[name])
134
+ v.val
135
+ end
136
+ end
137
+ end
138
+
139
+
140
+ # Skipps into object context (anther way beside using send)
141
+ #
142
+ # the special variable :self (attention, not to be mixed wiht 'self')
143
+ # is set to the object in which context we are!
144
+ #
145
+ # The class is stred in :class
146
+ class ObjectContext
147
+ def initialize object, code
148
+ @object = object
149
+ @code = code
150
+ end
151
+
152
+ def execute env
153
+ #The new
154
+ obj = @object.execute(env)
155
+ env = Interpreter::Enviroment.new({:functions => obj.functions, :locals => obj.variables}, env)
156
+ @code.execute(env)
157
+ end
158
+ end
159
+
160
+
161
+ #This sets a funciton on a Class (to be included in its objects)
162
+ #
163
+ #To define class functions use ObjectContext and define the function normaly, nifty isn't it?
164
+ class SetClassFunction
165
+ def initialize obj, name, function
166
+ @object = obj
167
+ @name = name
168
+ @function = function
169
+ end
170
+
171
+ def execute env
172
+ @object.object_functions[@name.execute(env)] = @function
173
+ @function
174
+ end
175
+ end
176
+
177
+ # A block localizes variables, do not mix this up with the
178
+ # +RVM::Classes::Block+ class!
179
+ #
180
+ # Blocks are mostly used to handle tasks as not interfeeing
181
+ # With outer code.
182
+ class Block
183
+ attr_reader :content
184
+ def initialize content
185
+ @content = content
186
+ end
187
+
188
+ # When executed a temporary enviroment is created with the passed
189
+ # Enviroement as a parent to it.
190
+ # This new enviroment is discaded after the execution.
191
+ def execute env
192
+ tenv = Enviroment.new({}, env)
193
+ @content.execute tenv
194
+ end
94
195
  end
95
196
 
197
+ # This is a function definition used to write in the function libary
198
+ #
96
199
  class FunctionDefinition
200
+
201
+ # Initializes a new function definition
202
+ #
203
+ # name:: is the name of the function to define, if it is not
204
+ # unique it will overwrite earlyer definitions
205
+ # (unless override is false)
206
+ #
207
+ # body:: is the body of the cuntion. this will be executed
208
+ # when the defined function is called.
209
+ #
210
+ # override:: when true (default) earlyer definitions are
211
+ # replaced when it is called a second time.
212
+ # When false a exception is thrown
97
213
  def initialize name, body, override = true
98
214
  @name = name
99
215
  @body = body
@@ -104,12 +220,21 @@ module RVM
104
220
  if (not @override) and env.function(@name)
105
221
  raise "Function #{@name} already defined!"
106
222
  end
107
- env.def_function(@name.execute(env),@body.execute(env))
223
+ env.def_function(@name.execute(env),@body)
108
224
  nil
109
225
  end
110
226
  end
111
227
 
228
+
229
+ # This is a loop. It is executed over and over again as long as
230
+ # the passed condition evaluates to a value that matches is_true?.
112
231
  class Loop
232
+ # Initializes a new loop.
233
+ #
234
+ # condition:: is executed before each run of the loop. If it evaluates
235
+ # to true the loop is executed another time otherwise the
236
+ # exection ends.
237
+ # body:: For each itteration of the loop this is executed once.
113
238
  def initialize(condition, body)
114
239
  @condition = condition
115
240
  @body = body
@@ -135,6 +260,7 @@ module RVM
135
260
  def data_type
136
261
  @value.data_type
137
262
  end
263
+
138
264
  def == v
139
265
  if v.is_a? Constant
140
266
  @value == v.value
@@ -242,41 +368,12 @@ module RVM
242
368
 
243
369
  def execute env
244
370
  RVM::debug "Executing Variable..."
245
- r = env[@name.execute(env).to_s]
371
+ r = env.read_var_val(@name.execute(env).to_s)
246
372
  @type = r.data_type if r
247
373
  r
248
374
  end
249
375
  end
250
376
 
251
-
252
- # Returns a parameter of the enviroment. This is needed for things like
253
- # *self* or *caller*.
254
- class EnvGetter
255
-
256
- def initialize what
257
- @envvar = what
258
- end
259
-
260
- def data_type
261
- if @envvar == :self or @envvar == :caller
262
- :object
263
- else
264
- :any
265
- end
266
- end
267
-
268
- def execute env
269
- case @envvar
270
- when :self
271
- env.object
272
- when :caller
273
- env.caller
274
- else
275
- RVM::Classes[:sting].new('')
276
- end
277
- end
278
- end
279
-
280
377
  # This evauates to the parameter passed to the function call.
281
378
  # The number of it is evaluated and typecasted to an interger.
282
379
  class Parameter
@@ -322,6 +419,35 @@ module RVM
322
419
  end
323
420
  end
324
421
 
422
+ # This is an exception designed to handle the return statement.
423
+ # It is thrown for for the return and the value can be evaluated.
424
+ #
425
+ # The catching is handled bythe +RVM::Classes::Block+ class.
426
+ class ReturnException < Exception
427
+ attr_reader :val
428
+ def initialize val
429
+ super()
430
+ @val = val
431
+ end
432
+ end
433
+
434
+ # Represents the return statement, it throws a
435
+ # +ReturnException+ which can be caught to have the function
436
+ # or block return what they wish.
437
+ class Return
438
+ def initialize val
439
+ @val = val
440
+ end
441
+
442
+ def data_type
443
+ :any
444
+ end
445
+
446
+ def execute env
447
+ raise ReturnException.new(@val.execute(env))
448
+ end
449
+ end
450
+
325
451
  # A function call or a function or a block. The initialization of a new
326
452
  # enviroment is done by the function Class as it also sorts the arguments
327
453
  # into it.
@@ -21,13 +21,13 @@ module RVM
21
21
  # require 'lib/base/languages'
22
22
  # code = RVM::Classes[:math].compile '(1 + 1) * 3^2'
23
23
  module Languages
24
- extend PluginHost
24
+ extend RVM::PluginHost
25
25
 
26
26
  # The Compiler class, it holds the compiler. As those grow big I suggest
27
27
  # to split the actuall code into multiple fils. Have a look at the MUSHCode
28
28
  # compile for an example.
29
29
  class Language
30
- extend Plugin
30
+ extend RVM::Plugin
31
31
  plugin_host Languages
32
32
  class << self
33
33
 
@@ -37,8 +37,9 @@ module RVM
37
37
  nil
38
38
  end
39
39
 
40
+ # Class method called from the plugin to register witht the plugin host.
40
41
  def register_for *ids
41
- plugin_host.register self.new, *ids
42
+ plugin_host.register self, *ids
42
43
  end
43
44
  end
44
45
  end