forked from rubinius/rubinius
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbinding.rb
116 lines (93 loc) · 2.94 KB
/
binding.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class Binding
attr_accessor :variables
attr_accessor :compiled_code
attr_accessor :lexical_scope
attr_accessor :proc_environment
attr_accessor :location
attr_accessor :receiver
def from_proc?
@proc_environment
end
def self.self_context(recv, variables)
Rubinius::Type.object_equal(recv, Kernel) ? recv : variables.self
end
private :self_context
# Create a new Binding object. MRI does not allow .new to be called, so
# we used .setup(). Any code can use this as they wish, provided they have
# all the right arguments.
#
# +variables+ is a Rubinius::VariableScope object
# +code+ is a Rubinius::CompiledCode object
# +lexical_scope+ is a Rubinius::LexicalScope object
#
# See Kernel#binding in core/eval.rb for a simple example of creating a
# Binding object.
#
def self.setup(variables, code, lexical_scope, recv=nil, location=nil)
bind = allocate()
bind.receiver = self_context(recv, variables)
bind.variables = variables
bind.compiled_code = code
bind.lexical_scope = lexical_scope
bind.location = location
return bind
end
def line_number
if proc_environment
proc_environment.line
else
location ? location.line : 1
end
end
# Evaluates the Ruby expression(s) in string, in the binding‘s context.
# If the optional filename and lineno parameters are present,
# they will be used when reporting syntax errors.
def eval(expr, filename=nil, lineno=nil)
lineno ||= filename ? 1 : line_number
Kernel.eval(expr, self, filename, lineno)
end
def local_variables
variables.local_variables
end
def local_variable_set(name, value)
unless name.is_a?(Symbol)
name = Rubinius::Type.coerce_to(name, String, :to_str).to_sym
end
vars = variables
# If a local variable is defined in a parent scope we should update the
# variable in said scope and all child scopes, instead of _only_ setting it
# in the current scope.
while vars
meth = vars.method
if meth.local_names.include?(name)
return vars.set_local(meth.local_slot(name), value)
elsif vars.eval_local_defined?(name)
return vars.set_eval_local(name, value)
end
vars = vars.parent
end
variables.set_eval_local(name, value)
end
def local_variable_get(name)
unless name.is_a?(Symbol)
name = Rubinius::Type.coerce_to(name, String, :to_str).to_sym
end
vars = variables
while vars
meth = vars.method
if meth.local_names.include?(name)
return vars.locals[meth.local_slot(name)]
elsif vars.eval_local_defined?(name)
return vars.get_eval_local(name)
end
vars = vars.parent
end
raise NameErrror, "local variable #{name.inspect} not defined for #{inspect}"
end
def local_variable_defined?(name)
unless name.is_a?(Symbol)
name = Rubinius::Type.coerce_to(name, String, :to_str).to_sym
end
variables.local_defined?(name)
end
end