diff options
| author | Kevin Newton <kddnewton@gmail.com> | 2025-11-29 15:25:35 -0500 |
|---|---|---|
| committer | git <svn-admin@ruby-lang.org> | 2025-11-30 02:08:52 +0000 |
| commit | c4b5fa419ee266c973be9b676caa2cfad0400d58 (patch) | |
| tree | b3072277ee21c7c8bf40257d96dd9f3eb86c6ae4 | |
| parent | b1314f159ec501f4fdc1c055293799b33c9ad134 (diff) | |
[ruby/prism] Ensure implicit parameter nodes are destroyed.
When we are about to destroy a node because of a syntax error, we
need to check if it is potentially containing an implicit
parameter in its subtree.
https://github.com/ruby/prism/commit/1531433e02
| -rw-r--r-- | prism/prism.c | 65 |
1 files changed, 37 insertions, 28 deletions
diff --git a/prism/prism.c b/prism/prism.c index 60d45cbcd2..8c886bb050 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -13454,28 +13454,43 @@ parse_unwriteable_target(pm_parser_t *parser, pm_node_t *target) { return (pm_node_t *) result; } +static bool +parse_target_implicit_parameter_each(const pm_node_t *node, void *data) { + switch (PM_NODE_TYPE(node)) { + case PM_LOCAL_VARIABLE_READ_NODE: + case PM_IT_LOCAL_VARIABLE_READ_NODE: { + pm_parser_t *parser = (pm_parser_t *) data; + pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters; + + for (size_t index = 0; index < implicit_parameters->size; index++) { + if (implicit_parameters->nodes[index] == node) { + // If the node is not the last one in the list, we need to + // shift the remaining nodes down to fill the gap. This is + // extremely unlikely to happen. + if (index != implicit_parameters->size - 1) { + memmove(&implicit_parameters->nodes[index], &implicit_parameters->nodes[index + 1], (implicit_parameters->size - index - 1) * sizeof(pm_node_t *)); + } + + implicit_parameters->size--; + break; + } + } + + return false; + } + default: + return true; + } +} + /** * When an implicit local variable is written to or targeted, it becomes a * regular, named local variable. This function removes it from the list of * implicit parameters when that happens. */ static void -parse_target_implicit_parameter(pm_parser_t *parser, pm_node_t *node) { - pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters; - - for (size_t index = 0; index < implicit_parameters->size; index++) { - if (implicit_parameters->nodes[index] == node) { - // If the node is not the last one in the list, we need to shift the - // remaining nodes down to fill the gap. This is extremely unlikely - // to happen. - if (index != implicit_parameters->size - 1) { - memmove(&implicit_parameters->nodes[index], &implicit_parameters->nodes[index + 1], (implicit_parameters->size - index - 1) * sizeof(pm_node_t *)); - } - - implicit_parameters->size--; - break; - } - } +parse_target_implicit_parameter(pm_parser_t *parser, const pm_node_t *node) { + pm_visit_node(node, parse_target_implicit_parameter_each, parser); } /** @@ -13851,18 +13866,12 @@ parse_write(pm_parser_t *parser, pm_node_t *target, pm_token_t *operator, pm_nod // syntax error. In this case we'll fall through to our default // handling. We need to free the value that we parsed because there // is no way for us to attach it to the tree at this point. - switch (PM_NODE_TYPE(value)) { - case PM_LOCAL_VARIABLE_READ_NODE: - case PM_IT_LOCAL_VARIABLE_READ_NODE: - // Since it is possible for the value to be an implicit - // parameter, we need to remove it from the list of implicit - // parameters. - parse_target_implicit_parameter(parser, value); - break; - default: - break; - } - + // + // Since it is possible for the value to contain an implicit + // parameter somewhere in its subtree, we need to walk it and remove + // any implicit parameters from the list of implicit parameters for + // the current scope. + parse_target_implicit_parameter(parser, value); pm_node_destroy(parser, value); } PRISM_FALLTHROUGH |
