unparser 0.6.15 → 0.8.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.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/lib/unparser/anima.rb +11 -0
- data/lib/unparser/ast/local_variable_scope.rb +28 -24
- data/lib/unparser/ast.rb +18 -22
- data/lib/unparser/buffer.rb +44 -2
- data/lib/unparser/cli.rb +28 -5
- data/lib/unparser/color.rb +2 -2
- data/lib/unparser/either.rb +6 -6
- data/lib/unparser/emitter/args.rb +5 -1
- data/lib/unparser/emitter/array.rb +0 -4
- data/lib/unparser/emitter/array_pattern.rb +1 -9
- data/lib/unparser/emitter/assignment.rb +17 -8
- data/lib/unparser/emitter/begin.rb +0 -6
- data/lib/unparser/emitter/binary.rb +1 -1
- data/lib/unparser/emitter/block.rb +13 -6
- data/lib/unparser/emitter/def.rb +1 -1
- data/lib/unparser/emitter/dstr.rb +6 -5
- data/lib/unparser/emitter/dsym.rb +1 -1
- data/lib/unparser/emitter/ensure.rb +16 -0
- data/lib/unparser/emitter/flow_modifier.rb +1 -7
- data/lib/unparser/emitter/for.rb +1 -1
- data/lib/unparser/emitter/hash.rb +0 -8
- data/lib/unparser/emitter/hash_pattern.rb +1 -1
- data/lib/unparser/emitter/in_pattern.rb +9 -1
- data/lib/unparser/emitter/index.rb +0 -4
- data/lib/unparser/emitter/kwbegin.rb +1 -1
- data/lib/unparser/emitter/match_pattern.rb +6 -1
- data/lib/unparser/emitter/match_pattern_p.rb +6 -1
- data/lib/unparser/emitter/mlhs.rb +7 -1
- data/lib/unparser/emitter/op_assign.rb +0 -10
- data/lib/unparser/emitter/primitive.rb +0 -13
- data/lib/unparser/emitter/range.rb +23 -2
- data/lib/unparser/emitter/regexp.rb +5 -17
- data/lib/unparser/emitter/rescue.rb +7 -1
- data/lib/unparser/emitter/root.rb +2 -9
- data/lib/unparser/emitter/send.rb +1 -5
- data/lib/unparser/emitter/string.rb +31 -0
- data/lib/unparser/emitter/xstr.rb +8 -1
- data/lib/unparser/emitter.rb +9 -10
- data/lib/unparser/generation.rb +14 -14
- data/lib/unparser/node_details.rb +1 -0
- data/lib/unparser/node_helpers.rb +18 -9
- data/lib/unparser/util.rb +23 -0
- data/lib/unparser/validation.rb +68 -28
- data/lib/unparser/writer/array.rb +51 -0
- data/lib/unparser/writer/binary.rb +8 -4
- data/lib/unparser/writer/dynamic_string.rb +128 -135
- data/lib/unparser/writer/regexp.rb +101 -0
- data/lib/unparser/writer/resbody.rb +37 -3
- data/lib/unparser/writer/rescue.rb +3 -7
- data/lib/unparser/writer/send/unary.rb +9 -4
- data/lib/unparser/writer/send.rb +8 -14
- data/lib/unparser/writer.rb +31 -1
- data/lib/unparser.rb +149 -38
- metadata +33 -17
@@ -7,15 +7,16 @@ module Unparser
|
|
7
7
|
|
8
8
|
handle :dstr
|
9
9
|
|
10
|
-
def emit_heredoc_reminders
|
11
|
-
writer_with(Writer::DynamicString, node).emit_heredoc_reminder
|
12
|
-
end
|
13
|
-
|
14
10
|
private
|
15
11
|
|
16
12
|
def dispatch
|
17
|
-
|
13
|
+
dstr_writer.dispatch
|
14
|
+
end
|
15
|
+
|
16
|
+
def dstr_writer
|
17
|
+
writer_with(Writer::DynamicString, node:)
|
18
18
|
end
|
19
|
+
memoize :dstr_writer
|
19
20
|
|
20
21
|
end # DStr
|
21
22
|
end # Emitter
|
@@ -14,12 +14,6 @@ module Unparser
|
|
14
14
|
|
15
15
|
handle(*MAP.keys)
|
16
16
|
|
17
|
-
def emit_heredoc_reminders
|
18
|
-
children.each do |node|
|
19
|
-
emitter(node).emit_heredoc_reminders
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
17
|
private
|
24
18
|
|
25
19
|
def dispatch
|
@@ -27,7 +21,7 @@ module Unparser
|
|
27
21
|
|
28
22
|
if children.one? && n_if?(children.first)
|
29
23
|
ws
|
30
|
-
emitter(children
|
24
|
+
emitter(Util.one(children)).emit_ternary
|
31
25
|
else
|
32
26
|
emit_arguments unless children.empty?
|
33
27
|
end
|
data/lib/unparser/emitter/for.rb
CHANGED
@@ -6,10 +6,6 @@ module Unparser
|
|
6
6
|
class Hash < self
|
7
7
|
handle :hash
|
8
8
|
|
9
|
-
def emit_heredoc_reminders
|
10
|
-
children.each(&method(:emit_heredoc_reminder_member))
|
11
|
-
end
|
12
|
-
|
13
9
|
private
|
14
10
|
|
15
11
|
def dispatch
|
@@ -24,10 +20,6 @@ module Unparser
|
|
24
20
|
end
|
25
21
|
end
|
26
22
|
|
27
|
-
def emit_heredoc_reminder_member(node)
|
28
|
-
emitter(node.children.last).emit_heredoc_reminders if n_pair?(node)
|
29
|
-
end
|
30
|
-
|
31
23
|
def emit_hash_body
|
32
24
|
delimited(children)
|
33
25
|
end
|
@@ -16,7 +16,7 @@ module Unparser
|
|
16
16
|
|
17
17
|
ws
|
18
18
|
|
19
|
-
|
19
|
+
dispatch_target(target)
|
20
20
|
|
21
21
|
if unless_guard
|
22
22
|
ws
|
@@ -31,6 +31,14 @@ module Unparser
|
|
31
31
|
nl
|
32
32
|
end
|
33
33
|
end
|
34
|
+
|
35
|
+
def dispatch_target(target)
|
36
|
+
if n_array?(target)
|
37
|
+
writer_with(Writer::Array, node: target).emit_compact
|
38
|
+
else
|
39
|
+
visit(target)
|
40
|
+
end
|
41
|
+
end
|
34
42
|
end # InPattern
|
35
43
|
end # Emitter
|
36
44
|
end # Unparser
|
@@ -6,10 +6,16 @@ module Unparser
|
|
6
6
|
class MLHS < self
|
7
7
|
handle :mlhs
|
8
8
|
|
9
|
-
NO_COMMA = %i[arg splat
|
9
|
+
NO_COMMA = %i[arg splat restarg].freeze
|
10
10
|
|
11
11
|
private_constant(*constants(false))
|
12
12
|
|
13
|
+
def dispatch_def
|
14
|
+
parentheses do
|
15
|
+
delimited(children)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
13
19
|
private
|
14
20
|
|
15
21
|
def dispatch
|
@@ -14,11 +14,6 @@ module Unparser
|
|
14
14
|
|
15
15
|
handle(*MAP.keys)
|
16
16
|
|
17
|
-
def emit_heredoc_reminders
|
18
|
-
emitter(target).emit_heredoc_reminders
|
19
|
-
emitter(expression).emit_heredoc_reminders
|
20
|
-
end
|
21
|
-
|
22
17
|
private
|
23
18
|
|
24
19
|
def dispatch
|
@@ -35,11 +30,6 @@ module Unparser
|
|
35
30
|
|
36
31
|
children :target, :operator, :value
|
37
32
|
|
38
|
-
def emit_heredoc_reminders
|
39
|
-
emitter(target).emit_heredoc_reminders
|
40
|
-
emitter(value).emit_heredoc_reminders
|
41
|
-
end
|
42
|
-
|
43
33
|
private
|
44
34
|
|
45
35
|
def dispatch
|
@@ -7,19 +7,6 @@ module Unparser
|
|
7
7
|
|
8
8
|
children :value
|
9
9
|
|
10
|
-
# Emitter for primitives based on Object#inspect
|
11
|
-
class Inspect < self
|
12
|
-
|
13
|
-
handle :str
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def dispatch
|
18
|
-
write(value.inspect)
|
19
|
-
end
|
20
|
-
|
21
|
-
end # Inspect
|
22
|
-
|
23
10
|
class Symbol < self
|
24
11
|
|
25
12
|
handle :sym
|
@@ -25,9 +25,30 @@ module Unparser
|
|
25
25
|
private
|
26
26
|
|
27
27
|
def dispatch
|
28
|
-
|
28
|
+
visit_begin_node(begin_node)
|
29
29
|
write(TOKENS.fetch(node.type))
|
30
|
-
|
30
|
+
visit_end_node(end_node)
|
31
|
+
end
|
32
|
+
|
33
|
+
def visit_begin_node(node)
|
34
|
+
return unless node
|
35
|
+
|
36
|
+
if n_array?(begin_node)
|
37
|
+
writer_with(Writer::Array, node: begin_node).emit_compact
|
38
|
+
else
|
39
|
+
visit(begin_node)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def visit_end_node(node)
|
44
|
+
return unless node
|
45
|
+
|
46
|
+
write(' ') if n_range?(node)
|
47
|
+
if n_array?(node)
|
48
|
+
writer_with(Writer::Array, node: node).emit_compact
|
49
|
+
else
|
50
|
+
visit(node)
|
51
|
+
end
|
31
52
|
end
|
32
53
|
|
33
54
|
end # Range
|
@@ -4,32 +4,20 @@ module Unparser
|
|
4
4
|
class Emitter
|
5
5
|
# Emitter for regexp literals
|
6
6
|
class Regexp < self
|
7
|
-
handle :regexp
|
8
7
|
|
9
|
-
|
8
|
+
handle :regexp
|
10
9
|
|
11
10
|
private
|
12
11
|
|
13
12
|
def dispatch
|
14
|
-
|
15
|
-
body.each(&method(:emit_body))
|
16
|
-
end
|
17
|
-
emit_options
|
13
|
+
writer.dispatch
|
18
14
|
end
|
19
15
|
|
20
|
-
def
|
21
|
-
|
16
|
+
def writer
|
17
|
+
writer_with(Writer::Regexp, node:)
|
22
18
|
end
|
19
|
+
memoize :writer
|
23
20
|
|
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
21
|
end # Regexp
|
34
22
|
end # Emitter
|
35
23
|
end # Unparser
|
@@ -9,7 +9,13 @@ module Unparser
|
|
9
9
|
private
|
10
10
|
|
11
11
|
def dispatch
|
12
|
-
|
12
|
+
resbody = children.fetch(1)
|
13
|
+
|
14
|
+
if resbody.children.fetch(1)
|
15
|
+
emit_rescue_regular(node)
|
16
|
+
else
|
17
|
+
emit_rescue_postcontrol(node)
|
18
|
+
end
|
13
19
|
end
|
14
20
|
end # Rescue
|
15
21
|
end # Emitter
|
@@ -2,22 +2,15 @@
|
|
2
2
|
|
3
3
|
module Unparser
|
4
4
|
class Emitter
|
5
|
-
# Root emitter a special case
|
6
5
|
class Root < self
|
7
|
-
include Concord::Public.new(:buffer, :node, :comments)
|
8
|
-
include LocalVariableRoot
|
9
|
-
|
10
6
|
END_NL = %i[class sclass module begin].freeze
|
11
7
|
|
12
8
|
private_constant(*constants(false))
|
13
9
|
|
14
10
|
def dispatch
|
15
|
-
|
16
|
-
emit_body(node, indent: false)
|
17
|
-
else
|
18
|
-
visit_deep(node)
|
19
|
-
end
|
11
|
+
emit_body(node, indent: false)
|
20
12
|
|
13
|
+
buffer.nl_flush_heredocs
|
21
14
|
emit_eof_comments
|
22
15
|
|
23
16
|
nl if END_NL.include?(node.type) && !buffer.fresh_line?
|
@@ -10,10 +10,6 @@ module Unparser
|
|
10
10
|
writer.emit_mlhs
|
11
11
|
end
|
12
12
|
|
13
|
-
def emit_heredoc_reminders
|
14
|
-
writer.emit_heredoc_reminders
|
15
|
-
end
|
16
|
-
|
17
13
|
private
|
18
14
|
|
19
15
|
def dispatch
|
@@ -21,7 +17,7 @@ module Unparser
|
|
21
17
|
end
|
22
18
|
|
23
19
|
def writer
|
24
|
-
writer_with(Writer::Send, node)
|
20
|
+
writer_with(Writer::Send, node:)
|
25
21
|
end
|
26
22
|
memoize :writer
|
27
23
|
end # Send
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Unparser
|
4
|
+
class Emitter
|
5
|
+
# Base class for primitive emitters
|
6
|
+
class String < self
|
7
|
+
children :value
|
8
|
+
|
9
|
+
handle :str
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def dispatch
|
14
|
+
if explicit_encoding && !value.encoding.equal?(explicit_encoding)
|
15
|
+
write_utf8_escaped
|
16
|
+
else
|
17
|
+
write(value.inspect)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def write_utf8_escaped
|
22
|
+
write('"')
|
23
|
+
value.each_codepoint do |codepoint|
|
24
|
+
write("\\u{#{codepoint.to_s(16)}}")
|
25
|
+
end
|
26
|
+
write('"')
|
27
|
+
end
|
28
|
+
|
29
|
+
end # String
|
30
|
+
end # Emitter
|
31
|
+
end # Unparser
|
@@ -41,6 +41,8 @@ module Unparser
|
|
41
41
|
children.each do |child|
|
42
42
|
if n_begin?(child)
|
43
43
|
emit_begin(child)
|
44
|
+
elsif n_gvar?(child)
|
45
|
+
emit_gvar(child)
|
44
46
|
else
|
45
47
|
emit_string(child)
|
46
48
|
end
|
@@ -64,9 +66,14 @@ module Unparser
|
|
64
66
|
|
65
67
|
def emit_begin(component)
|
66
68
|
write('#{')
|
67
|
-
visit(
|
69
|
+
visit(Util.one(component.children)) if component.children.any?
|
68
70
|
write('}')
|
69
71
|
end
|
72
|
+
|
73
|
+
def emit_gvar(component)
|
74
|
+
write('#')
|
75
|
+
write(Util.one(component.children).to_s)
|
76
|
+
end
|
70
77
|
end # XStr
|
71
78
|
end # Emitter
|
72
79
|
end # Unparser
|
data/lib/unparser/emitter.rb
CHANGED
@@ -6,7 +6,7 @@ module Unparser
|
|
6
6
|
# Emitter base class
|
7
7
|
class Emitter
|
8
8
|
include Adamantium, AbstractType, Constants, Generation, NodeHelpers
|
9
|
-
include Anima.new(:buffer, :comments, :
|
9
|
+
include Anima.new(:buffer, :comments, :explicit_encoding, :local_variable_scope, :node)
|
10
10
|
|
11
11
|
public :node
|
12
12
|
|
@@ -22,10 +22,9 @@ module Unparser
|
|
22
22
|
#
|
23
23
|
# @return [Parser::AST::Node]
|
24
24
|
#
|
25
|
-
#
|
26
|
-
#
|
25
|
+
# mutant:disable
|
27
26
|
def local_variable_scope
|
28
|
-
AST::LocalVariableScope.new(node)
|
27
|
+
AST::LocalVariableScope.new(node: node, static_local_variables: Set.new)
|
29
28
|
end
|
30
29
|
|
31
30
|
def self.included(descendant)
|
@@ -67,7 +66,7 @@ module Unparser
|
|
67
66
|
# @api private
|
68
67
|
#
|
69
68
|
# rubocop:disable Metrics/ParameterLists
|
70
|
-
def self.emitter(buffer:, comments:, node:, local_variable_scope:)
|
69
|
+
def self.emitter(buffer:, explicit_encoding:, comments:, node:, local_variable_scope:)
|
71
70
|
type = node.type
|
72
71
|
|
73
72
|
klass = REGISTRY.fetch(type) do
|
@@ -75,10 +74,11 @@ module Unparser
|
|
75
74
|
end
|
76
75
|
|
77
76
|
klass.new(
|
78
|
-
buffer
|
79
|
-
comments
|
80
|
-
|
81
|
-
|
77
|
+
buffer:,
|
78
|
+
comments:,
|
79
|
+
explicit_encoding:,
|
80
|
+
local_variable_scope:,
|
81
|
+
node:
|
82
82
|
)
|
83
83
|
end
|
84
84
|
# rubocop:enable Metrics/ParameterLists
|
@@ -90,6 +90,5 @@ module Unparser
|
|
90
90
|
# @api private
|
91
91
|
#
|
92
92
|
abstract_method :dispatch
|
93
|
-
|
94
93
|
end # Emitter
|
95
94
|
end # Unparser
|
data/lib/unparser/generation.rb
CHANGED
@@ -7,8 +7,6 @@ module Unparser
|
|
7
7
|
|
8
8
|
private_constant(*constants(false))
|
9
9
|
|
10
|
-
def emit_heredoc_reminders; end
|
11
|
-
|
12
10
|
def symbol_name; end
|
13
11
|
|
14
12
|
def write_to_buffer
|
@@ -149,16 +147,22 @@ module Unparser
|
|
149
147
|
def emit_body_inner(node)
|
150
148
|
head, *tail = node.children
|
151
149
|
emit_body_member(head)
|
150
|
+
write(';') if requires_explicit_statement_terminator?(head, tail)
|
152
151
|
|
153
152
|
tail.each do |child|
|
154
|
-
|
153
|
+
buffer.ensure_nl
|
155
154
|
|
156
155
|
nl if EXTRA_NL.include?(child.type)
|
157
156
|
|
158
157
|
emit_body_member(child)
|
158
|
+
write(';') if requires_explicit_statement_terminator?(child, tail)
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
162
|
+
def requires_explicit_statement_terminator?(node, nodes_group)
|
163
|
+
n_range?(node) && node.children.fetch(1).nil? && !node.eql?(nodes_group.fetch(-1))
|
164
|
+
end
|
165
|
+
|
162
166
|
def emit_body_member(node)
|
163
167
|
if n_rescue?(node)
|
164
168
|
emit_rescue_postcontrol(node)
|
@@ -208,21 +212,20 @@ module Unparser
|
|
208
212
|
end
|
209
213
|
|
210
214
|
def emit_rescue_postcontrol(node)
|
211
|
-
writer = writer_with(Writer::Rescue, node)
|
215
|
+
writer = writer_with(Writer::Rescue, node:)
|
212
216
|
writer.emit_postcontrol
|
213
|
-
writer.emit_heredoc_reminders
|
214
217
|
end
|
215
218
|
|
216
219
|
def emit_rescue_regular(node)
|
217
|
-
writer_with(Writer::Rescue, node).emit_regular
|
220
|
+
writer_with(Writer::Rescue, node:).emit_regular
|
218
221
|
end
|
219
222
|
|
220
|
-
def
|
221
|
-
|
223
|
+
def emitter(node)
|
224
|
+
Emitter.emitter(**to_h, node: node)
|
222
225
|
end
|
223
226
|
|
224
|
-
def
|
225
|
-
|
227
|
+
def writer_with(klass, node:, **attributes)
|
228
|
+
klass.new(to_h.merge(node: node, **attributes))
|
226
229
|
end
|
227
230
|
|
228
231
|
def visit(node)
|
@@ -230,10 +233,7 @@ module Unparser
|
|
230
233
|
end
|
231
234
|
|
232
235
|
def visit_deep(node)
|
233
|
-
emitter(node).tap
|
234
|
-
emitter.write_to_buffer
|
235
|
-
emitter.emit_heredoc_reminders
|
236
|
-
end
|
236
|
+
emitter(node).tap(&:write_to_buffer)
|
237
237
|
end
|
238
238
|
|
239
239
|
def first_child
|
@@ -31,7 +31,16 @@ module Unparser
|
|
31
31
|
node.type.equal?(type)
|
32
32
|
end
|
33
33
|
|
34
|
+
def n_flipflop?(node)
|
35
|
+
n_iflipflop?(node) || n_eflipflop?(node)
|
36
|
+
end
|
37
|
+
|
38
|
+
def n_range?(node)
|
39
|
+
n_irange?(node) || n_erange?(node)
|
40
|
+
end
|
41
|
+
|
34
42
|
%i[
|
43
|
+
and
|
35
44
|
arg
|
36
45
|
args
|
37
46
|
array
|
@@ -41,19 +50,26 @@ module Unparser
|
|
41
50
|
cbase
|
42
51
|
const
|
43
52
|
dstr
|
53
|
+
eflipflop
|
44
54
|
empty_else
|
55
|
+
erange
|
45
56
|
ensure
|
57
|
+
gvar
|
46
58
|
hash
|
47
59
|
hash_pattern
|
48
60
|
if
|
61
|
+
iflipflop
|
49
62
|
in_pattern
|
50
63
|
int
|
64
|
+
irange
|
51
65
|
kwarg
|
52
66
|
kwargs
|
53
67
|
kwsplat
|
54
68
|
lambda
|
55
69
|
lvar
|
56
70
|
match_rest
|
71
|
+
mlhs
|
72
|
+
or
|
57
73
|
pair
|
58
74
|
rescue
|
59
75
|
send
|
@@ -61,20 +77,13 @@ module Unparser
|
|
61
77
|
splat
|
62
78
|
str
|
63
79
|
sym
|
64
|
-
|
80
|
+
xstr
|
81
|
+
].to_set.each do |type|
|
65
82
|
name = "n_#{type}?"
|
66
83
|
define_method(name) do |node|
|
67
84
|
n?(type, node)
|
68
85
|
end
|
69
86
|
private(name)
|
70
87
|
end
|
71
|
-
|
72
|
-
def unwrap_single_begin(node)
|
73
|
-
if n_begin?(node) && node.children.one?
|
74
|
-
node.children.first
|
75
|
-
else
|
76
|
-
node
|
77
|
-
end
|
78
|
-
end
|
79
88
|
end # NodeHelpers
|
80
89
|
end # Unparser
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Unparser
|
4
|
+
# Original code before vendoring and reduction from: https://github.com/mbj/mutant/blob/main/lib/mutant/util.rb
|
5
|
+
module Util
|
6
|
+
# Error raised by `Util.one` if size is not exactly one
|
7
|
+
SizeError = Class.new(IndexError)
|
8
|
+
|
9
|
+
# Return only element in array if it contains exactly one member
|
10
|
+
#
|
11
|
+
# @param array [Array]
|
12
|
+
#
|
13
|
+
# @return [Object] first entry
|
14
|
+
def self.one(array)
|
15
|
+
case array
|
16
|
+
in [value]
|
17
|
+
value
|
18
|
+
else
|
19
|
+
fail SizeError, "expected size to be exactly 1 but size was #{array.size}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|