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

Commit eb3b27f

Browse files
committed
Combine the LambdaVar and BlockVar nodes
Both `LambdaVar` and `BlockVar` represent a collection of arguments (positional, optional, keyword, block) as well as block or lambda-local variables. This commit removes the `LambdaVar` node and folds its functionality into the `BlockVar` node, which reduces the number of nodes and simplifies logic.
1 parent 4963ad5 commit eb3b27f

File tree

3 files changed

+85
-93
lines changed

3 files changed

+85
-93
lines changed

lib/syntax_tree/node.rb

Lines changed: 47 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2087,13 +2087,18 @@ def ===(other)
20872087
end
20882088
end
20892089

2090-
# BlockVar represents the parameters being declared for a block. Effectively
2091-
# this node is everything contained within the pipes. This includes all of the
2092-
# various parameter types, as well as block-local variable declarations.
2090+
# BlockVar represents the parameters being declared for a block or lambda.
2091+
# This includes all of the various parameter types, as well as
2092+
# block-local/lambda-local variable declarations.
20932093
#
20942094
# method do |positional, optional = value, keyword:, █ local|
20952095
# end
20962096
#
2097+
# OR
2098+
#
2099+
# -> (positional, optional = value, keyword:, █ local) do
2100+
# end
2101+
#
20972102
class BlockVar < Node
20982103
# [Params] the parameters being declared with the block
20992104
attr_reader :params
@@ -2104,10 +2109,15 @@ class BlockVar < Node
21042109
# [Array[ Comment | EmbDoc ]] the comments attached to this node
21052110
attr_reader :comments
21062111

2107-
def initialize(params:, locals:, location:)
2112+
# [boolean] whether or not the variables are within pipes
2113+
attr_reader :pipe
2114+
alias pipe? pipe
2115+
2116+
def initialize(params:, locals:, location:, pipe:)
21082117
@params = params
21092118
@locals = locals
21102119
@location = location
2120+
@pipe = pipe
21112121
@comments = []
21122122
end
21132123

@@ -2119,12 +2129,13 @@ def child_nodes
21192129
[params, *locals]
21202130
end
21212131

2122-
def copy(params: nil, locals: nil, location: nil)
2132+
def copy(params: nil, locals: nil, location: nil, pipe: nil)
21232133
node =
21242134
BlockVar.new(
21252135
params: params || self.params,
21262136
locals: locals || self.locals,
2127-
location: location || self.location
2137+
location: location || self.location,
2138+
pipe: pipe || self.pipe
21282139
)
21292140

21302141
node.comments.concat(comments.map(&:copy))
@@ -2134,7 +2145,13 @@ def copy(params: nil, locals: nil, location: nil)
21342145
alias deconstruct child_nodes
21352146

21362147
def deconstruct_keys(_keys)
2137-
{ params: params, locals: locals, location: location, comments: comments }
2148+
{
2149+
params: params,
2150+
locals: locals,
2151+
location: location,
2152+
comments: comments,
2153+
pipe: pipe
2154+
}
21382155
end
21392156

21402157
# Within the pipes of the block declaration, we don't want any spaces. So
@@ -2150,30 +2167,44 @@ def call(q)
21502167
SEPARATOR = Separator.new.freeze
21512168

21522169
def format(q)
2153-
q.text("|")
2154-
q.group do
2155-
q.remove_breaks(q.format(params))
2156-
2157-
if locals.any?
2158-
q.text("; ")
2159-
q.seplist(locals, SEPARATOR) { |local| q.format(local) }
2170+
if pipe?
2171+
q.text("|")
2172+
q.group do
2173+
q.remove_breaks(q.format(params))
2174+
format_locals(q)
21602175
end
2176+
q.text("|")
2177+
else
2178+
q.format(params)
2179+
format_locals(q)
21612180
end
2162-
q.text("|")
21632181
end
21642182

21652183
def ===(other)
21662184
other.is_a?(BlockVar) && params === other.params &&
21672185
ArrayMatch.call(locals, other.locals)
21682186
end
21692187

2188+
def empty?
2189+
params.empty? && locals.empty?
2190+
end
2191+
21702192
# When a single required parameter is declared for a block, it gets
21712193
# automatically expanded if the values being yielded into it are an array.
21722194
def arg0?
21732195
params.requireds.length == 1 && params.optionals.empty? &&
21742196
params.rest.nil? && params.posts.empty? && params.keywords.empty? &&
21752197
params.keyword_rest.nil? && params.block.nil?
21762198
end
2199+
2200+
private
2201+
2202+
def format_locals(q)
2203+
if locals.any?
2204+
q.text("; ")
2205+
q.seplist(locals, SEPARATOR) { |local| q.format(local) }
2206+
end
2207+
end
21772208
end
21782209

21792210
# BlockArg represents declaring a block parameter on a method definition.
@@ -7076,7 +7107,7 @@ def ===(other)
70767107
# ->(value) { value * 2 }
70777108
#
70787109
class Lambda < Node
7079-
# [LambdaVar | Paren] the parameter declaration for this lambda
7110+
# [BlockVar | Paren] the parameter declaration for this lambda
70807111
attr_reader :params
70817112

70827113
# [BodyStmt | Statements] the expressions to be executed in this lambda
@@ -7192,76 +7223,6 @@ def ===(other)
71927223
end
71937224
end
71947225

