Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 86f4dbe

Browse files
committed
Wrap parentheses when necessary
1 parent a4e61ed commit 86f4dbe

File tree

3 files changed

+170
-95
lines changed

3 files changed

+170
-95
lines changed

bin/test

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,19 +67,16 @@ do_block.rb:4
6767
dyna_symbol.rb:0
6868
dyna_symbol.rb:4
6969
elsif.rb:0
70-
elsif.rb:2
7170
elsif.rb:3
7271
embdoc.rb:0
7372
embdoc.rb:1
7473
end_content.rb:0
7574
heredoc.rb:17
7675
heredoc.rb:18
7776
if.rb:3
78-
if.rb:4
7977
if.rb:7
8078
if.rb:10
8179
if.rb:13
82-
if_mod.rb:3
8380
ifop.rb:1
8481
ifop.rb:3
8582
label.rb:1
@@ -104,11 +101,7 @@ string_concat.rb:0
104101
string_embexpr.rb:5
105102
string_literal.rb:15
106103
string_literal.rb:16
107-
unless.rb:4
108104
unless.rb:7
109105
unless.rb:8
110-
unless_mod.rb:3
111-
until.rb:3
112106
when.rb:7
113107
when.rb:8
114-
while.rb:3

lib/syntax_tree/prism/formatter.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,5 +470,56 @@ def format_write(operator_loc, value)
470470
end
471471
end
472472
end
473+
474+
# If you have a modifier statement (for instance a modifier if statement or
475+
# a modifier while loop) there are times when you need to wrap the entire
476+
# statement in parentheses. This occurs when you have something like:
477+
#
478+
# foo[:foo] =
479+
# if bar?
480+
# baz
481+
# end
482+
#
483+
# Normally we would shorten this to an inline version, which would result in:
484+
#
485+
# foo[:foo] = baz if bar?
486+
#
487+
# but this actually has different semantic meaning. The first example will
488+
# result in a nil being inserted into the hash for the :foo key, whereas the
489+
# second example will result in an empty hash because the if statement
490+
# applies to the entire assignment.
491+
#
492+
# We can fix this in a couple of ways. We can use the then keyword, as in:
493+
#
494+
# foo[:foo] = if bar? then baz end
495+
#
496+
# But this isn't used very often. We can also just leave it as is with the
497+
# multi-line version, but for a short predicate and short value it looks
498+
# verbose. The last option and the one used here is to add parentheses on
499+
# both sides of the expression, as in:
500+
#
501+
# foo[:foo] = (baz if bar?)
502+
#
503+
# This approach maintains the nice conciseness of the inline version, while
504+
# keeping the correct semantic meaning.
505+
def format_flat_parentheses
506+
case parent&.type
507+
when :arguments_node,
508+
:call_and_write_node, :call_or_write_node, :call_operator_write_node,
509+
:class_variable_write_node, :class_variable_and_write_node, :class_variable_or_write_node, :class_variable_operator_write_node,
510+
:constant_write_node, :constant_and_write_node, :constant_or_write_node, :constant_operator_write_node,
511+
:constant_path_write_node, :constant_path_and_write_node, :constant_path_or_write_node, :constant_path_operator_write_node,
512+
:global_variable_write_node, :global_variable_and_write_node, :global_variable_or_write_node, :global_variable_operator_write_node,
513+
:instance_variable_write_node, :instance_variable_and_write_node, :instance_variable_or_write_node, :instance_variable_operator_write_node,
514+
:local_variable_write_node, :local_variable_and_write_node, :local_variable_or_write_node, :local_variable_operator_write_node,
515+
:multi_write_node,
516+
:assoc_node, :call_node, :defined_node
517+
text("(")
518+
yield
519+
text(")")
520+
else
521+
yield
522+
end
523+
end
473524
end
474525
end

lib/syntax_tree/prism/nodes.rb

