unparser 0.4.7 → 0.6.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +40 -9
  3. data/bin/unparser +2 -2
  4. data/lib/unparser/abstract_type.rb +121 -0
  5. data/lib/unparser/adamantium/method_builder.rb +111 -0
  6. data/lib/unparser/adamantium.rb +150 -0
  7. data/lib/unparser/anima/attribute.rb +59 -0
  8. data/lib/unparser/anima/error.rb +23 -0
  9. data/lib/unparser/anima.rb +184 -0
  10. data/lib/unparser/ast/local_variable_scope.rb +6 -76
  11. data/lib/unparser/ast.rb +1 -3
  12. data/lib/unparser/buffer.rb +14 -25
  13. data/lib/unparser/cli.rb +85 -77
  14. data/lib/unparser/{cli/color.rb → color.rb} +4 -14
  15. data/lib/unparser/comments.rb +0 -26
  16. data/lib/unparser/concord.rb +114 -0
  17. data/lib/unparser/constants.rb +4 -53
  18. data/lib/unparser/diff.rb +98 -0
  19. data/lib/unparser/dsl.rb +0 -32
  20. data/lib/unparser/either.rb +153 -0
  21. data/lib/unparser/emitter/alias.rb +2 -8
  22. data/lib/unparser/emitter/args.rb +45 -0
  23. data/lib/unparser/emitter/argument.rb +13 -169
  24. data/lib/unparser/emitter/array.rb +27 -0
  25. data/lib/unparser/emitter/array_pattern.rb +29 -0
  26. data/lib/unparser/emitter/assignment.rb +36 -127
  27. data/lib/unparser/emitter/begin.rb +9 -84
  28. data/lib/unparser/emitter/binary.rb +7 -20
  29. data/lib/unparser/emitter/block.rb +57 -41
  30. data/lib/unparser/emitter/case.rb +6 -48
  31. data/lib/unparser/emitter/case_guard.rb +27 -0
  32. data/lib/unparser/emitter/case_match.rb +40 -0
  33. data/lib/unparser/emitter/cbase.rb +1 -3
  34. data/lib/unparser/emitter/class.rb +6 -26
  35. data/lib/unparser/emitter/const_pattern.rb +24 -0
  36. data/lib/unparser/emitter/def.rb +7 -51
  37. data/lib/unparser/emitter/defined.rb +2 -12
  38. data/lib/unparser/emitter/dstr.rb +22 -0
  39. data/lib/unparser/emitter/dsym.rb +41 -0
  40. data/lib/unparser/emitter/find_pattern.rb +18 -0
  41. data/lib/unparser/emitter/flipflop.rb +11 -10
  42. data/lib/unparser/emitter/float.rb +29 -0
  43. data/lib/unparser/emitter/flow_modifier.rb +15 -53
  44. data/lib/unparser/emitter/for.rb +5 -19
  45. data/lib/unparser/emitter/hash.rb +36 -0
  46. data/lib/unparser/emitter/hash_pattern.rb +67 -0
  47. data/lib/unparser/emitter/hookexe.rb +5 -11
  48. data/lib/unparser/emitter/if.rb +15 -71
  49. data/lib/unparser/emitter/in_match.rb +21 -0
  50. data/lib/unparser/emitter/in_pattern.rb +36 -0
  51. data/lib/unparser/emitter/index.rb +22 -89
  52. data/lib/unparser/emitter/kwargs.rb +13 -0
  53. data/lib/unparser/emitter/kwbegin.rb +31 -0
  54. data/lib/unparser/emitter/lambda.rb +0 -8
  55. data/lib/unparser/emitter/masgn.rb +20 -0
  56. data/lib/unparser/emitter/match.rb +3 -17
  57. data/lib/unparser/emitter/match_alt.rb +23 -0
  58. data/lib/unparser/emitter/match_as.rb +21 -0
  59. data/lib/unparser/emitter/match_pattern.rb +30 -0
  60. data/lib/unparser/emitter/match_pattern_p.rb +20 -0
  61. data/lib/unparser/emitter/match_rest.rb +33 -0
  62. data/lib/unparser/emitter/match_var.rb +19 -0
  63. data/lib/unparser/emitter/mlhs.rb +40 -0
  64. data/lib/unparser/emitter/module.rb +3 -9
  65. data/lib/unparser/emitter/op_assign.rb +14 -29
  66. data/lib/unparser/emitter/pair.rb +33 -0
  67. data/lib/unparser/emitter/pin.rb +19 -0
  68. data/lib/unparser/emitter/primitive.rb +93 -0
  69. data/lib/unparser/emitter/range.rb +35 -0
  70. data/lib/unparser/emitter/regexp.rb +35 -0
  71. data/lib/unparser/emitter/repetition.rb +17 -57
  72. data/lib/unparser/emitter/rescue.rb +1 -97
  73. data/lib/unparser/emitter/root.rb +17 -1
  74. data/lib/unparser/emitter/send.rb +10 -219
  75. data/lib/unparser/emitter/simple.rb +33 -0
  76. data/lib/unparser/emitter/splat.rb +13 -19
  77. data/lib/unparser/emitter/super.rb +1 -29
  78. data/lib/unparser/emitter/undef.rb +1 -9
  79. data/lib/unparser/emitter/variable.rb +1 -31
  80. data/lib/unparser/emitter/xstr.rb +72 -0
  81. data/lib/unparser/emitter/yield.rb +1 -9
  82. data/lib/unparser/emitter.rb +24 -425
  83. data/lib/unparser/equalizer.rb +98 -0
  84. data/lib/unparser/generation.rb +252 -0
  85. data/lib/unparser/node_details/send.rb +65 -0
  86. data/lib/unparser/node_details.rb +21 -0
  87. data/lib/unparser/node_helpers.rb +48 -6
  88. data/lib/unparser/validation.rb +172 -0
  89. data/lib/unparser/writer/binary.rb +99 -0
  90. data/lib/unparser/writer/dynamic_string.rb +211 -0
  91. data/lib/unparser/writer/resbody.rb +40 -0
  92. data/lib/unparser/writer/rescue.rb +43 -0
  93. data/lib/unparser/{emitter → writer}/send/attribute_assignment.rb +11 -26
  94. data/lib/unparser/writer/send/binary.rb +27 -0
  95. data/lib/unparser/writer/send/conditional.rb +25 -0
  96. data/lib/unparser/writer/send/regular.rb +33 -0
  97. data/lib/unparser/{emitter → writer}/send/unary.rb +10 -17
  98. data/lib/unparser/writer/send.rb +115 -0
  99. data/lib/unparser/writer.rb +15 -0
  100. data/lib/unparser.rb +161 -77
  101. metadata +100 -157
  102. data/.circleci/config.yml +0 -49
  103. data/.gitignore +0 -37
  104. data/.rspec +0 -4
  105. data/.rubocop.yml +0 -9
  106. data/Changelog.md +0 -156
  107. data/Gemfile +0 -9
  108. data/Gemfile.lock +0 -181
  109. data/LICENSE +0 -20
  110. data/Rakefile +0 -22
  111. data/config/devtools.yml +0 -2
  112. data/config/flay.yml +0 -3
  113. data/config/flog.yml +0 -2
  114. data/config/mutant.yml +0 -6
  115. data/config/reek.yml +0 -98
  116. data/config/rubocop.yml +0 -122
  117. data/config/yardstick.yml +0 -2
  118. data/lib/unparser/cli/differ.rb +0 -152
  119. data/lib/unparser/cli/source.rb +0 -267
  120. data/lib/unparser/emitter/empty.rb +0 -23
  121. data/lib/unparser/emitter/ensure.rb +0 -37
  122. data/lib/unparser/emitter/literal/array.rb +0 -29
  123. data/lib/unparser/emitter/literal/dynamic.rb +0 -53
  124. data/lib/unparser/emitter/literal/dynamic_body.rb +0 -132
  125. data/lib/unparser/emitter/literal/execute_string.rb +0 -38
  126. data/lib/unparser/emitter/literal/hash.rb +0 -156
  127. data/lib/unparser/emitter/literal/primitive.rb +0 -145
  128. data/lib/unparser/emitter/literal/range.rb +0 -36
  129. data/lib/unparser/emitter/literal/regexp.rb +0 -114
  130. data/lib/unparser/emitter/literal/singleton.rb +0 -26
  131. data/lib/unparser/emitter/literal.rb +0 -10
  132. data/lib/unparser/emitter/meta.rb +0 -16
  133. data/lib/unparser/emitter/redo.rb +0 -25
  134. data/lib/unparser/emitter/resbody.rb +0 -76
  135. data/lib/unparser/emitter/retry.rb +0 -25
  136. data/lib/unparser/emitter/send/binary.rb +0 -57
  137. data/lib/unparser/emitter/send/conditional.rb +0 -40
  138. data/lib/unparser/emitter/send/regular.rb +0 -40
  139. data/lib/unparser/preprocessor.rb +0 -159
  140. data/spec/integration/unparser/corpus_spec.rb +0 -111
  141. data/spec/integrations.yml +0 -92
  142. data/spec/spec_helper.rb +0 -20
  143. data/spec/unit/unparser/buffer/append_spec.rb +0 -24
  144. data/spec/unit/unparser/buffer/append_without_prefix_spec.rb +0 -23
  145. data/spec/unit/unparser/buffer/capture_content_spec.rb +0 -17
  146. data/spec/unit/unparser/buffer/content_spec.rb +0 -38
  147. data/spec/unit/unparser/buffer/fresh_line_spec.rb +0 -20
  148. data/spec/unit/unparser/buffer/indent_spec.rb +0 -20
  149. data/spec/unit/unparser/buffer/nl_spec.rb +0 -16
  150. data/spec/unit/unparser/buffer/unindent_spec.rb +0 -20
  151. data/spec/unit/unparser/comments/consume_spec.rb +0 -22
  152. data/spec/unit/unparser/comments/take_all_spec.rb +0 -19
  153. data/spec/unit/unparser/comments/take_before_spec.rb +0 -46
  154. data/spec/unit/unparser/comments/take_eol_comments_spec.rb +0 -32
  155. data/spec/unit/unparser/emitter/class_methods/handle_spec.rb +0 -17
  156. data/spec/unit/unparser_spec.rb +0 -1849
  157. data/unparser.gemspec +0 -32
