sexp2ruby 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +3 -0
  3. data/.travis.yml +1 -2
  4. data/README.md +9 -0
  5. data/lib/{sexp2ruby/core_extensions → core_extensions}/regexp.rb +0 -0
  6. data/lib/sexp2ruby/node/alias.rb +9 -0
  7. data/lib/sexp2ruby/node/and.rb +9 -0
  8. data/lib/sexp2ruby/node/arglist.rb +16 -0
  9. data/lib/sexp2ruby/node/args.rb +33 -0
  10. data/lib/sexp2ruby/node/array.rb +9 -0
  11. data/lib/sexp2ruby/node/attrasgn.rb +27 -0
  12. data/lib/sexp2ruby/node/back_ref.rb +9 -0
  13. data/lib/sexp2ruby/node/base.rb +36 -0
  14. data/lib/sexp2ruby/node/begin.rb +19 -0
  15. data/lib/sexp2ruby/node/block.rb +24 -0
  16. data/lib/sexp2ruby/node/block_pass.rb +10 -0
  17. data/lib/sexp2ruby/node/break.rb +14 -0
  18. data/lib/sexp2ruby/node/call.rb +70 -0
  19. data/lib/sexp2ruby/node/case.rb +27 -0
  20. data/lib/sexp2ruby/node/cdecl.rb +17 -0
  21. data/lib/sexp2ruby/node/class.rb +9 -0
  22. data/lib/sexp2ruby/node/colon2.rb +9 -0
  23. data/lib/sexp2ruby/node/colon3.rb +9 -0
  24. data/lib/sexp2ruby/node/const.rb +9 -0
  25. data/lib/sexp2ruby/node/cvar.rb +9 -0
  26. data/lib/sexp2ruby/node/cvasgn.rb +9 -0
  27. data/lib/sexp2ruby/node/cvdecl.rb +9 -0
  28. data/lib/sexp2ruby/node/defined.rb +9 -0
  29. data/lib/sexp2ruby/node/defn.rb +66 -0
  30. data/lib/sexp2ruby/node/defs.rb +17 -0
  31. data/lib/sexp2ruby/node/dot2.rb +9 -0
  32. data/lib/sexp2ruby/node/dot3.rb +9 -0
  33. data/lib/sexp2ruby/node/dregx.rb +19 -0
  34. data/lib/sexp2ruby/node/dregx_once.rb +9 -0
  35. data/lib/sexp2ruby/node/dstr.rb +9 -0
  36. data/lib/sexp2ruby/node/dsym.rb +9 -0
  37. data/lib/sexp2ruby/node/dxstr.rb +9 -0
  38. data/lib/sexp2ruby/node/ensure.rb +18 -0
  39. data/lib/sexp2ruby/node/evstr.rb +9 -0
  40. data/lib/sexp2ruby/node/false.rb +9 -0
  41. data/lib/sexp2ruby/node/flip2.rb +9 -0
  42. data/lib/sexp2ruby/node/flip3.rb +9 -0
  43. data/lib/sexp2ruby/node/for.rb +17 -0
  44. data/lib/sexp2ruby/node/gasgn.rb +9 -0
  45. data/lib/sexp2ruby/node/gvar.rb +9 -0
  46. data/lib/sexp2ruby/node/hash.rb +53 -0
  47. data/lib/sexp2ruby/node/iasgn.rb +14 -0
  48. data/lib/sexp2ruby/node/if.rb +41 -0
  49. data/lib/sexp2ruby/node/iter.rb +50 -0
  50. data/lib/sexp2ruby/node/ivar.rb +9 -0
  51. data/lib/sexp2ruby/node/kwsplat.rb +9 -0
  52. data/lib/sexp2ruby/node/lasgn.rb +11 -0
  53. data/lib/sexp2ruby/node/lit.rb +15 -0
  54. data/lib/sexp2ruby/node/lvar.rb +9 -0
  55. data/lib/sexp2ruby/node/masgn.rb +46 -0
  56. data/lib/sexp2ruby/node/match.rb +9 -0
  57. data/lib/sexp2ruby/node/match2.rb +11 -0
  58. data/lib/sexp2ruby/node/match3.rb +17 -0
  59. data/lib/sexp2ruby/node/module.rb +9 -0
  60. data/lib/sexp2ruby/node/next.rb +14 -0
  61. data/lib/sexp2ruby/node/nil.rb +9 -0
  62. data/lib/sexp2ruby/node/not.rb +9 -0
  63. data/lib/sexp2ruby/node/nth_ref.rb +9 -0
  64. data/lib/sexp2ruby/node/op_asgn1.rb +16 -0
  65. data/lib/sexp2ruby/node/op_asgn2.rb +17 -0
  66. data/lib/sexp2ruby/node/op_asgn_and.rb +13 -0
  67. data/lib/sexp2ruby/node/op_asgn_or.rb +13 -0
  68. data/lib/sexp2ruby/node/or.rb +9 -0
  69. data/lib/sexp2ruby/node/postexe.rb +9 -0
  70. data/lib/sexp2ruby/node/redo.rb +9 -0
  71. data/lib/sexp2ruby/node/resbody.rb +19 -0
  72. data/lib/sexp2ruby/node/rescue.rb +32 -0
  73. data/lib/sexp2ruby/node/retry.rb +9 -0
  74. data/lib/sexp2ruby/node/return.rb +13 -0
  75. data/lib/sexp2ruby/node/sclass.rb +9 -0
  76. data/lib/sexp2ruby/node/self.rb +9 -0
  77. data/lib/sexp2ruby/node/splat.rb +13 -0
  78. data/lib/sexp2ruby/node/str.rb +9 -0
  79. data/lib/sexp2ruby/node/super.rb +10 -0
  80. data/lib/sexp2ruby/node/svalue.rb +13 -0
  81. data/lib/sexp2ruby/node/to_ary.rb +9 -0
  82. data/lib/sexp2ruby/node/true.rb +9 -0
  83. data/lib/sexp2ruby/node/undef.rb +9 -0
  84. data/lib/sexp2ruby/node/until.rb +9 -0
  85. data/lib/sexp2ruby/node/valias.rb +9 -0
  86. data/lib/sexp2ruby/node/when.rb +24 -0
  87. data/lib/sexp2ruby/node/while.rb +9 -0
  88. data/lib/sexp2ruby/node/xstr.rb +9 -0
  89. data/lib/sexp2ruby/node/yield.rb +18 -0
  90. data/lib/sexp2ruby/node/zsuper.rb +9 -0
  91. data/lib/sexp2ruby/processor.rb +121 -912
  92. data/lib/sexp2ruby/version.rb +1 -1
  93. data/lib/sexp2ruby.rb +88 -1
  94. data/sexp2ruby.gemspec +1 -0
  95. data/spec/lib/processor_spec.rb +478 -1
  96. metadata +104 -8
  97. data/Rakefile +0 -92
  98. data/test/test_ruby2ruby.rb +0 -496
