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

Commit 38a1b03

Browse files
committed
Fold IfMod into If and UnlessMod into Unless
1 parent 5afee6b commit 38a1b03

File tree

6 files changed

+77
-202
lines changed

6 files changed

+77
-202
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
66

77
## [Unreleased]
88

9+
### Changed
10+
11+
- Nodes no longer have a `comments:` keyword on their initializers. By default, they initialize to an empty array. If you were previously passing comments into the initializer, you should now create the node first, then call `node.comments.concat` to add your comments.
12+
- `IfMod` and `UnlessMod` are no longer nodes. Instead, they have been folded into `If` and `Unless`, respectively. The `If` and `Unless` nodes now have a `modifier?` method to tell you if they were original found in the modifier form.
13+
914
## [4.3.0] - 2022-10-28
1015

1116
### Added

lib/syntax_tree/node.rb

Lines changed: 63 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -2071,8 +2071,7 @@ def forced_brace_bounds?(q)
20712071
when Paren, Statements
20722072
# If we hit certain breakpoints then we know we're safe.
20732073
return false
2074-
when If, IfMod, IfOp, Unless, UnlessMod, While, WhileMod, Until,
2075-
UntilMod
2074+
when If, IfOp, Unless, While, WhileMod, Until, UntilMod
20762075
return true if parent.predicate == previous
20772076
end
20782077

@@ -3884,7 +3883,7 @@ def format(q)
38843883
q.format(left) if left
38853884

38863885
case q.parent
3887-
when If, IfMod, Unless, UnlessMod
3886+
when If, Unless
38883887
q.text(" #{operator} ")
38893888
else
38903889
q.text(operator)
@@ -5398,10 +5397,10 @@ def call(q, node)
53985397
# and default instead to breaking them into multiple lines.
53995398
def ternaryable?(statement)
54005399
case statement
5401-
when Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfMod,
5402-
IfOp, Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0,
5403-
Super, Undef, Unless, UnlessMod, Until, UntilMod, VarAlias,
5404-
VoidStmt, While, WhileMod, Yield, Yield0, ZSuper
5400+
when Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp,
5401+
Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super,
5402+
Undef, Unless, Until, UntilMod, VarAlias, VoidStmt, While,
5403+
WhileMod, Yield, Yield0, ZSuper
54055404
# This is a list of nodes that should not be allowed to be a part of a
54065405
# ternary clause.
54075406
false
@@ -5432,41 +5431,60 @@ def initialize(keyword, node)
54325431
end
54335432

54345433
def format(q)
5435-
# If we can transform this node into a ternary, then we're going to print
5436-
# a special version that uses the ternary operator if it fits on one line.
5437-
if Ternaryable.call(q, node)
5438-
format_ternary(q)
5439-
return
5440-
end
5434+
if node.modifier?
5435+
statement = node.statements.body[0]
54415436

5442-
# If the predicate of the conditional contains an assignment (in which
5443-
# case we can't know for certain that that assignment doesn't impact the
5444-
# statements inside the conditional) then we can't use the modifier form
5445-
# and we must use the block form.
5446-
if ContainsAssignment.call(node.predicate)
5447-
format_break(q, force: true)
5448-
return
5449-
end
5450-
5451-
if node.consequent || node.statements.empty? || contains_conditional?
5452-
q.group { format_break(q, force: true) }
5437+
if ContainsAssignment.call(statement) || q.parent.is_a?(In)
5438+
q.group { format_flat(q) }
5439+
else
5440+
q.group { q.if_break { format_break(q, force: false) }.if_flat { format_flat(q) } }
5441+
end
54535442
else
5454-
q.group do
5455-
q
5456-
.if_break { format_break(q, force: false) }
5457-
.if_flat do
5458-
Parentheses.flat(q) do
5459-
q.format(node.statements)
5460-
q.text(" #{keyword} ")
5461-
q.format(node.predicate)
5443+
# If we can transform this node into a ternary, then we're going to
5444+
# print a special version that uses the ternary operator if it fits on
5445+
# one line.
5446+
if Ternaryable.call(q, node)
5447+
format_ternary(q)
5448+
return
5449+
end
5450+
5451+
# If the predicate of the conditional contains an assignment (in which
5452+
# case we can't know for certain that that assignment doesn't impact the
5453+
# statements inside the conditional) then we can't use the modifier form
5454+
# and we must use the block form.
5455+
if ContainsAssignment.call(node.predicate)
5456+
format_break(q, force: true)
5457+
return
5458+
end
5459+
5460+
if node.consequent || node.statements.empty? || contains_conditional?
5461+
q.group { format_break(q, force: true) }
5462+
else
5463+
q.group do
5464+
q
5465+
.if_break { format_break(q, force: false) }
5466+
.if_flat do
5467+
Parentheses.flat(q) do
5468+
q.format(node.statements)
5469+
q.text(" #{keyword} ")
5470+
q.format(node.predicate)
5471+
end
54625472
end
5463-
end
5473+
end
54645474
end
54655475
end
54665476
end
54675477

