@@ -1695,10 +1695,13 @@ def format(q)
1695
1695
parts += posts
1696
1696
1697
1697
if constant
1698
- q . format ( constant )
1699
- q . text ( "[" )
1700
- q . seplist ( parts ) { |part | q . format ( part ) }
1701
- q . text ( "]" )
1698
+ q . group do
1699
+ q . format ( constant )
1700
+ q . text ( "[" )
1701
+ q . seplist ( parts ) { |part | q . format ( part ) }
1702
+ q . text ( "]" )
1703
+ end
1704
+
1702
1705
return
1703
1706
end
1704
1707
@@ -1708,7 +1711,7 @@ def format(q)
1708
1711
q . seplist ( parts ) { |part | q . format ( part ) }
1709
1712
q . text ( "]" )
1710
1713
else
1711
- q . seplist ( parts ) { |part | q . format ( part ) }
1714
+ q . group { q . seplist ( parts ) { |part | q . format ( part ) } }
1712
1715
end
1713
1716
end
1714
1717
@@ -2340,24 +2343,93 @@ def to_json(*opts)
2340
2343
end
2341
2344
end
2342
2345
2346
+ # PinnedBegin represents a pinning a nested statement within pattern matching.
2347
+ #
2348
+ # case value
2349
+ # in ^(statement)
2350
+ # end
2351
+ #
2352
+ class PinnedBegin
2353
+ # [untyped] the expression being pinned
2354
+ attr_reader :statement
2355
+
2356
+ # [Location] the location of this node
2357
+ attr_reader :location
2358
+
2359
+ # [Array[ Comment | EmbDoc ]] the comments attached to this node
2360
+ attr_reader :comments
2361
+
2362
+ def initialize ( statement :, location :, comments : [ ] )
2363
+ @statement = statement
2364
+ @location = location
2365
+ @comments = comments
2366
+ end
2367
+
2368
+ def child_nodes
2369
+ [ statement ]
2370
+ end
2371
+
2372
+ def format ( q )
2373
+ q . group do
2374
+ q . text ( "^(" )
2375
+ q . nest ( 1 ) do
2376
+ q . indent do
2377
+ q . breakable ( "" )
2378
+ q . format ( statement )
2379
+ end
2380
+ q . breakable ( "" )
2381
+ q . text ( ")" )
2382
+ end
2383
+ end
2384
+ end
2385
+
2386
+ def pretty_print ( q )
2387
+ q . group ( 2 , "(" , ")" ) do
2388
+ q . text ( "pinned_begin" )
2389
+
2390
+ q . breakable
2391
+ q . pp ( statement )
2392
+
2393
+ q . pp ( Comment ::List . new ( comments ) )
2394
+ end
2395
+ end
2396
+
2397
+ def to_json ( *opts )
2398
+ {
2399
+ type : :pinned_begin ,
2400
+ stmt : statement ,
2401
+ loc : location ,
2402
+ cmts : comments
2403
+ } . to_json ( *opts )
2404
+ end
2405
+ end
2406
+
2343
2407
# :call-seq:
2344
- # on_begin: (BodyStmt bodystmt) -> Begin
2408
+ # on_begin: (untyped bodystmt) -> Begin | PinnedBegin
2345
2409
def on_begin ( bodystmt )
2346
- keyword = find_token ( Kw , "begin" )
2347
- end_char =
2348
- if bodystmt . rescue_clause || bodystmt . ensure_clause ||
2349
- bodystmt . else_clause
2350
- bodystmt . location . end_char
2351
- else
2352
- find_token ( Kw , "end" ) . location . end_char
2353
- end
2410
+ if beginning = find_token ( Op , "^" , consume : false )
2411
+ tokens . delete ( beginning )
2412
+ find_token ( LParen )
2354
2413
2355
- bodystmt . bind ( keyword . location . end_char , end_char )
2414
+ ending = find_token ( RParen )
2415
+ location = beginning . location . to ( ending . location )
2356
2416
2357
- Begin . new (
2358
- bodystmt : bodystmt ,
2359
- location : keyword . location . to ( bodystmt . location )
2360
- )
2417
+ PinnedBegin . new ( statement : bodystmt , location : location )
2418
+ else
2419
+ keyword = find_token ( Kw , "begin" )
2420
+ end_char =
2421
+ if bodystmt . rescue_clause || bodystmt . ensure_clause ||
2422
+ bodystmt . else_clause
2423
+ bodystmt . location . end_char
2424
+ else
2425
+ find_token ( Kw , "end" ) . location . end_char
2426
+ end
2427
+
2428
+ bodystmt . bind ( keyword . location . end_char , end_char )
2429
+ location = keyword . location . to ( bodystmt . location )
2430
+
2431
+ Begin . new ( bodystmt : bodystmt , location : location )
2432
+ end
2361
2433
end
2362
2434
2363
2435
# Binary represents any expression that involves two sub-expressions with an
@@ -12952,10 +13024,68 @@ def to_json(*opts)
12952
13024
end
12953
13025
end
12954
13026
13027
+ # PinnedVarRef represents a pinned variable reference within a pattern
13028
+ # matching pattern.
13029
+ #
13030
+ # case value
13031
+ # in ^variable
13032
+ # end
13033
+ #
13034
+ # This can be a plain local variable like the example above. It can also be a
13035
+ # a class variable, a global variable, or an instance variable.
13036
+ class PinnedVarRef
13037
+ # [VarRef] the value of this node
13038
+ attr_reader :value
13039
+
13040
+ # [Location] the location of this node
13041
+ attr_reader :location
13042
+
13043
+ # [Array[ Comment | EmbDoc ]] the comments attached to this node
13044
+ attr_reader :comments
13045
+
13046
+ def initialize ( value :, location :, comments : [ ] )
13047
+ @value = value
13048
+ @location = location
13049
+ @comments = comments
13050
+ end
13051
+
13052
+ def child_nodes
13053
+ [ value ]
13054
+ end
13055
+
13056
+ def format ( q )
13057
+ q . group do
13058
+ q . text ( "^" )
13059
+ q . format ( value )
13060
+ end
13061
+ end
13062
+
13063
+ def pretty_print ( q )
13064
+ q . group ( 2 , "(" , ")" ) do
13065
+ q . text ( "pinned_var_ref" )
13066
+
13067
+ q . breakable
13068
+ q . pp ( value )
13069
+
13070
+ q . pp ( Comment ::List . new ( comments ) )
13071
+ end
13072
+ end
13073
+
13074
+ def to_json ( *opts )
13075
+ { type : :pinned_var_ref , value : value , loc : location , cmts : comments }
13076
+ . to_json ( *opts )
13077
+ end
13078
+ end
13079
+
12955
13080
# :call-seq:
12956
13081
# on_var_ref: ((Const | CVar | GVar | Ident | IVar | Kw) value) -> VarRef
12957
13082
def on_var_ref ( value )
12958
- VarRef . new ( value : value , location : value . location )
13083
+ if pin = find_token ( Op , "^" , consume : false )
13084
+ tokens . delete ( pin )
13085
+ PinnedVarRef . new ( value : value , location : pin . location . to ( value . location ) )
13086
+ else
13087
+ VarRef . new ( value : value , location : value . location )
13088
+ end
12959
13089
end
12960
13090
12961
13091
# VCall represent any plain named object with Ruby that could be either a
0 commit comments