Pattern matching pin operator against expression [Feature #17411]
This commit is based on the patch by @nobu.
This commit is contained in:
parent
232433f224
commit
21863470d9
7
NEWS.md
7
NEWS.md
@ -6,6 +6,12 @@ since the **3.0.0** release, except for bug fixes.
|
|||||||
Note that each entry is kept to a minimum, see links for details.
|
Note that each entry is kept to a minimum, see links for details.
|
||||||
|
|
||||||
## Language changes
|
## Language changes
|
||||||
|
* Pin operator now takes an expression. [[Feature #17411]]
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Prime.each_cons(2).lazy.find_all{_1 in [n, ^(n + 2)]}.take(3).to_a
|
||||||
|
#=> [[3, 5], [5, 7], [11, 13]]
|
||||||
|
```
|
||||||
|
|
||||||
## Command line options
|
## Command line options
|
||||||
|
|
||||||
@ -90,5 +96,6 @@ Excluding feature bug fixes.
|
|||||||
[Feature #16806]: https://bugs.ruby-lang.org/issues/16806
|
[Feature #16806]: https://bugs.ruby-lang.org/issues/16806
|
||||||
[Feature #17312]: https://bugs.ruby-lang.org/issues/17312
|
[Feature #17312]: https://bugs.ruby-lang.org/issues/17312
|
||||||
[Feature #17327]: https://bugs.ruby-lang.org/issues/17327
|
[Feature #17327]: https://bugs.ruby-lang.org/issues/17327
|
||||||
|
[Feature #17411]: https://bugs.ruby-lang.org/issues/17411
|
||||||
[Bug #17423]: https://bugs.ruby-lang.org/issues/17423
|
[Bug #17423]: https://bugs.ruby-lang.org/issues/17423
|
||||||
[Feature #17479]: https://bugs.ruby-lang.org/issues/17479
|
[Feature #17479]: https://bugs.ruby-lang.org/issues/17479
|
||||||
|
@ -6211,6 +6211,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
|
|||||||
case NODE_NIL:
|
case NODE_NIL:
|
||||||
case NODE_COLON2:
|
case NODE_COLON2:
|
||||||
case NODE_COLON3:
|
case NODE_COLON3:
|
||||||
|
case NODE_BEGIN:
|
||||||
CHECK(COMPILE(ret, "case in literal", node));
|
CHECK(COMPILE(ret, "case in literal", node));
|
||||||
ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
|
ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
|
||||||
ADD_INSNL(ret, line, branchif, matched);
|
ADD_INSNL(ret, line, branchif, matched);
|
||||||
|
@ -450,6 +450,7 @@ Approximate syntax is:
|
|||||||
value_pattern: literal
|
value_pattern: literal
|
||||||
| Constant
|
| Constant
|
||||||
| ^variable
|
| ^variable
|
||||||
|
| ^(expression)
|
||||||
|
|
||||||
variable_pattern: variable
|
variable_pattern: variable
|
||||||
|
|
||||||
|
18
parse.y
18
parse.y
@ -1196,7 +1196,7 @@ static int looking_at_eol_p(struct parser_params *p);
|
|||||||
%type <node> p_case_body p_cases p_top_expr p_top_expr_body
|
%type <node> p_case_body p_cases p_top_expr p_top_expr_body
|
||||||
%type <node> p_expr p_as p_alt p_expr_basic p_find
|
%type <node> p_expr p_as p_alt p_expr_basic p_find
|
||||||
%type <node> p_args p_args_head p_args_tail p_args_post p_arg
|
%type <node> p_args p_args_head p_args_tail p_args_post p_arg
|
||||||
%type <node> p_value p_primitive p_variable p_var_ref p_const
|
%type <node> p_value p_primitive p_variable p_var_ref p_expr_ref p_const
|
||||||
%type <node> p_kwargs p_kwarg p_kw
|
%type <node> p_kwargs p_kwarg p_kw
|
||||||
%type <id> keyword_variable user_variable sym operation operation2 operation3
|
%type <id> keyword_variable user_variable sym operation operation2 operation3
|
||||||
%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg
|
%type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg
|
||||||
@ -3994,7 +3994,7 @@ p_top_expr : p_top_expr_body
|
|||||||
| p_top_expr_body modifier_if expr_value
|
| p_top_expr_body modifier_if expr_value
|
||||||
{
|
{
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = new_if(p, $3, remove_begin($1), 0, &@$);
|
$$ = new_if(p, $3, $1, 0, &@$);
|
||||||
fixpos($$, $3);
|
fixpos($$, $3);
|
||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: if_mod!($3, $1) %*/
|
/*% ripper: if_mod!($3, $1) %*/
|
||||||
@ -4002,7 +4002,7 @@ p_top_expr : p_top_expr_body
|
|||||||
| p_top_expr_body modifier_unless expr_value
|
| p_top_expr_body modifier_unless expr_value
|
||||||
{
|
{
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = new_unless(p, $3, remove_begin($1), 0, &@$);
|
$$ = new_unless(p, $3, $1, 0, &@$);
|
||||||
fixpos($$, $3);
|
fixpos($$, $3);
|
||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: unless_mod!($3, $1) %*/
|
/*% ripper: unless_mod!($3, $1) %*/
|
||||||
@ -4066,6 +4066,7 @@ p_lparen : '(' {$<tbl>$ = push_pktbl(p);};
|
|||||||
p_lbracket : '[' {$<tbl>$ = push_pktbl(p);};
|
p_lbracket : '[' {$<tbl>$ = push_pktbl(p);};
|
||||||
|
|
||||||
p_expr_basic : p_value
|
p_expr_basic : p_value
|
||||||
|
| p_variable
|
||||||
| p_const p_lparen p_args rparen
|
| p_const p_lparen p_args rparen
|
||||||
{
|
{
|
||||||
pop_pktbl(p, $<tbl>2);
|
pop_pktbl(p, $<tbl>2);
|
||||||
@ -4400,8 +4401,8 @@ p_value : p_primitive
|
|||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: dot3!($1, Qnil) %*/
|
/*% ripper: dot3!($1, Qnil) %*/
|
||||||
}
|
}
|
||||||
| p_variable
|
|
||||||
| p_var_ref
|
| p_var_ref
|
||||||
|
| p_expr_ref
|
||||||
| p_const
|
| p_const
|
||||||
| tBDOT2 p_primitive
|
| tBDOT2 p_primitive
|
||||||
{
|
{
|
||||||
@ -4462,6 +4463,15 @@ p_var_ref : '^' tIDENTIFIER
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
p_expr_ref : '^' tLPAREN expr_value ')'
|
||||||
|
{
|
||||||
|
/*%%%*/
|
||||||
|
$$ = NEW_BEGIN($3, &@$);
|
||||||
|
/*% %*/
|
||||||
|
/*% ripper: begin!($3) %*/
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
p_const : tCOLON3 cname
|
p_const : tCOLON3 cname
|
||||||
{
|
{
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
|
@ -478,6 +478,14 @@ eot
|
|||||||
|
|
||||||
[__LINE__, %q{ case 0; in "a\x0":a1, "a\0":a2; end }] =>
|
[__LINE__, %q{ case 0; in "a\x0":a1, "a\0":a2; end }] =>
|
||||||
nil, # duplicated key name
|
nil, # duplicated key name
|
||||||
|
|
||||||
|
[__LINE__, %q{ case 0; in ^(0+0); end } ] =>
|
||||||
|
[:case,
|
||||||
|
[:@int, "0", [1, 5]],
|
||||||
|
[:in,
|
||||||
|
[:begin, [:binary, [:@int, "0", [1, 13]], :+, [:@int, "0", [1, 15]]]],
|
||||||
|
[[:void_stmt]],
|
||||||
|
nil]],
|
||||||
}
|
}
|
||||||
pattern_matching_data.each do |(i, src), expected|
|
pattern_matching_data.each do |(i, src), expected|
|
||||||
define_method(:"test_pattern_matching_#{i}") do
|
define_method(:"test_pattern_matching_#{i}") do
|
||||||
|
@ -402,6 +402,29 @@ END
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_pin_operator_expr_pattern
|
||||||
|
assert_block do
|
||||||
|
case 'abc'
|
||||||
|
in ^(/a/)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_block do
|
||||||
|
case {name: '2.6', released_at: Time.new(2018, 12, 25)}
|
||||||
|
in {released_at: ^(Time.new(2010)..Time.new(2020))}
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_block do
|
||||||
|
case 0
|
||||||
|
in ^(0+0)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_array_pattern
|
def test_array_pattern
|
||||||
assert_block do
|
assert_block do
|
||||||
[[0], C.new([0])].all? do |i|
|
[[0], C.new([0])].all? do |i|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user