]> granicus.if.org Git - python/commitdiff
PEP 342 implementation. Per Guido's comments, the generator throw()
authorPhillip J. Eby <pje@telecommunity.com>
Tue, 2 Aug 2005 00:46:46 +0000 (00:46 +0000)
committerPhillip J. Eby <pje@telecommunity.com>
Tue, 2 Aug 2005 00:46:46 +0000 (00:46 +0000)
method still needs to support string exceptions, and allow None for the
third argument.  Documentation updates are needed, too.

16 files changed:
Grammar/Grammar
Include/ceval.h
Include/graminit.h
Include/pyerrors.h
Lib/compiler/transformer.py
Lib/symbol.py
Lib/test/test_generators.py
Lib/test/test_genexps.py
Lib/test/test_parser.py
Modules/gcmodule.c
Modules/parsermodule.c
Objects/genobject.c
Python/ceval.c
Python/compile.c
Python/exceptions.c
Python/graminit.c

index 7b6acf7313221044427bd070a7b301f9d2643c52..01e4afd6fc7c679407e559751cb7cac1afa4a9c0 100644 (file)
@@ -39,7 +39,7 @@ fplist: fpdef (',' fpdef)* [',']
 stmt: simple_stmt | compound_stmt
 simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
 small_stmt: expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt
-expr_stmt: testlist (augassign testlist | ('=' testlist)*)
+expr_stmt: testlist (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist))*)
 augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='
 # For normal assignments, additional restrictions enforced by the interpreter
 print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] )
@@ -49,7 +49,7 @@ flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
 break_stmt: 'break'
 continue_stmt: 'continue'
 return_stmt: 'return' [testlist]
-yield_stmt: 'yield' testlist
+yield_stmt: yield_expr
 raise_stmt: 'raise' [test [',' test [',' test]]]
 import_stmt: import_name | import_from
 import_name: 'import' dotted_as_names
@@ -86,7 +86,7 @@ arith_expr: term (('+'|'-') term)*
 term: factor (('*'|'/'|'%'|'//') factor)*
 factor: ('+'|'-'|'~') factor | power
 power: atom trailer* ['**' factor]
-atom: '(' [testlist_gexp] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+
+atom: '(' [yield_expr|testlist_gexp] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+
 listmaker: test ( list_for | (',' test)* [','] )
 testlist_gexp: test ( gen_for | (',' test)* [','] )
 lambdef: 'lambda' [varargslist] ':' test
@@ -116,3 +116,6 @@ testlist1: test (',' test)*
 
 # not used in grammar, but may appear in "node" passed from Parser to Compiler
 encoding_decl: NAME
+
+yield_expr: 'yield' [testlist]
+
index d9320e02c18f6bfc3d88a04a401354b2a4bf8a8d..9481506b8e5ed2030381bd50ab6752b8c146ace6 100644 (file)
@@ -65,6 +65,7 @@ PyAPI_FUNC(char *) PyEval_GetFuncDesc(PyObject *);
 
 PyAPI_FUNC(PyObject *) PyEval_GetCallStats(PyObject *);
 PyAPI_FUNC(PyObject *) PyEval_EvalFrame(struct _frame *);
+PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(struct _frame *f, int exc);
 
 /* this used to be handled on a per-thread basis - now just two globals */
 PyAPI_DATA(volatile int) _Py_Ticker;
index a46cdc9e06c6654991964f95ae0fb7c21b84efd4..2c855ea72a759e3e8f20210bae86fe1fa79fd62c 100644 (file)
@@ -76,3 +76,4 @@
 #define gen_if 331
 #define testlist1 332
 #define encoding_decl 333
+#define yield_expr 334
index f433cc0d1d683958725e85c4e2b7d950bdd299c8..f18e5790026992aaafa73efcd2d1a67fb2af8c55 100644 (file)
@@ -25,6 +25,7 @@ PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**);
 
 PyAPI_DATA(PyObject *) PyExc_Exception;
 PyAPI_DATA(PyObject *) PyExc_StopIteration;
+PyAPI_DATA(PyObject *) PyExc_GeneratorExit;
 PyAPI_DATA(PyObject *) PyExc_StandardError;
 PyAPI_DATA(PyObject *) PyExc_ArithmeticError;
 PyAPI_DATA(PyObject *) PyExc_LookupError;
index 5844bb504d396d9fb761c8b21e60defd1592c0e3..47592807f2b1b6cbed82e74ec2e97e45b8a163b2 100644 (file)
@@ -403,7 +403,15 @@ class Transformer:
         return Return(self.com_node(nodelist[1]), lineno=nodelist[0][2])
 
     def yield_stmt(self, nodelist):
-        return Yield(self.com_node(nodelist[1]), lineno=nodelist[0][2])
+        expr = self.com_node(nodelist[0])
+        return Discard(expr, lineno=expr.lineno)
+
+    def yield_expr(self, nodelist):
+        if len(nodelist)>1:
+            value = nodelist[1]
+        else:
+            value = Const(None)
+        return Yield(self.com_node(value), lineno=nodelist[0][2])
 
     def raise_stmt(self, nodelist):
         # raise: [test [',' test [',' test]]]
