Class: RubyToRuby

Inherits:
SexpProcessor
  • Object
show all
Defined in:
lib/ruby2ruby.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeRubyToRuby

Returns a new instance of RubyToRuby.



15
16
17
18
19
20
21
22
# File 'lib/ruby2ruby.rb', line 15

def initialize
  super
  @env = Environment.new
  @indent = "  "
  self.auto_shift_type = true
  self.strict = true
  self.expected = String
end

Class Method Details

.translate(klass, method = nil) ⇒ Object



7
8
9
10
11
12
13
# File 'lib/ruby2ruby.rb', line 7

def self.translate(klass, method=nil)
  unless method.nil? then
    self.new.process(ParseTree.new(false).parse_tree_for_method(klass, method))
  else
    self.new.process(ParseTree.new(false).parse_tree(klass).first) # huh? why is the :class node wrapped?
  end
end

Instance Method Details

#cond_loop(exp, name) ⇒ Object



315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/ruby2ruby.rb', line 315

def cond_loop(exp, name)
  cond = process(exp.shift)
  body = indent(process(exp.shift))
  head_controlled = exp.empty? ? false : exp.shift

  code = []
  if head_controlled then
    code << "#{name} #{cond} do"
    code << body
    code << "end"
  else
    code << "begin"
    code << body
    code << "end #{name} #{cond}"
  end
  code.join("\n")
end

#indent(s) ⇒ Object



24
25
26
# File 'lib/ruby2ruby.rb', line 24

def indent(s)
  s.to_s.map{|line| @indent + line}.join
end

#process_and(exp) ⇒ Object



28
29
30
# File 'lib/ruby2ruby.rb', line 28

def process_and(exp)
  "(#{process exp.shift} and #{process exp.shift})"
end

#process_args(exp) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/ruby2ruby.rb', line 32

def process_args(exp)
  args = []

  until exp.empty? do
    arg = exp.shift
    if arg.is_a? Array
      args[-(arg.size-1)..-1] = arg[1..-1].map{|a| process a}
    else
      args << arg
    end
  end

  return "(#{args.join ', '})"
end

#process_array(exp) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/ruby2ruby.rb', line 47

def process_array(exp)
  code = []
  until exp.empty? do
    code << process(exp.shift)
  end
  return "[" + code.join(", ") + "]"
end

#process_attrasgn(exp) ⇒ Object



55
56
57
# File 'lib/ruby2ruby.rb', line 55

def process_attrasgn(exp)
  process_call(exp)
end

#process_block(exp) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
# File 'lib/ruby2ruby.rb', line 59

def process_block(exp)
  code = []
  until exp.empty? do
    code << process(exp.shift)
  end

  body = code.join("\n")
  body += "\n"

  return body
end

#process_call(exp) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/ruby2ruby.rb', line 71