54685478
private
54695479

5480+
def format_flat(q)
5481+
Parentheses.flat(q) do
5482+
q.format(node.statements.body[0])
5483+
q.text(" #{keyword} ")
5484+
q.format(node.predicate)
5485+
end
5486+
end
5487+
54705488
def format_break(q, force:)
54715489
q.text("#{keyword} ")
54725490
q.nest(keyword.length + 1) { q.format(node.predicate) }
@@ -5537,7 +5555,7 @@ def contains_conditional?
55375555
return false if statements.length != 1
55385556

55395557
case statements.first
5540-
when If, IfMod, IfOp, Unless, UnlessMod
5558+
when If, IfOp, Unless
55415559
true
55425560
else
55435561
false
@@ -5600,6 +5618,11 @@ def deconstruct_keys(_keys)
56005618
def format(q)
56015619
ConditionalFormatter.new("if", self).format(q)
56025620
end
5621+
5622+
# Checks if the node was originally found in the modifier form.
5623+
def modifier?
5624+
predicate.location.start_char > statements.location.start_char
5625+
end
56035626
end
56045627

56055628
# IfOp represents a ternary clause.
@@ -5649,10 +5672,9 @@ def deconstruct_keys(_keys)
56495672

56505673
def format(q)
56515674
force_flat = [
5652-
Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfMod, IfOp,
5653-
Lambda, MAssign, Next, OpAssign, RescueMod, Return, Return0, Super,
5654-
Undef, Unless, UnlessMod, UntilMod, VarAlias, VoidStmt, WhileMod, Yield,
5655-
Yield0, ZSuper
5675+
Alias, Assign, Break, Command, CommandCall, Heredoc, If, IfOp, Lambda,
5676+
MAssign, Next, OpAssign, RescueMod, Return, Return0, Super, Undef,
5677+
Unless, UntilMod, VarAlias, VoidStmt, WhileMod, Yield, Yield0, ZSuper
56565678
]
56575679

56585680
if q.parent.is_a?(Paren) || force_flat.include?(truthy.class) ||
@@ -5704,94 +5726,6 @@ def format_flat(q)
57045726
end
57055727
end
57065728

