summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS.md8
-rw-r--r--compile.c3
-rw-r--r--doc/syntax/pattern_matching.rdoc32
-rw-r--r--parse.y14
-rw-r--r--test/ruby/test_pattern_matching.rb24
5 files changed, 79 insertions, 2 deletions
diff --git a/NEWS.md b/NEWS.md
index 702803eee7..5f0b5a6b2c 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -14,6 +14,13 @@ Note that each entry is kept to a minimum, see links for details.
#=> [[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.
[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 a7862194c0..38a96f165e 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
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 69756369fb..49835def22 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
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:
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 df16cf6236..dec4b7dfd9 100644
--- a/parse.y
+++ b/parse.y
@@ -1203,7 +1203,7 @@ static int looking_at_eol_p(struct parser_params *p);
%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
/*% %*/
/*% 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
| 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 c494550574..320c2c00c7 100644
--- a/test/ruby/test_pattern_matching.rb
+++ b/test/ruby/test_pattern_matching.rb
@@ -400,6 +400,30 @@ END
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