[前][次][番号順一覧][スレッド一覧]

ruby-changes:65608

From: Kazuki <ko1@a...>
Date: Sun, 21 Mar 2021 15:14:59 +0900 (JST)
Subject: [ruby-changes:65608] 21863470d9 (master): Pattern matching pin operator against expression [Feature #17411]

https://git.ruby-lang.org/ruby.git/commit/?id=21863470d9

From 21863470d965b8cc299b1f82417c70d5d26f8ab2 Mon Sep 17 00:00:00 2001
From: Kazuki Tsujimoto <kazuki@c...>
Date: Sun, 21 Mar 2021 15:12:54 +0900
Subject: Pattern matching pin operator against expression [Feature #17411]

This commit is based on the patch by @nobu.
---
 NEWS.md                            |  7 +++++++
 compile.c                          |  1 +
 doc/syntax/pattern_matching.rdoc   |  1 +
 parse.y                            | 18 ++++++++++++++----
 test/ripper/test_sexp.rb           |  8 ++++++++
 test/ruby/test_pattern_matching.rb | 23 +++++++++++++++++++++++
 6 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/NEWS.md b/NEWS.md
index d620819..f8d2179 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -6,6 +6,12 @@ since the **3.0.0** release, except for bug fixes. https://github.com/ruby/ruby/blob/trunk/NEWS.md#L6
 Note that each entry is kept to a minimum, see links for details.
 
 ## 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
 
@@ -90,5 +96,6 @@ Excluding feature bug fixes. https://github.com/ruby/ruby/blob/trunk/NEWS.md#L96
 [Feature #16806]: https://bugs.ruby-lang.org/issues/16806
 [Feature #17312]: https://bugs.ruby-lang.org/issues/17312
 [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
 [Feature #17479]: https://bugs.ruby-lang.org/issues/17479
diff --git a/compile.c b/compile.c
index 78870ee..230b800 100644
--- a/compile.c
+++ b/compile.c
@@ -6211,6 +6211,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c https://github.com/ruby/ruby/blob/trunk/compile.c#L6211
       case NODE_NIL:
       case NODE_COLON2:
       case NODE_COLON3:
+      case NODE_BEGIN:
         CHECK(COMPILE(ret, "case in literal", node));
         ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
         ADD_INSNL(ret, line, branchif, matched);
diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc
index 9f6954f..6975636 100644
--- a/doc/syntax/pattern_matching.rdoc
+++ b/doc/syntax/pattern_matching.rdoc
@@ -450,6 +450,7 @@ Approximate syntax is: https://github.com/ruby/ruby/blob/trunk/doc/syntax/pattern_matching.rdoc#L450
   value_pattern: literal
                | Constant
                | ^variable
+               | ^(expression)
 
   variable_pattern: variable
 
diff --git a/parse.y b/parse.y
index 10cd100..e24d26e 100644
--- a/parse.y
+++ b/parse.y
@@ -1196,7 +1196,7 @@ static int looking_at_eol_p(struct parser_params *p); https://github.com/ruby/ruby/blob/trunk/parse.y#L1196
 %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_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 <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
@@ -3994,7 +3994,7 @@ p_top_expr	: p_top_expr_body https://github.com/ruby/ruby/blob/trunk/parse.y#L3994
 		| p_top_expr_body modifier_if expr_value
 		    {
 		    /*%%%*/
-			$$ = new_if(p, $3, remove_begin($1), 0, &@$);
+			$$ = new_if(p, $3, $1, 0, &@$);
 			fixpos($$, $3);
 		    /*% %*/
 		    /*% ripper: if_mod!($3, $1) %*/
@@ -4002,7 +4002,7 @@ p_top_expr	: p_top_expr_body https://github.com/ruby/ruby/blob/trunk/parse.y#L4002
 		| p_top_expr_body modifier_unless expr_value
 		    {
 		    /*%%%*/
-			$$ = new_unless(p, $3, remove_begin($1), 0, &@$);
+			$$ = new_unless(p, $3, $1, 0, &@$);
 			fixpos($$, $3);
 		    /*% %*/
 		    /*% ripper: unless_mod!($3, $1) %*/
@@ -4066,6 +4066,7 @@ p_lparen	: '(' {$<tbl>$ = push_pktbl(p);}; https://github.com/ruby/ruby/blob/trunk/parse.y#L4066
 p_lbracket	: '[' {$<tbl>$ = push_pktbl(p);};
 
 p_expr_basic	: p_value
+		| p_variable
 		| p_const p_lparen p_args rparen
 		    {
 			pop_pktbl(p, $<tbl>2);
@@ -4400,8 +4401,8 @@ p_value 	: p_primitive https://github.com/ruby/ruby/blob/trunk/parse.y#L4401
 		    /*% %*/
 		    /*% ripper: dot3!($1, Qnil) %*/
 		    }
-		| p_variable
 		| p_var_ref
+		| p_expr_ref
 		| p_const
 		| tBDOT2 p_primitive
 		    {
@@ -4462,6 +4463,15 @@ p_var_ref	: '^' tIDENTIFIER https://github.com/ruby/ruby/blob/trunk/parse.y#L4463
 		    }
 		;
 
+p_expr_ref	: '^' tLPAREN expr_value ')'
+		    {
+		    /*%%%*/
+			$$ = NEW_BEGIN($3, &@$);
+		    /*% %*/
+		    /*% ripper: begin!($3) %*/
+		    }
+		;
+
 p_const 	: tCOLON3 cname
 		    {
 		    /*%%%*/
diff --git a/test/ripper/test_sexp.rb b/test/ripper/test_sexp.rb
index 22ee418..b4e70fa 100644
--- a/test/ripper/test_sexp.rb
+++ b/test/ripper/test_sexp.rb
@@ -478,6 +478,14 @@ eot https://github.com/ruby/ruby/blob/trunk/test/ripper/test_sexp.rb#L478
 
     [__LINE__, %q{ case 0; in "a\x0":a1, "a\0":a2; end }] =>
     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|
     define_method(:"test_pattern_matching_#{i}") do
diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb
index b18ef68..c494550 100644
--- a/test/ruby/test_pattern_matching.rb
+++ b/test/ruby/test_pattern_matching.rb
@@ -402,6 +402,29 @@ END https://github.com/ruby/ruby/blob/trunk/test/ruby/test_pattern_matching.rb#L402
     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
     assert_block do
       [[0], C.new([0])].all? do |i|
-- 
cgit v1.1


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]