@@ -4,109 +4,13 @@ module Unparser
4
4
  class Emitter
5
5
  # Emitter for rescue nodes
6
6
  class Rescue < self
7
- include Unterminated
8
-
9
7
  handle :rescue
10
8
 
11
- children :body, :rescue_body
12
-
13
- define_group :rescue_bodies, 1..-2
14
-
15
- EMBEDDED_TYPES = %i[block def defs kwbegin ensure].to_set.freeze
16
-
17
- NOINDENT_STANDALONE_RESCUE = %i[root begin pair_rocket pair_colon lvasgn ivasgn].to_set.freeze
18
-
19
9
  private
20
10
 
21
- # Perform dispatch
22
- #
23
- # @return [undefined]
24
- #
25
- # @api private
26
- #
27
11
  def dispatch
28
- if standalone?
29
- if NOINDENT_STANDALONE_RESCUE.include?(parent_type)
30
- emit_standalone
31
- else
32
- indented { emit_standalone }
33
- end
34
- else
35
- emit_embedded
36
- end
37
- end
38
-
39
- # Test if rescue node ist standalone
40
- #
41
- # @return [Boolean]
42
- #
43
- # @api private
44
- #
45
- def standalone?
46
- if parent_type.equal?(:ensure)
47
- !parent.node.children.first.equal?(node)
48
- else
49
- !EMBEDDED_TYPES.include?(parent_type)
50
- end
51
- end
52
-
53
- # Emit standalone form
54
- #
55
- # @return [undefined]
56
- #
57
- # @api private
58
- #
59
- def emit_standalone
60
- visit_plain(body)
61
- ws
62
- run(Resbody::Standalone, rescue_body)
12
+ emit_rescue_postcontrol(node)
63
13
  end
