Merge pull request #1430 from Kodiologist/eval-situation

Refactoring and docs for eval-X-compile
This commit is contained in:
Kodi Arfer 2017-11-02 21:45:33 -07:00 committed by GitHub
commit 97987d739c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 12 deletions

View File

@ -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
-----

View File

@ -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):