def test_countYieldsInOuterScope(self): def f(): x = 0 yield x if x: yield x else: yield def f(): return 4 class D1: def f(self): yield 0 for x in xrange(3): while False: yield x else: yield x else: yield x x = [f() for _ in xrange(1000) if f() > 0] yield None ast = PyAstUtil.pyAstFor(f) self.assertEqual(PyAstUtil.countReturnsInOuterScope(ast.body[0]), 0) self.assertEqual(PyAstUtil.countYieldsInOuterScope(ast.body[0]), 7) self.assertFalse(PyAstUtil.hasReturnInOuterScope(ast.body[0])) self.assertTrue(PyAstUtil.hasYieldInOuterScope(ast.body[0])) self.assertTrue(PyAstUtil.hasReturnOrYieldInOuterScope(ast.body[0])) returnLocs = PyAstUtil.getReturnLocationsInOuterScope(ast.body[0]) yieldLocs = PyAstUtil.getYieldLocationsInOuterScope(ast.body[0]) returnLocs = map(lambda x: x - returnLocs[0] if len(returnLocs) > 0 else 0, returnLocs) yieldLocs = map(lambda x: x - yieldLocs[0] if len(yieldLocs) > 0 else 0, yieldLocs) self.assertEqual(returnLocs, []) self.assertEqual(yieldLocs, [0, 2, 4, 12, 14, 16, 18])
def test_hasReturnInOuterScope(self): def f(): x = 0 return x if x: return x else: return def f(): yield 4 class D1: def f(self): return 0 for x in xrange(3): while False: return x else: return x else: return x x = [f() for _ in xrange(1000) if f() > 0] return None ast = PyAstUtil.pyAstFor(f) self.assertEqual(PyAstUtil.countReturnsInOuterScope(ast.body[0]), 7) self.assertEqual(PyAstUtil.countYieldsInOuterScope(ast.body[0]), 0) self.assertTrue(PyAstUtil.hasReturnInOuterScope(ast.body[0])) self.assertFalse(PyAstUtil.hasYieldInOuterScope(ast.body[0])) self.assertTrue(PyAstUtil.hasReturnOrYieldInOuterScope(ast.body[0])) returnLocs = PyAstUtil.getReturnLocationsInOuterScope(ast.body[0]) yieldLocs = PyAstUtil.getYieldLocationsInOuterScope(ast.body[0]) returnLocs = [x - returnLocs[0] for x in returnLocs] yieldLocs = [x - yieldLocs[0] for x in yieldLocs] self.assertEqual(returnLocs, [0, 2, 4, 12, 14, 16, 18]) self.assertEqual(yieldLocs, [])
def test_hasReturnInOuterScope(self): def f(): x = 0 return x if x: return x else: return def f(): yield 4 class D1: def f(self): return 0 for x in xrange(3): while False: return x else: return x else: return x x = [f() for _ in xrange(1000) if f() > 0] return None ast = PyAstUtil.pyAstFor(f) self.assertEqual(PyAstUtil.countReturnsInOuterScope(ast.body[0]), 7) self.assertEqual(PyAstUtil.countYieldsInOuterScope(ast.body[0]), 0) self.assertTrue(PyAstUtil.hasReturnInOuterScope(ast.body[0])) self.assertFalse(PyAstUtil.hasYieldInOuterScope(ast.body[0])) self.assertTrue(PyAstUtil.hasReturnOrYieldInOuterScope(ast.body[0])) returnLocs = PyAstUtil.getReturnLocationsInOuterScope(ast.body[0]) yieldLocs = PyAstUtil.getYieldLocationsInOuterScope(ast.body[0]) returnLocs = [x - returnLocs[0] for x in returnLocs] yieldLocs = [x - yieldLocs[0] for x in yieldLocs] self.assertEqual(returnLocs, [0, 2, 4, 12, 14, 16, 18]) self.assertEqual(yieldLocs, [])
def _registerWithBlock(self, objectId, pyObject): """ `_registerWithBlock`: register a `PyforaWithBlock.PyforaWithBlock` with `self.objectRegistry`. Recursively call `walkPyObject` on the resolvable free variable member access chains in the block and on the file object. """ lineNumber = pyObject.lineNumber sourceTree = PyAstUtil.pyAstFromText(pyObject.sourceText) withBlockAst = PyAstUtil.withBlockAtLineNumber(sourceTree, lineNumber) withBlockFun = ast.FunctionDef( name="", args=ast.arguments(args=[], defaults=[], kwarg=None, vararg=None), body=withBlockAst.body, decorator_list=[], lineno=lineNumber, col_offset=0 ) if PyAstUtil.hasReturnInOuterScope(withBlockFun): raise Exceptions.BadWithBlockError( "return statement not supported in pyfora with-block (line %s)" % PyAstUtil.getReturnLocationsInOuterScope(withBlockFun)[0]) if PyAstUtil.hasYieldInOuterScope(withBlockFun): raise Exceptions.BadWithBlockError( "yield expression not supported in pyfora with-block (line %s)" % PyAstUtil.getYieldLocationsInOuterScope(withBlockFun)[0]) freeVariableMemberAccessChainsWithPositions = \ self._freeMemberAccessChainsWithPositions(withBlockFun) boundValuesInScopeWithPositions = \ PyAstFreeVariableAnalyses.collectBoundValuesInScope( withBlockFun, getPositions=True) for boundValueWithPosition in boundValuesInScopeWithPositions: val, pos = boundValueWithPosition if val not in pyObject.unboundLocals and val in pyObject.boundVariables: freeVariableMemberAccessChainsWithPositions.add( PyAstFreeVariableAnalyses.VarWithPosition(var=(val,), pos=pos) ) try: freeVariableMemberAccessChainResolutions = \ self._resolveFreeVariableMemberAccessChains( freeVariableMemberAccessChainsWithPositions, pyObject.boundVariables ) except UnresolvedFreeVariableException as e: _convertUnresolvedFreeVariableExceptionAndRaise(e, pyObject.sourceFileName) try: processedFreeVariableMemberAccessChainResolutions = {} for chain, (resolution, position) in \ freeVariableMemberAccessChainResolutions.iteritems(): processedFreeVariableMemberAccessChainResolutions['.'.join(chain)] = \ self.walkPyObject(resolution) except UnresolvedFreeVariableExceptionWithTrace as e: e.addToTrace( Exceptions.makeTraceElement( path=pyObject.sourceFileName, lineNumber=position.lineno ) ) raise sourceFileId = self.walkPyObject( _FileDescription.cachedFromArgs( fileName=pyObject.sourceFileName ) ) self._objectRegistry.defineWithBlock( objectId=objectId, freeVariableMemberAccessChainsToId=\ processedFreeVariableMemberAccessChainResolutions, sourceFileId=sourceFileId, lineNumber=lineNumber )
def _registerWithBlock(self, objectId, pyObject): """ `_registerWithBlock`: register a `PyforaWithBlock.PyforaWithBlock` with `self.objectRegistry`. Recursively call `walkPyObject` on the resolvable free variable member access chains in the block and on the file object. """ lineNumber = pyObject.lineNumber sourceTree = PyAstUtil.pyAstFromText(pyObject.sourceText) withBlockAst = PyAstUtil.withBlockAtLineNumber(sourceTree, lineNumber) withBlockFun = ast.FunctionDef(name="", args=ast.arguments(args=[], defaults=[], kwarg=None, vararg=None), body=withBlockAst.body, decorator_list=[], lineno=lineNumber, col_offset=0) if PyAstUtil.hasReturnInOuterScope(withBlockFun): raise Exceptions.InvalidPyforaOperation( "return statement not supported in pyfora with-block (line %s)" % PyAstUtil.getReturnLocationsInOuterScope(withBlockFun)[0]) if PyAstUtil.hasYieldInOuterScope(withBlockFun): raise Exceptions.InvalidPyforaOperation( "yield expression not supported in pyfora with-block (line %s)" % PyAstUtil.getYieldLocationsInOuterScope(withBlockFun)[0]) freeVariableMemberAccessChainsWithPositions = \ self._freeMemberAccessChainsWithPositions(withBlockFun) boundValuesInScopeWithPositions = \ PyAstFreeVariableAnalyses.collectBoundValuesInScope( withBlockFun, getPositions=True) for boundValueWithPosition in boundValuesInScopeWithPositions: val, pos = boundValueWithPosition if val not in pyObject.unboundLocals and val in pyObject.boundVariables: freeVariableMemberAccessChainsWithPositions.add( PyAstFreeVariableAnalyses.VarWithPosition(var=(val, ), pos=pos)) try: freeVariableMemberAccessChainResolutions = \ self._resolveFreeVariableMemberAccessChains( freeVariableMemberAccessChainsWithPositions, pyObject.boundVariables ) except UnresolvedFreeVariableException as e: _convertUnresolvedFreeVariableExceptionAndRaise( e, pyObject.sourceFileName) try: processedFreeVariableMemberAccessChainResolutions = {} for chain, (resolution, position) in \ freeVariableMemberAccessChainResolutions.iteritems(): processedFreeVariableMemberAccessChainResolutions['.'.join(chain)] = \ self.walkPyObject(resolution) except UnresolvedFreeVariableExceptionWithTrace as e: e.addToTrace( Exceptions.makeTraceElement(path=pyObject.sourceFileName, lineNumber=position.lineno)) raise sourceFileId = self.walkPyObject( _FileDescription.cachedFromArgs(fileName=pyObject.sourceFileName)) self._objectRegistry.defineWithBlock( objectId=objectId, freeVariableMemberAccessChainsToId=\ processedFreeVariableMemberAccessChainResolutions, sourceFileId=sourceFileId, lineNumber=lineNumber )