# 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__':
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:
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))
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:
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
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
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))
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('}')
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.
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):
"""