64
-
65
- # Emit embedded form
66
- #
67
- # @return [undefined]
68
- #
69
- # @api private
70
- #
71
- def emit_embedded
72
- if body
73
- visit_indented(body)
74
- else
75
- nl
76
- end
77
- rescue_bodies.each do |child|
78
- run(Resbody::Embedded, child)
79
- end
80
- emit_else
81
- end
82
-
83
- # Emit else
84
- #
85
- # @return [undefined]
86
- #
87
- # @api private
88
- #
89
- def emit_else
90
- return unless else_branch
91
-
92
- write(K_ELSE)
93
- visit_indented(else_branch)
94
- end
95
-
96
- # Return else body
97
- #
98
- # @return [Parser::AST::Node]
99
- # if else body is present
100
- #
101
- # @return [nil]
102
- # otherwise
103
- #
104
- # @api private
105
- #
106
- def else_branch
107
- children.last
108
- end
109
-
110
14
  end # Rescue
111
15
  end # Emitter
112
16
  end # Unparser
@@ -4,8 +4,24 @@ module Unparser
4
4
  class Emitter
5
5
  # Root emitter a special case
6
6
  class Root < self
7
- include Concord::Public.new(:node, :buffer, :comments)
7
+ include Concord::Public.new(:buffer, :node, :comments)
8
8
  include LocalVariableRoot
