to_source 0.1.3 → 0.2.0

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.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml CHANGED
@@ -1,3 +1,14 @@
1
+ language: ruby
2
+ bundler_args: --without guard metrics
3
+ script: "bundle exec rake spec"
1
4
  rvm:
2
- - rbx-18mode
5
+ #- 1.8.7
6
+ - 1.9.2
7
+ - 1.9.3
8
+ #- jruby-18mode # JRuby in 1.8 mode, no cextension support on travis
9
+ #- jruby-19mode # JRuby in 1.9 mode, no cextension support on travis
10
+ #- rbx-18mode
3
11
  - rbx-19mode
12
+ notifications:
13
+ email:
14
+ - mbj@seonic.net
data/Changelog.md ADDED
@@ -0,0 +1,11 @@
1
+ # v0.2.0 2012-12-07
2
+
3
+ * [BRAKING CHANGE] Remove core extension Rubinius::AST::Node#to_source (mbj)
4
+ * [feature] Add support for MRI via melbourne gem (mbj)
5
+ * [fixed] 100% Yard covered documentation (mbj)
6
+ * [fixed] Emit most binary operators without parantheses (mbj)
7
+ * [feature] Port tests to rspec2 and greatly improve coverage and layout of these.
8
+ * [feature] Introduce metric tools via devtools
9
+ * [fixed] Lots of transitvity edge cases
10
+
11
+ [Compare v0.1.3..v0.2.0](https://github.com/solnic/virtus/compare/v0.1.3...v0.2.0)
data/Gemfile CHANGED
@@ -1,5 +1,8 @@
1
- source "http://rubygems.org"
1
+ source :rubygems
2
2
 
3
- # Specify your gem's dependencies in to_source.gemspec
4
3
  gemspec
5
- gem 'rake'
4
+
5
+ gem 'mutant-melbourne', :git => 'https://github.com/mbj/melbourne.git'
6
+ gem 'devtools', :git => 'https://github.com/mbj/devtools.git', :branch => 'rspec-2-mutant'
7
+
8
+ eval File.read('Gemfile.devtools')
data/Gemfile.devtools ADDED
@@ -0,0 +1,52 @@
1
+ group :development do
2
+ gem 'rake', '~> 0.9.2'
3
+ gem 'rspec', '~> 2.12.0'
4
+ gem 'yard', '~> 0.8.3'
5
+ end
6
+
7
+ group :guard do
8
+ gem 'guard', '~> 1.5.4'
9
+ gem 'guard-bundler', '~> 1.0.0'
10
+ gem 'guard-rspec', '~> 2.1.1'
11
+ gem 'rb-inotify', :git => 'https://github.com/mbj/rb-inotify'
12
+ end
13
+
14
+ group :benchmarks do
15
+ gem 'rbench', '~> 0.2.3'
16
+ end
17
+
18
+ platform :jruby do
19
+ group :jruby do
20
+ gem 'jruby-openssl', '~> 0.7.4'
21
+ end
22
+ end
23
+
24
+ group :metrics do
25
+ gem 'flay', '~> 1.4.2'
26
+ gem 'flog', '~> 2.5.1'
27
+ gem 'reek', '~> 1.2.8', :git => 'https://github.com/dkubb/reek.git'
28
+ gem 'roodi', '~> 2.1.0'
29
+ gem 'yardstick', '~> 0.7.0'
30
+ gem 'simplecov'
31
+
32
+ platforms :ruby_18, :ruby_19 do
33
+ # this indirectly depends on ffi which does not build on ruby-head
34
+ gem 'yard-spellcheck', '~> 0.1.5'
35
+ end
36
+
37
+ platforms :mri_18 do
38
+ gem 'arrayfields', '~> 4.7.4' # for metric_fu
39
+ gem 'fattr', '~> 2.2.0' # for metric_fu
40
+ gem 'json', '~> 1.7.3' # for metric_fu rake task
41
+ gem 'map', '~> 6.0.1' # for metric_fu
42
+ gem 'metric_fu', '~> 2.1.1'
43
+ gem 'mspec', '~> 1.5.17'
44
+ gem 'rcov', '~> 1.0.0'
45
+ end
46
+
47
+ platforms :rbx do
48
+ gem 'pelusa', '~> 0.2.1'
49
+ gem 'anima', '~> 0.0.1', :git => 'https://github.com/mbj/anima.git'
50
+ gem 'mutant', '~> 0.0.1', :git => 'https://github.com/mbj/mutant.git'
51
+ end
52
+ end
data/Guardfile ADDED
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+
3
+ guard :bundler do
4
+ watch('Gemfile')
5
+ end
6
+
7
+ guard :rspec do
8
+ # run all specs if the spec_helper or supporting files files are modified
9
+ watch('spec/spec_helper.rb') { 'spec' }
10
+ watch(%r{\Aspec/(?:lib|support|shared)/.+\.rb\z}) { 'spec' }
11
+
12
+ # run unit specs if associated lib code is modified
13
+ watch(%r{\Alib/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}"] }
14
+ watch("lib/#{File.basename(File.expand_path('../', __FILE__))}.rb") { 'spec' }
15
+
16
+ # run a spec if it is modified
17
+ watch(%r{\Aspec/(?:unit|integration)/.+_spec\.rb\z})
18
+ end
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ to_source
2
+ =========
3
+
4
+ [![Build Status](https://secure.travis-ci.org/mbj/to_source.png?branch=master)](http://travis-ci.org/mbj/to_source)
5
+ [![Dependency Status](https://gemnasium.com/mbj/to_source.png)](https://gemnasium.com/mbj/to_source)
6
+ [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/mbj/to_source)
7
+
8
+ Reverse parser to generate source code from the Rubinius AST. Also works well under MRI.
9
+
10
+ Installation
11
+ ------------
12
+
13
+ Install the gem ```to_source``` via your preferred method.
14
+
15
+ Examples
16
+ --------
17
+
18
+ ```ruby
19
+ require 'to_source'
20
+ some_code = "a = 123"
21
+ ast = some_code.to_ast
22
+ # => #<Rubinius::AST::LocalVariableAssignment:0x21b8
23
+ # @value=#<Rubinius::AST::FixnumLiteral:0x21bc @value=123 @line=1>
24
+ # @variable=nil @line=1 @name=:a>
25
+ ast.to_source
26
+ # => "a = 123"
27
+ ```
28
+
29
+ Credits
30
+ -------
31
+
32
+ * [Josep M. Bach (Txus)](http://txustice.me), [@txustice](http://twitter.com/txustice) on twitter
33
+ * [Markus Schirp (mbj)](https://github.com/mbj), [@_m_b_j_](http://twitter.com/_m_b_j_) on twitter
34
+
35
+ Contributing
36
+ -------------
37
+
38
+ * Fork the project.
39
+ * Make your feature addition or bug fix.
40
+ * Add tests for it. This is important so I don't break it in a
41
+ future version unintentionally.
42
+ * Commit, do not mess with Rakefile or version
43
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
44
+ * Send me a pull request. Bonus points for topic branches.
45
+
46
+ License
47
+ -------
48
+
49
+ Copyright (c) 2012 Josep M. Bach (Txus), Markus Schirp (mbj)
50
+
51
+ Permission is hereby granted, free of charge, to any person obtaining
52
+ a copy of this software and associated documentation files (the
53
+ "Software"), to deal in the Software without restriction, including
54
+ without limitation the rights to use, copy, modify, merge, publish,
55
+ distribute, sublicense, and/or sell copies of the Software, and to
56
+ permit persons to whom the Software is furnished to do so, subject to
57
+ the following conditions:
58
+
59
+ The above copyright notice and this permission notice shall be
60
+ included in all copies or substantial portions of the Software.
61
+
62
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
63
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
64
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
65
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
66
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
67
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
68
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,10 +1,5 @@
1
- require "bundler/gem_tasks"
1
+ require 'rake'
2
2
 
3
- require 'rake/testtask'
4
- Rake::TestTask.new do |t|
5
- t.libs << "test"
6
- t.test_files = FileList['test/**/*_test.rb']
7
- t.verbose = true
8
- end
3
+ require 'devtools'
9
4
 
10
- task :default => :test
5
+ Devtools.init
data/TODO ADDED
@@ -0,0 +1,5 @@
1
+ * Fix parsing errors from ruby parser
2
+ It breaks on def $keyword.
3
+ * Do a metric driven refactor once flay flog and friends work.
4
+ * Report bug about missing Rubinius::AST::SClass#body
5
+ * Decide about to support 18-mode or not
data/bin/to_source ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'to_source'
4
+
5
+ ARGV.each do |path|
6
+ source = File.read(path)
7
+ ast = source.to_ast
8
+ next if ast.nil? # When file only has comments
9
+ $stderr.puts(path)
10
+ begin
11
+ $stdout.puts(ToSource.to_source(ast))
12
+ rescue
13
+ ast.ascii_graph
14
+ raise
15
+ end
16
+ end
data/config/flay.yml ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ threshold: 18
3
+ total_score: 296
data/config/flog.yml ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 14.4
data/config/roodi.yml ADDED
@@ -0,0 +1,26 @@
1
+ ---
2
+ AbcMetricMethodCheck:
3
+ score: 12.2
4
+ AssignmentInConditionalCheck: {}
5
+ CaseMissingElseCheck: {}
6
+ ClassLineCountCheck:
7
+ line_count: 324
8
+ ClassNameCheck:
9
+ pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/
10
+ ClassVariableCheck: {}
11
+ CyclomaticComplexityBlockCheck:
12
+ complexity: 2
13
+ CyclomaticComplexityMethodCheck:
14
+ complexity: 4
15
+ EmptyRescueBodyCheck: {}
16
+ ForLoopCheck: {}
17
+ MethodLineCountCheck:
18
+ line_count: 9
19
+ MethodNameCheck:
20
+ pattern: !ruby/regexp /\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\]=?|==|<=>|<<|[+*&|-])\z/
21
+ ModuleLineCountCheck:
22
+ line_count: 327
23
+ ModuleNameCheck:
24
+ pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/
25
+ ParameterNumberCheck:
26
+ parameter_count: 3
data/config/site.reek ADDED
@@ -0,0 +1,93 @@
1
+ ---
2
+ UncommunicativeParameterName:
3
+ accept: []
4
+ exclude: []
5
+ enabled: true
6
+ reject:
7
+ - !ruby/regexp /^.$/
8
+ - !ruby/regexp /[0-9]$/
9
+ - !ruby/regexp /[A-Z]/
10
+ LargeClass:
11
+ max_methods: 10
12
+ exclude:
13
+ - "Mutant::Matcher::Method" # 13 methods
14
+ enabled: true
15
+ max_instance_variables: 3
16
+ UncommunicativeMethodName:
17
+ accept: []
18
+ exclude: []
19
+ enabled: true
20
+ reject:
21
+ - !ruby/regexp /^[a-z]$/
22
+ - !ruby/regexp /[0-9]$/
23
+ - !ruby/regexp /[A-Z]/
24
+ LongParameterList:
25
+ max_params: 2
26
+ exclude:
27
+ - "Mutant::Context::Constant#initialize" # 3 params
28
+ enabled: true
29
+ overrides: {}
30
+ FeatureEnvy:
31
+ exclude: []
32
+ enabled: true
33
+ ClassVariable:
34
+ exclude: []
35
+ enabled: true
36
+ BooleanParameter:
37
+ exclude: []
38
+ enabled: true
39
+ IrresponsibleModule:
40
+ exclude: []
41
+ enabled: true
42
+ UncommunicativeModuleName:
43
+ accept: []
44
+ exclude: []
45
+ enabled: true
46
+ reject:
47
+ - !ruby/regexp /^.$/
48
+ - !ruby/regexp /[0-9]$/
49
+ NestedIterators:
50
+ ignore_iterators: []
51
+ exclude: []
52
+ enabled: true
53
+ max_allowed_nesting: 1
54
+ LongMethod:
55
+ max_statements: 6
56
+ exclude: []
57
+ enabled: true
58
+ Duplication:
59
+ allow_calls: []
60
+ exclude: []
61
+ enabled: true
62
+ max_calls: 1
63
+ UtilityFunction:
64
+ max_helper_calls: 0
65
+ exclude: []
66
+ enabled: true
67
+ Attribute:
68
+ exclude: []
69
+ enabled: false
70
+ UncommunicativeVariableName:
71
+ accept: []
72
+ exclude: []
73
+ enabled: true
74
+ reject:
75
+ - !ruby/regexp /^.$/
76
+ - !ruby/regexp /[0-9]$/
77
+ - !ruby/regexp /[A-Z]/
78
+ SimulatedPolymorphism:
79
+ exclude: []
80
+ enabled: true
81
+ max_ifs: 1
82
+ DataClump:
83
+ exclude: []
84
+ enabled: true
85
+ max_copies: 2
86
+ min_clump_size: 2
87
+ ControlCouple:
88
+ exclude: []
89
+ enabled: true
90
+ LongYieldList:
91
+ max_params: 1
92
+ exclude: []
93
+ enabled: true
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 100
data/lib/to_source.rb CHANGED
@@ -1,16 +1,18 @@
1
- require "to_source/version"
2
- require "to_source/core_ext/node"
3
- require "to_source/visitor"
1
+ require 'melbourne'
2
+ require 'to_source/version'
3
+ require 'to_source/visitor'
4
4
 
5
+ # Namespace of library
5
6
  module ToSource
6
- # Public: Converts the node back to its original source code.
7
+ # Convert node to string
7
8
  #
8
- # Returns the String output.
9
- def to_source
10
- visitor = Visitor.new
11
- lazy_visit(visitor)
12
- visitor.output
9
+ # @param [Rubinius::AST::Node] node
10
+ #
11
+ # @return [String]
12
+ #
13
+ # @api private
14
+ #
15
+ def self.to_source(node)
16
+ Visitor.run(node)
13
17
  end
14
18
  end
15
-
16
- Rubinius::AST::Node.send :include, ToSource
@@ -1,3 +1,3 @@
1
1
  module ToSource
2
- VERSION = "0.1.3"
2
+ VERSION = '0.2.0'
3
3
  end
@@ -1,189 +1,1276 @@
1
1
  module ToSource
2
+ # Converter from AST to source
2
3
  class Visitor
3
- def initialize
4
+
5
+ # Create source code from AST node
6
+ #
7
+ # @param [Rubinius::AST::Node] node
8
+ # the node to convert to source code
9
+ #
10
+ # @return [String]
11
+ # returns the source code for ast node
12
+ #
13
+ # @api private
14
+ #
15
+ def self.run(node)
16
+ new(node).output
17
+ end
18
+
19
+ # Return the source code of AST
20
+ #
21
+ # @return [String]
22
+ #
23
+ # @api private
24
+ #
25
+ def output
26
+ @output.join
27
+ end
28
+
29
+ private
30
+
31
+ # Initialize visitor
32
+ #
33
+ # @param [Rubinius::AST::Node] node
34
+ #
35
+ # @return [undefined]
36
+ #
37
+ # @api private
38
+ #
39
+ def initialize(node)
4
40
  @output = []
5
41
  @indentation = 0
42
+ dispatch(node)
6
43
  end
7
44
 
8
- def emit(code)
9
- @output.push code
45
+ # Dispatch node
46
+ #
47
+ # @param [Rubinius::AST::Node] node
48
+ #
49
+ # @return [undefined]
50
+ #
51
+ # @api private
52
+ #
53
+ def dispatch(node)
54
+ name = node.node_name
55
+ name = "#{name}_def" if %w[ class module ].include?(name)
56
+ __send__(name, node)
10
57
  end
11
58
 
12
- def output
13
- @output.join
59
+ # Emit file
60
+ #
61
+ # @param [Rubinius::AST::Node] node
62
+ #
63
+ # @return [undefined]
64
+ #
65
+ # @api private
66
+ #
67
+ def file(node)
68
+ emit('__FILE__')
69
+ end
70
+
71
+ # Emit element assignment
72
+ #
73
+ # @param [Rubinius::AST::Node] node
74
+ #
75
+ # @return [undefined]
76
+ #
77
+ # @api private
78
+ #
79
+ def element_assignment(node)
80
+ index, value = node.arguments.array
81
+ dispatch(node.receiver)
82
+ emit('[')
83
+ dispatch(index)
84
+ emit('] = ')
85
+ dispatch(value)
86
+ end
87
+
88
+ # Emit alias
89
+ #
90
+ # @param [Rubinius::AST::Node] node
91
+ #
92
+ # @return [undefined]
93
+ #
94
+ # @api private
95
+ #
96
+ def alias(node)
97
+ emit("alias #{node.to.value} #{node.from.value}")
14
98
  end
15
99
 
100
+ # Emit match operator
101
+ #
102
+ # @param [Rubinius::AST::Node] node
103
+ #
104
+ # @return [undefined]
105
+ #
106
+ # @api private
107
+ #
108
+ def match3(node)
109
+ dispatch(node.value)
110
+ emit(' =~ ')
111
+ dispatch(node.pattern)
112
+ end
113
+
114
+ # Emit break
115
+ #
116
+ # @param [Rubinius::AST::Node] node
117
+ #
118
+ # @return [undefined]
119
+ #
120
+ # @api private
121
+ #
122
+ def break(node)
123
+ emit('break')
124
+ end
125
+
126
+ # Emit next
127
+ #
128
+ # @param [Rubinius::AST::Node] node
129
+ #
130
+ # @return [undefined]
131
+ #
132
+ # @api private
133
+ #
134
+ def next(node)
135
+ emit('next')
136
+ end
137
+
138
+ # Emit conditional element assignment
139
+ #
140
+ # @param [Rubinius::AST::Node] node
141
+ #
142
+ # @return [undefined]
143
+ #
144
+ # @api private
145
+ #
146
+ def op_assign1(node)
147
+ receiver(node)
148
+ emit('[')
149
+ dispatch(node.arguments.array.first)
150
+ emit('] ||= ')
151
+ dispatch(node.value)
152
+ end
153
+
154
+ # Emit attribute assignment after merge
155
+ #
156
+ # @param [Rubinius::AST::Node] node
157
+ #
158
+ # @return [undefined]
159
+ #
160
+ # @api private
161
+ #
162
+ def op_assign2(node)
163
+ dispatch(node.receiver)
164
+ emit('.')
165
+ emit(node.name)
166
+ emit(' |= ')
167
+ dispatch(node.value)
168
+ end
169
+
170
+ # Emit rescue
171
+ #
172
+ # @param [Rubinius::AST::Node] node
173
+ #
174
+ # @return [undefined]
175
+ #
176
+ # @api private
177
+ #
178
+ def rescue(node)
179
+ body(node.body)
180
+ rescue_condition(node.rescue)
181
+ end
182
+
183
+ # Emit rescue condition
184
+ #
185
+ # @param [Rubinius::AST::Node] node
186
+ #
187
+ # @return [undefined]
188
+ #
189
+ # @api private
190
+ #
191
+ def rescue_condition(node)
192
+ emit('rescue')
193
+ if node.conditions
194
+ body = node.conditions.body
195
+ first = body.first
196
+ unless body.one? and first.kind_of?(Rubinius::AST::ConstantAccess) and first.name == :StandardError
197
+ emit(' ')
198
+ array_body(body)
199
+ end
200
+ end
201
+
202
+ if node.splat
203
+ emit(',') if node.conditions
204
+ emit(' ')
205
+ dispatch(node.splat)
206
+ end
207
+
208
+ if node.assignment
209
+ emit(' => ')
210
+ emit(node.assignment.name)
211
+ end
212
+ nl
213
+ body(node.body)
214
+
215
+ if node.next
216
+ dispatch(node.next)
217
+ end
218
+ end
219
+
220
+ # Emit rescue splat
221
+ #
222
+ # @param [Rubinius::AST::Node] node
223
+ #
224
+ # @return [undefined]
225
+ #
226
+ # @api private
227
+ #
228
+ def rescue_splat(node)
229
+ emit('*')
230
+ dispatch(node.value)
231
+ end
232
+
233
+ # Emit ensure
234
+ #
235
+ # @param [Rubinius::AST::Node] node
236
+ #
237
+ # @return [undefined]
238
+ #
239
+ # @api private
240
+ #
241
+ def ensure(node)
242
+ body(node.body)
243
+ emit('ensure')
244
+ nl
245
+ body(node.ensure)
246
+ end
247
+
248
+ # Emit attribute assignment
249
+ #
250
+ # @param [Rubinius::AST::Node] node
251
+ #
252
+ # @return [undefined]
253
+ #
254
+ # @api private
255
+ #
256
+ def attribute_assignment(node)
257
+ dispatch(node.receiver)
258
+ emit('.')
259
+ emit(node.name)
260
+ emit(' ')
261
+ actual_arguments(node.arguments)
262
+ end
263
+
264
+ # Emit body with taking care on indentation
265
+ #
266
+ # @param [Rubinius::AST::Node] node
267
+ #
268
+ # @return [undefined]
269
+ #
270
+ # @api private
271
+ #
272
+ def body(node)
273
+ @indentation+=1
274
+ node =
275
+ case node
276
+ when Rubinius::AST::EmptyBody
277
+ node
278
+ when Rubinius::AST::Block
279
+ # Hack to correctly indent ensure or rescue
280
+ noindent = [Rubinius::AST::Ensure, Rubinius::AST::Rescue]
281
+ if node.array.one? && noindent.include?(node.array.first.class)
282
+ @indentation-=1
283
+ dispatch(node)
284
+ return
285
+ end
286
+ node
287
+ else
288
+ Rubinius::AST::Block.new(node.line, [node])
289
+ end
290
+
291
+ dispatch(node)
292
+ nl
293
+ @indentation-=1
294
+ end
295
+
296
+ # Emit end keyword
297
+ #
298
+ # @return [undefined]
299
+ #
300
+ # @api private
301
+ #
302
+ def kend
303
+ emit(current_indentation)
304
+ emit('end')
305
+ end
306
+
307
+ # Emit newline
308
+ #
309
+ # @return [undefined]
310
+ #
311
+ # @api private
312
+ #
313
+ def nl
314
+ emit("\n")
315
+ end
316
+
317
+ # Emit pice of code
318
+ #
319
+ # @param [String] code
320
+ #
321
+ # @return [undefined]
322
+ #
323
+ # @api private
324
+ #
325
+ def emit(code)
326
+ @output << code
327
+ end
328
+
329
+ # Return current indentation
330
+ #
331
+ # @return [String]
332
+ #
333
+ # @api private
334
+ #
16
335
  def current_indentation
17
336
  ' ' * @indentation
18
337
  end
19
338
 
20
- def class_def(node, parent)
21
- emit "class %s" % node.name.name
339
+ # Emit dynamic regexp
340
+ #
341
+ # @param [Rubinius::AST::Node] node
342
+ #
343
+ # @return [undefined]
344
+ #
345
+ # @api private
346
+ #
347
+ def dynamic_regex(node)
348
+ emit('/')
349
+ emit(node.string)
350
+ node.array.each do |member|
351
+ case member
352
+ when Rubinius::AST::ToString
353
+ emit('#{')
354
+ dispatch(member.value)
355
+ emit('}')
356
+ when Rubinius::AST::StringLiteral
357
+ emit(member.string)
358
+ end
359
+ end
360
+ emit('/')
361
+ end
362
+
363
+ # Emit dynamic string body
364
+ #
365
+ # @param [Rubinius::AST::Node] node
366
+ #
367
+ # @return [undefined]
368
+ #
369
+ # @api private
370
+ #
371
+ def dynamic_string_body(node)
372
+ emit(node.string.inspect[1..-2])
373
+ node.array.each do |member|
374
+ case member
375
+ when Rubinius::AST::ToString
376
+ emit('#{')
377
+ dispatch(member.value)
378
+ emit('}')
379
+ when Rubinius::AST::StringLiteral
380
+ emit(member.string.inspect[1..-2])
381
+ end
382
+ end
383
+ end
384
+
385
+ # Emit dynamic execute string
386
+ #
387
+ # @param [Rubinius::AST::Node] node
388
+ #
389
+ # @return [undefined]
390
+ #
391
+ # @api private
392
+ #
393
+ def dynamic_execute_string(node)
394
+ emit('`')
395
+ dynamic_string_body(node)
396
+ emit('`')
397
+ end
398
+
399
+ # Emit dynamic string
400
+ #
401
+ # @param [Rubinius::AST::Node] node
402
+ #
403
+ # @return [undefined]
404
+ #
405
+ # @api private
406
+ #
407
+ def dynamic_string(node)
408
+ emit('"')
409
+ dynamic_string_body(node)
410
+ emit('"')
411
+ end
412
+
413
+ # Emit dynamic symbol
414
+ #
415
+ # @param [Rubinius::AST::Node] node
416
+ #
417
+ # @return [undefined]
418
+ #
419
+ # @api private
420
+ #
421
+ def dynamic_symbol(node)
422
+ emit(':')
423
+ dynamic_string(node)
424
+ end
425
+
426
+ # Emit singleton class inheritance
427
+ #
428
+ # @param [Rubinius::AST::Node] node
429
+ #
430
+ # @return [undefined]
431
+ #
432
+ # @api private
433
+ #
434
+ def s_class(node)
435
+ emit('class << ')
436
+ dispatch(node.receiver)
437
+ nl
438
+ # FIXME: attr_reader missing on Rubinius::AST::SClass
439
+ scope = node.instance_variable_get(:@body)
440
+ body = scope.body
441
+ if body
442
+ body(body)
443
+ end
444
+ kend
445
+ end
446
+
447
+ # Emit to array
448
+ #
449
+ # @param [Rubinius::AST::Node] node
450
+ #
451
+ # @return [undefined]
452
+ #
453
+ # @api private
454
+ #
455
+ def to_array(node)
456
+ dispatch(node.value)
457
+ end
458
+
459
+ # Emit multiple assignment
460
+ #
461
+ # @param [Rubinius::AST::Node] node
462
+ #
463
+ # @return [undefined]
464
+ #
465
+ # @api private
466
+ #
467
+ def multiple_assignment(node)
468
+ body = node.left.body
469
+
470
+ array_body(node.left.body)
471
+
472
+ emit(' = ')
473
+
474
+ right = node.right
475
+
476
+ if node.right.kind_of?(Rubinius::AST::ArrayLiteral)
477
+ array_body(right.body)
478
+ else
479
+ dispatch(right)
480
+ end
481
+ end
482
+
483
+ # Emit constant assignment
484
+ #
485
+ # @param [Rubinius::AST::Node] node
486
+ #
487
+ # @return [undefined]
488
+ #
489
+ # @api private
490
+ #
491
+ def constant_assignment(node)
492
+ dispatch(node.constant)
493
+ emit(' = ')
494
+ dispatch(node.value)
495
+ end
496
+
497
+ # Emit negation
498
+ #
499
+ # @param [Rubinius::AST::Node] node
500
+ #
501
+ # @return [undefined]
502
+ #
503
+ # @api private
504
+ #
505
+ def negate(node)
506
+ emit('-')
507
+ dispatch(node.value)
508
+ end
509
+
510
+ # Emit class definition
511
+ #
512
+ # @param [Rubinius::AST::Node] node
513
+ #
514
+ # @return [undefined]
515
+ #
516
+ # @api private
517
+ #
518
+ def class_def(node)
519
+ emit('class ')
520
+
521
+ dispatch(node.name)
22
522
 
23
523
  superclass = node.superclass
24
524
  unless superclass.is_a?(Rubinius::AST::NilLiteral)
25
- emit " < %s" % superclass.name
525
+ emit ' < '
526
+ dispatch(superclass)
26
527
  end
528
+ nl
27
529
 
28
- node.body.lazy_visit self, node, true
530
+ dispatch(node.body)
29
531
 
30
- emit "\n"
31
- emit "end"
532
+ kend
32
533
  end
33
534
 
34
- def module_def(node, parent)
35
- emit "module %s" % node.name.name
535
+ # Emit class name
536
+ #
537
+ # @param [Rubinius::AST::Node] node
538
+ #
539
+ # @return [undefined]
540
+ #
541
+ # @api private
542
+ #
543
+ def class_name(node)
544
+ emit(node.name)
545
+ end
36
546
 
37
- node.body.lazy_visit self, node, true
547
+ # Emit module name
548
+ #
549
+ # @param [Rubinius::AST::Node] node
550
+ #
551
+ # @return [undefined]
552
+ #
553
+ # @api private
554
+ #
555
+ def module_name(node)
556
+ emit(node.name)
557
+ end
38
558
 
39
- emit "\n"
40
- emit "end"
559
+ # Emit module definition
560
+ #
561
+ # @param [Rubinius::AST::Node] node
562
+ #
563
+ # @return [undefined]
564
+ #
565
+ # @api private
566
+ #
567
+ def module_def(node)
568
+ emit "module "
569
+ dispatch(node.name)
570
+ nl
571
+
572
+ dispatch(node.body)
573
+
574
+ kend
41
575
  end
42
576
 
43
- def empty_body(*)
577
+ # Emit empty body
578
+ #
579
+ # @param [Rubinius::AST::Node] node
580
+ #
581
+ # @return [undefined]
582
+ #
583
+ # @api private
584
+ #
585
+ def empty_body(node)
44
586
  # do nothing
45
587
  end
46
588
 
47
- def class_scope(node, parent, indent)
48
- emit "\n"
49
- @indentation += 1 if indent
50
- node.body.lazy_visit self, node, indent
51
- ensure
52
- @indentation -= 1 if indent
589
+ # Emit class scope
590
+ #
591
+ # @param [Rubinius::AST::Node] node
592
+ #
593
+ # @return [undefined]
594
+ #
595
+ # @api private
596
+ #
597
+ def class_scope(node)
598
+ body(node.body)
599
+ end
600
+
601
+ # Emit module scope
602
+ #
603
+ # @param [Rubinius::AST::Node] node
604
+ #
605
+ # @return [undefined]
606
+ #
607
+ # @api private
608
+ #
609
+ def module_scope(node)
610
+ body(node.body)
611
+ end
612
+
613
+ # Emit class variable assignment
614
+ #
615
+ # @param [Rubinius::AST::Node] node
616
+ #
617
+ # @return [undefined]
618
+ #
619
+ # @api private
620
+ #
621
+ def class_variable_assignment(node)
622
+ if node.value
623
+ emit("#{node.name} = ")
624
+ dispatch(node.value)
625
+ else
626
+ emit(node.name)
627
+ end
628
+ end
629
+
630
+ # Emit local variable assignment
631
+ #
632
+ # @param [Rubinius::AST::Node] node
633
+ #
634
+ # @return [undefined]
635
+ #
636
+ # @api private
637
+ #
638
+ def local_variable_assignment(node)
639
+ if node.value
640
+ emit("#{node.name} = ")
641
+ dispatch(node.value)
642
+ else
643
+ emit(node.name)
644
+ end
645
+ end
646
+
647
+ # Emit class variable
648
+ #
649
+ # @param [Rubinius::AST::Node] node
650
+ #
651
+ # @return [undefined]
652
+ #
653
+ # @api private
654
+ #
655
+ def class_variable_access(node)
656
+ emit(node.name)
657
+ end
658
+
659
+ # Emit local variable access
660
+ #
661
+ # @param [Rubinius::AST::Node] node
662
+ #
663
+ # @return [undefined]
664
+ #
665
+ # @api private
666
+ #
667
+ def local_variable_access(node)
668
+ emit(node.name)
53
669
  end
54
- alias module_scope class_scope
55
670
 
56
- def local_variable_assignment(node, parent)
57
- emit "%s = " % node.name
58
- node.value.lazy_visit self, node
671
+ # Emit global variable access
672
+ #
673
+ # @param [Rubinius::AST::Node] node
674
+ #
675
+ # @return [undefined]
676
+ #
677
+ # @api private
678
+ #
679
+ def global_variable_access(node)
680
+ emit(node.name)
681
+ end
682
+
683
+ # Emit global variable assignment
684
+ #
685
+ # @param [Rubinius::AST::Node] node
686
+ #
687
+ # @return [undefined]
688
+ #
689
+ # @api private
690
+ #
691
+ def global_variable_assignment(node)
692
+ if(node.value)
693
+ emit("%s = " % node.name)
694
+ dispatch(node.value)
695
+ else
696
+ emit(node.name)
697
+ end
698
+ end
699
+
700
+ # Emit nref global variable access
701
+ #
702
+ # @param [Rubinius::AST::Node] node
703
+ #
704
+ # @return [undefined]
705
+ #
706
+ # @api private
707
+ #
708
+ def nth_ref(node)
709
+ emit("$#{node.which}")
710
+ end
711
+
712
+ # Emit instance variable assignment
713
+ #
714
+ # @param [Rubinius::AST::Node] node
715
+ #
716
+ # @return [undefined]
717
+ #
718
+ # @api private
719
+ #
720
+ def instance_variable_assignment(node)
721
+ if(node.value)
722
+ emit("%s = " % node.name)
723
+ dispatch(node.value)
724
+ else
725
+ emit(node.name)
726
+ end
59
727
  end
60
728
 
61
- def local_variable_access(node, parent)
62
- emit node.name
729
+ # Emit instance variable access
730
+ #
731
+ # @param [Rubinius::AST::Node] node
732
+ #
733
+ # @return [undefined]
734
+ #
735
+ # @api private
736
+ #
737
+ def instance_variable_access(node)
738
+ emit(node.name)
63
739
  end
64
740
 
65
- def instance_variable_assignment(node, parent)
66
- emit "%s = " % node.name
67
- node.value.lazy_visit self, node
741
+ # Emit defined check
742
+ #
743
+ # @param [Rubinius::AST::Node] node
744
+ #
745
+ # @return [undefined]
746
+ #
747
+ # @api private
748
+ #
749
+ def defined(node)
750
+ emit('defined?(')
751
+ dispatch(node.expression)
752
+ emit(')')
68
753
  end
69
754
 
70
- def instance_variable_access(node, parent)
71
- emit node.name
755
+ # Emit fixnum literal
756
+ #
757
+ # @param [Rubinius::AST::Node] node
758
+ #
759
+ # @return [undefined]
760
+ #
761
+ # @api private
762
+ #
763
+ def fixnum_literal(node)
764
+ emit(node.value.to_s)
72
765
  end
73
766
 
74
- def fixnum_literal(node, parent)
75
- emit node.value.to_s
767
+ # Emit float literal
768
+ #
769
+ # @param [Rubinius::AST::Node] node
770
+ #
771
+ # @return [undefined]
772
+ #
773
+ # @api private
774
+ #
775
+ def float_literal(node)
776
+ emit(node.value.to_s)
76
777
  end
77
778
 
78
- def float_literal(node, parent)
79
- emit node.value.to_s
779
+ # Emit string literal
780
+ #
781
+ # @param [Rubinius::AST::Node] node
782
+ #
783
+ # @return [undefined]
784
+ #
785
+ # @api private
786
+ #
787
+ def string_literal(node)
788
+ emit(node.string.inspect)
80
789
  end
81
790
 
82
- def string_literal(node, parent)
83
- emit '"' << node.string.to_s << '"'
791
+ # Emit execute string
792
+ #
793
+ # @param [Rubinius::AST::Node] node
794
+ #
795
+ # @return [undefined]
796
+ #
797
+ # @api private
798
+ #
799
+ def execute_string(node)
800
+ emit("`#{node.string.inspect[1..-2]}`")
84
801
  end
85
802
 
86
- def symbol_literal(node, parent)
87
- emit ':' << node.value.to_s
803
+ # Emit symbol literal
804
+ #
805
+ # @param [Rubinius::AST::Node] node
806
+ #
807
+ # @return [undefined]
808
+ #
809
+ # @api private
810
+ #
811
+ def symbol_literal(node)
812
+ emit ":#{node.value.to_s}"
88
813
  end
89
814
 
90
- def true_literal(node, parent)
815
+ # Emit true literal
816
+ #
817
+ # @param [Rubinius::AST::Node] node
818
+ #
819
+ # @return [undefined]
820
+ #
821
+ # @api private
822
+ #
823
+ def true_literal(node)
91
824
  emit 'true'
92
825
  end
93
826
 
94
- def false_literal(node, parent)
827
+ # Emit false literal
828
+ #
829
+ # @param [Rubinius::AST::Node] node
830
+ #
831
+ # @return [undefined]
832
+ #
833
+ # @api private
834
+ #
835
+ def false_literal(node)
95
836
  emit 'false'
96
837
  end
97
838
 
98
- def nil_literal(node, parent)
839
+ # Emit nil literal
840
+ #
841
+ # @param [Rubinius::AST::Node] node
842
+ #
843
+ # @return [undefined]
844
+ #
845
+ # @api private
846
+ #
847
+ def nil_literal(node)
99
848
  emit 'nil'
100
849
  end
101
850
 
102
- def array_literal(node, parent)
103
- body = node.body
851
+ # Emit argumentless super
852
+ #
853
+ # @param [Rubinius::AST::Node] node
854
+ #
855
+ # @return [undefined]
856
+ #
857
+ # @api private
858
+ #
859
+ def z_super(node)
860
+ emit('super')
861
+ end
862
+
863
+ # Emit super
864
+ #
865
+ # @param [Rubinius::AST::Node] node
866
+ #
867
+ # @return [undefined]
868
+ #
869
+ # @api private
870
+ #
871
+ def super(node)
872
+ z_super(node)
873
+ arguments(node)
874
+ end
104
875
 
105
- emit '['
876
+ # Emit concat args
877
+ #
878
+ # @param [Rubinius::AST::Node] node
879
+ #
880
+ # @return [undefined]
881
+ #
882
+ # @api private
883
+ #
884
+ def concat_args(node)
885
+ emit('[')
886
+ array_body(node.array.body)
887
+ emit(', ')
888
+ emit('*')
889
+ dispatch(node.rest)
890
+ emit(']')
891
+ end
892
+
893
+ # Emit array body
894
+ #
895
+ # @param [Array] body
896
+ #
897
+ # @return [undefined]
898
+ #
899
+ # @api private
900
+ #
901
+ def array_body(body)
106
902
  body.each_with_index do |node, index|
107
- node.lazy_visit self, node
903
+ dispatch(node)
108
904
  emit ', ' unless body.length == index + 1 # last element
109
905
  end
110
- emit ']'
111
906
  end
112
907
 
113
- def hash_literal(node, parent)
908
+ # Emit array literal
909
+ #
910
+ # @param [Rubinius::AST::Node] node
911
+ #
912
+ # @return [undefined]
913
+ #
914
+ # @api private
915
+ #
916
+ def array_literal(node)
917
+ emit('[')
918
+ array_body(node.body)
919
+ emit(']')
920
+ end
921
+
922
+
923
+ # Emit emtpy array literal
924
+ #
925
+ # @param [Rubinius::AST::Node] node
926
+ #
927
+ # @return [undefined]
928
+ #
929
+ # @api private
930
+ #
931
+ def empty_array(node)
932
+ emit('[]')
933
+ end
934
+
935
+ # Emit hash literal
936
+ #
937
+ # @param [Rubinius::AST::Node] node
938
+ #
939
+ # @return [undefined]
940
+ #
941
+ # @api private
942
+ #
943
+ def hash_literal(node)
114
944
  body = node.array.each_slice(2)
115
945
 
116
946
  emit '{'
117
947
  body.each_with_index do |slice, index|
118
948
  key, value = slice
119
949
 
120
- key.lazy_visit self, node
950
+ dispatch(key)
121
951
  emit " => "
122
- value.lazy_visit self, node
952
+ dispatch(value)
123
953
 
124
954
  emit ', ' unless body.to_a.length == index + 1 # last element
125
955
  end
126
956
  emit '}'
127
957
  end
128
958
 
129
- def range(node, parent)
130
- node.start.lazy_visit self, node
959
+ # Emit inclusive range literal
960
+ #
961
+ # @param [Rubinius::AST::Node] node
962
+ #
963
+ # @return [undefined]
964
+ #
965
+ # @api private
966
+ #
967
+ def range(node)
968
+ dispatch(node.start)
131
969
  emit '..'
132
- node.finish.lazy_visit self, node
970
+ dispatch(node.finish)
133
971
  end
134
972
 
135
- def range_exclude(node, parent)
136
- node.start.lazy_visit self, node
973
+ # Emit exlusive range literal
974
+ #
975
+ # @param [Rubinius::AST::Node] node
976
+ #
977
+ # @return [undefined]
978
+ #
979
+ # @api private
980
+ #
981
+ def range_exclude(node)
982
+ dispatch(node.start)
137
983
  emit '...'
138
- node.finish.lazy_visit self, node
984
+ dispatch(node.finish)
139
985
  end
140
986
 
141
- def regex_literal(node, parent)
987
+ # Emit range literal
988
+ #
989
+ # @param [Rubinius::AST::Node] node
990
+ #
991
+ # @return [undefined]
992
+ #
993
+ # @api private
994
+ #
995
+ def regex_literal(node)
142
996
  emit '/'
143
997
  emit node.source
144
998
  emit '/'
145
999
  end
146
1000
 
147
- def send(node, parent)
148
- unless node.receiver.is_a?(Rubinius::AST::Self)
149
- node.receiver.lazy_visit self, node
150
- emit '.'
1001
+
1002
+ # Emit receiver
1003
+ #
1004
+ # @param [Rubinius::AST::Node] node
1005
+ #
1006
+ # @return [true]
1007
+ # returns true if there is an explicit receiver
1008
+ #
1009
+ # @return [false]
1010
+ # returns false otherwise
1011
+ #
1012
+ # @api private
1013
+ #
1014
+ def receiver(node)
1015
+ unless node.receiver.is_a?(Rubinius::AST::Self) and node.privately
1016
+ dispatch(node.receiver)
1017
+ true
1018
+ else
1019
+ false
151
1020
  end
152
- emit node.name
1021
+ end
153
1022
 
154
- if node.block
155
- emit ' '
156
- node.block.lazy_visit self, node if node.block
1023
+ # Emit send literal
1024
+ #
1025
+ # @param [Rubinius::AST::Node] node
1026
+ #
1027
+ # @return [undefined]
1028
+ #
1029
+ # @api private
1030
+ #
1031
+ def send(node)
1032
+ if node.name == :'!'
1033
+ emit('!')
1034
+ dispatch(node.receiver)
1035
+ return
1036
+ end
1037
+
1038
+ if receiver(node)
1039
+ emit('.')
1040
+ end
1041
+
1042
+ emit(node.name)
1043
+
1044
+ block = node.block
1045
+
1046
+ if(block)
1047
+ if block.kind_of?(Rubinius::AST::BlockPass)
1048
+ emit('(')
1049
+ block_pass(block)
1050
+ emit(')')
1051
+ else
1052
+ dispatch(block)
1053
+ end
157
1054
  end
158
1055
  end
159
1056
 
160
- def send_with_arguments(node, parent)
161
- return if process_binary_operator(node, parent) # 1 * 2, a / 3, true && false
1057
+ # Emit arguments
1058
+ #
1059
+ # @param [Rubinius::AST::Node] node
1060
+ #
1061
+ # @return [undefined]
1062
+ #
1063
+ # @api private
1064
+ #
1065
+ def arguments(node, open='(', close=')')
1066
+ arguments = node.arguments
1067
+ array, block = arguments.array, node.block
162
1068
 
1069
+ return if array.empty? and block.nil? and arguments.splat.nil?
1070
+
1071
+ emit(open)
1072
+
1073
+ array_body(array)
1074
+ is_block_pass = block.kind_of?(Rubinius::AST::BlockPass)
1075
+
1076
+ if arguments.splat
1077
+ emit(', ') unless array.empty?
1078
+ dispatch(arguments.splat)
1079
+ end
1080
+
1081
+ if is_block_pass
1082
+ emit(', ') unless array.empty?
1083
+ block_pass(block)
1084
+ end
1085
+
1086
+ emit(close)
1087
+
1088
+ if block and !is_block_pass
1089
+ dispatch(node.block)
1090
+ end
1091
+ end
1092
+
1093
+ # Emit self
1094
+ #
1095
+ # @param [Rubinius::AST::Node] node
1096
+ #
1097
+ # @return [undefined]
1098
+ #
1099
+ # @api private
1100
+ #
1101
+ def self(node)
1102
+ emit('self')
1103
+ end
1104
+
1105
+ # Emit element reference
1106
+ #
1107
+ # @param [Rubinius::AST::Node] node
1108
+ #
1109
+ # @return [undefined]
1110
+ #
1111
+ # @api private
1112
+ #
1113
+ def element_reference(node)
163
1114
  unless node.receiver.is_a?(Rubinius::AST::Self)
164
- node.receiver.lazy_visit self, node
165
- emit '.'
1115
+ dispatch(node.receiver)
1116
+ end
1117
+
1118
+ arguments(node,'[',']')
1119
+ end
1120
+
1121
+ # Emit send with arguments
1122
+ #
1123
+ # @param [Rubinius::AST::Node] node
1124
+ #
1125
+ # @return [undefined]
1126
+ #
1127
+ # @api private
1128
+ #
1129
+ def send_with_arguments(node)
1130
+ if node.name == :[]
1131
+ return element_reference(node)
1132
+ end
1133
+ return if process_binary_operator(node)
1134
+
1135
+ if receiver(node)
1136
+ emit('.')
166
1137
  end
167
1138
 
168
- emit node.name
169
- emit '('
170
- node.arguments.lazy_visit self, node
171
- emit ')'
172
- if node.block
173
- emit ' '
174
- node.block.lazy_visit self, node if node.block
1139
+ emit(node.name)
1140
+
1141
+ arguments(node)
1142
+ end
1143
+
1144
+ # Emit yield
1145
+ #
1146
+ # @param [Rubinius::AST::Node] node
1147
+ #
1148
+ # @return [undefined]
1149
+ #
1150
+ # @api private
1151
+ #
1152
+ def yield(node)
1153
+ emit('yield')
1154
+ arguments(node)
1155
+ end
1156
+
1157
+ # Emit receiver case statment
1158
+ #
1159
+ # @param [Rubinius::AST::Node] node
1160
+ #
1161
+ # @return [undefined]
1162
+ #
1163
+ # @api private
1164
+ #
1165
+ def receiver_case(node)
1166
+ emit('case ')
1167
+ dispatch(node.receiver)
1168
+ nl
1169
+ node.whens.each do |branch|
1170
+ dispatch(branch)
1171
+ end
1172
+ else_body = node.else
1173
+ unless else_body.kind_of?(Rubinius::AST::NilLiteral)
1174
+ emit('else')
1175
+ nl
1176
+ body(else_body)
175
1177
  end
1178
+ kend
176
1179
  end
177
1180
 
178
- def actual_arguments(node, parent)
179
- body = node.array
180
- body.each_with_index do |argument, index|
181
- argument.lazy_visit self, parent
182
- emit ', ' unless body.length == index + 1 # last element
1181
+ # Emit when
1182
+ #
1183
+ # @param [Rubinius::AST::Node] node
1184
+ #
1185
+ # @return [undefined]
1186
+ #
1187
+ # @api private
1188
+ #
1189
+ def when(node)
1190
+ emit('when ')
1191
+ if node.single
1192
+ dispatch(node.single)
1193
+ end
1194
+ if node.conditions
1195
+ array_body(node.conditions.body)
183
1196
  end
1197
+ if node.splat
1198
+ dispatch(node.splat)
1199
+ end
1200
+ nl
1201
+ body(node.body)
1202
+ end
1203
+
1204
+ # Emit splat when
1205
+ #
1206
+ # @param [Rubinius::AST::Node] node
1207
+ #
1208
+ # @return [undefined]
1209
+ #
1210
+ # @api private
1211
+ #
1212
+ def splat_when(node)
1213
+ emit('*')
1214
+ dispatch(node.condition)
184
1215
  end
185
1216
 
186
- def iter_arguments(node, parent)
1217
+ # Emit splat value
1218
+ #
1219
+ # @param [Rubinius::AST::Node] node
1220
+ #
1221
+ # @return [undefined]
1222
+ #
1223
+ # @api private
1224
+ #
1225
+ def splat_value(node)
1226
+ emit('*')
1227
+ dispatch(node.value)
1228
+ end
1229
+
1230
+ # Emit acutal arguments
1231
+ #
1232
+ # @param [Rubinius::AST::Node] node
1233
+ #
1234
+ # @return [undefined]
1235
+ #
1236
+ # @api private
1237
+ #
1238
+ def actual_arguments(node)
1239
+ array_body(node.array)
1240
+ end
1241
+
1242
+ # Emit iteration
1243
+ #
1244
+ # @param [Rubinius::AST::Node] node
1245
+ #
1246
+ # @return [undefined]
1247
+ #
1248
+ # @api private
1249
+ #
1250
+ def iter(node)
1251
+ emit(' do')
1252
+
1253
+ arguments = node.arguments
1254
+ unless arguments.names.empty?
1255
+ emit(' ')
1256
+ iter_arguments(node.arguments)
1257
+ end
1258
+
1259
+ nl
1260
+ body(node.body)
1261
+
1262
+ kend
1263
+ end
1264
+
1265
+ # Emit iteration arguments for ruby18 mode
1266
+ #
1267
+ # @param [Rubinius::AST::Node] node
1268
+ #
1269
+ # @return [undefined]
1270
+ #
1271
+ # @api private
1272
+ #
1273
+ def iter_arguments(node)
187
1274
  body = if node.prelude == :single
188
1275
  Array(node.arguments.name)
189
1276
  else
@@ -198,180 +1285,463 @@ module ToSource
198
1285
  emit '|'
199
1286
  end
200
1287
 
201
- def iter(node, parent)
202
- emit 'do'
203
-
204
- if node.arguments && node.arguments.arity != -1
205
- emit ' '
206
- node.arguments.lazy_visit self, parent
1288
+ # Emit iteration arguments for ruby19 mode
1289
+ #
1290
+ # @param [Rubinius::AST::Node] node
1291
+ #
1292
+ # @return [undefined]
1293
+ #
1294
+ # @api private
1295
+ #
1296
+ def iter19(node)
1297
+ emit(' do')
1298
+
1299
+ arguments = node.arguments
1300
+ unless arguments.names.empty?
1301
+ emit(' ')
1302
+ formal_arguments_generic(node.arguments,'|','|')
207
1303
  end
208
1304
 
209
- emit "\n"
210
- @indentation += 1
211
-
212
- if node.body.is_a?(Rubinius::AST::Block)
213
- node.body.lazy_visit self, parent, true
214
- else
215
- emit current_indentation
216
- node.body.lazy_visit self, parent
217
- end
1305
+ nl
1306
+ body(node.body)
218
1307
 
219
- emit "\n"
220
- emit 'end'
1308
+ kend
221
1309
  end
222
1310
 
223
- def block(node, parent, indent=false)
1311
+ # Emit block
1312
+ #
1313
+ # @param [Rubinius::AST::Node] node
1314
+ #
1315
+ # @return [undefined]
1316
+ #
1317
+ # @api private
1318
+ #
1319
+ def block(node)
224
1320
  body = node.array
225
- body.each_with_index do |expression, index|
226
- emit current_indentation if indent
227
- expression.lazy_visit self, parent
228
- emit "\n" unless body.length == index + 1 # last element
1321
+ body.each_with_index do |expression,index|
1322
+ emit(current_indentation)
1323
+ dispatch(expression)
1324
+ nl unless body.length == index+1
229
1325
  end
230
1326
  end
231
1327
 
232
- def not(node, parent)
233
- emit '!'
234
- node.value.lazy_visit self, parent
1328
+ # Emit not
1329
+ #
1330
+ # @param [Rubinius::AST::Node] node
1331
+ #
1332
+ # @return [undefined]
1333
+ #
1334
+ # @api private
1335
+ #
1336
+ def not(node)
1337
+ emit('!')
1338
+ dispatch(node.value)
235
1339
  end
236
1340
 
237
- def and(node, parent)
238
- node.left.lazy_visit self, node
239
- emit ' && '
240
- node.right.lazy_visit self, node
1341
+ # Emit and
1342
+ #
1343
+ # @param [Rubinius::AST::Node] node
1344
+ #
1345
+ # @return [undefined]
1346
+ #
1347
+ # @api private
1348
+ #
1349
+ def and(node)
1350
+ dispatch(node.left)
1351
+ emit(' && ')
1352
+ dispatch(node.right)
241
1353
  end
242
1354
 
243
- def or(node, parent)
244
- node.left.lazy_visit self, node
245
- emit ' || '
246
- node.right.lazy_visit self, node
1355
+ # Emit or
1356
+ #
1357
+ # @param [Rubinius::AST::Node] node
1358
+ #
1359
+ # @return [undefined]
1360
+ #
1361
+ # @api private
1362
+ #
1363
+ def or(node)
1364
+ dispatch(node.left)
1365
+ emit(' || ')
1366
+ dispatch(node.right)
247
1367
  end
248
1368
 
249
- def op_assign_and(node, parent)
250
- node.left.lazy_visit self, node
251
- emit ' && '
252
- node.right.lazy_visit self, node
1369
+ # Emit and operation with assignment
1370
+ #
1371
+ # @param [Rubinius::AST::Node] node
1372
+ #
1373
+ # @return [undefined]
1374
+ #
1375
+ # @api private
1376
+ #
1377
+ def op_assign_and(node)
1378
+ dispatch(node.left)
1379
+ emit(' && ')
1380
+ dispatch(node.right)
253
1381
  end
254
1382
 
255
- def op_assign_or(node, parent)
256
- node.left.lazy_visit self, node
257
- emit ' || '
258
- node.right.lazy_visit self, node
1383
+ # Emit or operation with assignment
1384
+ #
1385
+ # @param [Rubinius::AST::Node] node
1386
+ #
1387
+ # @return [undefined]
1388
+ #
1389
+ # @api private
1390
+ #
1391
+ def op_assign_or(node)
1392
+ dispatch(node.left)
1393
+ emit(' || ')
1394
+ dispatch(node.right)
259
1395
  end
260
-
261
- def toplevel_constant(node, parent)
262
- emit "::"
263
- emit node.name
1396
+ alias_method :op_assign_or19, :op_assign_or
1397
+
1398
+ # Emit toplevel constant
1399
+ #
1400
+ # @param [Rubinius::AST::Node] node
1401
+ #
1402
+ # @return [undefined]
1403
+ #
1404
+ # @api private
1405
+ #
1406
+ def toplevel_constant(node)
1407
+ emit('::')
1408
+ emit(node.name)
264
1409
  end
265
1410
 
266
- def constant_access(node, parent)
267
- emit node.name
1411
+ # Emit constant accesws
1412
+ #
1413
+ # @param [Rubinius::AST::Node] node
1414
+ #
1415
+ # @return [undefined]
1416
+ #
1417
+ # @api private
1418
+ #
1419
+ def constant_access(node)
1420
+ emit(node.name)
268
1421
  end
269
1422
 
270
- def scoped_constant(node, parent)
271
- node.parent.lazy_visit self, node
272
- emit '::'
273
- emit node.name
1423
+ # Emit scoped constant
1424
+ #
1425
+ # @param [Rubinius::AST::Node] node
1426
+ #
1427
+ # @return [undefined]
1428
+ #
1429
+ # @api private
1430
+ #
1431
+ def scoped_constant(node)
1432
+ dispatch(node.parent)
1433
+ emit('::')
1434
+ emit(node.name)
1435
+ end
1436
+ alias_method :scoped_class_name, :scoped_constant
1437
+ alias_method :scoped_module_name, :scoped_constant
1438
+
1439
+ # Emit toplevel class name
1440
+ #
1441
+ # @param [Rubinius::AST::Node] node
1442
+ #
1443
+ # @return [undefined]
1444
+ #
1445
+ # @api private
1446
+ #
1447
+ def toplevel_class_name(node)
1448
+ emit("::#{node.name}")
274
1449
  end
275
1450
 
276
- def if(node, parent)
1451
+ # Emit if expression
1452
+ #
1453
+ # @param [Rubinius::AST::Node] node
1454
+ #
1455
+ # @return [undefined]
1456
+ #
1457
+ # @api private
1458
+ #
1459
+ def if(node)
277
1460
  body, else_body = node.body, node.else
1461
+
278
1462
  keyword = 'if'
279
1463
 
280
1464
  if node.body.is_a?(Rubinius::AST::NilLiteral) && !node.else.is_a?(Rubinius::AST::NilLiteral)
281
-
282
1465
  body, else_body = else_body, body
283
1466
  keyword = 'unless'
284
1467
  end
285
1468
 
286
- emit keyword << ' '
287
- node.condition.lazy_visit self, node
288
- emit "\n"
1469
+ emit(keyword)
1470
+ emit(' ')
1471
+ dispatch(node.condition)
1472
+ nl
289
1473
 
290
- @indentation += 1
291
-
292
- if body.is_a?(Rubinius::AST::Block)
293
- body.lazy_visit self, parent, true
294
- else
295
- emit current_indentation
296
- body.lazy_visit self, parent
297
- end
298
-
299
- emit "\n"
1474
+ body(body)
300
1475
 
301
1476
  if else_body.is_a?(Rubinius::AST::NilLiteral)
302
- emit 'end'
1477
+ kend
303
1478
  return
304
1479
  end
305
1480
 
306
- emit "else\n"
1481
+ emit('else')
1482
+ nl
307
1483
 
308
- if else_body.is_a?(Rubinius::AST::Block)
309
- else_body.lazy_visit self, parent, true
310
- else
311
- emit current_indentation
312
- else_body.lazy_visit self, parent
313
- end
1484
+ body(else_body)
314
1485
 
315
- emit "\n"
316
- emit 'end'
1486
+ kend
317
1487
  end
318
1488
 
319
- def while(node, parent)
1489
+ # Dispatch node
1490
+ #
1491
+ # @param [Rubinius::AST::Node] node
1492
+ #
1493
+ # @return [undefined]
1494
+ #
1495
+ # @api private
1496
+ #
1497
+ def while(node)
320
1498
  emit 'while '
321
- node.condition.lazy_visit self, node
322
- emit "\n"
1499
+ dispatch(node.condition)
1500
+ nl
323
1501
 
324
- @indentation += 1
1502
+ body(node.body)
325
1503
 
326
- if node.body.is_a?(Rubinius::AST::Block)
327
- node.body.lazy_visit self, parent, true
328
- else
329
- emit current_indentation
330
- node.body.lazy_visit self, parent
1504
+ kend
1505
+ end
1506
+
1507
+ # Emit until
1508
+ #
1509
+ # @param [Rubinius::AST::Node] node
1510
+ #
1511
+ # @return [undefined]
1512
+ #
1513
+ # @api private
1514
+ #
1515
+ def until(node)
1516
+ emit 'until '
1517
+ dispatch(node.condition)
1518
+ nl
1519
+
1520
+ body(node.body)
1521
+
1522
+ kend
1523
+ end
1524
+
1525
+ # Emit formal arguments as shared between ruby18 and ruby19 mode
1526
+ #
1527
+ # @param [Rubinius::AST::Node] node
1528
+ #
1529
+ # @return [undefined]
1530
+ #
1531
+ # @api private
1532
+ #
1533
+ def formal_arguments_generic(node,open,close)
1534
+ return if node.names.empty?
1535
+ required, defaults, splat = node.required, node.defaults, node.splat
1536
+
1537
+ emit(open)
1538
+ emit(required.join(', '))
1539
+
1540
+ empty = required.empty?
1541
+
1542
+ if defaults
1543
+ emit(', ') unless empty
1544
+ dispatch(node.defaults)
1545
+ end
1546
+
1547
+ if splat
1548
+ emit(', ') unless empty
1549
+ emit('*')
1550
+ unless splat == :@unnamed_splat
1551
+ emit(splat)
1552
+ end
331
1553
  end
332
1554
 
333
- emit "\n"
334
- emit "end"
1555
+ if node.block_arg
1556
+ emit(', ') unless empty
1557
+
1558
+ dispatch(node.block_arg)
1559
+ end
1560
+
1561
+ emit(close)
335
1562
  end
336
1563
 
337
- def until(node, parent)
338
- emit 'until '
339
- node.condition.lazy_visit self, node
340
- emit "\n"
1564
+ # Emit formal arguments for ruby19 and ruby18
1565
+ #
1566
+ # @param [Rubinius::AST::Node] node
1567
+ #
1568
+ # @return [undefined]
1569
+ #
1570
+ # @api private
1571
+ #
1572
+ def formal_arguments(node)
1573
+ formal_arguments_generic(node,'(',')')
1574
+ end
1575
+ alias_method :formal_arguments19, :formal_arguments
1576
+
1577
+ # Emit block argument
1578
+ #
1579
+ # @param [Rubinius::AST::Node] node
1580
+ #
1581
+ # @return [undefined]
1582
+ #
1583
+ # @api private
1584
+ #
1585
+ def block_argument(node)
1586
+ emit('&')
1587
+ emit(node.name)
1588
+ end
341
1589
 
342
- @indentation += 1
1590
+ # Emit default arguments
1591
+ #
1592
+ # @param [Rubinius::AST::Node] node
1593
+ #
1594
+ # @return [undefined]
1595
+ #
1596
+ # @api private
1597
+ #
1598
+ def default_arguments(node)
1599
+ last = node.arguments.length - 1
1600
+ node.arguments.each_with_index do |argument, index|
1601
+ dispatch(argument)
1602
+ emit(',') unless index == last
1603
+ end
1604
+ end
343
1605
 
344
- if node.body.is_a?(Rubinius::AST::Block)
345
- node.body.lazy_visit self, parent, true
1606
+ # Emit begin
1607
+ #
1608
+ # @param [Rubinius::AST::Node] node
1609
+ #
1610
+ # @return [undefined]
1611
+ #
1612
+ # @api private
1613
+ #
1614
+ def begin(node)
1615
+ emit('begin')
1616
+ nl
1617
+
1618
+ body = node.rescue
1619
+ case body
1620
+ when Rubinius::AST::Rescue
1621
+ # Rescue is reserved keyword
1622
+ __send__(:rescue,body)
1623
+ when Rubinius::AST::Ensure
1624
+ # Ensure is reserved keyword
1625
+ __send__(:ensure,body)
346
1626
  else
347
- emit current_indentation
348
- node.body.lazy_visit self, parent
1627
+ body(node.rescue)
349
1628
  end
350
1629
 
351
- emit "\n"
352
- emit "end"
1630
+ kend
353
1631
  end
354
1632
 
355
- def return(node, parent)
356
- emit 'return '
357
- node.value.lazy_visit self, parent
1633
+ # Emit define on instances
1634
+ #
1635
+ # @param [Rubinius::AST::Node] node
1636
+ #
1637
+ # @return [undefined]
1638
+ #
1639
+ # @api private
1640
+ #
1641
+ def define(node)
1642
+ emit('def ')
1643
+
1644
+ emit(node.name)
1645
+ dispatch(node.arguments)
1646
+ nl
1647
+
1648
+ body(node.body)
1649
+ kend
358
1650
  end
359
1651
 
360
- private
1652
+ # Emit define on singletons
1653
+ #
1654
+ # @param [Rubinius::AST::Node] node
1655
+ #
1656
+ # @return [undefined]
1657
+ #
1658
+ # @api private
1659
+ #
1660
+ def define_singleton(node)
1661
+ emit('def ')
1662
+ dispatch(node.receiver)
1663
+ emit('.')
1664
+ dispatch(node.body)
1665
+ end
361
1666
 
362
- def process_binary_operator(node, parent)
363
- operators = %w(+ - * / & | <<).map(&:to_sym)
364
- return false unless operators.include?(node.name)
365
- return false if node.arguments.array.length != 1
1667
+ # Emit singleton scope
1668
+ #
1669
+ # @param [Rubinius::AST::Node] node
1670
+ #
1671
+ # @return [undefined]
1672
+ #
1673
+ # @api private
1674
+ #
1675
+ def define_singleton_scope(node)
1676
+ emit(node.name)
1677
+ dispatch(node.arguments)
1678
+ nl
1679
+
1680
+ body(node.body)
1681
+
1682
+ kend
1683
+ end
366
1684
 
367
- operand = node.arguments.array[0]
1685
+ # Emit block pass
1686
+ #
1687
+ # @param [Rubinius::AST::Node] node
1688
+ #
1689
+ # @return [undefined]
1690
+ #
1691
+ # @api private
1692
+ #
1693
+ def block_pass(node)
1694
+ emit('&')
1695
+ dispatch(node.body)
1696
+ end
368
1697
 
369
- unless node.receiver.is_a?(Rubinius::AST::Self)
370
- node.receiver.lazy_visit self, node
1698
+ # Emit return statement
1699
+ #
1700
+ # @param [Rubinius::AST::Node] node
1701
+ #
1702
+ # @return [undefined]
1703
+ #
1704
+ # @api private
1705
+ #
1706
+ def return(node)
1707
+ emit('return')
1708
+ if node.value
1709
+ emit(' ')
1710
+ dispatch(node.value)
371
1711
  end
1712
+ end
1713
+
1714
+ OPERATORS = %w(
1715
+ + - * / & | && || << >> ==
1716
+ === != <= < <=> > >= =~ !~ ^
1717
+ **
1718
+ ).map(&:to_sym).to_set
1719
+
1720
+ # Process binary operator
1721
+ #
1722
+ # @param [Rubinius::AST::Node] node
1723
+ #
1724
+ # @return [self]
1725
+ # if node was handled
1726
+ #
1727
+ # @return [nil]
1728
+ # otherwise
1729
+ #
1730
+ # @api private
1731
+ #
1732
+ def process_binary_operator(node)
1733
+ name = node.name
1734
+ return unless OPERATORS.include?(name)
1735
+ return if node.arguments.array.length != 1
1736
+
1737
+ operand = node.arguments.array[0]
1738
+
1739
+ dispatch(node.receiver)
1740
+
1741
+ emit(" #{name.to_s} ")
1742
+ dispatch(operand)
372
1743
 
373
- emit ' ' << node.name.to_s << ' '
374
- operand.lazy_visit self, node
1744
+ self
375
1745
  end
376
1746
  end
377
1747
  end