Re-enable spec/library for full CI runs.
[rbx.git] / kernel / core / eval.rb
blob4d1d50e0c23ce559802f8d87633c4fef08b2c5c2
1 # depends on: array.rb proc.rb binding.rb
2 # (due to alias_method)
4 module Kernel
5   
6   def local_variables
7     ary = []
8     ctx = MethodContext.current.sender
9     
10     while ctx.kind_of? BlockContext
11       if names = ctx.method.local_names
12         names.each { |n| ary << n.to_s }
13       end
14       ctx = ctx.home
15     end
16         
17     if names = ctx.method.local_names
18       names.each { |n| ary << n.to_s }
19     end
20     
21     return ary
22   end
23   module_function :local_variables
25   def binding
26     ctx = MethodContext.current.sender
27     # If we are here because of eval, fetch the context of
28     # the thing that invoked eval
29     if ctx.from_eval?
30       Binding.setup ctx.sender.sender
31     else
32       Binding.setup ctx
33     end
34   end
35   module_function :binding
37   def eval(string, binding=nil, filename='(eval)', lineno=1)
38     if !binding
39       binding = Binding.setup MethodContext.current.sender
40     elsif binding.__kind_of__ Proc
41       binding = binding.binding
42     elsif !binding.__kind_of__ Binding
43       raise ArgumentError, "unknown type of binding"
44     end
46     compiled_method = Compile.compile_string string, binding.context, filename, lineno
47     compiled_method.staticscope = binding.context.method.staticscope.dup
49     # This has to be setup so __FILE__ works in eval.
50     script = CompiledMethod::Script.new
51     script.path = filename
52     compiled_method.staticscope.script = script
54     be = BlockEnvironment.new
55     be.under_context binding.context, compiled_method
57     # Pass the BlockEnvironment this binding was created from
58     # down into the new BlockEnvironment we just created.
59     # This indicates the "declaration trace" to the stack trace
60     # mechanisms, which can be different from the "call trace"
61     # in the case of, say: eval("caller", a_proc_instance)
62     if binding.from_proc? then
63       be.proc_environment = binding.proc_environment
64     end
66     be.from_eval!
67     be.call
68   end
69   module_function :eval
70   private :eval
72   ##
73   # :call-seq:
74   #   obj.instance_eval(string [, filename [, lineno]] )   => obj
75   #   obj.instance_eval {| | block }                       => obj
76   #
77   # Evaluates a string containing Ruby source code, or the given block, within
78   # the context of the receiver +obj+. In order to set the context, the
79   # variable +self+ is set to +obj+ while the code is executing, giving the
80   # code access to +obj+'s instance variables. In the version of
81   # #instance_eval that takes a +String+, the optional second and third
82   # parameters supply a filename and starting line number that are used when
83   # reporting compilation errors.
84   #
85   #   class Klass
86   #     def initialize
87   #       @secret = 99
88   #     end
89   #   end
90   #   k = Klass.new
91   #   k.instance_eval { @secret }   #=> 99
93   def instance_eval(string = nil, filename = "(eval)", line = 1, modeval = false, binding = nil, &prc)
94     if prc
95       if string
96         raise ArgumentError, 'cannot pass both a block and a string to evaluate'
97       end
98       # Return a copy of the BlockEnvironment with the receiver set to self
99       env = prc.block.redirect_to self
100       env.method.staticscope = StaticScope.new(__metaclass__, env.method.staticscope)
101       original_scope = prc.block.home.method.staticscope
102       env.constant_scope = original_scope
103       return env.call(*self)
104     elsif string
105       string = StringValue(string)
107       if binding
108         context = binding.context
109       else
110         context = MethodContext.current.sender
111       end
113       compiled_method = Compile.compile_string string, context, filename, line
114       compiled_method.inherit_scope context.method
116       # If this is a module_eval style evaluation, add self to the top of the
117       # staticscope chain, so that methods and such are added directly to it.
118       if modeval
119         compiled_method.staticscope = StaticScope.new(self, compiled_method.staticscope)
120       else
122       # Otherwise add our metaclass, so thats where new methods go.
123         compiled_method.staticscope = StaticScope.new(metaclass, compiled_method.staticscope)
124       end
126       # This has to be setup so __FILE__ works in eval.
127       script = CompiledMethod::Script.new
128       script.path = filename
129       compiled_method.staticscope.script = script
131       be = BlockEnvironment.new
132       be.from_eval!
133       be.under_context context, compiled_method
134       be.call_on_instance(self)
135     else
136       raise ArgumentError, 'block not supplied'
137     end
138   end
142 class Module
144   #--
145   # These have to be aliases, not methods that call instance eval, because we
146   # need to pull in the binding of the person that calls them, not the
147   # intermediate binding.
148   #++
150   def module_eval(string = Undefined, filename = "(eval)", line = 1, &prc)
151     # we have a custom version with the prc, rather than using instance_exec
152     # so that we can setup the StaticScope properly.
153     if prc
154       unless string.equal?(Undefined)
155         raise ArgumentError, "cannot pass both string and proc"
156       end
158       env = prc.block.redirect_to self
159       env.method.staticscope = StaticScope.new(self, env.method.staticscope)
160       return env.call()
161     elsif string.equal?(Undefined)
162       raise ArgumentError, 'block not supplied'
163     end
165     context = MethodContext.current.sender
167     string = StringValue(string)
169     compiled_method = Compile.compile_string string, context, filename, line
171     # The staticscope of a module_eval CM is the receiver of module_eval
172     ss = StaticScope.new(self, context.method.staticscope)
174     # This has to be setup so __FILE__ works in eval.
175     script = CompiledMethod::Script.new
176     script.path = filename
177     ss.script = script
179     compiled_method.staticscope = ss
181     # The gist of this code is that we need the receiver's static scope
182     # but the caller's binding to implement the proper constant behavior
183     be = BlockEnvironment.new
184     be.from_eval!
185     be.under_context context, compiled_method
186     be.make_independent
187     be.home.receiver = self
188     be.home.make_independent
189     # open_module and friends in the VM use this field to determine scope
190     be.home.method.staticscope = ss
191     be.call
192   end
193   alias_method :class_eval, :module_eval
195   def _eval_under(*args, &block)
196     raise "not yet" unless block
198     env = block.block.redirect_to self
199     env.method.staticscope = StaticScope.new(self, env.method.staticscope)
201     return env.call(*args)
202   end
203   private :_eval_under