Endless method definition [Feature #16746]
This commit is contained in:
parent
878e21c6cd
commit
e8f53692ca
Notes:
git
2020-04-10 19:06:24 +09:00
7
NEWS.md
7
NEWS.md
@ -45,6 +45,13 @@ sufficient information, see the ChangeLog file or Redmine
|
|||||||
fib(10) => x
|
fib(10) => x
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* Endless method definition is added. [EXPERIMENTAL]
|
||||||
|
[[Feature #16746]]
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
def square(x) = x * x
|
||||||
|
```
|
||||||
|
|
||||||
## Command line options
|
## Command line options
|
||||||
|
|
||||||
## Core classes updates
|
## Core classes updates
|
||||||
|
143
parse.y
143
parse.y
@ -59,6 +59,8 @@ struct lex_context {
|
|||||||
#include "ruby/util.h"
|
#include "ruby/util.h"
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
|
|
||||||
|
#define AREF(ary, i) RARRAY_AREF(ary, i)
|
||||||
|
|
||||||
#ifndef WARN_PAST_SCOPE
|
#ifndef WARN_PAST_SCOPE
|
||||||
# define WARN_PAST_SCOPE 0
|
# define WARN_PAST_SCOPE 0
|
||||||
#endif
|
#endif
|
||||||
@ -906,8 +908,27 @@ static VALUE heredoc_dedent(struct parser_params*,VALUE);
|
|||||||
#define ID2VAL(id) (id)
|
#define ID2VAL(id) (id)
|
||||||
#define TOKEN2VAL(t) ID2VAL(t)
|
#define TOKEN2VAL(t) ID2VAL(t)
|
||||||
#define KWD2EID(t, v) keyword_##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 */
|
#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
|
#ifndef RIPPER
|
||||||
# define Qnone 0
|
# define Qnone 0
|
||||||
# define Qnull 0
|
# define Qnull 0
|
||||||
@ -1082,7 +1103,7 @@ static int looking_at_eol_p(struct parser_params *p);
|
|||||||
%type <node> singleton strings string string1 xstring regexp
|
%type <node> singleton strings string string1 xstring regexp
|
||||||
%type <node> string_contents xstring_contents regexp_contents string_content
|
%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> 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> 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> 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
|
%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);
|
|||||||
%type <node> command_rhs arg_rhs
|
%type <node> command_rhs arg_rhs
|
||||||
%type <node> command_asgn mrhs mrhs_arg superclass block_call block_command
|
%type <node> command_asgn mrhs mrhs_arg superclass block_call block_command
|
||||||
%type <node> f_block_optarg f_block_opt
|
%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> 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> block_param opt_block_param block_param_def f_opt
|
||||||
%type <node> f_kwarg f_kw f_block_kwarg f_block_kw
|
%type <node> f_kwarg f_kw f_block_kwarg f_block_kw
|
||||||
@ -1635,6 +1656,46 @@ expr : command_call
|
|||||||
| arg %prec tLBRACE_ARG
|
| 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
|
expr_value : expr
|
||||||
{
|
{
|
||||||
value_expr($1);
|
value_expr($1);
|
||||||
@ -2392,6 +2453,26 @@ arg : lhs '=' arg_rhs
|
|||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: ifop!($1, $3, $6) %*/
|
/*% 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
|
| primary
|
||||||
{
|
{
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
@ -3018,56 +3099,31 @@ primary : literal
|
|||||||
local_pop(p);
|
local_pop(p);
|
||||||
p->ctxt.in_class = $<ctxt>1.in_class;
|
p->ctxt.in_class = $<ctxt>1.in_class;
|
||||||
}
|
}
|
||||||
| k_def fname
|
| defn_head
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
f_arglist
|
f_arglist
|
||||||
bodystmt
|
bodystmt
|
||||||
k_end
|
k_end
|
||||||
{
|
{
|
||||||
|
restore_defun(p, $<node>1->nd_defn);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
NODE *body = remove_begin($5);
|
$$ = set_defun_body(p, $1, $2, $3, &@$);
|
||||||
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);
|
|
||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: def!($2, $4, $5) %*/
|
/*% ripper: def!(get_value($1), $2, $3) %*/
|
||||||
local_pop(p);
|
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
|
f_arglist
|
||||||
bodystmt
|
bodystmt
|
||||||
k_end
|
k_end
|
||||||
{
|
{
|
||||||
|
restore_defun(p, $<node>1->nd_defn);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
NODE *body = remove_begin($8);
|
$$ = set_defun_body(p, $1, $2, $3, &@$);
|
||||||
reduce_nodes(p, &body);
|
/*%
|
||||||
$$ = NEW_DEFS($2, $5, $7, body, &@$);
|
$1 = get_value($1);
|
||||||
nd_set_line($$->nd_defn, @9.end_pos.lineno);
|
%*/
|
||||||
set_line_body(body, @1.beg_pos.lineno);
|
/*% ripper: defs!(AREF($1, 0), AREF($1, 1), AREF($1, 2), $2, $3) %*/
|
||||||
/*% %*/
|
|
||||||
/*% ripper: defs!($2, $3, $5, $7, $8) %*/
|
|
||||||
local_pop(p);
|
local_pop(p);
|
||||||
p->ctxt.in_def = $<ctxt>1.in_def;
|
|
||||||
p->cur_arg = $<id>6;
|
|
||||||
}
|
}
|
||||||
| keyword_break
|
| keyword_break
|
||||||
{
|
{
|
||||||
@ -4840,6 +4896,17 @@ superclass : '<'
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
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
|
f_arglist : '(' f_args rparen
|
||||||
{
|
{
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
|
@ -1766,3 +1766,16 @@ describe "An array-dereference method ([])" do
|
|||||||
end
|
end
|
||||||
end
|
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
|
||||||
|
@ -1414,6 +1414,13 @@ eom
|
|||||||
assert_equal(line, e.backtrace_locations[0].lineno)
|
assert_equal(line, e.backtrace_locations[0].lineno)
|
||||||
end
|
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
|
def test_methoddef_in_cond
|
||||||
assert_valid_syntax('while def foo; tap do end; end; break; end')
|
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')
|
assert_valid_syntax('while def foo a = tap do end; end; break; end')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user