diff --git a/NEWS b/NEWS index 6580965..4a2a9e5 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,10 @@ Changes from 0.13.0 * `exec` now works under Python 2 * No TypeError from multi-arity defn returning values evaluating to None + [ Misc. Improvements ] + * `read`, `read_str`, and `eval` are exposed and documented as top-level + functions in the `hy` module + Changes from 0.12.1 [ Language Changes ] diff --git a/docs/language/interop.rst b/docs/language/interop.rst index 433679c..039d825 100644 --- a/docs/language/interop.rst +++ b/docs/language/interop.rst @@ -131,5 +131,17 @@ argument:: test() bar +Evaluating strings of Hy code from Python +----------------------------------------- +Evaluating a string (or ``file`` object) containing a Hy expression requires +two separate steps. First, use the ``read_str`` function (or ``read`` for a +``file`` object) to turn the expression into a Hy model:: + >>> import hy + >>> expr = hy.read_str("(- (/ (+ 1 3 88) 2) 8)") + +Then, use the ``eval`` function to evaluate it:: + + >>> hy.eval(expr) + 38.0 diff --git a/hy/__init__.py b/hy/__init__.py index a17ddbb..6b986d1 100644 --- a/hy/__init__.py +++ b/hy/__init__.py @@ -10,3 +10,7 @@ from hy.models import HyExpression, HyInteger, HyKeyword, HyComplex, HyString, H import hy.importer # NOQA # we import for side-effects. + + +from hy.core.language import read, read_str # NOQA +from hy.importer import hy_eval as eval # NOQA diff --git a/hy/core/language.hy b/hy/core/language.hy index 5f9378a..4504b6a 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -426,8 +426,8 @@ (defn read [&optional [from-file sys.stdin] [eof ""]] - "Read from input and returns a tokenized string. - Can take a given input buffer to read from" + "Read from input and returns a tokenized string. Can take a given input buffer + to read from, and a single byte as EOF (defaults to an empty string)" (setv buff "") (while True (setv inn (string (.readline from-file))) diff --git a/tests/importer/test_importer.py b/tests/importer/test_importer.py index 79b72da..9fa5aa5 100644 --- a/tests/importer/test_importer.py +++ b/tests/importer/test_importer.py @@ -2,12 +2,14 @@ # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. +import hy from hy.importer import (import_file_to_module, import_buffer_to_ast, MetaLoader, get_bytecode_path) from hy.errors import HyTypeError import os import ast import tempfile +from fractions import Fraction def test_basics(): @@ -64,3 +66,20 @@ def test_import_autocompiles(): os.remove(f.name) os.remove(get_bytecode_path(f.name)) + + +def test_eval(): + def eval_str(s): + return hy.eval(hy.read_str(s)) + + assert eval_str('[1 2 3]') == [1, 2, 3] + assert eval_str('{"dog" "bark" "cat" "meow"}') == { + 'dog': 'bark', 'cat': 'meow'} + assert eval_str('(, 1 2 3)') == (1, 2, 3) + assert eval_str('#{3 1 2}') == {1, 2, 3} + assert eval_str('1/2') == Fraction(1, 2) + assert eval_str('(.strip " fooooo ")') == 'fooooo' + assert eval_str( + '(if True "this is if true" "this is if false")') == "this is if true" + assert eval_str('(list-comp (pow num 2) (num (range 100)) (= (% num 2) 1))') == [ + pow(num, 2) for num in range(100) if num % 2 == 1]