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

Commit d76d084

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 c4c78b3 commit d76d084

File tree

3 files changed

+31
-107
lines changed

3 files changed

+31
-107
lines changed

lib/syntax_tree/node.rb

Lines changed: 22 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -4780,95 +4780,6 @@ def ===(other)
47804780
end
47814781
end
47824782

4783-
# Elsif represents another clause in an +if+ or +unless+ chain.
4784-
#
4785-
# if variable
4786-
# elsif other_variable
4787-
# end
4788-
#
4789-
class Elsif < Node
4790-
# [untyped] the expression to be checked
4791-
attr_reader :predicate
4792-
4793-
# [Statements] the expressions to be executed
4794-
attr_reader :statements
4795-
4796-
# [nil | Elsif | Else] the next clause in the chain
4797-
attr_reader :consequent
4798-
4799-
# [Array[ Comment | EmbDoc ]] the comments attached to this node
4800-
attr_reader :comments
4801-
4802-
def initialize(predicate:, statements:, consequent:, location:)
4803-
@predicate = predicate
4804-
@statements = statements
4805-
@consequent = consequent
4806-
@location = location
4807-
@comments = []
4808-
end
4809-
4810-
def accept(visitor)
4811-
visitor.visit_elsif(self)
4812-
end
4813-
4814-
def child_nodes
4815-
[predicate, statements, consequent]
4816-
end
4817-
4818-
def copy(predicate: nil, statements: nil, consequent: nil, location: nil)
4819-
node =
4820-
Elsif.new(
4821-
predicate: predicate || self.predicate,
4822-
statements: statements || self.statements,
4823-
consequent: consequent || self.consequent,
4824-
location: location || self.location
4825-
)
4826-
4827-
node.comments.concat(comments.map(&:copy))
4828-
node
4829-
end
4830-
4831-
alias deconstruct child_nodes
4832-
4833-
def deconstruct_keys(_keys)
4834-
{
4835-
predicate: predicate,
4836-
statements: statements,
4837-
consequent: consequent,
4838-
location: location,
4839-
comments: comments
4840-
}
4841-
end
4842-
4843-
def format(q)
4844-
q.group do
4845-
q.group do
4846-
q.text("elsif ")
4847-
q.nest("elsif".length - 1) { q.format(predicate) }
4848-
end
4849-
4850-
unless statements.empty?
4851-
q.indent do
4852-
q.breakable_force
4853-
q.format(statements)
4854-
end
4855-
end
4856-
4857-
if consequent
4858-
q.group do
4859-
q.breakable_force
4860-
q.format(consequent)
4861-
end
4862-
end
4863-
end
4864-
end
4865-
4866-
def ===(other)
4867-
other.is_a?(Elsif) && predicate === other.predicate &&
4868-
statements === other.statements && consequent === other.consequent
4869-
end
4870-
end
4871-
48724783
# EmbDoc represents a multi-line comment.
48734784
#
48744785
# =begin
@@ -6264,7 +6175,7 @@ def format(q)
62646175
# If we can transform this node into a ternary, then we're going to
62656176
# print a special version that uses the ternary operator if it fits on
62666177
# one line.
6267-
if Ternaryable.call(q, node)
6178+
if Ternaryable.call(q, node) && keyword != "elsif"
62686179
format_ternary(q)
62696180
return
62706181
end
@@ -6273,7 +6184,7 @@ def format(q)
62736184
# case we can't know for certain that that assignment doesn't impact the
62746185
# statements inside the conditional) then we can't use the modifier form
62756186
# and we must use the block form.
6276-
if ContainsAssignment.call(node.predicate)
6187+
if keyword == "elsif" || ContainsAssignment.call(node.predicate)
62776188
format_break(q, force: true)
62786189
return
62796190
end
@@ -6322,8 +6233,10 @@ def format_break(q, force:)
63226233
q.format(node.consequent)
63236234
end
63246235

6325-
force ? q.breakable_force : q.breakable_space
6326-
q.text("end")
6236+
unless keyword == "elsif"
6237+
force ? q.breakable_force : q.breakable_space
6238+
q.text("end")
6239+
end
63276240
end
63286241

63296242
def format_ternary(q)
@@ -6384,7 +6297,7 @@ def contains_conditional?
63846297
end
63856298
end
63866299

