[ruby/prism] Introduce transparent scopes.
A transparent scope is a scope that cannot have local variables added to it's local table. When a local is added to it's table, it instead gets added to the first non-transparent parent scope. This is used in for loops to ensure the correct depth for local variables inside the body https://github.com/ruby/prism/commit/ddb8e82253 Co-Authored-By: Kevin Newton <kddnewton@gmail.com>
This commit is contained in:
parent
723318f5d7
commit
7db4ce13ed
@ -293,6 +293,11 @@ typedef struct pm_scope {
|
||||
// This is necessary to determine if child blocks are allowed to use
|
||||
// numbered parameters.
|
||||
bool numbered_params;
|
||||
|
||||
// A transparent scope is a scope that cannot have locals set on itself.
|
||||
// When a local is set on this scope, it will instead be set on the parent
|
||||
// scope's local table.
|
||||
bool transparent;
|
||||
} pm_scope_t;
|
||||
|
||||
// This struct represents the overall parser. It contains a reference to the
|
||||
|
@ -4863,7 +4863,8 @@ pm_parser_scope_push(pm_parser_t *parser, bool closed) {
|
||||
.previous = parser->current_scope,
|
||||
.closed = closed,
|
||||
.explicit_params = false,
|
||||
.numbered_params = false
|
||||
.numbered_params = false,
|
||||
.transparent = false
|
||||
};
|
||||
|
||||
pm_constant_id_list_init(&scope->locals);
|
||||
@ -4872,6 +4873,25 @@ pm_parser_scope_push(pm_parser_t *parser, bool closed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allocate and initialize a new scope. Push it onto the scope stack.
|
||||
static bool
|
||||
pm_parser_scope_push_transparent(pm_parser_t *parser) {
|
||||
pm_scope_t *scope = (pm_scope_t *) malloc(sizeof(pm_scope_t));
|
||||
if (scope == NULL) return false;
|
||||
|
||||
*scope = (pm_scope_t) {
|
||||
.previous = parser->current_scope,
|
||||
.closed = false,
|
||||
.explicit_params = false,
|
||||
.numbered_params = false,
|
||||
.transparent = true
|
||||
};
|
||||
|
||||
parser->current_scope = scope;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the current scope has a given local variables.
|
||||
static int
|
||||
pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
|
||||
@ -4880,7 +4900,8 @@ pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
|
||||
int depth = 0;
|
||||
|
||||
while (scope != NULL) {
|
||||
if (pm_constant_id_list_includes(&scope->locals, constant_id)) return depth;
|
||||
if (!scope->transparent &&
|
||||
pm_constant_id_list_includes(&scope->locals, constant_id)) return depth;
|
||||
if (scope->closed) break;
|
||||
|
||||
scope = scope->previous;
|
||||
@ -4893,8 +4914,12 @@ pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
|
||||
// Add a constant id to the local table of the current scope.
|
||||
static inline void
|
||||
pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id) {
|
||||
if (!pm_constant_id_list_includes(&parser->current_scope->locals, constant_id)) {
|
||||
pm_constant_id_list_append(&parser->current_scope->locals, constant_id);
|
||||
pm_scope_t *scope = parser->current_scope;
|
||||
while (scope && scope->transparent) scope = scope->previous;
|
||||
|
||||
assert(scope != NULL);
|
||||
if (!pm_constant_id_list_includes(&scope->locals, constant_id)) {
|
||||
pm_constant_id_list_append(&scope->locals, constant_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12755,8 +12780,10 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power) {
|
||||
pm_statements_node_t *statements = NULL;
|
||||
|
||||
if (!accept1(parser, PM_TOKEN_KEYWORD_END)) {
|
||||
pm_parser_scope_push_transparent(parser);
|
||||
statements = parse_statements(parser, PM_CONTEXT_FOR);
|
||||
expect1(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM);
|
||||
pm_parser_scope_pop(parser);
|
||||
}
|
||||
|
||||
return (pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->previous);
|
||||
|
@ -23,7 +23,7 @@
|
||||
│ │ └── body: (length: 1)
|
||||
│ │ └── @ LocalVariableReadNode (location: (2,0)-(2,1))
|
||||
│ │ ├── name: :i
|
||||
│ │ └── depth: 0
|
||||
│ │ └── depth: 1
|
||||
│ ├── for_keyword_loc: (1,0)-(1,3) = "for"
|
||||
│ ├── in_keyword_loc: (1,6)-(1,8) = "in"
|
||||
│ ├── do_keyword_loc: ∅
|
||||
@ -48,7 +48,7 @@
|
||||
│ │ └── body: (length: 1)
|
||||
│ │ └── @ LocalVariableReadNode (location: (5,16)-(5,17))
|
||||
│ │ ├── name: :i
|
||||
│ │ └── depth: 0
|
||||
│ │ └── depth: 1
|
||||
│ ├── for_keyword_loc: (5,0)-(5,3) = "for"
|
||||
│ ├── in_keyword_loc: (5,6)-(5,8) = "in"
|
||||
│ ├── do_keyword_loc: ∅
|
||||
@ -80,7 +80,7 @@
|
||||
│ │ └── body: (length: 1)
|
||||
│ │ └── @ LocalVariableReadNode (location: (8,0)-(8,1))
|
||||
│ │ ├── name: :i
|
||||
│ │ └── depth: 0
|
||||
│ │ └── depth: 1
|
||||
│ ├── for_keyword_loc: (7,0)-(7,3) = "for"
|
||||
│ ├── in_keyword_loc: (7,8)-(7,10) = "in"
|
||||
│ ├── do_keyword_loc: ∅
|
||||
@ -115,7 +115,7 @@
|
||||
│ │ └── body: (length: 1)
|
||||
│ │ └── @ LocalVariableReadNode (location: (12,0)-(12,1))
|
||||
│ │ ├── name: :i
|
||||
│ │ └── depth: 0
|
||||
│ │ └── depth: 1
|
||||
│ ├── for_keyword_loc: (11,0)-(11,3) = "for"
|
||||
│ ├── in_keyword_loc: (11,10)-(11,12) = "in"
|
||||
│ ├── do_keyword_loc: ∅
|
||||
@ -140,7 +140,7 @@
|
||||
│ │ └── body: (length: 1)
|
||||
│ │ └── @ LocalVariableReadNode (location: (16,0)-(16,1))
|
||||
│ │ ├── name: :i
|
||||
│ │ └── depth: 0
|
||||
│ │ └── depth: 1
|
||||
│ ├── for_keyword_loc: (15,0)-(15,3) = "for"
|
||||
│ ├── in_keyword_loc: (15,6)-(15,8) = "in"
|
||||
│ ├── do_keyword_loc: (15,15)-(15,17) = "do"
|
||||
@ -165,7 +165,7 @@
|
||||
│ └── body: (length: 1)
|
||||
│ └── @ LocalVariableReadNode (location: (19,16)-(19,17))
|
||||
│ ├── name: :i
|
||||
│ └── depth: 0
|
||||
│ └── depth: 1
|
||||
├── for_keyword_loc: (19,0)-(19,3) = "for"
|
||||
├── in_keyword_loc: (19,6)-(19,8) = "in"
|
||||
├── do_keyword_loc: ∅
|
||||
|
@ -32,7 +32,7 @@
|
||||
│ │ │ └── arguments: (length: 1)
|
||||
│ │ │ └── @ LocalVariableReadNode (location: (1,18)-(1,19))
|
||||
│ │ │ ├── name: :a
|
||||
│ │ │ └── depth: 0
|
||||
│ │ │ └── depth: 1
|
||||
│ │ ├── closing_loc: ∅
|
||||
│ │ ├── block: ∅
|
||||
│ │ ├── flags: ∅
|
||||
@ -70,7 +70,7 @@
|
||||
│ │ └── arguments: (length: 1)
|
||||
│ │ └── @ LocalVariableReadNode (location: (3,16)-(3,17))
|
||||
│ │ ├── name: :a
|
||||
│ │ └── depth: 0
|
||||
│ │ └── depth: 1
|
||||
│ ├── closing_loc: ∅
|
||||
│ ├── block: ∅
|
||||
│ ├── flags: ∅
|
||||
|
@ -39,10 +39,10 @@
|
||||
│ │ └── arguments: (length: 2)
|
||||
│ │ ├── @ LocalVariableReadNode (location: (1,19)-(1,20))
|
||||
│ │ │ ├── name: :a
|
||||
│ │ │ └── depth: 0
|
||||
│ │ │ └── depth: 1
|
||||
│ │ └── @ LocalVariableReadNode (location: (1,22)-(1,23))
|
||||
│ │ ├── name: :b
|
||||
│ │ └── depth: 0
|
||||
│ │ └── depth: 1
|
||||
│ ├── closing_loc: ∅
|
||||
│ ├── block: ∅
|
||||
│ ├── flags: ∅
|
||||
|
Loading…
x
Reference in New Issue
Block a user