From 86af7eacf1396d068b5bb36db4794d0f621a0f87 Mon Sep 17 00:00:00 2001 From: Paul Tagliamonte Date: Sat, 29 Jun 2013 11:50:31 -0400 Subject: [PATCH] Add in a new core language file. This will let us implement common functions seen in other lisps, and allow them to be importable, without explicit imports. The goal is to keep this as small as we can; we don't want too much magic. I've added `take' and `drop' as examples of what we can do. --- .travis.yml | 2 +- hy/compiler.py | 26 ++++++++++++++++++++++---- hy/core/__init__.py | 4 ++++ hy/core/bootstrap.py | 15 --------------- hy/core/language.hy | 22 ++++++++++++++++++++++ tests/native_tests/language.hy | 13 ++++++++++--- tox.ini | 1 + 7 files changed, 60 insertions(+), 23 deletions(-) create mode 100644 hy/core/language.hy diff --git a/.travis.yml b/.travis.yml index 4dcaa29..1b8ef6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ python: # command to install dependencies install: - pip install -r requirements.txt --use-mirrors - - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2 astor --use-mirrors; fi + - if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install importlib unittest2 astor --use-mirrors; fi - if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install astor --use-mirrors; fi - if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then pip install astor --use-mirrors; fi - python setup.py -q install diff --git a/hy/compiler.py b/hy/compiler.py index d92ede3..9259a9b 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -36,14 +36,14 @@ from hy.models.list import HyList from hy.models.dict import HyDict import hy.importer -from hy.core import process - -from hy.util import str_type from hy.macros import require +from hy.util import str_type +from hy.core import process -import codecs import traceback +import importlib +import codecs import ast import sys @@ -61,6 +61,17 @@ def compile_time_ns(module_name): return ns +_stdlib = {} + + +def load_stdlib(): + import hy.core + for module in hy.core.STDLIB: + mod = importlib.import_module(module) + for e in mod.EXPORTS: + _stdlib[e] = module + + class HyCompileError(HyError): def __init__(self, exception, traceback=None): self.exception = exception @@ -339,6 +350,9 @@ class HyASTCompiler(object): self.anon_var_count = 0 self.imports = defaultdict(set) self.module_name = module_name + if not module_name.startswith("hy.core"): + # everything in core needs to be explicit. + load_stdlib() def get_anon_var(self): self.anon_var_count += 1 @@ -1432,6 +1446,10 @@ class HyASTCompiler(object): ret = self.compile_atom(fn, expression) if ret: return ret + + if fn in _stdlib: + self.imports[_stdlib[fn]].add(fn) + if fn.startswith("."): # (.split "test test") -> "test test".split() diff --git a/hy/core/__init__.py b/hy/core/__init__.py index df38a3d..2c29df6 100644 --- a/hy/core/__init__.py +++ b/hy/core/__init__.py @@ -24,6 +24,10 @@ MACROS = [ "hy.core.bootstrap", ] +STDLIB = [ + "hy.core.language" +] + def process(tree, module_name): load_macros() diff --git a/hy/core/bootstrap.py b/hy/core/bootstrap.py index 5cf4106..6b9171f 100644 --- a/hy/core/bootstrap.py +++ b/hy/core/bootstrap.py @@ -137,21 +137,6 @@ def let_macro(variables, *body): return HyExpression([expr + list(body)]) -@macro("take") -def take_macro(n, lst): - return HyExpression([HySymbol('slice'), - lst, - HyInteger(0), - HyInteger(n)]) - - -@macro("drop") -def drop_macro(n, lst): - return HyExpression([HySymbol('slice'), - lst, - HyInteger(n)]) - - @macro("when") def when_macro(test, *body): return HyExpression([ diff --git a/hy/core/language.hy b/hy/core/language.hy new file mode 100644 index 0000000..1401db5 --- /dev/null +++ b/hy/core/language.hy @@ -0,0 +1,22 @@ +;;;; This contains some of the core Hy functions used +;;;; to make functional programming slightly easier. +;;;; + + +(defn take [count what] + "Take `count` elements from `what`, or the whole set if the total + number of entries in `what` is less than `count`." + (setv what (iter what)) + (for [i (range count)] + (yield (next what)))) + + +(defn drop [count coll] + "Drop `count` elements from `coll` and return the iter" + (let [ [citer (iter coll)] ] + (for [i (range count)] + (next citer)) + citer)) + + +(def *exports* ["take" "drop"]) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 03c62b0..d8f3825 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -385,9 +385,9 @@ (defn test-drop [] "NATIVE: test drop" - (assert (= (drop 0 [2 3]) [2 3])) - (assert (= (drop 1 [2 3]) [3])) - (assert (= (drop 2 [2 3]) []))) + (assert (= (list (drop 0 [2 3])) [2 3])) + (assert (= (list (drop 1 [2 3])) [3])) + (assert (= (list (drop 2 [2 3])) []))) (defn test-rest [] @@ -741,6 +741,13 @@ (assert (= "test" (:foo {:foo "test"})))) +(defn test-take [] + "NATIVE: test the take operator" + (assert (= [1 2 3] (list (take 3 [1 2 3])))) + (assert (= [1 2 3] (list (take 4 [1 2 3])))) + (assert (= [1 2] (list (take 2 [1 2 4]))))) + + (defn test-break-breaking [] "NATIVE: test checking if break actually breaks" (defn holy-grail [] (for [x (range 10)] (if (= x 5) (break))) x) diff --git a/tox.ini b/tox.ini index 1fb410a..dc99df8 100644 --- a/tox.ini +++ b/tox.ini @@ -26,6 +26,7 @@ deps = nose setuptools unittest2 + importlib [testenv:flake8] deps = flake8