9
+
10
+ END_NL = %i[class sclass module begin].freeze
11
+
12
+ private_constant(*constants(false))
13
+
14
+ def dispatch
15
+ if children.any?
16
+ emit_body(node, indent: false)
17
+ else
18
+ visit_deep(node)
19
+ end
20
+
21
+ emit_eof_comments
22
+
23
+ nl if END_NL.include?(node.type) && !buffer.fresh_line?
24
+ end
9
25
  end # Root
10
26
  end # Emitter
11
27
  end # Unparser
@@ -3,236 +3,27 @@
3
3
  module Unparser
4
4
  class Emitter
5
5
  # Emitter for send
6
- # ignore :reek:TooManyMethods
7
6
  class Send < self
7
+ handle :csend, :send
8
8
 
9
- handle :send
10
-
11
- ASSIGN_SUFFIX = '='.freeze
12
- INDEX_ASSIGN = :'[]='
13
- INDEX_REFERENCE = :'[]'
14
- NON_ASSIGN_RANGE = (0..-2).freeze
15
-
16
- children :receiver, :selector
9
+ def emit_mlhs
10
+ writer.emit_mlhs
11
+ end
17
12
 
18
- def terminated?
19
- effective_emitter.terminated?
13
+ def emit_heredoc_reminders
14
+ writer.emit_heredoc_reminders
20
15
  end
21
16
 
22
17
  private
23
18
 
24
- # Perform dispatch
25
- #
26
- # @return [undefined]
27
- #
28
- # @api private
29
- #
30
19
  def dispatch
