diff options
author | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-10-18 16:15:10 (GMT) |
---|---|---|
committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2001-10-18 16:15:10 (GMT) |
commit | 961dfe0d854ad28e3258d209210cc4053ebfb866 (patch) | |
tree | 6683af1d16a23ca2255acb7f0a23899a3b40cd73 /Python | |
parent | f76de62f7d48a25d5f67357ae7b2f487904a5fcc (diff) | |
download | cpython-961dfe0d854ad28e3258d209210cc4053ebfb866.zip cpython-961dfe0d854ad28e3258d209210cc4053ebfb866.tar.gz cpython-961dfe0d854ad28e3258d209210cc4053ebfb866.tar.bz2 |
Fix for SF bug [ #471928 ] global made w/nested list comprehensions
The symbol table pass didn't have an explicit case for the list_iter
node which is used only for a nested list comprehension. As a result,
the target of the list comprehension was treated as a use instead of
an assignment. Fix is to add a case to symtable_node() to handle
list_iter.
Also, rework and document a couple of the subtler implementation
issues in the symbol table pass. The symtable_node() switch statement
depends on falling through the last several cases, in order to handle
some of the more complicated nodes like atom. Add a comment
explaining the behavior before the first fall through case. Add a
comment /* fall through */ at the end of case so that it is explicitly
marked as such.
Move the for_stmt case out of the fall through logic, which simplifies
both for_stmt and default. (The default used the local variable start
to skip the first three nodes of a for_stmt when it fell through.)
Rename the flag argument to symtable_assign() to def_flag and add a
comment explaining its use:
The third argument to symatble_assign() is a flag to be passed to
symtable_add_def() if it is eventually called. The flag is useful
to specify the particular type of assignment that should be
recorded, e.g. an assignment caused by import.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/compile.c | 70 |
1 files changed, 51 insertions, 19 deletions
diff --git a/Python/compile.c b/Python/compile.c index 537aaac..f2cd59e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4991,7 +4991,7 @@ look_for_yield(node *n) static void symtable_node(struct symtable *st, node *n) { - int i, start = 0; + int i; loop: switch (TYPE(n)) { @@ -5105,36 +5105,62 @@ symtable_node(struct symtable *st, node *n) } } goto loop; - /* watchout for fall-through logic below */ + case list_iter: + n = CHILD(n, 0); + if (TYPE(n) == list_for) { + st->st_tmpname++; + symtable_list_comprehension(st, n); + st->st_tmpname--; + } else { + REQ(n, list_if); + symtable_node(st, CHILD(n, 1)); + if (NCH(n) == 3) { + n = CHILD(n, 2); + goto loop; + } + } + break; + case for_stmt: + symtable_assign(st, CHILD(n, 1), 0); + for (i = 3; i < NCH(n); ++i) + if (TYPE(CHILD(n, i)) >= single_input) + symtable_node(st, CHILD(n, i)); + break; + /* The remaining cases fall through to default except in + special circumstances. This requires the individual cases + to be coded with great care, even though they look like + rather innocuous. Each case must double-check TYPE(n). + */ case argument: - if (NCH(n) == 3) { + if (TYPE(n) == argument && NCH(n) == 3) { n = CHILD(n, 2); goto loop; } + /* fall through */ case listmaker: if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for) { st->st_tmpname++; symtable_list_comprehension(st, CHILD(n, 1)); symtable_node(st, CHILD(n, 0)); st->st_tmpname--; - return; + break; } + /* fall through */ case atom: if (TYPE(n) == atom && TYPE(CHILD(n, 0)) == NAME) { symtable_add_use(st, STR(CHILD(n, 0))); break; } - case for_stmt: - if (TYPE(n) == for_stmt) { - symtable_assign(st, CHILD(n, 1), 0); - start = 3; - } + /* fall through */ default: + /* Walk over every non-token child with a special case + for one child. + */ if (NCH(n) == 1) { n = CHILD(n, 0); goto loop; } - for (i = start; i < NCH(n); ++i) + for (i = 0; i < NCH(n); ++i) if (TYPE(CHILD(n, i)) >= single_input) symtable_node(st, CHILD(n, i)); } @@ -5370,8 +5396,14 @@ symtable_import(struct symtable *st, node *n) } } +/* The third argument to symatble_assign() is a flag to be passed to + symtable_add_def() if it is eventually called. The flag is useful + to specify the particular type of assignment that should be + recorded, e.g. an assignment caused by import. + */ + static void -symtable_assign(struct symtable *st, node *n, int flag) +symtable_assign(struct symtable *st, node *n, int def_flag) { node *tmp; int i; @@ -5403,7 +5435,7 @@ symtable_assign(struct symtable *st, node *n, int flag) return; } else { for (i = 0; i < NCH(n); i += 2) - symtable_assign(st, CHILD(n, i), flag); + symtable_assign(st, CHILD(n, i), def_flag); } return; case exprlist: @@ -5415,7 +5447,7 @@ symtable_assign(struct symtable *st, node *n, int flag) else { int i; for (i = 0; i < NCH(n); i += 2) - symtable_assign(st, CHILD(n, i), flag); + symtable_assign(st, CHILD(n, i), def_flag); return; } case atom: @@ -5426,24 +5458,24 @@ symtable_assign(struct symtable *st, node *n, int flag) } else if (TYPE(tmp) == NAME) { if (strcmp(STR(tmp), "__debug__") == 0) symtable_warn(st, ASSIGN_DEBUG); - symtable_add_def(st, STR(tmp), DEF_LOCAL | flag); + symtable_add_def(st, STR(tmp), DEF_LOCAL | def_flag); } return; case dotted_as_name: if (NCH(n) == 3) symtable_add_def(st, STR(CHILD(n, 2)), - DEF_LOCAL | flag); + DEF_LOCAL | def_flag); else symtable_add_def(st, STR(CHILD(CHILD(n, 0), 0)), - DEF_LOCAL | flag); + DEF_LOCAL | def_flag); return; case dotted_name: - symtable_add_def(st, STR(CHILD(n, 0)), DEF_LOCAL | flag); + symtable_add_def(st, STR(CHILD(n, 0)), DEF_LOCAL | def_flag); return; case NAME: - symtable_add_def(st, STR(n), DEF_LOCAL | flag); + symtable_add_def(st, STR(n), DEF_LOCAL | def_flag); return; default: if (NCH(n) == 0) @@ -5456,6 +5488,6 @@ symtable_assign(struct symtable *st, node *n, int flag) which will be caught in the next pass. */ for (i = 0; i < NCH(n); ++i) if (TYPE(CHILD(n, i)) >= single_input) - symtable_assign(st, CHILD(n, i), flag); + symtable_assign(st, CHILD(n, i), def_flag); } } |