From e3e01d4405ba636b1027436aada2a0a94b4bcfb3 Mon Sep 17 00:00:00 2001 From: Simon Gomizelj Date: Fri, 29 Dec 2017 16:40:19 -0500 Subject: [PATCH] Introduce fn/a and defn/a Closes #1054 --- hy/compiler.py | 26 +++++++++++++++++++------- hy/core/bootstrap.hy | 9 +++++++++ tests/native_tests/py35_only_tests.hy | 19 +++++++++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 0020607..ef5268b 100755 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -250,6 +250,8 @@ class Result(object): var.arg = new_name elif isinstance(var, ast.FunctionDef): var.name = new_name + elif PY35 and isinstance(var, ast.AsyncFunctionDef): + var.name = new_name else: raise TypeError("Don't know how to rename a %s!" % ( var.__class__.__name__)) @@ -1139,6 +1141,12 @@ class HyASTCompiler(object): node = asty.Yield if expr[0] == "yield" else asty.YieldFrom return ret + node(expr, value=ret.force_expr) + @builds("await", iff=PY35) + @checkargs(1) + def compile_await_expression(self, expr): + ret = Result() + self.compile(expr[1]) + return ret + asty.Await(expr, value=ret.force_expr) + @builds("import") def compile_import_expression(self, expr): expr = copy.deepcopy(expr) @@ -1890,12 +1898,15 @@ class HyASTCompiler(object): return ret @builds("fn", "fn*") + @builds("fn/a", iff=PY35) # The starred version is for internal use (particularly, in the # definition of `defn`). It ensures that a FunctionDef is # produced rather than a Lambda. @checkargs(min=1) def compile_function_def(self, expression): - force_functiondef = expression.pop(0) == "fn*" + root = expression.pop(0) + force_functiondef = root in ("fn*", "fn/a") + asyncdef = root == "fn/a" arglist = expression.pop(0) docstring = None @@ -1904,7 +1915,7 @@ class HyASTCompiler(object): if not isinstance(arglist, HyList): raise HyTypeError(expression, - "First argument to `fn' must be a list") + "First argument to `{}' must be a list".format(root)) (ret, args, defaults, stararg, kwonlyargs, kwonlydefaults, kwargs) = self._parse_lambda_list(arglist) @@ -1980,11 +1991,12 @@ class HyASTCompiler(object): name = self.get_anon_var() - ret += asty.FunctionDef(expression, - name=name, - args=args, - body=body.stmts, - decorator_list=[]) + node = asty.AsyncFunctionDef if asyncdef else asty.FunctionDef + ret += node(expression, + name=name, + args=args, + body=body.stmts, + decorator_list=[]) ast_name = asty.Name(expression, id=name, ctx=ast.Load()) diff --git a/hy/core/bootstrap.hy b/hy/core/bootstrap.hy index 678ef06..bd2585f 100644 --- a/hy/core/bootstrap.hy +++ b/hy/core/bootstrap.hy @@ -70,6 +70,15 @@ (macro-error name "defn takes a parameter list as second argument")) `(setv ~name (fn* ~lambda-list ~@body))) +(defmacro defn/a [name lambda-list &rest body] + "Define `name` as a function with `lambda-list` signature and body `body`." + (import hy) + (if (not (= (type name) hy.HySymbol)) + (macro-error name "defn/a takes a name as first argument")) + (if (not (isinstance lambda-list hy.HyList)) + (macro-error name "defn/a takes a parameter list as second argument")) + `(setv ~name (fn/a ~lambda-list ~@body))) + (defmacro if-python2 [python2-form python3-form] "If running on python2, execute python2-form, else, execute python3-form" (import sys) diff --git a/tests/native_tests/py35_only_tests.hy b/tests/native_tests/py35_only_tests.hy index 716a9f8..7e144d7 100644 --- a/tests/native_tests/py35_only_tests.hy +++ b/tests/native_tests/py35_only_tests.hy @@ -5,6 +5,8 @@ ;; Tests where the emitted code relies on Python ≥3.5. ;; conftest.py skips this file when running on Python <3.5. +(import [asyncio [get-event-loop sleep]]) + (defn test-unpacking-pep448-1star [] (setv l [1 2 3]) @@ -24,3 +26,20 @@ (assert (= {1 "x" #**d1 #**d2 2 "y"} {"a" 1 "b" 2 "c" 3 "d" 4 1 "x" 2 "y"})) (defn fun [&optional a b c d e f] [a b c d e f]) (assert (= (fun #**d1 :e "eee" #**d2) [1 2 3 4 "eee" None]))) + + +(defn run-coroutine [coro] + "Run a coroutine until its done in the default event loop.""" + (.run_until_complete (get-event-loop) (coro))) + + +(defn test-fn/a [] + (assert (= (run-coroutine (fn/a [] (await (sleep 0)) [1 2 3])) + [1 2 3]))) + + +(defn test-defn/a [] + (defn/a coro-test [] + (await (sleep 0)) + [1 2 3]) + (assert (= (run-coroutine coro-test) [1 2 3])))