aboutsummaryrefslogtreecommitdiffstats
path: root/prism
diff options
context:
space:
mode:
Diffstat (limited to 'prism')
-rw-r--r--prism/parser.h5
-rw-r--r--prism/prism.c35
2 files changed, 36 insertions, 4 deletions
diff --git a/prism/parser.h b/prism/parser.h
index 0a5ba80819..0553e29819 100644
--- a/prism/parser.h
+++ b/prism/parser.h
@@ -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
diff --git a/prism/prism.c b/prism/prism.c
index 303ee2e50e..be227e2198 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -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);