def process_call(exp)
  receiver = process exp.shift
  name = exp.shift
  args_exp = exp.shift
  if args_exp && args_exp.first == :array
    args = "#{process(args_exp)[1..-2]}"
  else
    args = process args_exp
  end

  case name
  when :<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :% then #
    "(#{receiver} #{name} #{args})"
  when :[] then
    "#{receiver}[#{args}]"
  else
    "#{receiver}.#{name}#{args ? "(#{args})" : args}"
  end
end

#process_case(exp) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/ruby2ruby.rb', line 91

def process_case(exp)
  s = "case #{process exp.shift}\n"
  until exp.empty?
    pt = exp.shift
    if pt.first == :when
      s << "#{process(pt)}\n"
    else
      s << "else\n#{indent(process(pt))}\n"
    end
  end
  s + "\nend"
end

#process_class(exp) ⇒ Object



104
105
106
107
108
109
# File 'lib/ruby2ruby.rb', line 104

def process_class(exp)
  s = "class #{exp.shift} < #{exp.shift}\n"
  body = ""
  body << "#{process exp.shift}\n\n" until exp.empty?
  s + indent(body) + "end"
end

#process_const(exp) ⇒ Object



111
112
113
# File 'lib/ruby2ruby.rb', line 111

def process_const(exp)
  exp.shift.to_s
end

#process_dasgn_curr(exp) ⇒ Object



115
116
117
# File 'lib/ruby2ruby.rb', line 115

def process_dasgn_curr(exp)
  exp.shift.to_s
end

#process_defn(exp) ⇒ Object



169
170
171
172
173
174
# File 'lib/ruby2ruby.rb', line 169

def process_defn(exp)
  name = exp.shift
  args = process(exp.shift).to_a
  body = indent(process(exp.shift))
  return "def #{name}#{args}\n#{body}end".gsub(/\n\s*\n+/, "\n")
end

#process_dot2(exp) ⇒ Object



176
177
178
# File 'lib/ruby2ruby.rb', line 176

def process_dot2(exp)
  "(#{process exp.shift}..#{process exp.shift})"
end

#process_dot3(exp) ⇒ Object



180
181
182
# File 'lib/ruby2ruby.rb', line 180

def process_dot3(exp)
  "(#{process exp.shift}...#{process exp.shift})"
end

#process_dstr(exp) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/ruby2ruby.rb', line 184

def process_dstr(exp)
  s = exp.shift.dump[0..-2]
  until exp.empty?
    pt = exp.shift
    if pt.first == :str
      s << process(pt)[1..-2]
    else
      s << '#{' + process(pt) + '}'
    end
  end
  s + '"'
end

#process_dvar(exp) ⇒ Object



197
198
199
# File 'lib/ruby2ruby.rb', line 197

def process_dvar(exp)
  exp.shift.to_s
end

#process_false(exp) ⇒ Object



201
202
203
# File 'lib/ruby2ruby.rb', line 201

def process_false(exp)
  "false"
end

#process_fcall(exp) ⇒ Object



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/ruby2ruby.rb', line 205

def process_fcall(exp)
  exp_orig = exp.deep_clone
  # [:fcall, :puts, [:array, [:str, "This is a weird loop"]]]
  name = exp.shift.to_s
  args = exp.shift
  code = []
  unless args.nil? then
    assert_type args, :array
    args.shift # :array
    until args.empty? do
      code << process(args.shift)
    end
  end
  return "#{name}(#{code.join(', ')})"
end

#process_iasgn(exp) ⇒ Object



221
222
223
# File 'lib/ruby2ruby.rb', line 221

def process_iasgn(exp)
  "#{exp.shift} = #{process exp.shift}"
end

#process_if(exp) ⇒ Object



225
226
227
228
229
230
231
# File 'lib/ruby2ruby.rb', line 225

def process_if(exp)
  s = ["if (#{process exp.shift})"]
  s << "#{indent(process(exp.shift))}"
  s << "else\n#{indent(process(exp.shift))}" until exp.empty?
  s << "end"
  s.join("\n")
end

#process_iter(exp) ⇒ Object



233
234
235
236
237
# File 'lib/ruby2ruby.rb', line 233

def process_iter(exp)
  "#{process exp.shift} {|#{process exp.shift}|\n" +
  indent("#{process exp.shift}\n") +
  "}"
end

#process_ivar(exp) ⇒ Object



239
240
241
# File 'lib/ruby2ruby.rb', line 239

def process_ivar(exp)
  exp.shift.to_s
end

#process_lasgn(exp) ⇒ Object



243
244
245
# File 'lib/ruby2ruby.rb', line 243

def process_lasgn(exp)
  return "#{exp.shift} = #{process exp.shift}"
end

#process_lit(exp) ⇒ Object



247
248
249
250
251
252
253
254
# File 'lib/ruby2ruby.rb', line 247

def process_lit(exp)
  obj = exp.shift
  if obj.is_a? Range # to get around how parsed ranges turn into lits and lose parens
    "(" + obj.inspect + ")"
  else
    obj.inspect
  end
end

#process_lvar(exp) ⇒ Object



256
257
258
# File 'lib/ruby2ruby.rb', line 256

def process_lvar(exp)
  exp.shift.to_s
end

#process_masgn(exp) ⇒ Object



260
261
262
# File 'lib/ruby2ruby.rb', line 260

def process_masgn(exp)
  process(exp.shift)[1..-2]
end

#process_nil(exp) ⇒ Object



264
265
266
# File 'lib/ruby2ruby.rb', line 264

def process_nil(exp)
  "nil"
end

#process_return(exp) ⇒ Object



268
269
270
# File 'lib/ruby2ruby.rb', line 268

def process_return(exp)
  return "return #{process exp.shift}"
end

#process_scope(exp) ⇒ Object



272
273
274
# File 'lib/ruby2ruby.rb', line 272

def process_scope(exp)
  return process(exp.shift)
end

#process_self(exp) ⇒ Object



276
277
278
# File 'lib/ruby2ruby.rb', line 276

def process_self(exp)
  "self"
end

#process_str(exp) ⇒ Object



279
280
281
# File 'lib/ruby2ruby.rb', line 279

def process_str(exp)
  return exp.shift.dump
end

#process_super(exp) ⇒ Object



283
284
285
# File 'lib/ruby2ruby.rb', line 283

def process_super(exp)
  "super(#{process(exp.shift)})"
end

#process_true(exp) ⇒ Object



287
288
289
# File 'lib/ruby2ruby.rb', line 287

def process_true(exp)
  "true"
end

#process_until(exp) ⇒ Object



291
292
293
# File 'lib/ruby2ruby.rb', line 291

def process_until(exp)
  cond_loop(exp, 'until')
end

#process_vcall(exp) ⇒ Object



295
296
297
# File 'lib/ruby2ruby.rb', line 295

def process_vcall(exp)
  return exp.shift.to_s
end

#process_when(exp) ⇒ Object



299
300
301
# File 'lib/ruby2ruby.rb', line 299

def process_when(exp)
  "when #{process(exp.shift).to_s[1..-2]}\n#{indent(process(exp.shift))}"
end

#process_while(exp) ⇒ Object



303
304
305
# File 'lib/ruby2ruby.rb', line 303

def process_while(exp)
  cond_loop(exp, 'while')
end

#process_zarray(exp) ⇒ Object



307
308
309
# File 'lib/ruby2ruby.rb', line 307

def process_zarray(exp)
  "[]"
end

#process_zsuper(exp) ⇒ Object



311
312
313
# File 'lib/ruby2ruby.rb', line 311

def process_zsuper(exp)
  "super"
end

#rewrite_defn(exp) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/ruby2ruby.rb', line 119

def rewrite_defn(exp)
  exp.shift # :defn
  name = exp.shift
  args = s(:args)
  body = Sexp.from_array exp.shift

  case body.first
  when :scope, :fbody then
    body = body[1] if body.first == :fbody
    args = body.last[1]
    assert_type args, :args
    assert_type body, :scope
    assert_type body[1], :block
    body.last.delete_at 1
  when :bmethod then
    # BEFORE: [:defn, :bmethod_added, [:bmethod, [:dasgn_curr, :x], ...]]
    # AFTER:  [:defn, :bmethod_added, [:args, :x], [:scope, [:block, ...]]]
    body.shift # :bmethod
    # [:dasgn_curr, :x],
    # [:call, [:dvar, :x], :+, [:arglist, [:lit, 1]]]]]
    dasgn = body.shift
    assert_type dasgn, :dasgn_curr
    dasgn.shift # type
    args.push(*dasgn)
    body.find_and_replace_all(:dvar, :lvar)
    if body.first.first == :block then
      body = s(:scope, body.shift)
    else
      body = s(:scope, s(:block, body.shift)) # single statement
    end
  when :dmethod
    # BEFORE: [:defn, :dmethod_added, [:dmethod, :bmethod_maker, ...]]
    # AFTER:  [:defn, :dmethod_added, ...]
    body = body[2][1][2] # UGH! FIX
    args = body[1]
    body.delete_at 1
    body = s(:scope, body)
  when :ivar then
    body = s(:scope, s(:block, s(:return, body)))
  when :attrset then
    argname = body.last
    args << :arg
    body = s(:scope, s(:block, s(:return, s(:iasgn, argname, s(:lvar, :arg)))))
  else
    raise "Unknown :defn format: #{name.inspect} #{args.inspect} #{body.inspect}"
  end

  return s(:defn, name, args, body)
end