diff --git a/NEWS b/NEWS index b99e228..f8a209a 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ Changes from 0.13.0 * Single-character "sharp macros" changed to "tag macros", which can have longer names * Periods are no longer allowed in keywords + * `eval` is now a function instead of a special form [ Bug Fixes ] * Numeric literals are no longer parsed as symbols when followed by a dot diff --git a/docs/language/api.rst b/docs/language/api.rst index 0058c7d..5ed646d 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -863,27 +863,6 @@ doto => collection [2 1] -eval ----- - -``eval`` evaluates a quoted expression and returns the value. The optional -second and third arguments specify the dictionary of globals to use and the -module name. The globals dictionary defaults to ``(local)`` and the module name -defaults to the name of the current module. - -.. code-block:: clj - - => (eval '(print "Hello World")) - "Hello World" - -If you want to evaluate a string, use ``read-str`` to convert it to a -form first: - -.. code-block:: clj - - => (eval (read-str "(+ 1 1)")) - 2 - eval-and-compile ---------------- diff --git a/docs/language/core.rst b/docs/language/core.rst index b52cef4..21c111b 100644 --- a/docs/language/core.rst +++ b/docs/language/core.rst @@ -230,6 +230,30 @@ Returns ``True`` if *coll* is empty. Equivalent to ``(= 0 (len coll))``. False +.. _eval-fn: + +eval +---- + +``eval`` evaluates a quoted expression and returns the value. The optional +second and third arguments specify the dictionary of globals to use and the +module name. The globals dictionary defaults to ``(local)`` and the module name +defaults to the name of the current module. + +.. code-block:: clj + + => (eval '(print "Hello World")) + "Hello World" + +If you want to evaluate a string, use ``read-str`` to convert it to a +form first: + +.. code-block:: clj + + => (eval (read-str "(+ 1 1)")) + 2 + + .. _every?-fn: every? diff --git a/hy/compiler.py b/hy/compiler.py index 437495d..f864fcf 100755 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -706,31 +706,6 @@ class HyASTCompiler(object): raise HyTypeError(expr, "`%s' can't be used at the top-level" % expr[0]) - @builds("eval") - @checkargs(min=1, max=3) - def compile_eval(self, expr): - expr.pop(0) - - if not isinstance(expr[0], (HyExpression, HySymbol)): - raise HyTypeError(expr, "expression expected as first argument") - - elist = [HySymbol("hy_eval")] + [expr[0]] - if len(expr) >= 2: - elist.append(expr[1]) - else: - elist.append(HyExpression([HySymbol("locals")])) - - if len(expr) == 3: - elist.append(expr[2]) - else: - elist.append(HyString(self.module_name)) - - ret = self.compile(HyExpression(elist).replace(expr)) - - ret.add_imports("hy.importer", ["hy_eval"]) - - return ret - @builds("do") def compile_do(self, expression): expression.pop(0) diff --git a/hy/core/language.hy b/hy/core/language.hy index d498c45..25fadd7 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -19,6 +19,7 @@ (import [hy.models [HyCons HySymbol HyKeyword]]) (import [hy.lex [LexException PrematureEndOfInput tokenize]]) (import [hy.compiler [HyASTCompiler]]) +(import [hy.importer [hy-eval :as eval]]) (defn butlast [coll] "Returns coll except of last element." @@ -469,7 +470,7 @@ (def *exports* '[*map accumulate butlast calling-module-name chain coll? combinations comp complement compress cons cons? constantly count cycle dec distinct - disassemble drop drop-last drop-while empty? even? every? first filter + disassemble drop drop-last drop-while empty? eval even? every? first filter flatten float? fraction gensym group-by identity inc input instance? integer integer? integer-char? interleave interpose islice iterable? iterate iterator? juxt keyword keyword? last list* macroexpand diff --git a/hy/importer.py b/hy/importer.py index ec3b606..6f40d3d 100644 --- a/hy/importer.py +++ b/hy/importer.py @@ -14,6 +14,7 @@ import struct import imp import sys import ast +import inspect import os import __future__ @@ -142,7 +143,14 @@ def import_buffer_to_module(module_name, buf): return mod -def hy_eval(hytree, namespace, module_name, ast_callback=None): +def hy_eval(hytree, namespace=None, module_name=None, ast_callback=None): + if namespace is None: + frame = inspect.stack()[1][0] + namespace = inspect.getargvalues(frame).locals + if module_name is None: + m = inspect.getmodule(inspect.stack()[1][0]) + module_name = '__eval__' if m is None else m.__name__ + foo = HyObject() foo.start_line = 0 foo.end_line = 0 diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 5b2421f..4d7c262 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -1087,10 +1087,11 @@ (defn test-eval-failure [] "NATIVE: test eval failure modes" ; yo dawg - (try (eval '(eval)) (except [e HyTypeError]) (else (assert False))) - (try (eval '(eval "snafu")) (except [e HyTypeError]) (else (assert False))) + (import [hy.compiler [HyCompileError]]) + (try (eval '(eval)) (except [e TypeError]) (else (assert False))) + (try (eval '(eval "snafu")) (except [e HyCompileError]) (else (assert False))) (try (eval 'False []) (except [e HyTypeError]) (else (assert False))) - (try (eval 'False {} 1) (except [e HyTypeError]) (else (assert False)))) + (try (eval 'False {} 1) (except [e TypeError]) (else (assert False)))) (defn test-import-syntax []