Lines changed: 119 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,6 +1551,11 @@ def format(q)
15511551
q.format(statements)
15521552
end
15531553
end
1554+
1555+
if consequent
1556+
q.breakable_force
1557+
q.format(consequent)
1558+
end
15541559
end
15551560
elsif !if_keyword_loc
15561561
q.group do
@@ -1560,57 +1565,58 @@ def format(q)
15601565
q.text(" : ")
15611566
q.format(consequent.statements.body.first)
15621567
end
1563-
elsif statements.nil? || predicate.contains_write?
1568+
elsif statements.nil?
15641569
q.group do
1565-
q.loc(if_keyword_loc)
1566-
q.text(" ")
1567-
q.nest(3) { q.format(predicate) }
1568-
1569-
if statements
1570-
q.indent do
1571-
q.breakable_force
1572-
q.format(statements)
1573-
end
1574-
end
1575-
1576-
if consequent
1577-
q.breakable_force
1578-
q.format(consequent)
1570+
format_break(q)
1571+
q.break_parent
1572+
end
1573+
elsif predicate.contains_write? || statements.contains_write?
1574+
if end_keyword_loc
1575+
q.group do
1576+
format_break(q)
1577+
q.break_parent
15791578
end
1580-
1581-
q.breakable_force
1582-
q.text("end")
1579+
else
1580+
q.group { format_flat(q) }
15831581
end
15841582
else
15851583
q.group do
15861584
q
1587-
.if_break do
1588-
q.group do
1589-
q.loc(if_keyword_loc)
1590-
q.text(" ")
1591-
q.nest(3) { q.format(predicate) }
1592-
end
1585+
.if_break { format_break(q) }
1586+
.if_flat { q.format_flat_parentheses { format_flat(q) } }
1587+
end
1588+
end
1589+
end
15931590

1594-
q.indent do
1595-
q.breakable_space
1596-
q.format(statements)
1597-
end
1591+
private
15981592

1599-
if consequent
1600-
q.breakable_space
1601-
q.format(consequent)
1602-
end
1593+
def format_break(q)
1594+
q.group do
1595+
q.loc(if_keyword_loc)
1596+
q.text(" ")
1597+
q.nest(3) { q.format(predicate) }
1598+
end
16031599

1604-
q.breakable_space
1605-
q.text("end")
1606-
end
1607-
.if_flat do
1608-
q.format(statements)
1609-
q.text(" if ")
1610-
q.format(predicate)
1611-
end
1600+
if statements
1601+
q.indent do
1602+
q.breakable_space
1603+
q.format(statements)
16121604
end
16131605
end
1606+
1607+
if consequent
1608+
q.breakable_space
1609+
q.format(consequent)
1610+
end
1611+
1612+
q.breakable_space
1613+
q.text("end")
1614+
end
1615+
1616+
def format_flat(q)
1617+
q.format(statements)
1618+
q.text(" if ")
1619+
q.format(predicate)
16141620
end
16151621
end
16161622

@@ -2939,55 +2945,58 @@ def format(q)
29392945
statements = self.statements
29402946
consequent = self.consequent
29412947

2942-
if !statements || consequent || predicate.contains_write?
2948+
if !statements || consequent
29432949
q.group do
2944-
q.text("unless ")
2945-
q.nest(3) { q.format(predicate) }
2946-
2947-
if statements
2948-
q.indent do
2949-
q.breakable_force
2950-
q.format(statements)
2951-
end
2952-
end
2953-
2954-
if consequent
2955-
q.breakable_force
2956-
q.format(consequent)
2950+
format_break(q)
2951+
q.break_parent
2952+
end
2953+
elsif predicate.contains_write? || statements.contains_write?
2954+
if end_keyword_loc
2955+
q.group do
2956+
format_break(q)
2957+
q.break_parent
29572958
end
2958-
2959-
q.breakable_force
2960-
q.text("end")
2959+
else
2960+
q.group { format_flat(q) }
29612961
end
29622962
else
29632963
q.group do
29642964
q
2965-
.if_break do
2966-
q.group do
2967-
q.text("unless ")
2968-
q.nest(3) { q.format(predicate) }
2969-
end
2965+
.if_break { format_break(q) }
2966+
.if_flat { q.format_flat_parentheses { format_flat(q) } }
2967+
end
2968+
end
2969+
end
29702970

