Skip to content

Commit 61eefa8

Browse files
authored
Merge pull request #299 from egiurleo/elsif
Combine `Elsif` node with `IfNode`
2 parents 4eb2a7f + 17539d0 commit 61eefa8

File tree

11 files changed

+55
-187
lines changed

11 files changed

+55
-187
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
1717

1818
- Fixed the AST output by adding blocks to `Command` and `CommandCall` nodes in the `FieldVisitor`.
1919
- Fixed the location of lambda local variables (e.g., `->(; a) {}`).
20+
- The `Elsif` node has been folded into `IfNode`. A `keyword` field has been added to `IfNode` specifying if the node represents an `if` or `elsif`.
2021

2122
## [6.0.1] - 2023-02-26
2223

Diff for: lib/syntax_tree/dsl.rb

+2-11
Original file line numberDiff line numberDiff line change
@@ -347,16 +347,6 @@ def Else(keyword, statements)
347347
)
348348
end
349349

350-
# Create a new Elsif node.
351-
def Elsif(predicate, statements, consequent)
352-
Elsif.new(
353-
predicate: predicate,
354-
statements: statements,
355-
consequent: consequent,
356-
location: Location.default
357-
)
358-
end
359-
360350
# Create a new EmbDoc node.
361351
def EmbDoc(value)
362352
EmbDoc.new(value: value, location: Location.default)
@@ -478,8 +468,9 @@ def Ident(value)
478468
end
479469

480470
# Create a new IfNode node.
481-
def IfNode(predicate, statements, consequent)
471+
def IfNode(keyword, predicate, statements, consequent)
482472
IfNode.new(
473+
keyword: keyword,
483474
predicate: predicate,
484475
statements: statements,
485476
consequent: consequent,

Diff for: lib/syntax_tree/field_visitor.rb

-9
Original file line numberDiff line numberDiff line change
@@ -353,15 +353,6 @@ def visit_else(node)
353353
end
354354
end
355355

356-
def visit_elsif(node)
357-
node(node, "elsif") do
358-
field("predicate", node.predicate)
359-
field("statements", node.statements)
360-
field("consequent", node.consequent) if node.consequent
361-
comments(node)
362-
end
363-
end
364-
365356
def visit_embdoc(node)
366357
node(node, "embdoc") { field("value", node.value) }
367358
end

Diff for: lib/syntax_tree/mutation_visitor.rb

-8
Original file line numberDiff line numberDiff line change
@@ -322,14 +322,6 @@ def visit_else(node)
322322
)
323323
end
324324

325-
# Visit a Elsif node.
326-
def visit_elsif(node)
327-
node.copy(
328-
statements: visit(node.statements),
329-
consequent: visit(node.consequent)
330-
)
331-
end
332-
333325
# Visit a EmbDoc node.
334326
def visit_embdoc(node)
335327
node.copy

Diff for: lib/syntax_tree/node.rb

+43-96
Original file line numberDiff line numberDiff line change
@@ -4853,95 +4853,6 @@ def ===(other)
48534853
end
48544854
end
48554855

4856-
# Elsif represents another clause in an +if+ or +unless+ chain.
4857-
#
4858-
# if variable
4859-
# elsif other_variable
4860-
# end
4861-
#
4862-
class Elsif < Node
4863-
# [Node] the expression to be checked
4864-
attr_reader :predicate
4865-
4866-
# [Statements] the expressions to be executed
4867-
attr_reader :statements
4868-
4869-
# [nil | Elsif | Else] the next clause in the chain
4870-
attr_reader :consequent
4871-
4872-
# [Array[ Comment | EmbDoc ]] the comments attached to this node
4873-
attr_reader :comments
4874-
4875-
def initialize(predicate:, statements:, consequent:, location:)
4876-
@predicate = predicate
4877-
@statements = statements
4878-
@consequent = consequent
4879-
@location = location
4880-
@comments = []
4881-
end
4882-
4883-
def accept(visitor)
4884-
visitor.visit_elsif(self)
4885-
end
4886-
4887-
def child_nodes
4888-
[predicate, statements, consequent]
4889-
end
4890-
4891-
def copy(predicate: nil, statements: nil, consequent: nil, location: nil)
4892-
node =
4893-
Elsif.new(
4894-
predicate: predicate || self.predicate,
4895-
statements: statements || self.statements,
4896-
consequent: consequent || self.consequent,
4897-
location: location || self.location
4898-
)
4899-
4900-
node.comments.concat(comments.map(&:copy))
4901-
node
4902-
end
4903-
4904-
alias deconstruct child_nodes
4905-
4906-
def deconstruct_keys(_keys)
4907-
{
4908-
predicate: predicate,
4909-
statements: statements,
4910-
consequent: consequent,
4911-
location: location,
4912-
comments: comments
4913-
}
4914-
end
4915-
4916-
def format(q)
4917-
q.group do
4918-
q.group do
4919-
q.text("elsif ")
4920-
q.nest("elsif".length - 1) { q.format(predicate) }
4921-
end
4922-
4923-
unless statements.empty?
4924-
q.indent do
4925-
q.breakable_force
4926-
q.format(statements)
4927-
end
4928-
end
4929-
4930-
if consequent
4931-
q.group do
4932-
q.breakable_force
4933-
q.format(consequent)
4934-
end
4935-
end
4936-
end
4937-
end
4938-
4939-
def ===(other)
4940-
other.is_a?(Elsif) && predicate === other.predicate &&
4941-
statements === other.statements && consequent === other.consequent
4942-
end
4943-
end
4944-
49454856
# EmbDoc represents a multi-line comment.
49464857
#
49474858
# =begin
@@ -6460,25 +6371,29 @@ def contains_conditional?
64606371
end
64616372
end
64626373

