[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
This commit is contained in:
Kevin Newton 2024-02-21 14:11:50 -05:00
parent 0be09967fe
commit 90c5393f9f
6 changed files with 205 additions and 121 deletions

View File

@ -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

View File

@ -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 },

View File

@ -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,

View File

@ -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;
/** The IDs of the locals in the given scope. */
pm_constant_id_list_t locals;
/**
* 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;
/**
* 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:
*
* For example, some combinations of:
* def foo(*); end
* def foo(**); end
* def foo(&); end
* def foo(...); end
* - 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:
*
* - 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

View File

@ -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);
}
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);
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 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_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_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_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_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);

View File

@ -543,6 +543,10 @@ module Prism
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