diff options
| author | Jemma Issroff <jemmaissroff@gmail.com> | 2023-11-28 15:42:33 -0500 |
|---|---|---|
| committer | git <svn-admin@ruby-lang.org> | 2023-11-28 21:08:46 +0000 |
| commit | 04cbcd37b1c18c4db4b9df8d80abb4efec11755c (patch) | |
| tree | cda45c96254e9720ac53101b74a962f4dace7c8a /prism | |
| parent | 6310522a9a33c19e963e56a8f87388d802525937 (diff) | |
[ruby/prism] Add numbered_parameters field to BlockNode and LambdaNode
We are aware at parse time how many numbered parameters we have
on a BlockNode or LambdaNode, but prior to this commit, did not
store that information anywhere in its own right.
The numbered parameters were stored as locals, but this does not
distinguish them from other locals that have been set, for example
in `a { b = 1; _1 }` there is nothing on the AST that distinguishes
b from _1.
Consumers such as the compiler need to know information about how
many numbered parameters exist to set up their own tables around
parameters. Since we have this information at parse time, we should
compute it here, instead of deferring the work later on.
https://github.com/ruby/prism/commit/bf4a1e124d
Diffstat (limited to 'prism')
| -rw-r--r-- | prism/config.yml | 4 | ||||
| -rw-r--r-- | prism/parser.h | 7 | ||||
| -rw-r--r-- | prism/prism.c | 54 |
3 files changed, 47 insertions, 18 deletions
diff --git a/prism/config.yml b/prism/config.yml index 84e458ed8c..353ad50c0d 100644 --- a/prism/config.yml +++ b/prism/config.yml @@ -596,6 +596,8 @@ nodes: type: location - name: closing_loc type: location + - name: numbered_parameters + type: uint32 comment: | Represents a block of ruby code. @@ -1758,6 +1760,8 @@ nodes: kind: BlockParametersNode - name: body type: node? + - name: numbered_parameters + type: uint32 comment: | Represents using a lambda literal (not the lambda method call). diff --git a/prism/parser.h b/prism/parser.h index 8c98892ee9..fec1036229 100644 --- a/prism/parser.h +++ b/prism/parser.h @@ -468,11 +468,12 @@ typedef struct pm_scope { bool explicit_params; /** - * A boolean indicating whether or not this scope has numbered parameters. + * An integer indicating the number of numbered parameters on this scope. * This is necessary to determine if child blocks are allowed to use - * numbered parameters. + * numbered parameters, and to pass information to consumers of the AST + * about how many numbered parameters exist. */ - bool numbered_params; + uint32_t numbered_parameters; /** * A transparent scope is a scope that cannot have locals set on itself. diff --git a/prism/prism.c b/prism/prism.c index 971949ca53..05ecc6ad60 100644 --- a/prism/prism.c +++ b/prism/prism.c @@ -1465,7 +1465,7 @@ pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, p * Allocate and initialize a new BlockNode node. */ static pm_block_node_t * -pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_block_parameters_node_t *parameters, pm_node_t *body, const pm_token_t *closing) { +pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_block_parameters_node_t *parameters, pm_node_t *body, const pm_token_t *closing, uint32_t numbered_parameters) { pm_block_node_t *node = PM_ALLOC_NODE(parser, pm_block_node_t); *node = (pm_block_node_t) { @@ -1476,6 +1476,7 @@ pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const p .locals = *locals, .parameters = parameters, .body = body, + .numbered_parameters = numbered_parameters, .opening_loc = PM_LOCATION_TOKEN_VALUE(opening), .closing_loc = PM_LOCATION_TOKEN_VALUE(closing) }; @@ -3937,7 +3938,8 @@ pm_lambda_node_create( const pm_token_t *opening, const pm_token_t *closing, pm_block_parameters_node_t *parameters, - pm_node_t *body + pm_node_t *body, + uint32_t numbered_parameters ) { pm_lambda_node_t *node = PM_ALLOC_NODE(parser, pm_lambda_node_t); @@ -3954,7 +3956,8 @@ pm_lambda_node_create( .opening_loc = PM_LOCATION_TOKEN_VALUE(opening), .closing_loc = PM_LOCATION_TOKEN_VALUE(closing), .parameters = parameters, - .body = body + .body = body, + .numbered_parameters = numbered_parameters }; return node; @@ -5746,7 +5749,7 @@ pm_parser_scope_push(pm_parser_t *parser, bool closed) { .previous = parser->current_scope, .closed = closed, .explicit_params = false, - .numbered_params = false, + .numbered_parameters = 0, .transparent = false }; @@ -5768,7 +5771,7 @@ pm_parser_scope_push_transparent(pm_parser_t *parser) { .previous = parser->current_scope, .closed = false, .explicit_params = false, - .numbered_params = false, + .numbered_parameters = 0, .transparent = true }; @@ -5822,6 +5825,18 @@ pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id) { } /** + * Add a constant id to the local table of the current scope. + */ +static inline void +pm_parser_numbered_parameters_set(pm_parser_t *parser, uint32_t numbered_parameters) { + pm_scope_t *scope = parser->current_scope; + while (scope && scope->transparent) scope = scope->previous; + + assert(scope != NULL); + scope->numbered_parameters = numbered_parameters; +} + +/** * Add a local variable from a location to the current scope. */ static pm_constant_id_t @@ -12052,9 +12067,10 @@ parse_block(pm_parser_t *parser) { } pm_constant_id_list_t locals = parser->current_scope->locals; + uint32_t numbered_parameters = parser->current_scope->numbered_parameters; pm_parser_scope_pop(parser); pm_accepts_block_stack_pop(parser); - return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous); + return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous, numbered_parameters); } /** @@ -12625,9 +12641,9 @@ parse_alias_argument(pm_parser_t *parser, bool first) { * numbered parameters. */ static bool -outer_scope_using_numbered_params_p(pm_parser_t *parser) { +outer_scope_using_numbered_parameters_p(pm_parser_t *parser) { for (pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) { - if (scope->numbered_params) return true; + if (scope->numbered_parameters) return true; } return false; @@ -12647,25 +12663,32 @@ parse_variable_call(pm_parser_t *parser) { } if (!parser->current_scope->closed && pm_token_is_numbered_parameter(parser->previous.start, parser->previous.end)) { - // Indicate that this scope is using numbered params so that child - // scopes cannot. - parser->current_scope->numbered_params = true; - // 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 (parser->current_scope->explicit_params) { pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_NOT_ALLOWED); - } else if (outer_scope_using_numbered_params_p(parser)) { + } else if (outer_scope_using_numbered_parameters_p(parser)) { pm_parser_err_previous(parser, PM_ERR_NUMBERED_PARAMETER_OUTER_SCOPE); } else { + // Indicate that this scope is using numbered params so that child + // scopes cannot. + uint8_t number = parser->previous.start[1]; + + // We subtract the value for the character '0' to get the actual + // integer value of the number (only _1 through _9 are valid) + uint32_t number_as_int = (uint32_t) (number - '0'); + if (number_as_int > parser->current_scope->numbered_parameters) { + parser->current_scope->numbered_parameters = number_as_int; + pm_parser_numbered_parameters_set(parser, number_as_int); + } + // When you use a numbered parameter, it implies the existence // of all of the locals that exist before it. For example, // referencing _2 means that _1 must exist. Therefore here we // loop through all of the possibilities and add them into the // constant pool. - uint8_t number = parser->previous.start[1]; uint8_t current = '1'; uint8_t *value; @@ -15856,9 +15879,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) { } pm_constant_id_list_t locals = parser->current_scope->locals; + uint32_t numbered_parameters = parser->current_scope->numbered_parameters; pm_parser_scope_pop(parser); pm_accepts_block_stack_pop(parser); - return (pm_node_t *) pm_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, params, body); + return (pm_node_t *) pm_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, params, body, numbered_parameters); } case PM_TOKEN_UPLUS: { parser_lex(parser); |
