unparser 0.4.9 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ class Emitter
5
+ # Range emitters
6
+ class Range < self
7
+ TOKENS = {
8
+ irange: '..',
9
+ erange: '...'
10
+ }.freeze
11
+
12
+ SYMBOLS = {
13
+ erange: :tDOT3,
14
+ irange: :tDOT2
15
+ }.freeze
16
+
17
+ def symbol_name
18
+ true
19
+ end
20
+
21
+ handle(*TOKENS.keys)
22
+
23
+ children :begin_node, :end_node
24
+
25
+ private
26
+
27
+ def dispatch
28
+ visit(begin_node) if begin_node
29
+ write(TOKENS.fetch(node.type))
30
+ visit(end_node) if end_node
31
+ end
32
+
33
+ end # Range
34
+ end # Emitter
35
+ end # Unparser
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Unparser
4
+ class Emitter
5
+ # Emitter for regexp literals
6
+ class Regexp < self
7
+ handle :regexp
8
+
9
+ define_group(:body, 0..-2)
10
+
11
+ private
12
+
13
+ def dispatch
14
+ parentheses('/', '/') do
15
+ body.each(&method(:emit_body))
16
+ end
17
+ emit_options
18
+ end
19
+
20
+ def emit_options
21
+ write(children.last.children.join)
22
+ end
23
+
24
+ def emit_body(node)
25
+ if n_begin?(node)
26
+ write('#{')
27
+ node.children.each(&method(:visit))
28
+ write('}')
29
+ else
30
+ buffer.append_without_prefix(node.children.first.gsub('/', '\/'))
31
+ end
32
+ end
33
+ end # Regexp
34
+ end # Emitter
35
+ end # Unparser
@@ -5,39 +5,29 @@ module Unparser
5
5
 
6
6
  # Emitter for postconditions
7
7
  class Post < self
8
- include Unterminated
9
-
10
- handle :while_post, :until_post
11
-
12
8
  children :condition, :body
13
9
 
14
10
  MAP = {
15
- while_post: K_WHILE,
16
- until_post: K_UNTIL
11
+ while_post: 'while',
12
+ until_post: 'until'
17
13
  }.freeze
18
14
 
19
15
  handle(*MAP.keys)
20
16
 
21
- # Perform dispatch
22
- #
23
- # @return [undefined]
24
- #
25
- # @api private
26
- #
17
+ private
18
+
27
19
  def dispatch
28
20
  visit(body)
29
- write(WS, MAP.fetch(node.type), WS)
21
+ write(' ', MAP.fetch(node.type), ' ')
30
22
  visit(condition)
31
23
  end
32
24
  end
33
25
 
34
- # Base class for while and until emitters
26
+ # Emitter for while and until nodes
35
27
  class Repetition < self
36
- include Terminated
37
-
38
28
  MAP = {
39
- while: K_WHILE,
40
- until: K_UNTIL
29
+ while: 'while',
30
+ until: 'until'
41
31
  }.freeze
42
32
 
43
33
  handle(*MAP.keys)
@@ -46,12 +36,6 @@ module Unparser
46
36
 
47
37
  private
48
38
 
49
- # Perform dispatch
50
- #
51
- # @return [undefined]
52
- #
53
- # @api private
54
- #
55
39
  def dispatch
56
40
  if postcontrol?
57
41
  emit_postcontrol
@@ -60,54 +44,30 @@ module Unparser
60
44
  end
61
45
  end
62
46
 
63
- # Test if node must be emitted in postcontrol form
64
- #
65
- # @return [Boolean]
66
- #
67
- # @api private
68
- #
69
47
  def postcontrol?
70
- return nil unless body # greez from falsyness
71
-
72
- local_variable_scope.first_assignment_in_body_and_used_in_condition?(body, condition)
48
+ body && local_variable_scope.first_assignment_in?(body, condition)
73
49
  end
74
50
 
75
- # Emit keyword
76
- #
77
- # @return [undefined]
78
- #
79
- # @api private
80
- #
81
51
  def emit_keyword
82
- write(MAP.fetch(node.type), WS)
52
+ write(MAP.fetch(node.type), ' ')
83
53
  end
84
54
 
85
- # Emit embedded
86
- #
87
- # @return [undefned]
88
- #
89
- # @api private
90
- #
91
55
  def emit_normal
92
56
  emit_keyword
93
- conditional_parentheses(condition.type.equal?(:block)) do
94
- visit(condition)
57
+ visit(condition)
58
+ if body
59
+ emit_body(body)
60
+ else
61
+ nl
95
62
  end
96
- emit_body
97
63
  k_end
98
64
  end
99
65
 
100
- # Emit postcontrol
101
- #
102
- # @return [undefined]
103
- #
104
- # @api private
105
- #
106
66
  def emit_postcontrol
107
- visit_plain(body)
67
+ visit(body)
108
68
  ws
109
69
  emit_keyword
110
- visit_plain(condition)
70
+ visit(condition)
111
71
  end
112
72
 
113
73
  end # Repetition
@@ -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