@@ -1402,6 +1410,8 @@ _legal_node_types = [
 
 if hasattr(symbol, 'yield_stmt'):
     _legal_node_types.append(symbol.yield_stmt)
+if hasattr(symbol, 'yield_expr'):
+    _legal_node_types.append(symbol.yield_expr)
 
 _assign_types = [
     symbol.test,
index eaf5a2581d34466367205f672cf4a43ecda01239..8219008ac39d44a50033b4f15f792ccfd9d3068c 100755 (executable)
@@ -88,6 +88,7 @@ gen_for = 330
 gen_if = 331
 testlist1 = 332
 encoding_decl = 333
+yield_expr = 334
 #--end constants--
 
 sym_name = {}
index 109af733474282a5a93eaa097e1845f886bed83b..97cdd2abb20e2e359b97f251085aad4bba7abd78 100644 (file)
@@ -382,7 +382,7 @@ From the Iterators list, about the types of these things.
 >>> type(i)
 <type 'generator'>
 >>> [s for s in dir(i) if not s.startswith('_')]
-['gi_frame', 'gi_running', 'next']
+['close', 'gi_frame', 'gi_running', 'next', 'send', 'throw']
 >>> print i.next.__doc__
 x.next() -> the next value, or raise StopIteration
 >>> iter(i) is i
@@ -421,6 +421,7 @@ Subject: Re: PEP 255: Simple Generators
 ...         self.name = name
 ...         self.parent = None
 ...         self.generator = self.generate()
+...         self.close = self.generator.close
 ...
 ...     def generate(self):
 ...         while not self.parent:
@@ -482,6 +483,9 @@ merged F into A
 A->A B->G C->A D->G E->G F->A G->G H->G I->A J->G K->A L->A M->G
 merged A into G
 A->G B->G C->G D->G E->G F->G G->G H->G I->G J->G K->G L->G M->G
+
+>>> for s in sets: s.close()   # break cycles
+
 """
 # Emacs turd '
 
@@ -589,6 +593,7 @@ arguments are iterable -- a LazyList is the same as a generator to times().
 ...     def __init__(self, g):
 ...         self.sofar = []
 ...         self.fetch = g.next
+...         self.close = g.close
 ...
 ...     def __getitem__(self, i):
 ...         sofar, fetch = self.sofar, self.fetch
@@ -619,6 +624,7 @@ efficient.
 [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]
 
+>>> m235.close()
 
 Ye olde Fibonacci generator, LazyList style.
 
@@ -642,6 +648,7 @@ Ye olde Fibonacci generator, LazyList style.
 >>> fib = LazyList(fibgen(1, 2))
 >>> firstn(iter(fib), 17)
 [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584]
+>>> fib.close()
 """
 
 # syntax_tests mostly provokes SyntaxErrors.  Also fiddling with #if 0
@@ -672,7 +679,7 @@ Traceback (most recent call last):
   ..
 SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[2]>, line 3)
 
-This one is fine:
+These are fine:
 
 >>> def f():
 ...     yield 1
@@ -683,9 +690,6 @@ This one is fine:
 ...         yield 1
 ...     finally:
 ...         pass
-Traceback (most recent call last):
-  ..
-SyntaxError: 'yield' not allowed in a 'try' block with a 'finally' clause (<doctest test.test_generators.__test__.syntax[4]>, line 3)
 
 >>> def f():
 ...     try:
@@ -697,11 +701,6 @@ SyntaxError: 'yield' not allowed in a 'try' block with a 'finally' clause (<doct
 ...             pass
 ...     finally:
 ...         pass
-Traceback (most recent call last):
-  ...
-SyntaxError: 'yield' not allowed in a 'try' block with a 'finally' clause (<doctest test.test_generators.__test__.syntax[5]>, line 6)
-
-But this is fine:
 
 >>> def f():
 ...     try:
@@ -722,14 +721,16 @@ But this is fine:
 
 >>> def f():
 ...    yield
-Traceback (most recent call last):
-SyntaxError: invalid syntax
+>>> type(f())
+<type 'generator'>
+
 
 >>> def f():
 ...    if 0:
 ...        yield
-Traceback (most recent call last):
-SyntaxError: invalid syntax
+>>> type(f())
+<type 'generator'>
+
 
 >>> def f():
 ...     if 0:
@@ -805,7 +806,7 @@ SyntaxError: invalid syntax
 ...     if 0:
 ...         yield 2             # because it's a generator
 Traceback (most recent call last):
-SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[22]>, line 8)
+SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[24]>, line 8)
 
 This one caused a crash (see SF bug 567538):
 
