From 52a0c8a870f5c03d1df001d8116c5f44fdcfc6c2 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Tue, 19 Sep 2017 16:35:33 -0700 Subject: [PATCH 1/2] Unify implementations of `eval-X-compile` --- hy/compiler.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 8ca12ae..ccd28e4 100755 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -2081,22 +2081,15 @@ class HyASTCompiler(object): expr = tag_macroexpand(tag, expression.pop(0), self) return self.compile(expr) - @builds("eval_and_compile") - def compile_eval_and_compile(self, expression): + @builds("eval_and_compile", "eval_when_compile") + def compile_eval_and_compile(self, expression, building): expression[0] = HySymbol("do") hy.importer.hy_eval(expression, compile_time_ns(self.module_name), self.module_name) - expression.pop(0) - return self._compile_branch(expression) - - @builds("eval_when_compile") - def compile_eval_when_compile(self, expression): - expression[0] = HySymbol("do") - hy.importer.hy_eval(expression, - compile_time_ns(self.module_name), - self.module_name) - return Result() + return (self._compile_branch(expression[1:]) + if building == "eval_and_compile" + else Result()) @builds(HyCons) def compile_cons(self, cons): From 1b3fc81f3fa7850553e0a0088e0ff55314721e8b Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Tue, 19 Sep 2017 17:04:05 -0700 Subject: [PATCH 2/2] Document `eval-X-compile` --- docs/language/api.rst | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/language/api.rst b/docs/language/api.rst index 63102c8..8f9b398 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -940,10 +940,38 @@ doto eval-and-compile ---------------- +``eval-and-compile`` is a special form that takes any number of forms. The input forms are evaluated as soon as the ``eval-and-compile`` form is compiled, instead of being deferred until run-time. The input forms are also left in the program so they can be executed at run-time as usual. So, if you compile and immediately execute a program (as calling ``hy foo.hy`` does when ``foo.hy`` doesn't have an up-to-date byte-compiled version), ``eval-and-compile`` forms will be evaluated twice. + +One possible use of ``eval-and-compile`` is to make a function available both at compile-time (so a macro can call it while expanding) and run-time (so it can be called like any other function):: + + (eval-and-compile + (defn add [x y] + (+ x y))) + + (defmacro m [x] + (add x 2)) + + (print (m 3)) ; prints 5 + (print (add 3 6)) ; prints 9 + +Had the ``defn`` not been wrapped in ``eval-and-compile``, ``m`` wouldn't be able to call ``add``, because when the compiler was expanding ``(m 3)``, ``add`` wouldn't exist yet. eval-when-compile ----------------- +``eval-when-compile`` is like ``eval-and-compile``, but the code isn't executed at run-time. Hence, ``eval-when-compile`` doesn't directly contribute any code to the final program, although it can still change Hy's state while compiling (e.g., by defining a function). + +.. code-block:: clj + + (eval-when-compile + (defn add [x y] + (+ x y))) + + (defmacro m [x] + (add x 2)) + + (print (m 3)) ; prints 5 + (print (add 3 6)) ; raises NameError: name 'add' is not defined first -----