5707-
# Formats an IfMod or UnlessMod node.
5708-
class ConditionalModFormatter
5709-
# [String] the keyword associated with this conditional
5710-
attr_reader :keyword
5711-
5712-
# [IfMod | UnlessMod] the node that is being formatted
5713-
attr_reader :node
5714-
5715-
def initialize(keyword, node)
5716-
@keyword = keyword
5717-
@node = node
5718-
end
5719-
5720-
def format(q)
5721-
if ContainsAssignment.call(node.statement) || q.parent.is_a?(In)
5722-
q.group { format_flat(q) }
5723-
else
5724-
q.group { q.if_break { format_break(q) }.if_flat { format_flat(q) } }
5725-
end
5726-
end
5727-
5728-
private
5729-
5730-
def format_break(q)
5731-
q.text("#{keyword} ")
5732-
q.nest(keyword.length + 1) { q.format(node.predicate) }
5733-
q.indent do
5734-
q.breakable_space
5735-
q.format(node.statement)
5736-
end
5737-
q.breakable_space
5738-
q.text("end")
5739-
end
5740-
5741-
def format_flat(q)
5742-
Parentheses.flat(q) do
5743-
q.format(node.statement)
5744-
q.text(" #{keyword} ")
5745-
q.format(node.predicate)
5746-
end
5747-
end
5748-
end
5749-
5750-
# IfMod represents the modifier form of an +if+ statement.
5751-
#
5752-
# expression if predicate
5753-
#
5754-
class IfMod < Node
5755-
# [untyped] the expression to be executed
5756-
attr_reader :statement
5757-
5758-
# [untyped] the expression to be checked
5759-
attr_reader :predicate
5760-
5761-
# [Array[ Comment | EmbDoc ]] the comments attached to this node
5762-
attr_reader :comments
5763-
5764-
def initialize(statement:, predicate:, location:)
5765-
@statement = statement
5766-
@predicate = predicate
5767-
@location = location
5768-
@comments = []
5769-
end
5770-
5771-
def accept(visitor)
5772-
visitor.visit_if_mod(self)
5773-
end
5774-
5775-
def child_nodes
5776-
[statement, predicate]
5777-
end
5778-
5779-
alias deconstruct child_nodes
5780-
5781-
def deconstruct_keys(_keys)
5782-
{
5783-
statement: statement,
5784-
predicate: predicate,
5785-
location: location,
5786-
comments: comments
5787-
}
5788-
end
5789-
5790-
def format(q)
5791-
ConditionalModFormatter.new("if", self).format(q)
5792-
end
5793-
end
5794-
57955729
# Imaginary represents an imaginary number literal.
57965730
#
57975731
# 1i
@@ -9443,50 +9377,10 @@ def deconstruct_keys(_keys)
94439377
def format(q)
94449378
ConditionalFormatter.new("unless", self).format(q)
94459379
end
9446-
end
9447-
9448-
# UnlessMod represents the modifier form of an +unless+ statement.
9449-
#
9450-
# expression unless predicate
9451-
#
9452-
class UnlessMod < Node
9453-
# [untyped] the expression to be executed
9454-
attr_reader :statement
9455-
9456-
# [untyped] the expression to be checked
9457-
attr_reader :predicate
9458-
9459-
# [Array[ Comment | EmbDoc ]] the comments attached to this node
9460-
attr_reader :comments
9461-
9462-
def initialize(statement:, predicate:, location:)
9463-
@statement = statement
9464-
@predicate = predicate
9465-
@location = location
9466-
@comments = []
9467-
end
9468-
9469-
def accept(visitor)
9470-
visitor.visit_unless_mod(self)
9471-
end
9472-
9473-
def child_nodes
9474-
[statement, predicate]
9475-
end
9476-
9477-
alias deconstruct child_nodes
9478-
9479-
def deconstruct_keys(_keys)
9480-
{
9481-
statement: statement,
9482-
predicate: predicate,
9483-
location: location,
9484-
comments: comments
9485-
}
9486-
end
94879380

9488-
def format(q)
9489-
ConditionalModFormatter.new("unless", self).format(q)
9381+
# Checks if the node was originally found in the modifier form.
9382+
def modifier?
9383+
predicate.location.start_char > statements.location.start_char
94909384
end
94919385
end
94929386

lib/syntax_tree/parser.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1911,13 +1911,14 @@ def on_ifop(predicate, truthy, falsy)
19111911
end
19121912

19131913
# :call-seq:
1914-
# on_if_mod: (untyped predicate, untyped statement) -> IfMod
1914+
# on_if_mod: (untyped predicate, untyped statement) -> If
19151915
def on_if_mod(predicate, statement)
19161916
consume_keyword(:if)
19171917

1918-
IfMod.new(
1919-
statement: statement,
1918+
If.new(
19201919
predicate: predicate,
1920+
statements: Statements.new(self, body: [statement], location: statement.location),
1921+
consequent: nil,
19211922
location: statement.location.to(predicate.location)
19221923
)
19231924
end
@@ -3586,13 +3587,14 @@ def on_unless(predicate, statements, consequent)
35863587
end
35873588

35883589
# :call-seq:
3589-
# on_unless_mod: (untyped predicate, untyped statement) -> UnlessMod
3590+
# on_unless_mod: (untyped predicate, untyped statement) -> Unless
35903591
def on_unless_mod(predicate, statement)
35913592
consume_keyword(:unless)
35923593

3593-
UnlessMod.new(
3594-
statement: statement,
3594+
Unless.new(
35953595
predicate: predicate,
3596+
statements: Statements.new(self, body: [statement], location: statement.location),
3597+
consequent: nil,
35963598
location: statement.location.to(predicate.location)
35973599
)
35983600
end

lib/syntax_tree/visitor.rb

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,6 @@ class Visitor < BasicVisitor
206206
# Visit an If node.
207207
alias visit_if visit_child_nodes
208208

209-
# Visit an IfMod node.
210-
alias visit_if_mod visit_child_nodes
211-
212209
# Visit an IfOp node.
213210
alias visit_if_op visit_child_nodes
214211

@@ -431,9 +428,6 @@ class Visitor < BasicVisitor
431428
# Visit an Unless node.
432429
alias visit_unless visit_child_nodes
433430

434-
# Visit an UnlessMod node.
435-
alias visit_unless_mod visit_child_nodes
436-
437431
# Visit an Until node.
438432
alias visit_until visit_child_nodes
439433

0 commit comments

Comments
 (0)