6463-
# If represents the first clause in an +if+ chain.
6374+
# If an +if+ or +elsif+ clause in an +if+ chain.
64646375
#
64656376
# if predicate
64666377
# end
64676378
#
64686379
class IfNode < Node
6380+
# [Kw] the opening keyword of the conditional statement
6381+
attr_reader :keyword
6382+
64696383
# [Node] the expression to be checked
64706384
attr_reader :predicate
64716385

64726386
# [Statements] the expressions to be executed
64736387
attr_reader :statements
64746388

6475-
# [nil | Elsif | Else] the next clause in the chain
6389+
# [nil | IfNode | Else] the next clause in the chain
64766390
attr_reader :consequent
64776391

64786392
# [Array[ Comment | EmbDoc ]] the comments attached to this node
64796393
attr_reader :comments
64806394

6481-
def initialize(predicate:, statements:, consequent:, location:)
6395+
def initialize(keyword:, predicate:, statements:, consequent:, location:)
6396+
@keyword = keyword
64826397
@predicate = predicate
64836398
@statements = statements
64846399
@consequent = consequent
@@ -6494,9 +6409,16 @@ def child_nodes
64946409
[predicate, statements, consequent]
64956410
end
64966411

6497-
def copy(predicate: nil, statements: nil, consequent: nil, location: nil)
6412+
def copy(
6413+
keyword: nil,
6414+
predicate: nil,
6415+
statements: nil,
6416+
consequent: nil,
6417+
location: nil
6418+
)
64986419
node =
64996420
IfNode.new(
6421+
keyword: keyword || self.keyword,
65006422
predicate: predicate || self.predicate,
65016423
statements: statements || self.statements,
65026424
consequent: consequent || self.consequent,
@@ -6515,17 +6437,42 @@ def deconstruct_keys(_keys)
65156437
statements: statements,
65166438
consequent: consequent,
65176439
location: location,
6440+
keyword: keyword,
65186441
comments: comments
65196442
}
65206443
end
65216444

65226445
def format(q)
6523-
ConditionalFormatter.new("if", self).format(q)
6446+
if keyword.value == "elsif"
6447+
q.group do
6448+
q.group do
6449+
q.text("elsif ")
6450+
q.nest("elsif".length - 1) { q.format(predicate) }
6451+
end
6452+
6453+
unless statements.empty?
6454+
q.indent do
6455+
q.breakable_force
6456+
q.format(statements)
6457+
end
6458+
end
6459+
6460+
if consequent
6461+
q.group do
6462+
q.breakable_force
6463+
q.format(consequent)
6464+
end
6465+
end
6466+
end
6467+
else
6468+
ConditionalFormatter.new(keyword.value, self).format(q)
6469+
end
65246470
end
65256471

65266472
def ===(other)
65276473
other.is_a?(IfNode) && predicate === other.predicate &&
6528-
statements === other.statements && consequent === other.consequent
6474+
statements === other.statements && consequent === other.consequent &&
6475+
keyword === other.keyword
65296476
end
65306477

65316478
# Checks if the node was originally found in the modifier form.
@@ -11328,7 +11275,7 @@ class UnlessNode < Node
1132811275
# [Statements] the expressions to be executed
1132911276
attr_reader :statements
1133011277

11331-
# [nil | Elsif | Else] the next clause in the chain
11278+
# [nil | IfNode | Else] the next clause in the chain
1133211279
attr_reader :consequent
1133311280

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

