Created
October 12, 2010 16:14
-
-
Save radiospiel/622451 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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