summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2023-09-13 13:34:30 +0900
committerNobuyoshi Nakada <nobu@ruby-lang.org>2023-09-28 16:23:51 +0900
commitb5e23d3e3b5ff2f5328aa43a2392ebe7c951a222 (patch)
tree408005ab7b1b51f2a04bd3a15142361937683208
parentad96962173c824aeb4ecdd1d9a2e98eaa23a7536 (diff)
Syntax check of `yield` in the parser
-rw-r--r--parse.y15
-rw-r--r--test/prism/parse_test.rb2
-rw-r--r--test/ruby/test_ast.rb28
-rw-r--r--test/ruby/test_rubyoptions.rb3
4 files changed, 43 insertions, 5 deletions
diff --git a/parse.y b/parse.y
index 7570ba050f..e9ebfebf61 100644
--- a/parse.y
+++ b/parse.y
@@ -2697,7 +2697,7 @@ command : fcall command_args %prec tLOWEST
/*% %*/
/*% ripper: super!($2) %*/
}
- | keyword_yield command_args
+ | k_yield command_args
{
/*%%%*/
$$ = new_yield(p, $2, &@$);
@@ -3797,21 +3797,21 @@ primary : literal
/*% %*/
/*% ripper: return0! %*/
}
- | keyword_yield '(' call_args rparen
+ | k_yield '(' call_args rparen
{
/*%%%*/
$$ = new_yield(p, $3, &@$);
/*% %*/
/*% ripper: yield!(paren!($3)) %*/
}
- | keyword_yield '(' rparen
+ | k_yield '(' rparen
{
/*%%%*/
$$ = NEW_YIELD(0, &@$);
/*% %*/
/*% ripper: yield!(paren!(args_new!)) %*/
}
- | keyword_yield
+ | k_yield
{
/*%%%*/
$$ = NEW_YIELD(0, &@$);
@@ -4294,6 +4294,13 @@ k_return : keyword_return
}
;
+k_yield : keyword_yield
+ {
+ if (!p->ctxt.in_defined && !p->ctxt.in_def && !dyna_in_block(p))
+ yyerror1(&@1, "Invalid yield");
+ }
+ ;
+
then : term
| keyword_then
| term keyword_then
diff --git a/test/prism/parse_test.rb b/test/prism/parse_test.rb
index 65128bf5a7..3c0d584a12 100644
--- a/test/prism/parse_test.rb
+++ b/test/prism/parse_test.rb
@@ -89,7 +89,7 @@ module Prism
src = source
case relative
- when /break|next|redo|if|unless|rescue|control|keywords|retry/
+ when /break|next|redo|if|unless|rescue|control|keywords|retry|yield|\/args_assocs/
# Uncaught syntax errors: Invalid break, Invalid next
src = "->do\nrescue\n#{src}\nend"
ripper_should_match = false
diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb
index 70ebd22a98..76fd2b3783 100644
--- a/test/ruby/test_ast.rb
+++ b/test/ruby/test_ast.rb
@@ -285,6 +285,34 @@ class TestAst < Test::Unit::TestCase
assert_parse("begin rescue; END {defined? retry}; end")
end
+ def test_invalid_yield
+ msg = /Invalid yield/
+ assert_invalid_parse(msg, "yield")
+ assert_invalid_parse(msg, "class C; yield; end")
+ assert_invalid_parse(msg, "BEGIN {yield}")
+ assert_invalid_parse(msg, "END {yield}")
+
+ assert_invalid_parse(msg, "yield true")
+ assert_invalid_parse(msg, "class C; yield true; end")
+ assert_invalid_parse(msg, "BEGIN {yield true}")
+ assert_invalid_parse(msg, "END {yield true}")
+
+ assert_parse("!defined?(yield)")
+ assert_parse("class C; defined?(yield); end")
+ assert_parse("BEGIN {defined?(yield)}")
+ assert_parse("END {defined?(yield)}")
+
+ assert_parse("!defined?(yield true)")
+ assert_parse("class C; defined?(yield true); end")
+ assert_parse("BEGIN {defined?(yield true)}")
+ assert_parse("END {defined?(yield true)}")
+
+ assert_parse("!defined? yield")
+ assert_parse("class C; defined? yield; end")
+ assert_parse("BEGIN {defined? yield}")
+ assert_parse("END {defined? yield}")
+ end
+
def test_node_id_for_location
exception = begin
raise
diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb
index a2f738d9a5..b2e2e7bb6c 100644
--- a/test/ruby/test_rubyoptions.rb
+++ b/test/ruby/test_rubyoptions.rb
@@ -373,14 +373,17 @@ class TestRubyOptions < Test::Unit::TestCase
assert_in_out_err(%w(-cw -e next), "", [], ["-e:1: Invalid next", :*])
assert_in_out_err(%w(-cw -e redo), "", [], ["-e:1: Invalid redo", :*])
assert_in_out_err(%w(-cw -e retry), "", [], ["-e:1: Invalid retry", :*])
+ assert_in_out_err(%w(-cw -e yield), "", [], ["-e:1: Invalid yield", :*])
assert_in_out_err(%w(-cw -e begin -e break -e end), "", [], ["-e:2: Invalid break", :*])
assert_in_out_err(%w(-cw -e begin -e next -e end), "", [], ["-e:2: Invalid next", :*])
assert_in_out_err(%w(-cw -e begin -e redo -e end), "", [], ["-e:2: Invalid redo", :*])
assert_in_out_err(%w(-cw -e begin -e retry -e end), "", [], ["-e:2: Invalid retry", :*])
+ assert_in_out_err(%w(-cw -e begin -e yield -e end), "", [], ["-e:2: Invalid yield", :*])
assert_in_out_err(%w(-cw -e !defined?(break)), "", ["Syntax OK"], [])
assert_in_out_err(%w(-cw -e !defined?(next)), "", ["Syntax OK"], [])
assert_in_out_err(%w(-cw -e !defined?(redo)), "", ["Syntax OK"], [])
assert_in_out_err(%w(-cw -e !defined?(retry)), "", ["Syntax OK"], [])
+ assert_in_out_err(%w(-cw -e !defined?(yield)), "", ["Syntax OK"], [])
assert_in_out_err(%w(-n -cw -e break), "", ["Syntax OK"], [])
assert_in_out_err(%w(-n -cw -e next), "", ["Syntax OK"], [])
assert_in_out_err(%w(-n -cw -e redo), "", ["Syntax OK"], [])