unparser 0.4.9 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/bin/unparser +1 -1
  3. data/lib/unparser.rb +98 -61
  4. data/lib/unparser/ast.rb +0 -1
  5. data/lib/unparser/ast/local_variable_scope.rb +6 -76
  6. data/lib/unparser/buffer.rb +19 -16
  7. data/lib/unparser/cli.rb +26 -39
  8. data/lib/unparser/color.rb +0 -3
  9. data/lib/unparser/comments.rb +0 -26
  10. data/lib/unparser/constants.rb +4 -53
  11. data/lib/unparser/diff.rb +0 -17
  12. data/lib/unparser/dsl.rb +0 -32
  13. data/lib/unparser/emitter.rb +23 -425
  14. data/lib/unparser/emitter/alias.rb +2 -8
  15. data/lib/unparser/emitter/args.rb +45 -0
  16. data/lib/unparser/emitter/argument.rb +8 -166
  17. data/lib/unparser/emitter/array.rb +27 -0
  18. data/lib/unparser/emitter/array_pattern.rb +29 -0
  19. data/lib/unparser/emitter/assignment.rb +36 -127
  20. data/lib/unparser/emitter/begin.rb +9 -84
  21. data/lib/unparser/emitter/binary.rb +7 -20
  22. data/lib/unparser/emitter/block.rb +57 -41
  23. data/lib/unparser/emitter/case.rb +6 -48
  24. data/lib/unparser/emitter/case_guard.rb +27 -0
  25. data/lib/unparser/emitter/case_match.rb +40 -0
  26. data/lib/unparser/emitter/cbase.rb +1 -3
  27. data/lib/unparser/emitter/class.rb +6 -26
  28. data/lib/unparser/emitter/const_pattern.rb +24 -0
  29. data/lib/unparser/emitter/def.rb +7 -51
  30. data/lib/unparser/emitter/defined.rb +2 -12
  31. data/lib/unparser/emitter/dstr.rb +22 -0
  32. data/lib/unparser/emitter/dsym.rb +41 -0
  33. data/lib/unparser/emitter/flipflop.rb +11 -10
  34. data/lib/unparser/emitter/float.rb +29 -0
  35. data/lib/unparser/emitter/flow_modifier.rb +8 -55
  36. data/lib/unparser/emitter/for.rb +5 -19
  37. data/lib/unparser/emitter/hash.rb +74 -0
  38. data/lib/unparser/emitter/hash_pattern.rb +67 -0
  39. data/lib/unparser/emitter/hookexe.rb +5 -11
  40. data/lib/unparser/emitter/if.rb +9 -73
  41. data/lib/unparser/emitter/in_match.rb +21 -0
  42. data/lib/unparser/emitter/in_pattern.rb +34 -0
  43. data/lib/unparser/emitter/index.rb +21 -88
  44. data/lib/unparser/emitter/kwbegin.rb +31 -0
  45. data/lib/unparser/emitter/lambda.rb +0 -8
  46. data/lib/unparser/emitter/masgn.rb +20 -0
  47. data/lib/unparser/emitter/match.rb +3 -17
  48. data/lib/unparser/emitter/match_alt.rb +23 -0
  49. data/lib/unparser/emitter/match_as.rb +21 -0
  50. data/lib/unparser/emitter/match_rest.rb +26 -0
  51. data/lib/unparser/emitter/match_var.rb +19 -0
  52. data/lib/unparser/emitter/mlhs.rb +40 -0
  53. data/lib/unparser/emitter/module.rb +3 -9
  54. data/lib/unparser/emitter/op_assign.rb +12 -27
  55. data/lib/unparser/emitter/pin.rb +19 -0
  56. data/lib/unparser/emitter/primitive.rb +93 -0
  57. data/lib/unparser/emitter/range.rb +35 -0
  58. data/lib/unparser/emitter/regexp.rb +35 -0
  59. data/lib/unparser/emitter/repetition.rb +17 -57
  60. data/lib/unparser/emitter/rescue.rb +1 -97
  61. data/lib/unparser/emitter/root.rb +17 -1
  62. data/lib/unparser/emitter/send.rb +10 -219
  63. data/lib/unparser/emitter/simple.rb +33 -0
  64. data/lib/unparser/emitter/splat.rb +2 -18
  65. data/lib/unparser/emitter/super.rb +1 -29
  66. data/lib/unparser/emitter/undef.rb +1 -9
  67. data/lib/unparser/emitter/variable.rb +1 -31
  68. data/lib/unparser/emitter/xstr.rb +72 -0
  69. data/lib/unparser/emitter/yield.rb +1 -9
  70. data/lib/unparser/generation.rb +250 -0
  71. data/lib/unparser/node_details.rb +21 -0
  72. data/lib/unparser/node_details/send.rb +62 -0
  73. data/lib/unparser/node_helpers.rb +45 -6
  74. data/lib/unparser/validation.rb +37 -35
  75. data/lib/unparser/writer.rb +15 -0
  76. data/lib/unparser/writer/binary.rb +99 -0
  77. data/lib/unparser/writer/dynamic_string.rb +229 -0
  78. data/lib/unparser/writer/resbody.rb +40 -0
  79. data/lib/unparser/writer/rescue.rb +39 -0
  80. data/lib/unparser/writer/send.rb +124 -0
  81. data/lib/unparser/{emitter → writer}/send/attribute_assignment.rb +11 -26
  82. data/lib/unparser/writer/send/binary.rb +27 -0
  83. data/lib/unparser/writer/send/conditional.rb +25 -0
  84. data/lib/unparser/writer/send/regular.rb +33 -0
  85. data/lib/unparser/{emitter → writer}/send/unary.rb +10 -17
  86. metadata +63 -31
  87. data/lib/unparser/emitter/empty.rb +0 -23
  88. data/lib/unparser/emitter/ensure.rb +0 -37
  89. data/lib/unparser/emitter/literal.rb +0 -10
  90. data/lib/unparser/emitter/literal/array.rb +0 -29
  91. data/lib/unparser/emitter/literal/dynamic.rb +0 -53
  92. data/lib/unparser/emitter/literal/dynamic_body.rb +0 -132
  93. data/lib/unparser/emitter/literal/execute_string.rb +0 -38
  94. data/lib/unparser/emitter/literal/hash.rb +0 -156
  95. data/lib/unparser/emitter/literal/primitive.rb +0 -145
  96. data/lib/unparser/emitter/literal/range.rb +0 -36
  97. data/lib/unparser/emitter/literal/regexp.rb +0 -114
  98. data/lib/unparser/emitter/literal/singleton.rb +0 -26
  99. data/lib/unparser/emitter/meta.rb +0 -16
  100. data/lib/unparser/emitter/redo.rb +0 -25
  101. data/lib/unparser/emitter/resbody.rb +0 -76
  102. data/lib/unparser/emitter/retry.rb +0 -25
  103. data/lib/unparser/emitter/send/binary.rb +0 -57
  104. data/lib/unparser/emitter/send/conditional.rb +0 -40
  105. data/lib/unparser/emitter/send/regular.rb +0 -40
  106. data/lib/unparser/preprocessor.rb +0 -159
