Author: Jeremy Thurgood <fir...@gmail.com> Branch: Changeset: r68725:3f7024813427 Date: 2014-01-17 18:31 +0200 http://bitbucket.org/pypy/pypy/changeset/3f7024813427/
Log: merge remove-del-from-generatoriterator branch diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py --- a/pypy/interpreter/astcompiler/codegen.py +++ b/pypy/interpreter/astcompiler/codegen.py @@ -1234,6 +1234,8 @@ flags |= consts.CO_NESTED if scope.is_generator: flags |= consts.CO_GENERATOR + if scope.has_yield_inside_try: + flags |= consts.CO_YIELD_INSIDE_TRY if scope.has_variable_arg: flags |= consts.CO_VARARGS if scope.has_keywords_arg: diff --git a/pypy/interpreter/astcompiler/consts.py b/pypy/interpreter/astcompiler/consts.py --- a/pypy/interpreter/astcompiler/consts.py +++ b/pypy/interpreter/astcompiler/consts.py @@ -17,6 +17,7 @@ CO_FUTURE_UNICODE_LITERALS = 0x20000 #pypy specific: CO_KILL_DOCSTRING = 0x100000 +CO_YIELD_INSIDE_TRY = 0x200000 PyCF_SOURCE_IS_UTF8 = 0x0100 PyCF_DONT_IMPLY_DEDENT = 0x0200 diff --git a/pypy/interpreter/astcompiler/symtable.py b/pypy/interpreter/astcompiler/symtable.py --- a/pypy/interpreter/astcompiler/symtable.py +++ b/pypy/interpreter/astcompiler/symtable.py @@ -43,6 +43,7 @@ self.child_has_free = False self.nested = False self.doc_removable = False + self._in_try_body_depth = 0 def lookup(self, name): """Find the scope of identifier 'name'.""" @@ -75,6 +76,14 @@ self.varnames.append(mangled) return mangled + def note_try_start(self, try_node): + """Called when a try is found, before visiting the body.""" + self._in_try_body_depth += 1 + + def note_try_end(self, try_node): + """Called after visiting a try body.""" + self._in_try_body_depth -= 1 + def note_yield(self, yield_node): """Called when a yield is found.""" raise SyntaxError("'yield' outside function", yield_node.lineno, @@ -210,6 +219,7 @@ self.has_variable_arg = False self.has_keywords_arg = False self.is_generator = False + self.has_yield_inside_try = False self.optimized = True self.return_with_value = False self.import_star = None @@ -220,6 +230,8 @@ raise SyntaxError("'return' with argument inside generator", self.ret.lineno, self.ret.col_offset) self.is_generator = True + if self._in_try_body_depth > 0: + self.has_yield_inside_try = True def note_return(self, ret): if ret.value: @@ -463,7 +475,12 @@ self.scope.new_temporary_name() if wih.optional_vars: self.scope.new_temporary_name() - ast.GenericASTVisitor.visit_With(self, wih) + wih.context_expr.walkabout(self) + if wih.optional_vars: + wih.optional_vars.walkabout(self) + self.scope.note_try_start(wih) + self.visit_sequence(wih.body) + self.scope.note_try_end(wih) def visit_arguments(self, arguments): scope = self.scope @@ -505,3 +522,16 @@ else: role = SYM_ASSIGNED self.note_symbol(name.id, role) + + def visit_TryExcept(self, node): + self.scope.note_try_start(node) + self.visit_sequence(node.body) + self.scope.note_try_end(node) + self.visit_sequence(node.handlers) + self.visit_sequence(node.orelse) + + def visit_TryFinally(self, node): + self.scope.note_try_start(node) + self.visit_sequence(node.body) + self.scope.note_try_end(node) + self.visit_sequence(node.finalbody) diff --git a/pypy/interpreter/astcompiler/test/test_symtable.py b/pypy/interpreter/astcompiler/test/test_symtable.py --- a/pypy/interpreter/astcompiler/test/test_symtable.py +++ b/pypy/interpreter/astcompiler/test/test_symtable.py @@ -346,6 +346,23 @@ assert exc.msg == "'return' with argument inside generator" scp = self.func_scope("def f():\n return\n yield x") + def test_yield_inside_try(self): + scp = self.func_scope("def f(): yield x") + assert not scp.has_yield_inside_try + scp = self.func_scope("def f():\n try:\n yield x\n except: pass") + assert scp.has_yield_inside_try + scp = self.func_scope("def f():\n try:\n yield x\n finally: pass") + assert scp.has_yield_inside_try + scp = self.func_scope("def f():\n with x: yield y") + assert scp.has_yield_inside_try + + def test_yield_outside_try(self): + for input in ("try: pass\n except: pass", + "try: pass\n finally: pass", + "with x: pass"): + input = "def f():\n yield y\n %s\n yield y" % (input,) + assert not self.func_scope(input).has_yield_inside_try + def test_return(self): for input in ("class x: return", "return"): exc = py.test.raises(SyntaxError, self.func_scope, input).value diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py --- a/pypy/interpreter/generator.py +++ b/pypy/interpreter/generator.py @@ -155,20 +155,6 @@ code_name = self.pycode.co_name return space.wrap(code_name) - def __del__(self): - # Only bother enqueuing self to raise an exception if the frame is - # still not finished and finally or except blocks are present. - self.clear_all_weakrefs() - if self.frame is not None: - block = self.frame.lastblock - while block is not None: - if not isinstance(block, LoopBlock): - self.enqueue_for_destruction(self.space, - GeneratorIterator.descr_close, - "interrupting generator of ") - break - block = block.previous - # Results can be either an RPython list of W_Root, or it can be an # app-level W_ListObject, which also has an append() method, that's why we # generate 2 versions of the function and 2 jit drivers. @@ -211,3 +197,20 @@ return unpack_into unpack_into = _create_unpack_into() unpack_into_w = _create_unpack_into() + + +class GeneratorIteratorWithDel(GeneratorIterator): + + def __del__(self): + # Only bother enqueuing self to raise an exception if the frame is + # still not finished and finally or except blocks are present. + self.clear_all_weakrefs() + if self.frame is not None: + block = self.frame.lastblock + while block is not None: + if not isinstance(block, LoopBlock): + self.enqueue_for_destruction(self.space, + GeneratorIterator.descr_close, + "interrupting generator of ") + break + block = block.previous diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py --- a/pypy/interpreter/pycode.py +++ b/pypy/interpreter/pycode.py @@ -12,7 +12,7 @@ from pypy.interpreter.gateway import unwrap_spec from pypy.interpreter.astcompiler.consts import ( CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED, - CO_GENERATOR, CO_KILL_DOCSTRING) + CO_GENERATOR, CO_KILL_DOCSTRING, CO_YIELD_INSIDE_TRY) from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT from rpython.rlib.rarithmetic import intmask from rpython.rlib.objectmodel import compute_hash diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -167,8 +167,12 @@ def run(self): """Start this frame's execution.""" if self.getcode().co_flags & pycode.CO_GENERATOR: - from pypy.interpreter.generator import GeneratorIterator - return self.space.wrap(GeneratorIterator(self)) + if pycode.CO_YIELD_INSIDE_TRY: + from pypy.interpreter.generator import GeneratorIteratorWithDel + return self.space.wrap(GeneratorIteratorWithDel(self)) + else: + from pypy.interpreter.generator import GeneratorIterator + return self.space.wrap(GeneratorIterator(self)) else: return self.execute_frame() diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -5,7 +5,7 @@ from pypy.interpreter.module import Module from pypy.interpreter.pyframe import PyFrame from pypy.interpreter.pytraceback import PyTraceback -from pypy.interpreter.generator import GeneratorIterator +from pypy.interpreter.generator import GeneratorIteratorWithDel from rpython.rlib.objectmodel import instantiate from pypy.interpreter.gateway import unwrap_spec from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject @@ -60,7 +60,7 @@ return space.wrap(tb) def generator_new(space): - new_generator = instantiate(GeneratorIterator) + new_generator = instantiate(GeneratorIteratorWithDel) return space.wrap(new_generator) @unwrap_spec(current=int, remaining=int, step=int) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit