to_source 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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