@@ -1383,6 +1384,250 @@ True
 
 """
 
+coroutine_tests = """\
+Sending a value into a started generator:
+
+>>> def f():
+...     print (yield 1)
+...     yield 2
+>>> g = f()
+>>> g.next()
+1
+>>> g.send(42)
+42
+2
+
+Sending a value into a new generator produces a TypeError:
+
+>>> f().send("foo")
+Traceback (most recent call last):
+...
+TypeError: can't send non-None value to a just-started generator
+
+
+Yield by itself yields None:
+
+>>> def f(): yield
+>>> list(f())
+[None]
+
+
+
+An obscene abuse of a yield expression within a generator expression:
+
+>>> list((yield 21) for i in range(4))
+[21, None, 21, None, 21, None, 21, None]
+
+And a more sane, but still weird usage:
+
+>>> def f(): list(i for i in [(yield 26)])
+>>> type(f())
+<type 'generator'>
+
+
+Check some syntax errors for yield expressions:
+
+>>> f=lambda: (yield 1),(yield 2)
+Traceback (most recent call last):
+  ...
+SyntaxError: 'yield' outside function (<doctest test.test_generators.__test__.coroutine[10]>, line 1)
+
+>>> def f(): return lambda x=(yield): 1
+Traceback (most recent call last):
+  ...
+SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.coroutine[11]>, line 1)
+
+>>> def f(): x = yield = y
+Traceback (most recent call last):
+  ...
+SyntaxError: assignment to yield expression not possible (<doctest test.test_generators.__test__.coroutine[12]>, line 1)
+
+
+Now check some throw() conditions:
+
+>>> def f():
+...     while True:
+...         try:
+...             print (yield)
+...         except ValueError,v:
+...             print "caught ValueError (%s)" % (v),
+>>> import sys
+>>> g = f()
+>>> g.next()
+
+>>> g.throw(ValueError) # type only
+caught ValueError ()
+
+>>> g.throw(ValueError("xyz"))  # value only
+caught ValueError (xyz)
+
+>>> g.throw(ValueError, ValueError(1))   # value+matching type
+caught ValueError (1)
+
+>>> g.throw(ValueError, TypeError(1))  # mismatched type, rewrapped
+caught ValueError (1)
+
+>>> g.throw(ValueError(1), "foo")      # bad args
+Traceback (most recent call last):
+  ...
+TypeError: instance exception may not have a separate value
+
+>>> g.throw(ValueError, "foo", 23)     # bad args
+Traceback (most recent call last):
+  ...
+TypeError: throw() third argument must be a traceback object
+
+>>> def throw(g,exc):
+...     try:
+...         raise exc
+...     except:
+...         g.throw(*sys.exc_info())
+>>> throw(g,ValueError)        # do it with traceback included
+caught ValueError ()
+
+>>> g.send(1)
+1
+
+>>> throw(g,TypeError) # terminate the generator
+Traceback (most recent call last):
+  ...
+TypeError
+
+>>> print g.gi_frame
+None
+
+>>> g.send(2)
+Traceback (most recent call last):
+  ...
+StopIteration
+
+>>> g.throw(ValueError,6)      # throw on closed generator
+Traceback (most recent call last):
+  ...
+ValueError: 6
+
+>>> f().throw(ValueError,7)    # throw on just-opened generator
+Traceback (most recent call last):
+  ...
+ValueError: 7
+
+
+Now let's try closing a generator:
+
+>>> def f():
+...     try: yield
+...     except GeneratorExit:
+...         print "exiting"
+
+>>> g = f()
+>>> g.next()
+>>> g.close()
+exiting
+>>> g.close()  # should be no-op now
+
+>>> f().close()  # close on just-opened generator should be fine
+
+>>> def f(): yield     # an even simpler generator
+>>> f().close()                # close before opening
+>>> g = f()
+>>> g.next()
+>>> g.close()          # close normally
+
+And finalization:
+
+>>> def f():
+...     try: yield
+...     finally:
+...         print "exiting"
+
+>>> g = f()
+>>> g.next()
+>>> del g
+exiting
+
+
+Now let's try some ill-behaved generators:
+
+>>> def f():
+...     try: yield
+...     except GeneratorExit:
+...         yield "foo!"
+>>> g = f()
+>>> g.next()
+>>> g.close()
+Traceback (most recent call last):
+  ...
+RuntimeError: generator ignored GeneratorExit
+>>> g.close()
+
+
+Our ill-behaved code should be invoked during GC:
+
+>>> import sys, StringIO
+>>> old, sys.stderr = sys.stderr, StringIO.StringIO()
+>>> g = f()
+>>> g.next()
+>>> del g
+>>> sys.stderr.getvalue().startswith(
+...     "Exception exceptions.RuntimeError: 'generator ignored GeneratorExit' in "
+... )
+True
+>>> sys.stderr = old
+
+
+And errors thrown during closing should propagate:
+
+>>> def f():
+...     try: yield
+...     except GeneratorExit:
+...         raise TypeError("fie!")
+>>> g = f()
+>>> g.next()
+>>> g.close()
+Traceback (most recent call last):
+  ...
+TypeError: fie!
+
+
+Ensure that various yield expression constructs make their
+enclosing function a generator:
+
+>>> def f(): x += yield
+>>> type(f())
+<type 'generator'>
+
+>>> def f(): x = yield
+>>> type(f())
+<type 'generator'>
+
+>>> def f(): lambda x=(yield): 1
+>>> type(f())
+<type 'generator'>
+
+>>> def f(): x=(i for i in (yield) if (yield))
+>>> type(f())
+<type 'generator'>
+
+>>> def f(d): d[(yield "a")] = d[(yield "b")] = 27
+>>> data = [1,2]
+>>> g = f(data)
+>>> type(g)
+<type 'generator'>
+>>> g.send(None)
+'a'
+>>> data
+[1, 2]
+>>> g.send(0)
+'b'
+>>> data
+[27, 2]
+>>> try: g.send(1)
+... except StopIteration: pass
+>>> data
+[27, 27]
+
+"""
+
 __test__ = {"tut":      tutorial_tests,
             "pep":      pep_tests,
             "email":    email_tests,
@@ -1390,6 +1635,7 @@ __test__ = {"tut":      tutorial_tests,
             "syntax":   syntax_tests,
             "conjoin":  conjoin_tests,
             "weakref":  weakref_tests,
+            "coroutine":  coroutine_tests,
             }
 
 # Magic test name that regrtest.py invokes *after* importing this module.
index 04694f8e2e7ac6907c39569d8f1d89e529740fbf..7c6fe4a2e4f53178a839a844fa9b162168c9b480 100644 (file)
@@ -130,7 +130,7 @@ Verify that syntax error's are raised for genexps used as lvalues
     >>> (y for y in (1,2)) += 10
     Traceback (most recent call last):
        ...
-    SyntaxError: augmented assign to tuple literal or generator expression not possible
+    SyntaxError: augmented assign to tuple literal, yield, or generator expression not possible
 
 
 
index 205c4065d8c04a20ad7898dc66fa737aa02cd0b7..d1ace674dcb49170c09deb7bea5a79d091f6bdbc 100644 (file)
@@ -29,11 +29,22 @@ class RoundtripLegalSyntaxTestCase(unittest.TestCase):
 
     def test_yield_statement(self):
         self.check_suite("def f(): yield 1")
+        self.check_suite("def f(): yield")
+        self.check_suite("def f(): x += yield")
+        self.check_suite("def f(): x = yield 1")
+        self.check_suite("def f(): x = y = yield 1")
+        self.check_suite("def f(): x = yield")
+        self.check_suite("def f(): x = y = yield")
+        self.check_suite("def f(): 1 + (yield)*2")
+        self.check_suite("def f(): (yield 1)*2")
         self.check_suite("def f(): return; yield 1")
         self.check_suite("def f(): yield 1; return")
         self.check_suite("def f():\n"
                          "    for x in range(30):\n"
                          "        yield x\n")
+        self.check_suite("def f():\n"
+                         "    if (yield):\n"
+                         "        yield x\n")
 
     def test_expressions(self):
         self.check_expr("foo(1)")
index 38494ead3fd53847834da4f7ae895babe5be2104..db9dd3268c9a5ca23f104a149557d9722049e163 100644 (file)
@@ -413,10 +413,8 @@ has_finalizer(PyObject *op)
                assert(delstr != NULL);
                return _PyInstance_Lookup(op, delstr) != NULL;
        }
-       else if (PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE))
+       else 
                return op->ob_type->tp_del != NULL;
-       else
-               return 0;
 }
 
 /* Move the objects in unreachable with __del__ methods into `finalizers`.
index 63b2cd784f42617f021542031d32e98e7fd61467..12226a41a975480617eedb4638f212d75607b8aa 100644 (file)
@@ -859,7 +859,8 @@ VALIDATER(arglist);             VALIDATER(argument);
 VALIDATER(listmaker);           VALIDATER(yield_stmt);
 VALIDATER(testlist1);           VALIDATER(gen_for);
 VALIDATER(gen_iter);            VALIDATER(gen_if);
-VALIDATER(testlist_gexp);
+VALIDATER(testlist_gexp);      VALIDATER(yield_expr);
+VALIDATER(yield_or_testlist);  
 
 #undef VALIDATER
 
@@ -1506,6 +1507,15 @@ validate_compound_stmt(node *tree)
 }
 
 
+static int
+validate_yield_or_testlist(node *tree)
+{
+       if (TYPE(tree) == yield_expr) 
+               return validate_yield_expr(tree);
+       else
+               return validate_testlist(tree);
+}
+
 static int
 validate_expr_stmt(node *tree)
 {
@@ -1517,8 +1527,8 @@ validate_expr_stmt(node *tree)
 
     if (res && nch == 3
         && TYPE(CHILD(tree, 1)) == augassign) {
-        res = (validate_numnodes(CHILD(tree, 1), 1, "augassign")
-               && validate_testlist(CHILD(tree, 2)));
+        res = validate_numnodes(CHILD(tree, 1), 1, "augassign")
+               && validate_yield_or_testlist(CHILD(tree, 2));
 
         if (res) {
             char *s = STR(CHILD(CHILD(tree, 1), 0));
@@ -1541,8 +1551,8 @@ validate_expr_stmt(node *tree)
     }
     else {
         for (j = 1; res && (j < nch); j += 2)
-            res = (validate_equal(CHILD(tree, j))
-                   && validate_testlist(CHILD(tree, j + 1)));
+            res = validate_equal(CHILD(tree, j))
+                   && validate_yield_or_testlist(CHILD(tree, j + 1));
     }
     return (res);
 }
@@ -1649,15 +1659,31 @@ validate_raise_stmt(node *tree)
 }
 
 
-/* yield_stmt: 'yield' testlist
+/* yield_expr: 'yield' [testlist]
+ */
+static int
+validate_yield_expr(node *tree)
+{
+    int nch = NCH(tree);
+    int res = (validate_ntype(tree, yield_expr)
+               && ((nch == 1) || (nch == 2))
+               && validate_name(CHILD(tree, 0), "yield"));
+
+    if (res && (nch == 2))
+        res = validate_testlist(CHILD(tree, 1));
+
+    return (res);
+}
+
+
+/* yield_stmt: yield_expr
  */
 static int
 validate_yield_stmt(node *tree)
 {
     return (validate_ntype(tree, yield_stmt)
-            && validate_numnodes(tree, 2, "yield_stmt")
-            && validate_name(CHILD(tree, 0), "yield")
-            && validate_testlist(CHILD(tree, 1)));
+            && validate_numnodes(tree, 1, "yield_stmt")
+            && validate_yield_expr(CHILD(tree, 0)));
 }
 
 
@@ -2300,8 +2326,12 @@ validate_atom(node *tree)
             res = ((nch <= 3)
                    && (validate_rparen(CHILD(tree, nch - 1))));
 
-            if (res && (nch == 3))
-                res = validate_testlist_gexp(CHILD(tree, 1));
+            if (res && (nch == 3)) {
+               if (TYPE(CHILD(tree, 1))==yield_expr)
+                       res = validate_yield_expr(CHILD(tree, 1));
+               else
+                       res = validate_testlist_gexp(CHILD(tree, 1));
+           }
             break;
           case LSQB:
             if (nch == 2)
@@ -2914,6 +2944,9 @@ validate_node(node *tree)
           case testlist:
             res = validate_testlist(tree);
             break;
+          case yield_expr:
+            res = validate_yield_expr(tree);
+            break;
           case testlist1:
             res = validate_testlist1(tree);
             break;
index 174c697137349d6a2e8c42e26c8ca7eb25f807c1..d281274b0fe477d2f4e88faa8c4589c44ad1321d 100644 (file)
@@ -15,15 +15,31 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
 static void
 gen_dealloc(PyGenObject *gen)
 {
+       PyObject *self = (PyObject *) gen;
+
        _PyObject_GC_UNTRACK(gen);
+
        if (gen->gi_weakreflist != NULL)
                PyObject_ClearWeakRefs((PyObject *) gen);
-       Py_DECREF(gen->gi_frame);
+
+
+       _PyObject_GC_TRACK(self);
+
+       if (gen->gi_frame->f_stacktop!=NULL) {
+               /* Generator is paused, so we need to close */
+               gen->ob_type->tp_del(self);
+               if (self->ob_refcnt > 0)
+                       return;         /* resurrected.  :( */
+       }
+
+       _PyObject_GC_UNTRACK(self);
+       Py_XDECREF(gen->gi_frame);
        PyObject_GC_Del(gen);
 }
 
+
 static PyObject *
-gen_iternext(PyGenObject *gen)
+gen_send_ex(PyGenObject *gen, PyObject *arg, int exc)
 {
        PyThreadState *tstate = PyThreadState_GET();
        PyFrameObject *f = gen->gi_frame;
@@ -34,8 +50,24 @@ gen_iternext(PyGenObject *gen)
                                "generator already executing");
                return NULL;
        }
-       if (f->f_stacktop == NULL)
+       if ((PyObject *)f == Py_None || f->f_stacktop == NULL) {
+               /* Only set exception if called from send() */
+               if (arg && !exc) PyErr_SetNone(PyExc_StopIteration);
                return NULL;
+       }
+
+       if (f->f_lasti == -1) {
+               if (arg && arg != Py_None) {
+                       PyErr_SetString(PyExc_TypeError,
+                               "can't send non-None value to a just-started generator");
+                       return NULL;
+               }
+       } else {
+               /* Push arg onto the frame's value stack */
+               result = arg ? arg : Py_None;
+               Py_INCREF(result);
+               *(f->f_stacktop++) = result;
+       }
 
        /* Generators always return to their most recent caller, not
         * necessarily their creator. */
@@ -44,7 +76,7 @@ gen_iternext(PyGenObject *gen)
        f->f_back = tstate->frame;
 
        gen->gi_running = 1;
-       result = PyEval_EvalFrame(f);
+       result = PyEval_EvalFrameEx(f, exc);
        gen->gi_running = 0;
 
        /* Don't keep the reference to f_back any longer than necessary.  It
@@ -58,17 +90,199 @@ gen_iternext(PyGenObject *gen)
        if (result == Py_None && f->f_stacktop == NULL) {
                Py_DECREF(result);
                result = NULL;
+               /* Set exception if not called by gen_iternext() */
+               if (arg) PyErr_SetNone(PyExc_StopIteration);
+       }
+
+       if (!result || f->f_stacktop == NULL) {
+               /* generator can't be rerun, so release the frame */
+               Py_DECREF(f);
+               gen->gi_frame = (PyFrameObject *)Py_None;
+               Py_INCREF(Py_None);
        }
 
        return result;
 }
 
+PyDoc_STRVAR(send_doc,
+"send(arg) -> send 'arg' into generator, return next yielded value or raise StopIteration.");
+
+static PyObject *
+gen_send(PyGenObject *gen, PyObject *arg)
+{
+       return gen_send_ex(gen, arg, 0);
+}
+
+PyDoc_STRVAR(close_doc,
+"close(arg) -> raise GeneratorExit inside generator.");
+
+static PyObject *
+gen_close(PyGenObject *gen, PyObject *args)
+{
+       PyObject *retval;
+       PyErr_SetNone(PyExc_GeneratorExit);
+       retval = gen_send_ex(gen, Py_None, 1);
+       if (retval) {
+               Py_DECREF(retval);
+               PyErr_SetString(PyExc_RuntimeError,
+                       "generator ignored GeneratorExit");
+               return NULL;
+       }
+       if ( PyErr_ExceptionMatches(PyExc_StopIteration) 
+            || PyErr_ExceptionMatches(PyExc_GeneratorExit) ) 
+       {
+               PyErr_Clear();  /* ignore these errors */
+               Py_INCREF(Py_None);
+               return Py_None;
+       }
+       return NULL;
+}
+
+static void
+gen_del(PyObject *self)
+{
+        PyObject *res;
+        PyObject *error_type, *error_value, *error_traceback;
+       PyGenObject *gen = (PyGenObject *)self;
+
+       if ((PyObject *)gen->gi_frame == Py_None || gen->gi_frame->f_stacktop==NULL)
+               /* Generator isn't paused, so no need to close */
+               return;
+
+        /* Temporarily resurrect the object. */
+        assert(self->ob_refcnt == 0);
+        self->ob_refcnt = 1;
+
+        /* Save the current exception, if any. */
+        PyErr_Fetch(&error_type, &error_value, &error_traceback);
+
+       res = gen_close((PyGenObject *)self, NULL);
+
+       if (res == NULL)
+               PyErr_WriteUnraisable((PyObject *)self);
+       else
+               Py_DECREF(res);
+
+        /* Restore the saved exception. */
+        PyErr_Restore(error_type, error_value, error_traceback);
+
+        /* Undo the temporary resurrection; can't use DECREF here, it would
+         * cause a recursive call.
+         */
+        assert(self->ob_refcnt > 0);
+        if (--self->ob_refcnt == 0)
+                return; /* this is the normal path out */
+
+        /* close() resurrected it!  Make it look like the original Py_DECREF
+         * never happened.
+         */
+        {
+                int refcnt = self->ob_refcnt;
+                _Py_NewReference(self);
+                self->ob_refcnt = refcnt;
+        }
+        assert(!PyType_IS_GC(self->ob_type) ||
+               _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED);
+
+        /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
+         * we need to undo that. */
+        _Py_DEC_REFTOTAL;
+        /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
+         * chain, so no more to do there.
+         * If COUNT_ALLOCS, the original decref bumped tp_frees, and
+         * _Py_NewReference bumped tp_allocs:  both of those need to be
+         * undone.
+         */
+#ifdef COUNT_ALLOCS
+        --self->ob_type->tp_frees;
+        --self->ob_type->tp_allocs;
+#endif
+}
+
+
+
+PyDoc_STRVAR(throw_doc,
+"throw(typ[,val[,tb]]) -> raise exception in generator, return next yielded value or raise StopIteration.");
+
+static PyObject *
+gen_throw(PyGenObject *gen, PyObject *args) 
+{
+       PyObject *typ;
+       PyObject *tb = NULL;
+       PyObject *val = NULL;
+
+       if (!PyArg_ParseTuple(args, "O|OO:throw", &typ, &val, &tb))
+               return NULL;
+
+       if (tb && !PyTraceBack_Check(tb)) {
+               PyErr_SetString(PyExc_TypeError,
+                       "throw() third argument must be a traceback object");
+               return NULL;
+       }
+
+       Py_INCREF(typ);
+       Py_XINCREF(val);
+       Py_XINCREF(tb);
+
+       if (PyClass_Check(typ)) {
+               PyErr_NormalizeException(&typ, &val, &tb);
+       }
+
+       else if (PyInstance_Check(typ)) {
+               /* Raising an instance.  The value should be a dummy. */
+               if (val && val != Py_None) {
+                       PyErr_SetString(PyExc_TypeError,
+                         "instance exception may not have a separate value");
+                       goto failed_throw;
+               }
+               else {
+                       /* Normalize to raise <class>, <instance> */
+                       val = typ;
+                       typ = (PyObject*) ((PyInstanceObject*)typ)->in_class;
+                       Py_INCREF(typ);
+               }
+       }
+       else {
+               /* Not something you can raise.  You get an exception
+                  anyway, just not what you specified :-) */
+               PyErr_Format(PyExc_TypeError,
+                            "exceptions must be classes, or instances, not %s",
+                            typ->ob_type->tp_name);
+                       goto failed_throw;
+       }
+
+       PyErr_Restore(typ,val,tb);
+       return gen_send_ex(gen, Py_None, 1);
+
+failed_throw:
+       /* Didn't use our arguments, so restore their original refcounts */
+       Py_DECREF(typ);
+       Py_XDECREF(val);
+       Py_XDECREF(tb);
+       return NULL;
+}
+
+
+static PyObject *
+gen_iternext(PyGenObject *gen)
+{
+       return gen_send_ex(gen, NULL, 0);
+}
+
+
 static PyMemberDef gen_memberlist[] = {
        {"gi_frame",    T_OBJECT, offsetof(PyGenObject, gi_frame),      RO},
        {"gi_running",  T_INT,    offsetof(PyGenObject, gi_running),    RO},
        {NULL}  /* Sentinel */
 };
 
+static PyMethodDef gen_methods[] = {
+       {"send",(PyCFunction)gen_send, METH_O, send_doc},
+       {"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc},
+       {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc},
+       {NULL, NULL}    /* Sentinel */
+};
+
 PyTypeObject PyGen_Type = {
        PyObject_HEAD_INIT(&PyType_Type)
        0,                                      /* ob_size */
@@ -99,11 +313,26 @@ PyTypeObject PyGen_Type = {
        offsetof(PyGenObject, gi_weakreflist),  /* tp_weaklistoffset */
        PyObject_SelfIter,                      /* tp_iter */
        (iternextfunc)gen_iternext,             /* tp_iternext */
-       0,                                      /* tp_methods */
+       gen_methods,                            /* tp_methods */
        gen_memberlist,                         /* tp_members */
        0,                                      /* tp_getset */
        0,                                      /* tp_base */
        0,                                      /* tp_dict */
+        
+       0,                                      /* tp_descr_get */
+       0,                                      /* tp_descr_set */
+       0,                                      /* tp_dictoffset */
+       0,                                      /* tp_init */
+       0,                                      /* tp_alloc */
+       0,                                      /* tp_new */
+       0,                                      /* tp_free */
+       0,                                      /* tp_is_gc */
+       0,                                      /* tp_bases */
+       0,                                      /* tp_mro */
+       0,                                      /* tp_cache */
+       0,                                      /* tp_subclasses */
+       0,                                      /* tp_weaklist */
+       gen_del,                                /* tp_del */
 };
 
 PyObject *
index 1103dfc736532215315c92ee72e39e3c4f8624fa..d311537c8ea2165a4a09514184ce51157b6bed18 100644 (file)
@@ -499,7 +499,14 @@ PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
 /* Interpreter main loop */
 
 PyObject *
-PyEval_EvalFrame(PyFrameObject *f)
+PyEval_EvalFrame(PyFrameObject *f) {
+       /* This is for backward compatibility with extension modules that
+           used this API; core interpreter code should call PyEval_EvalFrameEx() */
+       return PyEval_EvalFrameEx(f, 0);
+}
+
+PyObject *
+PyEval_EvalFrameEx(PyFrameObject *f, int throw)
 {
 #ifdef DXPAIRS
        int lastopcode = 0;
@@ -747,6 +754,11 @@ PyEval_EvalFrame(PyFrameObject *f)
        x = Py_None;    /* Not a reference, just anything non-NULL */
        w = NULL;
 
+       if (throw) { /* support for generator.throw() */
+               why = WHY_EXCEPTION;
+               goto on_error;
+       }
+               
        for (;;) {
 #ifdef WITH_TSC
                if (inst1 == 0) {
@@ -2733,7 +2745,7 @@ PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals,
                return PyGen_New(f);
        }
 
-        retval = PyEval_EvalFrame(f);
+        retval = PyEval_EvalFrameEx(f,0);
 
   fail: /* Jump here from prelude on failure */
 
@@ -3636,7 +3648,7 @@ fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
                        Py_INCREF(*stack);
                        fastlocals[i] = *stack++;
                }
-               retval = PyEval_EvalFrame(f);
+               retval = PyEval_EvalFrameEx(f,0);
                assert(tstate != NULL);
                ++tstate->recursion_depth;
                Py_DECREF(f);
index 476dbe6e5669851e4ba6d246046c0a80b6e74836..56b3a3e5927b4952942c03ea42489c06f279de73 100644 (file)
@@ -2145,6 +2145,7 @@ com_gen_for(struct compiling *c, node *n, node *t, int is_outmost)
        else {
                com_test(c, t);
                com_addbyte(c, YIELD_VALUE);
+               com_addbyte(c, POP_TOP);
                com_pop(c, 1);
        }
 
@@ -2193,6 +2194,7 @@ com_gen_if(struct compiling *c, node *n, node *t)
        else {
                com_test(c, t);
                com_addbyte(c, YIELD_VALUE);
+               com_addbyte(c, POP_TOP);
                com_pop(c, 1);
        }
        com_addfwref(c, JUMP_FORWARD, &anchor);
@@ -2354,6 +2356,10 @@ com_dictmaker(struct compiling *c, node *n)
        }
 }
 
+
+/* forward reference */
+static void com_yield_expr(struct compiling *c, node *n);
+
 static void
 com_atom(struct compiling *c, node *n)
 {
@@ -2369,7 +2375,10 @@ com_atom(struct compiling *c, node *n)
                        com_push(c, 1);
                }
                else
-                       com_testlist_gexp(c, CHILD(n, 1));
+                       if (TYPE(CHILD(n, 1)) == yield_expr)
+                               com_yield_expr(c, CHILD(n, 1));
+                       else
+                               com_testlist_gexp(c, CHILD(n, 1));
                break;
        case LSQB: /* '[' [listmaker] ']' */
                if (TYPE(CHILD(n, 1)) == RSQB) {
@@ -3436,7 +3445,11 @@ com_assign(struct compiling *c, node *n, int assigning, node *augn)
                        }
                        n = CHILD(n, 0);
                        break;
-               
+               case yield_expr:
+                       com_error(c, PyExc_SyntaxError,
+                         "assignment to yield expression not possible");
+                       return;
+                                       
                case test:
                case and_test:
                case not_test:
@@ -3493,7 +3506,7 @@ com_assign(struct compiling *c, node *n, int assigning, node *augn)
                                }
                                if (assigning > OP_APPLY) {
                                        com_error(c, PyExc_SyntaxError,
-                                 "augmented assign to tuple literal or generator expression not possible");
+                                 "augmented assign to tuple literal, yield, or generator expression not possible");
                                        return;
                                }
                                break;
@@ -3729,27 +3742,42 @@ com_return_stmt(struct compiling *c, node *n)
 }
 
 static void
-com_yield_stmt(struct compiling *c, node *n)
+com_yield_expr(struct compiling *c, node *n)
 {
        int i;
-       REQ(n, yield_stmt); /* 'yield' testlist */
+       REQ(n, yield_expr); /* 'yield' testlist */
        if (!c->c_infunction) {
                com_error(c, PyExc_SyntaxError, "'yield' outside function");
        }
        
-       for (i = 0; i < c->c_nblocks; ++i) {
+       /* for (i = 0; i < c->c_nblocks; ++i) {
                if (c->c_block[i] == SETUP_FINALLY) {
                        com_error(c, PyExc_SyntaxError,
                                  "'yield' not allowed in a 'try' block "
                                  "with a 'finally' clause");
                        return;
                }
+       } */
+
+       if (NCH(n) < 2) {
+               com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
+               com_push(c, 1);
        }
-       com_node(c, CHILD(n, 1));
+       else
+               com_node(c, CHILD(n, 1));
        com_addbyte(c, YIELD_VALUE);
+}
+
+static void
+com_yield_stmt(struct compiling *c, node *n)
+{
+       REQ(n, yield_stmt); /* yield_expr */
+       com_node(c, CHILD(n, 0));
+       com_addbyte(c, POP_TOP);
        com_pop(c, 1);
 }
 
+
 static void
 com_raise_stmt(struct compiling *c, node *n)
 {
@@ -4768,6 +4796,10 @@ com_node(struct compiling *c, node *n)
        
        /* Expression nodes */
        
+       case yield_expr:
+               com_yield_expr(c, n);
+               break;
+
        case testlist:
        case testlist1:
        case testlist_safe:
@@ -5027,7 +5059,9 @@ compile_generator_expression(struct compiling *c, node *n)
        REQ(CHILD(n, 1), gen_for); 
 
        c->c_name = "<generator expression>";
+       c->c_infunction = 1;
        com_gen_for(c, CHILD(n, 1), CHILD(n, 0), 1);
+       c->c_infunction = 0;
 
        com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
        com_push(c, 1);
@@ -6115,7 +6149,7 @@ 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.
+/* Look for a yield stmt or expr under n.  Return 1 if found, else 0.
    This hack is used to look inside "if 0:" blocks (which are normally
    ignored) in case those are the only places a yield occurs (so that this
    function is a generator). */
@@ -6137,6 +6171,7 @@ look_for_yield(node *n)
                        return 0;
 
                case yield_stmt:
+               case yield_expr:
                        return GENERATOR;
 
                default:
@@ -6247,8 +6282,10 @@ symtable_node(struct symtable *st, node *n)
        case del_stmt:
                symtable_assign(st, CHILD(n, 1), 0);
                break;
-       case yield_stmt:
+       case yield_expr:
                st->st_cur->ste_generator = 1;
+               if (NCH(n)==1) 
+                       break;
                n = CHILD(n, 1);
                goto loop;
        case expr_stmt:
@@ -6341,9 +6378,15 @@ symtable_node(struct symtable *st, node *n)
                /* fall through */
 
        case atom:
-               if (TYPE(n) == atom && TYPE(CHILD(n, 0)) == NAME) {
-                       symtable_add_use(st, STR(CHILD(n, 0)));
-                       break;
+               if (TYPE(n) == atom) {
+                       if (TYPE(CHILD(n, 0)) == NAME) {
+                               symtable_add_use(st, STR(CHILD(n, 0)));
+                               break;
+                       }
+                       else if (TYPE(CHILD(n,0)) == LPAR) {
+                               n = CHILD(n,1);
+                               goto loop;
+                       }
                }
                /* fall through */
        default:
@@ -6739,6 +6782,15 @@ symtable_assign(struct symtable *st, node *n, int def_flag)
                        symtable_add_def(st, STR(tmp), DEF_LOCAL | def_flag);
                }
                return;
+
+       case yield_expr:
+               st->st_cur->ste_generator = 1;
+               if (NCH(n)==2) {
+                       n = CHILD(n, 1);
+                       goto loop;
+               }
+               return;
+
        case dotted_as_name:
                if (NCH(n) == 3)
                        symtable_add_def(st, STR(CHILD(n, 2)),
index 2fd74bc76d33a46266c6949d7b876c493ddcbdef..2e7c820bf1e96e40ab4e90ecc1a7532740a676ed 100644 (file)
@@ -57,6 +57,7 @@ Exception\n\
  |\n\
  +-- SystemExit\n\
  +-- StopIteration\n\
+ +-- GeneratorExit\n\
  +-- StandardError\n\
  |    |\n\
  |    +-- KeyboardInterrupt\n\
@@ -394,6 +395,7 @@ PyDoc_STRVAR(StandardError__doc__,
 PyDoc_STRVAR(TypeError__doc__, "Inappropriate argument type.");
 
 PyDoc_STRVAR(StopIteration__doc__, "Signal the end from iterator.next().");
+PyDoc_STRVAR(GeneratorExit__doc__, "Request that a generator exit.");
 
 
 \f
@@ -1583,6 +1585,7 @@ static PyMethodDef functions[] = {
 
 PyObject *PyExc_Exception;
 PyObject *PyExc_StopIteration;
+PyObject *PyExc_GeneratorExit;
 PyObject *PyExc_StandardError;
 PyObject *PyExc_ArithmeticError;
 PyObject *PyExc_LookupError;
@@ -1657,6 +1660,8 @@ static struct {
  {"Exception", &PyExc_Exception},
  {"StopIteration", &PyExc_StopIteration, &PyExc_Exception,
   StopIteration__doc__},
+ {"GeneratorExit", &PyExc_GeneratorExit, &PyExc_Exception,
+  GeneratorExit__doc__},
  {"StandardError", &PyExc_StandardError, &PyExc_Exception,
   StandardError__doc__},
  {"TypeError", &PyExc_TypeError, 0, TypeError__doc__},
index 464f0aeddd74e50d674f031e9255454c112c5d13..91d20f2ad1509c3a93ee541090d12442fa5232e2 100644 (file)
@@ -279,10 +279,12 @@ static arc arcs_13_1[3] = {
        {25, 3},
        {0, 1},
 };
-static arc arcs_13_2[1] = {
+static arc arcs_13_2[2] = {
+       {43, 4},
        {9, 4},
 };
-static arc arcs_13_3[1] = {
+static arc arcs_13_3[2] = {
+       {43, 5},
        {9, 5},
 };
 static arc arcs_13_4[1] = {
@@ -295,13 +297,12 @@ static arc arcs_13_5[2] = {
 static state states_13[6] = {
        {1, arcs_13_0},
        {3, arcs_13_1},
-       {1, arcs_13_2},
-       {1, arcs_13_3},
+       {2, arcs_13_2},
+       {2, arcs_13_3},
        {1, arcs_13_4},
        {2, arcs_13_5},
 };
 static arc arcs_14_0[12] = {
-       {43, 1},
        {44, 1},
        {45, 1},
        {46, 1},
@@ -313,6 +314,7 @@ static arc arcs_14_0[12] = {
        {52, 1},
        {53, 1},
        {54, 1},
+       {55, 1},
 };
 static arc arcs_14_1[1] = {
        {0, 1},
@@ -322,11 +324,11 @@ static state states_14[2] = {
        {1, arcs_14_1},
 };
 static arc arcs_15_0[1] = {
-       {55, 1},
+       {56, 1},
 };
 static arc arcs_15_1[3] = {
        {26, 2},
-       {56, 3},
+       {57, 3},
        {0, 1},
 };
 static arc arcs_15_2[2] = {
@@ -367,10 +369,10 @@ static state states_15[9] = {
        {2, arcs_15_8},
 };
 static arc arcs_16_0[1] = {
-       {57, 1},
+       {58, 1},
 };
 static arc arcs_16_1[1] = {
-       {58, 2},
+       {59, 2},
 };
 static arc arcs_16_2[1] = {
        {0, 2},
@@ -381,7 +383,7 @@ static state states_16[3] = {
        {1, arcs_16_2},
 };
 static arc arcs_17_0[1] = {
-       {59, 1},
+       {60, 1},
 };
 static arc arcs_17_1[1] = {
        {0, 1},
@@ -391,11 +393,11 @@ static state states_17[2] = {
        {1, arcs_17_1},
 };
 static arc arcs_18_0[5] = {
-       {60, 1},
        {61, 1},
        {62, 1},
        {63, 1},
        {64, 1},
+       {65, 1},
 };
 static arc arcs_18_1[1] = {
        {0, 1},
@@ -405,7 +407,7 @@ static state states_18[2] = {
        {1, arcs_18_1},
 };
 static arc arcs_19_0[1] = {
-       {65, 1},
+       {66, 1},
 };
 static arc arcs_19_1[1] = {
        {0, 1},
@@ -415,7 +417,7 @@ static state states_19[2] = {
        {1, arcs_19_1},
 };
 static arc arcs_20_0[1] = {
-       {66, 1},
+       {67, 1},
 };
 static arc arcs_20_1[1] = {
        {0, 1},
@@ -425,7 +427,7 @@ static state states_20[2] = {
        {1, arcs_20_1},
 };
 static arc arcs_21_0[1] = {
-       {67, 1},
+       {68, 1},
 };
 static arc arcs_21_1[2] = {
        {9, 2},
@@ -440,18 +442,14 @@ static state states_21[3] = {
        {1, arcs_21_2},
 };
 static arc arcs_22_0[1] = {
-       {68, 1},
+       {43, 1},
 };
 static arc arcs_22_1[1] = {
-       {9, 2},
-};
-static arc arcs_22_2[1] = {
-       {0, 2},
+       {0, 1},
 };
-static state states_22[3] = {
+static state states_22[2] = {
        {1, arcs_22_0},
        {1, arcs_22_1},
-       {1, arcs_22_2},
 };
 static arc arcs_23_0[1] = {
        {69, 1},
@@ -779,7 +777,7 @@ static arc arcs_38_0[1] = {
        {93, 1},
 };
 static arc arcs_38_1[1] = {
-       {58, 2},
+       {59, 2},
 };
 static arc arcs_38_2[1] = {
        {82, 3},
@@ -1034,7 +1032,7 @@ static arc arcs_50_0[1] = {
 };
 static arc arcs_50_1[3] = {
        {123, 0},
-       {56, 0},
+       {57, 0},
        {0, 1},
 };
 static state states_50[2] = {
@@ -1113,7 +1111,8 @@ static arc arcs_55_0[7] = {
        {144, 5},
        {145, 6},
 };
-static arc arcs_55_1[2] = {
+static arc arcs_55_1[3] = {
+       {43, 7},
        {135, 7},
        {15, 5},
 };
@@ -1149,7 +1148,7 @@ static arc arcs_55_10[1] = {
 };
 static state states_55[11] = {
        {7, arcs_55_0},
-       {2, arcs_55_1},
+       {3, arcs_55_1},
        {2, arcs_55_2},
        {2, arcs_55_3},
        {1, arcs_55_4},
@@ -1533,7 +1532,7 @@ static arc arcs_71_0[1] = {
        {93, 1},
 };
 static arc arcs_71_1[1] = {
-       {58, 2},
+       {59, 2},
 };
 static arc arcs_71_2[1] = {
        {82, 3},
@@ -1590,7 +1589,7 @@ static arc arcs_74_0[1] = {
        {93, 1},
 };
 static arc arcs_74_1[1] = {
-       {58, 2},
+       {59, 2},
 };
 static arc arcs_74_2[1] = {
        {82, 3},
@@ -1653,165 +1652,182 @@ static state states_77[2] = {
        {1, arcs_77_0},
        {1, arcs_77_1},
 };
-static dfa dfas[78] = {
+static arc arcs_78_0[1] = {
+       {160, 1},
+};
+static arc arcs_78_1[2] = {
+       {9, 2},
+       {0, 1},
+};
+static arc arcs_78_2[1] = {
+       {0, 2},
+};
+static state states_78[3] = {
+       {1, arcs_78_0},
+       {2, arcs_78_1},
+       {1, arcs_78_2},
+};
+static dfa dfas[79] = {
        {256, "single_input", 0, 3, states_0,
-        "\004\050\014\000\000\000\200\012\076\205\011\162\000\002\000\140\010\111\023\002"},
+        "\004\050\014\000\000\000\000\025\074\205\011\162\000\002\000\140\010\111\023\002\001"},
        {257, "file_input", 0, 2, states_1,
-        "\204\050\014\000\000\000\200\012\076\205\011\162\000\002\000\140\010\111\023\002"},
+        "\204\050\014\000\000\000\000\025\074\205\011\162\000\002\000\140\010\111\023\002\001"},
        {258, "eval_input", 0, 3, states_2,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {259, "decorator", 0, 7, states_3,
-        "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {260, "decorators", 0, 2, states_4,
-        "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {261, "funcdef", 0, 7, states_5,
-        "\000\010\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\010\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {262, "parameters", 0, 4, states_6,
-        "\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {263, "varargslist", 0, 10, states_7,
-        "\000\040\010\060\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\040\010\060\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {264, "fpdef", 0, 4, states_8,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {265, "fplist", 0, 3, states_9,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {266, "stmt", 0, 2, states_10,
-        "\000\050\014\000\000\000\200\012\076\205\011\162\000\002\000\140\010\111\023\002"},
+        "\000\050\014\000\000\000\000\025\074\205\011\162\000\002\000\140\010\111\023\002\001"},
        {267, "simple_stmt", 0, 4, states_11,
-        "\000\040\010\000\000\000\200\012\076\205\011\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\025\074\205\011\000\000\002\000\140\010\111\023\000\001"},
        {268, "small_stmt", 0, 2, states_12,
-        "\000\040\010\000\000\000\200\012\076\205\011\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\025\074\205\011\000\000\002\000\140\010\111\023\000\001"},
        {269, "expr_stmt", 0, 6, states_13,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {270, "augassign", 0, 2, states_14,
-        "\000\000\000\000\000\370\177\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\360\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {271, "print_stmt", 0, 9, states_15,
-        "\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {272, "del_stmt", 0, 3, states_16,
-        "\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {273, "pass_stmt", 0, 2, states_17,
-        "\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {274, "flow_stmt", 0, 2, states_18,
-        "\000\000\000\000\000\000\000\000\076\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\074\000\000\000\000\000\000\000\000\000\000\000\001"},
        {275, "break_stmt", 0, 2, states_19,
-        "\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000"},
        {276, "continue_stmt", 0, 2, states_20,
-        "\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000"},
        {277, "return_stmt", 0, 3, states_21,
-        "\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000"},
-       {278, "yield_stmt", 0, 3, states_22,
-        "\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000"},
+       {278, "yield_stmt", 0, 2, states_22,
+        "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001"},
        {279, "raise_stmt", 0, 7, states_23,
-        "\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000"},
        {280, "import_stmt", 0, 2, states_24,
-        "\000\000\000\000\000\000\000\000\000\005\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\005\000\000\000\000\000\000\000\000\000\000\000"},
        {281, "import_name", 0, 3, states_25,
-        "\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000"},
        {282, "import_from", 0, 7, states_26,
-        "\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000"},
        {283, "import_as_name", 0, 4, states_27,
-        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {284, "dotted_as_name", 0, 4, states_28,
-        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {285, "import_as_names", 0, 3, states_29,
-        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {286, "dotted_as_names", 0, 2, states_30,
-        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {287, "dotted_name", 0, 2, states_31,
-        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {288, "global_stmt", 0, 3, states_32,
-        "\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000"},
        {289, "exec_stmt", 0, 7, states_33,
-        "\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000"},
        {290, "assert_stmt", 0, 5, states_34,
-        "\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000"},
        {291, "compound_stmt", 0, 2, states_35,
-        "\000\010\004\000\000\000\000\000\000\000\000\162\000\000\000\000\000\000\000\002"},
+        "\000\010\004\000\000\000\000\000\000\000\000\162\000\000\000\000\000\000\000\002\000"},
        {292, "if_stmt", 0, 8, states_36,
-        "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000"},
        {293, "while_stmt", 0, 8, states_37,
-        "\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000"},
        {294, "for_stmt", 0, 10, states_38,
-        "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000"},
        {295, "try_stmt", 0, 10, states_39,
-        "\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000"},
        {296, "except_clause", 0, 5, states_40,
-        "\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000"},
        {297, "suite", 0, 5, states_41,
-        "\004\040\010\000\000\000\200\012\076\205\011\000\000\002\000\140\010\111\023\000"},
+        "\004\040\010\000\000\000\000\025\074\205\011\000\000\002\000\140\010\111\023\000\001"},
        {298, "test", 0, 4, states_42,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {299, "and_test", 0, 2, states_43,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\003\000\000"},
        {300, "not_test", 0, 3, states_44,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\003\000\000"},
        {301, "comparison", 0, 2, states_45,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"},
        {302, "comp_op", 0, 4, states_46,
-        "\000\000\000\000\000\000\000\000\000\000\004\000\000\362\017\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\004\000\000\362\017\000\000\000\000\000\000"},
        {303, "expr", 0, 2, states_47,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"},
        {304, "xor_expr", 0, 2, states_48,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"},
        {305, "and_expr", 0, 2, states_49,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"},
        {306, "shift_expr", 0, 2, states_50,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"},
        {307, "arith_expr", 0, 2, states_51,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"},
        {308, "term", 0, 2, states_52,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"},
        {309, "factor", 0, 3, states_53,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"},
        {310, "power", 0, 4, states_54,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\111\003\000\000"},
        {311, "atom", 0, 11, states_55,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\111\003\000\000"},
        {312, "listmaker", 0, 5, states_56,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {313, "testlist_gexp", 0, 5, states_57,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {314, "lambdef", 0, 5, states_58,
-        "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\000"},
        {315, "trailer", 0, 7, states_59,
-        "\000\040\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\001\000\000"},
+        "\000\040\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\001\000\000\000"},
        {316, "subscriptlist", 0, 3, states_60,
-        "\000\040\050\000\000\000\000\000\000\100\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\050\000\000\000\000\000\000\100\000\000\000\002\000\140\010\111\023\000\000"},
        {317, "subscript", 0, 7, states_61,
-        "\000\040\050\000\000\000\000\000\000\100\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\050\000\000\000\000\000\000\100\000\000\000\002\000\140\010\111\023\000\000"},
        {318, "sliceop", 0, 3, states_62,
-        "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
        {319, "exprlist", 0, 3, states_63,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"},
        {320, "testlist", 0, 3, states_64,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {321, "testlist_safe", 0, 5, states_65,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {322, "dictmaker", 0, 5, states_66,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {323, "classdef", 0, 8, states_67,
-        "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002"},
+        "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000"},
        {324, "arglist", 0, 8, states_68,
-        "\000\040\010\060\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\060\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {325, "argument", 0, 5, states_69,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {326, "list_iter", 0, 2, states_70,
-        "\000\000\000\000\000\000\000\000\000\000\000\042\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\042\000\000\000\000\000\000\000\000\000"},
        {327, "list_for", 0, 6, states_71,
-        "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000"},
        {328, "list_if", 0, 4, states_72,
-        "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000"},
        {329, "gen_iter", 0, 2, states_73,
-        "\000\000\000\000\000\000\000\000\000\000\000\042\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\042\000\000\000\000\000\000\000\000\000"},
        {330, "gen_for", 0, 6, states_74,
-        "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000"},
        {331, "gen_if", 0, 4, states_75,
-        "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000"},
+        "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000"},
        {332, "testlist1", 0, 2, states_76,
-        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"},
+        "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"},
        {333, "encoding_decl", 0, 2, states_77,
-        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+        "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"},
+       {334, "yield_expr", 0, 3, states_78,
+        "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001"},
 };
-static label labels[160] = {
+static label labels[161] = {
        {0, "EMPTY"},
        {256, 0},
        {4, 0},
@@ -1855,6 +1871,7 @@ static label labels[160] = {
        {289, 0},
        {290, 0},
        {270, 0},
+       {334, 0},
        {37, 0},
        {38, 0},
        {39, 0},
@@ -1880,7 +1897,6 @@ static label labels[160] = {
        {1, "break"},
        {1, "continue"},
        {1, "return"},
-       {1, "yield"},
        {1, "raise"},
        {281, 0},
        {282, 0},
@@ -1972,10 +1988,11 @@ static label labels[160] = {
        {329, 0},
        {331, 0},
        {333, 0},
+       {1, "yield"},
 };
 grammar _PyParser_Grammar = {
-       78,
+       79,
        dfas,
-       {160, labels},
+       {161, labels},
        256
 };