@@ -4,14 +4,8 @@ module Sexp2Ruby
4
4
 
5
5
  # Generate ruby code from a sexp.
6
6
  class Processor < SexpProcessor
7
+ LF = "\n"
7
8
 
8
- # cutoff for one-liners
9
- LINE_LENGTH = 78
10
-
11
- # binary operation messages
12
- BINARY = [:<=>, :==, :<, :>, :<=, :>=, :-, :+, :*, :/, :%, :<<, :>>, :**, :'!=']
13
-
14
- ##
15
9
  # Nodes that represent assignment and probably need () around them.
16
10
  #
17
11
  # TODO: this should be replaced with full precedence support :/
@@ -32,32 +26,100 @@ module Sexp2Ruby
32
26
  :rescue,
33
27
  ]
34
28
 
35
- ##
36
- # Some sexp types are OK without parens when appearing as hash values.
37
- # This list can include `:call`s because they're always printed with parens
38
- # around their arguments. For example:
39
- #
40
- # { :foo => (bar("baz")) } # The outer parens are unnecessary
41
- # { :foo => bar("baz") } # This is the normal code style
29
+ HASH_SYNTAXES = [:ruby18, :ruby19]
30
+ RUBY_19_HASH_KEY = /\A[a-z][_a-zA-Z0-9]+\Z/
31
+
32
+ CONSTRUCTOR_OPTIONS = [:hash_syntax]
42
33
 