31
- effective_emitter.write_to_buffer
32
- end
33
-
34
- # Return effective emitter
35
- #
36
- # @return [Emitter]
37
- #
38
- # @api private
39
- #
40
- def effective_emitter
41
- effective_emitter_class.new(node, parent)
42
- end
43
-
44
- # Return effective emitter
45
- #
46
- # @return [Class:Emitter]
47
- #
48
- # @api private
49
- #
50
- def effective_emitter_class
51
- if binary_operator?
52
- Binary
53
- elsif unary_operator?
54
- Unary
55
- elsif attribute_assignment?
56
- AttributeAssignment
57
- else
58
- Regular
59
- end
60
- end
61
-
62
- # Return string selector
63
- #
64
- # @return [String]
65
- #
66
- # @api private
67
- #
68
- def string_selector
69
- selector.to_s
70
- end
71
-
72
- # Test for unary operator implemented as method
73
- #
74
- # @return [Boolean]
75
- #
76
- # @api private
77
- #
78
- def unary_operator?
79
- UNARY_OPERATORS.include?(selector)
80
- end
81
-
82
- # Test for binary operator implemented as method
83
- #
84
- # @return [Boolean]
85
- #
86
- # @api private
87
- #
88
- def binary_operator?
89
- BINARY_OPERATORS.include?(selector) && arguments.one? && !arguments.first.type.equal?(:splat)
90
- end
91
-
92
- # Emit selector
93
- #
94
- # @return [undefined]
95
- #
96
- # @api private
97
- #
98
- def emit_selector
99
- write(mlhs? ? non_assignment_selector : string_selector)
100
- end
101
-
102
- # Test for mlhs
103
- #
104
- # @return [Boolean]
105
- #
106
- # @api private
107
- #
108
- def mlhs?
109
- parent_type.equal?(:mlhs)
110
- end
111
-
112
- # Test for assignment
113
- #
114
- # FIXME: This also returns true for <= operator!
115
- #
116
- # @return [Boolean]
117
- #
118
- # @api private
119
- #
120
- def assignment?
121
- string_selector[-1].eql?(ASSIGN_SUFFIX)
122
- end
123
-
124
- # Test for attribute assignment
125
- #
126
- # @return [Boolean]
127
- #
128
- # @api private
129
- #
130
- def attribute_assignment?
131
- !BINARY_OPERATORS.include?(selector) && !UNARY_OPERATORS.include?(selector) && assignment? && !mlhs?
132
- end
133
-
134
- # Test for empty arguments
135
- #
136
- # @return [Boolean]
137
- #
138
- # @api private
139
- #
140
- def arguments?
141
- arguments.any?
142
- end
143
-
144
- # Return argument nodes
145
- #
146
- # @return [Array<Parser::AST::Node>]
147
- #
148
- # @api private
149
- #
150
- def arguments
151
- children[2..-1]
152
- end
153
- memoize :arguments
154
-
155
- # Emit arguments
156
- #
157
- # @return [undefined]
158
- #
159
- # @api private
160
- #
161
- def emit_arguments
162
- if arguments.empty?
163
- write('()') if receiver.nil? && avoid_clash?
164
- else
165
- normal_arguments
166
- end
167
- end
168
-
169
- # Emit normal arguments
170
- #
171
- # @return [undefined]
172
- #
173
- # @api private
174
- #
175
- def normal_arguments
176
- parentheses do
177
- delimited_plain(effective_arguments)
178
- end
179
- end
180
-
181
- # The effective arguments
182
- #
183
- # @return [Parser::AST::Node]
184
- #
185
- # @api private
186
- #
187
- def effective_arguments
188
- last = arguments.length - 1
189
- arguments.each_with_index.map do |argument, index|
190
- if last.equal?(index) && argument.type.equal?(:hash) && argument.children.any?
191
- argument.updated(:hash_body)
192
- else
193
- argument
194
- end
195
- end
196
- end
197
-
198
- # Test if clash with local variable or constant needs to be avoided
199
- #
200
- # @return [Boolean]
201
- #
202
- # @api private
203
- #
204
- def avoid_clash?
205
- local_variable_clash? || parses_as_constant?
206
- end
207
-
208
- # Test for local variable clash
209
- #
210
- # @return [Boolean]
211
- #
212
- # @api private
213
- #
214
- def local_variable_clash?
215
- local_variable_scope.local_variable_defined_for_node?(node, selector)
216
- end
217
-
218
- # The non assignment selector
219
- #
220
- # @return [String]
221
- #
222
- # @api private
223
- def non_assignment_selector
224
- string_selector[NON_ASSIGN_RANGE]
20
+ writer.dispatch
225
21
  end
226
22
 
227
- # Test if selector parses as constant
228
- #
229
- # @return [Boolean]
230
- #
231
- # @api private
232
- #
233
- def parses_as_constant?
234
- Unparser.parse(selector.to_s).type.equal?(:const)
23
+ def writer
24
+ writer_with(Writer::Send, node)
235
25
  end
26
+ memoize :writer
236
27
  end # Send
237
28
  end # Emitter
