mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Introduce find pattern [Feature #16828]
This commit is contained in:
parent
f7906a7e31
commit
ddded1157a
10 changed files with 450 additions and 11 deletions
12
NEWS.md
12
NEWS.md
|
@ -38,6 +38,18 @@ sufficient information, see the ChangeLog file or Redmine
|
|||
instead of a warning. yield in a class definition outside of a method
|
||||
is now a SyntaxError instead of a LocalJumpError. [[Feature #15575]]
|
||||
|
||||
* Find pattern is added. [[Feature #16828]]
|
||||
|
||||
```ruby
|
||||
case ["a", 1, "b", "c", 2, "d", "e", "f", 3]
|
||||
in [*pre, String => x, String => y, *post]
|
||||
p pre #=> ["a", 1]
|
||||
p x #=> "b"
|
||||
p y #=> "c"
|
||||
p post #=> [2, "d", "e", "f", 3]
|
||||
end
|
||||
```
|
||||
|
||||
* Rightward assignment statement is added. [EXPERIMENTAL]
|
||||
[[Feature #15921]]
|
||||
|
||||
|
|
13
ast.c
13
ast.c
|
@ -599,6 +599,19 @@ node_children(rb_ast_t *ast, NODE *node)
|
|||
rest,
|
||||
NEW_CHILD(ast, apinfo->post_args));
|
||||
}
|
||||
case NODE_FNDPTN:
|
||||
{
|
||||
struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
|
||||
VALUE pre_rest = NODE_NAMED_REST_P(fpinfo->pre_rest_arg) ? NEW_CHILD(ast, fpinfo->pre_rest_arg) :
|
||||
ID2SYM(rb_intern("NODE_SPECIAL_NO_NAME_REST"));
|
||||
VALUE post_rest = NODE_NAMED_REST_P(fpinfo->post_rest_arg) ? NEW_CHILD(ast, fpinfo->post_rest_arg) :
|
||||
ID2SYM(rb_intern("NODE_SPECIAL_NO_NAME_REST"));
|
||||
return rb_ary_new_from_args(4,
|
||||
NEW_CHILD(ast, node->nd_pconst),
|
||||
pre_rest,
|
||||
NEW_CHILD(ast, fpinfo->args),
|
||||
post_rest);
|
||||
}
|
||||
case NODE_HSHPTN:
|
||||
{
|
||||
VALUE kwrest = node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD ? ID2SYM(rb_intern("NODE_SPECIAL_NO_REST_KEYWORD")) :
|
||||
|
|
167
compile.c
167
compile.c
|
@ -5752,6 +5752,173 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
|
|||
|
||||
break;
|
||||
}
|
||||
case NODE_FNDPTN: {
|
||||
/*
|
||||
* if pattern.has_constant_node?
|
||||
* unless pattern.constant === obj
|
||||
* goto match_failed
|
||||
* end
|
||||
* end
|
||||
* unless obj.respond_to?(:deconstruct)
|
||||
* goto match_failed
|
||||
* end
|
||||
* d = obj.deconstruct
|
||||
* unless Array === d
|
||||
* goto type_error
|
||||
* end
|
||||
* unless d.length >= pattern.args_num
|
||||
* goto match_failed
|
||||
* end
|
||||
*
|
||||
* begin
|
||||
* len = d.length
|
||||
* limit = d.length - pattern.args_num
|
||||
* i = 0
|
||||
* while i <= limit
|
||||
* if pattern.args_num.times.all? {|j| pattern.args[j].match?(d[i+j]) }
|
||||
* if pattern.has_pre_rest_arg_id
|
||||
* unless pattern.pre_rest_arg.match?(d[0, i])
|
||||
* goto find_failed
|
||||
* end
|
||||
* end
|
||||
* if pattern.has_post_rest_arg_id
|
||||
* unless pattern.post_rest_arg.match?(d[i+pattern.args_num, len])
|
||||
* goto find_failed
|
||||
* end
|
||||
* end
|
||||
* goto find_succeeded
|
||||
* end
|
||||
* i+=1
|
||||
* end
|
||||
* find_failed:
|
||||
* goto match_failed
|
||||
* find_succeeded:
|
||||
* end
|
||||
*
|
||||
* goto matched
|
||||
* type_error:
|
||||
* FrozenCore.raise TypeError
|
||||
* match_failed:
|
||||
* goto unmatched
|
||||
*/
|
||||
struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
|
||||
const NODE *args = fpinfo->args;
|
||||
const int args_num = fpinfo->args ? rb_long2int(fpinfo->args->nd_alen) : 0;
|
||||
|
||||
LABEL *match_failed, *type_error;
|
||||
match_failed = NEW_LABEL(line);
|
||||
type_error = NEW_LABEL(line);
|
||||
|
||||
if (node->nd_pconst) {
|
||||
ADD_INSN(ret, line, dup);
|
||||
CHECK(COMPILE(ret, "constant", node->nd_pconst));
|
||||
ADD_INSN1(ret, line, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
|
||||
ADD_INSNL(ret, line, branchunless, match_failed);
|
||||
}
|
||||
|
||||
ADD_INSN(ret, line, dup);
|
||||
ADD_INSN1(ret, line, putobject, ID2SYM(rb_intern("deconstruct")));
|
||||
ADD_SEND(ret, line, idRespond_to, INT2FIX(1));
|
||||
ADD_INSNL(ret, line, branchunless, match_failed);
|
||||
|
||||
ADD_SEND(ret, line, rb_intern("deconstruct"), INT2FIX(0));
|
||||
|
||||
ADD_INSN(ret, line, dup);
|
||||
ADD_INSN1(ret, line, checktype, INT2FIX(T_ARRAY));
|
||||
ADD_INSNL(ret, line, branchunless, type_error);
|
||||
|
||||
ADD_INSN(ret, line, dup);
|
||||
ADD_SEND(ret, line, idLength, INT2FIX(0));
|
||||
ADD_INSN1(ret, line, putobject, INT2FIX(args_num));
|
||||
ADD_SEND(ret, line, idGE, INT2FIX(1));
|
||||
ADD_INSNL(ret, line, branchunless, match_failed);
|
||||
|
||||
{
|
||||
LABEL *while_begin = NEW_LABEL(nd_line(node));
|
||||
LABEL *next_loop = NEW_LABEL(nd_line(node));
|
||||
LABEL *find_succeeded = NEW_LABEL(line);
|
||||
LABEL *find_failed = NEW_LABEL(nd_line(node));
|
||||
int j;
|
||||
|
||||
ADD_INSN(ret, line, dup); /* allocate stack for len */
|
||||
ADD_SEND(ret, line, idLength, INT2FIX(0));
|
||||
|
||||
ADD_INSN(ret, line, dup); /* allocate stack for limit */
|
||||
ADD_INSN1(ret, line, putobject, INT2FIX(args_num));
|
||||
ADD_SEND(ret, line, idMINUS, INT2FIX(1));
|
||||
|
||||
ADD_INSN1(ret, line, putobject, INT2FIX(0)); /* allocate stack for i */
|
||||
|
||||
ADD_LABEL(ret, while_begin);
|
||||
|
||||
ADD_INSN(ret, line, dup);
|
||||
ADD_INSN1(ret, line, topn, INT2FIX(2));
|
||||
ADD_SEND(ret, line, idLE, INT2FIX(1));
|
||||
ADD_INSNL(ret, line, branchunless, find_failed);
|
||||
|
||||
for (j = 0; j < args_num; j++) {
|
||||
ADD_INSN1(ret, line, topn, INT2FIX(3));
|
||||
ADD_INSN1(ret, line, topn, INT2FIX(1));
|
||||
if (j != 0) {
|
||||
ADD_INSN1(ret, line, putobject, INT2FIX(j));
|
||||
ADD_SEND(ret, line, idPLUS, INT2FIX(1));
|
||||
}
|
||||
ADD_SEND(ret, line, idAREF, INT2FIX(1));
|
||||
|
||||
CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, next_loop, in_alt_pattern));
|
||||
args = args->nd_next;
|
||||
}
|
||||
|
||||
if (NODE_NAMED_REST_P(fpinfo->pre_rest_arg)) {
|
||||
ADD_INSN1(ret, line, topn, INT2FIX(3));
|
||||
ADD_INSN1(ret, line, putobject, INT2FIX(0));
|
||||
ADD_INSN1(ret, line, topn, INT2FIX(2));
|
||||
ADD_SEND(ret, line, idAREF, INT2FIX(2));
|
||||
CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->pre_rest_arg, find_failed, in_alt_pattern));
|
||||
}
|
||||
if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) {
|
||||
ADD_INSN1(ret, line, topn, INT2FIX(3));
|
||||
ADD_INSN1(ret, line, topn, INT2FIX(1));
|
||||
ADD_INSN1(ret, line, putobject, INT2FIX(args_num));
|
||||
ADD_SEND(ret, line, idPLUS, INT2FIX(1));
|
||||
ADD_INSN1(ret, line, topn, INT2FIX(3));
|
||||
ADD_SEND(ret, line, idAREF, INT2FIX(2));
|
||||
CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->post_rest_arg, find_failed, in_alt_pattern));
|
||||
}
|
||||
ADD_INSNL(ret, line, jump, find_succeeded);
|
||||
|
||||
ADD_LABEL(ret, next_loop);
|
||||
ADD_INSN1(ret, line, putobject, INT2FIX(1));
|
||||
ADD_SEND(ret, line, idPLUS, INT2FIX(1));
|
||||
ADD_INSNL(ret, line, jump, while_begin);
|
||||
|
||||
ADD_LABEL(ret, find_failed);
|
||||
ADD_INSN(ret, line, pop);
|
||||
ADD_INSN(ret, line, pop);
|
||||
ADD_INSN(ret, line, pop);
|
||||
ADD_INSNL(ret, line, jump, match_failed);
|
||||
|
||||
ADD_LABEL(ret, find_succeeded);
|
||||
ADD_INSN(ret, line, pop);
|
||||
ADD_INSN(ret, line, pop);
|
||||
ADD_INSN(ret, line, pop);
|
||||
}
|
||||
|
||||
ADD_INSN(ret, line, pop);
|
||||
ADD_INSNL(ret, line, jump, matched);
|
||||
|
||||
ADD_LABEL(ret, type_error);
|
||||
ADD_INSN1(ret, line, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
|
||||
ADD_INSN1(ret, line, putobject, rb_eTypeError);
|
||||
ADD_INSN1(ret, line, putobject, rb_fstring_lit("deconstruct must return Array"));
|
||||
ADD_SEND(ret, line, id_core_raise, INT2FIX(2));
|
||||
|
||||
ADD_LABEL(ret, match_failed);
|
||||
ADD_INSN(ret, line, pop);
|
||||
ADD_INSNL(ret, line, jump, unmatched);
|
||||
|
||||
break;
|
||||
}
|
||||
case NODE_HSHPTN: {
|
||||
/*
|
||||
* keys = nil
|
||||
|
|
|
@ -479,6 +479,7 @@ count_nodes(int argc, VALUE *argv, VALUE os)
|
|||
COUNT_NODE(NODE_ATTRASGN);
|
||||
COUNT_NODE(NODE_LAMBDA);
|
||||
COUNT_NODE(NODE_ARYPTN);
|
||||
COUNT_NODE(NODE_FNDPTN);
|
||||
COUNT_NODE(NODE_HSHPTN);
|
||||
#undef COUNT_NODE
|
||||
case NODE_LAST: break;
|
||||
|
|
34
node.c
34
node.c
|
@ -1053,6 +1053,27 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
|
|||
F_NODE(nd_apinfo->post_args, "post arguments");
|
||||
return;
|
||||
|
||||
case NODE_FNDPTN:
|
||||
ANN("find pattern");
|
||||
ANN("format: [nd_pconst](*[pre_rest_arg], args, ..., *[post_rest_arg])");
|
||||
F_NODE(nd_pconst, "constant");
|
||||
if (NODE_NAMED_REST_P(node->nd_fpinfo->pre_rest_arg)) {
|
||||
F_NODE(nd_fpinfo->pre_rest_arg, "pre rest argument");
|
||||
}
|
||||
else {
|
||||
F_MSG(nd_fpinfo->pre_rest_arg, "pre rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
|
||||
}
|
||||
F_NODE(nd_fpinfo->args, "arguments");
|
||||
|
||||
LAST_NODE;
|
||||
if (NODE_NAMED_REST_P(node->nd_fpinfo->post_rest_arg)) {
|
||||
F_NODE(nd_fpinfo->post_rest_arg, "post rest argument");
|
||||
}
|
||||
else {
|
||||
F_MSG(nd_fpinfo->post_rest_arg, "post rest argument", "NODE_SPECIAL_NO_NAME_REST (rest argument without name)");
|
||||
}
|
||||
return;
|
||||
|
||||
case NODE_HSHPTN:
|
||||
ANN("hash pattern");
|
||||
ANN("format: [nd_pconst]([nd_pkwargs], ..., **[nd_pkwrestarg])");
|
||||
|
@ -1204,6 +1225,7 @@ rb_ast_newnode(rb_ast_t *ast, enum node_type type)
|
|||
case NODE_ARGS:
|
||||
case NODE_SCOPE:
|
||||
case NODE_ARYPTN:
|
||||
case NODE_FNDPTN:
|
||||
return ast_newnode_in_bucket(&nb->markable);
|
||||
default:
|
||||
return ast_newnode_in_bucket(&nb->unmarkable);
|
||||
|
@ -1271,6 +1293,12 @@ mark_ast_value(void *ctx, NODE * node)
|
|||
rb_gc_mark_movable(apinfo->imemo);
|
||||
break;
|
||||
}
|
||||
case NODE_FNDPTN:
|
||||
{
|
||||
struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
|
||||
rb_gc_mark_movable(fpinfo->imemo);
|
||||
break;
|
||||
}
|
||||
case NODE_ARGS:
|
||||
{
|
||||
struct rb_args_info *args = node->nd_ainfo;
|
||||
|
@ -1311,6 +1339,12 @@ update_ast_value(void *ctx, NODE * node)
|
|||
apinfo->imemo = rb_gc_location(apinfo->imemo);
|
||||
break;
|
||||
}
|
||||
case NODE_FNDPTN:
|
||||
{
|
||||
struct rb_fnd_pattern_info *fpinfo = node->nd_fpinfo;
|
||||
fpinfo->imemo = rb_gc_location(fpinfo->imemo);
|
||||
break;
|
||||
}
|
||||
case NODE_ARGS:
|
||||
{
|
||||
struct rb_args_info *args = node->nd_ainfo;
|
||||
|
|
11
node.h
11
node.h
|
@ -123,6 +123,7 @@ enum node_type {
|
|||
NODE_LAMBDA,
|
||||
NODE_ARYPTN,
|
||||
NODE_HSHPTN,
|
||||
NODE_FNDPTN,
|
||||
NODE_LAST
|
||||
};
|
||||
|
||||
|
@ -166,6 +167,7 @@ typedef struct RNode {
|
|||
struct rb_global_entry *entry;
|
||||
struct rb_args_info *args;
|
||||
struct rb_ary_pattern_info *apinfo;
|
||||
struct rb_fnd_pattern_info *fpinfo;
|
||||
VALUE value;
|
||||
} u3;
|
||||
rb_code_location_t nd_loc;
|
||||
|
@ -278,6 +280,8 @@ typedef struct RNode {
|
|||
|
||||
#define nd_apinfo u3.apinfo
|
||||
|
||||
#define nd_fpinfo u3.fpinfo
|
||||
|
||||
#define NEW_NODE(t,a0,a1,a2,loc) rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2),loc)
|
||||
#define NEW_NODE_WITH_LOCALS(t,a1,a2,loc) node_newnode_with_locals(p, (t),(VALUE)(a1),(VALUE)(a2),loc)
|
||||
|
||||
|
@ -456,6 +460,13 @@ struct rb_ary_pattern_info {
|
|||
VALUE imemo;
|
||||
};
|
||||
|
||||
struct rb_fnd_pattern_info {
|
||||
NODE *pre_rest_arg;
|
||||
NODE *args;
|
||||
NODE *post_rest_arg;
|
||||
VALUE imemo;
|
||||
};
|
||||
|
||||
struct parser_params;
|
||||
void *rb_parser_malloc(struct parser_params *, size_t);
|
||||
void *rb_parser_realloc(struct parser_params *, void *, size_t);
|
||||
|
|
123
parse.y
123
parse.y
|
@ -496,6 +496,8 @@ static NODE *new_args(struct parser_params*,NODE*,NODE*,ID,NODE*,NODE*,const YYL
|
|||
static NODE *new_args_tail(struct parser_params*,NODE*,ID,ID,const YYLTYPE*);
|
||||
static NODE *new_array_pattern(struct parser_params *p, NODE *constant, NODE *pre_arg, NODE *aryptn, const YYLTYPE *loc);
|
||||
static NODE *new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, ID rest_arg, NODE *post_args, const YYLTYPE *loc);
|
||||
static NODE *new_find_pattern(struct parser_params *p, NODE *constant, NODE *fndptn, const YYLTYPE *loc);
|
||||
static NODE *new_find_pattern_tail(struct parser_params *p, ID pre_rest_arg, NODE *args, ID post_rest_arg, const YYLTYPE *loc);
|
||||
static NODE *new_hash_pattern(struct parser_params *p, NODE *constant, NODE *hshptn, const YYLTYPE *loc);
|
||||
static NODE *new_hash_pattern_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, const YYLTYPE *loc);
|
||||
static NODE *new_case3(struct parser_params *p, NODE *val, NODE *pat, const YYLTYPE *loc);
|
||||
|
@ -871,6 +873,42 @@ new_array_pattern_tail(struct parser_params *p, VALUE pre_args, VALUE has_rest,
|
|||
return (VALUE)t;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
new_find_pattern(struct parser_params *p, VALUE constant, VALUE fndptn, const YYLTYPE *loc)
|
||||
{
|
||||
NODE *t = (NODE *)fndptn;
|
||||
struct rb_fnd_pattern_info *fpinfo = t->nd_fpinfo;
|
||||
VALUE pre_rest_arg = Qnil, args = Qnil, post_rest_arg = Qnil;
|
||||
|
||||
if (fpinfo) {
|
||||
pre_rest_arg = rb_ary_entry(fpinfo->imemo, 0);
|
||||
args = rb_ary_entry(fpinfo->imemo, 1);
|
||||
post_rest_arg = rb_ary_entry(fpinfo->imemo, 2);
|
||||
}
|
||||
|
||||
return dispatch4(fndptn, constant, pre_rest_arg, args, post_rest_arg);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
new_find_pattern_tail(struct parser_params *p, VALUE pre_rest_arg, VALUE args, VALUE post_rest_arg, const YYLTYPE *loc)
|
||||
{
|
||||
NODE *t;
|
||||
struct rb_fnd_pattern_info *fpinfo;
|
||||
|
||||
pre_rest_arg = dispatch1(var_field, pre_rest_arg ? pre_rest_arg : Qnil);
|
||||
post_rest_arg = dispatch1(var_field, post_rest_arg ? post_rest_arg : Qnil);
|
||||
|
||||
VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
|
||||
fpinfo = ZALLOC(struct rb_fnd_pattern_info);
|
||||
rb_imemo_tmpbuf_set_ptr(tmpbuf, fpinfo);
|
||||
fpinfo->imemo = rb_ary_new_from_args(4, pre_rest_arg, args, post_rest_arg, tmpbuf);
|
||||
|
||||
t = rb_node_newnode(NODE_FNDPTN, Qnil, Qnil, (VALUE)fpinfo, &NULL_LOC);
|
||||
RB_OBJ_WRITTEN(p->ast, Qnil, fpinfo->imemo);
|
||||
|
||||
return (VALUE)t;
|
||||
}
|
||||
|
||||
#define new_hash(p,h,l) rb_ary_new_from_args(0)
|
||||
|
||||
static VALUE
|
||||
|
@ -1139,14 +1177,14 @@ static int looking_at_eol_p(struct parser_params *p);
|
|||
%type <node> brace_block cmd_brace_block do_block lhs none fitem
|
||||
%type <node> mlhs mlhs_head mlhs_basic mlhs_item mlhs_node mlhs_post mlhs_inner
|
||||
%type <node> p_case_body p_cases p_top_expr p_top_expr_body
|
||||
%type <node> p_expr p_as p_alt p_expr_basic
|
||||
%type <node> p_expr p_as p_alt p_expr_basic p_find
|
||||
%type <node> p_args p_args_head p_args_tail p_args_post p_arg
|
||||
%type <node> p_value p_primitive p_variable p_var_ref p_const
|
||||
%type <node> p_kwargs p_kwarg p_kw
|
||||
%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 p_kwnorest p_any_kwrest p_kw_label
|
||||
%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
|
||||
%token END_OF_INPUT 0 "end-of-input"
|
||||
%token <id> '.'
|
||||
|
@ -3963,6 +4001,10 @@ p_top_expr_body : p_expr
|
|||
/*%
|
||||
%*/
|
||||
}
|
||||
| p_find
|
||||
{
|
||||
$$ = new_find_pattern(p, Qnone, $1, &@$);
|
||||
}
|
||||
| p_args_tail
|
||||
{
|
||||
$$ = new_array_pattern(p, Qnone, Qnone, $1, &@$);
|
||||
|
@ -4011,6 +4053,15 @@ p_expr_basic : p_value
|
|||
/*%
|
||||
%*/
|
||||
}
|
||||
| p_const p_lparen p_find rparen
|
||||
{
|
||||
pop_pktbl(p, $<tbl>2);
|
||||
$$ = new_find_pattern(p, $1, $3, &@$);
|
||||
/*%%%*/
|
||||
nd_set_first_loc($$, @1.beg_pos);
|
||||
/*%
|
||||
%*/
|
||||
}
|
||||
| p_const p_lparen p_kwargs rparen
|
||||
{
|
||||
pop_pktbl(p, $<tbl>2);
|
||||
|
@ -4034,6 +4085,15 @@ p_expr_basic : p_value
|
|||
/*%
|
||||
%*/
|
||||
}
|
||||
| p_const p_lbracket p_find rbracket
|
||||
{
|
||||
pop_pktbl(p, $<tbl>2);
|
||||
$$ = new_find_pattern(p, $1, $3, &@$);
|
||||
/*%%%*/
|
||||
nd_set_first_loc($$, @1.beg_pos);
|
||||
/*%
|
||||
%*/
|
||||
}
|
||||
| p_const p_lbracket p_kwargs rbracket
|
||||
{
|
||||
pop_pktbl(p, $<tbl>2);
|
||||
|
@ -4052,6 +4112,10 @@ p_expr_basic : p_value
|
|||
{
|
||||
$$ = new_array_pattern(p, Qnone, Qnone, $2, &@$);
|
||||
}
|
||||
| tLBRACK p_find rbracket
|
||||
{
|
||||
$$ = new_find_pattern(p, Qnone, $2, &@$);
|
||||
}
|
||||
| tLBRACK rbracket
|
||||
{
|
||||
$$ = new_array_pattern_tail(p, Qnone, 0, 0, Qnone, &@$);
|
||||
|
@ -4135,21 +4199,30 @@ p_args_head : p_arg ','
|
|||
}
|
||||
;
|
||||
|
||||
p_args_tail : tSTAR tIDENTIFIER
|
||||
p_args_tail : p_rest
|
||||
{
|
||||
$$ = new_array_pattern_tail(p, Qnone, 1, $2, Qnone, &@$);
|
||||
$$ = new_array_pattern_tail(p, Qnone, 1, $1, Qnone, &@$);
|
||||
}
|
||||
| tSTAR tIDENTIFIER ',' p_args_post
|
||||
| p_rest ',' p_args_post
|
||||
{
|
||||
$$ = new_array_pattern_tail(p, Qnone, 1, $2, $4, &@$);
|
||||
$$ = new_array_pattern_tail(p, Qnone, 1, $1, $3, &@$);
|
||||
}
|
||||
;
|
||||
|
||||
p_find : p_rest ',' p_args_post ',' p_rest
|
||||
{
|
||||
$$ = new_find_pattern_tail(p, $1, $3, $5, &@$);
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
p_rest : tSTAR tIDENTIFIER
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
| tSTAR
|
||||
{
|
||||
$$ = new_array_pattern_tail(p, Qnone, 1, 0, Qnone, &@$);
|
||||
}
|
||||
| tSTAR ',' p_args_post
|
||||
{
|
||||
$$ = new_array_pattern_tail(p, Qnone, 1, 0, $3, &@$);
|
||||
$$ = 0;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -11536,6 +11609,34 @@ new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, ID
|
|||
return node;
|
||||
}
|
||||
|
||||
static NODE*
|
||||
new_find_pattern(struct parser_params *p, NODE *constant, NODE *fndptn, const YYLTYPE *loc)
|
||||
{
|
||||
fndptn->nd_pconst = constant;
|
||||
|
||||
return fndptn;
|
||||
}
|
||||
|
||||
static NODE*
|
||||
new_find_pattern_tail(struct parser_params *p, ID pre_rest_arg, NODE *args, ID post_rest_arg, const YYLTYPE *loc)
|
||||
{
|
||||
int saved_line = p->ruby_sourceline;
|
||||
NODE *node;
|
||||
VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer();
|
||||
struct rb_fnd_pattern_info *fpinfo = ZALLOC(struct rb_fnd_pattern_info);
|
||||
rb_imemo_tmpbuf_set_ptr(tmpbuf, fpinfo);
|
||||
node = NEW_NODE(NODE_FNDPTN, 0, 0, fpinfo, loc);
|
||||
fpinfo->imemo = tmpbuf;
|
||||
RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf);
|
||||
|
||||
fpinfo->pre_rest_arg = pre_rest_arg ? assignable(p, pre_rest_arg, 0, loc) : NODE_SPECIAL_NO_NAME_REST;
|
||||
fpinfo->args = args;
|
||||
fpinfo->post_rest_arg = post_rest_arg ? assignable(p, post_rest_arg, 0, loc) : NODE_SPECIAL_NO_NAME_REST;
|
||||
|
||||
p->ruby_sourceline = saved_line;
|
||||
return node;
|
||||
}
|
||||
|
||||
static NODE*
|
||||
new_hash_pattern(struct parser_params *p, NODE *constant, NODE *hshptn, const YYLTYPE *loc)
|
||||
{
|
||||
|
|
|
@ -1548,6 +1548,12 @@ class TestRipper::ParserEvents < Test::Unit::TestCase
|
|||
assert_equal true, thru_aryptn
|
||||
end
|
||||
|
||||
def test_fndptn
|
||||
thru_fndptn = false
|
||||
parse('case 0; in [*,0,*]; end', :on_fndptn) {thru_fndptn = true}
|
||||
assert_equal true, thru_fndptn
|
||||
end
|
||||
|
||||
def test_hshptn
|
||||
thru_hshptn = false
|
||||
parse('case 0; in {a:}; end', :on_hshptn) {thru_hshptn = true}
|
||||
|
|
|
@ -412,6 +412,43 @@ eot
|
|||
[:@int, "0", [1, 5]],
|
||||
[:in, [:aryptn, nil, nil, nil, nil], [[:void_stmt]], nil]],
|
||||
|
||||
[__LINE__, %q{ 0 in [*, a, *] }] =>
|
||||
[:case,
|
||||
[:@int, "0", [1, 0]],
|
||||
[:in,
|
||||
[:fndptn,
|
||||
nil,
|
||||
[:var_field, nil],
|
||||
[[:var_field, [:@ident, "a", [1, 9]]]],
|
||||
[:var_field, nil]],
|
||||
nil,
|
||||
nil]],
|
||||
|
||||
[__LINE__, %q{ 0 in [*a, b, *c] }] =>
|
||||
[:case,
|
||||
[:@int, "0", [1, 0]],
|
||||
[:in,
|
||||
[:fndptn,
|
||||
nil,
|
||||
[:var_field, [:@ident, "a", [1, 7]]],
|
||||
[[:var_field, [:@ident, "b", [1, 10]]]],
|
||||
[:var_field, [:@ident, "c", [1, 14]]]],
|
||||
nil,
|
||||
nil]],
|
||||
|
||||
[__LINE__, %q{ 0 in A(*a, b, c, *d) }] =>
|
||||
[:case,
|
||||
[:@int, "0", [1, 0]],
|
||||
[:in,
|
||||
[:fndptn,
|
||||
[:var_ref, [:@const, "A", [1, 5]]],
|
||||
[:var_field, [:@ident, "a", [1, 8]]],
|
||||
[[:var_field, [:@ident, "b", [1, 11]]],
|
||||
[:var_field, [:@ident, "c", [1, 14]]]],
|
||||
[:var_field, [:@ident, "d", [1, 18]]]],
|
||||
nil,
|
||||
nil]],
|
||||
|
||||
[__LINE__, %q{ case 0; in {a: 0}; end }] =>
|
||||
[:case,
|
||||
[:@int, "0", [1, 5]],
|
||||
|
|
|
@ -736,6 +736,63 @@ END
|
|||
end
|
||||
end
|
||||
|
||||
def test_find_pattern
|
||||
[0, 1, 2] in [*, 1 => a, *]
|
||||
assert_equal(1, a)
|
||||
|
||||
[0, 1, 2] in [*a, 1 => b, *c]
|
||||
assert_equal([0], a)
|
||||
assert_equal(1, b)
|
||||
assert_equal([2], c)
|
||||
|
||||
assert_block do
|
||||
case [0, 1, 2]
|
||||
in [*, 9, *]
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
assert_block do
|
||||
case [0, 1, 2]
|
||||
in [*, Integer, String, *]
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
[0, 1, 2] in [*a, 1 => b, 2 => c, *d]
|
||||
assert_equal([0], a)
|
||||
assert_equal(1, b)
|
||||
assert_equal(2, c)
|
||||
assert_equal([], d)
|
||||
|
||||
case [0, 1, 2]
|
||||
in *, 1 => a, *;
|
||||
assert_equal(1, a)
|
||||
end
|
||||
|
||||
assert_block do
|
||||
case [0, 1, 2]
|
||||
in String(*, 1, *)
|
||||
false
|
||||
in Array(*, 1, *)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
assert_block do
|
||||
case [0, 1, 2]
|
||||
in String[*, 1, *]
|
||||
false
|
||||
in Array[*, 1, *]
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_hash_pattern
|
||||
assert_block do
|
||||
[{}, C.new({})].all? do |i|
|
||||
|
|
Loading…
Reference in a new issue