Merge branch 'master' into pr/579
This commit is contained in:
commit
b92c19c73c
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
.git
|
11
.mailmap
Normal file
11
.mailmap
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
Paul R. Tagliamonte <paultag@debian.org> Paul Tagliamonte <paultag@debian.org>
|
||||||
|
Paul R. Tagliamonte <paultag@debian.org> Paul Tagliamonte <tag@pault.ag>
|
||||||
|
Paul R. Tagliamonte <paultag@debian.org> Paul Tagliamonte <paultag@sunlightfoundation.com>
|
||||||
|
Paul R. Tagliamonte <paultag@debian.org> Paul Tagliamonte <paultag@ubuntu.com>
|
||||||
|
Morten Linderud <morten@linderud.pw> Foxboron <morten@linderud.pw>
|
||||||
|
James King <james@agentultra.com> agentultra <james@agentultra.com>
|
||||||
|
James King <james@agentultra.com> J Kenneth King <james@agentultra.com>
|
||||||
|
Abhishek L <abhishek.lekshmanan@gmail.com> <abhishekl.2006@gmail.com>
|
||||||
|
Bob Tolbert <bob@tolbert.org> Bob Tolbert <bob@eyesopen.com>
|
||||||
|
Guillermo Vaya <guivaya@gmail.com> Guillermo Vaya <guillermo.vaya@gigas.com>
|
||||||
|
Gergely Nagy <algernon@balabit.hu> Gergely Nagy <algernon@madhouse-project.org>
|
10
.travis.yml
10
.travis.yml
@ -6,15 +6,11 @@ python:
|
|||||||
- "3.2"
|
- "3.2"
|
||||||
- "3.3"
|
- "3.3"
|
||||||
- "3.4"
|
- "3.4"
|
||||||
# command to install dependencies
|
cache:
|
||||||
install:
|
- $HOME/.pip-cache
|
||||||
- pip install -r requirements-dev.txt
|
|
||||||
- pip install coveralls
|
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi # needs for running tests
|
|
||||||
- pip install --allow-all-external -e .
|
|
||||||
# command to run tests
|
# command to run tests
|
||||||
script: make travis
|
script: make travis
|
||||||
after_success: coveralls
|
after_success: make coveralls
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
- paultag@gmail.com
|
- paultag@gmail.com
|
||||||
|
7
AUTHORS
7
AUTHORS
@ -42,7 +42,12 @@
|
|||||||
* Halit Alptekin <info@halitalptekin.com>
|
* Halit Alptekin <info@halitalptekin.com>
|
||||||
* Richard Parsons <richard.lee.parsons@gmail.com>
|
* Richard Parsons <richard.lee.parsons@gmail.com>
|
||||||
* han semaj <sangho.nah@gmail.com>
|
* han semaj <sangho.nah@gmail.com>
|
||||||
* kirbyfan64 <kirbyfan64@users.noreply.github.com>
|
* Ryan Gonzalez <rymg19@gmail.com>
|
||||||
* Brendan Curran-Johnson <brendan@bcjbcj.ca>
|
* Brendan Curran-Johnson <brendan@bcjbcj.ca>
|
||||||
* Ivan Kozik <ivan@ludios.org>
|
* Ivan Kozik <ivan@ludios.org>
|
||||||
* Allison Kaptur <allison.kaptur@gmail.com>
|
* Allison Kaptur <allison.kaptur@gmail.com>
|
||||||
|
* Matthew Wampler-Doty <matthew.wampler.doty@gmail.com>
|
||||||
|
* Tianon Gravi <admwiggin@gmail.com>
|
||||||
|
* Ian Denhardt <ian@zenhack.net>
|
||||||
|
* Ruslan Prokopiev <bismigalis@gmail.com>
|
||||||
|
* Alexander Artemenko <svetlyak.40wt@gmail.com>
|
||||||
|
44
CONTRIBUTING.rst
Normal file
44
CONTRIBUTING.rst
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
Contributions are welcome & greatly appreciated, every little bit
|
||||||
|
helps in making Hy more awesome.
|
||||||
|
|
||||||
|
Pull requests are great! We love them, here is a quick guide:
|
||||||
|
|
||||||
|
- Fork the repo, create a topic branch for a feature/fix. Avoid
|
||||||
|
making changes directly on the master branch
|
||||||
|
|
||||||
|
- All incoming features should be accompanied with tests
|
||||||
|
|
||||||
|
- Before you submit a PR, please run the tests and check your code
|
||||||
|
against the style guide. You can do both these things at once::
|
||||||
|
|
||||||
|
$ make d
|
||||||
|
|
||||||
|
- Make commits into logical units, so that it is easier to track &
|
||||||
|
navigate later. Before submitting a PR, try squashing the commits
|
||||||
|
into changesets that are easy to come back to later. Also make sure
|
||||||
|
you don't leave spurious whitespace in the changesets, this avoids
|
||||||
|
creation of whitespace fix commits later.
|
||||||
|
|
||||||
|
- As far as commit messages go, try to adhere to
|
||||||
|
the following:
|
||||||
|
|
||||||
|
+ Try sticking to the 50 character limit for the first line of git
|
||||||
|
commit messages
|
||||||
|
|
||||||
|
+ For more explanations etc. follow this up with a blank line and
|
||||||
|
continue describing the commit in detail
|
||||||
|
|
||||||
|
|
||||||
|
- Finally add yourself to the AUTHORS file (as a separate commit), you
|
||||||
|
deserve it :)
|
||||||
|
|
||||||
|
- All incoming changes need to be acked by 2 different members of
|
||||||
|
Hylang's core team. Additional review is clearly welcome, but we need
|
||||||
|
a minimum of 2 signoffs for any change.
|
||||||
|
|
||||||
|
- If a core member is sending in a PR, please find 2 core members that doesn't
|
||||||
|
include the PR submitter. The idea here is that one can work with the PR
|
||||||
|
author, and a second acks the entire change set.
|
||||||
|
|
||||||
|
- For documentation & other trivial changes, we're good to merge after one
|
||||||
|
ACK. We've got low coverage, so it'd be great to keep that barrier low.
|
10
Dockerfile
Normal file
10
Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Base image
|
||||||
|
#
|
||||||
|
# VERSION 0.2
|
||||||
|
FROM python:3
|
||||||
|
MAINTAINER Paul R. Tagliamonte <paultag@debian.org>
|
||||||
|
|
||||||
|
ADD . /opt/hylang/hy
|
||||||
|
RUN pip3 install -e /opt/hylang/hy
|
||||||
|
|
||||||
|
CMD ["hy"]
|
50
Makefile
50
Makefile
@ -1,3 +1,21 @@
|
|||||||
|
pypy_url=http://buildbot.pypy.org/nightly/trunk/pypy-c-jit-latest-linux64.tar.bz2
|
||||||
|
pip_url=https://bootstrap.pypa.io/get-pip.py
|
||||||
|
python=python
|
||||||
|
pip=pip
|
||||||
|
coveralls=coveralls
|
||||||
|
nose=nosetests
|
||||||
|
pcache=$(HOME)/.pip-cache
|
||||||
|
|
||||||
|
ifeq (PyPy 2.4,$(findstring PyPy 2.4,$(shell python -V 2>&1 | tail -1)))
|
||||||
|
bad_pypy=1
|
||||||
|
python=./pypy
|
||||||
|
pip=./pip
|
||||||
|
coveralls=./coveralls
|
||||||
|
nose=./nosetests
|
||||||
|
else
|
||||||
|
bad_pypy=
|
||||||
|
endif
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@echo "No default step. Use setup.py"
|
@echo "No default step. Use setup.py"
|
||||||
@echo ""
|
@echo ""
|
||||||
@ -53,14 +71,42 @@ diff:
|
|||||||
|
|
||||||
r: d tox diff
|
r: d tox diff
|
||||||
|
|
||||||
travis:
|
python:
|
||||||
nosetests -s --with-coverage --cover-package hy
|
ifeq ($(bad_pypy),1)
|
||||||
|
# Due to stupid PyPy 2.4 bugs, a custom version needs to be downloaded
|
||||||
|
curl $(pypy_url) -o pypy.tbz2
|
||||||
|
tar xf pypy.tbz2
|
||||||
|
ln -sf `pwd`/pypy-*/bin/pypy $(python)
|
||||||
|
curl $(pip_url) | $(python)
|
||||||
|
ln -sf `pwd`/pypy-*/bin/pip $(pip)
|
||||||
|
sudo $(pip) install nose
|
||||||
|
ln -sf `pwd`/pypy-*/bin/nosetests $(nose)
|
||||||
|
endif
|
||||||
|
ifeq (Python 2.6,$(findstring Python 2.6,$(shell python -V 2>&1)))
|
||||||
|
$(pip) install unittest2
|
||||||
|
endif
|
||||||
|
$(pip) install -r requirements-travis.txt --download-cache $(pcache)
|
||||||
|
$(pip) install coveralls --download-cache $(pcache)
|
||||||
|
$(pip) install --allow-all-external -e .
|
||||||
|
ifeq ($(bad_pypy),1)
|
||||||
|
ln -sf `pwd`/pypy-*/bin/coveralls $(coveralls)
|
||||||
|
endif
|
||||||
|
|
||||||
|
travis: python
|
||||||
|
ifeq ($(bad_pypy),1)
|
||||||
|
HY_DIR=`pwd`/pypy-*/bin $(nose) -s --with-coverage --cover-package hy
|
||||||
|
else
|
||||||
|
$(nose) -s --with-coverage --cover-package hy
|
||||||
|
endif
|
||||||
ifeq (PyPy,$(findstring PyPy,$(shell python -V 2>&1 | tail -1)))
|
ifeq (PyPy,$(findstring PyPy,$(shell python -V 2>&1 | tail -1)))
|
||||||
@echo "skipping flake8 on pypy"
|
@echo "skipping flake8 on pypy"
|
||||||
else
|
else
|
||||||
flake8 hy bin tests
|
flake8 hy bin tests
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
coveralls:
|
||||||
|
$(coveralls)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
@find . -name "*.pyc" -exec rm {} \;
|
@find . -name "*.pyc" -exec rm {} \;
|
||||||
@find -name __pycache__ -delete
|
@find -name __pycache__ -delete
|
||||||
|
58
NEWS
58
NEWS
@ -1,3 +1,49 @@
|
|||||||
|
Changes from 0.10.0
|
||||||
|
|
||||||
|
This release took some time (sorry, all my fault) but it's got a bunch of
|
||||||
|
really nice features. We hope you enjoy hacking with Hy as much as we enjoy
|
||||||
|
hacking on Hy.
|
||||||
|
|
||||||
|
In other news, we're Dockerized as an official library image!
|
||||||
|
<https://registry.hub.docker.com/_/hylang/>
|
||||||
|
|
||||||
|
$ docker run -it --rm hylang
|
||||||
|
hy 0.10.0 using CPython(default) 3.4.1 on Linux
|
||||||
|
=> ((lambda [] (print "Hello, World!")))
|
||||||
|
Hello, World!
|
||||||
|
|
||||||
|
- Hy Society
|
||||||
|
|
||||||
|
[ Language Changes ]
|
||||||
|
* Implement raise :from, Python 3 only.
|
||||||
|
* defmain macro
|
||||||
|
* name & keyword functions added to core
|
||||||
|
* (read) added to core
|
||||||
|
* shadow added to core
|
||||||
|
* New functions interleave interpose zip_longest added to core
|
||||||
|
* nth returns default value when out of bounds
|
||||||
|
* merge-with added
|
||||||
|
* doto macro added
|
||||||
|
* keyword? to findout keywords
|
||||||
|
* setv no longer allows "." in names
|
||||||
|
|
||||||
|
[Internals ]
|
||||||
|
* Builtins reimplemented in terms of python stdlib
|
||||||
|
* gensyms (defmacro/g!) handles non-string types better
|
||||||
|
|
||||||
|
[Tools]
|
||||||
|
* Added hy2py to installed scripts
|
||||||
|
|
||||||
|
[ Misc. Fixes ]
|
||||||
|
* Symbols like true, false, none can't be assigned
|
||||||
|
* Set sys.argv default to [''] like Python does
|
||||||
|
* REPL displays the the python version and platform at startup
|
||||||
|
* Dockerfile added for https://registry.hub.docker.com/_/hylang/
|
||||||
|
|
||||||
|
[ Contrib changes ]
|
||||||
|
* Fix ap-first and ap-last for failure conditions
|
||||||
|
|
||||||
|
|
||||||
Changes from 0.9.12
|
Changes from 0.9.12
|
||||||
|
|
||||||
0.10.0 - the "oh man I'm late for PyCon" release
|
0.10.0 - the "oh man I'm late for PyCon" release
|
||||||
@ -60,7 +106,7 @@ Changes from 0.9.12
|
|||||||
* "clean" target added to Makefile
|
* "clean" target added to Makefile
|
||||||
* hy2py supports a bunch of commandline options to show AST, source etc.
|
* hy2py supports a bunch of commandline options to show AST, source etc.
|
||||||
* Sub-object mangling: every identifier is split along the dots & mangled
|
* Sub-object mangling: every identifier is split along the dots & mangled
|
||||||
seperately
|
separately
|
||||||
|
|
||||||
[ Bug Fixes ]
|
[ Bug Fixes ]
|
||||||
* Empty MacroExpansions work as expected
|
* Empty MacroExpansions work as expected
|
||||||
@ -88,7 +134,7 @@ Changes from Hy 0.9.11
|
|||||||
what exactly was added.
|
what exactly was added.
|
||||||
|
|
||||||
The biggest feature, Reader Macros, landed later
|
The biggest feature, Reader Macros, landed later
|
||||||
in the cycle, but were big enough to warrent a release on it's
|
in the cycle, but were big enough to warrant a release on its
|
||||||
own. A huge thanks goes to Foxboron for implementing them
|
own. A huge thanks goes to Foxboron for implementing them
|
||||||
and a massive hug goes out to olasd for providing ongoing
|
and a massive hug goes out to olasd for providing ongoing
|
||||||
reviews during the development.
|
reviews during the development.
|
||||||
@ -267,7 +313,7 @@ Changes from Hy 0.9.6
|
|||||||
|
|
||||||
* UTF-8 encoded hy symbols are now hy_... rather than __hy_..., it's
|
* UTF-8 encoded hy symbols are now hy_... rather than __hy_..., it's
|
||||||
silly to prefex them as such. (PT)
|
silly to prefex them as such. (PT)
|
||||||
* `j' is no longer always intepreted as a complex number; we use it much
|
* `j' is no longer always interpreted as a complex number; we use it much
|
||||||
more as a symbol. (ND)
|
more as a symbol. (ND)
|
||||||
* (decorate-with) has been moved to (with-decorate) (JD)
|
* (decorate-with) has been moved to (with-decorate) (JD)
|
||||||
* New (unless) macro (JD)
|
* New (unless) macro (JD)
|
||||||
@ -286,7 +332,7 @@ Changes from Hy 0.9.6
|
|||||||
and jd for making this happen. This solves just an insane number
|
and jd for making this happen. This solves just an insane number
|
||||||
of bugs. (ND, PT, JD)
|
of bugs. (ND, PT, JD)
|
||||||
* Eval no longer sucks with statements (ND)
|
* Eval no longer sucks with statements (ND)
|
||||||
* New magic binary flags / mis fixes with the hy intepreter
|
* New magic binary flags / mis fixes with the hy interpreter
|
||||||
(WKG + @eigenhombre)
|
(WKG + @eigenhombre)
|
||||||
|
|
||||||
|
|
||||||
@ -311,7 +357,7 @@ Changes from Hy 0.9.5
|
|||||||
=============== WARNING: WARNING: READ ME: READ ME: ===================
|
=============== WARNING: WARNING: READ ME: READ ME: ===================
|
||||||
From here on out, we will only support "future division" as part of hy.
|
From here on out, we will only support "future division" as part of hy.
|
||||||
This is actually quite a pain for us, but it's going to be quite an
|
This is actually quite a pain for us, but it's going to be quite an
|
||||||
amazing feautre.
|
amazing feature.
|
||||||
|
|
||||||
This also normalizes behavior from Py 2 --> Py 3.
|
This also normalizes behavior from Py 2 --> Py 3.
|
||||||
|
|
||||||
@ -346,7 +392,7 @@ Changes from Hy 0.9.4
|
|||||||
|
|
||||||
* Statements in the `fn' path early will not return anymore. (PT)
|
* Statements in the `fn' path early will not return anymore. (PT)
|
||||||
* Added "not" as the inline "not" operator. It's advised to still
|
* Added "not" as the inline "not" operator. It's advised to still
|
||||||
use "not-in" or "is-not" rather then nesting. (JD)
|
use "not-in" or "is-not" rather than nesting. (JD)
|
||||||
* `let' macro added (PT)
|
* `let' macro added (PT)
|
||||||
* Added "~" as the "invert" operator. (JD)
|
* Added "~" as the "invert" operator. (JD)
|
||||||
* `catch' now accepts a new format: (JD)
|
* `catch' now accepts a new format: (JD)
|
||||||
|
@ -25,7 +25,7 @@ OK, so, why?
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
Well. Python is awesome. So awesome, that we have so many tools to alter the
|
Well. Python is awesome. So awesome, that we have so many tools to alter the
|
||||||
languge in a *core* way, but we never use them.
|
language in a *core* way, but we never use them.
|
||||||
|
|
||||||
Why?
|
Why?
|
||||||
|
|
||||||
|
@ -11,13 +11,13 @@ args and/or kwargs. Inspired by clojures take on `defn`.
|
|||||||
|
|
||||||
=> (require hy.contrib.multi)
|
=> (require hy.contrib.multi)
|
||||||
=> (defmulti fun
|
=> (defmulti fun
|
||||||
... ([a] a)
|
... ([a] "a")
|
||||||
... ([a b] "a b")
|
... ([a b] "a b")
|
||||||
... ([a b c] "a b c"))
|
... ([a b c] "a b c"))
|
||||||
=> (fun 1 2 3)
|
|
||||||
'a b c'
|
|
||||||
=> (fun a b)
|
|
||||||
"a b"
|
|
||||||
=> (fun 1)
|
=> (fun 1)
|
||||||
1
|
"a"
|
||||||
|
=> (fun 1 2)
|
||||||
|
"a b"
|
||||||
|
=> (fun 1 2 3)
|
||||||
|
"a b c"
|
||||||
|
|
||||||
|
@ -13,3 +13,4 @@
|
|||||||
* `Bob Tolbert <https://github.com/rwtolbert>`_
|
* `Bob Tolbert <https://github.com/rwtolbert>`_
|
||||||
* `Berker Peksag <https://github.com/berkerpeksag>`_
|
* `Berker Peksag <https://github.com/berkerpeksag>`_
|
||||||
* `Clinton N. Dreisbach <https://github.com/cndreisbach>`_
|
* `Clinton N. Dreisbach <https://github.com/cndreisbach>`_
|
||||||
|
* `han semaj <https://github.com/microamp>`_
|
||||||
|
@ -89,26 +89,10 @@ To build the docs in HTML::
|
|||||||
Write docs---docs are good! Even this doc!
|
Write docs---docs are good! Even this doc!
|
||||||
|
|
||||||
|
|
||||||
Core Development Rules
|
Contributing
|
||||||
======================
|
============
|
||||||
|
|
||||||
Pull requests are good!
|
|
||||||
|
|
||||||
Before you submit a PR, please run the tests and check your code against the style guide. You can do both these things at once::
|
|
||||||
|
|
||||||
$ make d
|
|
||||||
|
|
||||||
All incoming changes need to be acked by 2 different members of Hylang's
|
|
||||||
core team. Additional review is clearly welcome, but we need a minimum of
|
|
||||||
2 signoffs for any change.
|
|
||||||
|
|
||||||
If a core member is sending in a PR, please find 2 core members that don't
|
|
||||||
include the PR submitter. The idea here is that one can work with the PR
|
|
||||||
author, and a second acks the entire change set.
|
|
||||||
|
|
||||||
If the change is adding documentation, feel free to just merge after one
|
|
||||||
ACK. We've got low coverage, so it'd be great to keep that barrier low.
|
|
||||||
|
|
||||||
|
.. include:: ../CONTRIBUTING.rst
|
||||||
|
|
||||||
Core Team
|
Core Team
|
||||||
=========
|
=========
|
||||||
|
@ -271,6 +271,21 @@ however is called only for every other value in the list.
|
|||||||
(side-effect2 x)))
|
(side-effect2 x)))
|
||||||
|
|
||||||
|
|
||||||
|
dict-comp
|
||||||
|
---------
|
||||||
|
|
||||||
|
`dict-comp` is used to create dictionaries. It takes three or four parameters.
|
||||||
|
The first two parameters are for controlling the return value
|
||||||
|
(key-value pair), while the third is used to select items from a sequence. The
|
||||||
|
fourth and optional parameter can be used to filter out some of the items in
|
||||||
|
the sequence based on a conditional expression.
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (dict-comp x (* x 2) [x (range 10)] (odd? x))
|
||||||
|
{1: 2, 3: 6, 9: 18, 5: 10, 7: 14}
|
||||||
|
|
||||||
|
|
||||||
do / progn
|
do / progn
|
||||||
----------
|
----------
|
||||||
|
|
||||||
@ -290,7 +305,7 @@ Some example usage:
|
|||||||
Yeah, really!
|
Yeah, really!
|
||||||
|
|
||||||
;; assuming that (side-effect) is a function that we want to call for each
|
;; assuming that (side-effect) is a function that we want to call for each
|
||||||
;; and every value in the list, but which return values we do not care
|
;; and every value in the list, but whose return value we do not care about
|
||||||
=> (list-comp (do (side-effect x)
|
=> (list-comp (do (side-effect x)
|
||||||
... (if (< x 5) (* 2 x)
|
... (if (< x 5) (* 2 x)
|
||||||
... (* 4 x)))
|
... (* 4 x)))
|
||||||
@ -401,7 +416,7 @@ Parameters may have following keywords in front of them:
|
|||||||
arguments may be specified after this one.
|
arguments may be specified after this one.
|
||||||
|
|
||||||
The following code example defines a function that can be given 0 to n
|
The following code example defines a function that can be given 0 to n
|
||||||
numerical parameters. It then sums every odd number and substracts
|
numerical parameters. It then sums every odd number and subtracts
|
||||||
every even number.
|
every even number.
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
@ -441,6 +456,44 @@ symbols for function names as the first parameter, `defn-alias` and
|
|||||||
=> (alias)
|
=> (alias)
|
||||||
"Hello!"
|
"Hello!"
|
||||||
|
|
||||||
|
|
||||||
|
defmain
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. versionadded:: 0.10.1
|
||||||
|
|
||||||
|
The `defmain` macro defines a main function that is immediately called
|
||||||
|
with sys.argv as arguments if and only if this file is being executed
|
||||||
|
as a script. In other words this:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(defmain [&rest args]
|
||||||
|
(do-something-with args))
|
||||||
|
|
||||||
|
is the equivalent of::
|
||||||
|
|
||||||
|
def main(*args):
|
||||||
|
do_something_with(args)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
retval = main(*sys.arg)
|
||||||
|
|
||||||
|
if isinstance(retval, int):
|
||||||
|
sys.exit(retval)
|
||||||
|
|
||||||
|
Note, as you can see above, if you return an integer from this
|
||||||
|
function, this will be used as the exit status for your script.
|
||||||
|
(Python defaults to exit status 0 otherwise, which means everything's
|
||||||
|
okay!)
|
||||||
|
|
||||||
|
(Since (sys.exit 0) is not run explicitly in case of a non-integer
|
||||||
|
return from defmain, it's good to put (defmain) as the last bit of
|
||||||
|
code in your file.)
|
||||||
|
|
||||||
|
|
||||||
.. _defmacro:
|
.. _defmacro:
|
||||||
|
|
||||||
defmacro
|
defmacro
|
||||||
@ -560,6 +613,27 @@ del
|
|||||||
=> dic
|
=> dic
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
doto
|
||||||
|
----
|
||||||
|
|
||||||
|
.. versionadded:: 0.10.1
|
||||||
|
|
||||||
|
`doto` macro is used to make a sequence of method calls for an object easy.
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
=> (doto [] (.append 1) (.append 2) .reverse)
|
||||||
|
[2 1]
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
=> (setv collection [])
|
||||||
|
=> (.append collection 1)
|
||||||
|
=> (.append collection 2)
|
||||||
|
=> (.reverse collection)
|
||||||
|
=> collection
|
||||||
|
[2 1]
|
||||||
|
|
||||||
eval
|
eval
|
||||||
----
|
----
|
||||||
|
|
||||||
@ -629,6 +703,24 @@ normally. If the execution is halted with `break`, the `else` does not execute.
|
|||||||
loop finished
|
loop finished
|
||||||
|
|
||||||
|
|
||||||
|
genexpr
|
||||||
|
-------
|
||||||
|
|
||||||
|
`genexpr` is used to create generator expressions. It takes two or three parameters.
|
||||||
|
The first parameter is the expression controlling the return value, while
|
||||||
|
the second is used to select items from a list. The third and optional
|
||||||
|
parameter can be used to filter out some of the items in the list based on a
|
||||||
|
conditional expression. `genexpr` is similar to `list-comp`, except that it returns
|
||||||
|
an iterable that evaluates values one by one instead of evaluating them immediately.
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (def collection (range 10))
|
||||||
|
=> (def filtered (genexpr x [x collection] (even? x)))
|
||||||
|
=> (list filtered)
|
||||||
|
[0, 2, 4, 6, 8]
|
||||||
|
|
||||||
|
|
||||||
.. _gensym:
|
.. _gensym:
|
||||||
|
|
||||||
gensym
|
gensym
|
||||||
@ -726,14 +818,18 @@ any numeric type, empty sequence and empty dictionary are considered `False`.
|
|||||||
Everything else is considered `True`.
|
Everything else is considered `True`.
|
||||||
|
|
||||||
|
|
||||||
lisp-if / lif
|
lisp-if / lif and lisp-if-not / lif-not
|
||||||
-------------
|
---------------------------------------
|
||||||
|
|
||||||
.. versionadded:: 0.10.0
|
.. versionadded:: 0.10.0
|
||||||
|
|
||||||
|
.. versionadded:: 0.10.2
|
||||||
|
lisp-if-not / lif-not
|
||||||
|
|
||||||
For those that prefer a more lisp-y if clause, we have lisp-if, or lif. This
|
For those that prefer a more lisp-y if clause, we have lisp-if, or lif. This
|
||||||
*only* considers None/nil as false! All other values of python
|
*only* considers None/nil as false! All other values of python
|
||||||
"falseiness" are considered true.
|
"falseiness" are considered true. Conversely, we have lisp-if-not or lif-not,
|
||||||
|
in parallel to if / if-not, which reverses the comparison.
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
@ -748,12 +844,20 @@ For those that prefer a more lisp-y if clause, we have lisp-if, or lif. This
|
|||||||
"false"
|
"false"
|
||||||
=> (lisp-if None "true" "false")
|
=> (lisp-if None "true" "false")
|
||||||
"false"
|
"false"
|
||||||
|
=> (lisp-if-not nil "true" "false")
|
||||||
|
"true"
|
||||||
|
=> (lisp-if-not None "true" "false")
|
||||||
|
"true"
|
||||||
|
=> (lisp-if-not False "true" "false")
|
||||||
|
"false"
|
||||||
|
|
||||||
; And, same thing
|
; And, same thing
|
||||||
=> (lif True "true" "false")
|
=> (lif True "true" "false")
|
||||||
"true"
|
"true"
|
||||||
=> (lif nil "true" "false")
|
=> (lif nil "true" "false")
|
||||||
"false"
|
"false"
|
||||||
|
=> (lif-not None "true" "false")
|
||||||
|
"true"
|
||||||
|
|
||||||
|
|
||||||
import
|
import
|
||||||
@ -1003,6 +1107,22 @@ element:
|
|||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
[1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
|
||||||
|
|
||||||
|
set-comp
|
||||||
|
--------
|
||||||
|
|
||||||
|
`set-comp` is used to create sets. It takes two or three parameters.
|
||||||
|
The first parameter is for controlling the return value, while the second is
|
||||||
|
used to select items from a sequence. The third and optional parameter can be
|
||||||
|
used to filter out some of the items in the sequence based on a conditional
|
||||||
|
expression.
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (setv data [1 2 3 4 5 2 3 4 5 3 4 5])
|
||||||
|
=> (set-comp x [x data] (odd? x))
|
||||||
|
{1, 3, 5}
|
||||||
|
|
||||||
|
|
||||||
slice
|
slice
|
||||||
-----
|
-----
|
||||||
|
|
||||||
@ -1057,7 +1177,7 @@ Example usage
|
|||||||
; Throw an IOError("foobar")
|
; Throw an IOError("foobar")
|
||||||
|
|
||||||
|
|
||||||
`throw` can acccept a single argument (an `Exception` class or instance), or
|
`throw` can accept a single argument (an `Exception` class or instance), or
|
||||||
no arguments to re-raise the last Exception.
|
no arguments to re-raise the last Exception.
|
||||||
|
|
||||||
|
|
||||||
@ -1151,7 +1271,7 @@ while
|
|||||||
`while` form is used to execute a single or more blocks as long as a condition
|
`while` form is used to execute a single or more blocks as long as a condition
|
||||||
is being met.
|
is being met.
|
||||||
|
|
||||||
The following example will output "hello world!" on screen indefinetely:
|
The following example will output "hello world!" on screen indefinitely:
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
@ -1185,23 +1305,48 @@ file is automatically closed after it has been processed.
|
|||||||
with-decorator
|
with-decorator
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
`with-decorator` is used to wrap a function with another. The function performing
|
`with-decorator` is used to wrap a function with another. The function
|
||||||
decoration should accept a single value, the function being decorated and return
|
performing decoration should accept a single value, the function being
|
||||||
a new function. `with-decorator` takes two parameters, the function performing
|
decorated and return a new function. `with-decorator` takes a minimum
|
||||||
decoration and the function being decorated.
|
of two parameters, the function performing decoration and the function
|
||||||
|
being decorated. More than one decorator function can be applied, they
|
||||||
In the following example, `inc-decorator` is used to decorate function `addition`
|
will be applied in order from outermost to innermost, ie. the first
|
||||||
with a function that takes two parameters and calls the decorated function with
|
decorator will be the outermost one & so on. Decorators with arguments
|
||||||
values that are incremented by 1. When decorated `addition` is called with values
|
are called just like a function call.
|
||||||
1 and 1, the end result will be 4 (1+1 + 1+1).
|
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
=> (defn inc-decorator [func]
|
(with-decorator decorator-fun
|
||||||
|
(defn some-function [] ...)
|
||||||
|
|
||||||
|
(with-decorator decorator1 decorator2 ...
|
||||||
|
(defn some-function [] ...)
|
||||||
|
|
||||||
|
(with-decorator (decorator arg) ..
|
||||||
|
(defn some-function [] ...)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
In the following example, `inc-decorator` is used to decorate function
|
||||||
|
`addition` with a function that takes two parameters and calls the
|
||||||
|
decorated function with values that are incremented by 1. When
|
||||||
|
decorated `addition` is called with values 1 and 1, the end result
|
||||||
|
will be 4 (1+1 + 1+1).
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
=> (defn inc-decorator [func]
|
||||||
... (fn [value-1 value-2] (func (+ value-1 1) (+ value-2 1))))
|
... (fn [value-1 value-2] (func (+ value-1 1) (+ value-2 1))))
|
||||||
|
=> (defn inc2-decorator [func]
|
||||||
|
... (fn [value-1 value-2] (func (+ value-1 2) (+ value-2 2))))
|
||||||
|
|
||||||
=> (with-decorator inc-decorator (defn addition [a b] (+ a b)))
|
=> (with-decorator inc-decorator (defn addition [a b] (+ a b)))
|
||||||
=> (addition 1 1)
|
=> (addition 1 1)
|
||||||
4
|
4
|
||||||
|
=> (with-decorator inc2-decorator inc-decorator
|
||||||
|
... (defn addition [a b] (+ a b)))
|
||||||
|
=> (addition 1 1)
|
||||||
|
8
|
||||||
|
|
||||||
|
|
||||||
.. _with-gensyms:
|
.. _with-gensyms:
|
||||||
|
@ -6,6 +6,31 @@ Hy Core
|
|||||||
Core Functions
|
Core Functions
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
.. _butlast-fn:
|
||||||
|
|
||||||
|
butlast
|
||||||
|
-------
|
||||||
|
|
||||||
|
Usage: ``(butlast coll)``
|
||||||
|
|
||||||
|
Returns an iterator of all but the last item in ``coll``.
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (list (butlast (range 10)))
|
||||||
|
[0, 1, 2, 3, 4, 5, 6, 7, 8]
|
||||||
|
|
||||||
|
=> (list (butlast [1]))
|
||||||
|
[]
|
||||||
|
|
||||||
|
=> (list (butlast []))
|
||||||
|
[]
|
||||||
|
|
||||||
|
=> (import itertools)
|
||||||
|
=> (list (take 5 (butlast (itertools.count 10))))
|
||||||
|
[10, 11, 12, 13, 14]
|
||||||
|
|
||||||
|
|
||||||
.. _is-coll-fn:
|
.. _is-coll-fn:
|
||||||
|
|
||||||
coll?
|
coll?
|
||||||
@ -290,6 +315,46 @@ either ``int`` or ``long``. For Python 3, this is ``int``.
|
|||||||
False
|
False
|
||||||
|
|
||||||
|
|
||||||
|
.. _interleave-fn:
|
||||||
|
|
||||||
|
interleave
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. versionadded:: 0.10.1
|
||||||
|
|
||||||
|
Usage: ``(interleave seq1 seq2 ...)``
|
||||||
|
|
||||||
|
Return an iterable of the first item in each of the sequences, then the second etc.
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (list (interleave (range 5) (range 100 105)))
|
||||||
|
[0, 100, 1, 101, 2, 102, 3, 103, 4, 104]
|
||||||
|
|
||||||
|
=> (list (interleave (range 1000000) "abc"))
|
||||||
|
[0, 'a', 1, 'b', 2, 'c']
|
||||||
|
|
||||||
|
|
||||||
|
.. _interpose-fn:
|
||||||
|
|
||||||
|
interpose
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. versionadded:: 0.10.1
|
||||||
|
|
||||||
|
Usage: ``(interpose item seq)``
|
||||||
|
|
||||||
|
Return an iterable of the elements of the sequence separated by the item.
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (list (interpose "!" "abcd"))
|
||||||
|
['a', '!', 'b', '!', 'c', '!', 'd']
|
||||||
|
|
||||||
|
=> (list (interpose -1 (range 5)))
|
||||||
|
[0, -1, 1, -1, 2, -1, 3, -1, 4]
|
||||||
|
|
||||||
|
|
||||||
.. _iterable?-fn:
|
.. _iterable?-fn:
|
||||||
|
|
||||||
iterable?
|
iterable?
|
||||||
@ -409,6 +474,27 @@ Returns the single step macro expansion of form.
|
|||||||
=> (macroexpand-1 '(-> (a b) (-> (c d) (e f))))
|
=> (macroexpand-1 '(-> (a b) (-> (c d) (e f))))
|
||||||
(u'_>' (u'a' u'b') (u'c' u'd') (u'e' u'f'))
|
(u'_>' (u'a' u'b') (u'c' u'd') (u'e' u'f'))
|
||||||
|
|
||||||
|
|
||||||
|
.. _merge-with-fn:
|
||||||
|
|
||||||
|
merge-with
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. versionadded:: 0.10.1
|
||||||
|
|
||||||
|
Usage: ``(merge-with f &rest maps)
|
||||||
|
|
||||||
|
Returns a map that consist of the rest of the maps joined onto first.
|
||||||
|
If a key occurs in more than one map, the mapping(s) from the latter
|
||||||
|
(left-to-right) will be combined with the mapping in the result by
|
||||||
|
calling ``(f val-in-result val-in-latter)``.
|
||||||
|
|
||||||
|
.. code-block:: clojure
|
||||||
|
|
||||||
|
=> (merge-with (fn [x y] (+ x y)) {"a" 10 "b" 20} {"a" 1 "c" 30})
|
||||||
|
{u'a': 11L, u'c': 30L, u'b': 20L}
|
||||||
|
|
||||||
|
|
||||||
.. _neg?-fn:
|
.. _neg?-fn:
|
||||||
|
|
||||||
neg?
|
neg?
|
||||||
@ -492,11 +578,11 @@ Return True if x is None.
|
|||||||
nth
|
nth
|
||||||
---
|
---
|
||||||
|
|
||||||
Usage: ``(nth coll n)``
|
Usage: ``(nth coll n &optional [default nil])``
|
||||||
|
|
||||||
Return the `nth` item in a collection, counting from 0. Unlike
|
Return the `nth` item in a collection, counting from 0. Return the
|
||||||
``get``, ``nth`` works on both iterators and iterables. Raises ``IndexError``
|
default value, ``nil``, if out of bounds (unless specified otherwise).
|
||||||
if the `n` is outside the range of ``coll`` or ``ValueError`` if it's negative.
|
Raise ``ValueError`` if ``n`` is negative.
|
||||||
|
|
||||||
.. code-block:: hy
|
.. code-block:: hy
|
||||||
|
|
||||||
@ -506,14 +592,21 @@ if the `n` is outside the range of ``coll`` or ``ValueError`` if it's negative.
|
|||||||
=> (nth [1 2 4 7] 3)
|
=> (nth [1 2 4 7] 3)
|
||||||
7
|
7
|
||||||
|
|
||||||
=> (nth [1 2 4 7] 5)
|
=> (nil? (nth [1 2 4 7] 5))
|
||||||
Traceback (most recent call last):
|
True
|
||||||
...
|
|
||||||
IndexError: 5
|
=> (nth [1 2 4 7] 5 "default")
|
||||||
|
'default'
|
||||||
|
|
||||||
=> (nth (take 3 (drop 2 [1 2 3 4 5 6])) 2))
|
=> (nth (take 3 (drop 2 [1 2 3 4 5 6])) 2))
|
||||||
5
|
5
|
||||||
|
|
||||||
|
=> (nth [1 2 4 7] -1)
|
||||||
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
ValueError: Indices for islice() must be None or an integer: 0 <= x <= sys.maxsize.
|
||||||
|
|
||||||
|
|
||||||
.. _numeric?-fn:
|
.. _numeric?-fn:
|
||||||
|
|
||||||
numeric?
|
numeric?
|
||||||
@ -607,21 +700,25 @@ some
|
|||||||
|
|
||||||
Usage: ``(some pred coll)``
|
Usage: ``(some pred coll)``
|
||||||
|
|
||||||
Return True if ``(pred x)`` is logical true for any ``x`` in ``coll``, otherwise False. Return False if ``coll`` is empty.
|
Return the first logical true value of ``(pred x)`` for any ``x`` in
|
||||||
|
``coll``, otherwise ``nil``. Return ``nil`` if ``coll`` is empty.
|
||||||
|
|
||||||
.. code-block:: hy
|
.. code-block:: hy
|
||||||
|
|
||||||
=> (some even? [2 4 6])
|
=> (some even? [2 4 6])
|
||||||
True
|
True
|
||||||
|
|
||||||
=> (some even? [1 3 5])
|
=> (nil? (some even? [1 3 5]))
|
||||||
False
|
|
||||||
|
|
||||||
=> (some even? [1 3 6])
|
|
||||||
True
|
True
|
||||||
|
|
||||||
=> (some even? [])
|
=> (nil? (some identity [0 "" []]))
|
||||||
False
|
True
|
||||||
|
|
||||||
|
=> (some identity [0 "non-empty-string" []])
|
||||||
|
'non-empty-string'
|
||||||
|
|
||||||
|
=> (nil? (some even? []))
|
||||||
|
True
|
||||||
|
|
||||||
|
|
||||||
.. _string?-fn:
|
.. _string?-fn:
|
||||||
@ -782,6 +879,32 @@ Raises ``ValueError`` if ``n`` is negative.
|
|||||||
=> (list (drop 6 [1 2 3 4 5]))
|
=> (list (drop 6 [1 2 3 4 5]))
|
||||||
[]
|
[]
|
||||||
|
|
||||||
|
|
||||||
|
.. _drop-last-fn:
|
||||||
|
|
||||||
|
drop-last
|
||||||
|
---------
|
||||||
|
|
||||||
|
Usage: ``(drop-last n coll)``
|
||||||
|
|
||||||
|
Return an iterator of all but the last ``n`` items in ``coll``. Raise ``ValueError`` if ``n`` is negative.
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (list (drop-last 5 (range 10 20)))
|
||||||
|
[10, 11, 12, 13, 14]
|
||||||
|
|
||||||
|
=> (list (drop-last 0 (range 5)))
|
||||||
|
[0, 1, 2, 3, 4]
|
||||||
|
|
||||||
|
=> (list (drop-last 100 (range 100)))
|
||||||
|
[]
|
||||||
|
|
||||||
|
=> (import itertools)
|
||||||
|
=> (list (take 5 (drop-last 100 (itertools.count 10))))
|
||||||
|
[10, 11, 12, 13, 14]
|
||||||
|
|
||||||
|
|
||||||
.. _drop-while-fn:
|
.. _drop-while-fn:
|
||||||
|
|
||||||
drop-while
|
drop-while
|
||||||
@ -862,6 +985,53 @@ Return an iterator of `x`, `fn(x)`, `fn(fn(x))`.
|
|||||||
[5, 25, 625, 390625, 152587890625]
|
[5, 25, 625, 390625, 152587890625]
|
||||||
|
|
||||||
|
|
||||||
|
.. _read-fn:
|
||||||
|
|
||||||
|
read
|
||||||
|
----
|
||||||
|
|
||||||
|
Usage: ``(read &optional [from-file eof])``
|
||||||
|
|
||||||
|
Reads the next hy expression from `from-file` (defaults to `sys.stdin`), and
|
||||||
|
can take a single byte as EOF (defaults to an empty string).
|
||||||
|
Raises an `EOFError` if `from-file` ends before a complete expression can be
|
||||||
|
parsed.
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (read)
|
||||||
|
(+ 2 2)
|
||||||
|
('+' 2 2)
|
||||||
|
=> (eval (read))
|
||||||
|
(+ 2 2)
|
||||||
|
4
|
||||||
|
|
||||||
|
=> (import io)
|
||||||
|
=> (def buffer (io.StringIO "(+ 2 2)\n(- 2 1)"))
|
||||||
|
=> (eval (apply read [] {"from_file" buffer}))
|
||||||
|
4
|
||||||
|
=> (eval (apply read [] {"from_file" buffer}))
|
||||||
|
1
|
||||||
|
|
||||||
|
=> ; assuming "example.hy" contains:
|
||||||
|
=> ; (print "hello")
|
||||||
|
=> ; (print "hyfriends!")
|
||||||
|
=> (with [[f (open "example.hy")]]
|
||||||
|
... (try
|
||||||
|
... (while true
|
||||||
|
... (let [[exp (read f)]]
|
||||||
|
... (do
|
||||||
|
... (print "OHY" exp)
|
||||||
|
... (eval exp))))
|
||||||
|
... (catch [e EOFError]
|
||||||
|
... (print "EOF!"))))
|
||||||
|
OHY ('print' 'hello')
|
||||||
|
hello
|
||||||
|
OHY ('print' 'hyfriends!')
|
||||||
|
hyfriends!
|
||||||
|
EOF!
|
||||||
|
|
||||||
|
|
||||||
.. _remove-fn:
|
.. _remove-fn:
|
||||||
|
|
||||||
remove
|
remove
|
||||||
|
@ -387,7 +387,7 @@ for a more complete description.) ``nif`` is an example, something like a numeri
|
|||||||
where based on the expression, one of the 3 forms is called depending on if the
|
where based on the expression, one of the 3 forms is called depending on if the
|
||||||
expression is positive, zero or negative.
|
expression is positive, zero or negative.
|
||||||
|
|
||||||
A first pass might be someting like:
|
A first pass might be something like:
|
||||||
|
|
||||||
.. code-block:: hy
|
.. code-block:: hy
|
||||||
|
|
||||||
|
@ -70,4 +70,4 @@ and expression is passed to the correct function.
|
|||||||
.. warning::
|
.. warning::
|
||||||
Because of a limitation in Hy's lexer and parser, reader macros can't
|
Because of a limitation in Hy's lexer and parser, reader macros can't
|
||||||
redefine defined syntax such as ``()[]{}``. This will most likely be
|
redefine defined syntax such as ``()[]{}``. This will most likely be
|
||||||
adressed in the future.
|
addressed in the future.
|
||||||
|
@ -500,7 +500,7 @@ Let's take the classic:
|
|||||||
|
|
||||||
(loop (print (eval (read))))
|
(loop (print (eval (read))))
|
||||||
|
|
||||||
Rather then write it like that, we can write it as follows:
|
Rather than write it like that, we can write it as follows:
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env hy
|
#!/usr/bin/env hy
|
||||||
;; Copyright (c) Paul R. Tagliamonte <paultag@debian.org>, 2013 under the terms
|
;; Copyright (c) Paul R. Tagliamonte <paultag@debian.org>, 2013 under the terms
|
||||||
;; of the Expat license, a copy of which you have should have recieved with
|
;; of the Expat license, a copy of which you should have received with
|
||||||
;; the source.
|
;; the source.
|
||||||
|
|
||||||
(import sys)
|
(import sys)
|
||||||
|
@ -23,7 +23,6 @@ from hy.version import __version__, __appname__ # NOQA
|
|||||||
|
|
||||||
|
|
||||||
from hy.models.expression import HyExpression # NOQA
|
from hy.models.expression import HyExpression # NOQA
|
||||||
from hy.models.lambdalist import HyLambdaListKeyword # NOQA
|
|
||||||
from hy.models.integer import HyInteger # NOQA
|
from hy.models.integer import HyInteger # NOQA
|
||||||
from hy.models.keyword import HyKeyword # NOQA
|
from hy.models.keyword import HyKeyword # NOQA
|
||||||
from hy.models.complex import HyComplex # NOQA
|
from hy.models.complex import HyComplex # NOQA
|
||||||
|
@ -23,7 +23,7 @@ import imp
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
# This just mocks the normalish behavior of the Python interp. Helpful to aid
|
# This just mocks the normalish behavior of the Python interp. Helpful to aid
|
||||||
# with shiming existing apps that don't really "work" with Hy.
|
# with shimming existing apps that don't really "work" with Hy.
|
||||||
#
|
#
|
||||||
# You could say this script helps Hyjack a file.
|
# You could say this script helps Hyjack a file.
|
||||||
#
|
#
|
||||||
|
@ -52,3 +52,9 @@ if PY3:
|
|||||||
long_type = int
|
long_type = int
|
||||||
else:
|
else:
|
||||||
long_type = long # NOQA
|
long_type = long # NOQA
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
exec('def raise_empty(t, *args): raise t(*args) from None')
|
||||||
|
else:
|
||||||
|
def raise_empty(t, *args):
|
||||||
|
raise t(*args)
|
||||||
|
@ -47,7 +47,7 @@ from hy.models.expression import HyExpression
|
|||||||
from hy.models.string import HyString
|
from hy.models.string import HyString
|
||||||
from hy.models.symbol import HySymbol
|
from hy.models.symbol import HySymbol
|
||||||
|
|
||||||
from hy._compat import builtins
|
from hy._compat import builtins, PY3
|
||||||
|
|
||||||
|
|
||||||
class HyQuitter(object):
|
class HyQuitter(object):
|
||||||
@ -203,6 +203,7 @@ def run_file(filename):
|
|||||||
|
|
||||||
|
|
||||||
def run_repl(hr=None, spy=False):
|
def run_repl(hr=None, spy=False):
|
||||||
|
import platform
|
||||||
sys.ps1 = "=> "
|
sys.ps1 = "=> "
|
||||||
sys.ps2 = "... "
|
sys.ps2 = "... "
|
||||||
|
|
||||||
@ -210,10 +211,15 @@ def run_repl(hr=None, spy=False):
|
|||||||
if not hr:
|
if not hr:
|
||||||
hr = HyREPL(spy)
|
hr = HyREPL(spy)
|
||||||
|
|
||||||
hr.interact("{appname} {version}".format(
|
hr.interact("{appname} {version} using "
|
||||||
appname=hy.__appname__,
|
"{py}({build}) {pyversion} on {os}".format(
|
||||||
version=hy.__version__
|
appname=hy.__appname__,
|
||||||
))
|
version=hy.__version__,
|
||||||
|
py=platform.python_implementation(),
|
||||||
|
build=platform.python_build()[0],
|
||||||
|
pyversion=platform.python_version(),
|
||||||
|
os=platform.system()
|
||||||
|
))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@ -321,6 +327,7 @@ def hyc_main():
|
|||||||
|
|
||||||
# entry point for cmd line script "hy2py"
|
# entry point for cmd line script "hy2py"
|
||||||
def hy2py_main():
|
def hy2py_main():
|
||||||
|
import platform
|
||||||
module_name = "<STDIN>"
|
module_name = "<STDIN>"
|
||||||
|
|
||||||
options = dict(prog="hy2py", usage="%(prog)s [options] FILE",
|
options = dict(prog="hy2py", usage="%(prog)s [options] FILE",
|
||||||
@ -343,17 +350,42 @@ def hy2py_main():
|
|||||||
|
|
||||||
if options.with_source:
|
if options.with_source:
|
||||||
hst = import_file_to_hst(options.args[0])
|
hst = import_file_to_hst(options.args[0])
|
||||||
print(hst)
|
# need special printing on Windows in case the
|
||||||
|
# codepage doesn't support utf-8 characters
|
||||||
|
if PY3 and platform.system() == "Windows":
|
||||||
|
for h in hst:
|
||||||
|
try:
|
||||||
|
print(h)
|
||||||
|
except:
|
||||||
|
print(str(h).encode('utf-8'))
|
||||||
|
else:
|
||||||
|
print(hst)
|
||||||
print()
|
print()
|
||||||
print()
|
print()
|
||||||
|
|
||||||
_ast = import_file_to_ast(options.args[0], module_name)
|
_ast = import_file_to_ast(options.args[0], module_name)
|
||||||
if options.with_ast:
|
if options.with_ast:
|
||||||
print(astor.dump(_ast))
|
if PY3 and platform.system() == "Windows":
|
||||||
|
_print_for_windows(astor.dump(_ast))
|
||||||
|
else:
|
||||||
|
print(astor.dump(_ast))
|
||||||
print()
|
print()
|
||||||
print()
|
print()
|
||||||
|
|
||||||
if not options.without_python:
|
if not options.without_python:
|
||||||
print(astor.codegen.to_source(_ast))
|
if PY3 and platform.system() == "Windows":
|
||||||
|
_print_for_windows(astor.codegen.to_source(_ast))
|
||||||
|
else:
|
||||||
|
print(astor.codegen.to_source(_ast))
|
||||||
|
|
||||||
parser.exit(0)
|
parser.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
# need special printing on Windows in case the
|
||||||
|
# codepage doesn't support utf-8 characters
|
||||||
|
def _print_for_windows(src):
|
||||||
|
for line in src.split("\n"):
|
||||||
|
try:
|
||||||
|
print(line)
|
||||||
|
except:
|
||||||
|
print(line.encode('utf-8'))
|
||||||
|
103
hy/compiler.py
103
hy/compiler.py
@ -1,10 +1,10 @@
|
|||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
|
# Copyright (c) 2013, 2014 Paul Tagliamonte <paultag@debian.org>
|
||||||
# Copyright (c) 2013 Julien Danjou <julien@danjou.info>
|
# Copyright (c) 2013 Julien Danjou <julien@danjou.info>
|
||||||
# Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>
|
# Copyright (c) 2013 Nicolas Dandrimont <nicolas.dandrimont@crans.org>
|
||||||
# Copyright (c) 2013 James King <james@agentultra.com>
|
# Copyright (c) 2013 James King <james@agentultra.com>
|
||||||
# Copyright (c) 2013 Bob Tolbert <bob@tolbert.org>
|
# Copyright (c) 2013, 2014 Bob Tolbert <bob@tolbert.org>
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
# copy of this software and associated documentation files (the "Software"),
|
# copy of this software and associated documentation files (the "Software"),
|
||||||
@ -24,7 +24,6 @@
|
|||||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
# DEALINGS IN THE SOFTWARE.
|
# DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
from hy.models.lambdalist import HyLambdaListKeyword
|
|
||||||
from hy.models.expression import HyExpression
|
from hy.models.expression import HyExpression
|
||||||
from hy.models.keyword import HyKeyword
|
from hy.models.keyword import HyKeyword
|
||||||
from hy.models.integer import HyInteger
|
from hy.models.integer import HyInteger
|
||||||
@ -39,7 +38,7 @@ from hy.models.cons import HyCons
|
|||||||
from hy.errors import HyCompileError, HyTypeError
|
from hy.errors import HyCompileError, HyTypeError
|
||||||
|
|
||||||
import hy.macros
|
import hy.macros
|
||||||
from hy._compat import str_type, long_type, PY27, PY33, PY3, PY34
|
from hy._compat import str_type, long_type, PY27, PY33, PY3, PY34, raise_empty
|
||||||
from hy.macros import require, macroexpand, reader_macroexpand
|
from hy.macros import require, macroexpand, reader_macroexpand
|
||||||
import hy.importer
|
import hy.importer
|
||||||
|
|
||||||
@ -48,6 +47,7 @@ import importlib
|
|||||||
import codecs
|
import codecs
|
||||||
import ast
|
import ast
|
||||||
import sys
|
import sys
|
||||||
|
import keyword
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
@ -74,6 +74,21 @@ def load_stdlib():
|
|||||||
_stdlib[e] = module
|
_stdlib[e] = module
|
||||||
|
|
||||||
|
|
||||||
|
# True, False and None included here since they
|
||||||
|
# are assignable in Python 2.* but become
|
||||||
|
# keywords in Python 3.*
|
||||||
|
def _is_hy_builtin(name, module_name):
|
||||||
|
extras = ['True', 'False', 'None',
|
||||||
|
'true', 'false', 'nil', 'null']
|
||||||
|
if name in extras or keyword.iskeyword(name):
|
||||||
|
return True
|
||||||
|
# for non-Hy modules, check for pre-existing name in
|
||||||
|
# _compile_table
|
||||||
|
if not module_name.startswith("hy."):
|
||||||
|
return name in _compile_table
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
_compile_table = {}
|
_compile_table = {}
|
||||||
|
|
||||||
|
|
||||||
@ -305,13 +320,12 @@ def _raise_wrong_args_number(expression, error):
|
|||||||
len(expression)))
|
len(expression)))
|
||||||
|
|
||||||
|
|
||||||
def checkargs(exact=None, min=None, max=None, even=None):
|
def checkargs(exact=None, min=None, max=None, even=None, multiple=None):
|
||||||
def _dec(fn):
|
def _dec(fn):
|
||||||
def checker(self, expression):
|
def checker(self, expression):
|
||||||
if exact is not None and (len(expression) - 1) != exact:
|
if exact is not None and (len(expression) - 1) != exact:
|
||||||
_raise_wrong_args_number(
|
_raise_wrong_args_number(
|
||||||
expression, "`%%s' needs %d arguments, got %%d" % exact)
|
expression, "`%%s' needs %d arguments, got %%d" % exact)
|
||||||
|
|
||||||
if min is not None and (len(expression) - 1) < min:
|
if min is not None and (len(expression) - 1) < min:
|
||||||
_raise_wrong_args_number(
|
_raise_wrong_args_number(
|
||||||
expression,
|
expression,
|
||||||
@ -330,6 +344,14 @@ def checkargs(exact=None, min=None, max=None, even=None):
|
|||||||
"`%%s' needs an %s number of arguments, got %%d"
|
"`%%s' needs an %s number of arguments, got %%d"
|
||||||
% (even_str))
|
% (even_str))
|
||||||
|
|
||||||
|
if multiple is not None:
|
||||||
|
if not (len(expression) - 1) in multiple:
|
||||||
|
choices = ", ".join([str(val) for val in multiple[:-1]])
|
||||||
|
choices += " or %s" % multiple[-1]
|
||||||
|
_raise_wrong_args_number(
|
||||||
|
expression,
|
||||||
|
"`%%s' needs %s arguments, got %%d" % choices)
|
||||||
|
|
||||||
return fn(self, expression)
|
return fn(self, expression)
|
||||||
|
|
||||||
return checker
|
return checker
|
||||||
@ -407,7 +429,7 @@ class HyASTCompiler(object):
|
|||||||
except HyTypeError as e:
|
except HyTypeError as e:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HyCompileError(e, sys.exc_info()[2])
|
raise_empty(HyCompileError, e, sys.exc_info()[2])
|
||||||
|
|
||||||
raise HyCompileError(Exception("Unknown type: `%s'" % _type))
|
raise HyCompileError(Exception("Unknown type: `%s'" % _type))
|
||||||
|
|
||||||
@ -430,6 +452,7 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
def _parse_lambda_list(self, exprs):
|
def _parse_lambda_list(self, exprs):
|
||||||
""" Return FunctionDef parameter values from lambda list."""
|
""" Return FunctionDef parameter values from lambda list."""
|
||||||
|
ll_keywords = ("&rest", "&optional", "&key", "&kwargs")
|
||||||
ret = Result()
|
ret = Result()
|
||||||
args = []
|
args = []
|
||||||
defaults = []
|
defaults = []
|
||||||
@ -439,10 +462,7 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
for expr in exprs:
|
for expr in exprs:
|
||||||
|
|
||||||
if isinstance(expr, HyLambdaListKeyword):
|
if expr in ll_keywords:
|
||||||
if expr not in expr._valid_types:
|
|
||||||
raise HyTypeError(expr, "{0} is not a valid "
|
|
||||||
"lambda-keyword.".format(repr(expr)))
|
|
||||||
if expr == "&rest" and lambda_keyword is None:
|
if expr == "&rest" and lambda_keyword is None:
|
||||||
lambda_keyword = expr
|
lambda_keyword = expr
|
||||||
elif expr == "&optional":
|
elif expr == "&optional":
|
||||||
@ -616,7 +636,7 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
return imports, ret.replace(form), False
|
return imports, ret.replace(form), False
|
||||||
|
|
||||||
elif isinstance(form, (HySymbol, HyLambdaListKeyword)):
|
elif isinstance(form, HySymbol):
|
||||||
return imports, HyExpression([HySymbol(name),
|
return imports, HyExpression([HySymbol(name),
|
||||||
HyString(form)]).replace(form), False
|
HyString(form)]).replace(form), False
|
||||||
|
|
||||||
@ -665,13 +685,22 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
@builds("throw")
|
@builds("throw")
|
||||||
@builds("raise")
|
@builds("raise")
|
||||||
@checkargs(max=1)
|
@checkargs(multiple=[0, 1, 3])
|
||||||
def compile_throw_expression(self, expr):
|
def compile_throw_expression(self, expr):
|
||||||
expr.pop(0)
|
expr.pop(0)
|
||||||
ret = Result()
|
ret = Result()
|
||||||
if expr:
|
if expr:
|
||||||
ret += self.compile(expr.pop(0))
|
ret += self.compile(expr.pop(0))
|
||||||
|
|
||||||
|
cause = None
|
||||||
|
if len(expr) == 2 and expr[0] == HyKeyword(":from"):
|
||||||
|
if not PY3:
|
||||||
|
raise HyCompileError(
|
||||||
|
"raise from only supported in python 3")
|
||||||
|
expr.pop(0)
|
||||||
|
cause = self.compile(expr.pop(0))
|
||||||
|
cause = cause.expr
|
||||||
|
|
||||||
# Use ret.expr to get a literal `None`
|
# Use ret.expr to get a literal `None`
|
||||||
ret += ast.Raise(
|
ret += ast.Raise(
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
@ -680,7 +709,7 @@ class HyASTCompiler(object):
|
|||||||
exc=ret.expr,
|
exc=ret.expr,
|
||||||
inst=None,
|
inst=None,
|
||||||
tback=None,
|
tback=None,
|
||||||
cause=None)
|
cause=cause)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@ -707,7 +736,8 @@ class HyASTCompiler(object):
|
|||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column)
|
col_offset=expr.start_column)
|
||||||
|
|
||||||
returnable = Result(expr=expr_name, temp_variables=[expr_name, name])
|
returnable = Result(expr=expr_name, temp_variables=[expr_name, name],
|
||||||
|
contains_yield=body.contains_yield)
|
||||||
|
|
||||||
body += ast.Assign(targets=[name],
|
body += ast.Assign(targets=[name],
|
||||||
value=body.force_expr,
|
value=body.force_expr,
|
||||||
@ -999,7 +1029,10 @@ class HyASTCompiler(object):
|
|||||||
@checkargs(max=1)
|
@checkargs(max=1)
|
||||||
def compile_yield_expression(self, expr):
|
def compile_yield_expression(self, expr):
|
||||||
expr.pop(0)
|
expr.pop(0)
|
||||||
ret = Result(contains_yield=True)
|
if PY33:
|
||||||
|
ret = Result(contains_yield=False)
|
||||||
|
else:
|
||||||
|
ret = Result(contains_yield=True)
|
||||||
|
|
||||||
value = None
|
value = None
|
||||||
if expr != []:
|
if expr != []:
|
||||||
@ -1235,7 +1268,8 @@ class HyASTCompiler(object):
|
|||||||
def compile_decorate_expression(self, expr):
|
def compile_decorate_expression(self, expr):
|
||||||
expr.pop(0) # with-decorator
|
expr.pop(0) # with-decorator
|
||||||
fn = self.compile(expr.pop(-1))
|
fn = self.compile(expr.pop(-1))
|
||||||
if not fn.stmts or not isinstance(fn.stmts[-1], ast.FunctionDef):
|
if not fn.stmts or not (isinstance(fn.stmts[-1], ast.FunctionDef) or
|
||||||
|
isinstance(fn.stmts[-1], ast.ClassDef)):
|
||||||
raise HyTypeError(expr, "Decorated a non-function")
|
raise HyTypeError(expr, "Decorated a non-function")
|
||||||
decorators, ret = self._compile_collect(expr)
|
decorators, ret = self._compile_collect(expr)
|
||||||
fn.stmts[-1].decorator_list = decorators
|
fn.stmts[-1].decorator_list = decorators
|
||||||
@ -1512,7 +1546,7 @@ class HyASTCompiler(object):
|
|||||||
def compile_require(self, expression):
|
def compile_require(self, expression):
|
||||||
"""
|
"""
|
||||||
TODO: keep track of what we've imported in this run and then
|
TODO: keep track of what we've imported in this run and then
|
||||||
"unimport" it after we've completed `thing' so that we don't polute
|
"unimport" it after we've completed `thing' so that we don't pollute
|
||||||
other envs.
|
other envs.
|
||||||
"""
|
"""
|
||||||
expression.pop(0)
|
expression.pop(0)
|
||||||
@ -1750,19 +1784,26 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
def _compile_assign(self, name, result,
|
def _compile_assign(self, name, result,
|
||||||
start_line, start_column):
|
start_line, start_column):
|
||||||
|
|
||||||
|
str_name = "%s" % name
|
||||||
|
if _is_hy_builtin(str_name, self.module_name):
|
||||||
|
raise HyTypeError(name,
|
||||||
|
"Can't assign to a builtin: `%s'" % str_name)
|
||||||
|
|
||||||
result = self.compile(result)
|
result = self.compile(result)
|
||||||
|
|
||||||
if result.temp_variables and isinstance(name, HyString):
|
|
||||||
result.rename(name)
|
|
||||||
return result
|
|
||||||
|
|
||||||
ld_name = self.compile(name)
|
ld_name = self.compile(name)
|
||||||
st_name = self._storeize(ld_name)
|
|
||||||
|
|
||||||
result += ast.Assign(
|
if result.temp_variables \
|
||||||
lineno=start_line,
|
and isinstance(name, HyString) \
|
||||||
col_offset=start_column,
|
and '.' not in name:
|
||||||
targets=[st_name], value=result.force_expr)
|
result.rename(name)
|
||||||
|
else:
|
||||||
|
st_name = self._storeize(ld_name)
|
||||||
|
result += ast.Assign(
|
||||||
|
lineno=start_line,
|
||||||
|
col_offset=start_column,
|
||||||
|
targets=[st_name],
|
||||||
|
value=result.force_expr)
|
||||||
|
|
||||||
result += ld_name
|
result += ld_name
|
||||||
return result
|
return result
|
||||||
@ -1855,7 +1896,7 @@ class HyASTCompiler(object):
|
|||||||
ret, args, defaults, stararg, kwargs = self._parse_lambda_list(arglist)
|
ret, args, defaults, stararg, kwargs = self._parse_lambda_list(arglist)
|
||||||
|
|
||||||
if PY34:
|
if PY34:
|
||||||
# Python 3.4+ requres that args are an ast.arg object, rather
|
# Python 3.4+ requires that args are an ast.arg object, rather
|
||||||
# than an ast.Name or bare string.
|
# than an ast.Name or bare string.
|
||||||
args = [ast.arg(arg=ast_str(x),
|
args = [ast.arg(arg=ast_str(x),
|
||||||
annotation=None, # Fix me!
|
annotation=None, # Fix me!
|
||||||
@ -1963,12 +2004,12 @@ class HyASTCompiler(object):
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
raise HyTypeError(
|
raise HyTypeError(
|
||||||
expression,
|
expression,
|
||||||
"Wrong argument type for defclass slots definition.")
|
"Wrong argument type for defclass attributes definition.")
|
||||||
for b in body_expression:
|
for b in body_expression:
|
||||||
if len(b) != 2:
|
if len(b) != 2:
|
||||||
raise HyTypeError(
|
raise HyTypeError(
|
||||||
expression,
|
expression,
|
||||||
"Wrong number of argument in defclass slot.")
|
"Wrong number of argument in defclass attribute.")
|
||||||
body += self._compile_assign(b[0], b[1],
|
body += self._compile_assign(b[0], b[1],
|
||||||
b.start_line, b.start_column)
|
b.start_line, b.start_column)
|
||||||
body += body.expr_as_stmt()
|
body += body.expr_as_stmt()
|
||||||
|
@ -46,9 +46,10 @@
|
|||||||
|
|
||||||
(defmacro ap-map [form lst]
|
(defmacro ap-map [form lst]
|
||||||
"Yield elements evaluated in the form for each element in the list."
|
"Yield elements evaluated in the form for each element in the list."
|
||||||
`(let [[f (lambda [it] ~form)]]
|
(let [[v (gensym 'v)] [f (gensym 'f)]]
|
||||||
(for [v ~lst]
|
`(let [[~f (lambda [it] ~form)]]
|
||||||
(yield (f v)))))
|
(for [~v ~lst]
|
||||||
|
(yield (~f ~v))))))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-map-when [predfn rep lst]
|
(defmacro ap-map-when [predfn rep lst]
|
||||||
@ -83,18 +84,20 @@
|
|||||||
|
|
||||||
(defmacro ap-first [predfn lst]
|
(defmacro ap-first [predfn lst]
|
||||||
"Yield the first element that passes `predfn`"
|
"Yield the first element that passes `predfn`"
|
||||||
`(let [[n (gensym)]]
|
(with-gensyms [n]
|
||||||
(ap-each ~lst (when ~predfn (setv n it) (break)))
|
`(let [[~n None]]
|
||||||
n))
|
(ap-each ~lst (when ~predfn (setv ~n it) (break)))
|
||||||
|
~n)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-last [predfn lst]
|
(defmacro ap-last [predfn lst]
|
||||||
"Yield the last element that passes `predfn`"
|
"Yield the last element that passes `predfn`"
|
||||||
`(let [[n (gensym)]]
|
(with-gensyms [n]
|
||||||
(ap-each ~lst (none? n)
|
`(let [[~n None]]
|
||||||
(when ~predfn
|
(ap-each ~lst (none? ~n)
|
||||||
(setv n it)))
|
(when ~predfn
|
||||||
n))
|
(setv ~n it)))
|
||||||
|
~n)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-reduce [form lst &optional [initial-value None]]
|
(defmacro ap-reduce [form lst &optional [initial-value None]]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
STDLIB = [
|
STDLIB = [
|
||||||
"hy.core.language"
|
"hy.core.language",
|
||||||
|
"hy.core.shadow"
|
||||||
]
|
]
|
||||||
|
@ -26,14 +26,20 @@
|
|||||||
(import itertools)
|
(import itertools)
|
||||||
(import functools)
|
(import functools)
|
||||||
(import collections)
|
(import collections)
|
||||||
|
(import sys)
|
||||||
(import [hy._compat [long-type]]) ; long for python2, int for python3
|
(import [hy._compat [long-type]]) ; long for python2, int for python3
|
||||||
(import [hy.models.cons [HyCons]])
|
(import [hy.models.cons [HyCons]]
|
||||||
|
[hy.models.keyword [HyKeyword *keyword-prefix*]])
|
||||||
|
(import [hy.lex [LexException PrematureEndOfInput tokenize]])
|
||||||
|
|
||||||
(defn _numeric-check [x]
|
(defn _numeric-check [x]
|
||||||
(if (not (numeric? x))
|
(if (not (numeric? x))
|
||||||
(raise (TypeError (.format "{0!r} is not a number" x)))))
|
(raise (TypeError (.format "{0!r} is not a number" x)))))
|
||||||
|
|
||||||
|
(defn butlast [coll]
|
||||||
|
"Returns coll except of last element."
|
||||||
|
(drop-last 1 coll))
|
||||||
|
|
||||||
(defn coll? [coll]
|
(defn coll? [coll]
|
||||||
"Checks whether item is a collection"
|
"Checks whether item is a collection"
|
||||||
(and (iterable? coll) (not (string? coll))))
|
(and (iterable? coll) (not (string? coll))))
|
||||||
@ -51,24 +57,23 @@
|
|||||||
(and (instance? (type :foo) k)
|
(and (instance? (type :foo) k)
|
||||||
(.startswith k (get :foo 0))))
|
(.startswith k (get :foo 0))))
|
||||||
|
|
||||||
|
|
||||||
(defn dec [n]
|
(defn dec [n]
|
||||||
"Decrement n by 1"
|
"Decrement n by 1"
|
||||||
(_numeric-check n)
|
(_numeric-check n)
|
||||||
(- n 1))
|
(- n 1))
|
||||||
|
|
||||||
(defn disassemble [tree &optional [codegen false]]
|
(defn disassemble [tree &optional [codegen false]]
|
||||||
"Dump the python AST for a given Hy tree to standard output
|
"Return the python AST for a quoted Hy tree as a string.
|
||||||
If the second argument is true, generate python code instead."
|
If the second argument is true, generate python code instead."
|
||||||
(import astor)
|
(import astor)
|
||||||
(import hy.compiler)
|
(import hy.compiler)
|
||||||
|
|
||||||
(fake-source-positions tree)
|
(fake-source-positions tree)
|
||||||
(setv compiled (hy.compiler.hy_compile tree (calling-module-name)))
|
(setv compiled (hy.compiler.hy_compile tree (calling-module-name)))
|
||||||
(print ((if codegen
|
((if codegen
|
||||||
astor.codegen.to_source
|
astor.codegen.to_source
|
||||||
astor.dump)
|
astor.dump)
|
||||||
compiled)))
|
compiled))
|
||||||
|
|
||||||
(defn distinct [coll]
|
(defn distinct [coll]
|
||||||
"Return a generator from the original collection with duplicates
|
"Return a generator from the original collection with duplicates
|
||||||
@ -88,7 +93,8 @@
|
|||||||
(setv map itertools.imap)
|
(setv map itertools.imap)
|
||||||
(setv zip itertools.izip)
|
(setv zip itertools.izip)
|
||||||
(setv range xrange)
|
(setv range xrange)
|
||||||
(setv input raw_input))
|
(setv input raw_input)
|
||||||
|
(setv reduce reduce))
|
||||||
(do
|
(do
|
||||||
(setv reduce functools.reduce)
|
(setv reduce functools.reduce)
|
||||||
(setv filterfalse itertools.filterfalse)
|
(setv filterfalse itertools.filterfalse)
|
||||||
@ -106,11 +112,18 @@
|
|||||||
(setv drop-while itertools.dropwhile)
|
(setv drop-while itertools.dropwhile)
|
||||||
(setv take-while itertools.takewhile)
|
(setv take-while itertools.takewhile)
|
||||||
(setv zipwith map)
|
(setv zipwith map)
|
||||||
|
(setv remove filterfalse)
|
||||||
|
|
||||||
(defn drop [count coll]
|
(defn drop [count coll]
|
||||||
"Drop `count` elements from `coll` and yield back the rest"
|
"Drop `count` elements from `coll` and yield back the rest"
|
||||||
(itertools.islice coll count nil))
|
(itertools.islice coll count nil))
|
||||||
|
|
||||||
|
(defn drop-last [n coll]
|
||||||
|
"Return a sequence of all but the last n elements in coll."
|
||||||
|
(let [[iters (itertools.tee coll)]]
|
||||||
|
(map first (apply zip [(get iters 0)
|
||||||
|
(drop n (get iters 1))]))))
|
||||||
|
|
||||||
(defn empty? [coll]
|
(defn empty? [coll]
|
||||||
"Return True if `coll` is empty"
|
"Return True if `coll` is empty"
|
||||||
(= 0 (len coll)))
|
(= 0 (len coll)))
|
||||||
@ -203,6 +216,14 @@
|
|||||||
(catch [e ValueError] False)
|
(catch [e ValueError] False)
|
||||||
(catch [e TypeError] False)))
|
(catch [e TypeError] False)))
|
||||||
|
|
||||||
|
(defn interleave [&rest seqs]
|
||||||
|
"Return an iterable of the first item in each of seqs, then the second etc."
|
||||||
|
(itertools.chain.from_iterable (apply zip seqs)))
|
||||||
|
|
||||||
|
(defn interpose [item seq]
|
||||||
|
"Return an iterable of the elements of seq separated by item"
|
||||||
|
(drop 1 (interleave (itertools.repeat item) seq)))
|
||||||
|
|
||||||
(defn iterable? [x]
|
(defn iterable? [x]
|
||||||
"Return true if x is iterable"
|
"Return true if x is iterable"
|
||||||
(isinstance x collections.Iterable))
|
(isinstance x collections.Iterable))
|
||||||
@ -237,6 +258,22 @@
|
|||||||
(setv name (calling-module-name))
|
(setv name (calling-module-name))
|
||||||
(hy.macros.macroexpand-1 form name))
|
(hy.macros.macroexpand-1 form name))
|
||||||
|
|
||||||
|
(defn merge-with [f &rest maps]
|
||||||
|
"Returns a map that consists of the rest of the maps joined onto
|
||||||
|
the first. If a key occurs in more than one map, the mapping(s)
|
||||||
|
from the latter (left-to-right) will be combined with the mapping in
|
||||||
|
the result by calling (f val-in-result val-in-latter)."
|
||||||
|
(if (any maps)
|
||||||
|
(let [[merge-entry (fn [m e]
|
||||||
|
(let [[k (get e 0)] [v (get e 1)]]
|
||||||
|
(if (in k m)
|
||||||
|
(assoc m k (f (get m k) v))
|
||||||
|
(assoc m k v)))
|
||||||
|
m)]
|
||||||
|
[merge2 (fn [m1 m2]
|
||||||
|
(reduce merge-entry (.items m2) (or m1 {})))]]
|
||||||
|
(reduce merge2 maps))))
|
||||||
|
|
||||||
(defn neg? [n]
|
(defn neg? [n]
|
||||||
"Return true if n is < 0"
|
"Return true if n is < 0"
|
||||||
(_numeric-check n)
|
(_numeric-check n)
|
||||||
@ -254,11 +291,10 @@
|
|||||||
(import numbers)
|
(import numbers)
|
||||||
(instance? numbers.Number x))
|
(instance? numbers.Number x))
|
||||||
|
|
||||||
(defn nth [coll index]
|
(defn nth [coll n &optional [default nil]]
|
||||||
"Return nth item in collection or sequence, counting from 0"
|
"Return nth item in collection or sequence, counting from 0.
|
||||||
(try
|
Return nil if out of bounds unless specified otherwise."
|
||||||
(next (drop index coll))
|
(next (drop n coll) default))
|
||||||
(catch [e StopIteration] (raise (IndexError index)))))
|
|
||||||
|
|
||||||
(defn odd? [n]
|
(defn odd? [n]
|
||||||
"Return true if n is an odd number"
|
"Return true if n is an odd number"
|
||||||
@ -270,13 +306,6 @@
|
|||||||
(_numeric_check n)
|
(_numeric_check n)
|
||||||
(> n 0))
|
(> n 0))
|
||||||
|
|
||||||
(defn remove [pred coll]
|
|
||||||
"Return coll with elements removed that pass `pred`"
|
|
||||||
(let [[citer (iter coll)]]
|
|
||||||
(for* [val citer]
|
|
||||||
(if (not (pred val))
|
|
||||||
(yield val)))))
|
|
||||||
|
|
||||||
(defn rest [coll]
|
(defn rest [coll]
|
||||||
"Get all the elements of a coll, except the first."
|
"Get all the elements of a coll, except the first."
|
||||||
(drop 1 coll))
|
(drop 1 coll))
|
||||||
@ -291,8 +320,8 @@
|
|||||||
(nth coll 1))
|
(nth coll 1))
|
||||||
|
|
||||||
(defn some [pred coll]
|
(defn some [pred coll]
|
||||||
"Return true if (pred x) is logical true for any x in coll, else false"
|
"Return the first logical true value of (pred x) for any x in coll, else nil"
|
||||||
(any (map pred coll)))
|
(first (filter nil (map pred coll))))
|
||||||
|
|
||||||
(defn string [x]
|
(defn string [x]
|
||||||
"Cast x as current string implementation"
|
"Cast x as current string implementation"
|
||||||
@ -327,10 +356,63 @@
|
|||||||
(_numeric_check n)
|
(_numeric_check n)
|
||||||
(= n 0))
|
(= n 0))
|
||||||
|
|
||||||
(def *exports* '[calling-module-name coll? cons cons? cycle dec distinct
|
(defn read [&optional [from-file sys.stdin]
|
||||||
disassemble drop drop-while empty? even? every? first filter
|
[eof ""]]
|
||||||
flatten float? gensym identity inc instance? integer
|
"Read from input and returns a tokenized string.
|
||||||
integer? integer-char? iterable? iterate iterator? keyword?
|
Can take a given input buffer to read from"
|
||||||
list* macroexpand macroexpand-1 map neg? nil? none? nth
|
(def buff "")
|
||||||
numeric? odd? pos? range remove repeat repeatedly rest second
|
(while true
|
||||||
some string string? take take-nth take-while zero? zip zipwith])
|
(def inn (str (.read from-file 1)))
|
||||||
|
(if (= inn eof)
|
||||||
|
(throw (EOFError "Reached end of file" )))
|
||||||
|
(setv buff (+ buff inn))
|
||||||
|
(try
|
||||||
|
(def parsed (first (tokenize buff)))
|
||||||
|
(except [e [LexException PrematureEndOfInput IndexError]])
|
||||||
|
(else (if parsed (break)))))
|
||||||
|
parsed)
|
||||||
|
|
||||||
|
(defun Botsbuildbots () (Botsbuildbots))
|
||||||
|
|
||||||
|
(defn zipwith [func &rest lists]
|
||||||
|
"Zip the contents of several lists and map a function to the result"
|
||||||
|
(do
|
||||||
|
(import functools)
|
||||||
|
(map (functools.partial (fn [f args] (apply f args)) func) (apply zip lists))))
|
||||||
|
|
||||||
|
(defn hyify [text]
|
||||||
|
"Convert text to match hy identifier"
|
||||||
|
(.replace (string text) "_" "-"))
|
||||||
|
|
||||||
|
(defn keyword [value]
|
||||||
|
"Create a keyword from the given value. Strings numbers and even objects
|
||||||
|
with the __name__ magic will work"
|
||||||
|
(if (and (string? value) (value.startswith *keyword-prefix*))
|
||||||
|
(hyify value)
|
||||||
|
(if (string? value)
|
||||||
|
(HyKeyword (+ ":" (hyify value)))
|
||||||
|
(try
|
||||||
|
(hyify (.__name__ value))
|
||||||
|
(catch [] (HyKeyword (+ ":" (string value))))))))
|
||||||
|
|
||||||
|
(defn name [value]
|
||||||
|
"Convert the given value to a string. Keyword special character will be stripped.
|
||||||
|
String will be used as is. Even objects with the __name__ magic will work"
|
||||||
|
(if (and (string? value) (value.startswith *keyword-prefix*))
|
||||||
|
(hyify (slice value 2))
|
||||||
|
(if (string? value)
|
||||||
|
(hyify value)
|
||||||
|
(try
|
||||||
|
(hyify (. value __name__))
|
||||||
|
(catch [] (string value))))))
|
||||||
|
|
||||||
|
(def *exports* '[Botsbuildbots
|
||||||
|
butlast calling-module-name coll? cons cons? cycle
|
||||||
|
dec distinct disassemble drop drop-last drop-while empty? even?
|
||||||
|
every? first filter filterfalse flatten float? gensym identity
|
||||||
|
inc input instance? integer integer? integer-char? interleave
|
||||||
|
interpose iterable? iterate iterator? keyword keyword? list*
|
||||||
|
macroexpand macroexpand-1 map merge-with name neg? nil? none?
|
||||||
|
nth numeric? odd? pos? range read remove repeat repeatedly
|
||||||
|
rest reduce second some string string? take take-nth
|
||||||
|
take-while zero? zip zip_longest zipwith])
|
||||||
|
@ -31,34 +31,6 @@
|
|||||||
[hy._compat [PY33 PY34]])
|
[hy._compat [PY33 PY34]])
|
||||||
|
|
||||||
|
|
||||||
(defmacro for [args &rest body]
|
|
||||||
"shorthand for nested for loops:
|
|
||||||
(for [x foo
|
|
||||||
y bar]
|
|
||||||
baz) ->
|
|
||||||
(for* [x foo]
|
|
||||||
(for* [y bar]
|
|
||||||
baz))"
|
|
||||||
|
|
||||||
(if (odd? (len args))
|
|
||||||
(macro-error args "`for' requires an even number of args."))
|
|
||||||
|
|
||||||
(if (empty? body)
|
|
||||||
(macro-error None "`for' requires a body to evaluate"))
|
|
||||||
|
|
||||||
(if (empty? args)
|
|
||||||
`(do ~@body)
|
|
||||||
(if (= (len args) 2)
|
|
||||||
; basecase, let's just slip right in.
|
|
||||||
`(for* [~@args] ~@body)
|
|
||||||
; otherwise, let's do some legit handling.
|
|
||||||
(let [[alist (slice args 0 nil 2)]
|
|
||||||
[ilist (slice args 1 nil 2)]]
|
|
||||||
`(do
|
|
||||||
(import itertools)
|
|
||||||
(for* [(, ~@alist) (itertools.product ~@ilist)] ~@body))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defmacro with [args &rest body]
|
(defmacro with [args &rest body]
|
||||||
"shorthand for nested for* loops:
|
"shorthand for nested for* loops:
|
||||||
(with [[x foo] [y bar]] baz) ->
|
(with [[x foo] [y bar]] baz) ->
|
||||||
@ -116,6 +88,26 @@
|
|||||||
root)
|
root)
|
||||||
|
|
||||||
|
|
||||||
|
(defmacro for [args &rest body]
|
||||||
|
"shorthand for nested for loops:
|
||||||
|
(for [x foo
|
||||||
|
y bar]
|
||||||
|
baz) ->
|
||||||
|
(for* [x foo]
|
||||||
|
(for* [y bar]
|
||||||
|
baz))"
|
||||||
|
(cond
|
||||||
|
[(odd? (len args))
|
||||||
|
(macro-error args "`for' requires an even number of args.")]
|
||||||
|
[(empty? body)
|
||||||
|
(macro-error None "`for' requires a body to evaluate")]
|
||||||
|
[(empty? args) `(do ~@body)]
|
||||||
|
[(= (len args) 2) `(for* [~@args] ~@body)]
|
||||||
|
[true
|
||||||
|
(let [[alist (slice args 0 nil 2)]]
|
||||||
|
`(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] ~@body))]))
|
||||||
|
|
||||||
|
|
||||||
(defmacro -> [head &rest rest]
|
(defmacro -> [head &rest rest]
|
||||||
;; TODO: fix the docstring by someone who understands this
|
;; TODO: fix the docstring by someone who understands this
|
||||||
(setv ret head)
|
(setv ret head)
|
||||||
@ -127,6 +119,18 @@
|
|||||||
ret)
|
ret)
|
||||||
|
|
||||||
|
|
||||||
|
(defmacro doto [form &rest expressions]
|
||||||
|
"Performs a sequence of potentially mutating actions
|
||||||
|
on an initial object, returning the resulting object"
|
||||||
|
(setv f (gensym))
|
||||||
|
(defn build-form [expression]
|
||||||
|
(if (isinstance expression HyExpression)
|
||||||
|
`(~(first expression) ~f ~@(rest expression))
|
||||||
|
`(~expression ~f)))
|
||||||
|
`(let [[~f ~form]]
|
||||||
|
~@(map build-form expressions)
|
||||||
|
~f))
|
||||||
|
|
||||||
(defmacro ->> [head &rest rest]
|
(defmacro ->> [head &rest rest]
|
||||||
;; TODO: fix the docstring by someone who understands this
|
;; TODO: fix the docstring by someone who understands this
|
||||||
(setv ret head)
|
(setv ret head)
|
||||||
@ -149,6 +153,10 @@
|
|||||||
"Like `if`, but anything that is not None/nil is considered true."
|
"Like `if`, but anything that is not None/nil is considered true."
|
||||||
`(if (is-not ~test nil) ~@branches))
|
`(if (is-not ~test nil) ~@branches))
|
||||||
|
|
||||||
|
(defmacro-alias [lisp-if-not lif-not] [test &rest branches]
|
||||||
|
"Like `if-not`, but anything that is not None/nil is considered true."
|
||||||
|
`(if (is ~test nil) ~@branches))
|
||||||
|
|
||||||
|
|
||||||
(defmacro when [test &rest body]
|
(defmacro when [test &rest body]
|
||||||
"Execute `body` when `test` is true"
|
"Execute `body` when `test` is true"
|
||||||
@ -165,11 +173,26 @@
|
|||||||
~@body))
|
~@body))
|
||||||
|
|
||||||
(defmacro defmacro/g! [name args &rest body]
|
(defmacro defmacro/g! [name args &rest body]
|
||||||
(let [[syms (list (distinct (filter (fn [x] (.startswith x "g!")) (flatten body))))]]
|
(let [[syms (list (distinct (filter (fn [x] (and (hasattr x "startswith") (.startswith x "g!"))) (flatten body))))]]
|
||||||
`(defmacro ~name [~@args]
|
`(defmacro ~name [~@args]
|
||||||
(let ~(HyList (map (fn [x] `[~x (gensym (slice '~x 2))]) syms))
|
(let ~(HyList (map (fn [x] `[~x (gensym (slice '~x 2))]) syms))
|
||||||
~@body))))
|
~@body))))
|
||||||
|
|
||||||
|
|
||||||
|
(defmacro defmain [args &rest body]
|
||||||
|
"Write a function named \"main\" and do the if __main__ dance"
|
||||||
|
(let [[retval (gensym)]]
|
||||||
|
`(do
|
||||||
|
(defn main [~@args]
|
||||||
|
~@body)
|
||||||
|
|
||||||
|
(when (= --name-- "__main__")
|
||||||
|
(import sys)
|
||||||
|
(setv ~retval (apply main sys.argv))
|
||||||
|
(if (integer? ~retval)
|
||||||
|
(sys.exit ~retval))))))
|
||||||
|
|
||||||
|
|
||||||
(defmacro-alias [defn-alias defun-alias] [names lambda-list &rest body]
|
(defmacro-alias [defn-alias defun-alias] [names lambda-list &rest body]
|
||||||
"define one function with several names"
|
"define one function with several names"
|
||||||
(let [[main (first names)]
|
(let [[main (first names)]
|
||||||
@ -179,3 +202,15 @@
|
|||||||
(.append ret
|
(.append ret
|
||||||
`(setv ~name ~main)))
|
`(setv ~name ~main)))
|
||||||
ret))
|
ret))
|
||||||
|
|
||||||
|
(defmacro Botsbuildbots []
|
||||||
|
"Build bots, repeatedly.^W^W^WPrint the AUTHORS, forever."
|
||||||
|
`(try
|
||||||
|
(do
|
||||||
|
(import [requests])
|
||||||
|
|
||||||
|
(let [[r (requests.get
|
||||||
|
"https://raw.githubusercontent.com/hylang/hy/master/AUTHORS")]]
|
||||||
|
(repeat r.text)))
|
||||||
|
(catch [e ImportError]
|
||||||
|
(repeat "Botsbuildbots requires `requests' to function."))))
|
||||||
|
64
hy/core/shadow.hy
Normal file
64
hy/core/shadow.hy
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
;; Copyright (c) 2014 Paul Tagliamonte <paultag@debian.org>
|
||||||
|
;; Copyright (c) 2014 James King <james@agentultra.com>
|
||||||
|
|
||||||
|
;; Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
;; copy of this software and associated documentation files (the "Software"),
|
||||||
|
;; to deal in the Software without restriction, including without limitation
|
||||||
|
;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
;; and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
;; Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
;; The above copyright notice and this permission notice shall be included in
|
||||||
|
;; all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
;; DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
;;;; Hy shadow functions
|
||||||
|
|
||||||
|
(import operator)
|
||||||
|
|
||||||
|
|
||||||
|
(defn + [&rest args]
|
||||||
|
"Shadow + operator for when we need to import / map it against something"
|
||||||
|
(let [[count (len args)]]
|
||||||
|
(if (zero? count)
|
||||||
|
(raise (TypeError "Need at least 1 argument to add/concatenate"))
|
||||||
|
(if (= count 1)
|
||||||
|
(get args 0)
|
||||||
|
(reduce operator.add args)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn - [&rest args]
|
||||||
|
"Shadow - operator for when we need to import / map it against something"
|
||||||
|
(let [[count (len args)]]
|
||||||
|
(if (= count 0)
|
||||||
|
(raise (TypeError "Need at least 1 argument to subtract"))
|
||||||
|
(if (= count 1)
|
||||||
|
(- (get args 0))
|
||||||
|
(reduce operator.sub args)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn * [&rest args]
|
||||||
|
"Shadow * operator for when we need to import / map it against something"
|
||||||
|
(if (= (len args) 0)
|
||||||
|
1 ; identity
|
||||||
|
(reduce operator.mul args)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn / [&rest args]
|
||||||
|
"Shadow / operator for when we need to import / map it against something"
|
||||||
|
(let [[count (len args)]]
|
||||||
|
(if (= count 0)
|
||||||
|
(raise (TypeError "Need at least 1 argument to divide"))
|
||||||
|
(if (= count 1)
|
||||||
|
(operator.truediv 1 (get args 0))
|
||||||
|
(reduce operator.truediv args)))))
|
||||||
|
|
||||||
|
|
||||||
|
(setv *exports* ['+ '- '* '/])
|
@ -28,7 +28,7 @@ import traceback
|
|||||||
|
|
||||||
class HyError(Exception):
|
class HyError(Exception):
|
||||||
"""
|
"""
|
||||||
Generic Hy error. All interal Exceptions will be subclassed from this
|
Generic Hy error. All internal Exceptions will be subclassed from this
|
||||||
Exception.
|
Exception.
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
@ -30,7 +30,6 @@ from hy.models.expression import HyExpression
|
|||||||
from hy.models.float import HyFloat
|
from hy.models.float import HyFloat
|
||||||
from hy.models.integer import HyInteger
|
from hy.models.integer import HyInteger
|
||||||
from hy.models.keyword import HyKeyword
|
from hy.models.keyword import HyKeyword
|
||||||
from hy.models.lambdalist import HyLambdaListKeyword
|
|
||||||
from hy.models.list import HyList
|
from hy.models.list import HyList
|
||||||
from hy.models.string import HyString
|
from hy.models.string import HyString
|
||||||
from hy.models.symbol import HySymbol
|
from hy.models.symbol import HySymbol
|
||||||
@ -271,9 +270,6 @@ def t_identifier(p):
|
|||||||
if obj.startswith(":"):
|
if obj.startswith(":"):
|
||||||
return HyKeyword(obj)
|
return HyKeyword(obj)
|
||||||
|
|
||||||
if obj.startswith("&"):
|
|
||||||
return HyLambdaListKeyword(obj)
|
|
||||||
|
|
||||||
def mangle(p):
|
def mangle(p):
|
||||||
if p.startswith("*") and p.endswith("*") and p not in ("*", "**"):
|
if p.startswith("*") and p.endswith("*") and p not in ("*", "**"):
|
||||||
p = p[1:-1].upper()
|
p = p[1:-1].upper()
|
||||||
|
@ -117,6 +117,7 @@ _wrappers = {
|
|||||||
list: lambda l: HyList(_wrap_value(x) for x in l),
|
list: lambda l: HyList(_wrap_value(x) for x in l),
|
||||||
tuple: lambda t: HyList(_wrap_value(x) for x in t),
|
tuple: lambda t: HyList(_wrap_value(x) for x in t),
|
||||||
type(None): lambda foo: HySymbol("None"),
|
type(None): lambda foo: HySymbol("None"),
|
||||||
|
HyExpression: lambda e: HyExpression(_wrap_value(x) for x in e),
|
||||||
}
|
}
|
||||||
|
|
||||||
if sys.version_info[0] < 3: # do not add long on python3
|
if sys.version_info[0] < 3: # do not add long on python3
|
||||||
|
@ -23,7 +23,7 @@ from hy.models import HyObject
|
|||||||
|
|
||||||
class HyComplex(HyObject, complex):
|
class HyComplex(HyObject, complex):
|
||||||
"""
|
"""
|
||||||
Internal represntation of a Hy Complex. May raise a ValueError as if
|
Internal representation of a Hy Complex. May raise a ValueError as if
|
||||||
complex(foo) was called, given HyComplex(foo).
|
complex(foo) was called, given HyComplex(foo).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ from hy.models import HyObject
|
|||||||
|
|
||||||
class HyFloat(HyObject, float):
|
class HyFloat(HyObject, float):
|
||||||
"""
|
"""
|
||||||
Internal represntation of a Hy Float. May raise a ValueError as if
|
Internal representation of a Hy Float. May raise a ValueError as if
|
||||||
float(foo) was called, given HyFloat(foo).
|
float(foo) was called, given HyFloat(foo).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ from hy._compat import long_type
|
|||||||
|
|
||||||
class HyInteger(HyObject, long_type):
|
class HyInteger(HyObject, long_type):
|
||||||
"""
|
"""
|
||||||
Internal represntation of a Hy Integer. May raise a ValueError as if
|
Internal representation of a Hy Integer. May raise a ValueError as if
|
||||||
int(foo) was called, given HyInteger(foo). On python 2.x long will
|
int(foo) was called, given HyInteger(foo). On python 2.x long will
|
||||||
be used instead
|
be used instead
|
||||||
"""
|
"""
|
||||||
|
@ -23,14 +23,17 @@ from hy.models import HyObject
|
|||||||
from hy._compat import str_type
|
from hy._compat import str_type
|
||||||
|
|
||||||
|
|
||||||
|
KEYWORD_PREFIX = "\uFDD0"
|
||||||
|
|
||||||
|
|
||||||
class HyKeyword(HyObject, str_type):
|
class HyKeyword(HyObject, str_type):
|
||||||
"""Generic Hy Keyword object. It's either a ``str`` or a ``unicode``,
|
"""Generic Hy Keyword object. It's either a ``str`` or a ``unicode``,
|
||||||
depending on the Python version.
|
depending on the Python version.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __new__(cls, value):
|
def __new__(cls, value):
|
||||||
if not value.startswith("\uFDD0"):
|
if not value.startswith(KEYWORD_PREFIX):
|
||||||
value = "\uFDD0" + value
|
value = KEYWORD_PREFIX + value
|
||||||
|
|
||||||
obj = str_type.__new__(cls, value)
|
obj = str_type.__new__(cls, value)
|
||||||
return obj
|
return obj
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
# Copyright (c) 2013 James King <james@agentultra.com>
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
# copy of this software and associated documentation files (the "Software"),
|
|
||||||
# to deal in the Software without restriction, including without limitation
|
|
||||||
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
# and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
# Software is furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in
|
|
||||||
# all copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
# DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
from hy.models.string import HyString
|
|
||||||
|
|
||||||
|
|
||||||
class HyLambdaListKeyword(HyString):
|
|
||||||
"""
|
|
||||||
Hy LambdaListKeyword. Demarcates arguments in an argument list.
|
|
||||||
|
|
||||||
(defun my-fun (x &rest xs &optional (foo "default string")))
|
|
||||||
|
|
||||||
becomes:
|
|
||||||
|
|
||||||
def my_fun(x, *xs, foo="default string"):
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
|
|
||||||
_valid_types = ["&rest", "&optional", "&key", "&kwargs"]
|
|
||||||
|
|
||||||
def __init__(self, string):
|
|
||||||
self += string
|
|
@ -20,4 +20,4 @@
|
|||||||
|
|
||||||
|
|
||||||
__appname__ = "hy"
|
__appname__ = "hy"
|
||||||
__version__ = "0.10.0"
|
__version__ = "0.10.1"
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
|
-r requirements-travis.txt
|
||||||
# test tools
|
# test tools
|
||||||
nose
|
nose
|
||||||
tox
|
tox
|
||||||
|
|
||||||
# code quality
|
|
||||||
flake8
|
|
||||||
coverage
|
|
||||||
|
|
||||||
# documentation
|
# documentation
|
||||||
Pygments>=1.6
|
Pygments>=1.6
|
||||||
Sphinx
|
Sphinx
|
||||||
|
5
requirements-travis.txt
Normal file
5
requirements-travis.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# for Botsbuildbots
|
||||||
|
requests
|
||||||
|
# code quality
|
||||||
|
flake8
|
||||||
|
coverage
|
66
scripts/reformat-changelog
Executable file
66
scripts/reformat-changelog
Executable file
@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/env hy
|
||||||
|
|
||||||
|
(import re)
|
||||||
|
(import pdb)
|
||||||
|
(import codecs)
|
||||||
|
|
||||||
|
(setv *maintainer-line*
|
||||||
|
" -- Alexander Artemenko <svetlyak.40wt@gmail.com> Thu, 30 Sep 2014 13:06:09 +0400")
|
||||||
|
|
||||||
|
(defun read-lines-from-file [filename]
|
||||||
|
(let [[f (codecs.open filename "r" "utf-8")]]
|
||||||
|
(fn [] (let [[line (.readline f) ]]
|
||||||
|
line))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun get-version-number [line]
|
||||||
|
(let [[match (re.search r"Changes from.*(\d+\.\d+\.\d+)$" line)]]
|
||||||
|
(if match
|
||||||
|
(let [[version (.group match (int 1))]
|
||||||
|
[numbered (list (map int (.split version "."))) ]
|
||||||
|
[explicit-mapping {"0.9.12" "0.10.0"
|
||||||
|
"0.8.2" "0.9.0"}]]
|
||||||
|
(assoc numbered 2 (+ (get numbered 2) 1))
|
||||||
|
(.get explicit-mapping
|
||||||
|
version
|
||||||
|
(.join "." (map str numbered)))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun read-version-content [reader]
|
||||||
|
(setv line (reader))
|
||||||
|
(setv content [])
|
||||||
|
(while (and line (not (get-version-number line)))
|
||||||
|
(.append content (.strip line))
|
||||||
|
(setv line (reader)))
|
||||||
|
[content line])
|
||||||
|
|
||||||
|
|
||||||
|
(defun read-versions-from-file [filename]
|
||||||
|
(let [[reader (read-lines-from-file filename)]]
|
||||||
|
(read-versions-rec (reader)
|
||||||
|
reader)))
|
||||||
|
|
||||||
|
(defun read-versions-rec [line reader]
|
||||||
|
(if line
|
||||||
|
(let [[version (get-version-number line)]
|
||||||
|
[[content next-line] (read-version-content reader)]]
|
||||||
|
|
||||||
|
(+ [{"from" version
|
||||||
|
"content" content}]
|
||||||
|
(read-versions-rec next-line reader)))
|
||||||
|
[]))
|
||||||
|
|
||||||
|
(defun format-deb-version [version]
|
||||||
|
(setv result [(.format "hy ({}) unstable; urgency=low"
|
||||||
|
(get version "from"))])
|
||||||
|
(for [line (get version "content")]
|
||||||
|
(.append result (+ " " line)))
|
||||||
|
(.append result *maintainer-line*)
|
||||||
|
(.append result "")
|
||||||
|
(.join "\n" result))
|
||||||
|
|
||||||
|
|
||||||
|
(defmain [&rest args]
|
||||||
|
(let ((versions (read-versions-from-file "NEWS")))
|
||||||
|
(for [version versions]
|
||||||
|
(print (.encode (format-deb-version version) "utf-8")))))
|
@ -1,7 +1,6 @@
|
|||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
import hy # noqa
|
import hy # noqa
|
||||||
|
from hy._compat import PY3
|
||||||
from .native_tests.cons import * # noqa
|
from .native_tests.cons import * # noqa
|
||||||
from .native_tests.defclass import * # noqa
|
from .native_tests.defclass import * # noqa
|
||||||
from .native_tests.mathematics import * # noqa
|
from .native_tests.mathematics import * # noqa
|
||||||
@ -13,6 +12,7 @@ from .native_tests.when import * # noqa
|
|||||||
from .native_tests.with_decorator import * # noqa
|
from .native_tests.with_decorator import * # noqa
|
||||||
from .native_tests.core import * # noqa
|
from .native_tests.core import * # noqa
|
||||||
from .native_tests.reader_macros import * # noqa
|
from .native_tests.reader_macros import * # noqa
|
||||||
|
from .native_tests.shadow import * # noqa
|
||||||
from .native_tests.with_test import * # noqa
|
from .native_tests.with_test import * # noqa
|
||||||
from .native_tests.contrib.anaphoric import * # noqa
|
from .native_tests.contrib.anaphoric import * # noqa
|
||||||
from .native_tests.contrib.loop import * # noqa
|
from .native_tests.contrib.loop import * # noqa
|
||||||
@ -20,3 +20,6 @@ from .native_tests.contrib.meth import * # noqa
|
|||||||
from .native_tests.contrib.walk import * # noqa
|
from .native_tests.contrib.walk import * # noqa
|
||||||
from .native_tests.contrib.multi import * # noqa
|
from .native_tests.contrib.multi import * # noqa
|
||||||
from .native_tests.contrib.curry import * # noqa
|
from .native_tests.contrib.curry import * # noqa
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
from .native_tests.py3_only_tests import * # noqa
|
||||||
|
@ -27,6 +27,7 @@ from hy.compiler import hy_compile
|
|||||||
from hy.errors import HyCompileError, HyTypeError
|
from hy.errors import HyCompileError, HyTypeError
|
||||||
from hy.lex.exceptions import LexException
|
from hy.lex.exceptions import LexException
|
||||||
from hy.lex import tokenize
|
from hy.lex import tokenize
|
||||||
|
from hy._compat import PY3
|
||||||
|
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
@ -111,23 +112,29 @@ def test_ast_good_do():
|
|||||||
def test_ast_good_throw():
|
def test_ast_good_throw():
|
||||||
"Make sure AST can compile valid throw"
|
"Make sure AST can compile valid throw"
|
||||||
can_compile("(throw)")
|
can_compile("(throw)")
|
||||||
can_compile("(throw 1)")
|
can_compile("(throw Exception)")
|
||||||
|
|
||||||
|
|
||||||
def test_ast_bad_throw():
|
def test_ast_bad_throw():
|
||||||
"Make sure AST can't compile invalid throw"
|
"Make sure AST can't compile invalid throw"
|
||||||
cant_compile("(raise 1 2 3)")
|
cant_compile("(throw Exception Exception)")
|
||||||
|
|
||||||
|
|
||||||
def test_ast_good_raise():
|
def test_ast_good_raise():
|
||||||
"Make sure AST can compile valid raise"
|
"Make sure AST can compile valid raise"
|
||||||
can_compile("(raise)")
|
can_compile("(raise)")
|
||||||
can_compile("(raise 1)")
|
can_compile("(raise Exception)")
|
||||||
|
can_compile("(raise e)")
|
||||||
|
|
||||||
|
|
||||||
|
if PY3:
|
||||||
|
def test_ast_raise_from():
|
||||||
|
can_compile("(raise Exception :from NameError)")
|
||||||
|
|
||||||
|
|
||||||
def test_ast_bad_raise():
|
def test_ast_bad_raise():
|
||||||
"Make sure AST can't compile invalid raise"
|
"Make sure AST can't compile invalid raise"
|
||||||
cant_compile("(raise 1 2 3)")
|
cant_compile("(raise Exception Exception)")
|
||||||
|
|
||||||
|
|
||||||
def test_ast_good_try():
|
def test_ast_good_try():
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
|
|
||||||
from hy.models.expression import HyExpression
|
from hy.models.expression import HyExpression
|
||||||
from hy.models.integer import HyInteger
|
from hy.models.integer import HyInteger
|
||||||
from hy.models.lambdalist import HyLambdaListKeyword
|
|
||||||
from hy.models.float import HyFloat
|
from hy.models.float import HyFloat
|
||||||
from hy.models.complex import HyComplex
|
from hy.models.complex import HyComplex
|
||||||
from hy.models.symbol import HySymbol
|
from hy.models.symbol import HySymbol
|
||||||
@ -85,14 +84,6 @@ def test_lex_expression_integer():
|
|||||||
assert objs == [HyExpression([HySymbol("foo"), HyInteger(2)])]
|
assert objs == [HyExpression([HySymbol("foo"), HyInteger(2)])]
|
||||||
|
|
||||||
|
|
||||||
def test_lex_lambda_list_keyword():
|
|
||||||
""" Make sure expressions can produce lambda list keywords """
|
|
||||||
objs = tokenize("(x &rest xs)")
|
|
||||||
assert objs == [HyExpression([HySymbol("x"),
|
|
||||||
HyLambdaListKeyword("&rest"),
|
|
||||||
HySymbol("xs")])]
|
|
||||||
|
|
||||||
|
|
||||||
def test_lex_symbols():
|
def test_lex_symbols():
|
||||||
""" Make sure that symbols are valid expressions"""
|
""" Make sure that symbols are valid expressions"""
|
||||||
objs = tokenize("foo ")
|
objs = tokenize("foo ")
|
||||||
|
28
tests/macros/test_wrap_value.py
Normal file
28
tests/macros/test_wrap_value.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from hy._compat import long_type
|
||||||
|
from hy.models.integer import HyInteger
|
||||||
|
from hy.models.list import HyList
|
||||||
|
from hy.models.expression import HyExpression
|
||||||
|
|
||||||
|
from hy.macros import _wrap_value
|
||||||
|
|
||||||
|
|
||||||
|
def test_wrap_long_type():
|
||||||
|
""" Test conversion of integers."""
|
||||||
|
wrapped = _wrap_value(long_type(0))
|
||||||
|
assert type(wrapped) == HyInteger
|
||||||
|
|
||||||
|
|
||||||
|
def test_wrap_tuple():
|
||||||
|
""" Test conversion of tuples."""
|
||||||
|
wrapped = _wrap_value((HyInteger(0),))
|
||||||
|
assert type(wrapped) == HyList
|
||||||
|
assert type(wrapped[0]) == HyInteger
|
||||||
|
assert wrapped == HyList([HyInteger(0)])
|
||||||
|
|
||||||
|
|
||||||
|
def test_wrap_nested_expr():
|
||||||
|
""" Test conversion of HyExpressions with embedded non-HyObjects."""
|
||||||
|
wrapped = _wrap_value(HyExpression([long_type(0)]))
|
||||||
|
assert type(wrapped) == HyExpression
|
||||||
|
assert type(wrapped[0]) == HyInteger
|
||||||
|
assert wrapped == HyExpression([HyInteger(0)])
|
@ -54,7 +54,9 @@
|
|||||||
(assert-equal (list (ap-map (* it 3) [1 2 3]))
|
(assert-equal (list (ap-map (* it 3) [1 2 3]))
|
||||||
[3 6 9])
|
[3 6 9])
|
||||||
(assert-equal (list (ap-map (* it 3) []))
|
(assert-equal (list (ap-map (* it 3) []))
|
||||||
[]))
|
[])
|
||||||
|
(assert-equal (let [[v 1] [f 1]] (list (ap-map (it v f) [(fn [a b] (+ a b))])))
|
||||||
|
[2]))
|
||||||
|
|
||||||
(defn test-ap-map-when []
|
(defn test-ap-map-when []
|
||||||
"NATIVE: testing anaphoric map-when"
|
"NATIVE: testing anaphoric map-when"
|
||||||
@ -85,12 +87,14 @@
|
|||||||
(defn test-ap-first []
|
(defn test-ap-first []
|
||||||
"NATIVE: testing anaphoric first"
|
"NATIVE: testing anaphoric first"
|
||||||
(assert-equal (ap-first (> it 5) (range 10)) 6)
|
(assert-equal (ap-first (> it 5) (range 10)) 6)
|
||||||
(assert-equal (ap-first (even? it) [1 2 3 4]) 2))
|
(assert-equal (ap-first (even? it) [1 2 3 4]) 2)
|
||||||
|
(assert-equal (ap-first (> it 10) (range 10)) None))
|
||||||
|
|
||||||
(defn test-ap-last []
|
(defn test-ap-last []
|
||||||
"NATIVE: testing anaphoric last"
|
"NATIVE: testing anaphoric last"
|
||||||
(assert-equal (ap-last (> it 5) (range 10)) 9)
|
(assert-equal (ap-last (> it 5) (range 10)) 9)
|
||||||
(assert-equal (ap-last (even? it) [1 2 3 4]) 4))
|
(assert-equal (ap-last (even? it) [1 2 3 4]) 4)
|
||||||
|
(assert-equal (ap-last (> it 10) (range 10)) None))
|
||||||
|
|
||||||
(defn test-ap-reduce []
|
(defn test-ap-reduce []
|
||||||
"NATIVE: testing anaphoric reduce"
|
"NATIVE: testing anaphoric reduce"
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
(defn assert-equal [x y]
|
(defn assert-equal [x y]
|
||||||
(assert (= x y)))
|
(assert (= x y)))
|
||||||
|
|
||||||
|
(defn assert-nil [x]
|
||||||
|
(assert (is x nil)))
|
||||||
|
|
||||||
(defn test-coll? []
|
(defn test-coll? []
|
||||||
"NATIVE: testing coll?"
|
"NATIVE: testing coll?"
|
||||||
(assert-true (coll? [1 2 3]))
|
(assert-true (coll? [1 2 3]))
|
||||||
@ -38,6 +41,19 @@
|
|||||||
(assert-false (coll? "abc"))
|
(assert-false (coll? "abc"))
|
||||||
(assert-false (coll? 1)))
|
(assert-false (coll? 1)))
|
||||||
|
|
||||||
|
(defn test-butlast []
|
||||||
|
"NATIVE: testing butlast function"
|
||||||
|
(assert-equal (list (butlast (range 10)))
|
||||||
|
[0 1 2 3 4 5 6 7 8])
|
||||||
|
(assert-equal (list (butlast [1]))
|
||||||
|
[])
|
||||||
|
(assert-equal (list (butlast []))
|
||||||
|
[])
|
||||||
|
; with an infinite sequence
|
||||||
|
(import itertools)
|
||||||
|
(assert-equal (list (take 5 (butlast (itertools.count 10))))
|
||||||
|
[10 11 12 13 14]))
|
||||||
|
|
||||||
(defn test-cycle []
|
(defn test-cycle []
|
||||||
"NATIVE: testing cycle"
|
"NATIVE: testing cycle"
|
||||||
(assert-equal (list (cycle [])) [])
|
(assert-equal (list (cycle [])) [])
|
||||||
@ -57,6 +73,34 @@
|
|||||||
(try (do (dec None) (assert False))
|
(try (do (dec None) (assert False))
|
||||||
(catch [e [TypeError]] (assert (in "not a number" (str e))))))
|
(catch [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||||
|
|
||||||
|
(defn test-setv []
|
||||||
|
"NATIVE: testing setv mutation"
|
||||||
|
(setv x 1)
|
||||||
|
(setv y 1)
|
||||||
|
(assert-equal x y)
|
||||||
|
(setv x (setv y 12))
|
||||||
|
(assert-equal x 12)
|
||||||
|
(assert-equal y 12)
|
||||||
|
(setv x (setv y (fn [x] 9)))
|
||||||
|
(assert-equal (x y) 9)
|
||||||
|
(assert-equal (y x) 9)
|
||||||
|
(try (do (setv a.b 1) (assert False))
|
||||||
|
(catch [e [NameError]] (assert (in "name 'a' is not defined" (str e)))))
|
||||||
|
(try (do (setv b.a (fn [x] x)) (assert False))
|
||||||
|
(catch [e [NameError]] (assert (in "name 'b' is not defined" (str e)))))
|
||||||
|
(import itertools)
|
||||||
|
(setv foopermutations (fn [x] (itertools.permutations x)))
|
||||||
|
(setv p (set [(, 1 3 2) (, 3 2 1) (, 2 1 3) (, 3 1 2) (, 1 2 3) (, 2 3 1)]))
|
||||||
|
(assert-equal (set (itertools.permutations [1 2 3])) p)
|
||||||
|
(assert-equal (set (foopermutations [3 1 2])) p)
|
||||||
|
(setv permutations- itertools.permutations)
|
||||||
|
(setv itertools.permutations (fn [x] 9))
|
||||||
|
(assert-equal (itertools.permutations p) 9)
|
||||||
|
(assert-equal (foopermutations foopermutations) 9)
|
||||||
|
(setv itertools.permutations permutations-)
|
||||||
|
(assert-equal (set (itertools.permutations [2 1 3])) p)
|
||||||
|
(assert-equal (set (foopermutations [2 3 1])) p))
|
||||||
|
|
||||||
(defn test-distinct []
|
(defn test-distinct []
|
||||||
"NATIVE: testing the distinct function"
|
"NATIVE: testing the distinct function"
|
||||||
(setv res (list (distinct [ 1 2 3 4 3 5 2 ])))
|
(setv res (list (distinct [ 1 2 3 4 3 5 2 ])))
|
||||||
@ -89,6 +133,19 @@
|
|||||||
(setv res (list (take 5 (drop 2 (iterate inc 0)))))
|
(setv res (list (take 5 (drop 2 (iterate inc 0)))))
|
||||||
(assert-equal res [2 3 4 5 6]))
|
(assert-equal res [2 3 4 5 6]))
|
||||||
|
|
||||||
|
(defn test-drop-last []
|
||||||
|
"NATIVE: testing drop-last function"
|
||||||
|
(assert-equal (list (drop-last 5 (range 10 20)))
|
||||||
|
[10 11 12 13 14])
|
||||||
|
(assert-equal (list (drop-last 0 (range 5)))
|
||||||
|
[0 1 2 3 4])
|
||||||
|
(assert-equal (list (drop-last 100 (range 100)))
|
||||||
|
[])
|
||||||
|
; with an infinite sequence
|
||||||
|
(import itertools)
|
||||||
|
(assert-equal (list (take 5 (drop-last 100 (itertools.count 10))))
|
||||||
|
[10 11 12 13 14]))
|
||||||
|
|
||||||
(defn test-drop-while []
|
(defn test-drop-while []
|
||||||
"NATIVE: testing drop-while function"
|
"NATIVE: testing drop-while function"
|
||||||
(setv res (list (drop-while even? [2 4 7 8 9])))
|
(setv res (list (drop-while even? [2 4 7 8 9])))
|
||||||
@ -238,6 +295,33 @@
|
|||||||
(assert-false (integer-char? "foo"))
|
(assert-false (integer-char? "foo"))
|
||||||
(assert-false (integer-char? None)))
|
(assert-false (integer-char? None)))
|
||||||
|
|
||||||
|
(defn test-interleave []
|
||||||
|
"NATIVE: testing the interleave function"
|
||||||
|
;; with more than 2 sequences
|
||||||
|
(assert-equal (list (take 9 (interleave (range 10)
|
||||||
|
(range 10 20)
|
||||||
|
(range 20 30))))
|
||||||
|
[0 10 20 1 11 21 2 12 22])
|
||||||
|
;; with sequences of different length
|
||||||
|
(assert-equal (list (interleave (range 1000000)
|
||||||
|
(range 0 -3 -1)))
|
||||||
|
[0 0 1 -1 2 -2])
|
||||||
|
;; with infinite sequences
|
||||||
|
(import itertools)
|
||||||
|
(assert-equal (list (take 10 (interleave (itertools.count)
|
||||||
|
(itertools.count 100))))
|
||||||
|
[0 100 1 101 2 102 3 103 4 104]))
|
||||||
|
|
||||||
|
(defn test-interpose []
|
||||||
|
"NATIVE: testing the interpose function"
|
||||||
|
;; with a list
|
||||||
|
(assert-equal (list (interpose "!" ["a" "b" "c"]))
|
||||||
|
["a" "!" "b" "!" "c"])
|
||||||
|
;; with an infinite sequence
|
||||||
|
(import itertools)
|
||||||
|
(assert-equal (list (take 7 (interpose -1 (itertools.count))))
|
||||||
|
[0 -1 1 -1 2 -1 3]))
|
||||||
|
|
||||||
(defn test-iterable []
|
(defn test-iterable []
|
||||||
"NATIVE: testing iterable? function"
|
"NATIVE: testing iterable? function"
|
||||||
;; should work for a string
|
;; should work for a string
|
||||||
@ -335,13 +419,17 @@
|
|||||||
"NATIVE: testing the nth function"
|
"NATIVE: testing the nth function"
|
||||||
(assert-equal 2 (nth [1 2 4 7] 1))
|
(assert-equal 2 (nth [1 2 4 7] 1))
|
||||||
(assert-equal 7 (nth [1 2 4 7] 3))
|
(assert-equal 7 (nth [1 2 4 7] 3))
|
||||||
(try (do (nth [1 2 4 7] 5) (assert False))
|
(assert-nil (nth [1 2 4 7] 5))
|
||||||
(catch [e [IndexError]] nil))
|
(assert-equal (nth [1 2 4 7] 5 "some default value")
|
||||||
|
"some default value") ; with default specified
|
||||||
(try (do (nth [1 2 4 7] -1) (assert False))
|
(try (do (nth [1 2 4 7] -1) (assert False))
|
||||||
(catch [e [ValueError]] nil))
|
(catch [e [ValueError]] nil))
|
||||||
;; now for iterators
|
;; now for iterators
|
||||||
(assert-equal 2 (nth (iter [1 2 4 7]) 1))
|
(assert-equal 2 (nth (iter [1 2 4 7]) 1))
|
||||||
(assert-equal 7 (nth (iter [1 2 4 7]) 3))
|
(assert-equal 7 (nth (iter [1 2 4 7]) 3))
|
||||||
|
(assert-nil (nth (iter [1 2 4 7]) 5))
|
||||||
|
(assert-equal (nth (iter [1 2 4 7]) 5 "some default value")
|
||||||
|
"some default value") ; with default specified
|
||||||
(try (do (nth (iter [1 2 4 7]) -1) (assert False))
|
(try (do (nth (iter [1 2 4 7]) -1) (assert False))
|
||||||
(catch [e [ValueError]] nil))
|
(catch [e [ValueError]] nil))
|
||||||
(assert-equal 5 (nth (take 3 (drop 2 [1 2 3 4 5 6])) 2)))
|
(assert-equal 5 (nth (take 3 (drop 2 [1 2 3 4 5 6])) 2)))
|
||||||
@ -412,9 +500,16 @@
|
|||||||
(defn test-some []
|
(defn test-some []
|
||||||
"NATIVE: testing the some function"
|
"NATIVE: testing the some function"
|
||||||
(assert-true (some even? [2 4 6]))
|
(assert-true (some even? [2 4 6]))
|
||||||
(assert-false (some even? [1 3 5]))
|
(assert-nil (some even? [1 3 5]))
|
||||||
(assert-true (some even? [1 3 6]))
|
(assert-true (some even? [1 2 3]))
|
||||||
(assert-false (some even? [])))
|
(assert-nil (some even? []))
|
||||||
|
; 0, "" (empty string) and [] (empty list) are all logical false
|
||||||
|
(assert-nil (some identity [0 "" []]))
|
||||||
|
; non-empty string is logical true
|
||||||
|
(assert-equal (some identity [0 "this string is non-empty" []])
|
||||||
|
"this string is non-empty")
|
||||||
|
; nil if collection is empty
|
||||||
|
(assert-nil (some even? [])))
|
||||||
|
|
||||||
(defn test-string? []
|
(defn test-string? []
|
||||||
"NATIVE: testing string?"
|
"NATIVE: testing string?"
|
||||||
@ -482,6 +577,16 @@
|
|||||||
(setv res (zipwith operator.sub [3 7 9] [1 2 4]))
|
(setv res (zipwith operator.sub [3 7 9] [1 2 4]))
|
||||||
(assert-equal (list res) [2 5 5]))
|
(assert-equal (list res) [2 5 5]))
|
||||||
|
|
||||||
|
(defn test-doto []
|
||||||
|
"NATIVE: testing doto macro"
|
||||||
|
(setv collection [])
|
||||||
|
(doto collection (.append 1) (.append 2) (.append 3))
|
||||||
|
(assert-equal collection [1 2 3])
|
||||||
|
(setv res (doto (set) (.add 2) (.add 1)))
|
||||||
|
(assert-equal res (set [1 2]))
|
||||||
|
(setv res (doto [] (.append 1) (.append 2) .reverse))
|
||||||
|
(assert-equal res [2 1]))
|
||||||
|
|
||||||
(defn test-is-keyword []
|
(defn test-is-keyword []
|
||||||
"NATIVE: testing the keyword? function"
|
"NATIVE: testing the keyword? function"
|
||||||
(assert (keyword? ':bar))
|
(assert (keyword? ':bar))
|
||||||
|
@ -20,16 +20,16 @@
|
|||||||
(assert (not (isinstance (A) D))))
|
(assert (not (isinstance (A) D))))
|
||||||
|
|
||||||
|
|
||||||
(defn test-defclass-slots []
|
(defn test-defclass-attrs []
|
||||||
"NATIVE: test defclass slots"
|
"NATIVE: test defclass attributes"
|
||||||
(defclass A []
|
(defclass A []
|
||||||
[[x 42]])
|
[[x 42]])
|
||||||
(assert (= A.x 42))
|
(assert (= A.x 42))
|
||||||
(assert (= (getattr (A) "x") 42)))
|
(assert (= (getattr (A) "x") 42)))
|
||||||
|
|
||||||
|
|
||||||
(defn test-defclass-slots-fn []
|
(defn test-defclass-attrs-fn []
|
||||||
"NATIVE: test defclass slots with fn"
|
"NATIVE: test defclass attributes with fn"
|
||||||
(defclass B []
|
(defclass B []
|
||||||
[[x 42]
|
[[x 42]
|
||||||
[y (fn [self value]
|
[y (fn [self value]
|
||||||
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
|
|
||||||
(defn test-defclass-no-fn-leak []
|
(defn test-defclass-no-fn-leak []
|
||||||
"NATIVE: test defclass slots with fn"
|
"NATIVE: test defclass attributes with fn"
|
||||||
(defclass A []
|
(defclass A []
|
||||||
[[x (fn [] 1)]])
|
[[x (fn [] 1)]])
|
||||||
(try
|
(try
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
(import [tests.resources [kwtest function-with-a-dash]]
|
(import [tests.resources [kwtest function-with-a-dash]]
|
||||||
[os.path [exists isdir isfile]]
|
[os.path [exists isdir isfile]]
|
||||||
[sys :as systest])
|
[sys :as systest]
|
||||||
|
[operator [or_]])
|
||||||
(import sys)
|
(import sys)
|
||||||
|
|
||||||
|
(import [hy._compat [PY33 PY34]])
|
||||||
|
|
||||||
(defn test-sys-argv []
|
(defn test-sys-argv []
|
||||||
"NATIVE: test sys.argv"
|
"NATIVE: test sys.argv"
|
||||||
@ -27,9 +29,31 @@
|
|||||||
(setv (get foo 0) 12)
|
(setv (get foo 0) 12)
|
||||||
(assert (= (get foo 0) 12)))
|
(assert (= (get foo 0) 12)))
|
||||||
|
|
||||||
|
(defn test-setv-builtin []
|
||||||
|
"NATIVE: test that setv doesn't work on builtins"
|
||||||
|
(try (eval '(setv False 1))
|
||||||
|
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||||
|
(try (eval '(setv True 0))
|
||||||
|
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||||
|
(try (eval '(setv None 1))
|
||||||
|
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||||
|
(try (eval '(setv false 1))
|
||||||
|
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||||
|
(try (eval '(setv true 0))
|
||||||
|
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||||
|
(try (eval '(setv nil 1))
|
||||||
|
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||||
|
(try (eval '(setv null 1))
|
||||||
|
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||||
|
(try (eval '(defn defclass [] (print "hello")))
|
||||||
|
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||||
|
(try (eval '(defn get [] (print "hello")))
|
||||||
|
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||||
|
(try (eval '(defn lambda [] (print "hello")))
|
||||||
|
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))))
|
||||||
|
|
||||||
(defn test-for-loop []
|
(defn test-for-loop []
|
||||||
"NATIVE: test for loops?"
|
"NATIVE: test for loops"
|
||||||
(setv count 0)
|
(setv count 0)
|
||||||
(for [x [1 2 3 4 5]]
|
(for [x [1 2 3 4 5]]
|
||||||
(setv count (+ count x)))
|
(setv count (+ count x)))
|
||||||
@ -38,7 +62,11 @@
|
|||||||
(for [x [1 2 3 4 5]
|
(for [x [1 2 3 4 5]
|
||||||
y [1 2 3 4 5]]
|
y [1 2 3 4 5]]
|
||||||
(setv count (+ count x y)))
|
(setv count (+ count x y)))
|
||||||
(assert (= count 150)))
|
(assert (= count 150))
|
||||||
|
(assert (= (list ((fn [] (for [x [[1] [2 3]] y x] (yield y)))))
|
||||||
|
(list-comp y [x [[1] [2 3]] y x])))
|
||||||
|
(assert (= (list ((fn [] (for [x [[1] [2 3]] y x z (range 5)] (yield z)))))
|
||||||
|
(list-comp z [x [[1] [2 3]] y x z (range 5)]))))
|
||||||
|
|
||||||
|
|
||||||
(defn test-nasty-for-nesting []
|
(defn test-nasty-for-nesting []
|
||||||
@ -444,10 +472,35 @@
|
|||||||
(for [y (gen)] (setv ret (+ ret y)))
|
(for [y (gen)] (setv ret (+ ret y)))
|
||||||
(assert (= ret 10)))
|
(assert (= ret 10)))
|
||||||
|
|
||||||
|
(defn test-yield-with-return []
|
||||||
|
"NATIVE: test yield with return"
|
||||||
|
(defn gen [] (yield 3) "goodbye")
|
||||||
|
(if PY33
|
||||||
|
(do (setv gg (gen))
|
||||||
|
(assert (= 3 (next gg)))
|
||||||
|
(try (next gg)
|
||||||
|
(except [e StopIteration] (assert (hasattr e "value"))
|
||||||
|
(assert (= (getattr e "value") "goodbye")))))
|
||||||
|
(do (setv gg (gen))
|
||||||
|
(assert (= 3 (next gg)))
|
||||||
|
(try (next gg)
|
||||||
|
(except [e StopIteration] (assert (not (hasattr e "value"))))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-yield-in-try []
|
||||||
|
"NATIVE: test yield in try"
|
||||||
|
(defn gen []
|
||||||
|
(let [[x 1]]
|
||||||
|
(try (yield x)
|
||||||
|
(finally (print x)))))
|
||||||
|
(setv output (list (gen)))
|
||||||
|
(assert (= [1] output)))
|
||||||
|
|
||||||
|
|
||||||
(defn test-first []
|
(defn test-first []
|
||||||
"NATIVE: test firsty things"
|
"NATIVE: test firsty things"
|
||||||
(assert (= (first [1 2 3 4 5]) 1))
|
(assert (= (first [1 2 3 4 5]) 1))
|
||||||
|
(assert (is (first []) nil))
|
||||||
(assert (= (car [1 2 3 4 5]) 1)))
|
(assert (= (car [1 2 3 4 5]) 1)))
|
||||||
|
|
||||||
|
|
||||||
@ -958,6 +1011,24 @@
|
|||||||
(assert (= (macroexpand-1 '(-> (a b) (-> (c d) (e f))))
|
(assert (= (macroexpand-1 '(-> (a b) (-> (c d) (e f))))
|
||||||
'(-> (a b) (c d) (e f)))))
|
'(-> (a b) (c d) (e f)))))
|
||||||
|
|
||||||
|
(defn test-merge-with []
|
||||||
|
"NATIVE: test merge-with"
|
||||||
|
(assert (= (merge-with + {} {}) nil))
|
||||||
|
(assert (= (merge-with + {"a" 10 "b" 20} {}) {"a" 10 "b" 20}))
|
||||||
|
(assert (= (merge-with + {} {"a" 10 "b" 20}) {"a" 10 "b" 20}))
|
||||||
|
(assert (= (merge-with + {"a" 10 "b" 20} {"a" 1 "c" 30})
|
||||||
|
{"a" 11 "b" 20 "c" 30}))
|
||||||
|
(assert (= (merge-with +
|
||||||
|
{:a 1 :b 2}
|
||||||
|
{:a 9 :b 98 :c 0}
|
||||||
|
{:a 10 :b 100 :c 10}
|
||||||
|
{:a 5}
|
||||||
|
{:c 5 :d 42})
|
||||||
|
{:d 42 :c 15 :a 25 :b 200}))
|
||||||
|
(assert (= (merge-with or_
|
||||||
|
{"a" (set [1 2 3]) "b" (set [4 5 6])}
|
||||||
|
{"a" (set [2 3 7 8]) "c" (set [1 2 3])})
|
||||||
|
{"a" (set [1 2 3 7 8]) "c" (set [1 2 3]) "b" (set [4 5 6])})))
|
||||||
|
|
||||||
(defn test-calling-module-name []
|
(defn test-calling-module-name []
|
||||||
"NATIVE: Test the calling-module-name function"
|
"NATIVE: Test the calling-module-name function"
|
||||||
@ -967,22 +1038,10 @@
|
|||||||
|
|
||||||
(defn test-disassemble []
|
(defn test-disassemble []
|
||||||
"NATIVE: Test the disassemble function"
|
"NATIVE: Test the disassemble function"
|
||||||
(import sys)
|
(assert (= (disassemble '(do (leaky) (leaky) (macros)))
|
||||||
(if-python2
|
"Module(\n body=[\n Expr(value=Call(func=Name(id='leaky'), args=[], keywords=[], starargs=None, kwargs=None)),\n Expr(value=Call(func=Name(id='leaky'), args=[], keywords=[], starargs=None, kwargs=None)),\n Expr(value=Call(func=Name(id='macros'), args=[], keywords=[], starargs=None, kwargs=None))])"))
|
||||||
(import [io [BytesIO :as StringIO]])
|
(assert (= (disassemble '(do (leaky) (leaky) (macros)) true)
|
||||||
(import [io [StringIO]]))
|
"leaky()\nleaky()\nmacros()")))
|
||||||
(setv prev-stdout sys.stdout)
|
|
||||||
(setv sys.stdout (StringIO))
|
|
||||||
(disassemble '(do (leaky) (leaky) (macros)))
|
|
||||||
(setv stdout (.getvalue sys.stdout))
|
|
||||||
(setv sys.stdout prev-stdout)
|
|
||||||
(assert (in "leaky" stdout))
|
|
||||||
(assert (in "macros" stdout))
|
|
||||||
(setv sys.stdout (StringIO))
|
|
||||||
(disassemble '(do (leaky) (leaky) (macros)) true)
|
|
||||||
(setv stdout (.getvalue sys.stdout))
|
|
||||||
(setv sys.stdout prev-stdout)
|
|
||||||
(assert (= stdout "leaky()\nleaky()\nmacros()\n")))
|
|
||||||
|
|
||||||
|
|
||||||
(defn test-attribute-access []
|
(defn test-attribute-access []
|
||||||
@ -1008,3 +1067,60 @@
|
|||||||
"NATIVE: test keyword quoting magic"
|
"NATIVE: test keyword quoting magic"
|
||||||
(assert (= :foo "\ufdd0:foo"))
|
(assert (= :foo "\ufdd0:foo"))
|
||||||
(assert (= `:foo "\ufdd0:foo")))
|
(assert (= `:foo "\ufdd0:foo")))
|
||||||
|
|
||||||
|
(defn test-only-parse-lambda-list-in-defn []
|
||||||
|
"NATIVE: test lambda lists are only parsed in defn"
|
||||||
|
(try
|
||||||
|
(foo [&rest spam] 1)
|
||||||
|
(catch [NameError] True)
|
||||||
|
(else (raise AssertionError))))
|
||||||
|
|
||||||
|
(defn test-read []
|
||||||
|
"NATIVE: test that read takes something for stdin and reads"
|
||||||
|
(if-python2
|
||||||
|
(import [StringIO [StringIO]])
|
||||||
|
(import [io [StringIO]]))
|
||||||
|
(import [hy.models.expression [HyExpression]])
|
||||||
|
|
||||||
|
(def stdin-buffer (StringIO "(+ 2 2)\n(- 2 2)"))
|
||||||
|
(assert (= (eval (read stdin-buffer)) 4))
|
||||||
|
(assert (isinstance (read stdin-buffer) HyExpression))
|
||||||
|
|
||||||
|
"Multiline test"
|
||||||
|
(def stdin-buffer (StringIO "(\n+\n41\n1\n)\n(-\n2\n1\n)"))
|
||||||
|
(assert (= (eval (read stdin-buffer)) 42))
|
||||||
|
(assert (= (eval (read stdin-buffer)) 1))
|
||||||
|
|
||||||
|
"EOF test"
|
||||||
|
(def stdin-buffer (StringIO "(+ 2 2)"))
|
||||||
|
(read stdin-buffer)
|
||||||
|
(try
|
||||||
|
(read stdin-buffer)
|
||||||
|
(catch [e Exception]
|
||||||
|
(assert (isinstance e EOFError)))))
|
||||||
|
|
||||||
|
(defn test-keyword-creation []
|
||||||
|
"NATIVE: Test keyword creation"
|
||||||
|
(assert (= (keyword "foo") :foo))
|
||||||
|
(assert (= (keyword "foo_bar") :foo-bar))
|
||||||
|
(assert (= (keyword `foo) :foo))
|
||||||
|
(assert (= (keyword `foo-bar) :foo-bar))
|
||||||
|
(assert (= (keyword 'foo) :foo))
|
||||||
|
(assert (= (keyword 'foo-bar) :foo-bar))
|
||||||
|
(assert (= (keyword 1) :1))
|
||||||
|
(assert (= (keyword 1.0) :1.0))
|
||||||
|
(assert (= (keyword :foo_bar) :foo-bar)))
|
||||||
|
|
||||||
|
(defn test-name-conversion []
|
||||||
|
"NATIVE: Test name conversion"
|
||||||
|
(assert (= (name "foo") "foo"))
|
||||||
|
(assert (= (name "foo_bar") "foo-bar"))
|
||||||
|
(assert (= (name `foo) "foo"))
|
||||||
|
(assert (= (name `foo_bar) "foo-bar"))
|
||||||
|
(assert (= (name 'foo) "foo"))
|
||||||
|
(assert (= (name 'foo_bar) "foo-bar"))
|
||||||
|
(assert (= (name 1) "1"))
|
||||||
|
(assert (= (name 1.0) "1.0"))
|
||||||
|
(assert (= (name :foo) "foo"))
|
||||||
|
(assert (= (name :foo_bar) "foo-bar"))
|
||||||
|
(assert (= (name test-name-conversion) "test-name-conversion")))
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
(import [hy._compat [PY33]])
|
|
||||||
(import [hy.errors [HyCompileError]])
|
|
||||||
|
|
||||||
(defmacro rev [&rest body]
|
(defmacro rev [&rest body]
|
||||||
"Execute the `body` statements in reverse"
|
"Execute the `body` statements in reverse"
|
||||||
(quasiquote (do (unquote-splice (list (reversed body))))))
|
(quasiquote (do (unquote-splice (list (reversed body))))))
|
||||||
@ -100,21 +97,6 @@
|
|||||||
(assert initialized)
|
(assert initialized)
|
||||||
(assert (test-initialized))
|
(assert (test-initialized))
|
||||||
|
|
||||||
(defn test-yield-from []
|
|
||||||
"NATIVE: testing yield from"
|
|
||||||
|
|
||||||
(try
|
|
||||||
(eval
|
|
||||||
'(do (defn yield-from-test []
|
|
||||||
(for* [i (range 3)]
|
|
||||||
(yield i))
|
|
||||||
(yield-from [1 2 3]))
|
|
||||||
(assert (= (list (yield-from-test)) [0 1 2 1 2 3]))))
|
|
||||||
(catch [e HyCompileError]
|
|
||||||
;; Yup, this should happen on non-Python3.3 thingies
|
|
||||||
(assert (not PY33)))
|
|
||||||
(else (assert PY33))))
|
|
||||||
|
|
||||||
(defn test-if-python2 []
|
(defn test-if-python2 []
|
||||||
(import sys)
|
(import sys)
|
||||||
(assert (= (get sys.version_info 0)
|
(assert (= (get sys.version_info 0)
|
||||||
@ -188,7 +170,12 @@
|
|||||||
(setv s2 (to_source _ast2))
|
(setv s2 (to_source _ast2))
|
||||||
(assert (in ":res_" s1))
|
(assert (in ":res_" s1))
|
||||||
(assert (in ":res_" s2))
|
(assert (in ":res_" s2))
|
||||||
(assert (not (= s1 s2))))
|
(assert (not (= s1 s2)))
|
||||||
|
|
||||||
|
;; defmacro/g! didn't like numbers initially because they
|
||||||
|
;; don't have a startswith method and blew up during expansion
|
||||||
|
(setv macro2 "(defmacro/g! two-point-zero [] `(+ (float 1) 1.0))")
|
||||||
|
(assert (import_buffer_to_ast macro2 "foo")))
|
||||||
|
|
||||||
|
|
||||||
(defn test-if-not []
|
(defn test-if-not []
|
||||||
@ -219,6 +206,24 @@
|
|||||||
(assert (= (lif nil "true" "false") "false"))
|
(assert (= (lif nil "true" "false") "false"))
|
||||||
(assert (= (lif 0 "true" "false") "true")))
|
(assert (= (lif 0 "true" "false") "true")))
|
||||||
|
|
||||||
|
(defn test-lisp-if-not []
|
||||||
|
"test that lisp-if-not works as expected"
|
||||||
|
; nil is false
|
||||||
|
(assert (= (lisp-if-not None "false" "true") "false"))
|
||||||
|
(assert (= (lisp-if-not nil "false" "true") "false"))
|
||||||
|
|
||||||
|
; But everything else is True! Even falsey things.
|
||||||
|
(assert (= (lisp-if-not True "false" "true") "true"))
|
||||||
|
(assert (= (lisp-if-not False "false" "true") "true"))
|
||||||
|
(assert (= (lisp-if-not 0 "false" "true") "true"))
|
||||||
|
(assert (= (lisp-if-not "some-string" "false" "true") "true"))
|
||||||
|
(assert (= (lisp-if-not "" "false" "true") "true"))
|
||||||
|
(assert (= (lisp-if-not (+ 1 2 3) "false" "true") "true"))
|
||||||
|
|
||||||
|
; Just to be sure, test the alias lif-not
|
||||||
|
(assert (= (lif-not nil "false" "true") "false"))
|
||||||
|
(assert (= (lif-not 0 "false" "true") "true")))
|
||||||
|
|
||||||
|
|
||||||
(defn test-defn-alias []
|
(defn test-defn-alias []
|
||||||
(defn-alias [tda-main tda-a1 tda-a2] [] :bazinga)
|
(defn-alias [tda-main tda-a1 tda-a2] [] :bazinga)
|
||||||
@ -227,3 +232,6 @@
|
|||||||
(assert (= (tda-a1) :bazinga))
|
(assert (= (tda-a1) :bazinga))
|
||||||
(assert (= (tda-a2) :bazinga))
|
(assert (= (tda-a2) :bazinga))
|
||||||
(assert (= tda-main tda-a1 tda-a2)))
|
(assert (= tda-main tda-a1 tda-a2)))
|
||||||
|
|
||||||
|
(defn test-botsbuildbots []
|
||||||
|
(assert (> (len (first (Botsbuildbots))) 50)))
|
||||||
|
27
tests/native_tests/py3_only_tests.hy
Normal file
27
tests/native_tests/py3_only_tests.hy
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
;; Tests where the emited code relies on Python 3.
|
||||||
|
;; Conditionally included in nosetests runs.
|
||||||
|
|
||||||
|
(import [hy._compat [PY33]])
|
||||||
|
(import [hy.errors [HyCompileError]])
|
||||||
|
|
||||||
|
(defn test-yield-from []
|
||||||
|
"NATIVE: testing yield from"
|
||||||
|
|
||||||
|
(try
|
||||||
|
(eval
|
||||||
|
'(do (defn yield-from-test []
|
||||||
|
(for* [i (range 3)]
|
||||||
|
(yield i))
|
||||||
|
(yield-from [1 2 3]))
|
||||||
|
(assert (= (list (yield-from-test)) [0 1 2 1 2 3]))))
|
||||||
|
(catch [e HyCompileError]
|
||||||
|
;; Yield-from is supported in py3.3+ only
|
||||||
|
(assert (not PY33)))
|
||||||
|
(else (assert PY33))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-exception-cause []
|
||||||
|
(try (raise ValueError :from NameError)
|
||||||
|
(except [e [ValueError]]
|
||||||
|
(assert (= (type (. e __cause__)) NameError)))))
|
@ -77,12 +77,6 @@
|
|||||||
(assert (= q qq)))
|
(assert (= q qq)))
|
||||||
|
|
||||||
|
|
||||||
(defn test-quote-lambdalistkeyword []
|
|
||||||
"NATIVE: test quoting lambda list keywords"
|
|
||||||
(setv opt (quote &optional))
|
|
||||||
(assert (isinstance opt hy.HyLambdaListKeyword))
|
|
||||||
(assert (= (str opt) "&optional")))
|
|
||||||
|
|
||||||
(defmacro doodle [&rest body]
|
(defmacro doodle [&rest body]
|
||||||
`(do ~@body))
|
`(do ~@body))
|
||||||
|
|
||||||
|
52
tests/native_tests/shadow.hy
Normal file
52
tests/native_tests/shadow.hy
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
(defn test-shadow-addition []
|
||||||
|
"NATIVE: test shadow addition"
|
||||||
|
(let [[x +]]
|
||||||
|
(assert (try
|
||||||
|
(x)
|
||||||
|
(catch [TypeError] True)
|
||||||
|
(else (throw AssertionError))))
|
||||||
|
(assert (= (x 1 2 3 4) 10))
|
||||||
|
(assert (= (x 1 2 3 4 5) 15))
|
||||||
|
; with strings
|
||||||
|
(assert (= (x "a")
|
||||||
|
"a"))
|
||||||
|
(assert (= (x "a" "b" "c")
|
||||||
|
"abc"))
|
||||||
|
; with lists
|
||||||
|
(assert (= (x ["a"])
|
||||||
|
["a"]))
|
||||||
|
(assert (= (x ["a"] ["b"] ["c"])
|
||||||
|
["a" "b" "c"]))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-shadow-subtraction []
|
||||||
|
"NATIVE: test shadow subtraction"
|
||||||
|
(let [[x -]]
|
||||||
|
(assert (try
|
||||||
|
(x)
|
||||||
|
(catch [TypeError] True)
|
||||||
|
(else (throw AssertionError))))
|
||||||
|
(assert (= (x 1) -1))
|
||||||
|
(assert (= (x 2 1) 1))
|
||||||
|
(assert (= (x 2 1 1) 0))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-shadow-multiplication []
|
||||||
|
"NATIVE: test shadow multiplication"
|
||||||
|
(let [[x *]]
|
||||||
|
(assert (= (x) 1))
|
||||||
|
(assert (= (x 3) 3))
|
||||||
|
(assert (= (x 3 3) 9))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-shadow-division []
|
||||||
|
"NATIVE: test shadow division"
|
||||||
|
(let [[x /]]
|
||||||
|
(assert (try
|
||||||
|
(x)
|
||||||
|
(catch [TypeError] True)
|
||||||
|
(else (throw AssertionError))))
|
||||||
|
(assert (= (x 1) 1))
|
||||||
|
(assert (= (x 8 2) 4))
|
||||||
|
(assert (= (x 8 2 2) 2))
|
||||||
|
(assert (= (x 8 2 2 2) 1))))
|
@ -7,6 +7,16 @@
|
|||||||
(* 2 2)))
|
(* 2 2)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn bardec [cls]
|
||||||
|
(setv cls.my_attr 123)
|
||||||
|
cls)
|
||||||
|
|
||||||
|
(with-decorator bardec
|
||||||
|
(defclass cls []
|
||||||
|
[[my_attr 456]]))
|
||||||
|
|
||||||
|
|
||||||
(defn test-decorators []
|
(defn test-decorators []
|
||||||
"NATIVE: test decorators."
|
"NATIVE: test decorators."
|
||||||
(assert (= (tfunction) 2)))
|
(assert (= (tfunction) 2))
|
||||||
|
(assert (= cls.my_attr 123)))
|
||||||
|
5
tests/resources/bin/main.hy
Normal file
5
tests/resources/bin/main.hy
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
(defmain [&rest args]
|
||||||
|
(print args)
|
||||||
|
(print "Hello World")
|
||||||
|
(if (in "exit1" args)
|
||||||
|
1))
|
4
tests/resources/bin/nomain.hy
Normal file
4
tests/resources/bin/nomain.hy
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
(print "This Should Still Works")
|
||||||
|
|
||||||
|
(defn main []
|
||||||
|
(print "This Should Not Work"))
|
@ -23,10 +23,14 @@
|
|||||||
# DEALINGS IN THE SOFTWARE.
|
# DEALINGS IN THE SOFTWARE.
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from hy._compat import PY3
|
||||||
|
|
||||||
|
|
||||||
|
hy_dir = os.environ.get('HY_DIR', '')
|
||||||
|
|
||||||
|
|
||||||
def run_cmd(cmd, stdin_data=None):
|
def run_cmd(cmd, stdin_data=None):
|
||||||
p = subprocess.Popen(cmd,
|
p = subprocess.Popen(os.path.join(hy_dir, cmd),
|
||||||
stdin=subprocess.PIPE,
|
stdin=subprocess.PIPE,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
@ -128,12 +132,15 @@ def test_hy2py():
|
|||||||
for dirpath, dirnames, filenames in os.walk("tests/native_tests"):
|
for dirpath, dirnames, filenames in os.walk("tests/native_tests"):
|
||||||
for f in filenames:
|
for f in filenames:
|
||||||
if f.endswith(".hy"):
|
if f.endswith(".hy"):
|
||||||
i += 1
|
if f == "py3_only_tests.hy" and not PY3:
|
||||||
ret = run_cmd("hy2py -s -a "
|
continue
|
||||||
+ os.path.join(dirpath, f))
|
else:
|
||||||
assert ret[0] == 0, f
|
i += 1
|
||||||
assert len(ret[1]) > 1, f
|
ret = run_cmd("hy2py -s -a "
|
||||||
assert len(ret[2]) == 0, f
|
+ os.path.join(dirpath, f))
|
||||||
|
assert ret[0] == 0, f
|
||||||
|
assert len(ret[1]) > 1, f
|
||||||
|
assert len(ret[2]) == 0, f
|
||||||
assert i
|
assert i
|
||||||
|
|
||||||
|
|
||||||
@ -142,3 +149,27 @@ def test_bin_hy_builtins():
|
|||||||
|
|
||||||
assert str(exit) == "Use (exit) or Ctrl-D (i.e. EOF) to exit"
|
assert str(exit) == "Use (exit) or Ctrl-D (i.e. EOF) to exit"
|
||||||
assert str(quit) == "Use (quit) or Ctrl-D (i.e. EOF) to exit"
|
assert str(quit) == "Use (quit) or Ctrl-D (i.e. EOF) to exit"
|
||||||
|
|
||||||
|
|
||||||
|
def test_bin_hy_main():
|
||||||
|
ret = run_cmd("hy tests/resources/bin/main.hy")
|
||||||
|
assert ret[0] == 0
|
||||||
|
assert "Hello World" in ret[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_bin_hy_main_args():
|
||||||
|
ret = run_cmd("hy tests/resources/bin/main.hy test 123")
|
||||||
|
assert ret[0] == 0
|
||||||
|
assert "test" in ret[1]
|
||||||
|
assert "123" in ret[1]
|
||||||
|
|
||||||
|
|
||||||
|
def test_bin_hy_main_exitvalue():
|
||||||
|
ret = run_cmd("hy tests/resources/bin/main.hy exit1")
|
||||||
|
assert ret[0] == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_bin_hy_no_main():
|
||||||
|
ret = run_cmd("hy tests/resources/bin/nomain.hy")
|
||||||
|
assert ret[0] == 0
|
||||||
|
assert "This Should Still Work" in ret[1]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user