238
29
  end # Unparser
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ class Emitter
5
+ # Emitter for simple nodes that generate a single token
6
+ class Simple < self
7
+ MAP = {
8
+ __ENCODING__: '__ENCODING__',
9
+ __FILE__: '__FILE__',
10
+ __LINE__: '__LINE__',
11
+ false: 'false',
12
+ forward_arg: '...',
13
+ forwarded_args: '...',
14
+ kwnilarg: '**nil',
15
+ match_nil_pattern: '**nil',
16
+ nil: 'nil',
17
+ redo: 'redo',
18
+ retry: 'retry',
19
+ self: 'self',
20
+ true: 'true',
21
+ zsuper: 'super'
22
+ }.freeze
23
+
24
+ handle(*MAP.keys)
25
+
26
+ private
27
+
28
+ def dispatch
29
+ write(MAP.fetch(node_type))
30
+ end
31
+ end # Simple
32
+ end # Emitter
33
+ end # Unparser
@@ -4,46 +4,40 @@ module Unparser
4
4
  class Emitter
5
5
  # Emitter for splats
6
6
  class KwSplat < self
7
- include Terminated
8
-
9
7
  handle :kwsplat
10
8
 
11
9
  children :subject
12
10
 
13
11
  private
14
12
 
15
- # Perform dispatch
16
- #
17
- # @return [undefined]
18
- #
19
- # @api private
20
- #
21
13
  def dispatch
22
- write(T_SPLAT, T_SPLAT)
14
+ write('**')
23
15
  visit(subject)
24
16
  end
25
17
  end
26
18
 
27
19
  # Emitter for splats
28
20
  class Splat < self
29
- include Terminated
30
-
31
21
  handle :splat
32
22
 
33
23
  children :subject
34
24
 
25
+ def emit_mlhs
26
+ write('*')
27
+ subject_emitter.emit_mlhs if subject
28
+ end
29
+
35
30
  private
36
31
 
37
- # Perform dispatch
38
- #
39
- # @return [undefined]
40
- #
41
- # @api private
42
- #
43
32
  def dispatch
44
- write(T_SPLAT)
45
- visit(subject) if subject
33
+ write('*')
34
+ subject_emitter.write_to_buffer
35
+ end
36
+
37
+ def subject_emitter
38
+ emitter(subject)
46
39
  end
40
+ memoize :subject_emitter
47
41
  end
48
42
  end
49
43
  end # Unparser
@@ -3,42 +3,14 @@
3
3
  module Unparser
4
4
  class Emitter
5
5
 
6
- # Emitter for zsuper nodes
7
- class ZSuper < self
8
- include Terminated
9
-
10
- handle :zsuper
11
-
12
- private
13
-
14
- # Perform dispatch
15
- #
16
- # @return [undefined]
17
- #
18
- # @api private
19
- #
20
- def dispatch
21
- write(K_SUPER)
22
- end
23
-
24
- end # ZSuper
25
-
26
6
  # Emitter for super nodes
27
7
  class Super < self
28
- include Terminated
29
-
30
8
  handle :super
31
9
 
32
10
  private
33
11
 
34
- # Perform dispatch
35
- #
36
- # @return [undefined]
37
- #
38
- # @api private
39
- #
40
12
  def dispatch
41
- write(K_SUPER)
13
+ write('super')
42
14
  parentheses do
43
15
  delimited(children)
44
16
  end
@@ -4,20 +4,12 @@ module Unparser
4
4
  class Emitter
5
5
  # Emitter for undef nodes
6
6
  class Undef < self
7
- include Unterminated
8
-
9
7
  handle :undef
10
8
 
11
9
  private
12
10
 
13
- # Perform dispatch
14
- #
15
- # @return [undefined]
16
- #
17
- # @api private
18
- #
19
11
  def dispatch
20
- write(K_UNDEF, WS)
12
+ write('undef ')
21
13
  delimited(children)
22
14
  end
23
15
 
@@ -5,20 +5,12 @@ module Unparser
5
5
 
6
6
  # Emitter for various variable accesses
7
7
  class Variable < self
