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

ruby-changes:60731

From: Nobuyoshi <ko1@a...>
Date: Fri, 10 Apr 2020 19:06:21 +0900 (JST)
Subject: [ruby-changes:60731] e8f53692ca (master): Endless method definition [Feature #16746]

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

From e8f53692ca7d65c92bde6d5bc6a1aea492915d9f Mon Sep 17 00:00:00 2001
From: Nobuyoshi Nakada <nobu@r...>
Date: Wed, 1 Apr 2020 23:58:02 +0900
Subject: Endless method definition [Feature #16746]


diff --git a/NEWS.md b/NEWS.md
index 5b85ba4..68a1539 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -45,6 +45,13 @@ sufficient information, see the ChangeLog file or Redmine https://github.com/ruby/ruby/blob/trunk/NEWS.md#L45
     fib(10) => x
     ```
 
+* Endless method definition is added.  [EXPERIMENTAL]
+  [[Feature #16746]]
+
+    ```ruby
+    def square(x) = x * x
+    ```
+
 ## Command line options
 
 ## Core classes updates
diff --git a/parse.y b/parse.y
index 1c5ee84..794e676 100644
--- a/parse.y
+++ b/parse.y
@@ -59,6 +59,8 @@ struct lex_context { https://github.com/ruby/ruby/blob/trunk/parse.y#L59
 #include "ruby/util.h"
 #include "symbol.h"
 
+#define AREF(ary, i) RARRAY_AREF(ary, i)
+
 #ifndef WARN_PAST_SCOPE
 # define WARN_PAST_SCOPE 0
 #endif
@@ -906,8 +908,27 @@ static VALUE heredoc_dedent(struct parser_params*,VALUE); https://github.com/ruby/ruby/blob/trunk/parse.y#L908
 #define ID2VAL(id) (id)
 #define TOKEN2VAL(t) ID2VAL(t)
 #define KWD2EID(t, v) keyword_##t
+
+static NODE *
+set_defun_body(struct parser_params *p, NODE *n, NODE *args, NODE *body, const YYLTYPE *loc)
+{
+    body = remove_begin(body);
+    reduce_nodes(p, &body);
+    n->nd_defn = NEW_SCOPE(args, body, loc);
+    n->nd_loc = *loc;
+    nd_set_line(n->nd_defn, loc->end_pos.lineno);
+    set_line_body(body, loc->beg_pos.lineno);
+    return n;
+}
 #endif /* RIPPER */
 
+static void
+restore_defun(struct parser_params *p, NODE *name)
+{
+    p->cur_arg = name->nd_vid;
+    p->ctxt.in_def = name->nd_state & 1;
+}
+
 #ifndef RIPPER
 # define Qnone 0
 # define Qnull 0
@@ -1082,7 +1103,7 @@ static int looking_at_eol_p(struct parser_params *p); https://github.com/ruby/ruby/blob/trunk/parse.y#L1103
 %type <node> singleton strings string string1 xstring regexp
 %type <node> string_contents xstring_contents regexp_contents string_content
 %type <node> words symbols symbol_list qwords qsymbols word_list qword_list qsym_list word
-%type <node> literal numeric simple_numeric ssym dsym symbol cpath
+%type <node> literal numeric simple_numeric ssym dsym symbol cpath def_name defn_head defs_head
 %type <node> top_compstmt top_stmts top_stmt begin_block rassign
 %type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call
 %type <node> expr_value expr_value_do arg_value primary_value fcall rel_expr
@@ -1093,7 +1114,7 @@ static int looking_at_eol_p(struct parser_params *p); https://github.com/ruby/ruby/blob/trunk/parse.y#L1114
 %type <node> command_rhs arg_rhs
 %type <node> command_asgn mrhs mrhs_arg superclass block_call block_command
 %type <node> f_block_optarg f_block_opt
-%type <node> f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs f_rest_marg
+%type <node> f_arglist f_arglist_opt f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs f_rest_marg
 %type <node> assoc_list assocs assoc undef_list backref string_dvar for_var
 %type <node> block_param opt_block_param block_param_def f_opt
 %type <node> f_kwarg f_kw f_block_kwarg f_block_kw
@@ -1635,6 +1656,46 @@ expr		: command_call https://github.com/ruby/ruby/blob/trunk/parse.y#L1656
 		| arg %prec tLBRACE_ARG
 		;
 
+def_name	: fname
+		    {
+			ID fname = get_id($1);
+			ID cur_arg = p->cur_arg;
+			int in_def = p->ctxt.in_def;
+			numparam_name(p, fname);
+			local_push(p, 0);
+			p->cur_arg = 0;
+			p->ctxt.in_def = 1;
+			$<node>$ = NEW_NODE(NODE_SELF, /*vid*/cur_arg, /*mid*/fname, /*state*/in_def, &@$);
+		    /*%%%*/
+		    /*%
+			$$ = NEW_RIPPER(fname, get_value($1), $$, &NULL_LOC);
+		    %*/
+		    }
+		;
+
+defn_head	: k_def def_name
+		    {
+			$$ = $2;
+		    /*%%%*/
+			$$ = NEW_NODE(NODE_DEFN, 0, $$->nd_mid, $$, &@$);
+		    /*% %*/
+		    }
+		;
+
+defs_head	: k_def singleton dot_or_colon {SET_LEX_STATE(EXPR_FNAME);} def_name
+		    {
+			SET_LEX_STATE(EXPR_ENDFN|EXPR_LABEL); /* force for args */
+			$$ = $5;
+		    /*%%%*/
+			$$ = NEW_NODE(NODE_DEFS, $2, $$->nd_mid, $$, &@$);
+		    /*%
+			VALUE ary = rb_ary_new_from_args(3, $2, $3, get_value($$));
+			add_mark_object(p, ary);
+			$<node>$->nd_rval = ary;
+		    %*/
+		    }
+		;
+
 expr_value	: expr
 		    {
 			value_expr($1);
@@ -2392,6 +2453,26 @@ arg		: lhs '=' arg_rhs https://github.com/ruby/ruby/blob/trunk/parse.y#L2453
 		    /*% %*/
 		    /*% ripper: ifop!($1, $3, $6) %*/
 		    }
+		| defn_head f_arglist_opt '=' arg
+		    {
+			restore_defun(p, $<node>1->nd_defn);
+		    /*%%%*/
+			$$ = set_defun_body(p, $1, $2, $4, &@$);
+		    /*% %*/
+		    /*% ripper: def!(get_value($1), $2, $4) %*/
+			local_pop(p);
+		    }
+		| defs_head f_arglist_opt '=' arg
+		    {
+			restore_defun(p, $<node>1->nd_defn);
+		    /*%%%*/
+			$$ = set_defun_body(p, $1, $2, $4, &@$);
+		    /*%
+			$1 = get_value($1);
+		    %*/
+		    /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $4) %*/
+			local_pop(p);
+		    }
 		| primary
 		    {
 			$$ = $1;
@@ -3018,56 +3099,31 @@ primary		: literal https://github.com/ruby/ruby/blob/trunk/parse.y#L3099
 			local_pop(p);
 			p->ctxt.in_class = $<ctxt>1.in_class;
 		    }
-		| k_def fname
-		    {
-			numparam_name(p, get_id($2));
-			local_push(p, 0);
-			$<id>$ = p->cur_arg;
-			p->cur_arg = 0;
-			$<ctxt>1 = p->ctxt;
-			p->ctxt.in_def = 1;
-		    }
+		| defn_head
 		  f_arglist
 		  bodystmt
 		  k_end
 		    {
+			restore_defun(p, $<node>1->nd_defn);
 		    /*%%%*/
-			NODE *body = remove_begin($5);
-			reduce_nodes(p, &body);
-			$$ = NEW_DEFN($2, $4, body, &@$);
-			nd_set_line($$->nd_defn, @6.end_pos.lineno);
-			set_line_body(body, @1.beg_pos.lineno);
+			$$ = set_defun_body(p, $1, $2, $3, &@$);
 		    /*% %*/
-		    /*% ripper: def!($2, $4, $5) %*/
+		    /*% ripper: def!(get_value($1), $2, $3) %*/
 			local_pop(p);
-			p->ctxt.in_def = $<ctxt>1.in_def;
-			p->cur_arg = $<id>3;
-		    }
-		| k_def singleton dot_or_colon {SET_LEX_STATE(EXPR_FNAME);} fname
-		    {
-			numparam_name(p, get_id($5));
-			$<ctxt>1 = p->ctxt;
-			p->ctxt.in_def = 1;
-			SET_LEX_STATE(EXPR_ENDFN|EXPR_LABEL); /* force for args */
-			local_push(p, 0);
-			$<id>$ = p->cur_arg;
-			p->cur_arg = 0;
 		    }
+		| defs_head
 		  f_arglist
 		  bodystmt
 		  k_end
 		    {
+			restore_defun(p, $<node>1->nd_defn);
 		    /*%%%*/
-			NODE *body = remove_begin($8);
-			reduce_nodes(p, &body);
-			$$ = NEW_DEFS($2, $5, $7, body, &@$);
-			nd_set_line($$->nd_defn, @9.end_pos.lineno);
-			set_line_body(body, @1.beg_pos.lineno);
-		    /*% %*/
-		    /*% ripper: defs!($2, $3, $5, $7, $8) %*/
+			$$ = set_defun_body(p, $1, $2, $3, &@$);
+		    /*%
+			$1 = get_value($1);
+		    %*/
+		    /*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $3) %*/
 			local_pop(p);
-			p->ctxt.in_def = $<ctxt>1.in_def;
-			p->cur_arg = $<id>6;
 		    }
 		| keyword_break
 		    {
@@ -4840,6 +4896,17 @@ superclass	: '<' https://github.com/ruby/ruby/blob/trunk/parse.y#L4896
 		    }
 		;
 
+f_arglist_opt	: f_arglist
+		| /* none */
+		    {
+		    /*%%%*/
+			$$ = new_args_tail(p, Qnone, Qnone, Qnone, &@0);
+			$$ = new_args(p, Qnone, Qnone, Qnone, Qnone, $$, &@0);
+		    /*% %*/
+		    /*% ripper: Qnil %*/
+		    }
+		;
+
 f_arglist	: '(' f_args rparen
 		    {
 		    /*%%%*/
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index 0209ca2..bc7b8b6 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -1766,3 +1766,16 @@ describe "An array-dereference method ([])" do https://github.com/ruby/ruby/blob/trunk/spec/ruby/language/method_spec.rb#L1766
     end
   end
 end
+
+ruby_version_is '2.8' do
+  describe "An endless method definition" do
+    evaluate <<-ruby do
+      def m(a) = a
+    ruby
+
+      a = b = m 1
+      a.should == 1
+      b.should == 1
+    end
+  end
+end
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index 04e98ec..825d5e1 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -1414,6 +1414,13 @@ eom https://github.com/ruby/ruby/blob/trunk/test/ruby/test_syntax.rb#L1414
     assert_equal(line, e.backtrace_locations[0].lineno)
   end
 
+  def test_methoddef_endless
+    assert_valid_syntax('private def foo = 42')
+    assert_valid_syntax('private def inc(x) = x + 1')
+    assert_valid_syntax('private def obj.foo = 42')
+    assert_valid_syntax('private def obj.inc(x) = x + 1')
+  end
+
   def test_methoddef_in_cond
     assert_valid_syntax('while def foo; tap do end; end; break; end')
     assert_valid_syntax('while def foo a = tap do end; end; break; end')
-- 
cgit v0.10.2


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

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