lib/ruby2ruby.rb in ruby2ruby-2.3.2 vs lib/ruby2ruby.rb in ruby2ruby-2.4.0
- old
+ new
@@ -29,11 +29,11 @@
##
# Generate ruby code from a sexp.
class Ruby2Ruby < SexpProcessor
- VERSION = "2.3.2" # :nodoc:
+ VERSION = "2.4.0" # :nodoc:
# cutoff for one-liners
LINE_LENGTH = 78
# binary operation messages
@@ -80,11 +80,11 @@
]
def initialize # :nodoc:
super
@indent = " "
- self.auto_shift_type = true
+ self.require_empty = false
self.strict = true
self.expected = String
@calls = []
@@ -92,167 +92,173 @@
end
############################################################
# Processors
- def process_alias(exp) # :nodoc:
- parenthesize "alias #{process(exp.shift)} #{process(exp.shift)}"
+ def process_alias exp # :nodoc:
+ _, lhs, rhs = exp
+
+ parenthesize "alias #{process lhs} #{process rhs}"
end
- def process_and(exp) # :nodoc:
- parenthesize "#{process exp.shift} and #{process exp.shift}"
+ def process_and exp # :nodoc:
+ _, lhs, rhs = exp
+
+ parenthesize "#{process lhs} and #{process rhs}"
end
- def process_arglist(exp) # custom made node # :nodoc:
- code = []
- until exp.empty? do
- arg = exp.shift
- to_wrap = arg.first == :rescue
- arg_code = process arg
- code << (to_wrap ? "(#{arg_code})" : arg_code)
- end
- code.join ', '
+ def process_arglist exp # custom made node # :nodoc:
+ _, *args = exp
+
+ args.map { |arg|
+ code = process arg
+ arg.sexp_type == :rescue ? "(#{code})" : code
+ }.join ", "
end
- def process_args(exp) # :nodoc:
- args = []
+ def process_args exp # :nodoc:
+ _, *args = exp
- until exp.empty? do
- arg = exp.shift
+ args = args.map { |arg|
case arg
when Symbol then
- args << arg
+ arg
when Sexp then
- case arg.first
+ case arg.sexp_type
when :lasgn then
- args << process(arg)
+ process(arg)
when :masgn then
- args << process(arg)
+ process(arg)
when :kwarg then
_, k, v = arg
- args << "#{k}: #{process v}"
+ "#{k}: #{process v}"
else
raise "unknown arg type #{arg.first.inspect}"
end
else
raise "unknown arg type #{arg.inspect}"
end
- end
+ }
"(#{args.join ', '})"
end
- def process_array(exp) # :nodoc:
- "[#{process_arglist(exp)}]"
+ def process_array exp # :nodoc:
+ "[#{process_arglist exp}]"
end
- def process_attrasgn(exp) # :nodoc:
- receiver = process exp.shift
- name = exp.shift
- rhs = exp.pop
- args = s(:array, *exp)
- exp.clear
+ def process_attrasgn exp # :nodoc:
+ _, recv, name, *args = exp
+ rhs = args.pop
+ args = s(:array, *args)
+ receiver = process recv
+
case name
when :[]= then
args = process args
"#{receiver}#{args} = #{process rhs}"
else
- raise "dunno what to do: #{args.inspect}" unless args.size == 1 # s(:array)
- name = name.to_s.sub(/=$/, '')
+ raise "dunno what to do: #{args.inspect}" if args.size != 1 # s(:array)
+ name = name.to_s.chomp "="
if rhs && rhs != s(:arglist) then
"#{receiver}.#{name} = #{process(rhs)}"
else
raise "dunno what to do: #{rhs.inspect}"
end
end
end
- def process_back_ref(exp) # :nodoc:
- "$#{exp.shift}"
+ def process_back_ref exp # :nodoc:
+ _, n = exp
+
+ "$#{n}"
end
# TODO: figure out how to do rescue and ensure ENTIRELY w/o begin
- def process_begin(exp) # :nodoc:
- code = []
- code << "begin"
- until exp.empty?
- src = process(exp.shift)
- src = indent(src) unless src =~ /(^|\n)(rescue|ensure)/ # ensure no level 0 rescues
- code << src
- end
- code << "end"
- return code.join("\n")
+ def process_begin exp # :nodoc:
+ _, *rest = exp
+
+ code = rest.map { |sexp|
+ src = process sexp
+ src = indent src unless src =~ /(^|\n)(rescue|ensure)/ # ensure no level 0 rescues
+ src
+ }
+ code.unshift "begin"
+ code.push "end"
+
+ code.join "\n"
end
- def process_block(exp) # :nodoc:
- result = []
+ def process_block exp # :nodoc:
+ _, *body = exp
- exp << nil if exp.empty?
- until exp.empty? do
- code = exp.shift
- if code.nil? or code.first == :nil then
- result << "# do nothing\n"
- else
- result << process(code)
- end
- end
+ result = body.map { |sexp|
+ process sexp
+ }
+ result << "# do nothing\n" if result.empty?
result = parenthesize result.join "\n"
result += "\n" unless result.start_with? "("
- return result
+ result
end
def process_block_pass exp # :nodoc:
- raise "huh?: #{exp.inspect}" if exp.size > 1
+ raise "huh?: #{exp.inspect}" if exp.size > 2
- "&#{process exp.shift}"
+ _, sexp = exp
+
+ "&#{process sexp}"
end
- def process_break(exp) # :nodoc:
- val = exp.empty? ? nil : process(exp.shift)
- # HACK "break" + (val ? " #{val}" : "")
+ def process_break exp # :nodoc:
+ _, arg = exp
+
+ val = process arg
+
if val then
"break #{val}"
else
"break"
end
end
def process_call(exp, safe_call = false) # :nodoc:
- receiver_node_type = exp.first.nil? ? nil : exp.first.first
- receiver = process exp.shift
+ _, recv, name, *args = exp
+
+ receiver_node_type = recv && recv.sexp_type
+ receiver = process recv
receiver = "(#{receiver})" if ASSIGN_NODES.include? receiver_node_type
- name = exp.shift
- args = []
+ # args = []
# this allows us to do both old and new sexp forms:
- exp.push(*exp.pop[1..-1]) if exp.size == 1 && exp.first.first == :arglist
+ # exp.push(*exp.pop[1..-1]) if exp.size == 1 && exp.first.first == :arglist
@calls.push name
in_context :arglist do
- until exp.empty? do
- arg_type = exp.first.sexp_type
- is_empty_hash = (exp.first == s(:hash))
- arg = process exp.shift
+ max = args.size-1
+ args = args.map.with_index { |arg, i|
+ arg_type = arg.sexp_type
+ is_empty_hash = arg == s(:hash)
+ arg = process arg
next if arg.empty?
strip_hash = (arg_type == :hash and
not BINARY.include? name and
not is_empty_hash and
- (exp.empty? or exp.first.sexp_type == :splat))
+ (i == max or args[i+1].sexp_type == :splat))
wrap_arg = Ruby2Ruby::ASSIGN_NODES.include? arg_type
arg = arg[2..-3] if strip_hash
arg = "(#{arg})" if wrap_arg
- args << arg
- end
+ arg
+ }.compact
end
case name
when *BINARY then
if safe_call
@@ -285,131 +291,125 @@
end
ensure
@calls.pop
end
- def process_safe_call(exp) # :nodoc:
- process_call(exp, :safe)
+ def process_safe_call exp # :nodoc:
+ process_call exp, :safe
end
- def process_case(exp) # :nodoc:
+ def process_case exp # :nodoc:
+ _, expr, *rest = exp
+
result = []
- expr = process exp.shift
+
+ expr = process expr
+
if expr then
result << "case #{expr}"
else
result << "case"
end
- until exp.empty?
- pt = exp.shift
- if pt and pt.first == :when
- result << "#{process(pt)}"
+
+ result.concat rest.map { |pt|
+ if pt and pt.sexp_type == :when
+ "#{process pt}"
else
- code = indent(process(pt))
+ code = indent process pt
code = indent("# do nothing") if code =~ /^\s*$/
- result << "else\n#{code}"
+ "else\n#{code}"
end
- end
+ }
+
result << "end"
- result.join("\n")
+
+ result.join "\n"
end
- def process_cdecl(exp) # :nodoc:
- lhs = exp.shift
+ def process_cdecl exp # :nodoc:
+ _, lhs, rhs = exp
lhs = process lhs if Sexp === lhs
- unless exp.empty? then
- rhs = process(exp.shift)
+ if rhs then
+ rhs = process rhs
"#{lhs} = #{rhs}"
else
lhs.to_s
end
end
- def process_class(exp) # :nodoc:
+ def process_class exp # :nodoc:
"#{exp.comments}class #{util_module_or_class(exp, true)}"
end
- def process_colon2(exp) # :nodoc:
- "#{process(exp.shift)}::#{exp.shift}"
- end
+ def process_colon2 exp # :nodoc:
+ _, lhs, rhs = exp
- def process_colon3(exp) # :nodoc:
- "::#{exp.shift}"
+ "#{process lhs}::#{rhs}"
end
- def process_const(exp) # :nodoc:
- exp.shift.to_s
- end
+ def process_colon3 exp # :nodoc:
+ _, rhs = exp
- def process_cvar(exp) # :nodoc:
- "#{exp.shift}"
+ "::#{rhs}"
end
- def process_cvasgn(exp) # :nodoc:
- "#{exp.shift} = #{process(exp.shift)}"
- end
+ def process_const exp # :nodoc:
+ _, name = exp
- def process_cvdecl(exp) # :nodoc:
- "#{exp.shift} = #{process(exp.shift)}"
+ name.to_s
end
- def process_defined(exp) # :nodoc:
- "defined? #{process(exp.shift)}"
+ def process_cvar exp # :nodoc:
+ _, name = exp
+
+ name.to_s
end
- def process_defn(exp) # :nodoc:
- type1 = exp[1].first
- type2 = exp[2].first rescue nil
- expect = [:ivar, :iasgn, :attrset]
+ def process_cvasgn exp # :nodoc:
+ _, lhs, rhs = exp
- # s(name, args, ivar|iasgn|attrset)
- if exp.size == 3 and type1 == :args and expect.include? type2 then
- name = exp.first # don't shift in case we pass through
- case type2
- when :ivar then
- ivar_name = exp.ivar.last
+ "#{lhs} = #{process rhs}"
+ end
- meth_name = ivar_name.to_s[1..-1].to_sym
- expected = s(meth_name, s(:args), s(:ivar, ivar_name))
+ def process_cvdecl exp # :nodoc:
+ _, lhs, rhs = exp
- if exp == expected then
- exp.clear
- return "attr_reader #{name.inspect}"
- end
- when :attrset then
- # TODO: deprecate? this is a PT relic
- exp.clear
- return "attr_writer :#{name.to_s[0..-2]}"
- when :iasgn then
- ivar_name = exp.iasgn[1]
- meth_name = "#{ivar_name.to_s[1..-1]}=".to_sym
- arg_name = exp.args.last
- expected = s(meth_name, s(:args, arg_name),
- s(:iasgn, ivar_name, s(:lvar, arg_name)))
+ "#{lhs} = #{process rhs}"
+ end
- if exp == expected then
- exp.clear
- return "attr_writer :#{name.to_s[0..-2]}"
- end
- else
- raise "Unknown defn type: #{exp.inspect}"
- end
- end
+ def process_defined exp # :nodoc:
+ _, rhs = exp
+ "defined? #{process rhs}"
+ end
+ def process_defn(exp) # :nodoc:
+ _, name, args, *body = exp
+
comm = exp.comments
- name = exp.shift
- args = process exp.shift
+ args = process args
args = "" if args == "()"
- exp.shift if exp == s(s(:nil)) # empty it out of a default nil expression
+ body = s() if body == s(s(:nil)) # empty it out of a default nil expression
- # REFACTOR: use process_block but get it happier wrt parenthesize
- body = []
- until exp.empty? do
- body << process(exp.shift)
+ # s(:defn, name, args, ivar|iasgn)
+ case exp
+ when s{ s(:defn, atom, t(:args), s(:ivar, atom)) } then # TODO: atom -> _
+ _, ivar = body.first
+ ivar = ivar.to_s[1..-1] # remove leading @
+ reader = name.to_s
+ return "attr_reader #{name.inspect}" if reader == ivar
+ when s{ s(:defn, atom, t(:args), s(:iasgn, atom, s(:lvar, atom))) } then
+ _, ivar, _val = body.first
+ ivar = ivar.to_s[1..-1] # remove leading @
+ reader = name.to_s.chomp "="
+ return "attr_writer :#{reader}" if reader == ivar
end
+ body = body.map { |ssexp|
+ process ssexp
+ }
+
simple = body.size <= 1
body << "# do nothing" if body.empty?
body = body.join("\n")
body = body.lines.to_a[1..-2].join("\n") if
@@ -417,33 +417,40 @@
body = indent(body) unless simple && body =~ /(^|\n)rescue/
return "#{comm}def #{name}#{args}\n#{body}\nend".gsub(/\n\s*\n+/, "\n")
end
- def process_defs(exp) # :nodoc:
- lhs = exp.shift
- var = [:self, :cvar, :dvar, :ivar, :gvar, :lvar].include? lhs.first
- name = exp.shift
+ def process_defs exp # :nodoc:
+ _, lhs, name, args, *body = exp
+ var = [:self, :cvar, :dvar, :ivar, :gvar, :lvar].include? lhs.sexp_type
- lhs = process(lhs)
+ lhs = process lhs
lhs = "(#{lhs})" unless var
- exp.unshift "#{lhs}.#{name}"
- process_defn(exp)
+ name = "#{lhs}.#{name}"
+
+ process_defn s(:defn, name, args, *body)
end
def process_dot2(exp) # :nodoc:
- "(#{process exp.shift}..#{process exp.shift})"
+ _, lhs, rhs = exp
+
+ "(#{process lhs}..#{process rhs})"
end
def process_dot3(exp) # :nodoc:
- "(#{process exp.shift}...#{process exp.shift})"
+ _, lhs, rhs = exp
+
+ "(#{process lhs}...#{process rhs})"
end
- def process_dregx(exp) # :nodoc:
- options = re_opt exp.pop if Fixnum === exp.last
- "/" << util_dthing(:dregx, exp) << "/#{options}"
+ def process_dregx exp # :nodoc:
+ _, str, *rest = exp
+
+ options = re_opt rest.pop if Integer === rest.last
+
+ "/" << util_dthing(:dregx, s(:dregx, str, *rest)) << "/#{options}"
end
def process_dregx_once(exp) # :nodoc:
process_dregx(exp) + "o"
end
@@ -459,97 +466,109 @@
def process_dxstr(exp) # :nodoc:
"`#{util_dthing(:dxstr, exp)}`"
end
def process_ensure(exp) # :nodoc:
- body = process exp.shift
- ens = exp.shift
+ _, body, ens = exp
+
+ body = process body
ens = nil if ens == s(:nil)
ens = process(ens) || "# do nothing"
ens = "begin\n#{ens}\nend\n" if ens =~ /(^|\n)rescue/
body.sub!(/\n\s*end\z/, '')
body = indent(body) unless body =~ /(^|\n)rescue/
return "#{body}\nensure\n#{indent ens}"
end
- def process_evstr(exp) # :nodoc:
- exp.empty? ? '' : process(exp.shift)
+ def process_evstr exp # :nodoc:
+ _, x = exp
+
+ x ? process(x) : ""
end
- def process_false(exp) # :nodoc:
+ def process_false exp # :nodoc:
"false"
end
- def process_flip2(exp) # :nodoc:
- "#{process(exp.shift)}..#{process(exp.shift)}"
+ def process_flip2 exp # :nodoc:
+ _, lhs, rhs = exp
+
+ "#{process lhs}..#{process rhs}"
end
- def process_flip3(exp) # :nodoc:
- "#{process(exp.shift)}...#{process(exp.shift)}"
+ def process_flip3 exp # :nodoc:
+ _, lhs, rhs = exp
+
+ "#{process lhs}...#{process rhs}"
end
- def process_for(exp) # :nodoc:
- recv = process exp.shift
- iter = process exp.shift
- body = exp.empty? ? nil : process(exp.shift)
+ def process_for exp # :nodoc:
+ _, recv, iter, body = exp
+ recv = process recv
+ iter = process iter
+ body = process(body) || "# do nothing"
+
result = ["for #{iter} in #{recv} do"]
- result << indent(body ? body : "# do nothing")
+ result << indent(body)
result << "end"
- result.join("\n")
+ result.join "\n"
end
- def process_gasgn(exp) # :nodoc:
- process_iasgn(exp)
+ def process_gasgn exp # :nodoc:
+ process_iasgn exp
end
- def process_gvar(exp) # :nodoc:
- return exp.shift.to_s
+ def process_gvar exp # :nodoc:
+ _, name = exp
+
+ name.to_s
end
def process_hash(exp) # :nodoc:
+ _, *pairs = exp
+
result = []
- until exp.empty?
- s = exp.shift
- t = s.sexp_type
- lhs = process s
-
- case t
- when :kwsplat then
- result << lhs
+ result = pairs.each_slice(2).map { |k, v|
+ if k.sexp_type == :kwsplat then
+ "%s" % process(k)
else
- rhs = exp.shift
- t = rhs.first
- rhs = process rhs
+ t = v.sexp_type
+
+ lhs = process k
+ rhs = process v
rhs = "(#{rhs})" unless HASH_VAL_NO_PAREN.include? t
- result << "#{lhs} => #{rhs}"
+ "%s => %s" % [lhs, rhs]
end
- end
+ }
return result.empty? ? "{}" : "{ #{result.join(', ')} }"
end
def process_iasgn(exp) # :nodoc:
- lhs = exp.shift
- if exp.empty? then # part of an masgn
+ _, lhs, rhs = exp
+
+ if rhs then
+ "#{lhs} = #{process rhs}"
+ else # part of an masgn
lhs.to_s
- else
- "#{lhs} = #{process exp.shift}"
end
end
def process_if(exp) # :nodoc:
- expand = Ruby2Ruby::ASSIGN_NODES.include? exp.first.first
- c = process exp.shift
- t = process exp.shift
- f = process exp.shift
+ _, c, t, f = exp
+ expand = Ruby2Ruby::ASSIGN_NODES.include? c.sexp_type
+ c = process c
+ t = process t
+ f = process f
+
c = "(#{c.chomp})" if c =~ /\n/
if t then
unless expand then
if f then
@@ -577,14 +596,15 @@
"if #{c} then\n#{indent '# do nothing'}\nend"
end
end
def process_iter(exp) # :nodoc:
- iter = process exp.shift
- args = exp.shift
- body = exp.empty? ? nil : process(exp.shift)
+ _, iter, args, body = exp
+ iter = process iter
+ body = process body if body
+
args = case args
when 0 then
""
else
" |#{process(args)[1..-2]}|"
@@ -622,63 +642,69 @@
result << e
result.join
end
def process_ivar(exp) # :nodoc:
- exp.shift.to_s
+ _, name = exp
+ name.to_s
end
def process_kwsplat(exp)
- "**#{process exp.shift}"
+ _, kw = exp
+ "**#{process kw}"
end
def process_lasgn(exp) # :nodoc:
- s = "#{exp.shift}"
- s += " = #{process exp.shift}" unless exp.empty?
+ _, name, value = exp
+
+ s = "#{name}"
+ s += " = #{process value}" if value
s
end
- def process_lit(exp) # :nodoc:
- obj = exp.shift
+ def process_lit exp # :nodoc:
+ _, obj = exp
case obj
when Range then
"(#{obj.inspect})"
else
obj.inspect
end
end
def process_lvar(exp) # :nodoc:
- exp.shift.to_s
+ _, name = exp
+ name.to_s
end
def process_masgn(exp) # :nodoc:
# s(:masgn, s(:array, s(:lasgn, :var), ...), s(:to_ary, <val>, ...))
# s(:iter, <call>, s(:args, s(:masgn, :a, :b)), <body>)
+ _, *exp = exp # HACK
+
case exp.first
when Sexp then
- lhs = exp.shift
- rhs = exp.empty? ? nil : exp.shift
+ lhs, rhs = exp
- case lhs.first
+ case lhs.sexp_type
when :array then
- lhs.shift # node type
+ _, *lhs = lhs # HACK
lhs = lhs.map do |l|
- case l.first
+ case l.sexp_type
when :masgn then
"(#{process(l)})"
else
process(l)
end
end
else
raise "no clue: #{lhs.inspect}"
end
- unless rhs.nil? then
- t = rhs.first
+ if rhs then
+ t = rhs.sexp_type
rhs = process rhs
rhs = rhs[1..-2] if t == :array # FIX: bad? I dunno
return "#{lhs.join(", ")} = #{rhs}"
else
return lhs.join(", ")
@@ -690,25 +716,33 @@
else
raise "unknown masgn: #{exp.inspect}"
end
end
- def process_match(exp) # :nodoc:
- "#{process(exp.shift)}"
+ def process_match exp # :nodoc:
+ _, rhs = exp
+
+ "#{process rhs}"
end
- def process_match2(exp) # :nodoc:
- lhs = process(exp.shift)
- rhs = process(exp.shift)
+ def process_match2 exp # :nodoc:
+ # s(:match2, s(:lit, /x/), s(:str, "blah"))
+ _, lhs, rhs = exp
+
+ lhs = process lhs
+ rhs = process rhs
+
"#{lhs} =~ #{rhs}"
end
- def process_match3(exp) # :nodoc:
- rhs = process(exp.shift)
- left_type = exp.first.sexp_type
- lhs = process(exp.shift)
+ def process_match3 exp # :nodoc:
+ _, rhs, lhs = exp # yes, backwards
+ left_type = lhs.sexp_type
+ lhs = process lhs
+ rhs = process rhs
+
if ASSIGN_NODES.include? left_type then
"(#{lhs}) =~ #{rhs}"
else
"#{lhs} =~ #{rhs}"
end
@@ -717,11 +751,13 @@
def process_module(exp) # :nodoc:
"#{exp.comments}module #{util_module_or_class(exp)}"
end
def process_next(exp) # :nodoc:
- val = exp.empty? ? nil : process(exp.shift)
+ _, rhs = exp
+
+ val = rhs && process(rhs) # maybe push down into if and test rhs?
if val then
"next #{val}"
else
"next"
end
@@ -730,64 +766,69 @@
def process_nil(exp) # :nodoc:
"nil"
end
def process_not(exp) # :nodoc:
- "(not #{process exp.shift})"
+ _, sexp = exp
+ "(not #{process sexp})"
end
def process_nth_ref(exp) # :nodoc:
- "$#{exp.shift}"
+ _, n = exp
+ "$#{n}"
end
- def process_op_asgn(exp) # :nodoc:
+ def process_op_asgn exp # :nodoc:
# [[:lvar, :x], [:call, nil, :z, [:lit, 1]], :y, :"||"]
- lhs = process(exp.shift)
- rhs = process(exp.shift)
- index = exp.shift
- op = exp.shift
+ _, lhs, rhs, index, op = exp
+ lhs = process lhs
+ rhs = process rhs
+
"#{lhs}.#{index} #{op}= #{rhs}"
end
def process_op_asgn1(exp) # :nodoc:
# [[:lvar, :b], [:arglist, [:lit, 1]], :"||", [:lit, 10]]
- lhs = process(exp.shift)
- index = process(exp.shift)
- msg = exp.shift
- rhs = process(exp.shift)
+ _, lhs, index, msg, rhs = exp
+ lhs = process lhs
+ index = process index
+ rhs = process rhs
+
"#{lhs}[#{index}] #{msg}= #{rhs}"
end
- def process_op_asgn2(exp) # :nodoc:
+ def process_op_asgn2 exp # :nodoc:
# [[:lvar, :c], :var=, :"||", [:lit, 20]]
- lhs = process(exp.shift)
- index = exp.shift.to_s[0..-2]
- msg = exp.shift
+ _, lhs, index, msg, rhs = exp
- rhs = process(exp.shift)
+ lhs = process lhs
+ index = index.to_s[0..-2]
+ rhs = process rhs
"#{lhs}.#{index} #{msg}= #{rhs}"
end
def process_op_asgn_and(exp) # :nodoc:
# a &&= 1
# [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
- exp.shift
- process(exp.shift).sub(/\=/, '&&=')
+ _, _lhs, rhs = exp
+ process(rhs).sub(/\=/, '&&=')
end
def process_op_asgn_or(exp) # :nodoc:
# a ||= 1
# [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
- exp.shift
- process(exp.shift).sub(/\=/, '||=')
+ _, _lhs, rhs = exp
+ process(rhs).sub(/\=/, '||=')
end
def process_or(exp) # :nodoc:
- "(#{process exp.shift} or #{process exp.shift})"
+ _, lhs, rhs = exp
+
+ "(#{process lhs} or #{process rhs})"
end
def process_postexe(exp) # :nodoc:
"END"
end
@@ -795,12 +836,17 @@
def process_redo(exp) # :nodoc:
"redo"
end
def process_resbody exp # :nodoc:
- args = exp.shift
- body = finish(exp)
+ # s(:resbody, s(:array), s(:return, s(:str, "a")))
+ _, args, *body = exp
+
+ body = body.compact.map { |sexp|
+ process sexp
+ }
+
body << "# do nothing" if body.empty?
name = args.lasgn true
name ||= args.iasgn true
args = process(args)[1..-2]
@@ -809,26 +855,30 @@
"rescue#{args}\n#{indent body.join("\n")}"
end
def process_rescue exp # :nodoc:
- body = process(exp.shift) unless exp.first.first == :resbody
- els = process(exp.pop) unless exp.last.first == :resbody
+ _, *rest = exp
+ exp = nil
+ body = process rest.shift unless rest.first.sexp_type == :resbody
+ els = process rest.pop unless rest.last && rest.last.sexp_type == :resbody
+
body ||= "# do nothing"
- simple = exp.size == 1 && exp.resbody.size <= 3 &&
- !exp.resbody.block &&
- !exp.resbody.return
- resbodies = []
- until exp.empty? do
- resbody = exp.shift
- simple &&= resbody[1] == s(:array)
- simple &&= resbody[2] != nil && resbody[2].node_type != :block
- resbodies << process(resbody)
- end
+ # TODO: I don't like this using method_missing, but I need to ensure tests
+ simple = rest.size == 1 && rest.first.size <= 3 &&
+ !rest.first.block &&
+ !rest.first.return
+ resbodies = rest.map { |resbody|
+ _, rb_args, rb_body, *rb_rest = resbody
+ simple &&= rb_args == s(:array)
+ simple &&= rb_rest.empty? && rb_body && rb_body.node_type != :block
+ process resbody
+ }
+
if els then
"#{indent body}\n#{resbodies.join("\n")}\nelse\n#{indent els}"
elsif simple then
resbody = resbodies.first.sub(/\n\s*/, ' ')
"#{body} #{resbody}"
@@ -839,148 +889,168 @@
def process_retry(exp) # :nodoc:
"retry"
end
- def process_return(exp) # :nodoc:
- if exp.empty? then
+ def process_return exp # :nodoc:
+ _, rhs = exp
+
+ unless rhs then
"return"
else
- rhs = exp.shift
rhs_type = rhs.sexp_type
rhs = process rhs
rhs = "(#{rhs})" if ASSIGN_NODES.include? rhs_type
"return #{rhs}"
end
end
- def process_safe_attrasgn(exp) # :nodoc:
- receiver = process exp.shift
- name = exp.shift
- rhs = exp.pop
- args = exp.pop # should be nil
- exp.clear
+ def process_safe_attrasgn exp # :nodoc:
+ _, receiver, name, *rest = exp
+ receiver = process receiver
+ rhs = rest.pop
+ args = rest.pop # should be nil
+
raise "dunno what to do: #{args.inspect}" if args
name = name.to_s.sub(/=$/, '')
if rhs && rhs != s(:arglist) then
- "#{receiver}&.#{name} = #{process(rhs)}"
+ "#{receiver}&.#{name} = #{process rhs}"
else
raise "dunno what to do: #{rhs.inspect}"
end
end
- def process_safe_op_asgn(exp) # :nodoc:
+ def process_safe_op_asgn exp # :nodoc:
# [[:lvar, :x], [:call, nil, :z, [:lit, 1]], :y, :"||"]
- lhs = process(exp.shift)
- rhs = process(exp.shift)
- index = exp.shift
- op = exp.shift
+ _, lhs, rhs, index, op = exp
+ lhs = process lhs
+ rhs = process rhs
+
"#{lhs}&.#{index} #{op}= #{rhs}"
end
def process_safe_op_asgn2(exp) # :nodoc:
# [[:lvar, :c], :var=, :"||", [:lit, 20]]
- lhs = process(exp.shift)
- index = exp.shift.to_s[0..-2]
- msg = exp.shift
- rhs = process(exp.shift)
+ _, lhs, index, msg, rhs = exp
+ lhs = process lhs
+ index = index.to_s[0..-2]
+ rhs = process rhs
+
"#{lhs}&.#{index} #{msg}= #{rhs}"
end
def process_sclass(exp) # :nodoc:
- "class << #{process(exp.shift)}\n#{indent(process_block(exp))}\nend"
+ _, recv, *block = exp
+
+ recv = process recv
+ block = indent process_block s(:block, *block)
+
+ "class << #{recv}\n#{block}\nend"
end
def process_self(exp) # :nodoc:
"self"
end
def process_splat(exp) # :nodoc:
- if exp.empty? then
+ _, arg = exp
+ if arg.nil? then
"*"
else
- "*#{process(exp.shift)}"
+ "*#{process arg}"
end
end
def process_str(exp) # :nodoc:
- return exp.shift.dump
+ _, s = exp
+ s.dump
end
def process_super(exp) # :nodoc:
- args = finish exp
+ _, *args = exp
- "super(#{args.join(', ')})"
+ args = args.map { |arg|
+ process arg
+ }
+
+ "super(#{args.join ", "})"
end
def process_svalue(exp) # :nodoc:
- code = []
- until exp.empty? do
- code << process(exp.shift)
- end
- code.join(", ")
+ _, *args = exp
+
+ args.map { |arg|
+ process arg
+ }.join ", "
end
- def process_to_ary(exp) # :nodoc:
- process(exp.shift)
+ def process_to_ary exp # :nodoc:
+ _, sexp = exp
+
+ process sexp
end
def process_true(exp) # :nodoc:
"true"
end
def process_undef(exp) # :nodoc:
- "undef #{process(exp.shift)}"
+ _, name = exp
+
+ "undef #{process name}"
end
def process_until(exp) # :nodoc:
cond_loop(exp, 'until')
end
- def process_valias(exp) # :nodoc:
- "alias #{exp.shift} #{exp.shift}"
+ def process_valias exp # :nodoc:
+ _, lhs, rhs = exp
+
+ "alias #{lhs} #{rhs}"
end
- def process_when(exp) # :nodoc:
- src = []
+ def process_when exp # :nodoc:
+ s(:when, s(:array, s(:lit, 1)),
+ s(:call, nil, :puts, s(:str, "something")),
+ s(:lasgn, :result, s(:str, "red")))
- if self.context[1] == :array then # ugh. matz! why not an argscat?!?
- val = process(exp.shift)
- exp.shift # empty body
- return "*#{val}"
- end
+ _, lhs, *rhs = exp
- until exp.empty?
- cond = process(exp.shift).to_s[1..-2]
- code = indent(finish(exp).join("\n"))
- code = indent "# do nothing" if code =~ /\A\s*\Z/
- src << "when #{cond} then\n#{code.chomp}"
- end
+ cond = process(lhs)[1..-2]
- src.join("\n")
+ rhs = rhs.compact.map { |sexp|
+ indent process sexp
+ }
+
+ rhs << indent("# do nothing") if rhs.empty?
+ rhs = rhs.join "\n"
+
+ "when #{cond} then\n#{rhs.chomp}"
end
def process_while(exp) # :nodoc:
- cond_loop(exp, 'while')
+ cond_loop exp, "while"
end
def process_xstr(exp) # :nodoc:
"`#{process_str(exp)[1..-2]}`"
end
def process_yield(exp) # :nodoc:
- args = []
- until exp.empty? do
- args << process(exp.shift)
- end
+ _, *args = exp
+ args = args.map { |arg|
+ process arg
+ }
+
unless args.empty? then
"yield(#{args.join(', ')})"
else
"yield"
end
@@ -993,12 +1063,13 @@
############################################################
# Rewriters:
def rewrite_attrasgn exp # :nodoc:
if context.first(2) == [:array, :masgn] then
- exp[0] = :call
- exp[2] = exp[2].to_s.sub(/=$/, '').to_sym
+ _, recv, msg, *args = exp
+
+ exp = s(:call, recv, msg.to_s.chomp("=").to_sym, *args)
end
exp
end
@@ -1006,36 +1077,38 @@
exp = s(:begin, exp) unless context.first == :begin
exp
end
def rewrite_resbody exp # :nodoc:
- raise "no exception list in #{exp.inspect}" unless exp.size > 2 && exp[1]
- raise exp[1].inspect if exp[1][0] != :array
+ _, args, *_rest = exp
+ raise "no exception list in #{exp.inspect}" unless exp.size > 2 && args
+ raise args.inspect if args.sexp_type != :array
# for now, do nothing, just check and freak if we see an errant structure
exp
end
def rewrite_rescue exp # :nodoc:
complex = false
complex ||= exp.size > 3
complex ||= exp.resbody.block
complex ||= exp.resbody.size > 3
- complex ||= exp.find_nodes(:resbody).any? { |n| n[1] != s(:array) }
- complex ||= exp.find_nodes(:resbody).any? { |n| n.last.nil? }
- complex ||= exp.find_nodes(:resbody).any? { |n| n[2] and n[2].node_type == :block }
+ resbodies = exp.find_nodes(:resbody)
+ complex ||= resbodies.any? { |n| n[1] != s(:array) }
+ complex ||= resbodies.any? { |n| n.last.nil? }
+ complex ||= resbodies.any? { |(_, _, body)| body and body.node_type == :block }
handled = context.first == :ensure
exp = s(:begin, exp) if complex unless handled
exp
end
def rewrite_svalue(exp) # :nodoc:
- case exp.last.first
+ case exp.last.sexp_type
when :array
- s(:svalue, *exp[1][1..-1])
+ s(:svalue, *exp[1].sexp_body)
when :splat
exp
else
raise "huh: #{exp.inspect}"
end
@@ -1046,14 +1119,15 @@
##
# Generate a post-or-pre conditional loop.
def cond_loop(exp, name)
- cond = process(exp.shift)
- body = process(exp.shift)
- head_controlled = exp.shift
+ _, cond, body, head_controlled = exp
+ cond = process cond
+ body = process body
+
body = indent(body).chomp if body
code = []
if head_controlled then
code << "#{name} #{cond} do"
@@ -1062,10 +1136,11 @@
else
code << "begin"
code << body if body
code << "end #{name} #{cond}"
end
+
code.join("\n")
end
##
# Utility method to escape something interpolated.
@@ -1083,25 +1158,13 @@
raise "unsupported type #{type.inspect}"
end
end
##
- # Process all the remaining stuff in +exp+ and return the results
- # sans-nils.
-
- def finish exp # REFACTOR: work this out of the rest of the processors
- body = []
- until exp.empty? do
- body << process(exp.shift)
- end
- body.compact
- end
-
- ##
# Indent all lines of +s+ to the current indent level.
- def indent(s)
+ def indent s
s.to_s.split(/\n/).map{|line| @indent + line}.join("\n")
end
##
# Wrap appropriate expressions in matching parens.
@@ -1133,63 +1196,63 @@
##
# Utility method to generate something interpolated.
def util_dthing(type, exp)
- s = []
+ _, str, *rest = exp
# first item in sexp is a string literal
- s << dthing_escape(type, exp.shift)
+ str = dthing_escape(type, str)
- until exp.empty?
- pt = exp.shift
+ rest = rest.map { |pt|
case pt
- when Sexp then
- case pt.first
+ when Sexp then # TODO: what the fuck? why??
+ case pt.sexp_type
when :str then
- s << dthing_escape(type, pt.last)
+ dthing_escape(type, pt.last)
when :evstr then
- s << '#{' << process(pt) << '}' # do not use interpolation here
+ '#{%s}' % [process(pt)]
else
raise "unknown type: #{pt.inspect}"
end
else
raise "unhandled value in d-thing: #{pt.inspect}"
end
- end
+ }
- s.join
+ [str, rest].join
end
##
# Utility method to generate ether a module or class.
def util_module_or_class(exp, is_class=false)
result = []
- name = exp.shift
+ _, name, *body = exp
+ superk = body.shift if is_class
+
name = process name if Sexp === name
result << name
- if is_class then
- superk = process(exp.shift)
+ if superk then
+ superk = process superk
result << " < #{superk}" if superk
end
result << "\n"
- body = []
- begin
- code = process(exp.shift) unless exp.empty?
- body << code.chomp unless code.nil? or code.chomp.empty?
- end until exp.empty?
+ body = body.map { |sexp|
+ process(sexp).chomp
+ }
unless body.empty? then
body = indent(body.join("\n\n")) + "\n"
else
body = ""
end
+
result << body
result << "end"
result.join
end