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/