summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHiroya Fujinami <make.just.on@gmail.com>2023-11-21 00:52:40 +0900
committergit <svn-admin@ruby-lang.org>2023-11-20 15:52:44 +0000
commitcaa9ae780430a67c1ed3cb5f15b0e023452d76e4 (patch)
tree3ce025585f6e77db92f6c63436d1b732cf0c00e9
parent83da4a7e6291fbc919c1a5813f3e84b8fdd858d5 (diff)
[ruby/prism] Fix parsing `...` in arguments
(https://github.com/ruby/prism/pull/1882) * Fix parsing `...` in arguments Fix https://github.com/ruby/prism/pull/1830 Fix https://github.com/ruby/prism/pull/1831 * Rename the constant name to PM_ERR_ARGUMENT_FORWARDING_UNBOUND https://github.com/ruby/prism/pull/1882#discussion_r1398461156 https://github.com/ruby/prism/commit/519653aec2
-rw-r--r--prism/diagnostic.c2
-rw-r--r--prism/diagnostic.h2
-rw-r--r--prism/prism.c11
-rw-r--r--test/prism/errors_test.rb14
4 files changed, 29 insertions, 0 deletions
diff --git a/prism/diagnostic.c b/prism/diagnostic.c
index 2c59e4effc..c1d930a430 100644
--- a/prism/diagnostic.c
+++ b/prism/diagnostic.c
@@ -54,12 +54,14 @@ static const char* const diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = {
[PM_ERR_ALIAS_ARGUMENT] = "Invalid argument being passed to `alias`; expected a bare word, symbol, constant, or global variable",
[PM_ERR_AMPAMPEQ_MULTI_ASSIGN] = "Unexpected `&&=` in a multiple assignment",
[PM_ERR_ARGUMENT_AFTER_BLOCK] = "Unexpected argument after a block argument",
+ [PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES] = "Unexpected argument after `...`",
[PM_ERR_ARGUMENT_BARE_HASH] = "Unexpected bare hash argument",
[PM_ERR_ARGUMENT_BLOCK_MULTI] = "Multiple block arguments; only one block is allowed",
[PM_ERR_ARGUMENT_FORMAL_CLASS] = "Invalid formal argument; formal argument cannot be a class variable",
[PM_ERR_ARGUMENT_FORMAL_CONSTANT] = "Invalid formal argument; formal argument cannot be a constant",
[PM_ERR_ARGUMENT_FORMAL_GLOBAL] = "Invalid formal argument; formal argument cannot be a global variable",
[PM_ERR_ARGUMENT_FORMAL_IVAR] = "Invalid formal argument; formal argument cannot be an instance variable",
+ [PM_ERR_ARGUMENT_FORWARDING_UNBOUND] = "Unexpected `...` in an non-parenthesized call",
[PM_ERR_ARGUMENT_NO_FORWARDING_AMP] = "Unexpected `&` when the parent method is not forwarding",
[PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = "Unexpected `...` when the parent method is not forwarding",
[PM_ERR_ARGUMENT_NO_FORWARDING_STAR] = "Unexpected `*` when the parent method is not forwarding",
diff --git a/prism/diagnostic.h b/prism/diagnostic.h
index 10b547ae20..c963289cbf 100644
--- a/prism/diagnostic.h
+++ b/prism/diagnostic.h
@@ -40,12 +40,14 @@ typedef enum {
PM_ERR_ALIAS_ARGUMENT,
PM_ERR_AMPAMPEQ_MULTI_ASSIGN,
PM_ERR_ARGUMENT_AFTER_BLOCK,
+ PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES,
PM_ERR_ARGUMENT_BARE_HASH,
PM_ERR_ARGUMENT_BLOCK_MULTI,
PM_ERR_ARGUMENT_FORMAL_CLASS,
PM_ERR_ARGUMENT_FORMAL_CONSTANT,
PM_ERR_ARGUMENT_FORMAL_GLOBAL,
PM_ERR_ARGUMENT_FORMAL_IVAR,
+ PM_ERR_ARGUMENT_FORWARDING_UNBOUND,
PM_ERR_ARGUMENT_NO_FORWARDING_AMP,
PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
PM_ERR_ARGUMENT_NO_FORWARDING_STAR,
diff --git a/prism/prism.c b/prism/prism.c
index 86d9fce00f..83f5a33bea 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -11039,13 +11039,18 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
return;
}
+ bool parsed_first_argument = false;
bool parsed_bare_hash = false;
bool parsed_block_argument = false;
+ bool parsed_forwarding_arguments = false;
while (!match1(parser, PM_TOKEN_EOF)) {
if (parsed_block_argument) {
pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
}
+ if (parsed_forwarding_arguments) {
+ pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
+ }
pm_node_t *argument = NULL;
@@ -11129,9 +11134,13 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
if (pm_parser_local_depth(parser, &parser->previous) == -1) {
pm_parser_err_previous(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
}
+ if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
+ pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
+ }
argument = (pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->previous);
parse_arguments_append(parser, arguments, argument);
+ parsed_forwarding_arguments = true;
break;
}
}
@@ -11183,6 +11192,8 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
}
}
+ parsed_first_argument = true;
+
// If parsing the argument failed, we need to stop parsing arguments.
if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->recovering) break;
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index f13327c198..11036b1f81 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -1682,6 +1682,20 @@ module Prism
]
end
+ def test_argument_after_ellipsis
+ source = 'def foo(...); foo(..., 1); end'
+ assert_errors expression(source), source, [
+ ['Unexpected argument after `...`', 23..24]
+ ]
+ end
+
+ def test_ellipsis_in_no_paren_call
+ source = 'def foo(...); foo 1, ...; end'
+ assert_errors expression(source), source, [
+ ['Unexpected `...` in an non-parenthesized call', 21..24]
+ ]
+ end
+
private
def assert_errors(expected, source, errors, compare_ripper: RUBY_ENGINE == "ruby")