diff options
author | Tim Peters <tim.peters@gmail.com> | 2001-06-26 03:36:28 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2001-06-26 03:36:28 (GMT) |
commit | b6c3ceae79f193e4361651fea61dfb2528bc2746 (patch) | |
tree | f2dbdff39cd430c8dee9c0b2eb15793e25bedaa6 | |
parent | 3e7b1a04a0fe02098ffc03b5c0fc6546a5f7d2d1 (diff) | |
download | cpython-b6c3ceae79f193e4361651fea61dfb2528bc2746.zip cpython-b6c3ceae79f193e4361651fea61dfb2528bc2746.tar.gz cpython-b6c3ceae79f193e4361651fea61dfb2528bc2746.tar.bz2 |
SF bug #436207: "if 0: yield x" is ignored.
Not anymore <wink>. Pure hack. Doesn't fix any other "if 0:" glitches.
-rw-r--r-- | Lib/test/test_generators.py | 135 | ||||
-rw-r--r-- | Python/compile.c | 34 |
2 files changed, 161 insertions, 8 deletions
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 884cbc0..3646001 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -431,6 +431,9 @@ in increasing order, where i,j,k >= 0. Trickier than it may look at first! Try writing it without generators, and correctly, and without generating 3 internal results for each result output. +XXX Suspect there's memory leaks in this one; definitely in the next +XXX version. + >>> def times(n, g): ... for i in g: ... yield n * i @@ -482,6 +485,8 @@ namespace renaming trick. The *pretty* part is that the times() and merge() functions can be reused as-is, because they only assume their stream arguments are iterable -- a LazyList is the same as a generator to times(). +XXX Massive memory leaks in this; see Python-Iterators. + >>> class LazyList: ... def __init__(self, g): ... self.sofar = [] @@ -514,7 +519,8 @@ arguments are iterable -- a LazyList is the same as a generator to times(). [400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675] """ -# syntax_tests mostly provokes SyntaxErrors. +# syntax_tests mostly provokes SyntaxErrors. Also fiddling with #if 0 +# hackery. syntax_tests = """ @@ -588,13 +594,128 @@ But this is fine: ... return >>> list(f()) [12, 666] + +>>> def f(): +... if 0: +... yield 1 +>>> type(f()) +<type 'generator'> + +>>> def f(): +... if "": +... yield None +>>> type(f()) +<type 'generator'> + +>>> def f(): +... return +... try: +... if x==4: +... pass +... elif 0: +... try: +... 1/0 +... except SyntaxError: +... pass +... else: +... if 0: +... while 12: +... x += 1 +... yield 2 # don't blink +... f(a, b, c, d, e) +... else: +... pass +... except: +... x = 1 +... return +>>> type(f()) +<type 'generator'> + +>>> def f(): +... if 0: +... def g(): +... yield 1 +... +>>> type(f()) +<type 'None'> + +>>> def f(): +... if 0: +... class C: +... def __init__(self): +... yield 1 +... def f(self): +... yield 2 +>>> type(f()) +<type 'None'> +""" + + +x_tests = """ + +>>> def firstn(g, n): +... return [g.next() for i in range(n)] + +>>> def times(n, g): +... for i in g: +... yield n * i + +>>> def merge(g, h): +... ng = g.next() +... nh = h.next() +... while 1: +... if ng < nh: +... yield ng +... ng = g.next() +... elif ng > nh: +... yield nh +... nh = h.next() +... else: +... yield ng +... ng = g.next() +... nh = h.next() + +>>> class LazyList: +... def __init__(self, g): +... self.sofar = [] +... self.fetch = g.next +... +... def __getitem__(self, i): +... sofar, fetch = self.sofar, self.fetch +... while i >= len(sofar): +... sofar.append(fetch()) +... return sofar[i] + +>>> def m235(): +... yield 1 +... # Gack: m235 below actually refers to a LazyList. +... me_times2 = times(2, m235) +... me_times3 = times(3, m235) +... me_times5 = times(5, m235) +... for i in merge(merge(me_times2, +... me_times3), +... me_times5): +... yield i + +>>> m235 = LazyList(m235()) +>>> for i in range(5): +... x = [m235[j] for j in range(15*i, 15*(i+1))] + + +[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24] +[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80] +[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192] +[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384] +[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675] """ -__test__ = {"tut": tutorial_tests, - "pep": pep_tests, - "email": email_tests, - "fun": fun_tests, - "syntax": syntax_tests} +__test__ = {"tut": tutorial_tests, # clean + "pep": pep_tests, # clean + "email": email_tests, # clean + "fun": fun_tests, # leaks + "syntax": syntax_tests # clean + #"x": x_tests +} # Magic test name that regrtest.py invokes *after* importing this module. # This worms around a bootstrap problem. @@ -605,7 +726,7 @@ def test_main(): if 0: # Temporary block to help track down leaks. So far, the blame # has fallen mostly on doctest. - for i in range(1000): + for i in range(5000): doctest.master = None doctest.testmod(test_generators) else: diff --git a/Python/compile.c b/Python/compile.c index 2ce7487..e82c34c 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4840,6 +4840,34 @@ symtable_add_def_o(struct symtable *st, PyObject *dict, #define symtable_add_use(ST, NAME) symtable_add_def((ST), (NAME), USE) +/* Look for a yield stmt under n. Return 1 if found, else 0. */ +static int +look_for_yield(node *n) +{ + int i; + + for (i = 0; i < NCH(n); ++i) { + node *kid = CHILD(n, i); + + switch (TYPE(kid)) { + + case classdef: + case funcdef: + /* Stuff in nested functions and classes can't make + the parent a generator. */ + return 0; + + case yield_stmt: + return 1; + + default: + if (look_for_yield(kid)) + return 1; + } + } + return 0; +} + static void symtable_node(struct symtable *st, node *n) { @@ -4883,8 +4911,12 @@ symtable_node(struct symtable *st, node *n) } case if_stmt: for (i = 0; i + 3 < NCH(n); i += 4) { - if (is_constant_false(NULL, (CHILD(n, i + 1)))) + if (is_constant_false(NULL, (CHILD(n, i + 1)))) { + if (st->st_cur->ste_generator == 0) + st->st_cur->ste_generator = + look_for_yield(CHILD(n, i+3)); continue; + } symtable_node(st, CHILD(n, i + 1)); symtable_node(st, CHILD(n, i + 3)); } |