class ExecJS::MiniRacerRuntime::Context

def call(identifier, *args)

def call(identifier, *args)
  # TODO optimise generate
  eval "#{identifier}.apply(this, #{::JSON.generate(args)})"
end

def eval(source, options = {})

def eval(source, options = {})
  source = source.encode(Encoding::UTF_8)
  if /\S/ =~ source
    translate do
      @context.eval("(#{source})")
    end
  end
end

def exec(source, options = {})

def exec(source, options = {})
  source = source.encode(Encoding::UTF_8)
  if /\S/ =~ source
    eval "(function(){#{source}})()"
  end
end

def initialize(runtime, source = "", options={})

def initialize(runtime, source = "", options={})
  source = source.encode(Encoding::UTF_8)
  @context = ::MiniRacer::Context.new
  @context.eval("delete this.console");
  translate do
    @context.eval(source)
  end
end

def strip_functions!(value)

def strip_functions!(value)
  if Array === value
    value.map! do |v|
      if MiniRacer::JavaScriptFunction === value
        nil
      else
        strip_functions!(v)
      end
    end
  elsif Hash === value
    value.each do |k,v|
      if MiniRacer::JavaScriptFunction === v
        value.delete k
      else
        value[k] = strip_functions!(v)
      end
    end
    value
  elsif MiniRacer::JavaScriptFunction === value
    nil
  else
    value
  end
end

def translate

def translate
  begin
    strip_functions! yield
  rescue MiniRacer::RuntimeError => e
    ex = ProgramError.new e.message
    if backtrace = e.backtrace
      backtrace = backtrace.map { |line|
        if line =~ /JavaScript at/
          line.sub("JavaScript at ", "")
              .sub("<anonymous>", "(execjs)")
              .strip
        else
          line
        end
      }
      ex.set_backtrace backtrace
    end
    raise ex
  rescue MiniRacer::ParseError => e
    ex = RuntimeError.new e.message
    ex.set_backtrace(["(execjs):1"] + e.backtrace)
    raise ex
  end
end