8
- include Terminated
9
-
10
8
  handle :ivar, :lvar, :cvar, :gvar, :back_ref
11
9
 
12
10
  children :name
13
11
 
14
12
  private
15
13
 
16
- # Perform dispatch
17
- #
18
- # @return [undefined]
19
- #
20
- # @api private
21
- #
22
14
  def dispatch
23
15
  write(name.to_s)
24
16
  end
@@ -27,43 +19,27 @@ module Unparser
27
19
 
28
20
  # Emitter for constant access
29
21
  class Const < self
30
- include Terminated
31
-
32
22
  handle :const
33
23
 
34
24
  children :scope, :name
35
25
 
36
26
  private
37
27
 
38
- # Perform dispatch
39
- #
40
- # @return [undefined]
41
- #
42
- # @api private
43
- #
44
28
  def dispatch
45
29
  emit_scope
46
30
  write(name.to_s)
47
31
  end
48
32
 
49
- # Emit parent
50
- #
51
- # @return [undefined]
52
- #
53
- # @api private
54
- #
55
33
  def emit_scope
56
34
  return unless scope
57
35
 
58
36
  visit(scope)
59
- write(T_DCL) unless scope.type.equal?(:cbase)
37
+ write('::') unless n_cbase?(scope)
60
38
  end
61
39
  end
62
40
 
63
41
  # Emitter for nth_ref nodes (regexp captures)
64
42
  class NthRef < self
65
- include Terminated
66
-
67
43
  PREFIX = '$'.freeze
68
44
  handle :nth_ref
69
45
 
@@ -71,12 +47,6 @@ module Unparser
71
47
 
72
48
  private
73
49
 
74
- # Perform dispatch
75
- #
76
- # @return [undefined]
77
- #
78
- # @api private
79
- #
80
50
  def dispatch
81
51
  write(PREFIX)
82
52
  write(name.to_s)
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ class Emitter
5
+ # Dynamic execute string literal emitter
6
+ class XStr < self
7
+
8
+ handle :xstr
9
+
10
+ private
11
+
12
+ def dispatch
13
+ if heredoc?
14
+ emit_heredoc
15
+ else
16
+ emit_xstr
17
+ end
18
+ end
19
+
20
+ def heredoc?
21
+ children.any? { |node| node.eql?(s(:str, '')) }
22
+ end
23
+
24
+ def emit_heredoc
25
+ write(%(<<~`HEREDOC`))
26
+ buffer.indent
27
+ nl
28
+ children.each do |child|
29
+ if n_str?(child)
30
+ write(child.children.first)
31
+ else
32
+ emit_begin(child)
33
+ end
34
+ end
35
+ buffer.unindent
36
+ write("HEREDOC\n")
37
+ end
38
+
39
+ def emit_xstr
40
+ write('`')
41
+ children.each do |child|
42
+ if n_begin?(child)
43
+ emit_begin(child)
44
+ else
45
+ emit_string(child)
46
+ end
47
+ end
48
+ write('`')
49
+ end
50
+
51
+ def emit_string(value)
52
+ write(escape_xstr(value.children.first))
53
+ end
54
+
55
+ def escape_xstr(input)
56
+ input.chars.map do |char|
57
+ if char.eql?('`')
58
+ '\\`'
59
+ else
60
+ char
61
+ end
62
+ end.join
63
+ end
64
+
65
+ def emit_begin(component)
66
+ write('#{')
67
+ visit(unwrap_single_begin(component))
68
+ write('}')
69
+ end
70
+ end # XStr
71
+ end # Emitter
72
+ end # Unparser
@@ -5,20 +5,12 @@ module Unparser
5
5
 
6
6
  # Emitter for yield node
7
7
  class Yield < self
8
- include Terminated
9
-
10
8
  handle :yield
11
9
 
12
10
  private
13
11
 
14
- # Perform dispatch
15
- #
16
- # @return [undefined]
17
- #
18
- # @api private
19
- #
20
12
  def dispatch
21
- write(K_YIELD)
13
+ write('yield')
22
14
  return if children.empty?
23
15
 
24
16
  parentheses do