diff --git a/doc/AST_FORMAT.md b/doc/AST_FORMAT.md index a32cfb20b..c8c793a22 100644 --- a/doc/AST_FORMAT.md +++ b/doc/AST_FORMAT.md @@ -2112,6 +2112,24 @@ Format: ~~~~ expression ~~~ +### Pin operator with expression + +Format: + +~~~ +(pin + (begin + (send + (int 2) :+ + (int 2)))) +"in ^(2 + 2)" + ~ selector + ~~~~~~~~ expression + ~ begin (begin) + ~ end (begin) + ~~~~~~~ expression (begin) +~~~ + ### Match alternative Format: diff --git a/lib/parser/ruby31.y b/lib/parser/ruby31.y index 8c845fc0a..5a61ba48a 100644 --- a/lib/parser/ruby31.y +++ b/lib/parser/ruby31.y @@ -1946,6 +1946,7 @@ opt_block_args_tail: } p_expr_basic: p_value + | p_variable | p_const p_lparen p_args rparen { @pattern_hash_keys.pop @@ -2191,8 +2192,8 @@ opt_block_args_tail: { result = @builder.range_exclusive(val[0], val[1], nil) } - | p_variable | p_var_ref + | p_expr_ref | p_const | tBDOT2 p_primitive { @@ -2233,6 +2234,12 @@ opt_block_args_tail: result = @builder.pin(val[0], lvar) } + p_expr_ref: tCARET tLPAREN expr_value tRPAREN + { + expr = @builder.begin(val[1], val[2], val[3]) + result = @builder.pin(val[0], expr) + } + p_const: tCOLON3 cname { result = @builder.const_global(val[0], val[1]) diff --git a/test/test_parser.rb b/test/test_parser.rb index 364bc487e..849332abe 100644 --- a/test/test_parser.rb +++ b/test/test_parser.rb @@ -10171,4 +10171,53 @@ def test_parser_drops_truncated_parts_of_squiggly_heredoc %q{}, SINCE_2_3) end + + def test_pin_expr + assert_parses_pattern_match( + s(:in_pattern, + s(:pin, + s(:begin, + s(:int, 42))), nil, + s(:nil)), + %q{in ^(42) then nil}, + %q{ ~ selector (in_pattern.pin) + | ~~~~~ expression (in_pattern.pin) + | ~ begin (in_pattern.pin.begin) + | ~ end (in_pattern.pin.begin) + | ~~~~ expression (in_pattern.pin.begin)}, + SINCE_3_1) + + assert_parses_pattern_match( + s(:in_pattern, + s(:hash_pattern, + s(:pair, + s(:sym, :foo), + s(:pin, + s(:begin, + s(:int, 42))))), nil, + s(:nil)), + %q{in { foo: ^(42) } then nil}, + %q{ ~ selector (in_pattern.hash_pattern.pair.pin) + | ~~~~~ expression (in_pattern.hash_pattern.pair.pin) + | ~ begin (in_pattern.hash_pattern.pair.pin.begin) + | ~ end (in_pattern.hash_pattern.pair.pin.begin) + | ~~~~ expression (in_pattern.hash_pattern.pair.pin.begin)}, + SINCE_3_1) + + assert_parses_pattern_match( + s(:in_pattern, + s(:pin, + s(:begin, + s(:send, + s(:int, 0), :+, + s(:int, 0)))), nil, + s(:nil)), + %q{in ^(0+0) then nil}, + %q{ ~ selector (in_pattern.pin) + | ~~~~~~ expression (in_pattern.pin) + | ~ begin (in_pattern.pin.begin) + | ~ end (in_pattern.pin.begin) + | ~~~~~ expression (in_pattern.pin.begin)}, + SINCE_3_1) + end end