[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:
parent
0be09967fe
commit
90c5393f9f
@ -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
|
||||
|
@ -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 },
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
235
prism/prism.c
235
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user