rubinius/rubinius

View on GitHub
core/kernel.rb

Summary

Maintainability
F
3 days
Test Coverage
module Kernel
  def equal?(other)
    Rubinius.primitive :object_equal
    raise PrimitiveFailure, "Kernel#equal? primitive failed"
  end

  alias_method :eql?, :equal?
  alias_method :==,  :equal?
  alias_method :===, :equal?

  def !~(other)
    res = self =~ other ? false : true
    Regexp.last_match = Regexp.last_match
    res
  end

  def become(other)
    Rubinius.primitive :object_become
    raise PrimitiveFailure, "Object#become primitive failed"
  end

  def singleton_class
    Rubinius::Type.object_singleton_class self
  end

  def extend(mod)
    Rubinius::Type.object_singleton_class(self).include(mod)
    self
  end

  def freeze
    Rubinius.primitive :object_freeze
    raise PrimitiveFailure, "Kernel#freeze primitive failed"
  end

  def frozen?
    Rubinius.primitive :object_frozen_p
    raise PrimitiveFailure, "Kernel#frozen? primitive failed"
  end

  def hash
    Rubinius.primitive :object_hash
    raise PrimitiveFailure, "Kernel#hash primitive failed"
  end

  def inspect
    "#<#{self.class.name}"
  end

  def respond_to_prim?(meth, visibility)
    Rubinius.primitive :object_respond_to
    meth = Rubinius::Type.coerce_to_symbol meth
    respond_to_prim?(meth, visibility)
  end

  private :respond_to_prim?

  def taint
    Rubinius.primitive :object_taint
    raise PrimitiveFailure, "Kernel#taint primitive failed"
  end

  def tainted?
    Rubinius.primitive :object_tainted_p
    raise PrimitiveFailure, "Kernel#tainted? primitive failed"
  end

  def untaint
    Rubinius.primitive :object_untaint
    raise PrimitiveFailure, "Kernel#untaint primitive failed"
  end

  alias_method :untrust, :taint
  alias_method :trust, :untaint
  alias_method :untrusted?, :tainted?

  # NOTE: The bootstrap method used to add method definitions to the class
  # method_table still returns a CompiledCode instance, so this chaining
  # works.
  #
  # TODO: Fix this chaining by introducing a proper facility to operate on
  # methods.
  def respond_to?(meth, include_private=false)
    respond_to_prim?(meth, include_private)
  end

  custom_call_site :respond_to?

  def respond_to_missing?(meth, include_private)
    false
  end
  private :respond_to_missing?

  def yield_gdb(obj)
    Rubinius.primitive :yield_gdb
    raise PrimitiveFailure, "Kernel#yield_gdb primitive failed"
  end
  private :yield_gdb

  def Array(obj)
    ary = Rubinius::Type.check_convert_type obj, Array, :to_ary

    return ary if ary

    if array = Rubinius::Type.check_convert_type(obj, Array, :to_a)
      array
    else
      [obj]
    end
  end
  module_function :Array

  def Complex(*args)
    Rubinius.privately do
      Complex.convert(*args)
    end
  end
  module_function :Complex

  def Float(obj)
    case obj
    when String
      Rubinius::Type.coerce_string_to_float obj, true
    else
      Rubinius::Type.coerce_object_to_float obj
    end
  end
  module_function :Float

  ##
  # MRI uses a macro named NUM2DBL which has essentially the same semantics as
  # Float(), with the difference that it raises a TypeError and not a
  # ArgumentError. It is only used in a few places (in MRI and Rubinius).
  #--
  # If we can, we should probably get rid of this.

  def FloatValue(obj)
    exception = TypeError.new 'no implicit conversion to float'

    case obj
    when String
      raise exception
    else
      begin
        Rubinius::Type.coerce_object_to_float obj
      rescue
        raise exception
      end
    end
  end
  private :FloatValue

  def Hash(obj)
    return {} if obj.nil? || obj == []

    if hash = Rubinius::Type.check_convert_type(obj, Hash, :to_hash)
      return hash
    end

    raise TypeError, "can't convert #{obj.class} into Hash"
  end
  module_function :Hash

  def Integer(obj, base=nil)
    if obj.kind_of? String
      if obj.empty?
        raise ArgumentError, "invalid value for Integer: (empty string)"
      else
        base ||= 0
        return obj.to_inum(base, true)
      end
    end

    if base
      raise ArgumentError, "base is only valid for String values"
    end

    case obj
    when Integer
      obj
    when Float
      if obj.nan? or obj.infinite?
        raise FloatDomainError, "unable to coerce #{obj} to Integer"
      else
        obj.to_int
      end
    when NilClass
      raise TypeError, "can't convert nil into Integer"
    else
      # Can't use coerce_to or try_convert because I think there is an
      # MRI bug here where it will return the value without checking
      # the return type.
      if obj.respond_to? :to_int
        if val = obj.to_int
          return val
        end
      end

      Rubinius::Type.coerce_to obj, Integer, :to_i
    end
  end
  module_function :Integer

  def Rational(a, b = 1)
    Rubinius.privately do
      Rational.convert a, b
    end
  end
  module_function :Rational

  def String(obj)
    return obj if obj.kind_of? String

    unless obj.respond_to?(:to_s)
      raise TypeError, "can't convert #{obj.class} into String"
    end

    begin
      str = obj.to_s
    rescue NoMethodError
      raise TypeError, "can't convert #{obj.class} into String"
    end

    unless str.kind_of? String
      raise TypeError, "#to_s did not return a String"
    end

    return str
  end
  module_function :String

  ##
  # MRI uses a macro named StringValue which has essentially the same
  # semantics as obj.coerce_to(String, :to_str), but rather than using that
  # long construction everywhere, we define a private method similar to
  # String().
  #
  # Another possibility would be to change String() as follows:
  #
  #   String(obj, sym=:to_s)
  #
  # and use String(obj, :to_str) instead of StringValue(obj)

  def StringValue(obj)
    Rubinius::Type.coerce_to obj, String, :to_str
  end
  module_function :StringValue

  def __method__
    scope = Rubinius::VariableScope.of_sender

    return nil if scope.method.for_module_body?

    name = scope.method.name

    # If the name is still __block__, then it's in a script, so return nil
    return nil if name == :__block__ or name == :__script__

    name
  end
  module_function :__method__

  def __callee__
    scope = Rubinius::VariableScope.of_sender

    return nil if scope.method.for_module_body?

    name = scope.name

    # If the name is still __block__, then it's in a script, so return nil
    return nil if name == :__block__ or name == :__script__

    name
  end
  module_function :__callee__

  def __dir__
    scope = Rubinius::LexicalScope.of_sender
    script = scope.current_script
    basepath = script.file_path
    fullpath = nil

    return nil unless basepath

    fullpath = if script.data_path
      script.data_path
    else
      Rubinius.privately do
        File.basic_realpath(basepath)
      end
    end

    File.dirname fullpath
  end
  module_function :__dir__

  def `(str) #`
    str = StringValue(str) unless str.kind_of?(String)
    pid, output = Rubinius::Mirror::Process.backtick str
    Process.waitpid(pid)

    Rubinius::Type.external_string output
  end
  module_function :` # `

  def =~(other)
    nil
  end

  def <=>(other)
    self == other ? 0 : nil
  end

  def ===(other)
    equal?(other) || self == other
  end

  def itself
    self
  end

  def abort(msg=nil)
    Process.abort msg
  end
  module_function :abort

  def at_exit(prc=nil, &block)
    if prc
      unless prc.respond_to?(:call)
        raise "Argument must respond to #call"
      end
    else
      prc = block
    end

    unless prc
      raise "must pass a #call'able or block"
    end

    Rubinius::AtExit.unshift(prc)
  end
  module_function :at_exit

  def autoload(name, file)
    Object.autoload(name, file)
  end
  private :autoload

  def autoload?(name)
    Object.autoload?(name)
  end
  private :autoload?

  def block_given?
    Rubinius::VariableScope.of_sender.block != nil
  end
  module_function :block_given?

  alias_method :iterator?, :block_given?
  module_function :iterator?

  def caller_inner(start, length)
    if start.is_a?(Range)
      length = start.size
      start = start.begin
    end

    # The + 2 is to skip this frame and the caller's.
    #
    # TODO: plumb length into mri_backtrace to save some work.
    full_trace = Rubinius.mri_backtrace(start + 2)
    if length
      full_trace = full_trace.slice(0, length)
    end
    full_trace
  end
  module_function :caller_inner
  private :caller_inner

  def caller(start = 1, length = nil)
    caller_inner(start, length).map do |tup|
      code     = tup[0]
      line     = tup[1]
      is_block = tup[2]
      name     = tup[3]

      "#{code.active_path}:#{line}:in `#{name}'"
    end
  end
  module_function :caller

  ##
  # Returns the current call stack as an Array of Thread::Backtrace::Location
  # instances. This method is available starting with Ruby 2.0.
  #
  def caller_locations(start = 1, length = nil)
    caller_inner(start, length).map do |tup|
      scope    = tup[0].scope
      abs_path = tup[0].active_path
      path     = scope ? scope.active_path : abs_path
      label    = tup[3].to_s

      Thread::Backtrace::Location.new(label, abs_path, path, tup[1])
    end
  end
  module_function :caller_locations

  def define_singleton_method(*args, &block)
    singleton_class.send(:define_method, *args, &block)
  end

  def display(port=$>)
    port.write self
  end

  def exec(*args)
    Process.exec(*args)
  end
  module_function :exec

  def exit(code=0)
    Process.exit(code)
  end
  module_function :exit

  def exit!(code=1)
    Process.exit!(code)
  end
  module_function :exit!

  def fork(&block)
    Process.fork(&block)
  end
  module_function :fork

  def getc
    $stdin.getc
  end
  module_function :getc

  def gets(sep=$/)
    ARGF.gets(sep)
  end
  module_function :gets

  def global_variables
    Rubinius::Globals.variables
  end
  module_function :global_variables

  def initialize_dup(other)
    initialize_copy(other)
  end
  private :initialize_dup

  def initialize_clone(other)
    initialize_copy(other)
  end
  private :initialize_clone

  def initialize_copy(source)
    unless instance_of?(Rubinius::Type.object_class(source))
      raise TypeError, "initialize_copy should take same class object"
    end
  end
  private :initialize_copy

  def inspect
    prefix = "#<#{self.class}:0x#{self.__id__.to_s(16)}"

    # The protocol here seems odd, but it's to match MRI.
    #
    # MRI side-calls to the C function that implements Kernel#to_s. If that
    # method is overridden, the new Ruby method is never called. So, we inline
    # the code for Kernel#to_s here because we simply dispatch to Ruby
    # methods.
    ivars = Rubinius.invoke_primitive :object_instance_variables, self

    if ivars.empty?
      return Rubinius::Type.infect "#{prefix}>", self
    end

    # Otherwise, if it's already been inspected, return the ...
    return "#{prefix} ...>" if Thread.guarding? self

    # Otherwise, gather the ivars and show them.
    parts = []

    Thread.recursion_guard self do
      ivars.each do |var|
        parts << "#{var}=#{__instance_variable_get__(var).inspect}"
      end
    end

    if parts.empty?
      str = "#{prefix}>"
    else
      str = "#{prefix} #{parts.join(' ')}>"
    end

    Rubinius::Type.infect(str, self)

    return str
  end

  ##
  # Returns true if this object is an instance of the given class, otherwise
  # false. Raises a TypeError if a non-Class object given.
  #
  # Module objects can also be given for MRI compatibility but the result is
  # always false.

  def instance_of?(cls)
    Rubinius.primitive :object_instance_of

    arg_class = Rubinius::Type.object_class(cls)
    if arg_class != Class and arg_class != Module
      # We can obviously compare against Modules but result is always false
      raise TypeError, "instance_of? requires a Class argument"
    end

    Rubinius::Type.object_class(self) == cls
  end

  def instance_variable_get(sym)
    Rubinius.primitive :object_get_ivar

    sym = Rubinius::Type.ivar_validate sym
    instance_variable_get sym
  end

  alias_method :__instance_variable_get__, :instance_variable_get

  def instance_variable_set(sym, value)
    Rubinius.primitive :object_set_ivar

    sym = Rubinius::Type.ivar_validate sym
    instance_variable_set sym, value
  end

  alias_method :__instance_variable_set__, :instance_variable_set

  def instance_variables
    Rubinius.invoke_primitive :object_instance_variables, self
  end

  def instance_variable_defined?(name)
    Rubinius.primitive :object_ivar_defined

    instance_variable_defined? Rubinius::Type.ivar_validate(name)
  end

  # Both of these are for defined? when used inside a proxy obj that
  # may undef the regular method. The compiler generates __ calls.
  alias_method :__instance_variable_defined_p__, :instance_variable_defined?
  alias_method :__respond_to_p__, :respond_to?

  alias_method :is_a?, :kind_of?

  def lambda
    env = nil

    Rubinius.asm do
      push_block
      # assign a pushed block to the above local variable "env"
      # Note that "env" is indexed at 0.
      set_local 0
    end

    raise ArgumentError, "block required" unless env

    prc = Rubinius::Mirror::Proc.from_block ::Proc, env

    # Make a proc lambda only when passed an actual block (ie, not using the
    # "&block" notation), otherwise don't modify it at all.
    prc.lambda_style! if env.is_a?(Rubinius::BlockEnvironment)

    return prc
  end
  module_function :lambda

  def load(name, wrap=false)
    Rubinius::CodeLoader.new(name).load(wrap)
    # cl = Rubinius::CodeLoader.new(name)
    # cl.load(wrap)

    # Rubinius.run_script cl.compiled_code

    # Rubinius::CodeLoader.loaded_hook.trigger!(name)

    # return true
  end
  module_function :load

  def loop
    return to_enum(:loop) { Float::INFINITY } unless block_given?

    begin
      while true
        yield
      end
    rescue StopIteration => e
      e.result
    end
  end
  module_function :loop

  def method(name)
    name = Rubinius::Type.coerce_to_symbol name
    code = Rubinius.find_method(self, name)

    if code
      Method.new(self, code[1], code[0], name)
    elsif respond_to_missing?(name, true)
      Method.new(self, self.class, Rubinius::MissingMethod.new(self,  name), name)
    else
      raise NameError, "undefined method `#{name}' for class #{self.class}"
    end
  end

  def methods(all=true)
    methods = singleton_methods(all)

    if all
      # We have to special case these because unlike true, false, nil,
      # Type.object_singleton_class raises a TypeError.
      case self
      when Fixnum, Symbol
        methods |= Rubinius::Type.object_class(self).instance_methods(true)
      else
        methods |= Rubinius::Type.object_singleton_class(self).instance_methods(true)
      end
    end

    return methods if kind_of?(ImmediateValue)

    undefs = []
    Rubinius::Type.object_singleton_class(self).method_table.filter_entries do |entry|
      undefs << entry.name.to_s if entry.visibility == :undef
    end

    return methods - undefs
  end

  def object_id
    Rubinius.primitive :object_id
    raise PrimitiveFailure, "Kernel#object_id primitive failed"
  end

  def open(obj, *rest, &block)
    if obj.respond_to?(:to_open)
      obj = obj.to_open(*rest)

      if block_given?
        return yield(obj)
      else
        return obj
      end
    end

    path = Rubinius::Type.coerce_to_path obj

    if path.kind_of? String and path.prefix? '|'
      return IO.popen(path[1..-1], *rest, &block)
    end

    File.open(path, *rest, &block)
  end
  module_function :open

  def p(*a)
    return nil if a.empty?
    a.each { |obj| $stdout.puts obj.inspect }
    $stdout.flush

    a.size == 1 ? a.first : a
  end
  module_function :p

  def print(*args)
    args.each do |obj|
      $stdout.write obj.to_s
    end
    nil
  end
  module_function :print

  def printf(target, *args)
    if target.kind_of?(String)
      output = $stdout
    else
      output = target
      target = args.shift
    end
    output.write Rubinius::Sprinter.get(target).call(*args)
    nil
  end
  module_function :printf

  def private_methods(all=true)
    private_singleton_methods() | Rubinius::Type.object_class(self).private_instance_methods(all)
  end

  def private_singleton_methods
    sc = Rubinius::Type.object_singleton_class self
    methods = sc.method_table.private_names

    m = sc

    while m = m.direct_superclass
      unless Rubinius::Type.object_kind_of?(m, Rubinius::IncludedModule) or
             Rubinius::Type.singleton_class_object(m)
        break
      end

      methods.concat m.method_table.private_names
    end

    methods
  end
  private :private_singleton_methods

  def proc
    env = nil

    Rubinius.asm do
      push_block
      # assign a pushed block to the above local variable "env"
      set_local 0
    end

    unless env
      # Support for ancient pre-block-pass style:
      # def something
      #   proc
      # end
      # something { a_block } => Proc instance
      env = Rubinius::BlockEnvironment.of_sender

      unless env
        raise ArgumentError, "tried to create a Proc object without a block"
      end
    end

    Proc.new(&env)
  end
  module_function :proc

  def protected_methods(all=true)
    protected_singleton_methods() | Rubinius::Type.object_class(self).protected_instance_methods(all)
  end

  def protected_singleton_methods
    m = Rubinius::Type.object_singleton_class self
    methods = m.method_table.protected_names

    while m = m.direct_superclass
      unless Rubinius::Type.object_kind_of?(m, Rubinius::IncludedModule) or
             Rubinius::Type.singleton_class_object(m)
        break
      end

      methods.concat m.method_table.protected_names
    end

    methods
  end
  private :protected_singleton_methods

  def public_method(name)
    name = Rubinius::Type.coerce_to_symbol name
    code = Rubinius.find_public_method(self, name)

    if code
      Method.new(self, code[1], code[0], name)
    elsif respond_to_missing?(name, false)
      Method.new(self, self.class, Rubinius::MissingMethod.new(self,  name), name)
    else
      raise NameError, "undefined method `#{name}' for #{self.inspect}"
    end
  end

  def public_methods(all=true)
    public_singleton_methods | Rubinius::Type.object_class(self).public_instance_methods(all)
  end

  def public_send(message, *args)
    Rubinius.primitive :object_public_send
    raise PrimitiveFailure, "Kernel#public_send primitive failed"
  end

  def public_singleton_methods
    m = Rubinius::Type.object_singleton_class self
    methods = m.method_table.public_names

    while m = m.direct_superclass
      unless Rubinius::Type.object_kind_of?(m, Rubinius::IncludedModule) or
             Rubinius::Type.singleton_class_object(m)
        break
      end

      methods.concat m.method_table.public_names
    end

    methods
  end
  private :public_singleton_methods

  def putc(int)
    $stdout.putc(int)
  end
  module_function :putc

  def puts(*a)
    $stdout.puts(*a)
    nil
  end
  module_function :puts

  def rand(limit=0)
    if limit == 0
      return Thread.current.randomizer.random_float
    end

    if limit.kind_of?(Range)
      return Thread.current.randomizer.random(limit)
    else
      limit = Integer(limit).abs

      if limit == 0
        Thread.current.randomizer.random_float
      else
        Thread.current.randomizer.random_integer(limit - 1)
      end
    end
  end
  module_function :rand

  def readline(sep=$/)
    ARGF.readline(sep)
  end
  module_function :readline

  def readlines(sep=$/)
    ARGF.readlines(sep)
  end
  module_function :readlines

  def remove_instance_variable(sym)
    Rubinius.primitive :object_del_ivar

    # If it's already a symbol, then we're here because it doesn't exist.
    if sym.kind_of? Symbol
      raise NameError, "instance variable '#{sym}' not defined"
    end

    # Otherwise because sym isn't a symbol, coerce it and try again.
    remove_instance_variable Rubinius::Type.ivar_validate(sym)
  end

  def require(name)
    Rubinius::CodeLoader.new(name).require
  end
  module_function :require

  def require_relative(name)
    scope = Rubinius::LexicalScope.of_sender
    Rubinius::CodeLoader.new(name).require_relative(scope)
  end
  module_function :require_relative

  def select(*args)
    IO.select(*args)
  end
  module_function :select

  def send(message, *args)
    Rubinius.primitive :object_send
    raise PrimitiveFailure, "Kernel#send primitive failed"
  end

  def set_trace_func(*args)
    raise NotImplementedError
  end
  module_function :set_trace_func

  def sprintf(str, *args)
    Rubinius::Sprinter.get(str).call(*args)
  end
  module_function :sprintf

  alias_method :format, :sprintf
  module_function :format

  def sleep(duration=undefined)
    unless undefined.equal? duration
      if duration.kind_of? Numeric
        duration = Rubinius::Type.coerce_to duration, Float, :to_f
      else
        raise TypeError, 'time interval must be a numeric value'
      end
    end

    Rubinius.invoke_primitive :thread_suspend, Thread.current, duration
  end
  module_function :sleep

  def srand(seed=undefined)
    if undefined.equal? seed
      seed = Thread.current.randomizer.generate_seed
    end

    seed = Rubinius::Type.coerce_to seed, Integer, :to_int
    Thread.current.randomizer.swap_seed seed
  end
  module_function :srand

  def tap
    yield self
    self
  end

  def test(cmd, file1, file2=nil)
    case cmd
    when ?d
      File.directory? file1
    when ?e
      File.exist? file1
    when ?f
      File.file? file1
    when ?l
      File.symlink? file1
    when ?r
      File.readable? file1
    when ?R
      File.readable_real? file1
    when ?w
      File.writable? file1
    when ?W
      File.writable_real? file1
    when ?A
      File.atime file1
    when ?C
      File.ctime file1
    when ?M
      File.mtime file1
    else
      raise NotImplementedError, "command ?#{cmd.chr} not implemented"
    end
  end
  module_function :test

  def to_enum(method=:each, *args, &block)
    Enumerator.new(self, method, *args).tap do |enum|
      Rubinius.privately { enum.size = block } if block_given?
    end
  end
  alias_method :enum_for, :to_enum

  def trap(sig, prc=nil, &block)
    Signal.trap(sig, prc, &block)
  end
  module_function :trap

  def singleton_method_added(name)
  end
  private :singleton_method_added

  def singleton_method_removed(name)
  end
  private :singleton_method_removed

  def singleton_method_undefined(name)
  end
  private :singleton_method_undefined

  def singleton_methods(all=true)
    m = Rubinius::Type.object_singleton_class self
    mt = m.method_table
    methods = mt.public_names + mt.protected_names

    if all
      while m = m.direct_superclass
        unless Rubinius::Type.object_kind_of?(m, Rubinius::IncludedModule) or
               Rubinius::Type.singleton_class_object(m)
          break
        end

        mt = m.method_table
        methods.concat mt.public_names
        methods.concat mt.protected_names
      end
    end

    methods.uniq
  end

  def spawn(*args)
    Process.spawn(*args)
  end
  module_function :spawn

  def syscall(*args)
    raise NotImplementedError
  end
  module_function :syscall

  def system(*args)
    begin
      pid = Process.spawn(*args)
    rescue SystemCallError
      return nil
    end

    Process.waitpid pid
    $?.exitstatus == 0
  end
  module_function :system

  def trace_var(name, cmd = nil, &block)
    if !cmd && !block
      raise(
        ArgumentError,
        'The 2nd argument should be a Proc/String, alternatively use a block'
      )
    end

    # We have to use a custom proc since set_hook passes in both the variable
    # name and value.
    set = proc do |_, value|
      if cmd.is_a?(String)
        eval(cmd)

      # In MRI if one passes both a proc in `cmd` and a block the latter will
      # be ignored.
      elsif cmd.is_a?(Proc)
        cmd.call(value)

      elsif block
        block.call(value)
      end
    end

    Rubinius::Globals.set_hook(name, :[], set)
  end
  module_function :trace_var

  # In MRI one can specify a 2nd argument to remove a specific tracer.
  # Rubinius::Globals however only supports one hook per variable, hence the
  # 2nd dummy argument.
  def untrace_var(name, *args)
    Rubinius::Globals.remove_hook(name)
  end
  module_function :untrace_var

  def warn(*messages)
    $stderr.puts(*messages) if !$VERBOSE.nil? && !messages.empty?
    nil
  end
  module_function :warn

  def warning(message)
    $stderr.puts message if $VERBOSE
  end
  module_function :warning

  def catch(obj = Object.new, &block)
    raise LocalJumpError unless block_given?

    Rubinius::ThrownValue.register(obj) do
      return Rubinius.catch(obj, block)
    end
  end
  module_function :catch

  def throw(obj, value=nil)
    unless Rubinius::ThrownValue.available? obj
      exc = UncaughtThrowError.new "uncaught throw #{obj.inspect}"
      exc.tag = obj
      raise exc
    end

    Rubinius.throw obj, value
  end
  module_function :throw

  # Names of local variables at point of call (including evaled)
  #
  def local_variables
    scope = Rubinius::VariableScope.of_sender
    scope.local_variables
  end
  module_function :local_variables

  # Obtain binding here for future evaluation/execution context.
  #
  def binding
    return Binding.setup(
      Rubinius::VariableScope.of_sender,
      Rubinius::CompiledCode.of_sender,
      Rubinius::LexicalScope.of_sender,
      Rubinius::VariableScope.of_sender.self,
      Rubinius::Location.of_closest_ruby_method
    )
  end
  module_function :binding

  # Evaluate and execute code given in the String.
  #
  def eval(string, binding=nil, filename=nil, lineno=nil)
    string = StringValue(string)
    filename = StringValue(filename) if filename
    lineno = Rubinius::Type.coerce_to lineno, Fixnum, :to_i if lineno
    lineno = 1 if filename && !lineno

    if binding
      binding = Rubinius::Type.coerce_to_binding binding
      filename ||= binding.lexical_scope.active_path
    else
      binding = Binding.setup(Rubinius::VariableScope.of_sender,
                              Rubinius::CompiledCode.of_sender,
                              Rubinius::LexicalScope.of_sender,
                              self)

      filename ||= "(eval)"
    end

    lineno ||= binding.line_number

    existing_scope = binding.lexical_scope
    binding.lexical_scope = existing_scope.dup

    c = Rubinius::ToolSets::Runtime::Compiler
    be = c.construct_block string, binding, filename, lineno

    result = be.call_on_instance(binding.receiver)
    binding.lexical_scope = existing_scope
    result
  end
  module_function :eval
  private :eval
end