merge
authorStefan Behnel <scoder@users.berlios.de>
Tue, 14 Dec 2010 08:04:35 +0000 (09:04 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Tue, 14 Dec 2010 08:04:35 +0000 (09:04 +0100)
Cython/Compiler/Code.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/Nodes.py
tests/run/generators.pyx

index 4048074d7ff59b9a0e208ba8bc9aa2c7831645a6..f6a702fd668188754a7a433507369bac5453d11c 100644 (file)
@@ -1290,7 +1290,7 @@ class CCodeWriter(object):
         #    code = "((PyObject*)%s)" % code
         self.put_init_to_py_none(code, entry.type, nanny)
         if entry.in_closure:
-            self.put_giveref(code)
+            self.put_giveref('Py_None')
 
     def put_pymethoddef(self, entry, term, allow_skip=True):
         if entry.is_special or entry.name == '__getattribute__':
index bd45bae12d158df614d16d0640c5b71f2a846932..4bcee405e16a363c4da7b763569e6ca9005c7229 100755 (executable)
@@ -1619,9 +1619,9 @@ class NameNode(AtomicExprNode):
                 if self.use_managed_ref:
                     rhs.make_owned_reference(code)
                     is_external_ref = entry.is_cglobal or self.entry.in_closure or self.entry.from_closure
-                    if is_external_ref:
-                        code.put_gotref(self.py_result())
                     if not self.lhs_of_first_assignment:
+                        if is_external_ref:
+                            code.put_gotref(self.py_result())
                         if entry.is_local and not Options.init_local_none:
                             initialized = entry.scope.control_flow.get_state((entry.name, 'initialized'), self.pos)
                             if initialized is True:
@@ -5011,7 +5011,6 @@ class YieldExprNode(ExprNode):
             code.put_init_to_py_none(Naming.retval_cname, py_object_type)
         saved = []
         code.funcstate.closure_temps.reset()
-        code.putln('/* Save temporary variables */')
         for cname, type, manage_ref in code.funcstate.temps_in_use():
             save_cname = code.funcstate.closure_temps.allocate_temp(type)
             saved.append((cname, save_cname, type))
@@ -5021,11 +5020,10 @@ class YieldExprNode(ExprNode):
 
         code.put_xgiveref(Naming.retval_cname)
         code.put_finish_refcount_context()
-        code.putln("/* return from function, yielding value */")
+        code.putln("/* return from generator, yielding value */")
         code.putln("%s->%s.resume_label = %d;" % (Naming.cur_scope_cname, Naming.obj_base_cname, self.label_num))
         code.putln("return %s;" % Naming.retval_cname);
         code.put_label(self.label_name)
-        code.putln('/* Restore temporary variables */')
         for cname, save_cname, type in saved:
             code.putln('%s = %s->%s;' % (cname, Naming.cur_scope_cname, save_cname))
             if type.is_pyobject:
index a22d610061662146211753fe025700458dfaed90..39539cadc82ceaeb4c61ab547cdec3cedbbdb641 100644 (file)
@@ -1510,7 +1510,7 @@ class FuncDefNode(StatNode, BlockNode):
             resume_code.putln("case 0: goto %s;" % first_run_label)
             for yield_expr in self.yields:
                 resume_code.putln("case %d: goto %s;" % (yield_expr.label_num, yield_expr.label_name));
-            resume_code.putln("default: /* raise error here */");
+            resume_code.putln("default: /* CPython raises the right error here */");
             resume_code.putln("return NULL;");
             resume_code.putln("}");
         # ----- Python version
@@ -1910,6 +1910,7 @@ class GeneratorWrapperNode(object):
         self.header = header
 
     def generate_function_body(self, env, code):
+        code.mark_pos(self.def_node.pos)
         cenv = env.outer_scope # XXX: correct?
         while cenv.is_py_class_scope or cenv.is_c_class_scope:
             cenv = cenv.outer_scope
@@ -2430,8 +2431,8 @@ class DefNode(FuncDefNode):
             code.putln("0};")
 
     def generate_argument_parsing_code(self, env, code):
-        # Generate PyArg_ParseTuple call for generic
-        # arguments, if any.
+        # Generate fast equivalent of PyArg_ParseTuple call for
+        # generic arguments, if any, including args/kwargs
         if self.entry.signature.has_dummy_arg and not self.self_in_stararg:
             # get rid of unused argument warning
             code.putln("%s = %s;" % (Naming.self_cname, Naming.self_cname))
@@ -2752,6 +2753,8 @@ class DefNode(FuncDefNode):
             code.putln("if (unlikely(!%s)) {" % self.star_arg.entry.cname)
             if self.starstar_arg:
                 code.put_decref(self.starstar_arg.entry.cname, py_object_type)
+            if self.needs_closure:
+                code.put_decref(Naming.cur_scope_cname, self.local_scope.scope_class.type)
             code.put_finish_refcount_context()
             code.putln('return %s;' % self.error_value())
             code.putln('}')
@@ -2924,9 +2927,9 @@ class DefNode(FuncDefNode):
             if arg.needs_conversion:
                 self.generate_arg_conversion(arg, code)
             elif arg.entry.in_closure:
-                code.putln('%s = %s;' % (arg.entry.cname, arg.hdr_cname))
                 if arg.type.is_pyobject:
-                    code.put_var_incref(arg.entry)
+                    code.put_incref(arg.hdr_cname, py_object_type)
+                code.putln('%s = %s;' % (arg.entry.cname, arg.hdr_cname))
 
     def generate_arg_conversion(self, arg, code):
         # Generate conversion code for one argument.
index 02f519d4080be531dec2860a27ea47cce28fa936..f2243afc994bf2cce9acacabcc047fe8dc809acd 100644 (file)
@@ -148,6 +148,35 @@ def check_throw():
         except ValueError:
             pass
 
+def test_first_assignment():
+    """
+    >>> gen = test_first_assignment()
+    >>> next(gen)
+    5
+    >>> next(gen)
+    10
+    >>> next(gen)
+    (5, 10)
+    """
+    cdef x = 5 # first
+    yield x
+    cdef y = 10 # first
+    yield y
+    yield (x,y)
+
+def test_swap_assignment():
+    """
+    >>> gen = test_swap_assignment()
+    >>> next(gen)
+    (5, 10)
+    >>> next(gen)
+    (10, 5)
+    """
+    x,y = 5,10
+    yield (x,y)
+    x,y = y,x   # no ref-counting here
+    yield (x,y)
+
 
 class Foo(object):
     """