Skip to content

Commit

Permalink
Merge pull request #299 from egiurleo/elsif
Browse files Browse the repository at this point in the history
Combine `Elsif` node with `IfNode`
  • Loading branch information
kddnewton authored Mar 8, 2023
2 parents 4eb2a7f + 17539d0 commit 61eefa8
Show file tree
Hide file tree
Showing 11 changed files with 55 additions and 187 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a

- Fixed the AST output by adding blocks to `Command` and `CommandCall` nodes in the `FieldVisitor`.
- Fixed the location of lambda local variables (e.g., `->(; a) {}`).
- 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`.

## [6.0.1] - 2023-02-26

Expand Down
13 changes: 2 additions & 11 deletions lib/syntax_tree/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -347,16 +347,6 @@ def Else(keyword, statements)
)
end

# Create a new Elsif node.
def Elsif(predicate, statements, consequent)
Elsif.new(
predicate: predicate,
statements: statements,
consequent: consequent,
location: Location.default
)
end

# Create a new EmbDoc node.
def EmbDoc(value)
EmbDoc.new(value: value, location: Location.default)
Expand Down Expand Up @@ -478,8 +468,9 @@ def Ident(value)
end

# Create a new IfNode node.
def IfNode(predicate, statements, consequent)
def IfNode(keyword, predicate, statements, consequent)
IfNode.new(
keyword: keyword,
predicate: predicate,
statements: statements,
consequent: consequent,
Expand Down
9 changes: 0 additions & 9 deletions lib/syntax_tree/field_visitor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -353,15 +353,6 @@ def visit_else(node)
end
end

def visit_elsif(node)
node(node, "elsif") do
field("predicate", node.predicate)
field("statements", node.statements)
field("consequent", node.consequent) if node.consequent
comments(node)
end
end

def visit_embdoc(node)
node(node, "embdoc") { field("value", node.value) }
end
Expand Down
8 changes: 0 additions & 8 deletions lib/syntax_tree/mutation_visitor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -322,14 +322,6 @@ def visit_else(node)
)
end

# Visit a Elsif node.
def visit_elsif(node)
node.copy(
statements: visit(node.statements),
consequent: visit(node.consequent)
)
end

# Visit a EmbDoc node.
def visit_embdoc(node)
node.copy
Expand Down
139 changes: 43 additions & 96 deletions lib/syntax_tree/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4853,95 +4853,6 @@ def ===(other)
end
end

# Elsif represents another clause in an +if+ or +unless+ chain.
#
# if variable
# elsif other_variable
# end
#
class Elsif < Node
# [Node] the expression to be checked
attr_reader :predicate

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

# [nil | Elsif | Else] the next clause in the chain
attr_reader :consequent

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

def initialize(predicate:, statements:, consequent:, location:)
@predicate = predicate
@statements = statements
@consequent = consequent
@location = location
@comments = []
end

def accept(visitor)
visitor.visit_elsif(self)
end

def child_nodes
[predicate, statements, consequent]
end

def copy(predicate: nil, statements: nil, consequent: nil, location: nil)
node =
Elsif.new(
predicate: predicate || self.predicate,
statements: statements || self.statements,
consequent: consequent || self.consequent,
location: location || self.location
)

node.comments.concat(comments.map(&:copy))
node
end

alias deconstruct child_nodes

def deconstruct_keys(_keys)
{
predicate: predicate,
statements: statements,
consequent: consequent,
location: location,
comments: comments
}
end

def format(q)
q.group do
q.group do
q.text("elsif ")
q.nest("elsif".length - 1) { q.format(predicate) }
end

unless statements.empty?
q.indent do
q.breakable_force
q.format(statements)
end
end

if consequent
q.group do
q.breakable_force
q.format(consequent)
end
end
end
end

def ===(other)
other.is_a?(Elsif) && predicate === other.predicate &&
statements === other.statements && consequent === other.consequent
end
end

# EmbDoc represents a multi-line comment.
#
# =begin
Expand Down Expand Up @@ -6460,25 +6371,29 @@ def contains_conditional?
end
end

# If represents the first clause in an +if+ chain.
# If an +if+ or +elsif+ clause in an +if+ chain.
#
# if predicate
# end
#
class IfNode < Node
# [Kw] the opening keyword of the conditional statement
attr_reader :keyword

# [Node] the expression to be checked
attr_reader :predicate

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

# [nil | Elsif | Else] the next clause in the chain
# [nil | IfNode | Else] the next clause in the chain
attr_reader :consequent

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

def initialize(predicate:, statements:, consequent:, location:)
def initialize(keyword:, predicate:, statements:, consequent:, location:)
@keyword = keyword
@predicate = predicate
@statements = statements
@consequent = consequent
Expand All @@ -6494,9 +6409,16 @@ def child_nodes
[predicate, statements, consequent]
end

def copy(predicate: nil, statements: nil, consequent: nil, location: nil)
def copy(
keyword: nil,
predicate: nil,
statements: nil,
consequent: nil,
location: nil
)
node =
IfNode.new(
keyword: keyword || self.keyword,
predicate: predicate || self.predicate,
statements: statements || self.statements,
consequent: consequent || self.consequent,
Expand All @@ -6515,17 +6437,42 @@ def deconstruct_keys(_keys)
statements: statements,
consequent: consequent,
location: location,
keyword: keyword,
comments: comments
}
end

def format(q)
ConditionalFormatter.new("if", self).format(q)
if keyword.value == "elsif"
q.group do
q.group do
q.text("elsif ")
q.nest("elsif".length - 1) { q.format(predicate) }
end

unless statements.empty?
q.indent do
q.breakable_force
q.format(statements)
end
end

if consequent
q.group do
q.breakable_force
q.format(consequent)
end
end
end
else
ConditionalFormatter.new(keyword.value, self).format(q)
end
end

def ===(other)
other.is_a?(IfNode) && predicate === other.predicate &&
statements === other.statements && consequent === other.consequent
statements === other.statements && consequent === other.consequent &&
keyword === other.keyword
end

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

# [nil | Elsif | Else] the next clause in the chain
# [nil | IfNode | Else] the next clause in the chain
attr_reader :consequent

# [Array[ Comment | EmbDoc ]] the comments attached to this node
Expand Down
7 changes: 5 additions & 2 deletions lib/syntax_tree/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1575,7 +1575,8 @@ def on_elsif(predicate, statements, consequent)
ending.location.start_column
)

Elsif.new(
IfNode.new(
keyword: beginning,
predicate: predicate,
statements: statements,
consequent: consequent,
Expand Down Expand Up @@ -2062,6 +2063,7 @@ def on_if(predicate, statements, consequent)
)

IfNode.new(
keyword: beginning,
predicate: predicate,
statements: statements,
consequent: consequent,
Expand All @@ -2083,9 +2085,10 @@ def on_ifop(predicate, truthy, falsy)
# :call-seq:
# on_if_mod: (untyped predicate, untyped statement) -> IfNode
def on_if_mod(predicate, statement)
consume_keyword(:if)
beginning = consume_keyword(:if)

IfNode.new(
keyword: beginning,
predicate: predicate,
statements:
Statements.new(body: [statement], location: statement.location),
Expand Down
46 changes: 1 addition & 45 deletions lib/syntax_tree/translation/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1037,50 +1037,6 @@ def visit_else(node)
end
end

# Visit an Elsif node.
def visit_elsif(node)
begin_start = node.predicate.end_char
begin_end =
if node.statements.empty?
node.statements.end_char
else
node.statements.body.first.start_char
end

begin_token =
if buffer.source[begin_start...begin_end].include?("then")
srange_find(begin_start, begin_end, "then")
elsif buffer.source[begin_start...begin_end].include?(";")
srange_find(begin_start, begin_end, ";")
end

else_token =
case node.consequent
when Elsif
srange_length(node.consequent.start_char, 5)
when Else
srange_length(node.consequent.start_char, 4)
end

expression = srange(node.start_char, node.statements.end_char - 1)

s(
:if,
[
visit(node.predicate),
visit(node.statements),
visit(node.consequent)
],
smap_condition(
srange_length(node.start_char, 5),
begin_token,
else_token,
nil,
expression
)
)
end

# Visit an ENDBlock node.
def visit_END(node)
s(
Expand Down Expand Up @@ -1361,7 +1317,7 @@ def visit_if(node)

else_token =
case node.consequent
when Elsif
when IfNode
srange_length(node.consequent.start_char, 5)
when Else
srange_length(node.consequent.start_char, 4)
Expand Down
3 changes: 0 additions & 3 deletions lib/syntax_tree/visitor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,6 @@ class Visitor < BasicVisitor
# Visit an Else node.
alias visit_else visit_child_nodes

# Visit an Elsif node.
alias visit_elsif visit_child_nodes

# Visit an EmbDoc node.
alias visit_embdoc visit_child_nodes

Expand Down
12 changes: 1 addition & 11 deletions lib/syntax_tree/yarv/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -916,17 +916,6 @@ def visit_else(node)
iseq.pop unless last_statement?
end

def visit_elsif(node)
visit_if(
IfNode.new(
predicate: node.predicate,
statements: node.statements,
consequent: node.consequent,
location: node.location
)
)
end

def visit_ensure(node)
end

Expand Down Expand Up @@ -1054,6 +1043,7 @@ def visit_if(node)
def visit_if_op(node)
visit_if(
IfNode.new(
keyword: Kw.new(value: "if", location: Location.default),
predicate: node.predicate,
statements:
Statements.new(body: [node.truthy], location: Location.default),
Expand Down
Loading

0 comments on commit 61eefa8

Please sign in to comment.