summaryrefslogtreecommitdiff
path: root/prism
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2024-05-06 11:01:50 -0400
committerKevin Newton <kddnewton@gmail.com>2024-05-06 12:09:30 -0400
commitf92d82ef06f5478bd942a22ca987f787fa92cedc (patch)
tree32f0653186c2730ee660a79efdc69b7158ad561f /prism
parent14d400829d7bc6cdc8111ba534fb9e6aad2e96b5 (diff)
[ruby/prism] More specific error for conflicting forwarding parameters
https://github.com/ruby/prism/commit/1c3b48fedb
Diffstat (limited to 'prism')
-rw-r--r--prism/config.yml5
-rw-r--r--prism/prism.c89
-rw-r--r--prism/templates/src/diagnostic.c.erb5
3 files changed, 80 insertions, 19 deletions
diff --git a/prism/config.yml b/prism/config.yml
index 4fc4aa8e6a..5e6ee82ca4 100644
--- a/prism/config.yml
+++ b/prism/config.yml
@@ -7,13 +7,16 @@ errors:
- ARGUMENT_BARE_HASH
- ARGUMENT_BLOCK_FORWARDING
- ARGUMENT_BLOCK_MULTI
+ - ARGUMENT_CONFLICT_AMPERSAND
+ - ARGUMENT_CONFLICT_STAR
+ - ARGUMENT_CONFLICT_STAR_STAR
- ARGUMENT_FORMAL_CLASS
- ARGUMENT_FORMAL_CONSTANT
- ARGUMENT_FORMAL_GLOBAL
- ARGUMENT_FORMAL_IVAR
- ARGUMENT_FORWARDING_UNBOUND
- ARGUMENT_IN
- - ARGUMENT_NO_FORWARDING_AMP
+ - ARGUMENT_NO_FORWARDING_AMPERSAND
- ARGUMENT_NO_FORWARDING_ELLIPSES
- ARGUMENT_NO_FORWARDING_STAR
- ARGUMENT_NO_FORWARDING_STAR_STAR
diff --git a/prism/prism.c b/prism/prism.c
index d4926c25e4..4f55dad954 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -749,42 +749,97 @@ pm_parser_scope_find(pm_parser_t *parser, uint32_t depth) {
return scope;
}
-static void
-pm_parser_scope_forwarding_param_check(pm_parser_t *parser, const pm_token_t * token, const uint8_t mask, pm_diagnostic_id_t diag) {
+typedef enum {
+ PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
+ PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
+ PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
+} pm_scope_forwarding_param_check_result_t;
+
+static pm_scope_forwarding_param_check_result_t
+pm_parser_scope_forwarding_param_check(pm_parser_t *parser, const uint8_t mask) {
pm_scope_t *scope = parser->current_scope;
- while (scope) {
+ bool conflict = false;
+
+ while (scope != NULL) {
if (scope->parameters & mask) {
- if (!scope->closed) {
- pm_parser_err_token(parser, token, diag);
- return;
+ if (scope->closed) {
+ if (conflict) {
+ return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
+ } else {
+ return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
+ }
}
- return;
+
+ conflict = true;
}
+
if (scope->closed) break;
scope = scope->previous;
}
- pm_parser_err_token(parser, token, diag);
+ return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
}
-static inline void
+static void
pm_parser_scope_forwarding_block_check(pm_parser_t *parser, const pm_token_t * token) {
- pm_parser_scope_forwarding_param_check(parser, token, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK, PM_ERR_ARGUMENT_NO_FORWARDING_AMP);
+ switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
+ // Pass.
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
+ break;
+ }
}
-static inline void
+static void
pm_parser_scope_forwarding_positionals_check(pm_parser_t *parser, const pm_token_t * token) {
- pm_parser_scope_forwarding_param_check(parser, token, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
+ switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
+ // Pass.
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
+ break;
+ }
}
-static inline void
-pm_parser_scope_forwarding_all_check(pm_parser_t *parser, const pm_token_t * token) {
- pm_parser_scope_forwarding_param_check(parser, token, PM_SCOPE_PARAMETERS_FORWARDING_ALL, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
+static void
+pm_parser_scope_forwarding_all_check(pm_parser_t *parser, const pm_token_t *token) {
+ switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
+ // Pass.
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
+ // This shouldn't happen, because ... is not allowed in the
+ // declaration of blocks. If we get here, we assume we already have
+ // an error for this.
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
+ break;
+ }
}
-static inline void
+static void
pm_parser_scope_forwarding_keywords_check(pm_parser_t *parser, const pm_token_t * token) {
- pm_parser_scope_forwarding_param_check(parser, token, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
+ switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
+ // Pass.
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
+ break;
+ case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
+ pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
+ break;
+ }
}
/**
diff --git a/prism/templates/src/diagnostic.c.erb b/prism/templates/src/diagnostic.c.erb
index d9a1999645..ed3c61ec79 100644
--- a/prism/templates/src/diagnostic.c.erb
+++ b/prism/templates/src/diagnostic.c.erb
@@ -93,13 +93,16 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_MAX] = {
[PM_ERR_ARGUMENT_BARE_HASH] = { "unexpected bare hash argument", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_BLOCK_FORWARDING] = { "both a block argument and a forwarding argument; only one block is allowed", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_BLOCK_MULTI] = { "both block arg and actual block given; only one block is allowed", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_CONFLICT_AMPERSAND] = { "unexpected `&`; anonymous block parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_CONFLICT_STAR] = { "unexpected `*`; anonymous rest parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_CONFLICT_STAR_STAR] = { "unexpected `**`; anonymous keyword rest parameter is also used within block", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_FORMAL_CLASS] = { "invalid formal argument; formal argument cannot be a class variable", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_FORMAL_CONSTANT] = { "invalid formal argument; formal argument cannot be a constant", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_FORMAL_GLOBAL] = { "invalid formal argument; formal argument cannot be a global variable", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_FORMAL_IVAR] = { "invalid formal argument; formal argument cannot be an instance variable", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_FORWARDING_UNBOUND] = { "unexpected `...` in an non-parenthesized call", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_IN] = { "unexpected `in` keyword in arguments", PM_ERROR_LEVEL_SYNTAX },
- [PM_ERR_ARGUMENT_NO_FORWARDING_AMP] = { "unexpected `&`; no anonymous block parameter", PM_ERROR_LEVEL_SYNTAX },
+ [PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND] = { "unexpected `&`; no anonymous block parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES] = { "unexpected ... when the parent method is not forwarding", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_STAR] = { "unexpected `*`; no anonymous rest parameter", PM_ERROR_LEVEL_SYNTAX },
[PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR] = { "unexpected `**`; no anonymous keyword rest parameter", PM_ERROR_LEVEL_SYNTAX },