@@ -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 = IceNine.deep_freeze(
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
+ )
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,44 +4,28 @@ 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
 
35
25
  private
36
26
 
37
- # Perform dispatch
38
- #
39
- # @return [undefined]
40
- #
41
- # @api private
42
- #
43
27
  def dispatch
44
- write(T_SPLAT)
28
+ write('*')
45
29
  visit(subject) if subject
46
30
  end
47
31
  end
@@ -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
@@ -0,0 +1,250 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ # rubocop:disable Metrics/ModuleLength
5
+ module Generation
6
+ EXTRA_NL = %i[kwbegin def defs module class sclass].freeze
7
+
8
+ private_constant(*constants(false))
9
+
10
+ def emit_heredoc_reminders; end
11
+
12
+ def symbol_name; end
13
+
14
+ def write_to_buffer
15
+ with_comments { dispatch }
16
+ self
17
+ end
18
+
19
+ private
20
+
21
+ def delimited(nodes, delimiter = ', ', &block)
22
+ return if nodes.empty?
23
+
24
+ emit_join(nodes, block || method(:visit), -> { write(delimiter) })
25
+ end
26
+
27
+ def emit_join(nodes, emit_node, emit_delimiter)
28
+ return if nodes.empty?
29
+
30
+ head, *tail = nodes
31
+ emit_node.call(head)
32
+
33
+ tail.each do |node|
34
+ emit_delimiter.call
35
+ emit_node.call(node)
36
+ end
37
+ end
38
+
39
+ def nl
40
+ emit_eol_comments
41
+ buffer.nl
42
+ end
43
+
44
+ def with_comments
45
+ emit_comments_before if buffer.fresh_line?
46
+ yield
47
+ comments.consume(node)
48
+ end
49
+
50
+ def ws
51
+ write(' ')
52
+ end
53
+
54
+ def emit_eol_comments
55
+ comments.take_eol_comments.each do |comment|
56
+ write(' ', comment.text)
57
+ end
58
+ end
59
+
60
+ def emit_eof_comments
61
+ emit_eol_comments
62
+ comments_left = comments.take_all
63
+ return if comments_left.empty?
64
+
65
+ buffer.nl
66
+ emit_comments(comments_left)
67
+ end
68
+
69
+ def emit_comments_before(source_part = :expression)
70
+ comments_before = comments.take_before(node, source_part)
71
+ return if comments_before.empty?
72
+
73
+ emit_comments(comments_before)
74
+ buffer.nl
75
+ end
76
+
77
+ def emit_comments(comments)
78
+ max = comments.size - 1
79
+ comments.each_with_index do |comment, index|
80
+ if comment.type.equal?(:document)
81
+ buffer.append_without_prefix(comment.text.chomp)
82
+ else
83
+ write(comment.text)
84
+ end
85
+ buffer.nl if index < max
86
+ end
87
+ end
88
+
89
+ def write(*strings)
90
+ strings.each(&buffer.method(:append))
91
+ end
92
+
93
+ def k_end
94
+ buffer.indent
95
+ emit_comments_before(:end)
96
+ buffer.unindent
97
+ write('end')
98
+ end
99
+
100
+ def parentheses(open = '(', close = ')')
101
+ write(open)
102
+ yield
103
+ write(close)
104
+ end
105
+
106
+ def indented
107
+ buffer = buffer()
108
+ buffer.indent
109
+ nl
110
+ yield
111
+ nl
112
+ buffer.unindent
113
+ end
114
+
115
+ def emit_optional_body(node, indent: true)
116
+ if node
117
+ emit_body(node, indent: indent)
118
+ else
119
+ nl
120
+ end
121
+ end
122
+
123
+ def emit_body(node, indent: true)
124
+ if indent
125
+ buffer.indent
126
+ nl
127
+ end
128
+
129
+ if n_begin?(node)
130
+ if node.children.one?
131
+ visit_deep(node)
132
+ else
133
+ emit_body_inner(node)
134
+ end
135
+ else
136
+ visit_deep(node)
137
+ end
138
+
139
+ if indent
140
+ buffer.unindent
141
+ nl
142
+ end
143
+ end
144
+
145
+ def emit_body_inner(node)
146
+ head, *tail = node.children
147
+ emit_body_member(head)
148
+
149
+ tail.each do |child|
150
+ nl
151
+
152
+ nl if EXTRA_NL.include?(child.type)
153
+
154
+ emit_body_member(child)
155
+ end
156
+ end
157
+
158
+ def emit_body_member(node)
159
+ if n_rescue?(node)
160
+ emit_rescue_postcontrol(node)
161
+ else
162
+ visit_deep(node)
163
+ end
164
+ end
165
+
166
+ def emit_ensure(node)
167
+ body, ensure_body = node.children
168
+
169
+ if body
170
+ emit_body_rescue(body)
171
+ else
172
+ nl
173
+ end
174
+
175
+ write('ensure')
176
+
177
+ emit_optional_body(ensure_body)
178
+ end
179
+
180
+ def emit_body_rescue(node)
181
+ if n_rescue?(node)
182
+ emit_rescue_regular(node)
183
+ else
184
+ emit_body(node)
185
+ end
186
+ end
187
+
188
+ def emit_optional_body_ensure_rescue(node)
189
+ if node
190
+ emit_body_ensure_rescue(node)
191
+ else
192
+ nl
193
+ end
194
+ end
195
+
196
+ def emit_body_ensure_rescue(node)
197
+ if n_ensure?(node)
198
+ emit_ensure(node)
199
+ elsif n_rescue?(node)
200
+ emit_rescue_regular(node)
201
+ else
202
+ emit_body(node)
203
+ end
204
+ end
205
+
206
+ def emit_rescue_postcontrol(node)
207
+ writer_with(Writer::Rescue, node).emit_postcontrol
208
+ end
209
+
210
+ def emit_rescue_regular(node)
211
+ writer_with(Writer::Rescue, node).emit_regular
212
+ end
213
+
214
+ def writer_with(klass, node)
215
+ klass.new(to_h.merge(node: node))
216
+ end
217
+
218
+ def emitter(node)
219
+ Emitter.emitter(**to_h.merge(node: node))
220
+ end
221
+
222
+ def visit(node)
223
+ emitter(node).write_to_buffer
224
+ end
225
+
226
+ def visit_deep(node)
227
+ emitter(node).tap do |emitter|
228
+ emitter.write_to_buffer
229
+ emitter.emit_heredoc_reminders
230
+ end
231
+ end
232
+
233
+ def first_child
234
+ children.first
235
+ end
236
+
237
+ def conditional_parentheses(flag, &block)
238
+ if flag
239
+ parentheses(&block)
240
+ else
241
+ block.call
242
+ end
243
+ end
244
+
245
+ def children
246
+ node.children
247
+ end
248
+ end # Generation
249
+ # rubocop:enable Metrics/ModuleLength
250
+ end # Unparser