unparser 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +32 -8
- data/Changelog.md +5 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +26 -20
- data/README.md +21 -21
- data/config/flay.yml +1 -1
- data/config/reek.yml +9 -48
- data/lib/unparser.rb +62 -2
- data/lib/unparser/ast.rb +1 -1
- data/lib/unparser/cli/differ.rb +1 -1
- data/lib/unparser/cli/source.rb +2 -15
- data/lib/unparser/constants.rb +4 -2
- data/lib/unparser/emitter.rb +0 -14
- data/lib/unparser/emitter/argument.rb +62 -0
- data/lib/unparser/emitter/assignment.rb +4 -16
- data/lib/unparser/emitter/block.rb +29 -4
- data/lib/unparser/emitter/hookexe.rb +1 -1
- data/lib/unparser/emitter/index.rb +136 -0
- data/lib/unparser/emitter/lambda.rb +25 -0
- data/lib/unparser/emitter/literal/array.rb +1 -4
- data/lib/unparser/emitter/meta.rb +2 -2
- data/lib/unparser/emitter/rescue.rb +1 -1
- data/lib/unparser/emitter/send.rb +14 -28
- data/lib/unparser/emitter/send/attribute_assignment.rb +10 -24
- data/spec/spec_helper.rb +0 -11
- data/spec/unit/unparser/comments/consume_spec.rb +1 -1
- data/spec/unit/unparser/comments/take_all_spec.rb +1 -1
- data/spec/unit/unparser/comments/take_before_spec.rb +2 -2
- data/spec/unit/unparser/comments/take_eol_comments_spec.rb +6 -6
- data/spec/unit/unparser_spec.rb +365 -248
- data/unparser.gemspec +1 -1
- metadata +5 -6
- data/lib/unparser/emitter/send/index.rb +0 -127
- data/spec/support/parser_class_generator.rb +0 -21
data/lib/unparser/cli/differ.rb
CHANGED
data/lib/unparser/cli/source.rb
CHANGED
@@ -182,7 +182,7 @@ module Unparser
|
|
182
182
|
# @api private
|
183
183
|
#
|
184
184
|
def generated_ast
|
185
|
-
generated.success? && Preprocessor.run(parse(generated.source))
|
185
|
+
generated.success? && Preprocessor.run(Unparser.parse(generated.source))
|
186
186
|
rescue Parser::SyntaxError
|
187
187
|
nil
|
188
188
|
end
|
@@ -195,25 +195,12 @@ module Unparser
|
|
195
195
|
# @api private
|
196
196
|
#
|
197
197
|
def original_ast
|
198
|
-
Preprocessor.run(parse(original_source))
|
198
|
+
Preprocessor.run(Unparser.parse(original_source))
|
199
199
|
rescue Parser::SyntaxError
|
200
200
|
nil
|
201
201
|
end
|
202
202
|
memoize :original_ast
|
203
203
|
|
204
|
-
# Parse source with current ruby
|
205
|
-
#
|
206
|
-
# @param [String] source
|
207
|
-
#
|
208
|
-
# @return [Parser::AST::Node]
|
209
|
-
#
|
210
|
-
# @api private
|
211
|
-
#
|
212
|
-
# ignore :reek:UtilityFunction
|
213
|
-
def parse(source)
|
214
|
-
Parser::CurrentRuby.parse(source)
|
215
|
-
end
|
216
|
-
|
217
204
|
# CLI source from string
|
218
205
|
class String < self
|
219
206
|
include Concord.new(:original_source)
|
data/lib/unparser/constants.rb
CHANGED
@@ -22,6 +22,10 @@ module Unparser
|
|
22
22
|
end
|
23
23
|
private_class_method :symbol_set
|
24
24
|
|
25
|
+
BRACKETS_CURLY = IceNine.deep_freeze(%w[{ }])
|
26
|
+
BRACKETS_ROUND = IceNine.deep_freeze(%w[( )])
|
27
|
+
BRACKETS_SQUARE = IceNine.deep_freeze(%w([ ]))
|
28
|
+
|
25
29
|
# All unary operators of the ruby language
|
26
30
|
UNARY_OPERATORS = symbol_set %w[
|
27
31
|
! ~ -@ +@
|
@@ -105,8 +109,6 @@ module Unparser
|
|
105
109
|
|
106
110
|
DEFAULT_DELIMITER = ', '.freeze
|
107
111
|
|
108
|
-
CURLY_BRACKETS = IceNine.deep_freeze(%w[{ }])
|
109
|
-
|
110
112
|
KEYWORDS = constants.each_with_object([]) do |name, keywords|
|
111
113
|
value = const_get(name).freeze
|
112
114
|
next unless name.to_s.start_with?('K_')
|
data/lib/unparser/emitter.rb
CHANGED
@@ -17,10 +17,6 @@ module Unparser
|
|
17
17
|
|
18
18
|
NOINDENT = %i[rescue ensure].to_set.freeze
|
19
19
|
|
20
|
-
DEFAULT_DELIMITER = ', '.freeze
|
21
|
-
|
22
|
-
CURLY_BRACKETS = IceNine.deep_freeze(%w[{ }])
|
23
|
-
|
24
20
|
module Unterminated
|
25
21
|
def terminated?
|
26
22
|
false
|
@@ -111,16 +107,6 @@ module Unparser
|
|
111
107
|
end
|
112
108
|
memoize :write_to_buffer
|
113
109
|
|
114
|
-
# Emit node
|
115
|
-
#
|
116
|
-
# @return [self]
|
117
|
-
#
|
118
|
-
# @api private
|
119
|
-
#
|
120
|
-
def self.emit(*arguments)
|
121
|
-
new(*arguments).write_to_buffer
|
122
|
-
end
|
123
|
-
|
124
110
|
# Return emitter
|
125
111
|
#
|
126
112
|
# @return [Emitter]
|
@@ -30,6 +30,7 @@ module Unparser
|
|
30
30
|
handle :args
|
31
31
|
|
32
32
|
SHADOWARGS = ->(node) { node.type.equal?(:shadowarg) }.freeze
|
33
|
+
ARG = ->(node) { node.type.equal?(:arg) }.freeze
|
33
34
|
|
34
35
|
private
|
35
36
|
|
@@ -41,12 +42,35 @@ module Unparser
|
|
41
42
|
#
|
42
43
|
def dispatch
|
43
44
|
delimited(normal_arguments)
|
45
|
+
|
46
|
+
write(', ') if procarg_disambiguator?
|
47
|
+
|
44
48
|
return if shadowargs.empty?
|
45
49
|
|
46
50
|
write('; ')
|
47
51
|
delimited(shadowargs)
|
48
52
|
end
|
49
53
|
|
54
|
+
# Test for procarg_disambiguator
|
55
|
+
#
|
56
|
+
# @return [Boolean]
|
57
|
+
#
|
58
|
+
# @api private
|
59
|
+
#
|
60
|
+
def procarg_disambiguator?
|
61
|
+
regular_block? && normal_arguments.all?(&ARG) && normal_arguments.one?
|
62
|
+
end
|
63
|
+
|
64
|
+
# Test for regular block
|
65
|
+
#
|
66
|
+
# @return [Boolean]
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
#
|
70
|
+
def regular_block?
|
71
|
+
parent_type.equal?(:block) && !parent.node.children.first.type.equal?(:lambda)
|
72
|
+
end
|
73
|
+
|
50
74
|
# Return normal arguments
|
51
75
|
#
|
52
76
|
# @return [Enumerable<Parser::AST::Node>]
|
@@ -56,6 +80,7 @@ module Unparser
|
|
56
80
|
def normal_arguments
|
57
81
|
children.reject(&SHADOWARGS)
|
58
82
|
end
|
83
|
+
memoize :normal_arguments
|
59
84
|
|
60
85
|
# Return shadow args
|
61
86
|
#
|
@@ -209,6 +234,43 @@ module Unparser
|
|
209
234
|
|
210
235
|
end # Argument
|
211
236
|
|
237
|
+
# Progarg emitter
|
238
|
+
class Procarg < self
|
239
|
+
include Terminated
|
240
|
+
|
241
|
+
handle :procarg0
|
242
|
+
|
243
|
+
children :first_argument
|
244
|
+
|
245
|
+
private
|
246
|
+
|
247
|
+
# Perform dispatch
|
248
|
+
#
|
249
|
+
# @return [undefined]
|
250
|
+
#
|
251
|
+
# @api private
|
252
|
+
#
|
253
|
+
def dispatch
|
254
|
+
if first_argument.instance_of?(Symbol)
|
255
|
+
write(first_argument.to_s)
|
256
|
+
else
|
257
|
+
emit_multiple_children
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
# Emit multiple children
|
262
|
+
#
|
263
|
+
# @return [undefined]
|
264
|
+
#
|
265
|
+
# @api private
|
266
|
+
#
|
267
|
+
def emit_multiple_children
|
268
|
+
parentheses do
|
269
|
+
delimited(children)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
212
274
|
# Block pass node emitter
|
213
275
|
class BlockPass < self
|
214
276
|
include Terminated
|
@@ -29,7 +29,7 @@ module Unparser
|
|
29
29
|
# @api private
|
30
30
|
#
|
31
31
|
def terminated?
|
32
|
-
|
32
|
+
right.nil?
|
33
33
|
end
|
34
34
|
|
35
35
|
private
|
@@ -41,7 +41,6 @@ module Unparser
|
|
41
41
|
# @api private
|
42
42
|
#
|
43
43
|
def emit_right
|
44
|
-
right = right_node
|
45
44
|
return unless right
|
46
45
|
|
47
46
|
write(WS, T_ASN, WS)
|
@@ -55,7 +54,7 @@ module Unparser
|
|
55
54
|
|
56
55
|
handle :lvasgn, :ivasgn, :cvasgn, :gvasgn
|
57
56
|
|
58
|
-
children :name, :
|
57
|
+
children :name, :right
|
59
58
|
|
60
59
|
private
|
61
60
|
|
@@ -76,7 +75,7 @@ module Unparser
|
|
76
75
|
|
77
76
|
handle :casgn
|
78
77
|
|
79
|
-
children :base, :name, :
|
78
|
+
children :base, :name, :right
|
80
79
|
|
81
80
|
private
|
82
81
|
|
@@ -103,8 +102,6 @@ module Unparser
|
|
103
102
|
|
104
103
|
handle :masgn
|
105
104
|
|
106
|
-
PARENS = IceNine.deep_freeze(%w([ ]))
|
107
|
-
|
108
105
|
private
|
109
106
|
|
110
107
|
# Emit left
|
@@ -125,16 +122,7 @@ module Unparser
|
|
125
122
|
#
|
126
123
|
def emit_right
|
127
124
|
write(WS, T_ASN, WS)
|
128
|
-
|
129
|
-
case right.type
|
130
|
-
when :array
|
131
|
-
children = right.children
|
132
|
-
parentheses(*PARENS) do
|
133
|
-
delimited(children)
|
134
|
-
end
|
135
|
-
else
|
136
|
-
visit(right)
|
137
|
-
end
|
125
|
+
visit(children.last)
|
138
126
|
end
|
139
127
|
|
140
128
|
end # Multiple
|
@@ -4,12 +4,14 @@ module Unparser
|
|
4
4
|
class Emitter
|
5
5
|
|
6
6
|
# Block emitter
|
7
|
+
#
|
8
|
+
# ignore :reek:RepeatedConditional
|
7
9
|
class Block < self
|
8
10
|
include Terminated
|
9
11
|
|
10
12
|
handle :block
|
11
13
|
|
12
|
-
children :
|
14
|
+
children :target, :arguments, :body
|
13
15
|
|
14
16
|
private
|
15
17
|
|
@@ -20,14 +22,37 @@ module Unparser
|
|
20
22
|
# @api private
|
21
23
|
#
|
22
24
|
def dispatch
|
23
|
-
|
25
|
+
emit_target
|
24
26
|
write(WS, K_DO)
|
25
|
-
|
26
|
-
emit_block_arguments
|
27
|
+
emit_block_arguments unless stabby_lambda?
|
27
28
|
emit_body
|
28
29
|
k_end
|
29
30
|
end
|
30
31
|
|
32
|
+
# Emit target
|
33
|
+
#
|
34
|
+
# @return [undefined]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
#
|
38
|
+
def emit_target
|
39
|
+
visit(target)
|
40
|
+
|
41
|
+
if stabby_lambda?
|
42
|
+
parentheses { visit(arguments) }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Test if we are emitting a stabby lambda
|
47
|
+
#
|
48
|
+
# @return [Boolean]
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
#
|
52
|
+
def stabby_lambda?
|
53
|
+
target.type.equal?(:lambda)
|
54
|
+
end
|
55
|
+
|
31
56
|
# Emit arguments
|
32
57
|
#
|
33
58
|
# @return [undefined]
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Unparser
|
4
|
+
class Emitter
|
5
|
+
# Emitter for send to index references
|
6
|
+
#
|
7
|
+
# ignore :reek:RepeatedConditional
|
8
|
+
class Index < self
|
9
|
+
|
10
|
+
# Perform dispatch
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
def dispatch
|
17
|
+
emit_receiver
|
18
|
+
emit_operation
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# Emit receiver
|
24
|
+
#
|
25
|
+
# @return [undefined]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
def emit_receiver
|
30
|
+
visit(first_child)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Test for mlhs
|
34
|
+
#
|
35
|
+
# @return [Boolean]
|
36
|
+
#
|
37
|
+
# @api private
|
38
|
+
#
|
39
|
+
def mlhs?
|
40
|
+
parent_type.equal?(:mlhs)
|
41
|
+
end
|
42
|
+
|
43
|
+
class Reference < self
|
44
|
+
include Terminated
|
45
|
+
|
46
|
+
define_group(:indices, 1..-1)
|
47
|
+
|
48
|
+
handle :index
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# Emit arguments
|
53
|
+
#
|
54
|
+
# @return [undefined]
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
#
|
58
|
+
def emit_operation
|
59
|
+
parentheses(*BRACKETS_SQUARE) do
|
60
|
+
delimited_plain(indices)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end # Reference
|
64
|
+
|
65
|
+
# Emitter for assign to index nodes
|
66
|
+
class Assign < self
|
67
|
+
|
68
|
+
handle :indexasgn
|
69
|
+
|
70
|
+
VALUE_RANGE = (1..-2).freeze
|
71
|
+
NO_VALUE_PARENT = IceNine.deep_freeze(%i[and_asgn op_asgn or_asgn].to_set)
|
72
|
+
|
73
|
+
# Test if assign will be emitted terminated
|
74
|
+
#
|
75
|
+
# @return [Boolean]
|
76
|
+
#
|
77
|
+
# @api private
|
78
|
+
#
|
79
|
+
def terminated?
|
80
|
+
!emit_value?
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Emit arguments
|
86
|
+
#
|
87
|
+
# @return [undefined]
|
88
|
+
#
|
89
|
+
# @api private
|
90
|
+
#
|
91
|
+
def emit_operation
|
92
|
+
parentheses(*BRACKETS_SQUARE) do
|
93
|
+
delimited_plain(indices)
|
94
|
+
end
|
95
|
+
|
96
|
+
if emit_value?
|
97
|
+
write(WS, T_ASN, WS)
|
98
|
+
visit(children.last)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# The indices
|
103
|
+
#
|
104
|
+
# @return [Array<Parser::AST::Node>]
|
105
|
+
#
|
106
|
+
def indices
|
107
|
+
if emit_value?
|
108
|
+
children[VALUE_RANGE]
|
109
|
+
else
|
110
|
+
children.drop(1)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Test if value should be emitted
|
115
|
+
#
|
116
|
+
# @return [Boolean]
|
117
|
+
#
|
118
|
+
# @api private
|
119
|
+
#
|
120
|
+
def emit_value?
|
121
|
+
!mlhs? && !no_value_parent?
|
122
|
+
end
|
123
|
+
|
124
|
+
# Test for no value parent
|
125
|
+
#
|
126
|
+
# @return [Boolean]
|
127
|
+
#
|
128
|
+
# @api private
|
129
|
+
#
|
130
|
+
def no_value_parent?
|
131
|
+
NO_VALUE_PARENT.include?(parent_type)
|
132
|
+
end
|
133
|
+
end # Assign
|
134
|
+
end # Index
|
135
|
+
end # Emitter
|
136
|
+
end # Unparser
|