From ec668b5584ccef56640df78d12806aaba3e4216b Mon Sep 17 00:00:00 2001 From: Tim Martin Date: Fri, 1 Jan 2016 11:55:50 +0000 Subject: [PATCH] In python 3.3+, generator functions always return a value --- hy/compiler.py | 5 ++++- tests/compilers/test_compiler.py | 36 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index 21a8b1c..35b7c43 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -2309,7 +2309,10 @@ class HyASTCompiler(object): return ret if body.expr: - if body.contains_yield: + if body.contains_yield and not PY33: + # Prior to PEP 380 (introduced in Python 3.3) + # generators may not have a value in a return + # statement. body += body.expr_as_stmt() else: body += ast.Return(value=body.expr, diff --git a/tests/compilers/test_compiler.py b/tests/compilers/test_compiler.py index 59801cd..063bdda 100644 --- a/tests/compilers/test_compiler.py +++ b/tests/compilers/test_compiler.py @@ -26,6 +26,8 @@ from hy import compiler from hy.models.expression import HyExpression from hy.models.list import HyList from hy.models.symbol import HySymbol +from hy.models.integer import HyInteger +from hy._compat import PY33 if sys.version_info[0] <= 2 and sys.version_info[1] <= 6: import unittest2 as unittest @@ -98,3 +100,37 @@ class HyASTCompilerTest(unittest.TestCase): expr = ret.expr self.assertIsInstance(expr, ast.Name) self.assertEqual(expr.id, "c") + + def test_compiler_yield_return(self): + """ + Check that the compiler correctly generates return statements for + a generator function. In Python versions prior to 3.3, the return + statement in a generator can't take a value, so the final expression + should not generate a return statement. From 3.3 onwards a return + value should be generated. + """ + ret = self.c.compile_function_def( + self._make_expression(HySymbol("fn"), + HyList(), + HyExpression([HySymbol("yield"), + HyInteger(2)]), + HyExpression([HySymbol("+"), + HyInteger(1), + HyInteger(1)]))) + + self.assertEqual(len(ret.stmts), 1) + stmt = ret.stmts[0] + self.assertIsInstance(stmt, ast.FunctionDef) + body = stmt.body + self.assertEquals(len(body), 2) + self.assertIsInstance(body[0], ast.Expr) + self.assertIsInstance(body[0].value, ast.Yield) + + if PY33: + # From 3.3+, the final statement becomes a return value + self.assertIsInstance(body[1], ast.Return) + self.assertIsInstance(body[1].value, ast.BinOp) + else: + # In earlier versions, the expression is not returned + self.assertIsInstance(body[1], ast.Expr) + self.assertIsInstance(body[1].value, ast.BinOp)