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

Commit 36f2559

Browse files
committed
Combine Elsif node into IfNode
Many other Ruby ASTs do not have a separate node representing `elsif` conditionals; instead, they use the same node as `if` but make it a consequent of other `if` nodes. This commit removes the `Elsif` node and combines its functionality with `IfNode`, ensuring that both the parsing and formatting logic are still functional.
1 parent 05401da commit 36f2559

File tree

3 files changed

+38
-109
lines changed

3 files changed

+38
-109
lines changed

lib/syntax_tree/node.rb

Lines changed: 29 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ def trailing_comma?
800800
# after it without resulting in a syntax error.
801801
false
802802
elsif (parts.length == 1) && (part = parts.first) &&
803-
(part.is_a?(Command) || part.is_a?(CommandCall))
803+
(part.is_a?(Command) || part.is_a?(CommandCall))
804804
# If the only argument is a command or command call, then a trailing
805805
# comma would be parsed as part of that expression instead of on this
806806
# one, so we don't want to add a trailing comma.
@@ -4804,95 +4804,6 @@ def ===(other)
48044804
end
48054805
end
48064806

4807-
# Elsif represents another clause in an +if+ or +unless+ chain.
4808-
#
4809-
# if variable
4810-
# elsif other_variable
4811-
# end
4812-
#
4813-
class Elsif < Node
4814-
# [Node] the expression to be checked
4815-
attr_reader :predicate
4816-
4817-
# [Statements] the expressions to be executed
4818-
attr_reader :statements
4819-
4820-
# [nil | Elsif | Else] the next clause in the chain
4821-
attr_reader :consequent
4822-
4823-
# [Array[ Comment | EmbDoc ]] the comments attached to this node
4824-
attr_reader :comments
4825-
4826-
def initialize(predicate:, statements:, consequent:, location:)
4827-
@predicate = predicate
4828-
@statements = statements
4829-
@consequent = consequent
4830-
@location = location
4831-
@comments = []
4832-
end
4833-
4834-
def accept(visitor)
4835-
visitor.visit_elsif(self)
4836-
end
4837-
4838-
def child_nodes
4839-
[predicate, statements, consequent]
4840-
end
4841-
4842-
def copy(predicate: nil, statements: nil, consequent: nil, location: nil)
4843-
node =
4844-
Elsif.new(
4845-
predicate: predicate || self.predicate,
4846-
statements: statements || self.statements,
4847-
consequent: consequent || self.consequent,
4848-
location: location || self.location
4849-
)
4850-
4851-
node.comments.concat(comments.map(&:copy))
4852-
node
4853-
end
4854-
4855-
alias deconstruct child_nodes
4856-
4857-
def deconstruct_keys(_keys)
4858-
{
4859-
predicate: predicate,
4860-
statements: statements,
4861-
consequent: consequent,
4862-
location: location,
4863-
comments: comments
4864-
}
4865-
end
4866-
4867-
def format(q)
4868-
q.group do
4869-
q.group do
4870-
q.text("elsif ")
4871-
q.nest("elsif".length - 1) { q.format(predicate) }
4872-
end
4873-
4874-
unless statements.empty?
4875-
q.indent do
4876-
q.breakable_force
4877-
q.format(statements)
4878-
end
4879-
end
4880-
4881-
if consequent
4882-
q.group do
4883-
q.breakable_force
4884-
q.format(consequent)
4885-
end
4886-
end
4887-
end
4888-
end
4889-
4890-
def ===(other)
4891-
other.is_a?(Elsif) && predicate === other.predicate &&
4892-
statements === other.statements && consequent === other.consequent
4893-
end
4894-
end
4895-
48964807
# EmbDoc represents a multi-line comment.
48974808
#
48984809
# =begin
@@ -6288,7 +6199,7 @@ def format(q)
62886199
# If we can transform this node into a ternary, then we're going to
62896200
# print a special version that uses the ternary operator if it fits on
62906201
# one line.
6291-
if Ternaryable.call(q, node)
6202+
if Ternaryable.call(q, node) && keyword != "elsif"
62926203
format_ternary(q)
62936204
return
62946205
end
@@ -6297,7 +6208,7 @@ def format(q)
62976208
# case we can't know for certain that that assignment doesn't impact the
62986209
# statements inside the conditional) then we can't use the modifier form
62996210
# and we must use the block form.
6300-
if ContainsAssignment.call(node.predicate)
6211+
if keyword == "elsif" || ContainsAssignment.call(node.predicate)
63016212
format_break(q, force: true)
63026213
return
63036214
end
@@ -6346,8 +6257,10 @@ def format_break(q, force:)
63466257
q.format(node.consequent)
63476258
end
63486259

6349-
force ? q.breakable_force : q.breakable_space
6350-
q.text("end")
6260+
unless keyword == "elsif"
6261+
force ? q.breakable_force : q.breakable_space
6262+
q.text("end")
6263+
end
63516264
end
63526265

63536266
def format_ternary(q)
@@ -6408,7 +6321,7 @@ def contains_conditional?
64086321
end
64096322
end
64106323

