unparser 0.4.7 → 0.6.7

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