From 90c5393f9f7086e59ba5461ba7153bbed925402f Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Wed, 21 Feb 2024 14:11:50 -0500 Subject: [PATCH] [ruby/prism] Support ItParametersNode So that compilers know they need to add to add an anonymous variable to the local table. https://github.com/ruby/prism/commit/7f1aadd057 --- prism/config.yml | 6 + prism/diagnostic.c | 9 +- prism/diagnostic.h | 6 +- prism/parser.h | 66 ++++++----- prism/prism.c | 231 ++++++++++++++++++++++-------------- test/prism/location_test.rb | 4 + 6 files changed, 203 insertions(+), 119 deletions(-) diff --git a/prism/config.yml b/prism/config.yml index d5451f295e135a..15b7d4d0e9fd0a 100644 --- a/prism/config.yml +++ b/prism/config.yml @@ -1948,6 +1948,12 @@ nodes: `foo #{bar} baz` ^^^^^^^^^^^^^^^^ + - name: ItParametersNode + comment: | + Represents an implicit set of parameters through the use of the `it` keyword within a block or lambda. + + -> { it + it } + ^^^^^^^^^^^^^^ - name: KeywordHashNode fields: - name: flags diff --git a/prism/diagnostic.c b/prism/diagnostic.c index fe6a12857a4874..09ecb69fac9b25 100644 --- a/prism/diagnostic.c +++ b/prism/diagnostic.c @@ -202,8 +202,14 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_INVALID_MULTIBYTE_CHARACTER] = { "invalid multibyte character 0x%X", PM_ERROR_LEVEL_FATAL }, [PM_ERR_INVALID_PRINTABLE_CHARACTER] = { "invalid character `%c`", PM_ERROR_LEVEL_FATAL }, [PM_ERR_INVALID_PERCENT] = { "invalid `%` token", PM_ERROR_LEVEL_FATAL }, // TODO WHAT? +<<<<<<< HEAD:prism/diagnostic.c [PM_ERR_INVALID_VARIABLE_GLOBAL] = { "'%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_FATAL }, [PM_ERR_IT_NOT_ALLOWED] = { "`it` is not allowed when an ordinary parameter is defined", PM_ERROR_LEVEL_FATAL }, +======= + [PM_ERR_INVALID_VARIABLE_GLOBAL] = { "`%.*s' is not allowed as a global variable name", PM_ERROR_LEVEL_FATAL }, + [PM_ERR_IT_NOT_ALLOWED_NUMBERED] = { "`it` is not allowed when an numbered parameter is defined", PM_ERROR_LEVEL_FATAL }, + [PM_ERR_IT_NOT_ALLOWED_ORDINARY] = { "`it` is not allowed when an ordinary parameter is defined", PM_ERROR_LEVEL_FATAL }, +>>>>>>> 7f1aadd057 (Support ItParametersNode):src/diagnostic.c [PM_ERR_LAMBDA_OPEN] = { "expected a `do` keyword or a `{` to open the lambda block", PM_ERROR_LEVEL_FATAL }, [PM_ERR_LAMBDA_TERM_BRACE] = { "expected a lambda block beginning with `{` to end with `}`", PM_ERROR_LEVEL_FATAL }, [PM_ERR_LAMBDA_TERM_END] = { "expected a lambda block beginning with `do` to end with `end`", PM_ERROR_LEVEL_FATAL }, @@ -225,7 +231,8 @@ static const pm_diagnostic_data_t diagnostic_messages[PM_DIAGNOSTIC_ID_LEN] = { [PM_ERR_NOT_EXPRESSION] = { "expected an expression after `not`", PM_ERROR_LEVEL_FATAL }, [PM_ERR_NO_LOCAL_VARIABLE] = { "%.*s: no such local variable", PM_ERROR_LEVEL_FATAL }, [PM_ERR_NUMBER_LITERAL_UNDERSCORE] = { "number literal ending with a `_`", PM_ERROR_LEVEL_FATAL }, - [PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED] = { "numbered parameters are not allowed when an ordinary parameter is defined", PM_ERROR_LEVEL_FATAL }, + [PM_ERR_NUMBERED_PARAMETER_IT] = { "numbered parameters are not allowed when an 'it' parameter is defined", PM_ERROR_LEVEL_FATAL }, + [PM_ERR_NUMBERED_PARAMETER_ORDINARY] = { "numbered parameters are not allowed when an ordinary parameter is defined", PM_ERROR_LEVEL_FATAL }, [PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE] = { "numbered parameter is already used in outer scope", PM_ERROR_LEVEL_FATAL }, [PM_ERR_OPERATOR_MULTI_ASSIGN] = { "unexpected operator for a multiple assignment", PM_ERROR_LEVEL_FATAL }, [PM_ERR_OPERATOR_WRITE_ARGUMENTS] = { "unexpected operator after a call with arguments", PM_ERROR_LEVEL_FATAL }, diff --git a/prism/diagnostic.h b/prism/diagnostic.h index 50e434437d0c62..22c0a04b9d4e85 100644 --- a/prism/diagnostic.h +++ b/prism/diagnostic.h @@ -201,7 +201,8 @@ typedef enum { PM_ERR_INVALID_PRINTABLE_CHARACTER, PM_ERR_INVALID_PERCENT, PM_ERR_INVALID_VARIABLE_GLOBAL, - PM_ERR_IT_NOT_ALLOWED, + PM_ERR_IT_NOT_ALLOWED_NUMBERED, + PM_ERR_IT_NOT_ALLOWED_ORDINARY, PM_ERR_LAMBDA_OPEN, PM_ERR_LAMBDA_TERM_BRACE, PM_ERR_LAMBDA_TERM_END, @@ -223,7 +224,8 @@ typedef enum { PM_ERR_NOT_EXPRESSION, PM_ERR_NO_LOCAL_VARIABLE, PM_ERR_NUMBER_LITERAL_UNDERSCORE, - PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED, + PM_ERR_NUMBERED_PARAMETER_IT, + PM_ERR_NUMBERED_PARAMETER_ORDINARY, PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE, PM_ERR_OPERATOR_MULTI_ASSIGN, PM_ERR_OPERATOR_WRITE_ARGUMENTS, diff --git a/prism/parser.h b/prism/parser.h index 4efb253da2593d..86976fc5d2d321 100644 --- a/prism/parser.h +++ b/prism/parser.h @@ -450,37 +450,31 @@ typedef struct { * into their parent scopes, while others cannot. */ typedef struct pm_scope { - /** The IDs of the locals in the given scope. */ - pm_constant_id_list_t locals; - /** A pointer to the previous scope in the linked list. */ struct pm_scope *previous; - /** - * A boolean indicating whether or not this scope can see into its parent. - * If closed is true, then the scope cannot see into its parent. - */ - bool closed; - - /** - * A boolean indicating whether or not this scope has explicit parameters. - * This is necessary to determine whether or not numbered parameters are - * allowed. - */ - bool explicit_params; + /** The IDs of the locals in the given scope. */ + pm_constant_id_list_t locals; /** - * Booleans indicating whether the parameters for this scope have declared - * forwarding parameters. + * This is a bitfield that indicates the parameters that are being used in + * this scope. It is a combination of the PM_SCOPE_PARAMS_* constants. There + * are three different kinds of parameters that can be used in a scope: + * + * - Ordinary parameters (e.g., def foo(bar); end) + * - Numbered parameters (e.g., def foo; _1; end) + * - The it parameter (e.g., def foo; it; end) + * + * If ordinary parameters are being used, then certain parameters can be + * forwarded to another method/structure. Those are indicated by four + * additional bits in the params field. For example, some combinations of: * - * For example, some combinations of: - * def foo(*); end - * def foo(**); end - * def foo(&); end - * def foo(...); end + * - def foo(*); end + * - def foo(**); end + * - def foo(&); end + * - def foo(...); end */ - - uint8_t forwarding_params; + uint8_t parameters; /** * An integer indicating the number of numbered parameters on this scope. @@ -489,13 +483,27 @@ typedef struct pm_scope { * about how many numbered parameters exist. */ int8_t numbered_parameters; + + /** + * A boolean indicating whether or not this scope can see into its parent. + * If closed is true, then the scope cannot see into its parent. + */ + bool closed; } pm_scope_t; -static const uint8_t PM_FORWARDING_POSITIONALS = 0x1; -static const uint8_t PM_FORWARDING_KEYWORDS = 0x2; -static const uint8_t PM_FORWARDING_BLOCK = 0x4; -static const uint8_t PM_FORWARDING_ALL = 0x8; -static const int8_t PM_NUMBERED_PARAMETERS_DISALLOWED = -1; +static const uint8_t PM_SCOPE_PARAMETERS_NONE = 0x0; +static const uint8_t PM_SCOPE_PARAMETERS_ORDINARY = 0x1; +static const uint8_t PM_SCOPE_PARAMETERS_NUMBERED = 0x2; +static const uint8_t PM_SCOPE_PARAMETERS_IT = 0x4; +static const uint8_t PM_SCOPE_PARAMETERS_TYPE_MASK = 0x7; + +static const uint8_t PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS = 0x8; +static const uint8_t PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS = 0x10; +static const uint8_t PM_SCOPE_PARAMETERS_FORWARDING_BLOCK = 0x20; +static const uint8_t PM_SCOPE_PARAMETERS_FORWARDING_ALL = 0x40; + +static const int8_t PM_SCOPE_NUMBERED_PARAMETERS_DISALLOWED = -1; +static const int8_t PM_SCOPE_NUMBERED_PARAMETERS_NONE = 0; /** * This struct represents the overall parser. It contains a reference to the diff --git a/prism/prism.c b/prism/prism.c index ee3e3f0d5a432e..0bb8f2fcbf3ff7 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -4200,6 +4200,26 @@ pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, node->base.location.end = closing->end; } +/** + * Allocate and initialize a new ItParametersNode node. + */ +static pm_it_parameters_node_t * +pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) { + pm_it_parameters_node_t *node = PM_ALLOC_NODE(parser, pm_it_parameters_node_t); + + *node = (pm_it_parameters_node_t) { + { + .type = PM_IT_PARAMETERS_NODE, + .location = { + .start = opening->start, + .end = closing->end + } + } + }; + + return node; +} + /** * Allocate a new KeywordHashNode node. */ @@ -4506,27 +4526,6 @@ pm_node_is_it(pm_parser_t *parser, pm_node_t *node) { return pm_token_is_it(constant->start, constant->start + constant->length); } -/** - * Convert a `it` variable call node to a node for `it` default parameter. - */ -static pm_node_t * -pm_node_check_it(pm_parser_t *parser, pm_node_t *node) { - if ( - (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3_0) && - !parser->current_scope->closed && - pm_node_is_it(parser, node) - ) { - if (parser->current_scope->explicit_params) { - pm_parser_err_previous(parser, PM_ERR_IT_NOT_ALLOWED); - } else { - pm_node_destroy(parser, node); - pm_constant_id_t name_id = pm_parser_constant_id_constant(parser, "0it", 3); - node = (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0); - } - } - return node; -} - /** * Returns true if the given bounds comprise a numbered parameter (i.e., they * are of the form /^_\d$/). @@ -6257,24 +6256,21 @@ pm_parser_scope_push(pm_parser_t *parser, bool closed) { *scope = (pm_scope_t) { .previous = parser->current_scope, - .closed = closed, - .explicit_params = false, - .numbered_parameters = 0, - .forwarding_params = 0, + .locals = { 0 }, + .parameters = PM_SCOPE_PARAMETERS_NONE, + .numbered_parameters = PM_SCOPE_NUMBERED_PARAMETERS_NONE, + .closed = closed }; - pm_constant_id_list_init(&scope->locals); parser->current_scope = scope; - return true; } 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) -{ +pm_parser_scope_forwarding_param_check(pm_parser_t *parser, const pm_token_t * token, const uint8_t mask, pm_diagnostic_id_t diag) { pm_scope_t *scope = parser->current_scope; while (scope) { - if (scope->forwarding_params & mask) { + if (scope->parameters & mask) { if (!scope->closed) { pm_parser_err_token(parser, token, diag); return; @@ -6289,27 +6285,23 @@ pm_parser_scope_forwarding_param_check(pm_parser_t *parser, const pm_token_t * t } static inline 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_FORWARDING_BLOCK, PM_ERR_ARGUMENT_NO_FORWARDING_AMP); +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); } -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_FORWARDING_POSITIONALS, PM_ERR_ARGUMENT_NO_FORWARDING_STAR); +static inline 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); } 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_FORWARDING_ALL, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES); +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 inline 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_FORWARDING_KEYWORDS, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); +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_EXPECT_EXPRESSION_AFTER_SPLAT_HASH); } /** @@ -6379,14 +6371,6 @@ pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id) { } } -/** - * Set the numbered_parameters value of the current scope. - */ -static inline void -pm_parser_numbered_parameters_set(pm_parser_t *parser, int8_t numbered_parameters) { - parser->current_scope->numbered_parameters = numbered_parameters; -} - /** * Add a local variable from a location to the current scope. */ @@ -6425,6 +6409,50 @@ pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t leng return constant_id; } +/** + * Create a local variable read that is reading the implicit 'it' variable. + */ +static pm_local_variable_read_node_t * +pm_local_variable_read_node_create_it(pm_parser_t *parser, const pm_token_t *name) { + if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_ORDINARY) { + pm_parser_err_token(parser, name, PM_ERR_IT_NOT_ALLOWED_ORDINARY); + return NULL; + } + + if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED) { + pm_parser_err_token(parser, name, PM_ERR_IT_NOT_ALLOWED_NUMBERED); + return NULL; + } + + parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_IT; + + pm_constant_id_t name_id = pm_parser_constant_id_constant(parser, "0it", 3); + pm_parser_local_add(parser, name_id); + + return pm_local_variable_read_node_create_constant_id(parser, name, name_id, 0); +} + +/** + * Convert a `it` variable call node to a node for `it` default parameter. + */ +static pm_node_t * +pm_node_check_it(pm_parser_t *parser, pm_node_t *node) { + if ( + (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3_0) && + !parser->current_scope->closed && + pm_node_is_it(parser, node) + ) { + pm_local_variable_read_node_t *read = pm_local_variable_read_node_create_it(parser, &parser->previous); + + if (read != NULL) { + pm_node_destroy(parser, node); + node = (pm_node_t *) read; + } + } + + return node; +} + /** * Add a parameter name to the current scope and check whether the name of the * parameter is unique or not. @@ -12044,7 +12072,7 @@ parse_parameters( pm_parser_local_add_token(parser, &name); } else { name = not_provided(parser); - parser->current_scope->forwarding_params |= PM_FORWARDING_BLOCK; + parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK; } pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, &name, &operator); @@ -12069,8 +12097,8 @@ parse_parameters( update_parameter_state(parser, &parser->current, &order); parser_lex(parser); - parser->current_scope->forwarding_params |= PM_FORWARDING_BLOCK; - parser->current_scope->forwarding_params |= PM_FORWARDING_ALL; + parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK; + parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL; pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->previous); if (params->keyword_rest != NULL) { @@ -12251,8 +12279,7 @@ parse_parameters( pm_parser_local_add_token(parser, &name); } else { name = not_provided(parser); - - parser->current_scope->forwarding_params |= PM_FORWARDING_POSITIONALS; + parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS; } pm_node_t *param = (pm_node_t *) pm_rest_parameter_node_create(parser, &operator, &name); @@ -12288,8 +12315,7 @@ parse_parameters( pm_parser_local_add_token(parser, &name); } else { name = not_provided(parser); - - parser->current_scope->forwarding_params |= PM_FORWARDING_KEYWORDS; + parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS; } param = (pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &operator, &name); @@ -12530,6 +12556,40 @@ parse_block_parameters( return block_parameters; } +/** + * Return the node that should be used in the parameters field of a block-like + * (block or lambda) node, depending on the kind of parameters that were + * declared in the current scope. + */ +static pm_node_t * +parse_blocklike_parameters(pm_parser_t *parser, pm_node_t *parameters, const pm_token_t *opening, const pm_token_t *closing) { + uint8_t masked = parser->current_scope->parameters & PM_SCOPE_PARAMETERS_TYPE_MASK; + + if (masked == PM_SCOPE_PARAMETERS_NONE) { + assert(parameters == NULL); + return NULL; + } else if (masked == PM_SCOPE_PARAMETERS_ORDINARY) { + assert(parameters != NULL); + return parameters; + } else if (masked == PM_SCOPE_PARAMETERS_NUMBERED) { + assert(parameters == NULL); + + int8_t maximum = parser->current_scope->numbered_parameters; + if (maximum > 0) { + const pm_location_t location = { .start = opening->start, .end = closing->end }; + return (pm_node_t *) pm_numbered_parameters_node_create(parser, &location, (uint8_t) maximum); + } + + return NULL; + } else if (masked == PM_SCOPE_PARAMETERS_IT) { + assert(parameters == NULL); + return (pm_node_t *) pm_it_parameters_node_create(parser, opening, closing); + } else { + assert(false && "unreachable"); + return NULL; + } +} + /** * Parse a block. */ @@ -12545,9 +12605,10 @@ parse_block(pm_parser_t *parser) { pm_block_parameters_node_t *block_parameters = NULL; if (accept1(parser, PM_TOKEN_PIPE)) { - parser->current_scope->explicit_params = true; - pm_token_t block_parameters_opening = parser->previous; + assert(parser->current_scope->parameters == PM_SCOPE_PARAMETERS_NONE); + parser->current_scope->parameters = PM_SCOPE_PARAMETERS_ORDINARY; + pm_token_t block_parameters_opening = parser->previous; if (match1(parser, PM_TOKEN_PIPE)) { block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening); parser->command_start = true; @@ -12588,14 +12649,9 @@ parse_block(pm_parser_t *parser) { expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END); } - pm_node_t *parameters = (pm_node_t *) block_parameters; - int8_t maximum = parser->current_scope->numbered_parameters; - - if (parameters == NULL && (maximum > 0)) { - parameters = (pm_node_t *) pm_numbered_parameters_node_create(parser, &(pm_location_t) { .start = opening.start, .end = parser->previous.end }, (uint8_t) maximum); - } - pm_constant_id_list_t locals = parser->current_scope->locals; + pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &opening, &parser->previous); + pm_parser_scope_pop(parser); pm_accepts_block_stack_pop(parser); pm_parser_current_param_name_restore(parser, saved_param_name); @@ -13317,13 +13373,15 @@ parse_variable(pm_parser_t *parser) { } pm_scope_t *current_scope = parser->current_scope; - if (!current_scope->closed && current_scope->numbered_parameters != PM_NUMBERED_PARAMETERS_DISALLOWED && pm_token_is_numbered_parameter(parser->previous.start, parser->previous.end)) { + if (!current_scope->closed && current_scope->numbered_parameters != PM_SCOPE_NUMBERED_PARAMETERS_DISALLOWED && pm_token_is_numbered_parameter(parser->previous.start, parser->previous.end)) { // Now that we know we have a numbered parameter, we need to check // if it's allowed in this context. If it is, then we will create a // local variable read. If it's not, then we'll create a normal call // node but add an error. - if (current_scope->explicit_params) { - pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED); + if (current_scope->parameters & PM_SCOPE_PARAMETERS_ORDINARY) { + pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_ORDINARY); + } else if (current_scope->parameters & PM_SCOPE_PARAMETERS_IT) { + pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_IT); } else if (outer_scope_using_numbered_parameters_p(parser)) { pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE); } else { @@ -13332,9 +13390,10 @@ parse_variable(pm_parser_t *parser) { // the actual integer value of the number (only _1 through _9 are // valid). int8_t numbered_parameters = (int8_t) (parser->previous.start[1] - '0'); + current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED; + if (numbered_parameters > current_scope->numbered_parameters) { current_scope->numbered_parameters = numbered_parameters; - pm_parser_numbered_parameters_set(parser, numbered_parameters); } // When you use a numbered parameter, it implies the existence @@ -13342,8 +13401,8 @@ parse_variable(pm_parser_t *parser) { // referencing _2 means that _1 must exist. Therefore here we // loop through all of the possibilities and add them into the // constant pool. - for (int8_t numbered_parameter = 1; numbered_parameter <= numbered_parameters - 1; numbered_parameter++) { - pm_parser_local_add_constant(parser, pm_numbered_parameter_names[numbered_parameter - 1], 2); + for (int8_t numbered_param = 1; numbered_param <= numbered_parameters - 1; numbered_param++) { + pm_parser_local_add_constant(parser, pm_numbered_parameter_names[numbered_param - 1], 2); } // Finally we can create the local variable read node. @@ -13946,10 +14005,12 @@ parse_pattern_primitive(pm_parser_t *parser, pm_diagnostic_id_t diag_id) { case PM_TOKEN_IDENTIFIER: { parser_lex(parser); pm_node_t *variable = (pm_node_t *) parse_variable(parser); + if (variable == NULL) { if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3_0 && pm_token_is_it(parser->previous.start, parser->previous.end)) { - pm_constant_id_t name_id = pm_parser_constant_id_constant(parser, "0it", 3); - variable = (pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0); + pm_local_variable_read_node_t *read = pm_local_variable_read_node_create_it(parser, &parser->previous); + if (read == NULL) read = pm_local_variable_read_node_create(parser, &parser->previous, 0); + variable = (pm_node_t *) read; } else { PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->previous, PM_ERR_NO_LOCAL_VARIABLE); variable = (pm_node_t *) pm_local_variable_read_node_create(parser, &parser->previous, 0); @@ -16677,7 +16738,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b switch (parser->current.type) { case PM_TOKEN_PARENTHESIS_LEFT: { - parser->current_scope->explicit_params = true; + assert(parser->current_scope->parameters == PM_SCOPE_PARAMETERS_NONE); + parser->current_scope->parameters = PM_SCOPE_PARAMETERS_ORDINARY; + pm_token_t opening = parser->current; parser_lex(parser); @@ -16694,7 +16757,9 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b break; } case PM_CASE_PARAMETER: { - parser->current_scope->explicit_params = true; + assert(parser->current_scope->parameters == PM_SCOPE_PARAMETERS_NONE); + parser->current_scope->parameters = PM_SCOPE_PARAMETERS_ORDINARY; + pm_accepts_block_stack_push(parser, false); pm_token_t opening = not_provided(parser); block_parameters = parse_block_parameters(parser, false, &opening, true); @@ -16736,14 +16801,8 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END); } - pm_node_t *parameters = (pm_node_t *) block_parameters; - int8_t maximum = parser->current_scope->numbered_parameters; - - if (parameters == NULL && (maximum > 0)) { - parameters = (pm_node_t *) pm_numbered_parameters_node_create(parser, &(pm_location_t) { .start = operator.start, .end = parser->previous.end }, (uint8_t) maximum); - } - pm_constant_id_list_t locals = parser->current_scope->locals; + pm_node_t *parameters = parse_blocklike_parameters(parser, (pm_node_t *) block_parameters, &operator, &parser->previous); pm_parser_scope_pop(parser); pm_accepts_block_stack_pop(parser); @@ -16943,8 +17002,6 @@ parse_regular_expression_named_captures(pm_parser_t *parser, const pm_string_t * if (memory == NULL) abort(); memcpy(memory, source, length); - // This silences clang analyzer warning about leak of memory pointed by `memory`. - // NOLINTNEXTLINE(clang-analyzer-*) name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length); if (pm_token_is_numbered_parameter(source, source + length)) { @@ -18013,7 +18070,7 @@ pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm // Scopes given from the outside are not allowed to have numbered // parameters. - parser->current_scope->numbered_parameters = PM_NUMBERED_PARAMETERS_DISALLOWED; + parser->current_scope->numbered_parameters = PM_SCOPE_NUMBERED_PARAMETERS_DISALLOWED; for (size_t local_index = 0; local_index < scope->locals_count; local_index++) { const pm_string_t *local = pm_options_scope_local_get(scope, local_index); diff --git a/test/prism/location_test.rb b/test/prism/location_test.rb index f5b2ba6d219608..46ec7f4e3f1caf 100644 --- a/test/prism/location_test.rb +++ b/test/prism/location_test.rb @@ -543,6 +543,10 @@ def test_InterpolatedXStringNode assert_location(InterpolatedXStringNode, '`foo #{bar} baz`') end + def test_ItParametersNode + assert_location(ItParametersNode, "-> { it }", &:parameters) + end + def test_KeywordHashNode assert_location(KeywordHashNode, "foo(a, b: 1)", 7...11) { |node| node.arguments.arguments[1] } end