6411-
# If represents the first clause in an +if+ chain.
6324+
# If an +if+ or +elsif+ clause in an +if+ chain.
64126325
#
64136326
# if predicate
64146327
# end
@@ -6420,17 +6333,21 @@ class IfNode < Node
64206333
# [Statements] the expressions to be executed
64216334
attr_reader :statements
64226335

6423-
# [nil | Elsif | Else] the next clause in the chain
6336+
# [nil | IfNode | Else] the next clause in the chain
64246337
attr_reader :consequent
64256338

64266339
# [Array[ Comment | EmbDoc ]] the comments attached to this node
64276340
attr_reader :comments
64286341

6429-
def initialize(predicate:, statements:, consequent:, location:)
6342+
# [ String ] the opening of the conditional statement
6343+
attr_reader :beginning
6344+
6345+
def initialize(predicate:, statements:, consequent:, location:, beginning:)
64306346
@predicate = predicate
64316347
@statements = statements
64326348
@consequent = consequent
64336349
@location = location
6350+
@beginning = beginning
64346351
@comments = []
64356352
end
64366353

@@ -6442,13 +6359,20 @@ def child_nodes
64426359
[predicate, statements, consequent]
64436360
end
64446361

6445-
def copy(predicate: nil, statements: nil, consequent: nil, location: nil)
6362+
def copy(
6363+
predicate: nil,
6364+
statements: nil,
6365+
consequent: nil,
6366+
location: nil,
6367+
beginning: nil
6368+
)
64466369
node =
64476370
IfNode.new(
64486371
predicate: predicate || self.predicate,
64496372
statements: statements || self.statements,
64506373
consequent: consequent || self.consequent,
6451-
location: location || self.location
6374+
location: location || self.location,
6375+
beginning: beginning || self.beginning
64526376
)
64536377

64546378
node.comments.concat(comments.map(&:copy))
@@ -6463,17 +6387,19 @@ def deconstruct_keys(_keys)
64636387
statements: statements,
64646388
consequent: consequent,
64656389
location: location,
6390+
beginning: beginning,
64666391
comments: comments
64676392
}
64686393
end
64696394

64706395
def format(q)
6471-
ConditionalFormatter.new("if", self).format(q)
6396+
ConditionalFormatter.new(beginning, self).format(q)
64726397
end
64736398

64746399
def ===(other)
64756400
other.is_a?(IfNode) && predicate === other.predicate &&
6476-
statements === other.statements && consequent === other.consequent
6401+
statements === other.statements && consequent === other.consequent &&
6402+
beginning === other.beginning
64776403
end
64786404

64796405
# Checks if the node was originally found in the modifier form.
@@ -9929,7 +9855,7 @@ def format(q)
99299855
q.breakable_force
99309856
q.format(statement)
99319857
elsif (statement.is_a?(VCall) && statement.access_control?) ||
9932-
(previous.is_a?(VCall) && previous.access_control?)
9858+
(previous.is_a?(VCall) && previous.access_control?)
99339859
q.breakable_force
99349860
q.breakable_force
99359861
q.format(statement)
@@ -11264,7 +11190,7 @@ class UnlessNode < Node
1126411190
# [Statements] the expressions to be executed
1126511191
attr_reader :statements
1126611192

11267-
# [nil | Elsif | Else] the next clause in the chain
11193+
# [nil | IfNode | Else] the next clause in the chain
1126811194
attr_reader :consequent
1126911195

1127011196
# [Array[ Comment | EmbDoc ]] the comments attached to this node

lib/syntax_tree/parser.rb

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,11 +1566,12 @@ def on_elsif(predicate, statements, consequent)
15661566
ending.location.start_column
15671567
)
15681568

1569-
Elsif.new(
1569+
IfNode.new(
15701570
predicate: predicate,
15711571
statements: statements,
15721572
consequent: consequent,
1573-
location: beginning.location.to(ending.location)
1573+
location: beginning.location.to(ending.location),
1574+
beginning: beginning.value
15741575
)
15751576
end
15761577

@@ -2055,7 +2056,8 @@ def on_if(predicate, statements, consequent)
20552056
predicate: predicate,
20562057
statements: statements,
20572058
consequent: consequent,
2058-
location: beginning.location.to(ending.location)
2059+
location: beginning.location.to(ending.location),
2060+
beginning: beginning.value
20592061
)
20602062
end
20612063

@@ -2073,14 +2075,15 @@ def on_ifop(predicate, truthy, falsy)
20732075
# :call-seq:
20742076
# on_if_mod: (untyped predicate, untyped statement) -> IfNode
20752077
def on_if_mod(predicate, statement)
2076-
consume_keyword(:if)
2078+
beginning = consume_keyword(:if)
20772079

20782080
IfNode.new(
20792081
predicate: predicate,
20802082
statements:
20812083
Statements.new(body: [statement], location: statement.location),
20822084
consequent: nil,
2083-
location: statement.location.to(predicate.location)
2085+
location: statement.location.to(predicate.location),
2086+
beginning: beginning.value
20842087
)
20852088
end
20862089

test/node_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ def test_elsif
452452
SOURCE
453453

454454
at = location(lines: 2..4, chars: 9..30)
455-
assert_node(Elsif, source, at: at, &:consequent)
455+
assert_node(IfNode, source, at: at, &:consequent)
456456
end
457457

458458
def test_embdoc

0 commit comments

Comments
 (0)