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.
This commit is contained in:
Paul Tagliamonte 2013-06-29 11:50:31 -04:00
parent b65c2a4596
commit 86af7eacf1
7 changed files with 60 additions and 23 deletions

View File

@ -8,7 +8,7 @@ python:
# command to install dependencies # command to install dependencies
install: install:
- pip install -r requirements.txt --use-mirrors - 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 == '2.7' ]]; then pip install astor --use-mirrors; fi
- if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then pip install astor --use-mirrors; fi - if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then pip install astor --use-mirrors; fi
- python setup.py -q install - python setup.py -q install

View File

@ -36,14 +36,14 @@ from hy.models.list import HyList
from hy.models.dict import HyDict from hy.models.dict import HyDict
import hy.importer import hy.importer
from hy.core import process
from hy.util import str_type
from hy.macros import require from hy.macros import require
from hy.util import str_type
from hy.core import process
import codecs
import traceback import traceback
import importlib
import codecs
import ast import ast
import sys import sys
@ -61,6 +61,17 @@ def compile_time_ns(module_name):
return ns 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): class HyCompileError(HyError):
def __init__(self, exception, traceback=None): def __init__(self, exception, traceback=None):
self.exception = exception self.exception = exception
@ -339,6 +350,9 @@ class HyASTCompiler(object):
self.anon_var_count = 0 self.anon_var_count = 0
self.imports = defaultdict(set) self.imports = defaultdict(set)
self.module_name = module_name 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): def get_anon_var(self):
self.anon_var_count += 1 self.anon_var_count += 1
@ -1432,6 +1446,10 @@ class HyASTCompiler(object):
ret = self.compile_atom(fn, expression) ret = self.compile_atom(fn, expression)
if ret: if ret:
return ret return ret
if fn in _stdlib:
self.imports[_stdlib[fn]].add(fn)
if fn.startswith("."): if fn.startswith("."):
# (.split "test test") -> "test test".split() # (.split "test test") -> "test test".split()

View File

@ -24,6 +24,10 @@ MACROS = [
"hy.core.bootstrap", "hy.core.bootstrap",
] ]
STDLIB = [
"hy.core.language"
]
def process(tree, module_name): def process(tree, module_name):
load_macros() load_macros()

View File

@ -137,21 +137,6 @@ def let_macro(variables, *body):
return HyExpression([expr + list(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") @macro("when")
def when_macro(test, *body): def when_macro(test, *body):
return HyExpression([ return HyExpression([

22
hy/core/language.hy Normal file
View File

@ -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"])

View File

@ -385,9 +385,9 @@
(defn test-drop [] (defn test-drop []
"NATIVE: test drop" "NATIVE: test drop"
(assert (= (drop 0 [2 3]) [2 3])) (assert (= (list (drop 0 [2 3])) [2 3]))
(assert (= (drop 1 [2 3]) [3])) (assert (= (list (drop 1 [2 3])) [3]))
(assert (= (drop 2 [2 3]) []))) (assert (= (list (drop 2 [2 3])) [])))
(defn test-rest [] (defn test-rest []
@ -741,6 +741,13 @@
(assert (= "test" (:foo {:foo "test"})))) (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 [] (defn test-break-breaking []
"NATIVE: test checking if break actually breaks" "NATIVE: test checking if break actually breaks"
(defn holy-grail [] (for [x (range 10)] (if (= x 5) (break))) x) (defn holy-grail [] (for [x (range 10)] (if (= x 5) (break))) x)

View File

@ -26,6 +26,7 @@ deps =
nose nose
setuptools setuptools
unittest2 unittest2
importlib
[testenv:flake8] [testenv:flake8]
deps = flake8 deps = flake8