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

ruby-changes:57459

From: Kazuki <ko1@a...>
Date: Sun, 1 Sep 2019 16:41:14 +0900 (JST)
Subject: [ruby-changes:57459] Kazuki Tsujimoto: 94d6ec1d90 (master): Make pattern matching support **nil syntax

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

From 94d6ec1d90bb28e5f303867b048e6322d8781cb1 Mon Sep 17 00:00:00 2001
From: Kazuki Tsujimoto <kazuki@c...>
Date: Sun, 1 Sep 2019 16:39:34 +0900
Subject: Make pattern matching support **nil syntax


diff --git a/ast.c b/ast.c
index 601a819..fdb4b7a 100644
--- a/ast.c
+++ b/ast.c
@@ -652,10 +652,13 @@ node_children(rb_ast_t *ast, NODE *node) https://github.com/ruby/ruby/blob/trunk/ast.c#L652
         }
       case NODE_HSHPTN:
         {
+            VALUE kwrest = node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD ? ID2SYM(rb_intern("NODE_SPECIAL_NO_REST_KEYWORD")) :
+                                                                                 NEW_CHILD(ast, node->nd_pkwrestarg);
+
             return rb_ary_new_from_args(3,
                                         NEW_CHILD(ast, node->nd_pconst),
                                         NEW_CHILD(ast, node->nd_pkwargs),
-                                        NEW_CHILD(ast, node->nd_pkwrestarg));
+                                        kwrest);
         }
       case NODE_ARGS_AUX:
       case NODE_LAST:
diff --git a/compile.c b/compile.c
index d11e2f9..02171c6 100644
--- a/compile.c
+++ b/compile.c
@@ -5467,7 +5467,15 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c https://github.com/ruby/ruby/blob/trunk/compile.c#L5467
          *     end
          *   end
          *   if pattern.has_kw_rest_arg_node?
-         *     pattern.kw_rest_arg_node.match?(d)
+         *     if pattern.no_rest_keyword?
+         *       unless d.empty?
+         *         goto match_failed
+         *       end
+         *     else
+         *       unless pattern.kw_rest_arg_node.match?(d)
+         *         goto match_failed
+         *       end
+         *     end
          *   end
          *   true
          *   goto fin
@@ -5563,9 +5571,16 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c https://github.com/ruby/ruby/blob/trunk/compile.c#L5571
         }
 
         if (node->nd_pkwrestarg) {
-            ADD_INSN(ret, line, dup);
-            iseq_compile_pattern_each(iseq, ret, node->nd_pkwrestarg, in_alt_pattern);
-            ADD_INSNL(ret, line, branchunless, match_failed);
+            if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
+                ADD_INSN(ret, line, dup);
+                ADD_SEND(ret, line, idEmptyP, INT2FIX(0));
+                ADD_INSNL(ret, line, branchunless, match_failed);
+            }
+            else {
+                ADD_INSN(ret, line, dup);
+                iseq_compile_pattern_each(iseq, ret, node->nd_pkwrestarg, in_alt_pattern);
+                ADD_INSNL(ret, line, branchunless, match_failed);
+            }
         }
 
         ADD_INSN(ret, line, pop);
diff --git a/node.c b/node.c
index 4c2810b..f4df845 100644
--- a/node.c
+++ b/node.c
@@ -1065,7 +1065,12 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node) https://github.com/ruby/ruby/blob/trunk/node.c#L1065
         F_NODE(nd_pconst, "constant");
         F_NODE(nd_pkwargs, "keyword arguments");
         LAST_NODE;
-        F_NODE(nd_pkwrestarg, "keyword rest argument");
+        if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
+            F_MSG(nd_pkwrestarg, "keyword rest argument", "NODE_SPECIAL_NO_REST_KEYWORD (**nil)");
+        }
+        else {
+            F_NODE(nd_pkwrestarg, "keyword rest argument");
+        }
         return;
 
       case NODE_ARGS_AUX:
