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

ruby-changes:66803

From: Jeremy <ko1@a...>
Date: Fri, 16 Jul 2021 01:56:20 +0900 (JST)
Subject: [ruby-changes:66803] fa87f72e1e (master): Add pattern matching pin support for instance/class/global variables

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

From fa87f72e1e84e2b55516be188f00434a683b924c Mon Sep 17 00:00:00 2001
From: Jeremy Evans <code@j...>
Date: Thu, 13 May 2021 15:31:46 -0700
Subject: Add pattern matching pin support for instance/class/global variables

Pin matching for local variables and constants is already supported,
and it is fairly simple to add support for these variable types.

Note that pin matching for method calls is still not supported
without wrapping in parentheses (pin expressions).  I think that's
for the best as method calls are far more complex (arguments/blocks).

Implements [Feature #17724]
---
 NEWS.md                            |  8 ++++++++
 compile.c                          |  3 +++
 doc/syntax/pattern_matching.rdoc   | 32 +++++++++++++++++++++++++++++++-
 parse.y                            | 14 +++++++++++++-
 test/ruby/test_pattern_matching.rb | 24 ++++++++++++++++++++++++
 5 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/NEWS.md b/NEWS.md
index 702803e..5f0b5a6 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -14,6 +14,13 @@ Note that each entry is kept to a minimum, see links for details. https://github.com/ruby/ruby/blob/trunk/NEWS.md#L14
     #=> [[3, 5], [5, 7], [11, 13]]
     ```
 
+* Pin operator now supports instance, class, and global variables.
+  [[Feature #17724]] 
+
+    @n = 5
+    Prime.each_cons(2).lazy.find{_1 in [n, ^@n]}
+    #=> [3, 5]
+
 * Multiple assignment evaluation order has been made consistent with
   single assignment evaluation order.  With single assignment, Ruby
   uses a left-to-right evaluation order.  With this code:
@@ -190,6 +197,7 @@ Excluding feature bug fixes. https://github.com/ruby/ruby/blob/trunk/NEWS.md#L197
 [Bug #17423]: https://bugs.ruby-lang.org/issues/17423
 [Feature #17479]: https://bugs.ruby-lang.org/issues/17479
 [Feature #17490]: https://bugs.ruby-lang.org/issues/17490
+[Feature #17724]: https://bugs.ruby-lang.org/issues/17724
 [Feature #17744]: https://bugs.ruby-lang.org/issues/17744
 [Feature #17762]: https://bugs.ruby-lang.org/issues/17762
 [Bug #18003]: https://bugs.ruby-lang.org/issues/18003
diff --git a/compile.c b/compile.c
index a786219..38a96f1 100644
--- a/compile.c
+++ b/compile.c
@@ -6462,6 +6462,9 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c https://github.com/ruby/ruby/blob/trunk/compile.c#L6462
       case NODE_CONST:
       case NODE_LVAR:
       case NODE_DVAR:
+      case NODE_IVAR:
+      case NODE_CVAR:
+      case NODE_GVAR:
       case NODE_TRUE:
       case NODE_FALSE:
       case NODE_SELF:
diff --git a/doc/syntax/pattern_matching.rdoc b/doc/syntax/pattern_matching.rdoc
index 6975636..49835de 100644
--- a/doc/syntax/pattern_matching.rdoc
+++ b/doc/syntax/pattern_matching.rdoc
@@ -312,6 +312,33 @@ One important usage of variable pinning is specifying that the same value should https://github.com/ruby/ruby/blob/trunk/doc/syntax/pattern_matching.rdoc#L312
   end
   #=> "not matched"
 
+In addition to pinning local variables, you can also pin instance, global, and class variables:
+
+  $gvar = 1
+  class A
+    @ivar = 2
+    @@cvar = 3
+    case [1, 2, 3]
+    in ^$gvar, ^@ivar, ^@@cvar
+      "matched"
+    else
+      "not matched"
+    end
+    #=> "matched"
+  end
+
+You can also pin the result of arbitrary expressions using parentheses:
+
+  a = 1
+  b = 2
+  case 3
+  in ^(a + b)
+    "matched"
+  else
+    "not matched"
+  end
+  #=> "matched"
+
 == Matching non-primitive objects: +deconstruct+ and +deconstruct_keys+
 
 As already mentioned above, array, find, and hash patterns besides literal arrays and hashes will try to match any object implementing +deconstruct+ (for array/find patterns) or +deconstruct_keys+ (for hash patterns).
@@ -449,7 +476,10 @@ Approximate syntax is: https://github.com/ruby/ruby/blob/trunk/doc/syntax/pattern_matching.rdoc#L476
 
   value_pattern: literal
                | Constant
-               | ^variable
+               | ^local_variable
+               | ^instance_variable
+               | ^class_variable
+               | ^global_variable
                | ^(expression)
 
   variable_pattern: variable
diff --git a/parse.y b/parse.y
index df16cf6..dec4b7d 100644
--- a/parse.y
+++ b/parse.y
@@ -1203,7 +1203,7 @@ static int looking_at_eol_p(struct parser_params *p); https://github.com/ruby/ruby/blob/trunk/parse.y#L1203
 %type <id>   cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg
 %type <id>   f_kwrest f_label f_arg_asgn call_op call_op2 reswords relop dot_or_colon
 %type <id>   p_rest p_kwrest p_kwnorest p_any_kwrest p_kw_label
-%type <id>   f_no_kwarg f_any_kwrest args_forward excessed_comma
+%type <id>   f_no_kwarg f_any_kwrest args_forward excessed_comma nonlocal_var
  %type <ctxt> lex_ctxt /* keep <ctxt> in ripper */
 %token END_OF_INPUT 0	"end-of-input"
 %token <id> '.'
@@ -4517,6 +4517,13 @@ p_var_ref	: '^' tIDENTIFIER https://github.com/ruby/ruby/blob/trunk/parse.y#L4517
 		    /*% %*/
 		    /*% ripper: var_ref!($2) %*/
 		    }
+                | '^' nonlocal_var
+		    {
+		    /*%%%*/
+			if (!($$ = gettable(p, $2, &@$))) $$ = NEW_BEGIN(0, &@$);
+		    /*% %*/
+		    /*% ripper: var_ref!($2) %*/
+                    }
 		;
 
 p_expr_ref	: '^' tLPAREN expr_value ')'
@@ -4993,6 +5000,11 @@ simple_numeric	: tINTEGER https://github.com/ruby/ruby/blob/trunk/parse.y#L5000
 		| tIMAGINARY
 		;
 
+nonlocal_var    : tIVAR
+		| tGVAR
+		| tCVAR
+		;
+
 user_variable	: tIDENTIFIER
 		| tIVAR
 		| tGVAR
diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb
index c494550..320c2c0 100644
--- a/test/ruby/test_pattern_matching.rb
+++ b/test/ruby/test_pattern_matching.rb
@@ -400,6 +400,30 @@ END https://github.com/ruby/ruby/blob/trunk/test/ruby/test_pattern_matching.rb#L400
         a == 0
       end
     end
+
+    assert_block do
+      @a = /a/
+      case 'abc'
+      in ^@a
+        true
+      end
+    end
+
+    assert_block do
+      @@TestPatternMatching = /a/
+      case 'abc'
+      in ^@@TestPatternMatching
+        true
+      end
+    end
+
+    assert_block do
+      $TestPatternMatching = /a/
+      case 'abc'
+      in ^$TestPatternMatching
+        true
+      end
+    end
   end
 
   def test_pin_operator_expr_pattern
-- 
cgit v1.1


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

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