Skip to content

Commit e5925c5

Browse files
committed
Fix rubyspec / dstring collapse
* Removes preprocessing into non equivalent AST (turned out to be an antifeature) * Fix rubyspec location to reflect new repository location * Update excludes * Trade more correct AST for more ugly source.
1 parent d648b42 commit e5925c5

10 files changed

Lines changed: 34 additions & 209 deletions

File tree

config/flay.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
---
22
threshold: 13
3-
total_score: 670
3+
total_score: 663

config/flog.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
threshold: 23.7
2+
threshold: 21.3

lib/unparser/emitter/begin.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def terminated?
3636
children.empty?
3737
end
3838

39-
TERMINATING_PARENT = [:root, :dyn_str_body].to_set.freeze
39+
TERMINATING_PARENT = %i(root interpolated dyn_str_body).to_set.freeze
4040

4141
private
4242

lib/unparser/emitter/literal/dynamic.rb

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,7 @@ class Dynamic < self
1515
#
1616
def dispatch
1717
util = self.class
18-
if interpolation?
19-
visit_parentheses(dynamic_body, util::OPEN, util::CLOSE)
20-
else
21-
emit_non_interpolated
22-
end
23-
end
24-
25-
# Test for interpolation
26-
#
27-
# @return [Boolean]
28-
#
29-
# @api private
30-
#
31-
def interpolation?
32-
children.any? { |child| !child.type.equal?(:str) }
18+
visit_parentheses(dynamic_body, util::OPEN, util::CLOSE)
3319
end
3420

3521
# Return dynamic body
@@ -48,18 +34,6 @@ class String < self
4834
OPEN = CLOSE = '"'.freeze
4935
handle :dstr
5036

51-
private
52-
53-
# Emit non interpolated form
54-
#
55-
# @return [undefined]
56-
#
57-
# @api private
58-
#
59-
def emit_non_interpolated
60-
delimited(children, WS)
61-
end
62-
6337
end # String
6438

6539
# Dynamic symbol literal emitter
@@ -70,21 +44,8 @@ class Symbol < self
7044

7145
handle :dsym
7246

73-
private
74-
75-
# Emit non interpolated form
76-
#
77-
# @return [undefined]
78-
#
79-
# @api private
80-
#
81-
def emit_non_interpolated
82-
visit_parentheses(dynamic_body, OPEN, CLOSE)
83-
end
84-
8547
end # Symbol
86-
87-
end
48+
end # Dynamic
8849
end # Literal
8950
end # Emitter
9051
end # Unparser

lib/unparser/emitter/literal/dynamic_body.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,6 @@ def dispatch
5252
# @api private
5353
#
5454
def emit_segment(node)
55-
if node.type == :str
56-
emit_str_segment(node)
57-
return
58-
end
5955
emit_interpolated_segment(node)
6056
end
6157

lib/unparser/preprocessor.rb

Lines changed: 0 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -101,127 +101,6 @@ def result
101101

102102
end # Noop
103103

