Skip to content

Commit 0d10517

Browse files
committed
py/scope: Factor common code to find locals and close over them.
Saves 50-100 bytes of code.
1 parent d549596 commit 0d10517

4 files changed

Lines changed: 35 additions & 39 deletions

File tree

py/compile.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,17 +1172,14 @@ STATIC void compile_global_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
11721172
STATIC void compile_declare_nonlocal(compiler_t *comp, mp_parse_node_t pn, qstr qst) {
11731173
bool added;
11741174
id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qst, &added);
1175-
if (!added && id_info->kind != ID_INFO_KIND_FREE) {
1175+
if (added) {
1176+
scope_find_local_and_close_over(comp->scope_cur, id_info, qst);
1177+
if (id_info->kind == ID_INFO_KIND_GLOBAL_IMPLICIT) {
1178+
compile_syntax_error(comp, pn, "no binding for nonlocal found");
1179+
}
1180+
} else if (id_info->kind != ID_INFO_KIND_FREE) {
11761181
compile_syntax_error(comp, pn, "identifier redefined as nonlocal");
1177-
return;
1178-
}
1179-
id_info_t *id_info2 = scope_find_local_in_parent(comp->scope_cur, qst);
1180-
if (id_info2 == NULL || !(id_info2->kind == ID_INFO_KIND_LOCAL || id_info2->kind == ID_INFO_KIND_CELL || id_info2->kind == ID_INFO_KIND_FREE)) {
1181-
compile_syntax_error(comp, pn, "no binding for nonlocal found");
1182-
return;
11831182
}
1184-
id_info->kind = ID_INFO_KIND_FREE;
1185-
scope_close_over_in_parents(comp->scope_cur, qst);
11861183
}
11871184

11881185
STATIC void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {

py/emitcommon.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,7 @@ void mp_emit_common_get_id_for_load(scope_t *scope, qstr qst) {
3535
bool added;
3636
id_info_t *id = scope_find_or_add_id(scope, qst, &added);
3737
if (added) {
38-
id_info_t *id2 = scope_find_local_in_parent(scope, qst);
39-
if (id2 != NULL && (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE)) {
40-
id->kind = ID_INFO_KIND_FREE;
41-
scope_close_over_in_parents(scope, qst);
42-
} else {
43-
id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
44-
}
38+
scope_find_local_and_close_over(scope, id, qst);
4539
}
4640
}
4741

py/scope.c

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -106,39 +106,45 @@ id_info_t *scope_find_global(scope_t *scope, qstr qst) {
106106
return scope_find(scope, qst);
107107
}
108108

109-
id_info_t *scope_find_local_in_parent(scope_t *scope, qstr qst) {
110-
if (scope->parent == NULL) {
111-
return NULL;
112-
}
113-
for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
114-
id_info_t *id = scope_find(s, qst);
115-
if (id != NULL) {
116-
return id;
117-
}
118-
}
119-
return NULL;
120-
}
121-
122-
void scope_close_over_in_parents(scope_t *scope, qstr qst) {
109+
STATIC void scope_close_over_in_parents(scope_t *scope, qstr qst) {
123110
assert(scope->parent != NULL); // we should have at least 1 parent
124-
for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
111+
for (scope_t *s = scope->parent;; s = s->parent) {
112+
assert(s->parent != NULL); // we should not get to the outer scope
125113
bool added;
126114
id_info_t *id = scope_find_or_add_id(s, qst, &added);
127115
if (added) {
128116
// variable not previously declared in this scope, so declare it as free and keep searching parents
129117
id->kind = ID_INFO_KIND_FREE;
130118
} else {
131119
// variable is declared in this scope, so finish
132-
switch (id->kind) {
133-
case ID_INFO_KIND_LOCAL: id->kind = ID_INFO_KIND_CELL; break; // variable local to this scope, close it over
134-
case ID_INFO_KIND_FREE: break; // variable already closed over in a parent scope
135-
case ID_INFO_KIND_CELL: break; // variable already closed over in this scope
136-
default: assert(0); // TODO
120+
if (id->kind == ID_INFO_KIND_LOCAL) {
121+
// variable local to this scope, close it over
122+
id->kind = ID_INFO_KIND_CELL;
123+
} else {
124+
// ID_INFO_KIND_FREE: variable already closed over in a parent scope
125+
// ID_INFO_KIND_CELL: variable already closed over in this scope
126+
assert(id->kind == ID_INFO_KIND_FREE || id->kind == ID_INFO_KIND_CELL);
137127
}
138128
return;
139129
}
140130
}
141-
assert(0); // we should have found the variable in one of the parents
131+
}
132+
133+
void scope_find_local_and_close_over(scope_t *scope, id_info_t *id, qstr qst) {
134+
if (scope->parent != NULL) {
135+
for (scope_t *s = scope->parent; s->parent != NULL; s = s->parent) {
136+
id_info_t *id2 = scope_find(s, qst);
137+
if (id2 != NULL) {
138+
if (id2->kind == ID_INFO_KIND_LOCAL || id2->kind == ID_INFO_KIND_CELL || id2->kind == ID_INFO_KIND_FREE) {
139+
id->kind = ID_INFO_KIND_FREE;
140+
scope_close_over_in_parents(scope, qst);
141+
return;
142+
}
143+
break;
144+
}
145+
}
146+
}
147+
id->kind = ID_INFO_KIND_GLOBAL_IMPLICIT;
142148
}
143149

144150
#endif // MICROPY_ENABLE_COMPILER

py/scope.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ void scope_free(scope_t *scope);
9292
id_info_t *scope_find_or_add_id(scope_t *scope, qstr qstr, bool *added);
9393
id_info_t *scope_find(scope_t *scope, qstr qstr);
9494
id_info_t *scope_find_global(scope_t *scope, qstr qstr);
95-
id_info_t *scope_find_local_in_parent(scope_t *scope, qstr qstr);
96-
void scope_close_over_in_parents(scope_t *scope, qstr qstr);
95+
void scope_find_local_and_close_over(scope_t *scope, id_info_t *id, qstr qst);
9796

9897
#endif // __MICROPY_INCLUDED_PY_SCOPE_H__

0 commit comments

Comments
 (0)