aboutsummaryrefslogtreecommitdiffstats
path: root/prism
diff options
context:
space:
mode:
Diffstat (limited to 'prism')
-rw-r--r--prism/config.yml6
-rw-r--r--prism/diagnostic.c9
-rw-r--r--prism/diagnostic.h6
-rw-r--r--prism/parser.h66
-rw-r--r--prism/prism.c231
5 files changed, 199 insertions, 119 deletions
diff --git a/prism/config.yml b/prism/config.yml
index d5451f295e..15b7d4d0e9 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 fe6a12857a..09ecb69fac 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 50e434437d..22c0a04b9d 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 4efb253da2..86976fc5d2 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 ee3e3f0d5a..0bb8f2fcbf 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -4201,6 +4201,26 @@ pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node,
}
/**
+ * 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.
*/
static pm_keyword_hash_node_t *
@@ -4507,27 +4527,6 @@ pm_node_is_it(pm_parser_t *parser, pm_node_t *node) {
}
/**
- * 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);
}
/**
@@ -6380,14 +6372,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.
*/
static pm_constant_id_t
@@ -6426,6 +6410,50 @@ pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t leng
}
/**
+ * 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);
@@ -12531,6 +12557,40 @@ parse_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.
*/
static pm_block_node_t *
@@ -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);