104-
# Preprocessor for dynamic string regexp and xtr nodes. Collapses adjacent string segments into one.
105-
class CollapseStrChildren < self
106-
107-
register :dstr
108-
register :regexp
109-
register :xstr
110-
111-
# Return preprocessor result
112-
#
113-
# @return [Parser::AST::Node]
114-
#
115-
# @api private
116-
#
117-
def result
118-
node.updated(nil, collapsed_children)
119-
end
120-
121-
private
122-
123-
# Return collapsed children
124-
#
125-
# @return [Array<Parser::AST::Node>]
126-
#
127-
# @api private
128-
#
129-
def collapsed_children
130-
chunked_children.each_with_object([]) do |(type, nodes), aggregate|
131-
if type.equal?(:str)
132-
aggregate << s(:str, nodes.map { |node| node.children.first }.join)
133-
else
134-
aggregate.concat(nodes)
135-
end
136-
end
137-
end
138-
memoize :collapsed_children
139-
140-
# Return chunked children
141-
#
142-
# @return [Array<Parser::AST::Node>]
143-
#
144-
# @api private
145-
#
146-
def chunked_children
147-
visited_children.chunk(&:type)
148-
end
149-
150-
end # CollapseStrChildren
151-
152-
# Preprocessor flattening unneeded dstr nesting. This happens when a dstr is generated from
153-
# implicit string concatenation, and one of the strings being concatenated is itself a dstr.
154-
#
155-
# Example: "foo" "bar #{baz}"
156-
#
157-
# Without this preprocessor, this turns into: "foo#{"bar#{baz}"}"
158-
# With this preprocessor, this turns into: "foobar #{baz}"
159-
class FlattenImplicitDSTR < self
160-
161-
# No need to register :dsym, because Ruby doesn't do implicit concatenation of symbols
162-
register :dstr
163-
164-
FLATTEN_CHILDREN = IceNine.deep_freeze([:dstr, :str])
165-
166-
# Return preprocessor result
167-
#
168-
# @return [Parser::AST::Node]
169-
#
170-
# @api private
171-
#
172-
def result
173-
return node unless implicit_dstr?
174-
175-
flat_children = children.flat_map do |child|
176-
child.type.equal?(:dstr) ? child.children : child
177-
end
178-
node.updated(nil, flat_children)
179-
end
180-
181-
private
182-
183-
# Test for implicit dstr
184-
#
185-
# This should only ever be true for dstr nodes that are a result of implicit concatenation
186-
# (see the comments on this class). Any other dstr node would have a :begin node as a child.
187-
#
188-
# @return [Boolean]
189-
#
190-
# @api private
191-
#
192-
def implicit_dstr?
193-
children.map(&:type).all?(&FLATTEN_CHILDREN.method(:include?))
194-
end
195-
196-
end # FlattenImplicitDSTR
197-
198-
# Preprocessor eliminating unneeded dstr nodes
199-
class CompactDSTR < self
200-
201-
register :dstr
202-
register :dsym
203-
204-
MAP = IceNine.deep_freeze(
205-
dstr: :str,
206-
dsym: :sym
207-
)
208-
209-
# Return preprocessor result
210-
#
211-
# @return [Parser::AST::Node]
212-
#
213-
# @api private
214-
#
215-
def result
216-
if children.any? && children.all? { |child| child.type.equal?(:str) }
217-
node.updated(MAP.fetch(node.type), [children.map { |child| child.children.first }.join])
218-
else
219-
node
220-
end
221-
end
222-
223-
end # CompactDSTR
224-
225104
# Preprocessor transforming numeric nodes with infinity as value to round trippable aequivalent.
226105
class Infinity < self
227106

spec/integration/unparser/corpus_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def system(arguments)
8484
if block_given?
8585
yield
8686
else
87-
raise 'System command failed!'
87+
raise "System command #{arguments.inspect} failed!"
8888
end
8989
end
9090

