Skip to content

Instantly share code, notes, and snippets.

@radiospiel
Created October 12, 2010 16:14
Show Gist options
  • Save radiospiel/622451 to your computer and use it in GitHub Desktop.
Save radiospiel/622451 to your computer and use it in GitHub Desktop.
require "rubygems"
require "ruby2ruby"
require 'parse_tree' # gem ParseTree
#require 'ruby2ruby'
#require 'sexp_processor'
#require 'unified_ruby'
def Continuation.create(*args, &block)
cc = nil
result = callcc { |c|
cc = c
block.call(cc) if block and args.empty?
}
result ||= args
return *[cc, *result]
end
def Binding.of_caller(&block)
old_critical = Thread.critical
Thread.critical = true
count = 0
cc, result, error = Continuation.create(nil, nil)
error.call if error
tracer = lambda do |*args|
type, context = args[0], args[4]
if type == "return"
count += 1
# First this method and then calling one will return --
# the trace event of the second event gets the context
# of the method which called the method that called this
# method.
if count == 2
# It would be nice if we could restore the trace_func
# that was set before we swapped in our own one, but
# this is impossible without overloading set_trace_func
# in current Ruby.
set_trace_func(nil)
cc.call(eval("binding", context), nil)
end
elsif type != "line"
set_trace_func(nil)
error_msg = "Binding.of_caller used in non-method context or " +
"trailing statements of method using it aren't in the block."
cc.call(nil, lambda { raise(Exception, error_msg ) })
end
end
unless result
set_trace_func(tracer)
return nil
else
Thread.critical = old_critical
yield result
end
end
# The Beef
class Module
def to_ruby(*args)
Ruby2Ruby.translate(self, *args)
end
end
class Proc
def collect_lvars(sexp, lvars = [], lasgns = [])
sexp.each do |s|
next unless s.is_a?(Array)
case s.first
when :lvar
lvars.push s[1]
when :lasgn
lasgns.push s[1]
else
collect_lvars s, lvars, lasgns
end
end
lvars.uniq - lasgns
end
def _collect_lvars(sexp, &block)
end
def to_ruby
proc = self
Binding.of_caller do |b|
c = Class.new
c.class_eval do
define_method :serializable, proc
end
sexp = ParseTree.translate(c, :serializable)
lvars = collect_lvars(sexp)
scope = eval("local_variables", b).inject("") do |code, variable|
next code unless lvars.include?(variable.to_sym)
code += "#{variable}=#{eval(variable, b).to_ruby}\n"
end
unifier = Unifier.new
unifier.processors.each do |p|
p.unsupported.delete :cfunc # HACK
end
sexp = unifier.process(sexp)
s = Ruby2Ruby.new.process(sexp)
lambda = if proc.arity == 0
s.sub(/def serializable\n */, "lambda { ||\n" + scope)
elsif proc.arity < 0
s.sub(/def serializable\n */, "lambda {\n" + scope)
else
s.sub(/^def serializable\(([^\)]*)\)\n */, "lambda { |\\1|\n" + scope)
end
lambda.sub(/\nend$/, "\n}")
end
end
end
class Object
def to_ruby
inspect
end
end
def ex1
x = "1"
a = 2
lambda { |x| x * 3 }
end
def ex2
a = 2
lambda { |x|
x + a * 3
12
}
end
def ex3
x = "1"
a = 2
lambda { x + a * 3 }
end
def ex4
lambda { || x + a * 3 }
end
puts ex1.to_ruby
puts ex2.to_ruby
puts ex3.to_ruby
puts ex4.to_ruby
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment