unparser 0.6.15 → 0.7.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/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 +26 -5
- data/lib/unparser/either.rb +6 -6
- data/lib/unparser/emitter/array.rb +0 -4
- data/lib/unparser/emitter/array_pattern.rb +1 -9
- data/lib/unparser/emitter/assignment.rb +7 -8
- data/lib/unparser/emitter/begin.rb +0 -6
- data/lib/unparser/emitter/binary.rb +1 -1
- data/lib/unparser/emitter/block.rb +3 -4
- data/lib/unparser/emitter/def.rb +1 -1
- data/lib/unparser/emitter/dstr.rb +6 -5
- data/lib/unparser/emitter/flow_modifier.rb +0 -6
- 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/index.rb +0 -4
- data/lib/unparser/emitter/op_assign.rb +0 -10
- data/lib/unparser/emitter/primitive.rb +0 -13
- 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.rb +9 -10
- data/lib/unparser/generation.rb +8 -14
- data/lib/unparser/node_details.rb +1 -0
- data/lib/unparser/validation.rb +68 -28
- data/lib/unparser/writer/dynamic_string.rb +128 -135
- data/lib/unparser/writer/regexp.rb +98 -0
- data/lib/unparser/writer/resbody.rb +30 -1
- data/lib/unparser/writer/rescue.rb +2 -6
- data/lib/unparser/writer/send.rb +8 -14
- data/lib/unparser/writer.rb +32 -1
- data/lib/unparser.rb +103 -30
- metadata +15 -13
@@ -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
|
@@ -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
|
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
|
@@ -151,7 +149,7 @@ module Unparser
|
|
151
149
|
emit_body_member(head)
|
152
150
|
|
153
151
|
tail.each do |child|
|
154
|
-
|
152
|
+
buffer.ensure_nl
|
155
153
|
|
156
154
|
nl if EXTRA_NL.include?(child.type)
|
157
155
|
|
@@ -208,21 +206,20 @@ module Unparser
|
|
208
206
|
end
|
209
207
|
|
210
208
|
def emit_rescue_postcontrol(node)
|
211
|
-
writer = writer_with(Writer::Rescue, node)
|
209
|
+
writer = writer_with(Writer::Rescue, node:)
|
212
210
|
writer.emit_postcontrol
|
213
|
-
writer.emit_heredoc_reminders
|
214
211
|
end
|
215
212
|
|
216
213
|
def emit_rescue_regular(node)
|
217
|
-
writer_with(Writer::Rescue, node).emit_regular
|
214
|
+
writer_with(Writer::Rescue, node:).emit_regular
|
218
215
|
end
|
219
216
|
|
220
|
-
def
|
221
|
-
|
217
|
+
def emitter(node)
|
218
|
+
Emitter.emitter(**to_h, node: node)
|
222
219
|
end
|
223
220
|
|
224
|
-
def
|
225
|
-
|
221
|
+
def writer_with(klass, node:, **attributes)
|
222
|
+
klass.new(to_h.merge(node: node, **attributes))
|
226
223
|
end
|
227
224
|
|
228
225
|
def visit(node)
|
@@ -230,10 +227,7 @@ module Unparser
|
|
230
227
|
end
|
231
228
|
|
232
229
|
def visit_deep(node)
|
233
|
-
emitter(node).tap
|
234
|
-
emitter.write_to_buffer
|
235
|
-
emitter.emit_heredoc_reminders
|
236
|
-
end
|
230
|
+
emitter(node).tap(&:write_to_buffer)
|
237
231
|
end
|
238
232
|
|
239
233
|
def first_child
|
data/lib/unparser/validation.rb
CHANGED
@@ -7,10 +7,14 @@ module Unparser
|
|
7
7
|
:generated_node,
|
8
8
|
:generated_source,
|
9
9
|
:identification,
|
10
|
-
:
|
10
|
+
:original_ast,
|
11
11
|
:original_source
|
12
12
|
)
|
13
13
|
|
14
|
+
class PhaseException
|
15
|
+
include Anima.new(:exception, :phase)
|
16
|
+
end
|
17
|
+
|
14
18
|
# Test if source could be unparsed successfully
|
15
19
|
#
|
16
20
|
# @return [Boolean]
|
@@ -18,10 +22,11 @@ module Unparser
|
|
18
22
|
# @api private
|
19
23
|
#
|
20
24
|
# rubocop:disable Style/OperatorMethodCall
|
25
|
+
# mutant:disable
|
21
26
|
def success?
|
22
27
|
[
|
23
28
|
original_source,
|
24
|
-
|
29
|
+
original_ast,
|
25
30
|
generated_source,
|
26
31
|
generated_node
|
27
32
|
].all?(&:right?) && generated_node.from_right.==(original_node.from_right)
|
@@ -33,7 +38,7 @@ module Unparser
|
|
33
38
|
# @return [String]
|
34
39
|
#
|
35
40
|
# @api private
|
36
|
-
#
|
41
|
+
# mutant:disable
|
37
42
|
def report
|
38
43
|
message = [identification]
|
39
44
|
|
@@ -47,48 +52,57 @@ module Unparser
|
|
47
52
|
end
|
48
53
|
memoize :report
|
49
54
|
|
55
|
+
# mutant:disable
|
56
|
+
def original_node
|
57
|
+
original_ast.fmap(&:node)
|
58
|
+
end
|
59
|
+
|
50
60
|
# Create validator from string
|
51
61
|
#
|
52
62
|
# @param [String] original_source
|
53
63
|
#
|
54
64
|
# @return [Validator]
|
65
|
+
# mutant:disable
|
55
66
|
def self.from_string(original_source)
|
56
|
-
|
57
|
-
.parse_either(original_source)
|
67
|
+
original_ast = parse_ast_either(original_source)
|
58
68
|
|
59
|
-
generated_source =
|
69
|
+
generated_source = original_ast
|
60
70
|
.lmap(&method(:const_unit))
|
61
|
-
.bind(&
|
71
|
+
.bind(&method(:unparse_ast_either))
|
62
72
|
|
63
73
|
generated_node = generated_source
|
64
74
|
.lmap(&method(:const_unit))
|
65
|
-
.bind(&
|
75
|
+
.bind(&method(:parse_ast_either))
|
76
|
+
.fmap(&:node)
|
66
77
|
|
67
78
|
new(
|
68
|
-
|
69
|
-
original_source: Either::Right.new(original_source),
|
70
|
-
original_node: original_node,
|
79
|
+
generated_node: generated_node,
|
71
80
|
generated_source: generated_source,
|
72
|
-
|
81
|
+
identification: '(string)',
|
82
|
+
original_ast: original_ast,
|
83
|
+
original_source: Either::Right.new(original_source)
|
73
84
|
)
|
74
85
|
end
|
75
86
|
|
76
|
-
# Create validator from
|
87
|
+
# Create validator from ast
|
77
88
|
#
|
78
|
-
# @param [
|
89
|
+
# @param [Unparser::AST] ast
|
79
90
|
#
|
80
91
|
# @return [Validator]
|
81
|
-
|
82
|
-
|
92
|
+
#
|
93
|
+
# mutant:disable
|
94
|
+
def self.from_ast(ast:)
|
95
|
+
generated_source = Unparser.unparse_ast_either(ast)
|
83
96
|
|
84
97
|
generated_node = generated_source
|
85
98
|
.lmap(&method(:const_unit))
|
86
|
-
.bind(&
|
99
|
+
.bind(&method(:parse_ast_either))
|
100
|
+
.fmap(&:node)
|
87
101
|
|
88
102
|
new(
|
89
103
|
identification: '(string)',
|
90
104
|
original_source: generated_source,
|
91
|
-
|
105
|
+
original_ast: Either::Right.new(ast),
|
92
106
|
generated_source: generated_source,
|
93
107
|
generated_node: generated_node
|
94
108
|
)
|
@@ -99,24 +113,45 @@ module Unparser
|
|
99
113
|
# @param [Pathname] path
|
100
114
|
#
|
101
115
|
# @return [Validator]
|
116
|
+
#
|
117
|
+
# mutant:disable
|
102
118
|
def self.from_path(path)
|
103
|
-
from_string(path.read).with(identification: path.to_s)
|
119
|
+
from_string(path.read.freeze).with(identification: path.to_s)
|
104
120
|
end
|
105
121
|
|
122
|
+
# mutant:disable
|
123
|
+
def self.unparse_ast_either(ast)
|
124
|
+
Unparser.unparse_ast_either(ast)
|
125
|
+
end
|
126
|
+
private_class_method :unparse_ast_either
|
127
|
+
|
128
|
+
# mutant:disable
|
129
|
+
def self.parse_ast_either(source)
|
130
|
+
Unparser.parse_ast_either(source)
|
131
|
+
end
|
132
|
+
private_class_method :parse_ast_either
|
133
|
+
|
134
|
+
# mutant:disable
|
135
|
+
def self.const_unit(_); end
|
136
|
+
private_class_method :const_unit
|
137
|
+
|
106
138
|
private
|
107
139
|
|
140
|
+
# mutant:disable
|
108
141
|
def make_report(label, attribute_name)
|
109
142
|
["#{label}:"].concat(public_send(attribute_name).either(method(:report_exception), ->(value) { [value] }))
|
110
143
|
end
|
111
144
|
|
112
|
-
|
113
|
-
|
114
|
-
|
145
|
+
# mutant:disable
|
146
|
+
def report_exception(phase_exception)
|
147
|
+
if phase_exception
|
148
|
+
[phase_exception.inspect].concat(phase_exception.backtrace.take(20))
|
115
149
|
else
|
116
|
-
[
|
150
|
+
%w[undefined]
|
117
151
|
end
|
118
152
|
end
|
119
153
|
|
154
|
+
# mutant:disable
|
120
155
|
def node_diff_report
|
121
156
|
diff = nil
|
122
157
|
|
@@ -132,14 +167,13 @@ module Unparser
|
|
132
167
|
diff ? ['Node-Diff:', diff] : []
|
133
168
|
end
|
134
169
|
|
135
|
-
def self.const_unit(_value); end
|
136
|
-
private_class_method :const_unit
|
137
|
-
|
138
170
|
class Literal < self
|
171
|
+
# mutant:disable
|
139
172
|
def success?
|
140
173
|
original_source.eql?(generated_source)
|
141
174
|
end
|
142
175
|
|
176
|
+
# mutant:disable
|
143
177
|
def report
|
144
178
|
message = [identification]
|
145
179
|
|
@@ -155,20 +189,26 @@ module Unparser
|
|
155
189
|
|
156
190
|
private
|
157
191
|
|
192
|
+
# mutant:disable
|
158
193
|
def source_diff_report
|
159
194
|
diff = nil
|
160
195
|
|
161
196
|
original_source.fmap do |original|
|
162
197
|
generated_source.fmap do |generated|
|
163
198
|
diff = Diff.new(
|
164
|
-
original.split("\n", -1),
|
165
|
-
generated.split("\n", -1)
|
199
|
+
encode(original).split("\n", -1),
|
200
|
+
encode(generated).split("\n", -1)
|
166
201
|
).colorized_diff
|
167
202
|
end
|
168
203
|
end
|
169
204
|
|
170
205
|
diff ? ['Source-Diff:', diff] : []
|
171
206
|
end
|
207
|
+
|
208
|
+
# mutant:disable
|
209
|
+
def encode(string)
|
210
|
+
string.encode('UTF-8', invalid: :replace, undef: :replace)
|
211
|
+
end
|
172
212
|
end # Literal
|
173
213
|
end # Validation
|
174
214
|
end # Unparser
|