spec/integrations.yml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,25 @@
1212
repo_uri: 'https://github.com/ahawkins/chassis.git'
1313
exclude: []
1414
- name: rubyspec
15-
repo_uri: 'https://github.com/rubyspec/rubyspec.git'
15+
repo_uri: 'https://github.com/ruby/spec.git'
1616
exclude:
1717
# Binary encoded source subjected to limitations see Readme
18-
- core/array/pack/{b,h,u}_spec.rb
19-
- language/versions/*1.8*
18+
- core/array/pack/{b,c,h,m,u,w}_spec.rb
2019
- core/array/pack/shared/float.rb
2120
- core/array/pack/shared/integer.rb
22-
- core/array/pack/{c,m,w}_spec.rb
23-
- core/regexp/shared/new.rb
24-
- core/regexp/shared/quote.rb
2521
- core/encoding/compatible_spec.rb
26-
- core/io/readpartial_spec.rb
2722
- core/env/element_reference_spec.rb
28-
- core/dir/pwd_spec.rb
23+
- core/io/readpartial_spec.rb
2924
- core/regexp/shared/new_ascii_8bit.rb
30-
- core/regexp/encoding_spec.rb
25+
- core/regexp/shared/quote.rb
3126
- core/string/casecmp_spec.rb
3227
- core/string/unpack/{b,c,h,m,u,w}_spec.rb
33-
- core/string/unpack/b_spec.rb
3428
- core/string/unpack/shared/float.rb
3529
- core/string/unpack/shared/integer.rb
36-
- core/symbol/casecmp_spec.rb
30+
- library/zlib/gzipwriter/write_spec.rb
3731
- optional/capi/integer_spec.rb
32+
# parser crashes
33+
- core/symbol/casecmp_spec.rb
34+
- language/regexp/escapes_spec.rb
35+
- library/conditionvariable/broadcast_spec.rb
36+
- library/conditionvariable/signal_spec.rb

spec/unit/unparser/emitter/class_methods/handle_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require 'spec_helper'
22

3-
describe Unparser::Emitter, '.handle' do
3+
describe Unparser::Emitter, '.handle', mutant_expression: 'Unparser::Emitter*' do
44
subject { class_under_test.class_eval { handle :foo } }
55

66
let(:class_under_test) do

spec/unit/unparser_spec.rb

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require 'spec_helper'
22

3-
describe Unparser do
3+
describe Unparser, mutant_expression: 'Unparser::Emitter*' do
44
describe '.unparse' do
55

66
PARSERS = IceNine.deep_freeze(
@@ -137,20 +137,17 @@ def foo(bar:, baz: "value")
137137
end
138138

139139
context 'string' do
140-
assert_generates '?c', '"c"'
141-
assert_generates '"foo" "bar"', '"foobar"'
142-
assert_generates '"foo" "bar #{baz}"', '"foobar #{baz}"'
143-
assert_generates '%Q(foo"#{@bar})', '"foo\\"#{@bar}"'
140+
assert_generates '?c', '"c"'
141+
assert_generates '"foo" "bar"', '"#{"foo"}#{"bar"}"'
142+
assert_generates '"foo" "bar #{baz}"', '"#{"foo"}#{"#{"bar "}#{baz}"}"'
143+
assert_generates '%Q(foo"#{@bar})', '"#{"foo\\""}#{@bar}"'
144+
assert_generates '"foo#{1}bar"', '"#{"foo"}#{1}#{"bar"}"'
145+
assert_generates '"\\\\#{}"', '"#{"\\\\"}#{}"'
146+
assert_generates '"#{}\#{}"', '"#{}#{"\#{}"}"'
147+
assert_generates '"\#{}#{}"', '"#{"\#{}"}#{}"'
144148
assert_terminated '"\""'
145-
assert_terminated '"foo#{1}bar"'
146-
assert_terminated '"\"#{@a}"'
147-
assert_terminated '"\\\\#{}"'
148149
assert_terminated '"foo bar"'
149150
assert_terminated '"foo\nbar"'
150-
assert_terminated '"foo bar #{}"'
151-
assert_terminated '"foo\nbar #{}"'
152-
assert_terminated '"#{}\#{}"'
153-
assert_terminated '"\#{}#{}"'
154151
# Within indentation
155152
assert_generates <<-'RUBY', <<-'RUBY'
156153
if foo
@@ -160,21 +157,17 @@ def foo(bar:, baz: "value")
160157
end
161158
RUBY
162159
if foo
163-
"\n #{foo}\n "
160+
"#{"\n"}#{" "}#{foo}#{"\n"}#{" "}"
164161
end
165162
RUBY
166-
167-
assert_terminated '"foo#{@bar}"'
168-
assert_terminated '"fo\no#{bar}b\naz"'
169163
end
170164

171165
context 'execute string' do
172-
assert_terminated '`foo`'
173-
assert_terminated '`foo#{@bar}`'
174-
assert_generates '%x(\))', '`)`'
175-
# FIXME: Research into this one!
176-
# assert_generates '%x(`)', '`\``'
177-
assert_terminated '`"`'
166+
assert_generates '`foo`', '`#{"foo"}`'
167+
assert_generates '`foo#{@bar}`', '`#{"foo"}#{@bar}`'
168+
assert_generates '%x(\))', '`#{")"}`'
169+
assert_generates '%x(`)', '`#{"`"}`'
170+
assert_generates '`"`', '`#{"\\""}`'
178171
end
179172

180173
context 'symbol' do
@@ -211,11 +204,8 @@ def foo(bar:, baz: "value")
211204
end
212205

213206
context 'dynamic symbol' do
214-
assert_terminated ':"foo#{bar}baz"'
215-
assert_terminated ':"fo\no#{bar}b\naz"'
216-
assert_terminated ':"#{bar}foo"'
217-
assert_terminated ':"#{"foo"}"'
218-
assert_terminated ':"foo#{bar}"'
207+
assert_generates ':"foo#{bar}baz"', ':"#{"foo"}#{bar}#{"baz"}"'
208+
assert_source ':"#{"foo"}"'
219209
end
220210

221211
context 'irange' do

0 commit comments

Comments
 (0)