6387-
# If represents the first clause in an +if+ chain.
6300+
# If an +if+ or +elsif+ clause in an +if+ chain.
63886301
#
63896302
# if predicate
63906303
# end
@@ -6396,17 +6309,21 @@ class IfNode < Node
63966309
# [Statements] the expressions to be executed
63976310
attr_reader :statements
63986311

6399-
# [nil | Elsif | Else] the next clause in the chain
6312+
# [nil | IfNode | Else] the next clause in the chain
64006313
attr_reader :consequent
64016314

64026315
# [Array[ Comment | EmbDoc ]] the comments attached to this node
64036316
attr_reader :comments
64046317

6405-
def initialize(predicate:, statements:, consequent:, location:)
6318+
# [ String ] the opening of the conditional statement
6319+
attr_reader :beginning
6320+
6321+
def initialize(predicate:, statements:, consequent:, location:, beginning:)
64066322
@predicate = predicate
64076323
@statements = statements
64086324
@consequent = consequent
64096325
@location = location
6326+
@beginning = beginning
64106327
@comments = []
64116328
end
64126329

@@ -6418,13 +6335,15 @@ def child_nodes
64186335
[predicate, statements, consequent]
64196336
end
64206337

6421-
def copy(predicate: nil, statements: nil, consequent: nil, location: nil)
6338+
def copy(predicate: nil, statements: nil, consequent: nil, location: nil,
6339+
beginning: nil)
64226340
node =
64236341
IfNode.new(
64246342
predicate: predicate || self.predicate,
64256343
statements: statements || self.statements,
64266344
consequent: consequent || self.consequent,
6427-
location: location || self.location
6345+
location: location || self.location,
6346+
beginning: beginning || self.beginning,
64286347
)
64296348

64306349
node.comments.concat(comments.map(&:copy))
@@ -6439,17 +6358,19 @@ def deconstruct_keys(_keys)
64396358
statements: statements,
64406359
consequent: consequent,
64416360
location: location,
6361+
beginning: beginning,
64426362
comments: comments
64436363
}
64446364
end
64456365

64466366
def format(q)
6447-
ConditionalFormatter.new("if", self).format(q)
6367+
ConditionalFormatter.new(beginning, self).format(q)
64486368
end
64496369

64506370
def ===(other)
64516371
other.is_a?(IfNode) && predicate === other.predicate &&
6452-
statements === other.statements && consequent === other.consequent
6372+
statements === other.statements && consequent === other.consequent &&
6373+
beginning === other.beginning
64536374
end
64546375

64556376
# Checks if the node was originally found in the modifier form.
@@ -11208,7 +11129,7 @@ class UnlessNode < Node
1120811129
# [Statements] the expressions to be executed
1120911130
attr_reader :statements
1121011131

11211-
# [nil | Elsif | Else] the next clause in the chain
11132+
# [nil | IfNode | Else] the next clause in the chain
1121211133
attr_reader :consequent
1121311134

1121411135
# [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
@@ -1491,11 +1491,12 @@ def on_elsif(predicate, statements, consequent)
14911491
ending.location.start_column
14921492
)
14931493

1494-
Elsif.new(
1494+
IfNode.new(
14951495
predicate: predicate,
14961496
statements: statements,
14971497
consequent: consequent,
1498-
location: beginning.location.to(ending.location)
1498+
location: beginning.location.to(ending.location),
1499+
beginning: beginning.value
14991500
)
15001501
end
15011502

@@ -1942,7 +1943,8 @@ def on_if(predicate, statements, consequent)
19421943
predicate: predicate,
19431944
statements: statements,
19441945
consequent: consequent,
1945-
location: beginning.location.to(ending.location)
1946+
location: beginning.location.to(ending.location),
1947+
beginning: beginning.value
19461948
)
19471949
end
19481950

@@ -1960,14 +1962,15 @@ def on_ifop(predicate, truthy, falsy)
19601962
# :call-seq:
19611963
# on_if_mod: (untyped predicate, untyped statement) -> IfNode
19621964
def on_if_mod(predicate, statement)
1963-
consume_keyword(:if)
1965+
beginning = consume_keyword(:if)
19641966

19651967
IfNode.new(
19661968
predicate: predicate,
19671969
statements:
19681970
Statements.new(self, body: [statement], location: statement.location),
19691971
consequent: nil,
1970-
location: statement.location.to(predicate.location)
1972+
location: statement.location.to(predicate.location),
1973+
beginning: beginning.value
19711974
)
19721975
end
19731976

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)