sexp2ruby 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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