43
- HASH_VAL_NO_PAREN = [
34
+ NODES = [
35
+ :alias,
36
+ :and,
37
+ :arglist,
38
+ :args,
39
+ :array,
40
+ :attrasgn,
41
+ :back_ref,
42
+ :begin,
43
+ :block,
44
+ :block_pass,
45
+ :break,
44
46
  :call,
47
+ :case,
48
+ :cdecl,
49
+ :class,
50
+ :colon2,
51
+ :colon3,
52
+ :const,
53
+ :cvar,
54
+ :cvasgn,
55
+ :cvdecl,
56
+ :defined,
57
+ :defn,
58
+ :defs,
59
+ :dot2,
60
+ :dot3,
61
+ :dregx,
62
+ :dregx_once,
63
+ :dstr,
64
+ :dsym,
65
+ :dxstr,
66
+ :ensure,
67
+ :evstr,
45
68
  :false,
69
+ :flip2,
70
+ :flip3,
71
+ :for,
72
+ :gasgn,
73
+ :gvar,
74
+ :hash,
75
+ :iasgn,
76
+ :if,
77
+ :iter,
78
+ :ivar,
79
+ :kwsplat,
80
+ :lasgn,
46
81
  :lit,
47
82
  :lvar,
83
+ :masgn,
84
+ :match,
85
+ :match2,
86
+ :match3,
87
+ :module,
88
+ :next,
48
89
  :nil,
90
+ :not,
91
+ :nth_ref,
92
+ :op_asgn1,
93
+ :op_asgn2,
94
+ :op_asgn_and,
95
+ :op_asgn_or,
96
+ :or,
97
+ :postexe,
98
+ :redo,
99
+ :resbody,
100
+ :rescue,
101
+ :retry,
102
+ :return,
103
+ :sclass,
104
+ :self,
105
+ :splat,
49
106
  :str,
50
- :true
107
+ :super,
108
+ :svalue,
109
+ :to_ary,
110
+ :true,
111
+ :undef,
112
+ :until,
113
+ :valias,
114
+ :when,
115
+ :while,
116
+ :xstr,
117
+ :yield,
118
+ :zsuper
51
119
  ]
52
120
 
53
- HASH_SYNTAXES = [:ruby18, :ruby19]
54
- RUBY_19_HASH_KEY = /\A[a-z][_a-zA-Z0-9]+\Z/
55
-
56
- CONSTRUCTOR_OPTIONS = [:hash_syntax]
57
-
58
- attr_reader :hash_syntax
121
+ attr_reader :hash_syntax, :indent_lvl
59
122
 
60
- ##
61
123
  # Options:
62
124
  #
63
125
  # - `:hash_syntax` - either `:ruby18` or `:ruby19`
@@ -66,864 +128,44 @@ module Sexp2Ruby
66
128
  super()
67
129
  check_option_keys(option)
68
130
  @hash_syntax = extract_option(HASH_SYNTAXES, option[:hash_syntax], :ruby18)
69
- @indent = " "
131
+ @indent_lvl = " "
70
132
  self.auto_shift_type = true
71
133
  self.strict = true
72
134
  self.expected = String
73
-
74
135
  @calls = []
75
-
76
- # self.debug[:defn] = /zsuper/
77
- end
78
-
79
- ############################################################
80
- # Processors
81
-
82
- def process_alias(exp) # :nodoc:
83
- parenthesize "alias #{process(exp.shift)} #{process(exp.shift)}"
84
- end
85
-
86
- def process_and(exp) # :nodoc:
87
- parenthesize "#{process exp.shift} and #{process exp.shift}"
88
- end
89
-
90
- def process_arglist(exp) # custom made node # :nodoc:
91
- code = []
92
- until exp.empty? do
93
- arg = exp.shift
94
- to_wrap = arg.first == :rescue
95
- arg_code = process arg
96
- code << (to_wrap ? "(#{arg_code})" : arg_code)
97
- end
98
- code.join ', '
99
- end
100
-
101
- def process_args(exp) # :nodoc:
102
- args = []
103
-
104
- until exp.empty? do
105
- arg = exp.shift
106
- case arg
107
- when Symbol then
108
- args << arg
109
- when Sexp then
110
- case arg.first
111
- when :lasgn then
112
- args << process(arg)
113
- when :masgn then
114
- args << process(arg)
115
- when :kwarg then
116
- _, k, v = arg
117
- args << "#{k}: #{process v}"
118
- else
119
- raise "unknown arg type #{arg.first.inspect}"
120
- end
121
- else
122
- raise "unknown arg type #{arg.inspect}"
123
- end
124
- end
125
-
126
- "(#{args.join ', '})"
127
- end
128
-
129
- def process_array(exp) # :nodoc:
130
- "[#{process_arglist(exp)}]"
131
- end
132
-
133
- def process_attrasgn(exp) # :nodoc:
134
- receiver = process exp.shift
135
- name = exp.shift
136
- rhs = exp.pop
137
- args = s(:array, *exp)
138
- exp.clear
139
-
140
- case name
141
- when :[]= then
142
- args = process args
143
- "#{receiver}#{args} = #{process rhs}"
144
- else
145
- raise "dunno what to do: #{args.inspect}" unless args.size == 1 # s(:array)
146
- name = name.to_s.sub(/=$/, '')
147
- if rhs && rhs != s(:arglist) then
148
- "#{receiver}.#{name} = #{process(rhs)}"
149
- else
150
- raise "dunno what to do: #{rhs.inspect}"
151
- end
152
- end
153
136
  end
154
137
 
155
- def process_back_ref(exp) # :nodoc:
156
- "$#{exp.shift}"
157
- end
158
-
159
- # TODO: figure out how to do rescue and ensure ENTIRELY w/o begin
160
- def process_begin(exp) # :nodoc:
161
- code = []
162
- code << "begin"
163
- until exp.empty?
164
- src = process(exp.shift)
165
- src = indent(src) unless src =~ /(^|\n)(rescue|ensure)/ # ensure no level 0 rescues
166
- code << src
167
- end
168
- code << "end"
169
- return code.join("\n")
170
- end
171
-
172
- def process_block(exp) # :nodoc:
173
- result = []
174
-
175
- exp << nil if exp.empty?
176
- until exp.empty? do
177
- code = exp.shift
178
- if code.nil? or code.first == :nil then
179
- result << "# do nothing\n"
180
- else
181
- result << process(code)
182
- end
183
- end
184
-
185
- result = parenthesize result.join "\n"
186
- result += "\n" unless result.start_with? "("
187
-
188
- return result
189
- end
190
-
191
- def process_block_pass exp # :nodoc:
192
- raise "huh?: #{exp.inspect}" if exp.size > 1
193
-
194
- "&#{process exp.shift}"
195
- end
138
+ # Process Methods
139
+ # ---------------
140
+ #
141
+ # For each node that a SexpProcessor visits, it will call a
142
+ # method `#process_X` where X is is the node's `sexp_type`.
196
143
 
197
- def process_break(exp) # :nodoc:
198
- val = exp.empty? ? nil : process(exp.shift)
199
- # HACK "break" + (val ? " #{val}" : "")
200
- if val then
201
- "break #{val}"
202
- else
203
- "break"
204
- end
144
+ NODES.each do |p|
145
+ define_method("process_#{p}") { |exp|
146
+ "::Sexp2Ruby::Node::#{p.to_s.camelize}".
147
+ constantize.
148
+ new(self).
149
+ to_s(exp)
150
+ }
205
151
  end
206
152
 
207
- def process_call(exp) # :nodoc:
208
- receiver_node_type = exp.first.nil? ? nil : exp.first.first
209
- receiver = process exp.shift
210
- receiver = "(#{receiver})" if ASSIGN_NODES.include? receiver_node_type
153
+ # State
154
+ # -----
211
155
 
212
- name = exp.shift
213
- args = []
214
-
215
- # this allows us to do both old and new sexp forms:
216
- exp.push(*exp.pop[1..-1]) if exp.size == 1 && exp.first.first == :arglist
217
-
218
- @calls.push name
219
-
220
- in_context :arglist do
221
- until exp.empty? do
222
- arg_type = exp.first.sexp_type
223
- is_empty_hash = (exp.first == s(:hash))
224
- arg = process exp.shift
225
-
226
- next if arg.empty?
227
-
228
- strip_hash = (arg_type == :hash and
229
- not BINARY.include? name and
230
- not is_empty_hash and
231
- (exp.empty? or exp.first.sexp_type == :splat))
232
- wrap_arg = ASSIGN_NODES.include? arg_type
233
-
234
- arg = arg[2..-3] if strip_hash
235
- arg = "(#{arg})" if wrap_arg
236
-
237
- args << arg
238
- end
239
- end
240
-
241
- case name
242
- when *BINARY then
243
- "(#{receiver} #{name} #{args.join(', ')})"
244
- when :[] then
245
- receiver ||= "self"
246
- "#{receiver}[#{args.join(', ')}]"
247
- when :[]= then
248
- receiver ||= "self"
249
- rhs = args.pop
250
- "#{receiver}[#{args.join(', ')}] = #{rhs}"
251
- when :"!" then
252
- "(not #{receiver})"
253
- when :"-@" then
254
- "-#{receiver}"
255
- when :"+@" then
256
- "+#{receiver}"
257
- else
258
- args = nil if args.empty?
259
- args = "(#{args.join(', ')})" if args
260
- receiver = "#{receiver}." if receiver
261
-
262
- "#{receiver}#{name}#{args}"
263
- end
264
- ensure
156
+ def call_pop
265
157
  @calls.pop
266
158
  end
267
159
 
268
- def process_case(exp) # :nodoc:
269
- result = []
270
- expr = process exp.shift
271
- if expr then
272
- result << "case #{expr}"
273
- else
274
- result << "case"
275
- end
276
- until exp.empty?
277
- pt = exp.shift
278
- if pt and pt.first == :when
279
- result << "#{process(pt)}"
280
- else
281
- code = indent(process(pt))
282
- code = indent("# do nothing") if code =~ /^\s*$/
283
- result << "else\n#{code}"
284
- end
285
- end
286
- result << "end"
287
- result.join("\n")
288
- end
289
-
290
- def process_cdecl(exp) # :nodoc:
291
- lhs = exp.shift
292
- lhs = process lhs if Sexp === lhs
293
- unless exp.empty? then
294
- rhs = process(exp.shift)
295
- "#{lhs} = #{rhs}"
296
- else
297
- lhs.to_s
298
- end
299
- end
300
-
301
- def process_class(exp) # :nodoc:
302
- "#{exp.comments}class #{util_module_or_class(exp, true)}"
303
- end
304
-
305
- def process_colon2(exp) # :nodoc:
306
- "#{process(exp.shift)}::#{exp.shift}"
307
- end
308
-
309
- def process_colon3(exp) # :nodoc:
310
- "::#{exp.shift}"
311
- end
312
-
313
- def process_const(exp) # :nodoc:
314
- exp.shift.to_s
315
- end
316
-
317
- def process_cvar(exp) # :nodoc:
318
- "#{exp.shift}"
319
- end
320
-
321
- def process_cvasgn(exp) # :nodoc:
322
- "#{exp.shift} = #{process(exp.shift)}"
323
- end
324
-
325
- def process_cvdecl(exp) # :nodoc:
326
- "#{exp.shift} = #{process(exp.shift)}"
327
- end
328
-
329
- def process_defined(exp) # :nodoc:
330
- "defined? #{process(exp.shift)}"
331
- end
332
-
333
- def process_defn(exp) # :nodoc:
334
- type1 = exp[1].first
335
- type2 = exp[2].first rescue nil
336
- expect = [:ivar, :iasgn, :attrset]
337
-
338
- # s(name, args, ivar|iasgn|attrset)
339
- if exp.size == 3 and type1 == :args and expect.include? type2 then
340
- name = exp.first # don't shift in case we pass through
341
- case type2
342
- when :ivar then
343
- ivar_name = exp.ivar.last
344
-
345
- meth_name = ivar_name.to_s[1..-1].to_sym
346
- expected = s(meth_name, s(:args), s(:ivar, ivar_name))
347
-
348
- if exp == expected then
349
- exp.clear
350
- return "attr_reader #{name.inspect}"
351
- end
352
- when :attrset then
353
- # TODO: deprecate? this is a PT relic
354
- exp.clear
355
- return "attr_writer :#{name.to_s[0..-2]}"
356
- when :iasgn then
357
- ivar_name = exp.iasgn[1]
358
- meth_name = "#{ivar_name.to_s[1..-1]}=".to_sym
359
- arg_name = exp.args.last
360
- expected = s(meth_name, s(:args, arg_name),
361
- s(:iasgn, ivar_name, s(:lvar, arg_name)))
362
-
363
- if exp == expected then
364
- exp.clear
365
- return "attr_writer :#{name.to_s[0..-2]}"
366
- end
367
- else
368
- raise "Unknown defn type: #{exp.inspect}"
369
- end
370
- end
371
-
372
- comm = exp.comments
373
- name = exp.shift
374
- args = process exp.shift
375
- args = "" if args == "()"
376
-
377
- exp.shift if exp == s(s(:nil)) # empty it out of a default nil expression
378
-
379
- # REFACTOR: use process_block but get it happier wrt parenthesize
380
- body = []
381
- until exp.empty? do
382
- body << process(exp.shift)
383
- end
384
-
385
- body << "# do nothing" if body.empty?
386
- body = body.join("\n")
387
- body = body.lines.to_a[1..-2].join("\n") if
388
- body =~ /^\Abegin/ && body =~ /^end\z/
389
- body = indent(body) unless body =~ /(^|\n)rescue/
390
-
391
- return "#{comm}def #{name}#{args}\n#{body}\nend".gsub(/\n\s*\n+/, "\n")
392
- end
393
-
394
- def process_defs(exp) # :nodoc:
395
- lhs = exp.shift
396
- var = [:self, :cvar, :dvar, :ivar, :gvar, :lvar].include? lhs.first
397
- name = exp.shift
398
-
399
- lhs = process(lhs)
400
- lhs = "(#{lhs})" unless var
401
-
402
- exp.unshift "#{lhs}.#{name}"
403
- process_defn(exp)
404
- end
405
-
406
- def process_dot2(exp) # :nodoc:
407
- "(#{process exp.shift}..#{process exp.shift})"
408
- end
409
-
410
- def process_dot3(exp) # :nodoc:
411
- "(#{process exp.shift}...#{process exp.shift})"
412
- end
413
-
414
- def process_dregx(exp) # :nodoc:
415
- options = re_opt exp.pop if Fixnum === exp.last
416
- "/" << util_dthing(:dregx, exp) << "/#{options}"
417
- end
418
-
419
- def process_dregx_once(exp) # :nodoc:
420
- process_dregx(exp) + "o"
160
+ def call_push(name)
161
+ @calls.push(name)
421
162
  end
422
163
 
423
- def process_dstr(exp) # :nodoc:
424
- "\"#{util_dthing(:dstr, exp)}\""
425
- end
426
-
427
- def process_dsym(exp) # :nodoc:
428
- ":\"#{util_dthing(:dsym, exp)}\""
429
- end
164
+ # Rewriters
165
+ # ---------
430
166
 
431
- def process_dxstr(exp) # :nodoc:
432
- "`#{util_dthing(:dxstr, exp)}`"
433
- end
434
-
435
- def process_ensure(exp) # :nodoc:
436
- body = process exp.shift
437
- ens = exp.shift
438
- ens = nil if ens == s(:nil)
439
- ens = process(ens) || "# do nothing"
440
- ens = "begin\n#{ens}\nend\n" if ens =~ /(^|\n)rescue/
441
-
442
- body.sub!(/\n\s*end\z/, '')
443
- body = indent(body) unless body =~ /(^|\n)rescue/
444
-
445
- return "#{body}\nensure\n#{indent ens}"
446
- end
447
-
448
- def process_evstr(exp) # :nodoc:
449
- exp.empty? ? '' : process(exp.shift)
450
- end
451
-
452
- def process_false(exp) # :nodoc:
453
- "false"
454
- end
455
-
456
- def process_flip2(exp) # :nodoc:
457
- "#{process(exp.shift)}..#{process(exp.shift)}"
458
- end
459
-
460
- def process_flip3(exp) # :nodoc:
461
- "#{process(exp.shift)}...#{process(exp.shift)}"
462
- end
463
-
464
- def process_for(exp) # :nodoc:
465
- recv = process exp.shift
466
- iter = process exp.shift
467
- body = exp.empty? ? nil : process(exp.shift)
468
-
469
- result = ["for #{iter} in #{recv} do"]
470
- result << indent(body ? body : "# do nothing")
471
- result << "end"
472
-
473
- result.join("\n")
474
- end
475
-
476
- def process_gasgn(exp) # :nodoc:
477
- process_iasgn(exp)
478
- end
479
-
480
- def process_gvar(exp) # :nodoc:
481
- return exp.shift.to_s
482
- end
483
-
484
- def process_hash(exp) # :nodoc:
485
- result = []
486
-
487
- until exp.empty?
488
- s = exp.shift
489
- t = s.sexp_type
490
- ruby19_key = ruby19_hash_key?(s)
491
- lhs = process s
492
-
493
- case t
494
- when :kwsplat then
495
- result << lhs
496
- else
497
- rhs = exp.shift
498
- t = rhs.first
499
- rhs = process rhs
500
- rhs = "(#{rhs})" unless HASH_VAL_NO_PAREN.include? t
501
-
502
- if hash_syntax == :ruby19 && ruby19_key
503
- lhs.gsub!(/\A:/, "")
504
- result << "#{lhs}: #{rhs}"
505
- else
506
- result << "#{lhs} => #{rhs}"
507
- end
508
- end
509
- end
510
-
511
- return result.empty? ? "{}" : "{ #{result.join(', ')} }"
512
- end
513
-
514
- def process_iasgn(exp) # :nodoc:
515
- lhs = exp.shift
516
- if exp.empty? then # part of an masgn
517
- lhs.to_s
518
- else
519
- "#{lhs} = #{process exp.shift}"
520
- end
521
- end
522
-
523
- def process_if(exp) # :nodoc:
524
- expand = ASSIGN_NODES.include? exp.first.first
525
- c = process exp.shift
526
- t = process exp.shift
527
- f = process exp.shift
528
-
529
- c = "(#{c.chomp})" if c =~ /\n/
530
-
531
- if t then
532
- unless expand then
533
- if f then
534
- r = "#{c} ? (#{t}) : (#{f})"
535
- r = nil if r =~ /return/ # HACK - need contextual awareness or something
536
- else
537
- r = "#{t} if #{c}"
538
- end
539
- return r if r and (@indent+r).size < LINE_LENGTH and r !~ /\n/
540
- end
541
-
542
- r = "if #{c} then\n#{indent(t)}\n"
543
- r << "else\n#{indent(f)}\n" if f
544
- r << "end"
545
-
546
- r
547
- elsif f
548
- unless expand then
549
- r = "#{f} unless #{c}"
550
- return r if (@indent+r).size < LINE_LENGTH and r !~ /\n/
551
- end
552
- "unless #{c} then\n#{indent(f)}\nend"
553
- else
554
- # empty if statement, just do it in case of side effects from condition
555
- "if #{c} then\n#{indent '# do nothing'}\nend"
556
- end
557
- end
558
-
559
- def process_iter(exp) # :nodoc:
560
- iter = process exp.shift
561
- args = exp.shift
562
- body = exp.empty? ? nil : process(exp.shift)
563
-
564
- args = case args
565
- when 0 then
566
- " ||"
567
- else
568
- a = process(args)[1..-2]
569
- a = " |#{a}|" unless a.empty?
570
- a
571
- end
572
-
573
- b, e = if iter == "END" then
574
- [ "{", "}" ]
575
- else
576
- [ "do", "end" ]
577
- end
578
-
579
- iter.sub!(/\(\)$/, '')
580
-
581
- # REFACTOR: ugh
582
- result = []
583
- result << "#{iter} {"
584
- result << args
585
- if body then
586
- result << " #{body.strip} "
587
- else
588
- result << ' '
589
- end
590
- result << "}"
591
- result = result.join
592
- return result if result !~ /\n/ and result.size < LINE_LENGTH
593
-
594
- result = []
595
- result << "#{iter} #{b}"
596
- result << args
597
- result << "\n"
598
- if body then
599
- result << indent(body.strip)
600
- result << "\n"
601
- end
602
- result << e
603
- result.join
604
- end
605
-
606
- def process_ivar(exp) # :nodoc:
607
- exp.shift.to_s
608
- end
609
-
610
- def process_kwsplat(exp)
611
- "**#{process exp.shift}"
612
- end
613
-
614
- def process_lasgn(exp) # :nodoc:
615
- s = "#{exp.shift}"
616
- s += " = #{process exp.shift}" unless exp.empty?
617
- s
618
- end
619
-
620
- def process_lit(exp) # :nodoc:
621
- obj = exp.shift
622
- case obj
623
- when Range then
624
- "(#{obj.inspect})"
625
- else
626
- obj.inspect
627
- end
628
- end
629
-
630
- def process_lvar(exp) # :nodoc:
631
- exp.shift.to_s
632
- end
633
-
634
- def process_masgn(exp) # :nodoc:
635
- # s(:masgn, s(:array, s(:lasgn, :var), ...), s(:to_ary, <val>, ...))
636
- # s(:iter, <call>, s(:args, s(:masgn, :a, :b)), <body>)
637
-
638
- case exp.first
639
- when Sexp then
640
- lhs = exp.shift
641
- rhs = exp.empty? ? nil : exp.shift
642
-
643
- case lhs.first
644
- when :array then
645
- lhs.shift # node type
646
- lhs = lhs.map do |l|
647
- case l.first
648
- when :masgn then
649
- "(#{process(l)})"
650
- else
651
- process(l)
652
- end
653
- end
654
- else
655
- raise "no clue: #{lhs.inspect}"
656
- end
657
-
658
- unless rhs.nil? then
659
- t = rhs.first
660
- rhs = process rhs
661
- rhs = rhs[1..-2] if t == :array # FIX: bad? I dunno
662
- return "#{lhs.join(", ")} = #{rhs}"
663
- else
664
- return lhs.join(", ")
665
- end
666
- when Symbol then # block arg list w/ masgn
667
- result = exp.join ", "
668
- exp.clear
669
- "(#{result})"
670
- else
671
- raise "unknown masgn: #{exp.inspect}"
672
- end
673
- end
674
-
675
- def process_match(exp) # :nodoc:
676
- "#{process(exp.shift)}"
677
- end
678
-
679
- def process_match2(exp) # :nodoc:
680
- lhs = process(exp.shift)
681
- rhs = process(exp.shift)
682
- "#{lhs} =~ #{rhs}"
683
- end
684
-
685
- def process_match3(exp) # :nodoc:
686
- rhs = process(exp.shift)
687
- left_type = exp.first.sexp_type
688
- lhs = process(exp.shift)
689
-
690
- if ASSIGN_NODES.include? left_type then
691
- "(#{lhs}) =~ #{rhs}"
692
- else
693
- "#{lhs} =~ #{rhs}"
694
- end
695
- end
696
-
697
- def process_module(exp) # :nodoc:
698
- "#{exp.comments}module #{util_module_or_class(exp)}"
699
- end
700
-
701
- def process_next(exp) # :nodoc:
702
- val = exp.empty? ? nil : process(exp.shift)
703
- if val then
704
- "next #{val}"
705
- else
706
- "next"
707
- end
708
- end
709
-
710
- def process_nil(exp) # :nodoc:
711
- "nil"
712
- end
713
-
714
- def process_not(exp) # :nodoc:
715
- "(not #{process exp.shift})"
716
- end
717
-
718
- def process_nth_ref(exp) # :nodoc:
719
- "$#{exp.shift}"
720
- end
721
-
722
- def process_op_asgn1(exp) # :nodoc:
723
- # [[:lvar, :b], [:arglist, [:lit, 1]], :"||", [:lit, 10]]
724
- lhs = process(exp.shift)
725
- index = process(exp.shift)
726
- msg = exp.shift
727
- rhs = process(exp.shift)
728
-
729
- "#{lhs}[#{index}] #{msg}= #{rhs}"
730
- end
731
-
732
- def process_op_asgn2(exp) # :nodoc:
733
- # [[:lvar, :c], :var=, :"||", [:lit, 20]]
734
- lhs = process(exp.shift)
735
- index = exp.shift.to_s[0..-2]
736
- msg = exp.shift
737
-
738
- rhs = process(exp.shift)
739
-
740
- "#{lhs}.#{index} #{msg}= #{rhs}"
741
- end
742
-
743
- def process_op_asgn_and(exp) # :nodoc:
744
- # a &&= 1
745
- # [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
746
- exp.shift
747
- process(exp.shift).sub(/\=/, '&&=')
748
- end
749
-
750
- def process_op_asgn_or(exp) # :nodoc:
751
- # a ||= 1
752
- # [[:lvar, :a], [:lasgn, :a, [:lit, 1]]]
753
- exp.shift
754
- process(exp.shift).sub(/\=/, '||=')
755
- end
756
-
757
- def process_or(exp) # :nodoc:
758
- "(#{process exp.shift} or #{process exp.shift})"
759
- end
760
-
761
- def process_postexe(exp) # :nodoc:
762
- "END"
763
- end
764
-
765
- def process_redo(exp) # :nodoc:
766
- "redo"
767
- end
768
-
769
- def process_resbody exp # :nodoc:
770
- args = exp.shift
771
- body = finish(exp)
772
- body << "# do nothing" if body.empty?
773
-
774
- name = args.lasgn true
775
- name ||= args.iasgn true
776
- args = process(args)[1..-2]
777
- args = " #{args}" unless args.empty?
778
- args += " => #{name[1]}" if name
779
-
780
- "rescue#{args}\n#{indent body.join("\n")}"
781
- end
782
-
783
- def process_rescue exp # :nodoc:
784
- body = process(exp.shift) unless exp.first.first == :resbody
785
- els = process(exp.pop) unless exp.last.first == :resbody
786
-
787
- body ||= "# do nothing"
788
- simple = exp.size == 1 && exp.resbody.size <= 3 &&
789
- !exp.resbody.block &&
790
- !exp.resbody.return
791
-
792
- resbodies = []
793
- until exp.empty? do
794
- resbody = exp.shift
795
- simple &&= resbody[1] == s(:array)
796
- simple &&= resbody[2] != nil && resbody[2].node_type != :block
797
- resbodies << process(resbody)
798
- end
799
-
800
- if els then
801
- "#{indent body}\n#{resbodies.join("\n")}\nelse\n#{indent els}"
802
- elsif simple then
803
- resbody = resbodies.first.sub(/\n\s*/, ' ')
804
- "#{body} #{resbody}"
805
- else
806
- "#{indent body}\n#{resbodies.join("\n")}"
807
- end
808
- end
809
-
810
- def process_retry(exp) # :nodoc:
811
- "retry"
812
- end
813
-
814
- def process_return(exp) # :nodoc:
815
- # HACK return "return" + (exp.empty? ? "" : " #{process exp.shift}")
816
-
817
- if exp.empty? then
818
- return "return"
819
- else
820
- return "return #{process exp.shift}"
821
- end
822
- end
823
-
824
- def process_sclass(exp) # :nodoc:
825
- "class << #{process(exp.shift)}\n#{indent(process_block(exp))}\nend"
826
- end
827
-
828
- def process_self(exp) # :nodoc:
829
- "self"
830
- end
831
-
832
- def process_splat(exp) # :nodoc:
833
- if exp.empty? then
834
- "*"
835
- else
836
- "*#{process(exp.shift)}"
837
- end
838
- end
839
-
840
- def process_str(exp) # :nodoc:
841
- return exp.shift.dump
842
- end
843
-
844
- def process_super(exp) # :nodoc:
845
- args = finish exp
846
-
847
- "super(#{args.join(', ')})"
848
- end
849
-
850
- def process_svalue(exp) # :nodoc:
851
- code = []
852
- until exp.empty? do
853
- code << process(exp.shift)
854
- end
855
- code.join(", ")
856
- end
857
-
858
- def process_to_ary(exp) # :nodoc:
859
- process(exp.shift)
860
- end
861
-
862
- def process_true(exp) # :nodoc:
863
- "true"
864
- end
865
-
866
- def process_undef(exp) # :nodoc:
867
- "undef #{process(exp.shift)}"
868
- end
869
-
870
- def process_until(exp) # :nodoc:
871
- cond_loop(exp, 'until')
872
- end
873
-
874
- def process_valias(exp) # :nodoc:
875
- "alias #{exp.shift} #{exp.shift}"
876
- end
877
-
878
- def process_when(exp) # :nodoc:
879
- src = []
880
-
881
- if self.context[1] == :array then # ugh. matz! why not an argscat?!?
882
- val = process(exp.shift)
883
- exp.shift # empty body
884
- return "*#{val}"
885
- end
886
-
887
- until exp.empty?
888
- cond = process(exp.shift).to_s[1..-2]
889
- code = indent(finish(exp).join("\n"))
890
- code = indent "# do nothing" if code =~ /\A\s*\Z/
891
- src << "when #{cond} then\n#{code.chomp}"
892
- end
893
-
894
- src.join("\n")
895
- end
896
-
897
- def process_while(exp) # :nodoc:
898
- cond_loop(exp, 'while')
899
- end
900
-
901
- def process_xstr(exp) # :nodoc:
902
- "`#{process_str(exp)[1..-2]}`"
903
- end
904
-
905
- def process_yield(exp) # :nodoc:
906
- args = []
907
- until exp.empty? do
908
- args << process(exp.shift)
909
- end
910
-
911
- unless args.empty? then
912
- "yield(#{args.join(', ')})"
913
- else
914
- "yield"
915
- end
916
- end
917
-
918
- def process_zsuper(exp) # :nodoc:
919
- "super"
920
- end
921
-
922
- ############################################################
923
- # Rewriters:
924
-
925
- def rewrite_attrasgn exp # :nodoc:
926
- if context.first(2) == [:array, :masgn] then
167
+ def rewrite_attrasgn exp
168
+ if context.first(2) == [:array, :masgn]
927
169
  exp[0] = :call
928
170
  exp[2] = exp[2].to_s.sub(/=$/, '').to_sym
929
171
  end
@@ -931,19 +173,19 @@ module Sexp2Ruby
931
173
  exp
932
174
  end
933
175
 
934
- def rewrite_ensure exp # :nodoc:
176
+ def rewrite_ensure exp
935
177
  exp = s(:begin, exp) unless context.first == :begin
936
178
  exp
937
179
  end
938
180
 
939
- def rewrite_resbody exp # :nodoc:
181
+ def rewrite_resbody exp
940
182
  raise "no exception list in #{exp.inspect}" unless exp.size > 2 && exp[1]
941
183
  raise exp[1].inspect if exp[1][0] != :array
942
184
  # for now, do nothing, just check and freak if we see an errant structure
943
185
  exp
944
186
  end
945
187
 
946
- def rewrite_rescue exp # :nodoc:
188
+ def rewrite_rescue exp
947
189
  complex = false
948
190
  complex ||= exp.size > 3
949
191
  complex ||= exp.resbody.block
@@ -959,7 +201,7 @@ module Sexp2Ruby
959
201
  exp
960
202
  end
961
203
 
962
- def rewrite_svalue(exp) # :nodoc:
204
+ def rewrite_svalue(exp)
963
205
  case exp.last.first
964
206
  when :array
965
207
  s(:svalue, *exp[1][1..-1])
@@ -970,8 +212,8 @@ module Sexp2Ruby
970
212
  end
971
213
  end
972
214
 
973
- ############################################################
974
- # Utility Methods:
215
+ # Utility Methods
216
+ # ---------------
975
217
 
976
218
  def check_option_keys(option)
977
219
  diff = option.keys - CONSTRUCTOR_OPTIONS
@@ -980,9 +222,7 @@ module Sexp2Ruby
980
222
  end
981
223
  end
982
224
 
983
- ##
984
225
  # Generate a post-or-pre conditional loop.
985
-
986
226
  def cond_loop(exp, name)
987
227
  cond = process(exp.shift)
988
228
  body = process(exp.shift)
@@ -991,7 +231,7 @@ module Sexp2Ruby
991
231
  body = indent(body).chomp if body
992
232
 
993
233
  code = []
994
- if head_controlled then
234
+ if head_controlled
995
235
  code << "#{name} #{cond} do"
996
236
  code << body if body
997
237
  code << "end"
@@ -1000,12 +240,10 @@ module Sexp2Ruby
1000
240
  code << body if body
1001
241
  code << "end #{name} #{cond}"
1002
242
  end
1003
- code.join("\n")
243
+ code.join(LF)
1004
244
  end
1005
245
 
1006
- ##
1007
- # Utility method to escape something interpolated.
1008
-
246
+ # Escape something interpolated.
1009
247
  def dthing_escape type, lit
1010
248
  lit = lit.gsub(/\n/, '\n')
1011
249
  case type
@@ -1020,10 +258,8 @@ module Sexp2Ruby
1020
258
  end
1021
259
  end
1022
260
 
1023
- ##
1024
261
  # Check that `value` is in `array` of valid option values,
1025
262
  # or raise InvalidOption. If `value` is nil, return `default`.
1026
-
1027
263
  def extract_option(array, value, default)
1028
264
  if value.nil?
1029
265
  default
@@ -1034,10 +270,8 @@ module Sexp2Ruby
1034
270
  end
1035
271
  end
1036
272
 
1037
- ##
1038
273
  # Process all the remaining stuff in +exp+ and return the results
1039
274
  # sans-nils.
1040
-
1041
275
  def finish exp # REFACTOR: work this out of the rest of the processors
1042
276
  body = []
1043
277
  until exp.empty? do
@@ -1046,27 +280,21 @@ module Sexp2Ruby
1046
280
  body.compact
1047
281
  end
1048
282
 
1049
- ##
1050
283
  # Given `exp` representing the left side of a hash pair, return true
1051
284
  # if it is compatible with the ruby 1.9 hash syntax. For example,
1052
285
  # the symbol `:foo` is compatible, but the literal `7` is not. Note
1053
286
  # that strings are not considered "compatible". If we converted string
1054
287
  # keys to symbol keys, we wouldn't be faithfully representing the input.
1055
-
1056
288
  def ruby19_hash_key?(exp)
1057
289
  exp.sexp_type == :lit && exp.length == 2 && RUBY_19_HASH_KEY === exp[1].to_s
1058
290
  end
1059
291
 
1060
- ##
1061
292
  # Indent all lines of +s+ to the current indent level.
1062
-
1063
293
  def indent(s)
1064
- s.to_s.split(/\n/).map{|line| @indent + line}.join("\n")
294
+ s.to_s.split(/\n/).map{|line| @indent_lvl + line}.join(LF)
1065
295
  end
1066
296
 
1067
- ##
1068
297
  # Wrap appropriate expressions in matching parens.
1069
-
1070
298
  def parenthesize exp
1071
299
  case self.context[1]
1072
300
  when nil, :defn, :defs, :class, :sclass, :if, :iter, :resbody, :when, :while then
@@ -1076,25 +304,12 @@ module Sexp2Ruby
1076
304
  end
1077
305
  end
1078
306
 
1079
- ##
1080
- # Return the appropriate regexp flags for a given numeric code.
1081
-
1082
- def re_opt options
1083
- bits = (0..8).map { |n| options[n] * 2**n }
1084
- bits.delete 0
1085
- bits.map { |n| Regexp::CODES[n] }.join
1086
- end
1087
-
1088
- ##
1089
307
  # Return a splatted symbol for +sym+.
1090
-
1091
308
  def splat(sym)
1092
309
  :"*#{sym}"
1093
310
  end
1094
311
 
1095
- ##
1096
- # Utility method to generate something interpolated.
1097
-
312
+ # Generate something interpolated.
1098
313
  def util_dthing(type, exp)
1099
314
  s = []
1100
315
 
@@ -1121,9 +336,7 @@ module Sexp2Ruby
1121
336
  s.join
1122
337
  end
1123
338
 
1124
- ##
1125
339
  # Utility method to generate ether a module or class.
1126
-
1127
340
  def util_module_or_class(exp, is_class=false)
1128
341
  result = []
1129
342
 
@@ -1132,12 +345,12 @@ module Sexp2Ruby
1132
345
 
1133
346
  result << name
1134
347
 
1135
- if is_class then
348
+ if is_class
1136
349
  superk = process(exp.shift)
1137
350
  result << " < #{superk}" if superk
1138
351
  end
1139
352
 
1140
- result << "\n"
353
+ result << LF
1141
354
 
1142
355
  body = []
1143
356
  begin
@@ -1145,11 +358,7 @@ module Sexp2Ruby
1145
358
  body << code.chomp unless code.nil? or code.chomp.empty?
1146
359
  end until exp.empty?
1147
360
 
1148
- unless body.empty? then
1149
- body = indent(body.join("\n\n")) + "\n"
1150
- else
1151
- body = ""
1152
- end
361
+ body = body.empty? ? "" : indent(body.join("\n\n")) + LF
1153
362
  result << body
1154
363
  result << "end"
1155
364