Class: RVM::Interpreter::Environment

Inherits:
Object
  • Object
show all
Defined in:
lib/rvm/environment.rb

Overview

The environment holds environmental variables like who executes the code, on what object it runs, what parameters where passed to the call and as well, and perhaps most importantly the local variables.

Some of the functions called will initialize new environments, as for example function calls.

Instance Method Summary collapse

Constructor Details

#initialize(init_data = {}, oldenv = nil) ⇒ Environment

This creates a new environment environment, it generates a new env default variables are set if not defined in data.

If oldenv is provided it will also fall back to see if not existing variables

init_data is a hash that can be passed the following values:

:locals

A hash with local variables mapped name => value

:functions

A hash with functions for the scope.

:evaldeepth

A fixnum that indicates how deep the evaluation is.

:params

A array that holds local parameters for example for functions or blocks.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/rvm/environment.rb', line 23

def initialize init_data = {}, oldenv=nil
  
  @data = {
    :locals => {}, #oldenv ? oldenv.data[:locals] : {},
    :locals_swapped => true, # init_data.keys.include?(:locals),
    :functions => oldenv ? oldenv.data[:functions] : {},
    :functions_swapped => init_data.keys.include?(:functions),
    :evaldeepth => 0,
    :params => oldenv ? oldenv.data[:params] : [],
    :params_swapped => init_data.keys.include?(:params)
  }.merge(init_data)
  @path = [] if oldenv.nil?
  
  # Make sure that all locals that are passed, are actually in a variable
  # storage.
  if init_data[:locals]
    # For easy access we get us a link to the locals
    locals = @data[:locals]
    # Now we itterate through them
    init_data[:locals].each do |k,v|
      #For every variable that isn't already in a storage
      if not v.is_a?(VariableStorage)
        # We put it in a storage to assure the environment is propper.
        locals[k] = VariableStorage.new(v)
      end
    end
  end
  
  # We store the priviouse environment to look upwards through the scopes
  # for priviouse defined variables, if no old environment was given we
  # set the priviose scope to an empty hash.
  @prev = oldenv || {}
  RVM::debug "data: #{data}\noldenv:#{oldenv}" if $DEBUG
  RVM::debug "Creating new environment with: #{@data.inspect} as child" +
             " of #{@prev}" if $DEBUG
end

Instance Method Details

#[](k) ⇒ Object

Returns a local variable with the given name.

If the current environment does not have any local variables with the given name it tries the privious environments.

This returns the VariableData object NOT the value of the variable. Use read_var_val if you want to read the value of a variable.



92
93
94
95
96
97
98
# File 'lib/rvm/environment.rb', line 92

def [] k
  
  r = @data[:locals][k] 
  r = @prev[k] if not r and @data[:locals_swapped]
  RVM::debug "Getting variable #{k} (#{r})" if $DEBUG
  r
end

#[]=(name, value) ⇒ Object

Sets a local variable witin the environment.

If the variable exists in a ‘higher’ environment the value is changed.

If not it is newly created in the current environment and thus not visible in upper environments.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rvm/environment.rb', line 106

def []= name, value
  RVM::debug "Setting variable #{name} to #{value}" if $DEBUG
  
  # First we try to get the variable storage of the variable requested.
  # This will work if it was defined in this or a priviouse scope.
  if storage = self[name]
    # If we found the storage we'll change it's value and not define it
    # again.
    storage.val = value
  else
    # If we didn't found a Variable storage, the variable wasn't defined
    # before so we make a new VariableStorage and save the variable in
    # it.
    declare name, value
  end
  value
end

#dataObject

Allows raw access to the data, it should not be used unless somoene knows pretty exactly what they are doing.



63
64
65
# File 'lib/rvm/environment.rb', line 63

def data
  @data
end

#declare(name, value) ⇒ Object

Defines a varialbe in the current scope, priviose variables are not changed. This is needed for local varialbe declarations that overwrite priviouse globals.



128
129
130
131
132
133
134
135
# File 'lib/rvm/environment.rb', line 128

def declare name, value
  #Now we need to make our own set of storage!
  if not @data[:locals_swapped]
    @data[:locals_swapped] = true
    @data[:locals] = {}
  end
  @data[:locals][name] = VariableStorage.new(value)
end

#def_function(name, body) ⇒ Object

This defines a function within the environment and lets you call it later on.

It expects the body to be a RVM::Classes::Block so it can be executed. The return value is the given block



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/rvm/environment.rb', line 157

def def_function name, body
  if not body.is_a?(RVM::Classes::Block)
    raise(ArgumentError, "Function definitions must be of block class.") 
  end
  
  #Now we need to make our own set of storage!
  if not @data[:functions_swapped]
    @data[:functions_swapped] = true
    @data[:functions] = {}
  end
  
  @data[:functions][name] = body
  RVM::debug "Setting functon #{name} (#{body})" if $DEBUG
  body
end

#function(name) ⇒ Object

Returns a function for the environment. If the current environment does not hold a function with the requested name it checks through the entire tree if a function can be found in the outer scopes.

The result is to be execpted to be of the RVM::Classes::Block class.



142
143
144
145
146
147
148
149
150
# File 'lib/rvm/environment.rb', line 142

def function name
  # Try to get the function in the local defintions.
  fun = @data[:functions][name]
  # if that fails and we have a previous environment check that
  fun = @prev.function(name) if fun.nil? and @data[:functions_swapped] and @prev.is_a? Environment
  RVM::debug "Getting functon #{name} (#{fun})" if $DEBUG
  # return what was found
  fun
end

#param(i) ⇒ Object

returns a parameter that was passed to the call. For function calls this is especially important, it beginns with 0.

If the current environment does not have the given paramenter it tries it’s ‘oldenv’ attrib to see if that had a object.



76
77
78
79
80
81
82
83
# File 'lib/rvm/environment.rb', line 76

def param i
  RVM::debug "Getting param #{i} (#{@data[:params][i]})" if $DEBUG
  if @data[:params_swapped]
    @data[:params][i] || @prev.param(i)
  else
    @data[:params][i]
  end
end

#pathObject



67
68
69
# File 'lib/rvm/environment.rb', line 67

def path
  @path || @pre.path
end

#read_var_val(name) ⇒ Object

This functin is closely related to [] with the difference that it returns the value and not the VariableStorage object. It is equivalent to [].val just that it also deals with nil ojects and and returns a RVM::Classes::Error if the requested variable wasn’t found.



178
179
180
181
182
183
184
185
186
187
188
# File 'lib/rvm/environment.rb', line 178

def read_var_val name
  
  r = nil
  if (v = self[name])
    r = v.val
  else
    raise "Variable #{name} is not defined."
  end
  RVM::debug "Getting variable value #{name} (#{r})" if $DEBUG
  r
end