Merge branch 'master' into pr/565
This commit is contained in:
commit
1ae666e096
13
.travis.yml
13
.travis.yml
@ -1,19 +1,18 @@
|
|||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- "pypy"
|
- "pypy"
|
||||||
|
- "2.6"
|
||||||
- "2.7"
|
- "2.7"
|
||||||
- "3.2"
|
- "3.2"
|
||||||
- "3.3"
|
- "3.3"
|
||||||
- "2.6"
|
- "3.4"
|
||||||
# command to install dependencies
|
# command to install dependencies
|
||||||
install:
|
install:
|
||||||
- pip install -r requirements.txt
|
- pip install -r requirements-dev.txt
|
||||||
- pip install coveralls
|
- pip install coveralls
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install argparse importlib unittest2 astor; fi
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi # needs for running tests
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install astor; fi
|
- pip install --allow-all-external -e .
|
||||||
- if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then pip install astor; fi
|
# command to run tests
|
||||||
- python setup.py -q install
|
|
||||||
# # command to run tests
|
|
||||||
script: make travis
|
script: make travis
|
||||||
after_success: coveralls
|
after_success: coveralls
|
||||||
notifications:
|
notifications:
|
||||||
|
2
AUTHORS
2
AUTHORS
@ -45,3 +45,5 @@
|
|||||||
* kirbyfan64 <kirbyfan64@users.noreply.github.com>
|
* kirbyfan64 <kirbyfan64@users.noreply.github.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>
|
||||||
|
* Matthew Wampler-Doty <matthew.wampler.doty@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.
|
11
Dockerfile
Normal file
11
Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Base image
|
||||||
|
#
|
||||||
|
# VERSION 0.1
|
||||||
|
FROM debian:unstable
|
||||||
|
MAINTAINER Paul R. Tagliamonte <paultag@debian.org>
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y python3.4 python3-pip
|
||||||
|
ADD . /opt/hylang/hy
|
||||||
|
RUN python3.4 /usr/bin/pip3 install -e /opt/hylang/hy
|
||||||
|
|
||||||
|
CMD ["hy"]
|
12
NEWS
12
NEWS
@ -60,7 +60,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 +88,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 +267,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 +286,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 +311,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 +346,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?
|
||||||
|
|
||||||
|
40
bin/hy2py
40
bin/hy2py
@ -1,40 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
from hy.importer import import_file_to_ast, import_file_to_hst
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import astor.codegen
|
|
||||||
|
|
||||||
module_name = "<STDIN>"
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
prog="hy2py",
|
|
||||||
usage="%(prog)s [options] FILE",
|
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
||||||
parser.add_argument("--with-source", "-s", action="store_true",
|
|
||||||
help="Show the parsed source structure")
|
|
||||||
parser.add_argument("--with-ast", "-a", action="store_true",
|
|
||||||
help="Show the generated AST")
|
|
||||||
parser.add_argument("--without-python", "-np", action="store_true",
|
|
||||||
help="Do not show the python code generated from the AST")
|
|
||||||
parser.add_argument('args', nargs=argparse.REMAINDER, help=argparse.SUPPRESS)
|
|
||||||
|
|
||||||
options = parser.parse_args(sys.argv[1:])
|
|
||||||
|
|
||||||
if options.with_source:
|
|
||||||
hst = import_file_to_hst(options.args[0])
|
|
||||||
print(hst)
|
|
||||||
print()
|
|
||||||
print()
|
|
||||||
|
|
||||||
_ast = import_file_to_ast(options.args[0], module_name)
|
|
||||||
if options.with_ast:
|
|
||||||
print(astor.dump(_ast))
|
|
||||||
print()
|
|
||||||
print()
|
|
||||||
|
|
||||||
if not options.without_python:
|
|
||||||
print(astor.codegen.to_source(_ast))
|
|
@ -96,7 +96,13 @@ pygments_style = 'sphinx'
|
|||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
html_theme = 'default'
|
try:
|
||||||
|
import sphinx_rtd_theme
|
||||||
|
except ImportError:
|
||||||
|
html_theme = 'default'
|
||||||
|
else:
|
||||||
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
|
@ -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
|
||||||
----------
|
----------
|
||||||
|
|
||||||
@ -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
|
||||||
@ -629,6 +682,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
|
||||||
@ -1003,6 +1074,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 +1144,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 +1238,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
|
||||||
|
|
||||||
@ -1273,25 +1360,3 @@ yield-from
|
|||||||
want your coroutine to be able to delegate its processes to another
|
want your coroutine to be able to delegate its processes to another
|
||||||
coroutine, say if using something fancy like
|
coroutine, say if using something fancy like
|
||||||
`asyncio <http://docs.python.org/3.4/library/asyncio.html>`_.
|
`asyncio <http://docs.python.org/3.4/library/asyncio.html>`_.
|
||||||
|
|
||||||
|
|
||||||
.. _zipwith:
|
|
||||||
|
|
||||||
zipwith
|
|
||||||
-------
|
|
||||||
|
|
||||||
.. versionadded:: 0.10.0
|
|
||||||
|
|
||||||
`zipwith` zips multiple lists and maps the given function over the result. It is
|
|
||||||
equilavent to calling ``zip``, followed by calling ``map`` on the result.
|
|
||||||
|
|
||||||
In the following example, `zipwith` is used to add the contents of two lists
|
|
||||||
together. The equilavent ``map`` and ``zip`` calls follow.
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
=> (import operator.add)
|
|
||||||
=> (zipwith operator.add [1 2 3] [4 5 6]) ; using zipwith
|
|
||||||
[5, 7, 9]
|
|
||||||
=> (map operator.add (zip [1 2 3] [4 5 6])) ; using map+zip
|
|
||||||
[5, 7, 9]
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
Command Line Interface
|
Command Line Interface
|
||||||
======================
|
======================
|
||||||
|
|
||||||
|
.. _hy:
|
||||||
|
|
||||||
hy
|
hy
|
||||||
--
|
--
|
||||||
|
|
||||||
@ -46,6 +48,8 @@ Command line options
|
|||||||
Print the Hy version number and exit.
|
Print the Hy version number and exit.
|
||||||
|
|
||||||
|
|
||||||
|
.. _hyc:
|
||||||
|
|
||||||
hyc
|
hyc
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -71,3 +75,29 @@ Command line options
|
|||||||
$ hyc hyname.hy
|
$ hyc hyname.hy
|
||||||
$ python hyname.pyc
|
$ python hyname.pyc
|
||||||
Hy Afroman!
|
Hy Afroman!
|
||||||
|
|
||||||
|
|
||||||
|
.. _hy2py:
|
||||||
|
|
||||||
|
hy2py
|
||||||
|
-----
|
||||||
|
|
||||||
|
.. versionadded:: 0.10.1
|
||||||
|
|
||||||
|
Command line options
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. cmdoption:: -s
|
||||||
|
--with-source
|
||||||
|
|
||||||
|
Show the parsed source structure.
|
||||||
|
|
||||||
|
.. cmdoption:: -a
|
||||||
|
--with-ast
|
||||||
|
|
||||||
|
Show the generated AST.
|
||||||
|
|
||||||
|
.. cmdoption:: -np
|
||||||
|
--without-python
|
||||||
|
|
||||||
|
Do not show the Python code generated from the AST.
|
||||||
|
@ -495,8 +495,8 @@ nth
|
|||||||
Usage: ``(nth coll n)``
|
Usage: ``(nth coll n)``
|
||||||
|
|
||||||
Return the `nth` item in a collection, counting from 0. Unlike
|
Return the `nth` item in a collection, counting from 0. Unlike
|
||||||
``get``, ``nth`` works on both iterators and iterables. Returns ``None``
|
``get``, ``nth`` works on both iterators and iterables. Raises ``IndexError``
|
||||||
if the `n` is outside the range of `coll`.
|
if the `n` is outside the range of ``coll`` or ``ValueError`` if it's negative.
|
||||||
|
|
||||||
.. code-block:: hy
|
.. code-block:: hy
|
||||||
|
|
||||||
@ -506,8 +506,10 @@ if the `n` is outside the range of `coll`.
|
|||||||
=> (nth [1 2 4 7] 3)
|
=> (nth [1 2 4 7] 3)
|
||||||
7
|
7
|
||||||
|
|
||||||
=> (none? (nth [1 2 4 7] 5))
|
=> (nth [1 2 4 7] 5)
|
||||||
True
|
Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
IndexError: 5
|
||||||
|
|
||||||
=> (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
|
||||||
@ -764,6 +766,7 @@ drop
|
|||||||
Usage: ``(drop n coll)``
|
Usage: ``(drop n coll)``
|
||||||
|
|
||||||
Return an iterator, skipping the first ``n`` members of ``coll``
|
Return an iterator, skipping the first ``n`` members of ``coll``
|
||||||
|
Raises ``ValueError`` if ``n`` is negative.
|
||||||
|
|
||||||
.. code-block:: hy
|
.. code-block:: hy
|
||||||
|
|
||||||
@ -924,6 +927,7 @@ take
|
|||||||
Usage: ``(take n coll)``
|
Usage: ``(take n coll)``
|
||||||
|
|
||||||
Return an iterator containing the first ``n`` members of ``coll``.
|
Return an iterator containing the first ``n`` members of ``coll``.
|
||||||
|
Raises ``ValueError`` if ``n`` is negative.
|
||||||
|
|
||||||
.. code-block:: hy
|
.. code-block:: hy
|
||||||
|
|
||||||
@ -979,3 +983,21 @@ Return an iterator from ``coll`` as long as predicate, ``pred`` returns True.
|
|||||||
|
|
||||||
=> (list (take-while neg? [ 1 2 3 -4 5]))
|
=> (list (take-while neg? [ 1 2 3 -4 5]))
|
||||||
[]
|
[]
|
||||||
|
|
||||||
|
.. _zipwith:
|
||||||
|
|
||||||
|
zipwith
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. versionadded:: 0.9.13
|
||||||
|
|
||||||
|
Usage: ``(zipwith fn coll ...)``
|
||||||
|
|
||||||
|
Equivalent to ``zip``, but uses a multi-argument function instead of creating a tuple.
|
||||||
|
If ``zipwith`` is called with N collections, then ``fn`` must accept N arguments.
|
||||||
|
|
||||||
|
.. code-block:: clojure
|
||||||
|
|
||||||
|
=> (import operator)
|
||||||
|
=> (list (zipwith operator.add [1 2 3] [4 5 6]))
|
||||||
|
[5, 7, 9]
|
||||||
|
@ -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,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.
|
||||||
#
|
#
|
||||||
|
@ -25,16 +25,21 @@
|
|||||||
# 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 __future__ import print_function
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import code
|
import code
|
||||||
import ast
|
import ast
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import astor.codegen
|
||||||
|
|
||||||
import hy
|
import hy
|
||||||
|
|
||||||
from hy.lex import LexException, PrematureEndOfInput, tokenize
|
from hy.lex import LexException, PrematureEndOfInput, tokenize
|
||||||
from hy.compiler import hy_compile, HyTypeError
|
from hy.compiler import hy_compile, HyTypeError
|
||||||
from hy.importer import ast_compile, import_buffer_to_module
|
from hy.importer import (ast_compile, import_buffer_to_module,
|
||||||
|
import_file_to_ast, import_file_to_hst)
|
||||||
from hy.completer import completion
|
from hy.completer import completion
|
||||||
|
|
||||||
from hy.macros import macro, require
|
from hy.macros import macro, require
|
||||||
@ -66,7 +71,6 @@ builtins.exit = HyQuitter('exit')
|
|||||||
|
|
||||||
|
|
||||||
def print_python_code(_ast):
|
def print_python_code(_ast):
|
||||||
import astor.codegen
|
|
||||||
# astor cannot handle ast.Interactive, so disguise it as a module
|
# astor cannot handle ast.Interactive, so disguise it as a module
|
||||||
_ast_for_print = ast.Module()
|
_ast_for_print = ast.Module()
|
||||||
_ast_for_print.body = _ast.body
|
_ast_for_print.body = _ast.body
|
||||||
@ -313,3 +317,43 @@ def hyc_main():
|
|||||||
sys.stderr.write("hyc: Can't open file '%s': [Errno %d] %s\n" %
|
sys.stderr.write("hyc: Can't open file '%s': [Errno %d] %s\n" %
|
||||||
(x.filename, x.errno, x.strerror))
|
(x.filename, x.errno, x.strerror))
|
||||||
sys.exit(x.errno)
|
sys.exit(x.errno)
|
||||||
|
|
||||||
|
|
||||||
|
# entry point for cmd line script "hy2py"
|
||||||
|
def hy2py_main():
|
||||||
|
module_name = "<STDIN>"
|
||||||
|
|
||||||
|
options = dict(prog="hy2py", usage="%(prog)s [options] FILE",
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||||
|
parser = argparse.ArgumentParser(**options)
|
||||||
|
parser.add_argument("--with-source", "-s", action="store_true",
|
||||||
|
help="Show the parsed source structure")
|
||||||
|
parser.add_argument("--with-ast", "-a", action="store_true",
|
||||||
|
help="Show the generated AST")
|
||||||
|
parser.add_argument("--without-python", "-np", action="store_true",
|
||||||
|
help=("Do not show the Python code generated "
|
||||||
|
"from the AST"))
|
||||||
|
parser.add_argument('args', nargs=argparse.REMAINDER,
|
||||||
|
help=argparse.SUPPRESS)
|
||||||
|
|
||||||
|
options = parser.parse_args(sys.argv[1:])
|
||||||
|
|
||||||
|
if not options.args:
|
||||||
|
parser.exit(1, parser.format_help())
|
||||||
|
|
||||||
|
if options.with_source:
|
||||||
|
hst = import_file_to_hst(options.args[0])
|
||||||
|
print(hst)
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
|
||||||
|
_ast = import_file_to_ast(options.args[0], module_name)
|
||||||
|
if options.with_ast:
|
||||||
|
print(astor.dump(_ast))
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
|
||||||
|
if not options.without_python:
|
||||||
|
print(astor.codegen.to_source(_ast))
|
||||||
|
|
||||||
|
parser.exit(0)
|
||||||
|
@ -732,25 +732,10 @@ class HyASTCompiler(object):
|
|||||||
handler_results += self._compile_catch_expression(e, name)
|
handler_results += self._compile_catch_expression(e, name)
|
||||||
handlers.append(handler_results.stmts.pop())
|
handlers.append(handler_results.stmts.pop())
|
||||||
elif e[0] == HySymbol("else"):
|
elif e[0] == HySymbol("else"):
|
||||||
if orelse:
|
orelse = self.try_except_helper(e, HySymbol("else"), orelse)
|
||||||
raise HyTypeError(
|
|
||||||
e,
|
|
||||||
"`try' cannot have more than one `else'")
|
|
||||||
else:
|
|
||||||
orelse = self._compile_branch(e[1:])
|
|
||||||
# XXX tempvar magic
|
|
||||||
orelse += orelse.expr_as_stmt()
|
|
||||||
orelse = orelse.stmts
|
|
||||||
elif e[0] == HySymbol("finally"):
|
elif e[0] == HySymbol("finally"):
|
||||||
if finalbody:
|
finalbody = self.try_except_helper(e, HySymbol("finally"),
|
||||||
raise HyTypeError(
|
finalbody)
|
||||||
e,
|
|
||||||
"`try' cannot have more than one `finally'")
|
|
||||||
else:
|
|
||||||
finalbody = self._compile_branch(e[1:])
|
|
||||||
# XXX tempvar magic
|
|
||||||
finalbody += finalbody.expr_as_stmt()
|
|
||||||
finalbody = finalbody.stmts
|
|
||||||
else:
|
else:
|
||||||
raise HyTypeError(e, "Unknown expression in `try'")
|
raise HyTypeError(e, "Unknown expression in `try'")
|
||||||
|
|
||||||
@ -768,8 +753,8 @@ class HyASTCompiler(object):
|
|||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
type=None,
|
type=None,
|
||||||
name=None,
|
name=None,
|
||||||
body=[ast.Pass(lineno=expr.start_line,
|
body=[ast.Raise(lineno=expr.start_line,
|
||||||
col_offset=expr.start_column)])]
|
col_offset=expr.start_column)])]
|
||||||
|
|
||||||
ret = handler_results
|
ret = handler_results
|
||||||
|
|
||||||
@ -809,6 +794,17 @@ class HyASTCompiler(object):
|
|||||||
body=body,
|
body=body,
|
||||||
orelse=orelse) + returnable
|
orelse=orelse) + returnable
|
||||||
|
|
||||||
|
def try_except_helper(self, hy_obj, symbol, accumulated):
|
||||||
|
if accumulated:
|
||||||
|
raise HyTypeError(
|
||||||
|
hy_obj,
|
||||||
|
"`try' cannot have more than one `%s'" % symbol)
|
||||||
|
else:
|
||||||
|
accumulated = self._compile_branch(hy_obj[1:])
|
||||||
|
accumulated += accumulated.expr_as_stmt()
|
||||||
|
accumulated = accumulated.stmts
|
||||||
|
return accumulated
|
||||||
|
|
||||||
@builds("except")
|
@builds("except")
|
||||||
@builds("catch")
|
@builds("catch")
|
||||||
def magic_internal_form(self, expr):
|
def magic_internal_form(self, expr):
|
||||||
@ -1516,7 +1512,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)
|
||||||
@ -1755,18 +1751,19 @@ class HyASTCompiler(object):
|
|||||||
def _compile_assign(self, name, result,
|
def _compile_assign(self, name, result,
|
||||||
start_line, start_column):
|
start_line, start_column):
|
||||||
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
|
||||||
@ -1859,7 +1856,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!
|
||||||
|
@ -23,7 +23,9 @@
|
|||||||
;;;; to make functional programming slightly easier.
|
;;;; to make functional programming slightly easier.
|
||||||
;;;;
|
;;;;
|
||||||
|
|
||||||
|
(import itertools)
|
||||||
|
(import functools)
|
||||||
|
(import collections)
|
||||||
(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]])
|
||||||
|
|
||||||
@ -44,15 +46,11 @@
|
|||||||
"Check whether c can be used as a cons object"
|
"Check whether c can be used as a cons object"
|
||||||
(instance? HyCons c))
|
(instance? HyCons c))
|
||||||
|
|
||||||
(defn cycle [coll]
|
(defn keyword? [k]
|
||||||
"Yield an infinite repetition of the items in coll"
|
"Check whether k is a keyword"
|
||||||
(setv seen [])
|
(and (instance? (type :foo) k)
|
||||||
(for* [x coll]
|
(.startswith k (get :foo 0))))
|
||||||
(yield x)
|
|
||||||
(.append seen x))
|
|
||||||
(while seen
|
|
||||||
(for* [x seen]
|
|
||||||
(yield x))))
|
|
||||||
|
|
||||||
(defn dec [n]
|
(defn dec [n]
|
||||||
"Decrement n by 1"
|
"Decrement n by 1"
|
||||||
@ -82,22 +80,36 @@
|
|||||||
(yield val)
|
(yield val)
|
||||||
(.add seen val))))))
|
(.add seen val))))))
|
||||||
|
|
||||||
|
(if-python2
|
||||||
|
(do
|
||||||
|
(setv filterfalse itertools.ifilterfalse)
|
||||||
|
(setv zip_longest itertools.izip_longest)
|
||||||
|
(setv filter itertools.ifilter)
|
||||||
|
(setv map itertools.imap)
|
||||||
|
(setv zip itertools.izip)
|
||||||
|
(setv range xrange)
|
||||||
|
(setv input raw_input))
|
||||||
|
(do
|
||||||
|
(setv reduce functools.reduce)
|
||||||
|
(setv filterfalse itertools.filterfalse)
|
||||||
|
(setv zip_longest itertools.zip_longest)
|
||||||
|
; Someone can import these directly from `hy.core.language`;
|
||||||
|
; we'll make some duplicates.
|
||||||
|
(setv filter filter)
|
||||||
|
(setv map map)
|
||||||
|
(setv zip zip)
|
||||||
|
(setv range range)
|
||||||
|
(setv input input)))
|
||||||
|
|
||||||
|
(setv cycle itertools.cycle)
|
||||||
|
(setv repeat itertools.repeat)
|
||||||
|
(setv drop-while itertools.dropwhile)
|
||||||
|
(setv take-while itertools.takewhile)
|
||||||
|
(setv zipwith map)
|
||||||
|
|
||||||
(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"
|
||||||
(let [[citer (iter coll)]]
|
(itertools.islice coll count nil))
|
||||||
(try (for* [i (range count)]
|
|
||||||
(next citer))
|
|
||||||
(catch [StopIteration]))
|
|
||||||
citer))
|
|
||||||
|
|
||||||
(defn drop-while [pred coll]
|
|
||||||
"Drop all elements of `coll` until `pred` is False"
|
|
||||||
(let [[citer (iter coll)]]
|
|
||||||
(for* [val citer]
|
|
||||||
(if (not (pred val))
|
|
||||||
(do (yield val) (break))))
|
|
||||||
(for* [val citer]
|
|
||||||
(yield val))))
|
|
||||||
|
|
||||||
(defn empty? [coll]
|
(defn empty? [coll]
|
||||||
"Return True if `coll` is empty"
|
"Return True if `coll` is empty"
|
||||||
@ -121,13 +133,6 @@
|
|||||||
(if (not (hasattr tree attr))
|
(if (not (hasattr tree attr))
|
||||||
(setattr tree attr 1))))
|
(setattr tree attr 1))))
|
||||||
|
|
||||||
(defn filter [pred coll]
|
|
||||||
"Return all elements from `coll` that pass `pred`"
|
|
||||||
(let [[citer (iter coll)]]
|
|
||||||
(for* [val citer]
|
|
||||||
(if (pred val)
|
|
||||||
(yield val)))))
|
|
||||||
|
|
||||||
(defn flatten [coll]
|
(defn flatten [coll]
|
||||||
"Return a single flat list expanding all members of coll"
|
"Return a single flat list expanding all members of coll"
|
||||||
(if (coll? coll)
|
(if (coll? coll)
|
||||||
@ -169,7 +174,7 @@
|
|||||||
|
|
||||||
(defn first [coll]
|
(defn first [coll]
|
||||||
"Return first item from `coll`"
|
"Return first item from `coll`"
|
||||||
(get coll 0))
|
(nth coll 0))
|
||||||
|
|
||||||
(defn identity [x]
|
(defn identity [x]
|
||||||
"Returns the argument unchanged"
|
"Returns the argument unchanged"
|
||||||
@ -194,14 +199,13 @@
|
|||||||
(defn integer-char? [x]
|
(defn integer-char? [x]
|
||||||
"Return True if char `x` parses as an integer"
|
"Return True if char `x` parses as an integer"
|
||||||
(try
|
(try
|
||||||
(integer? (int x))
|
(integer? (int x))
|
||||||
(catch [e ValueError] False)
|
(catch [e ValueError] False)
|
||||||
(catch [e TypeError] False)))
|
(catch [e TypeError] False)))
|
||||||
|
|
||||||
(defn iterable? [x]
|
(defn iterable? [x]
|
||||||
"Return true if x is iterable"
|
"Return true if x is iterable"
|
||||||
(try (do (iter x) true)
|
(isinstance x collections.Iterable))
|
||||||
(catch [Exception] false)))
|
|
||||||
|
|
||||||
(defn iterate [f x]
|
(defn iterate [f x]
|
||||||
(setv val x)
|
(setv val x)
|
||||||
@ -211,8 +215,7 @@
|
|||||||
|
|
||||||
(defn iterator? [x]
|
(defn iterator? [x]
|
||||||
"Return true if x is an iterator"
|
"Return true if x is an iterator"
|
||||||
(try (= x (iter x))
|
(isinstance x collections.Iterator))
|
||||||
(catch [TypeError] false)))
|
|
||||||
|
|
||||||
(defn list* [hd &rest tl]
|
(defn list* [hd &rest tl]
|
||||||
"Return a dotted list construed from the elements of the argument"
|
"Return a dotted list construed from the elements of the argument"
|
||||||
@ -253,13 +256,9 @@
|
|||||||
|
|
||||||
(defn nth [coll index]
|
(defn nth [coll index]
|
||||||
"Return nth item in collection or sequence, counting from 0"
|
"Return nth item in collection or sequence, counting from 0"
|
||||||
(if (not (neg? index))
|
(try
|
||||||
(if (iterable? coll)
|
(next (drop index coll))
|
||||||
(try (get (list (take 1 (drop index coll))) 0)
|
(catch [e StopIteration] (raise (IndexError index)))))
|
||||||
(catch [IndexError] None))
|
|
||||||
(try (get coll index)
|
|
||||||
(catch [IndexError] None)))
|
|
||||||
None))
|
|
||||||
|
|
||||||
(defn odd? [n]
|
(defn odd? [n]
|
||||||
"Return true if n is an odd number"
|
"Return true if n is an odd number"
|
||||||
@ -280,14 +279,7 @@
|
|||||||
|
|
||||||
(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."
|
||||||
(slice coll 1))
|
(drop 1 coll))
|
||||||
|
|
||||||
(defn repeat [x &optional n]
|
|
||||||
"Yield x forever or optionally n times"
|
|
||||||
(if (none? n)
|
|
||||||
(setv dispatch (fn [] (while true (yield x))))
|
|
||||||
(setv dispatch (fn [] (for* [_ (range n)] (yield x)))))
|
|
||||||
(dispatch))
|
|
||||||
|
|
||||||
(defn repeatedly [func]
|
(defn repeatedly [func]
|
||||||
"Yield result of running func repeatedly"
|
"Yield result of running func repeatedly"
|
||||||
@ -296,7 +288,7 @@
|
|||||||
|
|
||||||
(defn second [coll]
|
(defn second [coll]
|
||||||
"Return second item from `coll`"
|
"Return second item from `coll`"
|
||||||
(get 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 true if (pred x) is logical true for any x in coll, else false"
|
||||||
@ -317,9 +309,7 @@
|
|||||||
(defn take [count coll]
|
(defn take [count coll]
|
||||||
"Take `count` elements from `coll`, or the whole set if the total
|
"Take `count` elements from `coll`, or the whole set if the total
|
||||||
number of entries in `coll` is less than `count`."
|
number of entries in `coll` is less than `count`."
|
||||||
(let [[citer (iter coll)]]
|
(itertools.islice coll nil count))
|
||||||
(for* [_ (range count)]
|
|
||||||
(yield (next citer)))))
|
|
||||||
|
|
||||||
(defn take-nth [n coll]
|
(defn take-nth [n coll]
|
||||||
"Return every nth member of coll
|
"Return every nth member of coll
|
||||||
@ -332,29 +322,15 @@
|
|||||||
(next citer))))
|
(next citer))))
|
||||||
(raise (ValueError "n must be positive"))))
|
(raise (ValueError "n must be positive"))))
|
||||||
|
|
||||||
(defn take-while [pred coll]
|
|
||||||
"Take all elements while `pred` is true"
|
|
||||||
(let [[citer (iter coll)]]
|
|
||||||
(for* [val citer]
|
|
||||||
(if (pred val)
|
|
||||||
(yield val)
|
|
||||||
(break)))))
|
|
||||||
|
|
||||||
(defn zero? [n]
|
(defn zero? [n]
|
||||||
"Return true if n is 0"
|
"Return true if n is 0"
|
||||||
(_numeric_check n)
|
(_numeric_check n)
|
||||||
(= n 0))
|
(= n 0))
|
||||||
|
|
||||||
(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))))
|
|
||||||
|
|
||||||
(def *exports* '[calling-module-name coll? cons cons? cycle dec distinct
|
(def *exports* '[calling-module-name coll? cons cons? cycle dec distinct
|
||||||
disassemble drop drop-while empty? even? every? first filter
|
disassemble drop drop-while empty? even? every? first filter
|
||||||
flatten float? gensym identity inc instance? integer
|
flatten float? gensym identity inc instance? integer
|
||||||
integer? integer-char? iterable? iterate iterator?
|
integer? integer-char? iterable? iterate iterator? keyword?
|
||||||
list* macroexpand macroexpand-1 neg? nil? none? nth
|
list* macroexpand macroexpand-1 map neg? nil? none? nth
|
||||||
numeric? odd? pos? remove repeat repeatedly rest second
|
numeric? odd? pos? range remove repeat repeatedly rest second
|
||||||
some string string? take take-nth take-while zero? zipwith])
|
some string string? take take-nth take-while zero? zip 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)
|
||||||
@ -170,6 +162,21 @@
|
|||||||
(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)]
|
||||||
|
@ -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
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
-r requirements.txt
|
# test tools
|
||||||
tox
|
|
||||||
nose
|
nose
|
||||||
|
tox
|
||||||
|
|
||||||
|
# code quality
|
||||||
|
flake8
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# documentation
|
||||||
Pygments>=1.6
|
Pygments>=1.6
|
||||||
Sphinx
|
Sphinx
|
||||||
coverage
|
sphinx_rtd_theme
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
# Check site / dev for more deps!
|
|
||||||
flake8
|
|
||||||
rply>=0.7.0
|
|
3
setup.py
3
setup.py
@ -59,7 +59,8 @@ setup(
|
|||||||
entry_points={
|
entry_points={
|
||||||
'console_scripts': [
|
'console_scripts': [
|
||||||
'hy = hy.cmdline:hy_main',
|
'hy = hy.cmdline:hy_main',
|
||||||
'hyc = hy.cmdline:hyc_main'
|
'hyc = hy.cmdline:hyc_main',
|
||||||
|
'hy2py = hy.cmdline:hy2py_main',
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
packages=find_packages(exclude=['tests*']),
|
packages=find_packages(exclude=['tests*']),
|
||||||
|
@ -57,6 +57,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 ])))
|
||||||
@ -82,8 +110,8 @@
|
|||||||
(assert-equal res [None 4 5])
|
(assert-equal res [None 4 5])
|
||||||
(setv res (list (drop 0 [1 2 3 4 5])))
|
(setv res (list (drop 0 [1 2 3 4 5])))
|
||||||
(assert-equal res [1 2 3 4 5])
|
(assert-equal res [1 2 3 4 5])
|
||||||
(setv res (list (drop -1 [1 2 3 4 5])))
|
(try (do (list (drop -1 [1 2 3 4 5])) (assert False))
|
||||||
(assert-equal res [1 2 3 4 5])
|
(catch [e [ValueError]] nil))
|
||||||
(setv res (list (drop 6 (iter [1 2 3 4 5]))))
|
(setv res (list (drop 6 (iter [1 2 3 4 5]))))
|
||||||
(assert-equal res [])
|
(assert-equal res [])
|
||||||
(setv res (list (take 5 (drop 2 (iterate inc 0)))))
|
(setv res (list (take 5 (drop 2 (iterate inc 0)))))
|
||||||
@ -335,12 +363,15 @@
|
|||||||
"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))
|
||||||
(assert-true (none? (nth [1 2 4 7] 5)))
|
(try (do (nth [1 2 4 7] 5) (assert False))
|
||||||
(assert-true (none? (nth [1 2 4 7] -1)))
|
(catch [e [IndexError]] nil))
|
||||||
|
(try (do (nth [1 2 4 7] -1) (assert False))
|
||||||
|
(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-true (none? (nth (iter [1 2 4 7]) -1)))
|
(try (do (nth (iter [1 2 4 7]) -1) (assert False))
|
||||||
|
(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)))
|
||||||
|
|
||||||
(defn test-numeric? []
|
(defn test-numeric? []
|
||||||
@ -429,8 +460,8 @@
|
|||||||
(assert-equal res ["s" "s" "s" "s"])
|
(assert-equal res ["s" "s" "s" "s"])
|
||||||
(setv res (list (take 0 (repeat "s"))))
|
(setv res (list (take 0 (repeat "s"))))
|
||||||
(assert-equal res [])
|
(assert-equal res [])
|
||||||
(setv res (list (take -1 (repeat "s"))))
|
(try (do (list (take -1 (repeat "s"))) (assert False))
|
||||||
(assert-equal res [])
|
(catch [e [ValueError]] nil))
|
||||||
(setv res (list (take 6 [1 2 None 4])))
|
(setv res (list (take 6 [1 2 None 4])))
|
||||||
(assert-equal res [1 2 None 4]))
|
(assert-equal res [1 2 None 4]))
|
||||||
|
|
||||||
@ -478,3 +509,14 @@
|
|||||||
(assert-equal (list res) [4 4 4])
|
(assert-equal (list res) [4 4 4])
|
||||||
(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-is-keyword []
|
||||||
|
"NATIVE: testing the keyword? function"
|
||||||
|
(assert (keyword? ':bar))
|
||||||
|
(assert (keyword? ':baz))
|
||||||
|
(assert (keyword? :bar))
|
||||||
|
(assert (keyword? :baz))
|
||||||
|
(assert (not (keyword? "foo")))
|
||||||
|
(assert (not (keyword? ":foo")))
|
||||||
|
(assert (not (keyword? 1)))
|
||||||
|
(assert (not (keyword? nil))))
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
|
|
||||||
(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 +38,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 []
|
||||||
@ -236,6 +240,11 @@
|
|||||||
"NATIVE: test do"
|
"NATIVE: test do"
|
||||||
(do))
|
(do))
|
||||||
|
|
||||||
|
(defn test-bare-try [] (try
|
||||||
|
(try (raise ValueError))
|
||||||
|
(except [ValueError])
|
||||||
|
(else (assert false))))
|
||||||
|
|
||||||
|
|
||||||
(defn test-exceptions []
|
(defn test-exceptions []
|
||||||
"NATIVE: test Exceptions"
|
"NATIVE: test Exceptions"
|
||||||
@ -469,7 +478,7 @@
|
|||||||
|
|
||||||
(defn test-rest []
|
(defn test-rest []
|
||||||
"NATIVE: test rest"
|
"NATIVE: test rest"
|
||||||
(assert (= (rest [1 2 3 4 5]) [2 3 4 5])))
|
(assert (= (list (rest [1 2 3 4 5])) [2 3 4 5])))
|
||||||
|
|
||||||
|
|
||||||
(defn test-importas []
|
(defn test-importas []
|
||||||
|
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"))
|
@ -129,7 +129,7 @@ def test_hy2py():
|
|||||||
for f in filenames:
|
for f in filenames:
|
||||||
if f.endswith(".hy"):
|
if f.endswith(".hy"):
|
||||||
i += 1
|
i += 1
|
||||||
ret = run_cmd("python bin/hy2py -s -a "
|
ret = run_cmd("hy2py -s -a "
|
||||||
+ os.path.join(dirpath, f))
|
+ os.path.join(dirpath, f))
|
||||||
assert ret[0] == 0, f
|
assert ret[0] == 0, f
|
||||||
assert len(ret[1]) > 1, f
|
assert len(ret[1]) > 1, f
|
||||||
@ -142,3 +142,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]
|
||||||
|
37
tox.ini
37
tox.ini
@ -1,39 +1,18 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py27,pypy,py32,py33,py26,flake8
|
envlist = py26,py27,pypy,py32,py33,flake8
|
||||||
|
skipsdist = True
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
commands = nosetests
|
commands =
|
||||||
|
pip install --allow-all-external -e .
|
||||||
|
nosetests
|
||||||
deps =
|
deps =
|
||||||
nose
|
-rrequirements-dev.txt
|
||||||
setuptools
|
|
||||||
rply
|
|
||||||
|
|
||||||
[testenv:pypy]
|
|
||||||
commands = nosetests
|
|
||||||
deps =
|
|
||||||
astor
|
|
||||||
nose
|
|
||||||
setuptools
|
|
||||||
rply
|
|
||||||
|
|
||||||
[testenv:py27]
|
|
||||||
commands = nosetests
|
|
||||||
deps =
|
|
||||||
astor
|
|
||||||
nose
|
|
||||||
setuptools
|
|
||||||
rply
|
|
||||||
|
|
||||||
[testenv:py26]
|
[testenv:py26]
|
||||||
deps =
|
deps =
|
||||||
astor
|
{[testenv]deps}
|
||||||
nose
|
|
||||||
setuptools
|
|
||||||
unittest2
|
unittest2
|
||||||
importlib
|
|
||||||
rply
|
|
||||||
|
|
||||||
[testenv:flake8]
|
[testenv:flake8]
|
||||||
deps =
|
|
||||||
flake8
|
|
||||||
rply
|
|
||||||
commands = flake8 hy bin tests
|
commands = flake8 hy bin tests
|
||||||
|
Loading…
Reference in New Issue
Block a user