diff --git a/node.h b/node.h
index 3b565fc..dbc3162 100644
--- a/node.h
+++ b/node.h
@@ -385,6 +385,7 @@ typedef struct RNode { https://github.com/ruby/ruby/blob/trunk/node.h#L385
 #define NODE_SPECIAL_NO_NAME_REST     ((NODE *)-1)
 #define NODE_NAMED_REST_P(node) ((node) != NODE_SPECIAL_NO_NAME_REST)
 #define NODE_SPECIAL_EXCESSIVE_COMMA   ((ID)1)
+#define NODE_SPECIAL_NO_REST_KEYWORD   ((NODE *)-1)
 
 VALUE rb_node_case_when_optimizable_literal(const NODE *const node);
 
diff --git a/parse.y b/parse.y
index f6d6e27..6729e10 100644
--- a/parse.y
+++ b/parse.y
@@ -1033,7 +1033,7 @@ static void token_info_warn(struct parser_params *p, const char *token, token_in https://github.com/ruby/ruby/blob/trunk/parse.y#L1033
 %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>   f_kwrest f_label f_arg_asgn call_op call_op2 reswords relop dot_or_colon
-%type <id>   p_kwrest
+%type <id>   p_kwrest p_kwnorest
 %type <id>   f_no_kwarg
 %token END_OF_INPUT 0	"end-of-input"
 %token <id> '.'
@@ -3950,6 +3950,14 @@ p_kwargs	: p_kwarg ',' p_kwrest https://github.com/ruby/ruby/blob/trunk/parse.y#L3950
 		    {
 			$$ =  new_hash_pattern_tail(p, new_hash(p, Qnone, &@$), $1, &@$);
 		    }
+		| p_kwarg ',' p_kwnorest
+		    {
+			$$ =  new_hash_pattern_tail(p, new_unique_key_hash(p, $1, &@$), ID2SYM(idNil), &@$);
+		    }
+		| p_kwnorest
+		    {
+			$$ =  new_hash_pattern_tail(p, new_hash(p, Qnone, &@$), ID2SYM(idNil), &@$);
+		    }
 		;
 
 p_kwarg 	: p_kw
@@ -4026,6 +4034,12 @@ p_kwrest	: kwrest_mark tIDENTIFIER https://github.com/ruby/ruby/blob/trunk/parse.y#L4034
 		    }
 		;
 
+p_kwnorest	: kwrest_mark keyword_nil
+		    {
+		        $$ = 0;
+		    }
+		;
+
 p_value 	: p_primitive
 		| p_primitive tDOT2 p_primitive
 		    {
@@ -11253,7 +11267,10 @@ new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, co https://github.com/ruby/ruby/blob/trunk/parse.y#L11267
     int saved_line = p->ruby_sourceline;
     NODE *node, *kw_rest_arg_node;
 
-    if (kw_rest_arg) {
+    if (kw_rest_arg == ID2SYM(idNil)) {
+	kw_rest_arg_node = NODE_SPECIAL_NO_REST_KEYWORD;
+    }
+    else if (kw_rest_arg) {
 	kw_rest_arg_node = assignable(p, kw_rest_arg, 0, loc);
     }
     else {
diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb
index 988a9df..1f209b0 100644
--- a/test/ruby/test_pattern_matching.rb
+++ b/test/ruby/test_pattern_matching.rb
@@ -847,6 +847,44 @@ END https://github.com/ruby/ruby/blob/trunk/test/ruby/test_pattern_matching.rb#L847
     end
 
     assert_block do
+      [{}, C.new({})].all? do |i|
+        case i
+        in **nil
+          true
+        end
+      end
+    end
+
+    assert_block do
+      [{a: 0}, C.new({a: 0})].all? do |i|
+        case i
+        in **nil
+        else
+          true
+        end
+      end
+    end
+
+    assert_block do
+      [{a: 0}, C.new({a: 0})].all? do |i|
+        case i
+        in a:, **nil
+          true
+        end
+      end
+    end
+
+    assert_block do
+      [{a: 0, b: 1}, C.new({a: 0, b: 1})].all? do |i|
+        case i
+        in a:, **nil
+        else
+          true
+        end
+      end
+    end
+
+    assert_block do
       case C.new({a: 0})
       in C(a: 0)
         true
-- 
cgit v0.10.2


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

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