Out of place jumps are valid in `defined?`

This commit is contained in:
Nobuyoshi Nakada 2023-09-12 00:35:05 +09:00
Родитель 29e5fca718
Коммит 5b36c11e21
3 изменённых файлов: 42 добавлений и 9 удалений

22
parse.y
Просмотреть файл

@ -1493,10 +1493,12 @@ add_block_exit(struct parser_params *p, NODE *node)
compile_error(p, "unexpected node: %s", ruby_node_name(nd_type(node)));
break;
}
NODE *exits = p->exits;
if (exits) {
exits->nd_end->nd_next = node;
exits->nd_end = node;
if (!p->ctxt.in_defined) {
NODE *exits = p->exits;
if (exits) {
exits->nd_end->nd_next = node;
exits->nd_end = node;
}
}
return node;
}
@ -3865,11 +3867,13 @@ primary : literal
}
| keyword_retry
{
switch (p->ctxt.in_rescue) {
case before_rescue: yyerror1(&@1, "Invalid retry without rescue"); break;
case after_rescue: /* ok */ break;
case after_else: yyerror1(&@1, "Invalid retry after else"); break;
case after_ensure: yyerror1(&@1, "Invalid retry after ensure"); break;
if (!p->ctxt.in_defined) {
switch (p->ctxt.in_rescue) {
case before_rescue: yyerror1(&@1, "Invalid retry without rescue"); break;
case after_rescue: /* ok */ break;
case after_else: yyerror1(&@1, "Invalid retry after else"); break;
case after_ensure: yyerror1(&@1, "Invalid retry after ensure"); break;
}
}
/*%%%*/
$$ = NEW_RETRY(&@$);

Просмотреть файл

@ -244,6 +244,15 @@ class TestAst < Test::Unit::TestCase
assert_invalid_parse(msg, "def m; #{code}; end")
assert_invalid_parse(msg, "begin; #{code}; end")
assert_parse("END {#{code}}")
assert_parse("defined?(#{code})")
assert_parse("def m; defined?(#{code}); end")
assert_parse("begin; defined?(#{code}); end")
next if code.include?(" ")
assert_parse("defined? #{code}")
assert_parse("def m; defined? #{code}; end")
assert_parse("begin; defined? #{code}; end")
end
end
@ -258,6 +267,22 @@ class TestAst < Test::Unit::TestCase
assert_parse("nil rescue retry")
assert_invalid_parse(msg, "END {retry}")
assert_invalid_parse(msg, "begin rescue; END {retry}; end")
assert_parse("defined?(retry)")
assert_parse("def m; defined?(retry); end")
assert_parse("begin defined?(retry); end")
assert_parse("begin rescue; else; defined?(retry); end")
assert_parse("begin rescue; ensure; defined?(retry); end")
assert_parse("END {defined?(retry)}")
assert_parse("begin rescue; END {defined?(retry)}; end")
assert_parse("defined? retry")
assert_parse("def m; defined? retry; end")
assert_parse("begin defined? retry; end")
assert_parse("begin rescue; else; defined? retry; end")
assert_parse("begin rescue; ensure; defined? retry; end")
assert_parse("END {defined? retry}")
assert_parse("begin rescue; END {defined? retry}; end")
end
def test_node_id_for_location

Просмотреть файл

@ -377,6 +377,10 @@ class TestRubyOptions < Test::Unit::TestCase
assert_in_out_err(%w(-c -e begin -e next -e end), "", [], ["-e:2: Invalid next", :*])
assert_in_out_err(%w(-c -e begin -e redo -e end), "", [], ["-e:2: Invalid redo", :*])
assert_in_out_err(%w(-c -e begin -e retry -e end), "", [], ["-e:2: Invalid retry", :*])
assert_in_out_err(%w(-c -e defined?(break)), "", ["Syntax OK"], [])
assert_in_out_err(%w(-c -e defined?(next)), "", ["Syntax OK"], [])
assert_in_out_err(%w(-c -e defined?(redo)), "", ["Syntax OK"], [])
assert_in_out_err(%w(-c -e defined?(retry)), "", ["Syntax OK"], [])
end
def test_invalid_option