mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Disallow duplicated pattern variable
This commit is contained in:
parent
1e620c67af
commit
a396bef8d8
2 changed files with 100 additions and 12 deletions
45
parse.y
45
parse.y
|
@ -250,6 +250,7 @@ struct parser_params {
|
||||||
int heredoc_line_indent;
|
int heredoc_line_indent;
|
||||||
char *tokenbuf;
|
char *tokenbuf;
|
||||||
struct local_vars *lvtbl;
|
struct local_vars *lvtbl;
|
||||||
|
st_table *pvtbl;
|
||||||
int line_count;
|
int line_count;
|
||||||
int ruby_sourceline; /* current line no. */
|
int ruby_sourceline; /* current line no. */
|
||||||
const char *ruby_sourcefile; /* current source file */
|
const char *ruby_sourcefile; /* current source file */
|
||||||
|
@ -496,6 +497,8 @@ static NODE *heredoc_dedent(struct parser_params*,NODE*);
|
||||||
|
|
||||||
static void check_literal_when(struct parser_params *p, NODE *args, const YYLTYPE *loc);
|
static void check_literal_when(struct parser_params *p, NODE *args, const YYLTYPE *loc);
|
||||||
|
|
||||||
|
static void error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *loc);
|
||||||
|
|
||||||
#define get_id(id) (id)
|
#define get_id(id) (id)
|
||||||
#define get_value(val) (val)
|
#define get_value(val) (val)
|
||||||
#define get_num(num) (num)
|
#define get_num(num) (num)
|
||||||
|
@ -974,6 +977,7 @@ static int looking_at_eol_p(struct parser_params *p);
|
||||||
NODE *node;
|
NODE *node;
|
||||||
ID id;
|
ID id;
|
||||||
int num;
|
int num;
|
||||||
|
st_table *tbl;
|
||||||
const struct vtable *vars;
|
const struct vtable *vars;
|
||||||
struct rb_strterm_struct *strterm;
|
struct rb_strterm_struct *strterm;
|
||||||
}
|
}
|
||||||
|
@ -1561,14 +1565,22 @@ expr : command_call
|
||||||
$<num>$ = p->in_kwarg;
|
$<num>$ = p->in_kwarg;
|
||||||
p->in_kwarg = 1;
|
p->in_kwarg = 1;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
$<tbl>$ = p->pvtbl;
|
||||||
|
p->pvtbl = st_init_numtable();
|
||||||
|
}
|
||||||
p_top_expr_body
|
p_top_expr_body
|
||||||
|
{
|
||||||
|
st_free_table(p->pvtbl);
|
||||||
|
p->pvtbl = $<tbl>4;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
p->in_kwarg = !!$<num>3;
|
p->in_kwarg = !!$<num>3;
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_CASE3($1, NEW_IN($4, NEW_TRUE(&@4), NEW_FALSE(&@4), &@4), &@$);
|
$$ = NEW_CASE3($1, NEW_IN($5, NEW_TRUE(&@5), NEW_FALSE(&@5), &@5), &@$);
|
||||||
rb_warn0L(nd_line($$), "Pattern matching is experimental, and the behavior may change in future versions of Ruby!");
|
rb_warn0L(nd_line($$), "Pattern matching is experimental, and the behavior may change in future versions of Ruby!");
|
||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: case!($1, in!($4, Qnil, Qnil)) %*/
|
/*% ripper: case!($1, in!($5, Qnil, Qnil)) %*/
|
||||||
}
|
}
|
||||||
| arg %prec tLBRACE_ARG
|
| arg %prec tLBRACE_ARG
|
||||||
;
|
;
|
||||||
|
@ -3800,7 +3812,15 @@ p_case_body : keyword_in
|
||||||
$<num>$ = p->in_kwarg;
|
$<num>$ = p->in_kwarg;
|
||||||
p->in_kwarg = 1;
|
p->in_kwarg = 1;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
$<tbl>$ = p->pvtbl;
|
||||||
|
p->pvtbl = st_init_numtable();
|
||||||
|
}
|
||||||
p_top_expr then
|
p_top_expr then
|
||||||
|
{
|
||||||
|
st_free_table(p->pvtbl);
|
||||||
|
p->pvtbl = $<tbl>3;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
p->in_kwarg = !!$<num>2;
|
p->in_kwarg = !!$<num>2;
|
||||||
}
|
}
|
||||||
|
@ -3808,9 +3828,9 @@ p_case_body : keyword_in
|
||||||
p_cases
|
p_cases
|
||||||
{
|
{
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_IN($3, $6, $7, &@$);
|
$$ = NEW_IN($4, $8, $9, &@$);
|
||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: in!($3, $6, escape_Qundef($7)) %*/
|
/*% ripper: in!($4, $8, escape_Qundef($9)) %*/
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -4089,6 +4109,7 @@ p_kw : tLABEL p_expr
|
||||||
yyerror1(&@1, "key must be valid as local variables");
|
yyerror1(&@1, "key must be valid as local variables");
|
||||||
}
|
}
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
|
error_duplicate_pattern_variable(p, $1, &@1);
|
||||||
$$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@$), &@$), assignable(p, $1, 0, &@$));
|
$$ = list_append(p, NEW_LIST(NEW_LIT(ID2SYM($1), &@$), &@$), assignable(p, $1, 0, &@$));
|
||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: rb_ary_new_from_args(1, rb_ary_new_from_args(2, get_value($1), Qnil)) %*/
|
/*% ripper: rb_ary_new_from_args(1, rb_ary_new_from_args(2, get_value($1), Qnil)) %*/
|
||||||
|
@ -4119,6 +4140,7 @@ p_kw : tLABEL p_expr
|
||||||
if (!is_local_id(id)) {
|
if (!is_local_id(id)) {
|
||||||
yyerror1(&loc, "key must be valid as local variables");
|
yyerror1(&loc, "key must be valid as local variables");
|
||||||
}
|
}
|
||||||
|
error_duplicate_pattern_variable(p, id, &loc);
|
||||||
$$ = list_append(p, NEW_LIST(node, &loc), assignable(p, id, 0, &@$));
|
$$ = list_append(p, NEW_LIST(node, &loc), assignable(p, id, 0, &@$));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -4249,6 +4271,7 @@ p_primitive : literal
|
||||||
p_variable : tIDENTIFIER
|
p_variable : tIDENTIFIER
|
||||||
{
|
{
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
|
error_duplicate_pattern_variable(p, $1, &@1);
|
||||||
$$ = assignable(p, $1, 0, &@$);
|
$$ = assignable(p, $1, 0, &@$);
|
||||||
/*% %*/
|
/*% %*/
|
||||||
/*% ripper: assignable(p, var_field(p, $1)) %*/
|
/*% ripper: assignable(p, var_field(p, $1)) %*/
|
||||||
|
@ -11529,6 +11552,20 @@ new_hash(struct parser_params *p, NODE *hash, const YYLTYPE *loc)
|
||||||
return NEW_HASH(hash, loc);
|
return NEW_HASH(hash, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
error_duplicate_pattern_variable(struct parser_params *p, ID id, const YYLTYPE *loc)
|
||||||
|
{
|
||||||
|
if (is_private_local_id(id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (st_is_member(p->pvtbl, id)) {
|
||||||
|
yyerror1(loc, "duplicated variable name");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
st_insert(p->pvtbl, (st_data_t)id, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
error_duplicate_keys(struct parser_params *p, NODE *hash)
|
error_duplicate_keys(struct parser_params *p, NODE *hash)
|
||||||
{
|
{
|
||||||
|
|
|
@ -193,25 +193,25 @@ class TestPatternMatching < Test::Unit::TestCase
|
||||||
def test_var_pattern
|
def test_var_pattern
|
||||||
# NODE_DASGN_CURR
|
# NODE_DASGN_CURR
|
||||||
assert_block do
|
assert_block do
|
||||||
case [0, 1]
|
case 0
|
||||||
in a, a
|
in a
|
||||||
a == 1
|
a == 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# NODE_DASGN
|
# NODE_DASGN
|
||||||
b = 0
|
b = 0
|
||||||
assert_block do
|
assert_block do
|
||||||
case [0, 1]
|
case 1
|
||||||
in b, b
|
in b
|
||||||
b == 1
|
b == 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# NODE_LASGN
|
# NODE_LASGN
|
||||||
case [0, 1]
|
case 0
|
||||||
in c, c
|
in c
|
||||||
assert_equal(1, c)
|
assert_equal(0, c)
|
||||||
else
|
else
|
||||||
flunk
|
flunk
|
||||||
end
|
end
|
||||||
|
@ -221,6 +221,57 @@ class TestPatternMatching < Test::Unit::TestCase
|
||||||
in ^a
|
in ^a
|
||||||
end
|
end
|
||||||
}, /no such local variable/)
|
}, /no such local variable/)
|
||||||
|
|
||||||
|
assert_syntax_error(%q{
|
||||||
|
case 0
|
||||||
|
in a, a
|
||||||
|
end
|
||||||
|
}, /duplicated variable name/)
|
||||||
|
|
||||||
|
assert_block do
|
||||||
|
case [0, 1, 2, 3]
|
||||||
|
in _, _, _a, _a
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_syntax_error(%q{
|
||||||
|
case 0
|
||||||
|
in a, {a:}
|
||||||
|
end
|
||||||
|
}, /duplicated variable name/)
|
||||||
|
|
||||||
|
assert_syntax_error(%q{
|
||||||
|
case 0
|
||||||
|
in a, {"a":}
|
||||||
|
end
|
||||||
|
}, /duplicated variable name/)
|
||||||
|
|
||||||
|
assert_block do
|
||||||
|
case [0, "1"]
|
||||||
|
in a, "#{case 1; in a; a; end}"
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_syntax_error(%q{
|
||||||
|
case [0, "1"]
|
||||||
|
in a, "#{case 1; in a; a; end}", a
|
||||||
|
end
|
||||||
|
}, /duplicated variable name/)
|
||||||
|
|
||||||
|
assert_block do
|
||||||
|
case 0
|
||||||
|
in a
|
||||||
|
true
|
||||||
|
in a
|
||||||
|
flunk
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_syntax_error(%q{
|
||||||
|
0 in [a, a]
|
||||||
|
}, /duplicated variable name/)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_literal_value_pattern
|
def test_literal_value_pattern
|
||||||
|
|
Loading…
Reference in a new issue