core/block_environment.rb
##
# Describes the environment a block was created in. BlockEnvironment is used
# to create a BlockContext.
module Rubinius
class BlockEnvironment
attr_reader :scope
attr_reader :top_scope
attr_reader :module
# The CompiledCode that implements the code for the block
attr_reader :compiled_code
attr_reader :lexical_scope
attr_accessor :proc_environment
def self.allocate
Rubinius.primitive :blockenvironment_allocate
raise PrimitiveFailure, "BlockEnvironment.allocate primitive failed"
end
def call(*args)
Rubinius.primitive :block_call
raise PrimitiveFailure, "BlockEnvironment#call primitive failed"
end
def call_under(recv, lexical_scope, visibility_scope, *args)
Rubinius.primitive :block_call_under
raise PrimitiveFailure, "BlockEnvironment#call_under primitive failed"
end
def self.of_sender
Rubinius.primitive :block_env_of_sender
raise PrimitiveFailure, "BlockEnvironment#of_sender primitive failed"
end
class AsMethod < Executable
attr_reader :block_env
def self.new(block_env)
Rubinius.primitive :block_as_method_create
raise PrimitiveFailure, "BlockEnvironment::AsMethod.new primitive failed"
end
def ==(other)
# Given the following code:
# class Foo
# p = Proc.new { :cool }
# define_method :a, p
# define_method :a, p
# end
# foo = Foo.new
# foo.method(:a)
# foo.method(:b)
#
# The Method instances for :a and :b have different
# BlockEnvironments as define_method dups the BE
# when given a Proc.
#
# The methods are equal if the BEs are equal.
return false unless other.kind_of? AsMethod
@block_env == other.block_env
end
def parameters
@block_env.parameters
end
def arity
@block_env.compiled_code.arity
end
def local_names
@block_env.compiled_code.local_names
end
def required_args
@block_env.compiled_code.required_args
end
def total_args
@block_env.compiled_code.total_args
end
def post_args
@block_env.compiled_code.post_args
end
def splat
@block_env.compiled_code.splat
end
def block_index
@block_env.compiled_code.block_index
end
def file
@block_env.file
end
def defined_line
@block_env.line
end
def scope
@block_env.scope
end
end
def from_proc?
@proc_environment
end
def under_context(scope, code)
@top_scope = scope
@scope = scope
@compiled_code = code
@lexical_scope = code.scope
@module = code.scope.module
return self
end
def change_name(name)
@compiled_code = @compiled_code.change_name name
end
def repoint_scope(where)
@lexical_scope.using_current_as where
end
def disable_scope!
@lexical_scope.using_disabled_scope
end
def to_binding
Binding.setup @scope, @compiled_code, @lexical_scope
end
def make_independent
@top_scope = @top_scope.dup
@scope = @scope.dup
end
def call_on_instance(obj, *args)
call_under obj, @lexical_scope, false, *args
end
def arity
@compiled_code.arity
end
def parameters
@compiled_code.parameters
end
def file
@compiled_code.file
end
def line
@compiled_code.defined_line
end
def source_location
[file.to_s, line]
end
def ==(other)
return false unless other.kind_of? BlockEnvironment
@top_scope == other.top_scope and
@scope == other.scope and
@module == other.module and
@compiled_code.equivalent_body?(other.compiled_code)
end
def inspect
"#<#{self.class.name}:0x#{self.object_id.to_s(16)} scope=#{@scope.inspect} top_scope=#{@top_scope.inspect} module=#{@module.inspect} compiled_code=#{@compiled_code.inspect} lexical_scope=#{@lexical_scope.inspect}>"
end
end
end