@@ -1173,7 +1173,7 @@ def on_args_add(arguments, argument)
11731173 # method(&expression)
11741174 #
11751175 class ArgBlock
1176- # [untyped] the expression being turned into a block
1176+ # [nil | untyped] the expression being turned into a block
11771177 attr_reader :value
11781178
11791179 # [Location] the location of this node
@@ -1194,15 +1194,17 @@ def child_nodes
11941194
11951195 def format ( q )
11961196 q . text ( "&" )
1197- q . format ( value )
1197+ q . format ( value ) if value
11981198 end
11991199
12001200 def pretty_print ( q )
12011201 q . group ( 2 , "(" , ")" ) do
12021202 q . text ( "arg_block" )
12031203
1204- q . breakable
1205- q . pp ( value )
1204+ if value
1205+ q . breakable
1206+ q . pp ( value )
1207+ end
12061208
12071209 q . pp ( Comment ::List . new ( comments ) )
12081210 end
@@ -1221,17 +1223,34 @@ def to_json(*opts)
12211223 # (false | untyped) block
12221224 # ) -> Args
12231225 def on_args_add_block ( arguments , block )
1224- return arguments unless block
1226+ operator = find_token ( Op , "&" , consume : false )
12251227
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 )
12311250
12321251 Args . new (
12331252 parts : arguments . parts << arg_block ,
1234- location : arguments . location . to ( arg_block . location )
1253+ location : arguments . location . to ( location )
12351254 )
12361255 end
12371256
@@ -1896,7 +1915,7 @@ def child_nodes
18961915 end
18971916
18981917 def format ( q )
1899- if value . is_a? ( HashLiteral )
1918+ if value & .is_a? ( HashLiteral )
19001919 format_contents ( q )
19011920 else
19021921 q . group { format_contents ( q ) }
@@ -1910,8 +1929,10 @@ def pretty_print(q)
19101929 q . breakable
19111930 q . pp ( key )
19121931
1913- q . breakable
1914- q . pp ( value )
1932+ if value
1933+ q . breakable
1934+ q . pp ( value )
1935+ end
19151936
19161937 q . pp ( Comment ::List . new ( comments ) )
19171938 end
@@ -1931,6 +1952,7 @@ def to_json(*opts)
19311952
19321953 def format_contents ( q )
19331954 q . parent . format_key ( q , key )
1955+ return unless value
19341956
19351957 if key . comments . empty? && AssignFormatting . skip_indent? ( value )
19361958 q . text ( " " )
@@ -1947,7 +1969,10 @@ def format_contents(q)
19471969 # :call-seq:
19481970 # on_assoc_new: (untyped key, untyped value) -> Assoc
19491971 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 )
19511976 end
19521977
19531978 # AssocSplat represents double-splatting a value into a hash (either a hash
@@ -2423,12 +2448,22 @@ def to_json(*opts)
24232448 # :call-seq:
24242449 # on_binary: (untyped left, (Op | Symbol) operator, untyped right) -> Binary
24252450 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
24322467
24332468 Binary . new (
24342469 left : left ,
@@ -2578,7 +2613,7 @@ def on_block_var(params, locals)
25782613 # def method(&block); end
25792614 #
25802615 class BlockArg
2581- # [Ident] the name of the block argument
2616+ # [nil | Ident] the name of the block argument
25822617 attr_reader :name
25832618
25842619 # [Location] the location of this node
@@ -2599,15 +2634,17 @@ def child_nodes
25992634
26002635 def format ( q )
26012636 q . text ( "&" )
2602- q . format ( name )
2637+ q . format ( name ) if name
26032638 end
26042639
26052640 def pretty_print ( q )
26062641 q . group ( 2 , "(" , ")" ) do
26072642 q . text ( "blockarg" )
26082643
2609- q . breakable
2610- q . pp ( name )
2644+ if name
2645+ q . breakable
2646+ q . pp ( name )
2647+ end
26112648
26122649 q . pp ( Comment ::List . new ( comments ) )
26132650 end
@@ -2625,7 +2662,10 @@ def to_json(*opts)
26252662 def on_blockarg ( name )
26262663 operator = find_token ( Op , "&" )
26272664
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 )
26292669 end
26302670
26312671 # bodystmt can't actually determine its bounds appropriately because it
@@ -4423,7 +4463,7 @@ class DefEndless
44234463 # [Backtick | Const | Ident | Kw | Op] the name of the method
44244464 attr_reader :name
44254465
4426- # [nil | Paren] the parameter declaration for the method
4466+ # [nil | Params | Paren] the parameter declaration for the method
44274467 attr_reader :paren
44284468
44294469 # [untyped] the expression to be executed by the method
@@ -4467,7 +4507,12 @@ def format(q)
44674507 end
44684508
44694509 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
44714516
44724517 q . text ( " =" )
44734518 q . group do
@@ -4533,21 +4578,6 @@ def on_def(name, params, bodystmt)
45334578 # and normal method definitions.
45344579 beginning = find_token ( Kw , "def" )
45354580
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-
45514581 # If there aren't any params then we need to correct the params node
45524582 # location information
45534583 if params . is_a? ( Params ) && params . empty?
@@ -4563,18 +4593,35 @@ def on_def(name, params, bodystmt)
45634593 params = Params . new ( location : location )
45644594 end
45654595
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 )
45714597
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
45784625 end
45794626
45804627 # 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)
47824829 end
47834830
47844831 beginning = find_token ( Kw , "def" )
4832+ ending = find_token ( Kw , "end" , consume : false )
47854833
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+ )
48024840
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
48074853
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
48164863 end
48174864
48184865 # DoBlock represents passing a block to a method call using the +do+ and +end+
@@ -8931,7 +8978,7 @@ def format(q)
89318978 end
89328979
89338980 class KeywordRestFormatter
8934- # [:nil | KwRestParam] the value of the parameter
8981+ # [:nil | ArgsForward | KwRestParam] the value of the parameter
89358982 attr_reader :value
89368983
89378984 def initialize ( value )
@@ -9046,7 +9093,7 @@ def format(q)
90469093 q . format ( rest ) if rest && rest . is_a? ( ExcessedComma )
90479094 end
90489095
9049- if [ Def , Defs ] . include? ( q . parent . class )
9096+ if [ Def , Defs , DefEndless ] . include? ( q . parent . class )
90509097 q . group ( 0 , "(" , ")" ) do
90519098 q . indent do
90529099 q . breakable ( "" )
@@ -9146,8 +9193,8 @@ def to_json(*opts)
91469193 # (nil | ArgsForward | ExcessedComma | RestParam) rest,
91479194 # (nil | Array[Ident]) posts,
91489195 # (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
91519198 # ) -> Params
91529199 def on_params (
91539200 requireds ,
@@ -9165,7 +9212,7 @@ def on_params(
91659212 *posts ,
91669213 *keywords &.flat_map { |( key , value ) | [ key , value || nil ] } ,
91679214 ( keyword_rest if keyword_rest != :nil ) ,
9168- block
9215+ ( block if block != :& )
91699216 ] . compact
91709217
91719218 location =
@@ -9182,7 +9229,7 @@ def on_params(
91829229 posts : posts || [ ] ,
91839230 keywords : keywords || [ ] ,
91849231 keyword_rest : keyword_rest ,
9185- block : block ,
9232+ block : ( block if block != :& ) ,
91869233 location : location
91879234 )
91889235 end
0 commit comments