7195-
# LambdaVar represents the parameters being declared for a lambda. Effectively
7196-
# this node is everything contained within the parentheses. This includes all
7197-
# of the various parameter types, as well as block-local variable
7198-
# declarations.
7199-
#
7200-
# -> (positional, optional = value, keyword:, &block; local) do
7201-
# end
7202-
#
7203-
class LambdaVar < Node
7204-
# [Params] the parameters being declared with the block
7205-
attr_reader :params
7206-
7207-
# [Array[ Ident ]] the list of block-local variable declarations
7208-
attr_reader :locals
7209-
7210-
# [Array[ Comment | EmbDoc ]] the comments attached to this node
7211-
attr_reader :comments
7212-
7213-
def initialize(params:, locals:, location:)
7214-
@params = params
7215-
@locals = locals
7216-
@location = location
7217-
@comments = []
7218-
end
7219-
7220-
def accept(visitor)
7221-
visitor.visit_lambda_var(self)
7222-
end
7223-
7224-
def child_nodes
7225-
[params, *locals]
7226-
end
7227-
7228-
def copy(params: nil, locals: nil, location: nil)
7229-
node =
7230-
LambdaVar.new(
7231-
params: params || self.params,
7232-
locals: locals || self.locals,
7233-
location: location || self.location
7234-
)
7235-
7236-
node.comments.concat(comments.map(&:copy))
7237-
node
7238-
end
7239-
7240-
alias deconstruct child_nodes
7241-
7242-
def deconstruct_keys(_keys)
7243-
{ params: params, locals: locals, location: location, comments: comments }
7244-
end
7245-
7246-
def empty?
7247-
params.empty? && locals.empty?
7248-
end
7249-
7250-
def format(q)
7251-
q.format(params)
7252-
7253-
if locals.any?
7254-
q.text("; ")
7255-
q.seplist(locals, BlockVar::SEPARATOR) { |local| q.format(local) }
7256-
end
7257-
end
7258-
7259-
def ===(other)
7260-
other.is_a?(LambdaVar) && params === other.params &&
7261-
ArrayMatch.call(locals, other.locals)
7262-
end
7263-
end
7264-
72657226
# LBrace represents the use of a left brace, i.e., {.
72667227
class LBrace < Node
72677228
# [String] the left brace

lib/syntax_tree/parser.rb

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,8 @@ def on_block_var(params, locals)
885885
BlockVar.new(
886886
params: params,
887887
locals: locals || [],
888-
location: beginning.location.to(ending.location)
888+
location: beginning.location.to(ending.location),
889+
pipe: true
889890
)
890891
end
891892

@@ -2211,10 +2212,11 @@ def on_lambda(params, statements)
22112212
Paren.new(
22122213
lparen: params.lparen,
22132214
contents:
2214-
LambdaVar.new(
2215+
BlockVar.new(
22152216
params: params.contents,
22162217
locals: locals,
2217-
location: location
2218+
location: location,
2219+
pipe: false
22182220
),
22192221
location: params.location
22202222
)
@@ -2225,8 +2227,13 @@ def on_lambda(params, statements)
22252227
# In this case we've gotten to the <3.2 plain set of parameters. In
22262228
# this case there cannot be lambda locals, so we will wrap the
22272229
# parameters into a lambda var that has no locals.
2228-
LambdaVar.new(params: params, locals: [], location: params.location)
2229-
when LambdaVar
2230+
BlockVar.new(
2231+
params: params,
2232+
locals: [],
2233+
location: params.location,
2234+
pipe: false
2235+
)
2236+
when BlockVar
22302237
# In this case we've gotten to 3.2+ lambda var. In this case we don't
22312238
# need to do anything and can just the value as given.
22322239
params
@@ -2256,12 +2263,17 @@ def on_lambda(params, statements)
22562263
end
22572264

22582265
# :call-seq:
2259-
# on_lambda_var: (Params params, Array[ Ident ] locals) -> LambdaVar
2266+
# on_lambda_var: (Params params, Array[ Ident ] locals) -> BlockVar
22602267
def on_lambda_var(params, locals)
22612268
location = params.location
22622269
location = location.to(locals.last.location) if locals.any?
22632270

2264-
LambdaVar.new(params: params, locals: locals || [], location: location)
2271+
BlockVar.new(
2272+
params: params,
2273+
locals: locals || [],
2274+
location: location,
2275+
pipe: false
2276+
)
22652277
end
22662278

22672279
# Ripper doesn't support capturing lambda local variables until 3.2. To

test/node_test.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,25 @@ def test_lambda
635635
source = "->(value) { value * 2 }"
636636

637637
assert_node(Lambda, source)
638+
639+
at = location(chars: 3..8)
640+
assert_node(BlockVar, source, at: at) { |node| node.params.contents }
641+
end
642+
643+
def test_lambda_no_parens
644+
source = "-> value { value * 2 }"
645+
646+
assert_node(Lambda, source)
647+
648+
at = location(chars: 3..8)
649+
assert_node(BlockVar, source, at: at, &:params)
650+
end
651+
652+
def test_lambda_braces
653+
source = "lambda { |value| value * 2 }"
654+
655+
at = location(chars: 9..16)
656+
assert_node(BlockVar, source, at: at) { |node| node.block.block_var }
638657
end
639658

640659
def test_lambda_do

0 commit comments

Comments
 (0)