@@ -1173,7 +1173,7 @@ def on_args_add(arguments, argument)
1173
1173
# method(&expression)
1174
1174
#
1175
1175
class ArgBlock
1176
- # [untyped] the expression being turned into a block
1176
+ # [nil | untyped] the expression being turned into a block
1177
1177
attr_reader :value
1178
1178
1179
1179
# [Location] the location of this node
@@ -1194,15 +1194,17 @@ def child_nodes
1194
1194
1195
1195
def format ( q )
1196
1196
q . text ( "&" )
1197
- q . format ( value )
1197
+ q . format ( value ) if value
1198
1198
end
1199
1199
1200
1200
def pretty_print ( q )
1201
1201
q . group ( 2 , "(" , ")" ) do
1202
1202
q . text ( "arg_block" )
1203
1203
1204
- q . breakable
1205
- q . pp ( value )
1204
+ if value
1205
+ q . breakable
1206
+ q . pp ( value )
1207
+ end
1206
1208
1207
1209
q . pp ( Comment ::List . new ( comments ) )
1208
1210
end
@@ -1221,17 +1223,34 @@ def to_json(*opts)
1221
1223
# (false | untyped) block
1222
1224
# ) -> Args
1223
1225
def on_args_add_block ( arguments , block )
1224
- return arguments unless block
1226
+ operator = find_token ( Op , "&" , consume : false )
1225
1227
1226
- arg_block =
1227
- ArgBlock . new (
1228
- value : block ,
1229
- location : find_token ( Op , "&" ) . location . to ( block . location )
1230
- )
1228
+ # If we can't find the & operator, then there's no block to add to the list,
1229
+ # so we're just going to return the arguments as-is.
1230
+ return arguments unless operator
1231
+
1232
+ # Now we know we have an & operator, so we're going to delete it from the
1233
+ # list of tokens to make sure it doesn't get confused with anything else.
1234
+ tokens . delete ( operator )
1235
+
1236
+ # Construct the location that represents the block argument.
1237
+ location = operator . location
1238
+ location = operator . location . to ( block . location ) if block
1239
+
1240
+ # If there are any arguments and the operator we found from the list is not
1241
+ # after them, then we're going to return the arguments as-is because we're
1242
+ # looking at an & that occurs before the arguments are done.
1243
+ if arguments . parts . any? && location . start_char < arguments . location . end_char
1244
+ return arguments
1245
+ end
1246
+
1247
+ # Otherwise, we're looking at an actual block argument (with or without a
1248
+ # block, which could be missing because it could be a bare & since 3.1.0).
1249
+ arg_block = ArgBlock . new ( value : block , location : location )
1231
1250
1232
1251
Args . new (
1233
1252
parts : arguments . parts << arg_block ,
1234
- location : arguments . location . to ( arg_block . location )
1253
+ location : arguments . location . to ( location )
1235
1254
)
1236
1255
end
1237
1256
@@ -1896,7 +1915,7 @@ def child_nodes
1896
1915
end
1897
1916
1898
1917
def format ( q )
1899
- if value . is_a? ( HashLiteral )
1918
+ if value & .is_a? ( HashLiteral )
1900
1919
format_contents ( q )
1901
1920
else
1902
1921
q . group { format_contents ( q ) }
@@ -1910,8 +1929,10 @@ def pretty_print(q)
1910
1929
q . breakable
1911
1930
q . pp ( key )
1912
1931
1913
- q . breakable
1914
- q . pp ( value )
1932
+ if value
1933
+ q . breakable
1934
+ q . pp ( value )
1935
+ end
1915
1936
1916
1937
q . pp ( Comment ::List . new ( comments ) )
1917
1938
end
@@ -1931,6 +1952,7 @@ def to_json(*opts)
1931
1952
1932
1953
def format_contents ( q )
1933
1954
q . parent . format_key ( q , key )
1955
+ return unless value
1934
1956
1935
1957
if key . comments . empty? && AssignFormatting . skip_indent? ( value )
1936
1958
q . text ( " " )
@@ -1947,7 +1969,10 @@ def format_contents(q)
1947
1969
# :call-seq:
1948
1970
# on_assoc_new: (untyped key, untyped value) -> Assoc
1949
1971
def on_assoc_new ( key , value )
1950
- Assoc . new ( key : key , value : value , location : key . location . to ( value . location ) )
1972
+ location = key . location
1973
+ location = location . to ( value . location ) if value
1974
+
1975
+ Assoc . new ( key : key , value : value , location : location )
1951
1976
end
1952
1977
1953
1978
# AssocSplat represents double-splatting a value into a hash (either a hash
@@ -2423,12 +2448,22 @@ def to_json(*opts)
2423
2448
# :call-seq:
2424
2449
# on_binary: (untyped left, (Op | Symbol) operator, untyped right) -> Binary
2425
2450
def on_binary ( left , operator , right )
2426
- # On most Ruby implementations, operator is a Symbol that represents that
2427
- # operation being performed. For instance in the example `1 < 2`, the
2428
- # `operator` object would be `:<`. However, on JRuby, it's an `@op` node,
2429
- # so here we're going to explicitly convert it into the same normalized
2430
- # form.
2431
- operator = tokens . delete ( operator ) . value unless operator . is_a? ( Symbol )
2451
+ if operator . is_a? ( Symbol )
2452
+ # Here, we're going to search backward for the nearest token that matches
2453
+ # the operator so we can delete it from the list.
2454
+ token = find_token ( Op , operator . to_s , consume : false )
2455
+
2456
+ if token && token . location . start_char > left . location . end_char
2457
+ tokens . delete ( token )
2458
+ end
2459
+ else
2460
+ # On most Ruby implementations, operator is a Symbol that represents that
2461
+ # operation being performed. For instance in the example `1 < 2`, the
2462
+ # `operator` object would be `:<`. However, on JRuby, it's an `@op` node,
2463
+ # so here we're going to explicitly convert it into the same normalized
2464
+ # form.
2465
+ operator = tokens . delete ( operator ) . value
2466
+ end
2432
2467
2433
2468
Binary . new (
2434
2469
left : left ,
@@ -2578,7 +2613,7 @@ def on_block_var(params, locals)
2578
2613
# def method(&block); end
2579
2614
#
2580
2615
class BlockArg
2581
- # [Ident] the name of the block argument
2616
+ # [nil | Ident] the name of the block argument
2582
2617
attr_reader :name
2583
2618
2584
2619
# [Location] the location of this node
@@ -2599,15 +2634,17 @@ def child_nodes
2599
2634
2600
2635
def format ( q )
2601
2636
q . text ( "&" )
2602
- q . format ( name )
2637
+ q . format ( name ) if name
2603
2638
end
2604
2639
2605
2640
def pretty_print ( q )
2606
2641
q . group ( 2 , "(" , ")" ) do
2607
2642
q . text ( "blockarg" )
2608
2643
2609
- q . breakable
2610
- q . pp ( name )
2644
+ if name
2645
+ q . breakable
2646
+ q . pp ( name )
2647
+ end
2611
2648
2612
2649
q . pp ( Comment ::List . new ( comments ) )
2613
2650
end
@@ -2625,7 +2662,10 @@ def to_json(*opts)
2625
2662
def on_blockarg ( name )
2626
2663
operator = find_token ( Op , "&" )
2627
2664
2628
- BlockArg . new ( name : name , location : operator . location . to ( name . location ) )
2665
+ location = operator . location
2666
+ location = location . to ( name . location ) if name
2667
+
2668
+ BlockArg . new ( name : name , location : location )
2629
2669
end
2630
2670
2631
2671
# bodystmt can't actually determine its bounds appropriately because it
@@ -4423,7 +4463,7 @@ class DefEndless
4423
4463
# [Backtick | Const | Ident | Kw | Op] the name of the method
4424
4464
attr_reader :name
4425
4465
4426
- # [nil | Paren] the parameter declaration for the method
4466
+ # [nil | Params | Paren] the parameter declaration for the method
4427
4467
attr_reader :paren
4428
4468
4429
4469
# [untyped] the expression to be executed by the method
@@ -4467,7 +4507,12 @@ def format(q)
4467
4507
end
4468
4508
4469
4509
q . format ( name )
4470
- q . format ( paren ) if paren && !paren . contents . empty?
4510
+
4511
+ if paren
4512
+ params = paren
4513
+ params = params . contents if params . is_a? ( Paren )
4514
+ q . format ( paren ) unless params . empty?
4515
+ end
4471
4516
4472
4517
q . text ( " =" )
4473
4518
q . group do
@@ -4533,21 +4578,6 @@ def on_def(name, params, bodystmt)
4533
4578
# and normal method definitions.
4534
4579
beginning = find_token ( Kw , "def" )
4535
4580
4536
- # If we don't have a bodystmt node, then we have a single-line method
4537
- unless bodystmt . is_a? ( BodyStmt )
4538
- node =
4539
- DefEndless . new (
4540
- target : nil ,
4541
- operator : nil ,
4542
- name : name ,
4543
- paren : params ,
4544
- statement : bodystmt ,
4545
- location : beginning . location . to ( bodystmt . location )
4546
- )
4547
-
4548
- return node
4549
- end
4550
-
4551
4581
# If there aren't any params then we need to correct the params node
4552
4582
# location information
4553
4583
if params . is_a? ( Params ) && params . empty?
@@ -4563,18 +4593,35 @@ def on_def(name, params, bodystmt)
4563
4593
params = Params . new ( location : location )
4564
4594
end
4565
4595
4566
- ending = find_token ( Kw , "end" )
4567
- bodystmt . bind (
4568
- find_next_statement_start ( params . location . end_char ) ,
4569
- ending . location . start_char
4570
- )
4596
+ ending = find_token ( Kw , "end" , consume : false )
4571
4597
4572
- Def . new (
4573
- name : name ,
4574
- params : params ,
4575
- bodystmt : bodystmt ,
4576
- location : beginning . location . to ( ending . location )
4577
- )
4598
+ if ending
4599
+ tokens . delete ( ending )
4600
+ bodystmt . bind (
4601
+ find_next_statement_start ( params . location . end_char ) ,
4602
+ ending . location . start_char
4603
+ )
4604
+
4605
+ Def . new (
4606
+ name : name ,
4607
+ params : params ,
4608
+ bodystmt : bodystmt ,
4609
+ location : beginning . location . to ( ending . location )
4610
+ )
4611
+ else
4612
+ # In Ruby >= 3.1.0, this is a BodyStmt that wraps a single statement in
4613
+ # the statements list. Before, it was just the individual statement.
4614
+ statement = bodystmt . is_a? ( BodyStmt ) ? bodystmt . statements : bodystmt
4615
+
4616
+ DefEndless . new (
4617
+ target : nil ,
4618
+ operator : nil ,
4619
+ name : name ,
4620
+ paren : params ,
4621
+ statement : statement ,
4622
+ location : beginning . location . to ( bodystmt . location )
4623
+ )
4624
+ end
4578
4625
end
4579
4626
4580
4627
# Defined represents the use of the +defined?+ operator. It can be used with
@@ -4782,37 +4829,37 @@ def on_defs(target, operator, name, params, bodystmt)
4782
4829
end
4783
4830
4784
4831
beginning = find_token ( Kw , "def" )
4832
+ ending = find_token ( Kw , "end" , consume : false )
4785
4833
4786
- # If we don't have a bodystmt node, then we have a single-line method
4787
- unless bodystmt . is_a? ( BodyStmt )
4788
- node =
4789
- DefEndless . new (
4790
- target : target ,
4791
- operator : operator ,
4792
- name : name ,
4793
- paren : params ,
4794
- statement : bodystmt ,
4795
- location : beginning . location . to ( bodystmt . location )
4796
- )
4797
-
4798
- return node
4799
- end
4800
-
4801
- ending = find_token ( Kw , "end" )
4834
+ if ending
4835
+ tokens . delete ( ending )
4836
+ bodystmt . bind (
4837
+ find_next_statement_start ( params . location . end_char ) ,
4838
+ ending . location . start_char
4839
+ )
4802
4840
4803
- bodystmt . bind (
4804
- find_next_statement_start ( params . location . end_char ) ,
4805
- ending . location . start_char
4806
- )
4841
+ Defs . new (
4842
+ target : target ,
4843
+ operator : operator ,
4844
+ name : name ,
4845
+ params : params ,
4846
+ bodystmt : bodystmt ,
4847
+ location : beginning . location . to ( ending . location )
4848
+ )
4849
+ else
4850
+ # In Ruby >= 3.1.0, this is a BodyStmt that wraps a single statement in
4851
+ # the statements list. Before, it was just the individual statement.
4852
+ statement = bodystmt . is_a? ( BodyStmt ) ? bodystmt . statements : bodystmt
4807
4853
4808
- Defs . new (
4809
- target : target ,
4810
- operator : operator ,
4811
- name : name ,
4812
- params : params ,
4813
- bodystmt : bodystmt ,
4814
- location : beginning . location . to ( ending . location )
4815
- )
4854
+ DefEndless . new (
4855
+ target : target ,
4856
+ operator : operator ,
4857
+ name : name ,
4858
+ paren : params ,
4859
+ statement : statement ,
4860
+ location : beginning . location . to ( bodystmt . location )
4861
+ )
4862
+ end
4816
4863
end
4817
4864
4818
4865
# DoBlock represents passing a block to a method call using the +do+ and +end+
@@ -8931,7 +8978,7 @@ def format(q)
8931
8978
end
8932
8979
8933
8980
class KeywordRestFormatter
8934
- # [:nil | KwRestParam] the value of the parameter
8981
+ # [:nil | ArgsForward | KwRestParam] the value of the parameter
8935
8982
attr_reader :value
8936
8983
8937
8984
def initialize ( value )
@@ -9046,7 +9093,7 @@ def format(q)
9046
9093
q . format ( rest ) if rest && rest . is_a? ( ExcessedComma )
9047
9094
end
9048
9095
9049
- if [ Def , Defs ] . include? ( q . parent . class )
9096
+ if [ Def , Defs , DefEndless ] . include? ( q . parent . class )
9050
9097
q . group ( 0 , "(" , ")" ) do
9051
9098
q . indent do
9052
9099
q . breakable ( "" )
@@ -9146,8 +9193,8 @@ def to_json(*opts)
9146
9193
# (nil | ArgsForward | ExcessedComma | RestParam) rest,
9147
9194
# (nil | Array[Ident]) posts,
9148
9195
# (nil | Array[[Ident, nil | untyped]]) keywords,
9149
- # (nil | :nil | KwRestParam) keyword_rest,
9150
- # (nil | BlockArg) block
9196
+ # (nil | :nil | ArgsForward | KwRestParam) keyword_rest,
9197
+ # (nil | :& | BlockArg) block
9151
9198
# ) -> Params
9152
9199
def on_params (
9153
9200
requireds ,
@@ -9165,7 +9212,7 @@ def on_params(
9165
9212
*posts ,
9166
9213
*keywords &.flat_map { |( key , value ) | [ key , value || nil ] } ,
9167
9214
( keyword_rest if keyword_rest != :nil ) ,
9168
- block
9215
+ ( block if block != :& )
9169
9216
] . compact
9170
9217
9171
9218
location =
@@ -9182,7 +9229,7 @@ def on_params(
9182
9229
posts : posts || [ ] ,
9183
9230
keywords : keywords || [ ] ,
9184
9231
keyword_rest : keyword_rest ,
9185
- block : block ,
9232
+ block : ( block if block != :& ) ,
9186
9233
location : location
9187
9234
)
9188
9235
end
0 commit comments