Diff for: lib/syntax_tree/parser.rb

+5-2
Original file line numberDiff line numberDiff line change
@@ -1575,7 +1575,8 @@ def on_elsif(predicate, statements, consequent)
15751575
ending.location.start_column
15761576
)
15771577

1578-
Elsif.new(
1578+
IfNode.new(
1579+
keyword: beginning,
15791580
predicate: predicate,
15801581
statements: statements,
15811582
consequent: consequent,
@@ -2062,6 +2063,7 @@ def on_if(predicate, statements, consequent)
20622063
)
20632064

20642065
IfNode.new(
2066+
keyword: beginning,
20652067
predicate: predicate,
20662068
statements: statements,
20672069
consequent: consequent,
@@ -2083,9 +2085,10 @@ def on_ifop(predicate, truthy, falsy)
20832085
# :call-seq:
20842086
# on_if_mod: (untyped predicate, untyped statement) -> IfNode
20852087
def on_if_mod(predicate, statement)
2086-
consume_keyword(:if)
2088+
beginning = consume_keyword(:if)
20872089

20882090
IfNode.new(
2091+
keyword: beginning,
20892092
predicate: predicate,
20902093
statements:
20912094
Statements.new(body: [statement], location: statement.location),

Diff for: lib/syntax_tree/translation/parser.rb

+1-45
Original file line numberDiff line numberDiff line change
@@ -1037,50 +1037,6 @@ def visit_else(node)
10371037
end
10381038
end
10391039

1040-
# Visit an Elsif node.
1041-
def visit_elsif(node)
1042-
begin_start = node.predicate.end_char
1043-
begin_end =
1044-
if node.statements.empty?
1045-
node.statements.end_char
1046-
else
1047-
node.statements.body.first.start_char
1048-
end
1049-
1050-
begin_token =
1051-
if buffer.source[begin_start...begin_end].include?("then")
1052-
srange_find(begin_start, begin_end, "then")
1053-
elsif buffer.source[begin_start...begin_end].include?(";")
1054-
srange_find(begin_start, begin_end, ";")
1055-
end
1056-
1057-
else_token =
1058-
case node.consequent
1059-
when Elsif
1060-
srange_length(node.consequent.start_char, 5)
1061-
when Else
1062-
srange_length(node.consequent.start_char, 4)
1063-
end
1064-
1065-
expression = srange(node.start_char, node.statements.end_char - 1)
1066-
1067-
s(
1068-
:if,
1069-
[
1070-
visit(node.predicate),
1071-
visit(node.statements),
1072-
visit(node.consequent)
1073-
],
1074-
smap_condition(
1075-
srange_length(node.start_char, 5),
1076-
begin_token,
1077-
else_token,
1078-
nil,
1079-
expression
1080-
)
1081-
)
1082-
end
1083-
10841040
# Visit an ENDBlock node.
10851041
def visit_END(node)
10861042
s(
@@ -1361,7 +1317,7 @@ def visit_if(node)
13611317

13621318
else_token =
13631319
case node.consequent
1364-
when Elsif
1320+
when IfNode
13651321
srange_length(node.consequent.start_char, 5)
13661322
when Else
13671323
srange_length(node.consequent.start_char, 4)

Diff for: lib/syntax_tree/visitor.rb

-3
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,6 @@ class Visitor < BasicVisitor
131131
# Visit an Else node.
132132
alias visit_else visit_child_nodes
133133

134-
# Visit an Elsif node.
135-
alias visit_elsif visit_child_nodes
136-
137134
# Visit an EmbDoc node.
138135
alias visit_embdoc visit_child_nodes
139136

Diff for: lib/syntax_tree/yarv/compiler.rb

+1-11
Original file line numberDiff line numberDiff line change
@@ -916,17 +916,6 @@ def visit_else(node)
916916
iseq.pop unless last_statement?
917917
end
918918

919-
def visit_elsif(node)
920-
visit_if(
921-
IfNode.new(
922-
predicate: node.predicate,
923-
statements: node.statements,
924-
consequent: node.consequent,
925-
location: node.location
926-
)
927-
)
928-
end
929-
930919
def visit_ensure(node)
931920
end
932921

@@ -1054,6 +1043,7 @@ def visit_if(node)
10541043
def visit_if_op(node)
10551044
visit_if(
10561045
IfNode.new(
1046+
keyword: Kw.new(value: "if", location: Location.default),
10571047
predicate: node.predicate,
10581048
statements:
10591049
Statements.new(body: [node.truthy], location: Location.default),

0 commit comments

Comments
 (0)