diff --git a/.travis.yml b/.travis.yml index 2b9beda..1136a62 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,9 @@ python: - "3.3" - "2.6" # command to install dependencies -install: "pip install -r requirements.txt --use-mirrors" +install: + - pip install -r requirements.txt --use-mirrors + - python setup.py -q install # # command to run tests script: nosetests notifications: diff --git a/AUTHORS b/AUTHORS index 9f04615..74d26c9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,3 +9,4 @@ * Gergely Nagy * Konrad Hinsen * Vladimir Gorbunov +* John Jacobsen diff --git a/bin/hy b/bin/hy index 28dbe3e..5554f00 100755 --- a/bin/hy +++ b/bin/hy @@ -21,7 +21,7 @@ from hy.lex.states import Idle, LexException from hy.lex.machine import Machine from hy.compiler import hy_compile from hy.core import process -from hy.importer import compile_ +from hy.importer import ast_compile import hy.completer @@ -59,7 +59,7 @@ class HyREPL(code.InteractiveConsole): _machine = Machine(Idle, 1, 0) try: _ast = hy_compile(tokens, root=ast.Interactive) - code = compile_(_ast, filename, symbol) + code = ast_compile(_ast, filename, symbol) except Exception: self.showtraceback() return False diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 14b7193..1db2144 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -324,6 +324,18 @@ Comments start with semicolons: ; (print "but this will not") (+ 1 2 3) ; we'll execute the addition, but not this comment! +Python's context managers ('with' statements) are used like this: + +.. code-block:: clj + + (with [f (file "/tmp/data.in")] + (print (.read f))) + +which is equivalent to:: + + with file("/tmp/data.in") as f: + print f.read() + And yes, we do have lisp comprehensions! In Python you might do:: odds_squared = [ @@ -408,6 +420,8 @@ Much more readable, no! Use the threading macro! TODO ==== + - How do I index into arrays or dictionaries? + - How do I do array ranges? e.g. x[5:] or y[2:10] - How do I define classes? - Blow your mind with macros! - Where's my banana??? diff --git a/hy/importer.py b/hy/importer.py index 5406be0..548eb1f 100644 --- a/hy/importer.py +++ b/hy/importer.py @@ -34,45 +34,47 @@ import os import __future__ if sys.version_info[0] >= 3: - from io import StringIO long_type = int else: - from StringIO import StringIO # NOQA import __builtin__ long_type = long # NOQA -def compile_(ast, filename, mode): +def ast_compile(ast, filename, mode): + """Compile AST. + Like Python's compile, but with some special flags.""" return compile(ast, filename, mode, __future__.CO_FUTURE_DIVISION) -def import_buffer_to_hst(fd): - tree = tokenize(fd.read() + "\n") - tree = process(tree) - return tree +def import_buffer_to_hst(buf): + """Import content from buf and return an Hy AST.""" + return process(tokenize(buf + "\n")) def import_file_to_hst(fpath): - return import_buffer_to_hst(open(fpath, 'r', encoding='utf-8')) + """Import content from fpath and return an Hy AST.""" + with open(fpath, 'r', encoding='utf-8') as f: + return import_buffer_to_hst(f.read()) + + +def import_buffer_to_ast(buf): + """ Import content from buf and return a Python AST.""" + return hy_compile(import_buffer_to_hst(buf)) def import_file_to_ast(fpath): - tree = import_file_to_hst(fpath) - _ast = hy_compile(tree) - return _ast + """Import content from fpath and return a Python AST.""" + return hy_compile(import_file_to_hst(fpath)) -def import_string_to_ast(buff): - tree = import_buffer_to_hst(StringIO(buff)) - _ast = hy_compile(tree) - return _ast +def import_file_to_module(module_name, fpath): + """Import content from fpath and puts it into a Python module. - -def import_file_to_module(name, fpath): + Returns the module.""" _ast = import_file_to_ast(fpath) - mod = imp.new_module(name) + mod = imp.new_module(module_name) mod.__file__ = fpath - eval(compile_(_ast, fpath, "exec"), mod.__dict__) + eval(ast_compile(_ast, fpath, "exec"), mod.__dict__) return mod @@ -84,7 +86,7 @@ def hy_eval(hytree, namespace): foo.end_column = 0 hytree.replace(foo) _ast = hy_compile(hytree, root=ast.Expression) - return eval(compile_(_ast, "", "eval"), namespace) + return eval(ast_compile(_ast, "", "eval"), namespace) def write_hy_as_pyc(fname): @@ -96,7 +98,7 @@ def write_hy_as_pyc(fname): timestamp = long_type(st.st_mtime) _ast = import_file_to_ast(fname) - code = compile_(_ast, fname, "exec") + code = ast_compile(_ast, fname, "exec") cfile = "%s.pyc" % fname[:-len(".hy")] if sys.version_info[0] >= 3: @@ -118,7 +120,10 @@ def write_hy_as_pyc(fname): fc.write(MAGIC) -class HyFinder(object): +class MetaLoader(object): + def __init__(self, path): + self.path = path + def is_package(self, fullname): dirpath = "/".join(fullname.split(".")) for pth in sys.path: @@ -128,33 +133,20 @@ class HyFinder(object): return True return False - def find_on_path(self, fullname): - fls = ["%s/__init__.hy", "%s.hy"] - dirpath = "/".join(fullname.split(".")) - - for pth in sys.path: - pth = os.path.abspath(pth) - for fp in fls: - composed_path = fp % ("%s/%s" % (pth, dirpath)) - if os.path.exists(composed_path): - return composed_path - - -class MetaLoader(HyFinder): def load_module(self, fullname): if fullname in sys.modules: return sys.modules[fullname] - pth = self.find_on_path(fullname) - if pth is None: + if not self.path: return sys.modules[fullname] = None - mod = import_file_to_module(fullname, pth) + mod = import_file_to_module(fullname, + self.path) ispkg = self.is_package(fullname) - mod.__file__ = pth + mod.__file__ = self.path mod.__loader__ = self mod.__name__ = fullname @@ -168,12 +160,22 @@ class MetaLoader(HyFinder): return mod -class MetaImporter(HyFinder): +class MetaImporter(object): + def find_on_path(self, fullname): + fls = ["%s/__init__.hy", "%s.hy"] + dirpath = "/".join(fullname.split(".")) + + for pth in sys.path: + pth = os.path.abspath(pth) + for fp in fls: + composed_path = fp % ("%s/%s" % (pth, dirpath)) + if os.path.exists(composed_path): + return composed_path + def find_module(self, fullname, path=None): - pth = self.find_on_path(fullname) - if pth is None: - return - return MetaLoader() + path = self.find_on_path(fullname) + if path: + return MetaLoader(path) sys.meta_path.append(MetaImporter()) diff --git a/tests/importer/test_importer.py b/tests/importer/test_importer.py index ce5627c..2918c65 100644 --- a/tests/importer/test_importer.py +++ b/tests/importer/test_importer.py @@ -1,4 +1,4 @@ -from hy.importer import import_file_to_module, import_string_to_ast +from hy.importer import import_file_to_module, import_buffer_to_ast import ast @@ -10,5 +10,5 @@ def test_basics(): def test_stringer(): "Make sure the basics of the importer work" - _ast = import_string_to_ast("(defn square [x] (* x x))") + _ast = import_buffer_to_ast("(defn square [x] (* x x))") assert type(_ast.body[0]) == ast.FunctionDef diff --git a/tests/test_bin.py b/tests/test_bin.py new file mode 100644 index 0000000..ff05516 --- /dev/null +++ b/tests/test_bin.py @@ -0,0 +1,8 @@ +import subprocess + + +def test_bin_hy(): + p = subprocess.Popen("echo | bin/hy", + shell=True) + p.wait() + assert p.returncode == 0