2971-
q.indent do
2972-
q.breakable_space
2973-
q.format(statements)
2974-
end
2971+
private
29752972

2976-
if consequent
2977-
q.breakable_space
2978-
q.format(consequent)
2979-
end
2973+
def format_break(q)
2974+
q.group do
2975+
q.loc(keyword_loc)
2976+
q.text(" ")
2977+
q.nest(3) { q.format(predicate) }
2978+
end
29802979

2981-
q.breakable_space
2982-
q.text("end")
2983-
end
2984-
.if_flat do
2985-
q.format(statements)
2986-
q.text(" unless ")
2987-
q.format(predicate)
2988-
end
2980+
if statements
2981+
q.indent do
2982+
q.breakable_space
2983+
q.format(statements)
29892984
end
29902985
end
2986+
2987+
if consequent
2988+
q.breakable_space
2989+
q.format(consequent)
2990+
end
2991+
2992+
q.breakable_space
2993+
q.text("end")
2994+
end
2995+
2996+
def format_flat(q)
2997+
q.format(statements)
2998+
q.text(" unless ")
2999+
q.format(predicate)
29913000
end
29923001
end
29933002

@@ -3001,13 +3010,22 @@ class UntilNode
30013010
# until foo do bar end
30023011
# ^^^^^^^^^^^^^^^^^^^^
30033012
def format(q)
3004-
if begin_modifier? || statements&.contains_write?
3013+
if begin_modifier?
30053014
q.group { format_flat(q) }
3006-
elsif statements.nil? || keyword_loc.comments.any? || closing_loc&.comments&.any? || predicate.contains_write?
3015+
elsif statements.nil? || keyword_loc.comments.any? || closing_loc&.comments&.any?
30073016
q.group do
30083017
format_break(q)
30093018
q.break_parent
30103019
end
3020+
elsif predicate.contains_write? || statements.contains_write?
3021+
if closing_loc
3022+
q.group do
3023+
format_break(q)
3024+
q.break_parent
3025+
end
3026+
else
3027+
q.group { format_flat(q) }
3028+
end
30113029
else
30123030
q.group { q.if_break { format_break(q) }.if_flat { format_flat(q) } }
30133031
end
@@ -3025,9 +3043,11 @@ def format_break(q)
30253043
end
30263044

30273045
def format_flat(q)
3028-
q.format(statements)
3029-
q.text(" until ")
3030-
q.format(predicate)
3046+
q.format_flat_parentheses do
3047+
q.format(statements)
3048+
q.text(" until ")
3049+
q.format(predicate)
3050+
end
30313051
end
30323052
end
30333053

@@ -3069,13 +3089,22 @@ class WhileNode
30693089
# while foo do bar end
30703090
# ^^^^^^^^^^^^^^^^^^^^
30713091
def format(q)
3072-
if begin_modifier? || statements&.contains_write?
3092+
if begin_modifier?
30733093
q.group { format_flat(q) }
3074-
elsif statements.nil? || keyword_loc.comments.any? || closing_loc&.comments&.any? || predicate.contains_write?
3094+
elsif statements.nil? || keyword_loc.comments.any? || closing_loc&.comments&.any?
30753095
q.group do
30763096
format_break(q)
30773097
q.break_parent
30783098
end
3099+
elsif predicate.contains_write? || statements.contains_write?
3100+
if closing_loc
3101+
q.group do
3102+
format_break(q)
3103+
q.break_parent
3104+
end
3105+
else
3106+
q.group { format_flat(q) }
3107+
end
30793108
else
30803109
q.group { q.if_break { format_break(q) }.if_flat { format_flat(q) } }
30813110
end
@@ -3093,9 +3122,11 @@ def format_break(q)
30933122
end
30943123

30953124
def format_flat(q)
3096-
q.format(statements)
3097-
q.text(" while ")
3098-
q.format(predicate)
3125+
q.format_flat_parentheses do
3126+
q.format(statements)
3127+
q.text(" while ")
3128+
q.format(predicate)
3129+
end
30993130
end
31003131
end
31013132

0 commit comments

Comments
 (0)