unparser 0.6.5 → 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 +11 -6
- data/bin/unparser +1 -1
- data/lib/unparser/adamantium.rb +3 -1
- data/lib/unparser/anima.rb +11 -0
- data/lib/unparser/ast/local_variable_scope.rb +28 -25
- data/lib/unparser/ast.rb +18 -22
- data/lib/unparser/buffer.rb +43 -15
- data/lib/unparser/cli.rb +30 -7
- data/lib/unparser/color.rb +5 -0
- data/lib/unparser/either.rb +6 -6
- data/lib/unparser/emitter/args.rb +5 -1
- data/lib/unparser/emitter/argument.rb +6 -4
- 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/flipflop.rb +7 -2
- data/lib/unparser/emitter/flow_modifier.rb +1 -7
- data/lib/unparser/emitter/for.rb +1 -1
- data/lib/unparser/emitter/hash.rb +0 -16
- 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 +7 -11
- 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 -5
- data/lib/unparser/emitter/pair.rb +31 -5
- data/lib/unparser/emitter/primitive.rb +19 -6
- 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 +33 -29
- data/lib/unparser/node_details/send.rb +4 -3
- data/lib/unparser/node_details.rb +1 -0
- data/lib/unparser/node_helpers.rb +19 -9
- data/lib/unparser/util.rb +23 -0
- data/lib/unparser/validation.rb +70 -28
- data/lib/unparser/writer/array.rb +51 -0
- data/lib/unparser/writer/binary.rb +8 -4
- data/lib/unparser/writer/dynamic_string.rb +127 -146
- 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 +38 -20
|
@@ -5,7 +5,7 @@ module Unparser
|
|
|
5
5
|
|
|
6
6
|
# Block emitter
|
|
7
7
|
class Block < self
|
|
8
|
-
handle :block, :numblock
|
|
8
|
+
handle :block, :numblock, :itblock
|
|
9
9
|
|
|
10
10
|
children :target, :arguments, :body
|
|
11
11
|
|
|
@@ -16,7 +16,6 @@ module Unparser
|
|
|
16
16
|
ws
|
|
17
17
|
write_open
|
|
18
18
|
emit_block_arguments unless n_lambda?(target)
|
|
19
|
-
target_writer.emit_heredoc_reminders if n_send?(target)
|
|
20
19
|
emit_optional_body_ensure_rescue(body)
|
|
21
20
|
write_close
|
|
22
21
|
end
|
|
@@ -42,7 +41,7 @@ module Unparser
|
|
|
42
41
|
end
|
|
43
42
|
|
|
44
43
|
def target_writer
|
|
45
|
-
writer_with(Writer::Send::Regular, target)
|
|
44
|
+
writer_with(Writer::Send::Regular, node: target)
|
|
46
45
|
end
|
|
47
46
|
memoize :target_writer
|
|
48
47
|
|
|
@@ -65,20 +64,28 @@ module Unparser
|
|
|
65
64
|
end
|
|
66
65
|
|
|
67
66
|
def emit_lambda_arguments
|
|
68
|
-
parentheses { writer_with(Args, arguments).emit_lambda_arguments }
|
|
67
|
+
parentheses { writer_with(Args, node: arguments).emit_lambda_arguments }
|
|
69
68
|
end
|
|
70
69
|
|
|
71
70
|
def numblock?
|
|
72
71
|
node.type.equal?(:numblock)
|
|
73
72
|
end
|
|
74
73
|
|
|
74
|
+
# NOTE: mutant fails on Ruby < 3.4
|
|
75
|
+
# mutant:disable
|
|
76
|
+
def itblock?
|
|
77
|
+
node.type.equal?(:itblock)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# NOTE: mutant fails on Ruby < 3.4
|
|
81
|
+
# mutant:disable
|
|
75
82
|
def emit_block_arguments
|
|
76
|
-
return if numblock? || arguments.children.empty?
|
|
83
|
+
return if numblock? || itblock? || arguments.children.empty?
|
|
77
84
|
|
|
78
85
|
ws
|
|
79
86
|
|
|
80
87
|
parentheses('|', '|') do
|
|
81
|
-
writer_with(Args, arguments).emit_block_arguments
|
|
88
|
+
writer_with(Args, node: arguments).emit_block_arguments
|
|
82
89
|
end
|
|
83
90
|
end
|
|
84
91
|
|
data/lib/unparser/emitter/def.rb
CHANGED
|
@@ -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,18 +6,6 @@ module Unparser
|
|
|
6
6
|
class Hash < self
|
|
7
7
|
handle :hash
|
|
8
8
|
|
|
9
|
-
def emit_last_argument_hash
|
|
10
|
-
if children.empty?
|
|
11
|
-
write('{}')
|
|
12
|
-
else
|
|
13
|
-
emit_hash_body
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def emit_heredoc_reminders
|
|
18
|
-
children.each(&method(:emit_heredoc_reminder_member))
|
|
19
|
-
end
|
|
20
|
-
|
|
21
9
|
private
|
|
22
10
|
|
|
23
11
|
def dispatch
|
|
@@ -32,10 +20,6 @@ module Unparser
|
|
|
32
20
|
end
|
|
33
21
|
end
|
|
34
22
|
|
|
35
|
-
def emit_heredoc_reminder_member(node)
|
|
36
|
-
emitter(node.children.last).emit_heredoc_reminders
|
|
37
|
-
end
|
|
38
|
-
|
|
39
23
|
def emit_hash_body
|
|
40
24
|
delimited(children)
|
|
41
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
|
|
@@ -9,21 +9,17 @@ module Unparser
|
|
|
9
9
|
|
|
10
10
|
children :target, :pattern
|
|
11
11
|
|
|
12
|
-
# Modern ast format emits `match_pattern`
|
|
13
|
-
# node on single line pre 3.0, but 3.0+ uses `match_pattern_p`
|
|
14
|
-
SYMBOL =
|
|
15
|
-
if RUBY_VERSION < '3.0'
|
|
16
|
-
' in '
|
|
17
|
-
else
|
|
18
|
-
' => '
|
|
19
|
-
end
|
|
20
|
-
|
|
21
12
|
private
|
|
22
13
|
|
|
23
14
|
def dispatch
|
|
24
15
|
visit(target)
|
|
25
|
-
write(
|
|
26
|
-
|
|
16
|
+
write(' => ')
|
|
17
|
+
|
|
18
|
+
if n_array?(pattern)
|
|
19
|
+
writer_with(Writer::Array, node: pattern).emit_compact
|
|
20
|
+
else
|
|
21
|
+
visit(pattern)
|
|
22
|
+
end
|
|
27
23
|
end
|
|
28
24
|
end # MatchPattern
|
|
29
25
|
end # Emitter
|
|
@@ -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
|
|
@@ -15,19 +15,45 @@ module Unparser
|
|
|
15
15
|
private
|
|
16
16
|
|
|
17
17
|
def dispatch
|
|
18
|
-
if colon?
|
|
19
|
-
|
|
18
|
+
if colon?
|
|
19
|
+
emit_colon
|
|
20
|
+
unless implicit_value_lvar? || implicit_value_send?
|
|
21
|
+
write(' ')
|
|
22
|
+
visit(value)
|
|
23
|
+
end
|
|
20
24
|
else
|
|
21
25
|
visit(key)
|
|
22
26
|
write(' => ')
|
|
27
|
+
visit(value)
|
|
23
28
|
end
|
|
24
|
-
|
|
25
|
-
visit(value)
|
|
26
29
|
end
|
|
27
30
|
|
|
28
|
-
def colon?
|
|
31
|
+
def colon?
|
|
29
32
|
n_sym?(key) && BAREWORD.match?(key.children.first)
|
|
30
33
|
end
|
|
34
|
+
|
|
35
|
+
def emit_colon
|
|
36
|
+
write(key.children.first.to_s, ':')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def key_value
|
|
40
|
+
key.children.first
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def implicit_value_lvar?
|
|
44
|
+
n_lvar?(value) && value.children.first.equal?(key_value)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def implicit_value_send?
|
|
48
|
+
children = value.children
|
|
49
|
+
|
|
50
|
+
n_send?(value) \
|
|
51
|
+
&& !key_value.end_with?('?') \
|
|
52
|
+
&& !key_value.end_with?('!') \
|
|
53
|
+
&& children.fetch(0).nil? \
|
|
54
|
+
&& children.fetch(1).equal?(key_value) \
|
|
55
|
+
&& children.at(2).nil?
|
|
56
|
+
end
|
|
31
57
|
end
|
|
32
58
|
end
|
|
33
59
|
end
|
|
@@ -7,18 +7,31 @@ module Unparser
|
|
|
7
7
|
|
|
8
8
|
children :value
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
class Inspect < self
|
|
10
|
+
class Symbol < self
|
|
12
11
|
|
|
13
|
-
handle :sym
|
|
12
|
+
handle :sym
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
private
|
|
16
15
|
|
|
16
|
+
# mutant:disable
|
|
17
17
|
def dispatch
|
|
18
|
-
|
|
18
|
+
if inspect_breaks_parsing?
|
|
19
|
+
write(":#{value.name.inspect}")
|
|
20
|
+
else
|
|
21
|
+
write(value.inspect)
|
|
22
|
+
end
|
|
19
23
|
end
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
# mutant:disable
|
|
26
|
+
def inspect_breaks_parsing?
|
|
27
|
+
return false unless RUBY_VERSION < '3.2.'
|
|
28
|
+
|
|
29
|
+
Unparser.parse(value.inspect)
|
|
30
|
+
false
|
|
31
|
+
rescue Parser::SyntaxError
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
end # Symbol
|
|
22
35
|
|
|
23
36
|
# Emitter for complex literals
|
|
24
37
|
class Complex < self
|
|
@@ -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
|