commit
d91dbd19f8
24
.travis.yml
24
.travis.yml
@ -1,13 +1,21 @@
|
|||||||
sudo: false
|
sudo: false
|
||||||
language: python
|
language: python
|
||||||
python:
|
matrix:
|
||||||
- "pypy"
|
include:
|
||||||
- "2.7"
|
- python: 3.5
|
||||||
- "3.3"
|
env: TOXENV=py35
|
||||||
- "3.4"
|
env:
|
||||||
cache: pip
|
- TOXENV=py27
|
||||||
# command to run tests
|
- TOXENV=py33
|
||||||
script: make travis
|
- TOXENV=py34
|
||||||
|
- TOXENV=pypy
|
||||||
|
- TOXENV=flake8
|
||||||
|
install: pip install tox
|
||||||
|
script: tox
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- .tox
|
||||||
|
- $HOME/.cache/pip
|
||||||
after_success: make coveralls
|
after_success: make coveralls
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
|
4
AUTHORS
4
AUTHORS
@ -65,3 +65,7 @@
|
|||||||
* Antony Woods <antony@teamwoods.org>
|
* Antony Woods <antony@teamwoods.org>
|
||||||
* Matthew Egan Odendahl <github.gilch@xoxy.net>
|
* Matthew Egan Odendahl <github.gilch@xoxy.net>
|
||||||
* Tim Martin <tim@asymptotic.co.uk>
|
* Tim Martin <tim@asymptotic.co.uk>
|
||||||
|
* Johnathon Mlady <john@digitalvectorz.com>
|
||||||
|
* Andrew Savchyn <dev@scorpil.com>
|
||||||
|
* Lev Kravinsky <kravinskylev@gmail.com>
|
||||||
|
* Luna Lunapiena <lunacodes@gmail.com>
|
||||||
|
@ -6,11 +6,20 @@ helps in making Hy more awesome.
|
|||||||
|
|
||||||
Pull requests are great! We love them; here is a quick guide:
|
Pull requests are great! We love them; here is a quick guide:
|
||||||
|
|
||||||
- Fork the repo and create a topic branch for a feature/fix. Avoid
|
- `Fork the repo`_ and create a topic branch for a feature/fix. Avoid
|
||||||
making changes directly on the master branch.
|
making changes directly on the master branch.
|
||||||
|
(If you're new to Git: `Start Here`_)
|
||||||
|
|
||||||
- All incoming features should be accompanied with tests.
|
- All incoming features should be accompanied with tests.
|
||||||
|
|
||||||
|
- If you are contributing a major change to the Hy language (e.g. changing
|
||||||
|
the behavior of or removing functions or macros), or you're unsure of
|
||||||
|
the proposed change, please open an issue in the `issue tracker`_ before
|
||||||
|
submitting the PR. This will allow others to give feedback on your idea,
|
||||||
|
and it will avoid constant changes or wasted work. For other PRs (such as
|
||||||
|
documentation fixes or code cleanup), you can directly open the PR without
|
||||||
|
first opening a corresponding issue.
|
||||||
|
|
||||||
- Before you submit a PR, please run the tests and check your code
|
- Before you submit a PR, please run the tests and check your code
|
||||||
against the style guide. You can do both of these things at once::
|
against the style guide. You can do both of these things at once::
|
||||||
|
|
||||||
@ -82,3 +91,6 @@ version 1.1.0, available at
|
|||||||
http://contributor-covenant.org/version/1/1/0/.
|
http://contributor-covenant.org/version/1/1/0/.
|
||||||
|
|
||||||
.. _Contributor Covenant: http://contributor-covenant.org
|
.. _Contributor Covenant: http://contributor-covenant.org
|
||||||
|
.. _issue tracker: https://github.com/hylang/hy/issues
|
||||||
|
.. _Fork the Repo: https://help.github.com/articles/fork-a-repo/
|
||||||
|
.. _Start Here: http://rogerdudler.github.io/git-guide/)
|
8
Makefile
8
Makefile
@ -67,14 +67,6 @@ endif
|
|||||||
$(pip) install coveralls
|
$(pip) install coveralls
|
||||||
$(pip) install --allow-all-external -e .
|
$(pip) install --allow-all-external -e .
|
||||||
|
|
||||||
travis: python
|
|
||||||
$(nose) -s --with-coverage --cover-package hy
|
|
||||||
ifeq (PyPy,$(findstring PyPy,$(shell python -V 2>&1 | tail -1)))
|
|
||||||
@echo "skipping flake8 on pypy"
|
|
||||||
else
|
|
||||||
flake8 hy bin tests
|
|
||||||
endif
|
|
||||||
|
|
||||||
coveralls:
|
coveralls:
|
||||||
$(coveralls)
|
$(coveralls)
|
||||||
|
|
||||||
|
2
NEWS
2
NEWS
@ -107,7 +107,7 @@ Changes from 0.9.12
|
|||||||
Many thanks to algernon for working on adderall, which helped
|
Many thanks to algernon for working on adderall, which helped
|
||||||
push Hy further this cycle. Adderall is an implementation of miniKanren
|
push Hy further this cycle. Adderall is an implementation of miniKanren
|
||||||
in Hy. If you're interested in using Adderall, check out hydiomatic,
|
in Hy. If you're interested in using Adderall, check out hydiomatic,
|
||||||
which prettfies Hy source using Adderall rules.
|
which prettifies Hy source using Adderall rules.
|
||||||
|
|
||||||
This release saw an increase of about 11 contributors for a point
|
This release saw an increase of about 11 contributors for a point
|
||||||
release, you guys rock!
|
release, you guys rock!
|
||||||
|
@ -6,7 +6,7 @@ Hy
|
|||||||
[![Version](https://img.shields.io/pypi/v/hy.svg)](https://pypi.python.org/pypi/hy)
|
[![Version](https://img.shields.io/pypi/v/hy.svg)](https://pypi.python.org/pypi/hy)
|
||||||
[![Coverage Status](https://img.shields.io/coveralls/hylang/hy/master.svg)](https://coveralls.io/r/hylang/hy)
|
[![Coverage Status](https://img.shields.io/coveralls/hylang/hy/master.svg)](https://coveralls.io/r/hylang/hy)
|
||||||
|
|
||||||
![XKCD #224](https://raw.github.com/hylang/shyte/18f6925e08684b0e1f52b2cc2c803989cd62cd91/imgs/xkcd.png)
|
[![XKCD #224](https://raw.github.com/hylang/shyte/18f6925e08684b0e1f52b2cc2c803989cd62cd91/imgs/xkcd.png)](https://xkcd.com/224/)
|
||||||
|
|
||||||
Lisp and Python should love each other. Let's make it happen. [Try it](http://try-hy.appspot.com/).
|
Lisp and Python should love each other. Let's make it happen. [Try it](http://try-hy.appspot.com/).
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ It's really awesome.
|
|||||||
|
|
||||||
Oh, and lisps are neat.
|
Oh, and lisps are neat.
|
||||||
|
|
||||||
![Cuddles the Hacker](http://i.imgur.com/QbPMXTN.png)
|
![Cuddles the Hacker](https://i.imgur.com/QbPMXTN.png)
|
||||||
|
|
||||||
(fan art from the one and only [doctormo](http://doctormo.deviantart.com/art/Cuddles-the-Hacker-372184766))
|
(fan art from the one and only [doctormo](http://doctormo.deviantart.com/art/Cuddles-the-Hacker-372184766))
|
||||||
|
|
||||||
@ -46,3 +46,4 @@ Project
|
|||||||
* Bug reports: We have no bugs! Your bugs are your own! (https://github.com/hylang/hy/issues)
|
* Bug reports: We have no bugs! Your bugs are your own! (https://github.com/hylang/hy/issues)
|
||||||
* License: MIT (Expat)
|
* License: MIT (Expat)
|
||||||
* [Contributor Guidelines & Code of Conduct](https://github.com/hylang/hy/blob/master/CONTRIBUTING.rst)
|
* [Contributor Guidelines & Code of Conduct](https://github.com/hylang/hy/blob/master/CONTRIBUTING.rst)
|
||||||
|
* IRC: Join #hy on [freenode](https://webchat.freenode.net/)
|
||||||
|
@ -13,6 +13,9 @@ concise and easy to read.
|
|||||||
|
|
||||||
-- Wikipedia (http://en.wikipedia.org/wiki/Anaphoric_macro)
|
-- Wikipedia (http://en.wikipedia.org/wiki/Anaphoric_macro)
|
||||||
|
|
||||||
|
To use these macros you need to require the hy.contrib.anaphoric module like so:
|
||||||
|
|
||||||
|
``(require hy.contrib.anaphoric)``
|
||||||
|
|
||||||
.. _ap-if:
|
.. _ap-if:
|
||||||
|
|
||||||
@ -244,5 +247,3 @@ This is similar to Clojure's anonymous function literals (``#()``).
|
|||||||
=> (def add-10 (xi + 10 x1))
|
=> (def add-10 (xi + 10 x1))
|
||||||
=> (add-10 6)
|
=> (add-10 6)
|
||||||
16
|
16
|
||||||
|
|
||||||
|
|
||||||
|
@ -400,7 +400,7 @@ below:
|
|||||||
.. _defn:
|
.. _defn:
|
||||||
|
|
||||||
defn
|
defn
|
||||||
------------
|
----
|
||||||
|
|
||||||
``defn`` macro is used to define functions. It takes three
|
``defn`` macro is used to define functions. It takes three
|
||||||
parameters: the *name* of the function to define, a vector of *parameters*,
|
parameters: the *name* of the function to define, a vector of *parameters*,
|
||||||
@ -430,7 +430,26 @@ Parameters may have the following keywords in front of them:
|
|||||||
101.0
|
101.0
|
||||||
|
|
||||||
&key
|
&key
|
||||||
|
Parameter is a dict of keyword arguments. The keys of the dict
|
||||||
|
specify the parameter names and the values give the default values
|
||||||
|
of the parameters.
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
=> (defn key-parameters [&key {"a" 1 "b" 2}]
|
||||||
|
... (print "a is" a "and b is" b))
|
||||||
|
=> (key-parameters :a 1 :b 2)
|
||||||
|
a is 1 and b is 2
|
||||||
|
=> (key-parameters :b 1 :a 2)
|
||||||
|
a is 2 and b is 1
|
||||||
|
|
||||||
|
The following declarations are equivalent:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(defn key-parameters [&key {"a" 1 "b" 2}])
|
||||||
|
|
||||||
|
(defn key-parameters [&optional [a 1] [b 2]])
|
||||||
|
|
||||||
&kwargs
|
&kwargs
|
||||||
Parameter will contain 0 or more keyword arguments.
|
Parameter will contain 0 or more keyword arguments.
|
||||||
@ -1489,6 +1508,27 @@ expands to:
|
|||||||
Section :ref:`using-gensym`
|
Section :ref:`using-gensym`
|
||||||
|
|
||||||
|
|
||||||
|
xor
|
||||||
|
---
|
||||||
|
|
||||||
|
.. versionadded:: 0.12.0
|
||||||
|
|
||||||
|
``xor`` is used in logical expressions to perform exclusive or. It takes two
|
||||||
|
parameters. It returns ``True`` if only of the parameters is ``True``. In all
|
||||||
|
other cases ``False`` is returned. Example usage:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
=> (xor True False)
|
||||||
|
True
|
||||||
|
|
||||||
|
=> (xor True True)
|
||||||
|
False
|
||||||
|
|
||||||
|
=> (xor [] [0])
|
||||||
|
True
|
||||||
|
|
||||||
|
|
||||||
yield
|
yield
|
||||||
-----
|
-----
|
||||||
|
|
||||||
@ -1502,7 +1542,7 @@ infinite series without consuming infinite amount of memory.
|
|||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
=> (defn multiply [bases coefficients]
|
=> (defn multiply [bases coefficients]
|
||||||
... (for [[(, base coefficient) (zip bases coefficients)]]
|
... (for [(, base coefficient) (zip bases coefficients)]
|
||||||
... (yield (* base coefficient))))
|
... (yield (* base coefficient))))
|
||||||
|
|
||||||
=> (multiply (range 5) (range 5))
|
=> (multiply (range 5) (range 5))
|
||||||
@ -1514,7 +1554,7 @@ infinite series without consuming infinite amount of memory.
|
|||||||
=> (import random)
|
=> (import random)
|
||||||
=> (defn random-numbers [low high]
|
=> (defn random-numbers [low high]
|
||||||
... (while True (yield (.randint random low high))))
|
... (while True (yield (.randint random low high))))
|
||||||
=> (list-comp x [x (take 15 (random-numbers 1 50))])])
|
=> (list-comp x [x (take 15 (random-numbers 1 50))])
|
||||||
[7, 41, 6, 22, 32, 17, 5, 38, 18, 38, 17, 14, 23, 23, 19]
|
[7, 41, 6, 22, 32, 17, 5, 38, 18, 38, 17, 14, 23, 23, 19]
|
||||||
|
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ A cons cell is a 2-item object, containing a ``car`` (head) and a
|
|||||||
building block, and S-expressions are actually represented as linked
|
building block, and S-expressions are actually represented as linked
|
||||||
lists of cons cells. This is not the case in Hy, as the usual
|
lists of cons cells. This is not the case in Hy, as the usual
|
||||||
expressions are made of Python lists wrapped in a
|
expressions are made of Python lists wrapped in a
|
||||||
``HyExpression``. However, the ``HyCons`` mimicks the behavior of
|
``HyExpression``. However, the ``HyCons`` mimics the behavior of
|
||||||
"usual" Lisp variants thusly:
|
"usual" Lisp variants thusly:
|
||||||
|
|
||||||
- ``(cons something nil)`` is ``(HyExpression [something])``
|
- ``(cons something nil)`` is ``(HyExpression [something])``
|
||||||
@ -386,7 +386,7 @@ A first pass might be something like:
|
|||||||
[(zero? obscure-name) ~zero-form]
|
[(zero? obscure-name) ~zero-form]
|
||||||
[(neg? obscure-name) ~neg-form])))
|
[(neg? obscure-name) ~neg-form])))
|
||||||
|
|
||||||
where ``obsure-name`` is an attempt to pick some variable name as not to
|
where ``obscure-name`` is an attempt to pick some variable name as not to
|
||||||
conflict with other code. But of course, while well-intentioned,
|
conflict with other code. But of course, while well-intentioned,
|
||||||
this is no guarantee.
|
this is no guarantee.
|
||||||
|
|
||||||
|
@ -31,13 +31,18 @@ Quickstart
|
|||||||
|
|
||||||
7. Open up an elite programming editor and type::
|
7. Open up an elite programming editor and type::
|
||||||
|
|
||||||
|
#! /usr/bin/env hy
|
||||||
(print "I was going to code in Python syntax, but then I got Hy.")
|
(print "I was going to code in Python syntax, but then I got Hy.")
|
||||||
|
|
||||||
8. Save as ``awesome.hy``.
|
8. Save as ``awesome.hy``.
|
||||||
9. And run your first Hy program::
|
9. Make it executable::
|
||||||
|
|
||||||
hy awesome.hy
|
chmod +x awesome.hy
|
||||||
|
|
||||||
10. Take a deep breath so as to not hyperventilate.
|
10. And run your first Hy program::
|
||||||
11. Smile villainously and sneak off to your hydeaway and do
|
|
||||||
|
./awesome.hy
|
||||||
|
|
||||||
|
11. Take a deep breath so as to not hyperventilate.
|
||||||
|
12. Smile villainously and sneak off to your hydeaway and do
|
||||||
unspeakable things.
|
unspeakable things.
|
||||||
|
@ -9,7 +9,7 @@ Hy Style Guide
|
|||||||
The Hy style guide intends to be a set of ground rules for the Hyve
|
The Hy style guide intends to be a set of ground rules for the Hyve
|
||||||
(yes, the Hy community prides itself in appending Hy to everything)
|
(yes, the Hy community prides itself in appending Hy to everything)
|
||||||
to write idiomatic Hy code. Hy derives a lot from Clojure & Common
|
to write idiomatic Hy code. Hy derives a lot from Clojure & Common
|
||||||
Lisp, while always maintaining Python interopability.
|
Lisp, while always maintaining Python interoperability.
|
||||||
|
|
||||||
|
|
||||||
Prelude
|
Prelude
|
||||||
|
@ -168,7 +168,7 @@ There are some advantages to having a code structure that's actually a
|
|||||||
very simple data structure as the core of Lisp is based on. For one
|
very simple data structure as the core of Lisp is based on. For one
|
||||||
thing, it means that your programs are easy to parse and that the
|
thing, it means that your programs are easy to parse and that the
|
||||||
entire actual structure of the program is very clearly exposed to you.
|
entire actual structure of the program is very clearly exposed to you.
|
||||||
(There's an extra step in hy where the structure you see is converted
|
(There's an extra step in Hy where the structure you see is converted
|
||||||
to Python's own representations ... in "purer" Lisps such as Common
|
to Python's own representations ... in "purer" Lisps such as Common
|
||||||
Lisp or Emacs Lisp, the data structure you see in the code and the
|
Lisp or Emacs Lisp, the data structure you see in the code and the
|
||||||
data structure that is executed is much more literally close.)
|
data structure that is executed is much more literally close.)
|
||||||
@ -258,6 +258,7 @@ In Hy, you would do:
|
|||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(setv somevar 33)
|
||||||
(cond
|
(cond
|
||||||
[(> somevar 50)
|
[(> somevar 50)
|
||||||
(print "That variable is too big!")]
|
(print "That variable is too big!")]
|
||||||
@ -306,6 +307,13 @@ Comments start with semicolons:
|
|||||||
; (print "but this will not")
|
; (print "but this will not")
|
||||||
(+ 1 2 3) ; we'll execute the addition, but not this comment!
|
(+ 1 2 3) ; we'll execute the addition, but not this comment!
|
||||||
|
|
||||||
|
Hashbang (``#!``) syntax is supported:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
#! /usr/bin/env hy
|
||||||
|
(print "Make me executable, and run me!")
|
||||||
|
|
||||||
Looping is not hard but has a kind of special structure. In Python,
|
Looping is not hard but has a kind of special structure. In Python,
|
||||||
we might do::
|
we might do::
|
||||||
|
|
||||||
@ -505,22 +513,22 @@ In Hy:
|
|||||||
Macros
|
Macros
|
||||||
======
|
======
|
||||||
|
|
||||||
One really powerful feature of Hy are macros. They are small functios that are
|
One really powerful feature of Hy are macros. They are small functions that are
|
||||||
used to generate code (or data). When program written in Hy is started, the
|
used to generate code (or data). When program written in Hy is started, the
|
||||||
macros are executed and their output is placed in program source. After this,
|
macros are executed and their output is placed in the program source. After this,
|
||||||
the program starts executing normally. Very simple example:
|
the program starts executing normally. Very simple example:
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
=> (defmacro hello [person]
|
=> (defmacro hello [person]
|
||||||
... `(print "Hello there," ~person))
|
... `(print "Hello there," ~person))
|
||||||
=> (Hello "Tuukka")
|
=> (hello "Tuukka")
|
||||||
Hello there, Tuukka
|
Hello there, Tuukka
|
||||||
|
|
||||||
The thing to notice here is that hello macro doesn't output anything on
|
The thing to notice here is that hello macro doesn't output anything on
|
||||||
screen. Instead it creates piece of code that is then executed and prints on
|
screen. Instead it creates piece of code that is then executed and prints on
|
||||||
screen. Macro writes a piece of program that looks like this (provided that
|
screen. This macro writes a piece of program that looks like this (provided that
|
||||||
we used "Tuukka" as parameter:
|
we used "Tuukka" as parameter):
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
@ -536,14 +544,14 @@ We can also manipulate code with macros:
|
|||||||
=> (rev (1 2 3 +))
|
=> (rev (1 2 3 +))
|
||||||
6
|
6
|
||||||
|
|
||||||
The code that was generated with this macro just switched around some the
|
The code that was generated with this macro just switched around some of the
|
||||||
elements, so by the time program started executing, it actually red:
|
elements, so by the time program started executing, it actually reads:
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
(+ 1 2 3)
|
(+ 1 2 3)
|
||||||
|
|
||||||
Sometimes it's nice to have a very short name for macro that doesn't take much
|
Sometimes it's nice to have a very short name for a macro that doesn't take much
|
||||||
space or use extra parentheses. Reader macros can be pretty useful in these
|
space or use extra parentheses. Reader macros can be pretty useful in these
|
||||||
situations (and since Hy operates well with unicode, we aren't running out of
|
situations (and since Hy operates well with unicode, we aren't running out of
|
||||||
characters that soon):
|
characters that soon):
|
||||||
@ -556,14 +564,14 @@ characters that soon):
|
|||||||
=> #↻(1 2 3 +)
|
=> #↻(1 2 3 +)
|
||||||
6
|
6
|
||||||
|
|
||||||
Macros are useful when one wishes to extend the Hy or write their own
|
Macros are useful when one wishes to extend Hy or write their own
|
||||||
language on top of that. Many features of Hy are macros, like ``when``,
|
language on top of that. Many features of Hy are macros, like ``when``,
|
||||||
``cond`` and ``->``.
|
``cond`` and ``->``.
|
||||||
|
|
||||||
To use macros defined in a different module, it is not enough to
|
To use macros defined in a different module, it is not enough to
|
||||||
``import`` the module, because importing happens at run-time, while we
|
``import`` the module, because importing happens at run-time, while we
|
||||||
would need macros at compile-time. Instead of importing the module
|
would need macros at compile-time. Instead of importing the module
|
||||||
with macros, it must be ``require``d:
|
with macros, ``require`` must be used:
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ class HyREPL(code.InteractiveConsole):
|
|||||||
if e.source is None:
|
if e.source is None:
|
||||||
e.source = source
|
e.source = source
|
||||||
e.filename = filename
|
e.filename = filename
|
||||||
sys.stderr.write(str(e))
|
print(e, file=sys.stderr)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -110,7 +110,7 @@ class HyREPL(code.InteractiveConsole):
|
|||||||
e.source = source
|
e.source = source
|
||||||
e.filename = filename
|
e.filename = filename
|
||||||
if SIMPLE_TRACEBACKS:
|
if SIMPLE_TRACEBACKS:
|
||||||
sys.stderr.write(str(e))
|
print(e, file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
self.showtraceback()
|
self.showtraceback()
|
||||||
return False
|
return False
|
||||||
@ -179,16 +179,18 @@ require("hy.cmdline", "__main__")
|
|||||||
SIMPLE_TRACEBACKS = True
|
SIMPLE_TRACEBACKS = True
|
||||||
|
|
||||||
|
|
||||||
def run_command(source):
|
def pretty_error(func, *args, **kw):
|
||||||
try:
|
try:
|
||||||
import_buffer_to_module("__main__", source)
|
return func(*args, **kw)
|
||||||
except (HyTypeError, LexException) as e:
|
except (HyTypeError, LexException) as e:
|
||||||
if SIMPLE_TRACEBACKS:
|
if SIMPLE_TRACEBACKS:
|
||||||
sys.stderr.write(str(e))
|
print(e, file=sys.stderr)
|
||||||
return 1
|
sys.exit(1)
|
||||||
raise
|
|
||||||
except Exception:
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(source):
|
||||||
|
pretty_error(import_buffer_to_module, "__main__", source)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
@ -199,22 +201,14 @@ def run_module(mod_name):
|
|||||||
sys.argv = [pth] + sys.argv
|
sys.argv = [pth] + sys.argv
|
||||||
return run_file(pth)
|
return run_file(pth)
|
||||||
|
|
||||||
sys.stderr.write("{0}: module '{1}' not found.\n".format(hy.__appname__,
|
print("{0}: module '{1}' not found.\n".format(hy.__appname__, mod_name),
|
||||||
mod_name))
|
file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def run_file(filename):
|
def run_file(filename):
|
||||||
from hy.importer import import_file_to_module
|
from hy.importer import import_file_to_module
|
||||||
try:
|
pretty_error(import_file_to_module, "__main__", filename)
|
||||||
import_file_to_module("__main__", filename)
|
|
||||||
except (HyTypeError, LexException) as e:
|
|
||||||
if SIMPLE_TRACEBACKS:
|
|
||||||
sys.stderr.write(str(e))
|
|
||||||
return 1
|
|
||||||
raise
|
|
||||||
except Exception:
|
|
||||||
raise
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
@ -334,8 +328,8 @@ def cmdline_handler(scriptname, argv):
|
|||||||
try:
|
try:
|
||||||
return run_file(options.args[0])
|
return run_file(options.args[0])
|
||||||
except HyIOError as e:
|
except HyIOError as e:
|
||||||
sys.stderr.write("hy: Can't open file '%s': [Errno %d] %s\n" %
|
print("hy: Can't open file '{0}': [Errno {1}] {2}\n".format(
|
||||||
(e.filename, e.errno, e.strerror))
|
e.filename, e.errno, e.strerror), file=sys.stderr)
|
||||||
sys.exit(e.errno)
|
sys.exit(e.errno)
|
||||||
|
|
||||||
# User did NOTHING!
|
# User did NOTHING!
|
||||||
@ -359,11 +353,11 @@ def hyc_main():
|
|||||||
|
|
||||||
for file in options.files:
|
for file in options.files:
|
||||||
try:
|
try:
|
||||||
write_hy_as_pyc(file)
|
|
||||||
print("Compiling %s" % file)
|
print("Compiling %s" % file)
|
||||||
|
pretty_error(write_hy_as_pyc, file)
|
||||||
except IOError as x:
|
except IOError as x:
|
||||||
sys.stderr.write("hyc: Can't open file '%s': [Errno %d] %s\n" %
|
print("hyc: Can't open file '{0}': [Errno {1}] {2}\n".format(
|
||||||
(x.filename, x.errno, x.strerror))
|
x.filename, x.errno, x.strerror), file=sys.stderr)
|
||||||
sys.exit(x.errno)
|
sys.exit(x.errno)
|
||||||
|
|
||||||
|
|
||||||
@ -391,7 +385,7 @@ def hy2py_main():
|
|||||||
parser.exit(1, parser.format_help())
|
parser.exit(1, parser.format_help())
|
||||||
|
|
||||||
if options.with_source:
|
if options.with_source:
|
||||||
hst = import_file_to_hst(options.args[0])
|
hst = pretty_error(import_file_to_hst, options.args[0])
|
||||||
# need special printing on Windows in case the
|
# need special printing on Windows in case the
|
||||||
# codepage doesn't support utf-8 characters
|
# codepage doesn't support utf-8 characters
|
||||||
if PY3 and platform.system() == "Windows":
|
if PY3 and platform.system() == "Windows":
|
||||||
@ -405,7 +399,7 @@ def hy2py_main():
|
|||||||
print()
|
print()
|
||||||
print()
|
print()
|
||||||
|
|
||||||
_ast = import_file_to_ast(options.args[0], module_name)
|
_ast = pretty_error(import_file_to_ast, options.args[0], module_name)
|
||||||
if options.with_ast:
|
if options.with_ast:
|
||||||
if PY3 and platform.system() == "Windows":
|
if PY3 and platform.system() == "Windows":
|
||||||
_print_for_windows(astor.dump(_ast))
|
_print_for_windows(astor.dump(_ast))
|
||||||
|
@ -532,7 +532,7 @@ class HyASTCompiler(object):
|
|||||||
raise HyTypeError(expr,
|
raise HyTypeError(expr,
|
||||||
"There can only be one "
|
"There can only be one "
|
||||||
"&rest argument")
|
"&rest argument")
|
||||||
varargs = str(expr)
|
varargs = expr
|
||||||
elif lambda_keyword == "&key":
|
elif lambda_keyword == "&key":
|
||||||
if type(expr) != HyDict:
|
if type(expr) != HyDict:
|
||||||
raise HyTypeError(expr,
|
raise HyTypeError(expr,
|
||||||
@ -547,6 +547,10 @@ class HyASTCompiler(object):
|
|||||||
# defining keyword arguments.
|
# defining keyword arguments.
|
||||||
it = iter(expr)
|
it = iter(expr)
|
||||||
for k, v in zip(it, it):
|
for k, v in zip(it, it):
|
||||||
|
if not isinstance(k, HyString):
|
||||||
|
raise HyTypeError(expr,
|
||||||
|
"Only strings can be used "
|
||||||
|
"as parameter names")
|
||||||
args.append(k)
|
args.append(k)
|
||||||
ret += self.compile(v)
|
ret += self.compile(v)
|
||||||
defaults.append(ret.force_expr)
|
defaults.append(ret.force_expr)
|
||||||
@ -560,6 +564,10 @@ class HyASTCompiler(object):
|
|||||||
else:
|
else:
|
||||||
k = expr
|
k = expr
|
||||||
v = HySymbol("None").replace(k)
|
v = HySymbol("None").replace(k)
|
||||||
|
if not isinstance(k, HyString):
|
||||||
|
raise HyTypeError(expr,
|
||||||
|
"Only strings can be used as "
|
||||||
|
"parameter names")
|
||||||
args.append(k)
|
args.append(k)
|
||||||
ret += self.compile(v)
|
ret += self.compile(v)
|
||||||
defaults.append(ret.force_expr)
|
defaults.append(ret.force_expr)
|
||||||
@ -586,25 +594,26 @@ class HyASTCompiler(object):
|
|||||||
raise HyTypeError(expr,
|
raise HyTypeError(expr,
|
||||||
"There can only be one "
|
"There can only be one "
|
||||||
"&kwargs argument")
|
"&kwargs argument")
|
||||||
kwargs = str(expr)
|
kwargs = expr
|
||||||
|
|
||||||
return ret, args, defaults, varargs, kwonlyargs, kwonlydefaults, kwargs
|
return ret, args, defaults, varargs, kwonlyargs, kwonlydefaults, kwargs
|
||||||
|
|
||||||
def _storeize(self, name, func=None):
|
def _storeize(self, expr, name, func=None):
|
||||||
"""Return a new `name` object with an ast.Store() context"""
|
"""Return a new `name` object with an ast.Store() context"""
|
||||||
if not func:
|
if not func:
|
||||||
func = ast.Store
|
func = ast.Store
|
||||||
|
|
||||||
if isinstance(name, Result):
|
if isinstance(name, Result):
|
||||||
if not name.is_expr():
|
if not name.is_expr():
|
||||||
raise TypeError("Can't assign / delete a non-expression")
|
raise HyTypeError(expr,
|
||||||
|
"Can't assign or delete a non-expression")
|
||||||
name = name.expr
|
name = name.expr
|
||||||
|
|
||||||
if isinstance(name, (ast.Tuple, ast.List)):
|
if isinstance(name, (ast.Tuple, ast.List)):
|
||||||
typ = type(name)
|
typ = type(name)
|
||||||
new_elts = []
|
new_elts = []
|
||||||
for x in name.elts:
|
for x in name.elts:
|
||||||
new_elts.append(self._storeize(x, func))
|
new_elts.append(self._storeize(expr, x, func))
|
||||||
new_name = typ(elts=new_elts)
|
new_name = typ(elts=new_elts)
|
||||||
elif isinstance(name, ast.Name):
|
elif isinstance(name, ast.Name):
|
||||||
new_name = ast.Name(id=name.id, arg=name.arg)
|
new_name = ast.Name(id=name.id, arg=name.arg)
|
||||||
@ -613,7 +622,9 @@ class HyASTCompiler(object):
|
|||||||
elif isinstance(name, ast.Attribute):
|
elif isinstance(name, ast.Attribute):
|
||||||
new_name = ast.Attribute(value=name.value, attr=name.attr)
|
new_name = ast.Attribute(value=name.value, attr=name.attr)
|
||||||
else:
|
else:
|
||||||
raise TypeError("Can't assign / delete a %s object" % type(name))
|
raise HyTypeError(expr,
|
||||||
|
"Can't assign or delete a %s" %
|
||||||
|
type(expr).__name__)
|
||||||
|
|
||||||
new_name.ctx = func()
|
new_name.ctx = func()
|
||||||
ast.copy_location(new_name, name)
|
ast.copy_location(new_name, name)
|
||||||
@ -953,7 +964,7 @@ class HyASTCompiler(object):
|
|||||||
name = ast_str(name)
|
name = ast_str(name)
|
||||||
else:
|
else:
|
||||||
# Python2 requires an ast.Name, set to ctx Store.
|
# Python2 requires an ast.Name, set to ctx Store.
|
||||||
name = self._storeize(self.compile(name))
|
name = self._storeize(name, self.compile(name))
|
||||||
else:
|
else:
|
||||||
name = None
|
name = None
|
||||||
|
|
||||||
@ -971,7 +982,7 @@ class HyASTCompiler(object):
|
|||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
ctx=ast.Load())
|
ctx=ast.Load())
|
||||||
else:
|
else:
|
||||||
# [] → all exceptions catched
|
# [] → all exceptions caught
|
||||||
_type = Result()
|
_type = Result()
|
||||||
elif isinstance(exceptions_list, HySymbol):
|
elif isinstance(exceptions_list, HySymbol):
|
||||||
_type = self.compile(exceptions_list)
|
_type = self.compile(exceptions_list)
|
||||||
@ -1343,11 +1354,13 @@ class HyASTCompiler(object):
|
|||||||
col_offset=root.start_column)
|
col_offset=root.start_column)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
ld_targets, ret, _ = self._compile_collect(expr)
|
|
||||||
|
|
||||||
del_targets = []
|
del_targets = []
|
||||||
for target in ld_targets:
|
ret = Result()
|
||||||
del_targets.append(self._storeize(target, ast.Del))
|
for target in expr:
|
||||||
|
compiled_target = self.compile(target)
|
||||||
|
ret += compiled_target
|
||||||
|
del_targets.append(self._storeize(target, compiled_target,
|
||||||
|
ast.Del))
|
||||||
|
|
||||||
return ret + ast.Delete(
|
return ret + ast.Delete(
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
@ -1436,7 +1449,7 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
thing = None
|
thing = None
|
||||||
if args != []:
|
if args != []:
|
||||||
thing = self._storeize(self.compile(args.pop(0)))
|
thing = self._storeize(args[0], self.compile(args.pop(0)))
|
||||||
|
|
||||||
body = self._compile_branch(expr)
|
body = self._compile_branch(expr)
|
||||||
|
|
||||||
@ -1498,7 +1511,7 @@ class HyASTCompiler(object):
|
|||||||
gen = []
|
gen = []
|
||||||
for target, iterable in paired_gens:
|
for target, iterable in paired_gens:
|
||||||
comp_target = self.compile(target)
|
comp_target = self.compile(target)
|
||||||
target = self._storeize(comp_target)
|
target = self._storeize(target, comp_target)
|
||||||
gen_res += self.compile(iterable)
|
gen_res += self.compile(iterable)
|
||||||
gen.append(ast.comprehension(
|
gen.append(ast.comprehension(
|
||||||
target=target,
|
target=target,
|
||||||
@ -1963,7 +1976,7 @@ class HyASTCompiler(object):
|
|||||||
|
|
||||||
op = ops[expression[0]]
|
op = ops[expression[0]]
|
||||||
|
|
||||||
target = self._storeize(self.compile(expression[1]))
|
target = self._storeize(expression[1], self.compile(expression[1]))
|
||||||
ret = self.compile(expression[2])
|
ret = self.compile(expression[2])
|
||||||
|
|
||||||
ret += ast.AugAssign(
|
ret += ast.AugAssign(
|
||||||
@ -1984,7 +1997,7 @@ class HyASTCompiler(object):
|
|||||||
@builds(HyExpression)
|
@builds(HyExpression)
|
||||||
def compile_expression(self, expression):
|
def compile_expression(self, expression):
|
||||||
# Perform macro expansions
|
# Perform macro expansions
|
||||||
expression = macroexpand(expression, self.module_name)
|
expression = macroexpand(expression, self)
|
||||||
if not isinstance(expression, HyExpression):
|
if not isinstance(expression, HyExpression):
|
||||||
# Go through compile again if the type changed.
|
# Go through compile again if the type changed.
|
||||||
return self.compile(expression)
|
return self.compile(expression)
|
||||||
@ -2099,7 +2112,7 @@ class HyASTCompiler(object):
|
|||||||
and '.' not in name:
|
and '.' not in name:
|
||||||
result.rename(name)
|
result.rename(name)
|
||||||
else:
|
else:
|
||||||
st_name = self._storeize(ld_name)
|
st_name = self._storeize(name, ld_name)
|
||||||
result += ast.Assign(
|
result += ast.Assign(
|
||||||
lineno=start_line,
|
lineno=start_line,
|
||||||
col_offset=start_column,
|
col_offset=start_column,
|
||||||
@ -2127,7 +2140,7 @@ class HyASTCompiler(object):
|
|||||||
raise HyTypeError(expression,
|
raise HyTypeError(expression,
|
||||||
"for requires two forms in the list")
|
"for requires two forms in the list")
|
||||||
|
|
||||||
target = self._storeize(self.compile(target_name))
|
target = self._storeize(target_name, self.compile(target_name))
|
||||||
|
|
||||||
ret = Result()
|
ret = Result()
|
||||||
|
|
||||||
@ -2257,10 +2270,14 @@ class HyASTCompiler(object):
|
|||||||
# list because it's really just an internal parsing thing.
|
# list because it's really just an internal parsing thing.
|
||||||
|
|
||||||
if kwargs:
|
if kwargs:
|
||||||
kwargs = ast.arg(arg=kwargs, annotation=None)
|
kwargs = ast.arg(arg=ast_str(kwargs), annotation=None,
|
||||||
|
lineno=kwargs.start_line,
|
||||||
|
col_offset=kwargs.start_column)
|
||||||
|
|
||||||
if stararg:
|
if stararg:
|
||||||
stararg = ast.arg(arg=stararg, annotation=None)
|
stararg = ast.arg(arg=ast_str(stararg), annotation=None,
|
||||||
|
lineno=stararg.start_line,
|
||||||
|
col_offset=stararg.start_column)
|
||||||
|
|
||||||
# Let's find a better home for these guys.
|
# Let's find a better home for these guys.
|
||||||
else:
|
else:
|
||||||
@ -2275,6 +2292,12 @@ class HyASTCompiler(object):
|
|||||||
col_offset=x.start_column)
|
col_offset=x.start_column)
|
||||||
for x in kwonlyargs]
|
for x in kwonlyargs]
|
||||||
|
|
||||||
|
if kwargs:
|
||||||
|
kwargs = ast_str(kwargs)
|
||||||
|
|
||||||
|
if stararg:
|
||||||
|
stararg = ast_str(stararg)
|
||||||
|
|
||||||
args = ast.arguments(
|
args = ast.arguments(
|
||||||
args=args,
|
args=args,
|
||||||
vararg=stararg,
|
vararg=stararg,
|
||||||
@ -2294,7 +2317,10 @@ class HyASTCompiler(object):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
if body.expr:
|
if body.expr:
|
||||||
if body.contains_yield:
|
if body.contains_yield and not PY33:
|
||||||
|
# Prior to PEP 380 (introduced in Python 3.3)
|
||||||
|
# generators may not have a value in a return
|
||||||
|
# statement.
|
||||||
body += body.expr_as_stmt()
|
body += body.expr_as_stmt()
|
||||||
else:
|
else:
|
||||||
body += ast.Return(value=body.expr,
|
body += ast.Return(value=body.expr,
|
||||||
@ -2381,7 +2407,7 @@ class HyASTCompiler(object):
|
|||||||
body += self.compile(rewire_init(expr))
|
body += self.compile(rewire_init(expr))
|
||||||
|
|
||||||
for expression in expressions:
|
for expression in expressions:
|
||||||
expr = rewire_init(macroexpand(expression, self.module_name))
|
expr = rewire_init(macroexpand(expression, self))
|
||||||
body += self.compile(expr)
|
body += self.compile(expr)
|
||||||
|
|
||||||
self.allow_builtins = allow_builtins
|
self.allow_builtins = allow_builtins
|
||||||
@ -2441,7 +2467,7 @@ class HyASTCompiler(object):
|
|||||||
NOT_READERS = [":", "&"]
|
NOT_READERS = [":", "&"]
|
||||||
if name in NOT_READERS or len(name) > 1:
|
if name in NOT_READERS or len(name) > 1:
|
||||||
raise NameError("%s can't be used as a macro reader symbol" % name)
|
raise NameError("%s can't be used as a macro reader symbol" % name)
|
||||||
if not isinstance(name, HySymbol):
|
if not isinstance(name, HySymbol) and not isinstance(name, HyString):
|
||||||
raise HyTypeError(name,
|
raise HyTypeError(name,
|
||||||
("received a `%s' instead of a symbol "
|
("received a `%s' instead of a symbol "
|
||||||
"for reader macro name" % type(name).__name__))
|
"for reader macro name" % type(name).__name__))
|
||||||
@ -2467,10 +2493,7 @@ class HyASTCompiler(object):
|
|||||||
"Trying to expand a reader macro using `{0}' instead "
|
"Trying to expand a reader macro using `{0}' instead "
|
||||||
"of string".format(type(str_char).__name__),
|
"of string".format(type(str_char).__name__),
|
||||||
)
|
)
|
||||||
|
expr = reader_macroexpand(str_char, expression.pop(0), self)
|
||||||
module = self.module_name
|
|
||||||
expr = reader_macroexpand(str_char, expression.pop(0), module)
|
|
||||||
|
|
||||||
return self.compile(expr)
|
return self.compile(expr)
|
||||||
|
|
||||||
@builds("eval_and_compile")
|
@builds("eval_and_compile")
|
||||||
@ -2568,11 +2591,6 @@ def hy_compile(tree, module_name, root=ast.Module, get_expr=False):
|
|||||||
`last_expression` is the.
|
`last_expression` is the.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if hasattr(sys, "subversion"):
|
|
||||||
implementation = sys.subversion[0].lower()
|
|
||||||
elif hasattr(sys, "implementation"):
|
|
||||||
implementation = sys.implementation.name.lower()
|
|
||||||
|
|
||||||
body = []
|
body = []
|
||||||
expr = None
|
expr = None
|
||||||
|
|
||||||
@ -2592,12 +2610,6 @@ def hy_compile(tree, module_name, root=ast.Module, get_expr=False):
|
|||||||
|
|
||||||
ret = root(body=body)
|
ret = root(body=body)
|
||||||
|
|
||||||
# PyPy _really_ doesn't like the ast going backwards...
|
|
||||||
if implementation != "cpython":
|
|
||||||
for node in ast.walk(ret):
|
|
||||||
node.lineno = 1
|
|
||||||
node.col_offset = 1
|
|
||||||
|
|
||||||
if get_expr:
|
if get_expr:
|
||||||
expr = ast.Expression(body=expr)
|
expr = ast.Expression(body=expr)
|
||||||
ret = (ret, expr)
|
ret = (ret, expr)
|
||||||
|
@ -25,8 +25,9 @@
|
|||||||
;;; These macros make writing functional programs more concise
|
;;; These macros make writing functional programs more concise
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-if (test-form &rest args)
|
(defmacro ap-if [test-form then-form &optional else-form]
|
||||||
`(let [it ~test-form] (if it ~@args)))
|
`(let [it ~test-form]
|
||||||
|
(if it ~then-form ~else-form)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-each [lst &rest body]
|
(defmacro ap-each [lst &rest body]
|
||||||
@ -35,7 +36,7 @@
|
|||||||
|
|
||||||
|
|
||||||
(defmacro ap-each-while [lst form &rest body]
|
(defmacro ap-each-while [lst form &rest body]
|
||||||
"Evalutate the body form for each element in the list while the
|
"Evaluate the body form for each element in the list while the
|
||||||
predicate form evaluates to True."
|
predicate form evaluates to True."
|
||||||
`(let [p (lambda [it] ~form)]
|
`(let [p (lambda [it] ~form)]
|
||||||
(for [it ~lst]
|
(for [it ~lst]
|
||||||
@ -140,7 +141,7 @@
|
|||||||
(.startswith a 'x)
|
(.startswith a 'x)
|
||||||
(.isdigit (cdr a))))
|
(.isdigit (cdr a))))
|
||||||
[0]))))])
|
[0]))))])
|
||||||
;; generate the &rest paremeter only if 'xi is present in body
|
;; generate the &rest parameter only if 'xi is present in body
|
||||||
~@(if (in 'xi flatbody)
|
~@(if (in 'xi flatbody)
|
||||||
'(&rest xi)
|
'(&rest xi)
|
||||||
'())]
|
'())]
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
[hy.models.symbol [HySymbol]]
|
[hy.models.symbol [HySymbol]]
|
||||||
[hy.models.keyword [HyKeyword *keyword-prefix*]])
|
[hy.models.keyword [HyKeyword *keyword-prefix*]])
|
||||||
(import [hy.lex [LexException PrematureEndOfInput tokenize]])
|
(import [hy.lex [LexException PrematureEndOfInput tokenize]])
|
||||||
|
(import [hy.compiler [HyASTCompiler]])
|
||||||
|
|
||||||
(defn _numeric-check [x]
|
(defn _numeric-check [x]
|
||||||
(if (not (numeric? x))
|
(if (not (numeric? x))
|
||||||
@ -296,14 +297,14 @@
|
|||||||
(import hy.macros)
|
(import hy.macros)
|
||||||
|
|
||||||
(setv name (calling-module-name))
|
(setv name (calling-module-name))
|
||||||
(hy.macros.macroexpand form name))
|
(hy.macros.macroexpand form (HyASTCompiler name)))
|
||||||
|
|
||||||
(defn macroexpand-1 [form]
|
(defn macroexpand-1 [form]
|
||||||
"Return the single step macro expansion of form"
|
"Return the single step macro expansion of form"
|
||||||
(import hy.macros)
|
(import hy.macros)
|
||||||
|
|
||||||
(setv name (calling-module-name))
|
(setv name (calling-module-name))
|
||||||
(hy.macros.macroexpand-1 form name))
|
(hy.macros.macroexpand-1 form (HyASTCompiler name)))
|
||||||
|
|
||||||
(defn merge-with [f &rest maps]
|
(defn merge-with [f &rest maps]
|
||||||
"Returns a map that consists of the rest of the maps joined onto
|
"Returns a map that consists of the rest of the maps joined onto
|
||||||
@ -463,6 +464,11 @@
|
|||||||
(hyify (. value __name__))
|
(hyify (. value __name__))
|
||||||
(except [] (string value))))))
|
(except [] (string value))))))
|
||||||
|
|
||||||
|
(defn xor [a b]
|
||||||
|
"Perform exclusive or between two parameters"
|
||||||
|
(or (and a (not b))
|
||||||
|
(and b (not a))))
|
||||||
|
|
||||||
(def *exports*
|
(def *exports*
|
||||||
'[*map accumulate butlast calling-module-name chain coll? combinations
|
'[*map accumulate butlast calling-module-name chain coll? combinations
|
||||||
compress cons cons? count cycle dec distinct disassemble drop drop-last
|
compress cons cons? count cycle dec distinct disassemble drop drop-last
|
||||||
@ -472,4 +478,4 @@
|
|||||||
last list* macroexpand macroexpand-1 map merge-with multicombinations name
|
last list* macroexpand macroexpand-1 map merge-with multicombinations name
|
||||||
neg? nil? none? nth numeric? odd? partition permutations pos? product range
|
neg? nil? none? nth numeric? odd? partition permutations pos? product range
|
||||||
read read-str remove repeat repeatedly rest reduce second some string
|
read read-str remove repeat repeatedly rest reduce second some string
|
||||||
string? symbol? take take-nth take-while tee zero? zip zip-longest])
|
string? symbol? take take-nth take-while xor tee zero? zip zip-longest])
|
||||||
|
@ -25,8 +25,6 @@ import traceback
|
|||||||
|
|
||||||
from clint.textui import colored
|
from clint.textui import colored
|
||||||
|
|
||||||
from hy._compat import PY3
|
|
||||||
|
|
||||||
|
|
||||||
class HyError(Exception):
|
class HyError(Exception):
|
||||||
"""
|
"""
|
||||||
@ -101,11 +99,8 @@ class HyTypeError(TypeError):
|
|||||||
|
|
||||||
result += colored.yellow("%s: %s\n\n" %
|
result += colored.yellow("%s: %s\n\n" %
|
||||||
(self.__class__.__name__,
|
(self.__class__.__name__,
|
||||||
self.message))
|
self.message.encode('utf-8')))
|
||||||
|
|
||||||
if not PY3:
|
|
||||||
return result.encode('utf-8')
|
|
||||||
else:
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
34
hy/macros.py
34
hy/macros.py
@ -52,6 +52,8 @@ def macro(name):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
def _(fn):
|
def _(fn):
|
||||||
|
argspec = getargspec(fn)
|
||||||
|
fn._hy_macro_pass_compiler = argspec.keywords is not None
|
||||||
module_name = fn.__module__
|
module_name = fn.__module__
|
||||||
if module_name.startswith("hy.core"):
|
if module_name.startswith("hy.core"):
|
||||||
module_name = None
|
module_name = None
|
||||||
@ -123,7 +125,7 @@ def load_macros(module_name):
|
|||||||
_import(module)
|
_import(module)
|
||||||
|
|
||||||
|
|
||||||
def make_emtpy_fn_copy(fn):
|
def make_empty_fn_copy(fn):
|
||||||
argspec = getargspec(fn)
|
argspec = getargspec(fn)
|
||||||
formatted_args = formatargspec(*argspec)
|
formatted_args = formatargspec(*argspec)
|
||||||
fn_str = 'lambda {}: None'.format(
|
fn_str = 'lambda {}: None'.format(
|
||||||
@ -133,22 +135,22 @@ def make_emtpy_fn_copy(fn):
|
|||||||
return empty_fn
|
return empty_fn
|
||||||
|
|
||||||
|
|
||||||
def macroexpand(tree, module_name):
|
def macroexpand(tree, compiler):
|
||||||
"""Expand the toplevel macros for the `tree`.
|
"""Expand the toplevel macros for the `tree`.
|
||||||
|
|
||||||
Load the macros from the given `module_name`, then expand the (top-level)
|
Load the macros from the given `module_name`, then expand the (top-level)
|
||||||
macros in `tree` until it stops changing.
|
macros in `tree` until it stops changing.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
load_macros(module_name)
|
load_macros(compiler.module_name)
|
||||||
old = None
|
old = None
|
||||||
while old != tree:
|
while old != tree:
|
||||||
old = tree
|
old = tree
|
||||||
tree = macroexpand_1(tree, module_name)
|
tree = macroexpand_1(tree, compiler)
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
|
|
||||||
def macroexpand_1(tree, module_name):
|
def macroexpand_1(tree, compiler):
|
||||||
"""Expand the toplevel macro from `tree` once, in the context of
|
"""Expand the toplevel macro from `tree` once, in the context of
|
||||||
`module_name`."""
|
`module_name`."""
|
||||||
if isinstance(tree, HyExpression):
|
if isinstance(tree, HyExpression):
|
||||||
@ -161,22 +163,25 @@ def macroexpand_1(tree, module_name):
|
|||||||
ntree = HyExpression(tree[:])
|
ntree = HyExpression(tree[:])
|
||||||
ntree.replace(tree)
|
ntree.replace(tree)
|
||||||
|
|
||||||
|
opts = {}
|
||||||
|
|
||||||
if isinstance(fn, HyString):
|
if isinstance(fn, HyString):
|
||||||
m = _hy_macros[module_name].get(fn)
|
m = _hy_macros[compiler.module_name].get(fn)
|
||||||
if m is None:
|
if m is None:
|
||||||
m = _hy_macros[None].get(fn)
|
m = _hy_macros[None].get(fn)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
|
if m._hy_macro_pass_compiler:
|
||||||
|
opts['compiler'] = compiler
|
||||||
|
|
||||||
try:
|
try:
|
||||||
m_copy = make_emtpy_fn_copy(m)
|
m_copy = make_empty_fn_copy(m)
|
||||||
m_copy(*ntree[1:])
|
m_copy(*ntree[1:], **opts)
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
msg = "expanding `" + str(tree[0]) + "': "
|
msg = "expanding `" + str(tree[0]) + "': "
|
||||||
msg += str(e).replace("<lambda>()", "", 1).strip()
|
msg += str(e).replace("<lambda>()", "", 1).strip()
|
||||||
raise HyMacroExpansionError(tree, msg)
|
raise HyMacroExpansionError(tree, msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
obj = wrap_value(m(*ntree[1:]))
|
obj = wrap_value(m(*ntree[1:], **opts))
|
||||||
|
|
||||||
except HyTypeError as e:
|
except HyTypeError as e:
|
||||||
if e.expression is None:
|
if e.expression is None:
|
||||||
e.expression = tree
|
e.expression = tree
|
||||||
@ -186,16 +191,15 @@ def macroexpand_1(tree, module_name):
|
|||||||
raise HyMacroExpansionError(tree, msg)
|
raise HyMacroExpansionError(tree, msg)
|
||||||
replace_hy_obj(obj, tree)
|
replace_hy_obj(obj, tree)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
return ntree
|
return ntree
|
||||||
return tree
|
return tree
|
||||||
|
|
||||||
|
|
||||||
def reader_macroexpand(char, tree, module_name):
|
def reader_macroexpand(char, tree, compiler):
|
||||||
"""Expand the reader macro "char" with argument `tree`."""
|
"""Expand the reader macro "char" with argument `tree`."""
|
||||||
load_macros(module_name)
|
load_macros(compiler.module_name)
|
||||||
|
|
||||||
reader_macro = _hy_reader[module_name].get(char)
|
reader_macro = _hy_reader[compiler.module_name].get(char)
|
||||||
if reader_macro is None:
|
if reader_macro is None:
|
||||||
try:
|
try:
|
||||||
reader_macro = _hy_reader[None][char]
|
reader_macro = _hy_reader[None][char]
|
||||||
|
3
setup.py
3
setup.py
@ -50,7 +50,7 @@ if sys.version_info[:2] < (2, 7):
|
|||||||
install_requires.append('argparse>=1.2.1')
|
install_requires.append('argparse>=1.2.1')
|
||||||
install_requires.append('importlib>=1.0.2')
|
install_requires.append('importlib>=1.0.2')
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
install_requires.append('pyreadline==2.0')
|
install_requires.append('pyreadline>=2.1')
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name=PKG,
|
name=PKG,
|
||||||
@ -89,6 +89,7 @@ setup(
|
|||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.3",
|
"Programming Language :: Python :: 3.3",
|
||||||
"Programming Language :: Python :: 3.4",
|
"Programming Language :: Python :: 3.4",
|
||||||
|
"Programming Language :: Python :: 3.5",
|
||||||
"Topic :: Software Development :: Code Generators",
|
"Topic :: Software Development :: Code Generators",
|
||||||
"Topic :: Software Development :: Compilers",
|
"Topic :: Software Development :: Compilers",
|
||||||
"Topic :: Software Development :: Libraries",
|
"Topic :: Software Development :: Libraries",
|
||||||
|
@ -372,6 +372,7 @@ def test_ast_lambda_lists():
|
|||||||
cant_compile('(fn [&key {"a" b} &key {"foo" bar}] [a foo])')
|
cant_compile('(fn [&key {"a" b} &key {"foo" bar}] [a foo])')
|
||||||
cant_compile('(fn [&optional a &key {"foo" bar}] [a foo])')
|
cant_compile('(fn [&optional a &key {"foo" bar}] [a foo])')
|
||||||
cant_compile('(fn [&optional [a b c]] a)')
|
cant_compile('(fn [&optional [a b c]] a)')
|
||||||
|
cant_compile('(fn [&optional [1 2]] (list 1 2))')
|
||||||
|
|
||||||
|
|
||||||
def test_ast_print():
|
def test_ast_print():
|
||||||
@ -402,6 +403,7 @@ def test_lambda_list_keywords_key():
|
|||||||
""" Ensure we can compile functions with &key."""
|
""" Ensure we can compile functions with &key."""
|
||||||
can_compile("(fn (x &key {foo True}) (list x foo))")
|
can_compile("(fn (x &key {foo True}) (list x foo))")
|
||||||
cant_compile("(fn (x &key {bar \"baz\"} &key {foo 42}) (list x bar foo))")
|
cant_compile("(fn (x &key {bar \"baz\"} &key {foo 42}) (list x bar foo))")
|
||||||
|
cant_compile("(fn (x &key {1 2 3 4}) (list x))")
|
||||||
|
|
||||||
|
|
||||||
def test_lambda_list_keywords_kwargs():
|
def test_lambda_list_keywords_kwargs():
|
||||||
|
@ -26,6 +26,8 @@ from hy import compiler
|
|||||||
from hy.models.expression import HyExpression
|
from hy.models.expression import HyExpression
|
||||||
from hy.models.list import HyList
|
from hy.models.list import HyList
|
||||||
from hy.models.symbol import HySymbol
|
from hy.models.symbol import HySymbol
|
||||||
|
from hy.models.integer import HyInteger
|
||||||
|
from hy._compat import PY33
|
||||||
|
|
||||||
if sys.version_info[0] <= 2 and sys.version_info[1] <= 6:
|
if sys.version_info[0] <= 2 and sys.version_info[1] <= 6:
|
||||||
import unittest2 as unittest
|
import unittest2 as unittest
|
||||||
@ -98,3 +100,37 @@ class HyASTCompilerTest(unittest.TestCase):
|
|||||||
expr = ret.expr
|
expr = ret.expr
|
||||||
self.assertIsInstance(expr, ast.Name)
|
self.assertIsInstance(expr, ast.Name)
|
||||||
self.assertEqual(expr.id, "c")
|
self.assertEqual(expr.id, "c")
|
||||||
|
|
||||||
|
def test_compiler_yield_return(self):
|
||||||
|
"""
|
||||||
|
Check that the compiler correctly generates return statements for
|
||||||
|
a generator function. In Python versions prior to 3.3, the return
|
||||||
|
statement in a generator can't take a value, so the final expression
|
||||||
|
should not generate a return statement. From 3.3 onwards a return
|
||||||
|
value should be generated.
|
||||||
|
"""
|
||||||
|
ret = self.c.compile_function_def(
|
||||||
|
self._make_expression(HySymbol("fn"),
|
||||||
|
HyList(),
|
||||||
|
HyExpression([HySymbol("yield"),
|
||||||
|
HyInteger(2)]),
|
||||||
|
HyExpression([HySymbol("+"),
|
||||||
|
HyInteger(1),
|
||||||
|
HyInteger(1)])))
|
||||||
|
|
||||||
|
self.assertEqual(len(ret.stmts), 1)
|
||||||
|
stmt = ret.stmts[0]
|
||||||
|
self.assertIsInstance(stmt, ast.FunctionDef)
|
||||||
|
body = stmt.body
|
||||||
|
self.assertEquals(len(body), 2)
|
||||||
|
self.assertIsInstance(body[0], ast.Expr)
|
||||||
|
self.assertIsInstance(body[0].value, ast.Yield)
|
||||||
|
|
||||||
|
if PY33:
|
||||||
|
# From 3.3+, the final statement becomes a return value
|
||||||
|
self.assertIsInstance(body[1], ast.Return)
|
||||||
|
self.assertIsInstance(body[1].value, ast.BinOp)
|
||||||
|
else:
|
||||||
|
# In earlier versions, the expression is not returned
|
||||||
|
self.assertIsInstance(body[1], ast.Expr)
|
||||||
|
self.assertIsInstance(body[1].value, ast.BinOp)
|
||||||
|
@ -8,6 +8,8 @@ from hy.models.symbol import HySymbol
|
|||||||
from hy.models.expression import HyExpression
|
from hy.models.expression import HyExpression
|
||||||
from hy.errors import HyMacroExpansionError
|
from hy.errors import HyMacroExpansionError
|
||||||
|
|
||||||
|
from hy.compiler import HyASTCompiler
|
||||||
|
|
||||||
|
|
||||||
@macro("test")
|
@macro("test")
|
||||||
def tmac(*tree):
|
def tmac(*tree):
|
||||||
@ -17,14 +19,16 @@ def tmac(*tree):
|
|||||||
|
|
||||||
def test_preprocessor_simple():
|
def test_preprocessor_simple():
|
||||||
""" Test basic macro expansion """
|
""" Test basic macro expansion """
|
||||||
obj = macroexpand(tokenize('(test "one" "two")')[0], __name__)
|
obj = macroexpand(tokenize('(test "one" "two")')[0],
|
||||||
|
HyASTCompiler(__name__))
|
||||||
assert obj == HyList(["one", "two"])
|
assert obj == HyList(["one", "two"])
|
||||||
assert type(obj) == HyList
|
assert type(obj) == HyList
|
||||||
|
|
||||||
|
|
||||||
def test_preprocessor_expression():
|
def test_preprocessor_expression():
|
||||||
""" Test that macro expansion doesn't recurse"""
|
""" Test that macro expansion doesn't recurse"""
|
||||||
obj = macroexpand(tokenize('(test (test "one" "two"))')[0], __name__)
|
obj = macroexpand(tokenize('(test (test "one" "two"))')[0],
|
||||||
|
HyASTCompiler(__name__))
|
||||||
|
|
||||||
assert type(obj) == HyList
|
assert type(obj) == HyList
|
||||||
assert type(obj[0]) == HyExpression
|
assert type(obj[0]) == HyExpression
|
||||||
@ -35,13 +39,13 @@ def test_preprocessor_expression():
|
|||||||
|
|
||||||
obj = HyList([HyString("one"), HyString("two")])
|
obj = HyList([HyString("one"), HyString("two")])
|
||||||
obj = tokenize('(shill ["one" "two"])')[0][1]
|
obj = tokenize('(shill ["one" "two"])')[0][1]
|
||||||
assert obj == macroexpand(obj, '')
|
assert obj == macroexpand(obj, HyASTCompiler(""))
|
||||||
|
|
||||||
|
|
||||||
def test_preprocessor_exceptions():
|
def test_preprocessor_exceptions():
|
||||||
""" Test that macro expansion raises appropriate exceptions"""
|
""" Test that macro expansion raises appropriate exceptions"""
|
||||||
try:
|
try:
|
||||||
macroexpand(tokenize('(defn)')[0], __name__)
|
macroexpand(tokenize('(defn)')[0], HyASTCompiler(__name__))
|
||||||
assert False
|
assert False
|
||||||
except HyMacroExpansionError as e:
|
except HyMacroExpansionError as e:
|
||||||
assert "_hy_anon_fn_" not in str(e)
|
assert "_hy_anon_fn_" not in str(e)
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
from hy.macros import macroexpand
|
from hy.macros import macroexpand
|
||||||
from hy.compiler import HyTypeError
|
from hy.compiler import HyTypeError, HyASTCompiler
|
||||||
from hy.lex import tokenize
|
from hy.lex import tokenize
|
||||||
|
|
||||||
|
|
||||||
def test_reader_macro_error():
|
def test_reader_macro_error():
|
||||||
"""Check if we get correct error with wrong disptach character"""
|
"""Check if we get correct error with wrong dispatch character"""
|
||||||
try:
|
try:
|
||||||
macroexpand(tokenize("(dispatch_reader_macro '- '())")[0], __name__)
|
macroexpand(tokenize("(dispatch_reader_macro '- '())")[0],
|
||||||
|
HyASTCompiler(__name__))
|
||||||
except HyTypeError as e:
|
except HyTypeError as e:
|
||||||
assert "with the character `-`" in str(e)
|
assert "with the character `-`" in str(e)
|
||||||
|
@ -18,10 +18,11 @@
|
|||||||
;; 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.
|
||||||
|
|
||||||
;;;; some simple helpers
|
(import [hy.errors [HyMacroExpansionError]])
|
||||||
|
|
||||||
(require hy.contrib.anaphoric)
|
(require hy.contrib.anaphoric)
|
||||||
|
|
||||||
|
;;;; some simple helpers
|
||||||
|
|
||||||
(defn assert-true [x]
|
(defn assert-true [x]
|
||||||
(assert (= True x)))
|
(assert (= True x)))
|
||||||
|
|
||||||
@ -35,7 +36,10 @@
|
|||||||
(defn test-ap-if []
|
(defn test-ap-if []
|
||||||
"NATIVE: testing anaphoric if"
|
"NATIVE: testing anaphoric if"
|
||||||
(ap-if true (assert-true it))
|
(ap-if true (assert-true it))
|
||||||
(ap-if false true (assert-false it)))
|
(ap-if false true (assert-false it))
|
||||||
|
(try (macroexpand '(ap-if true))
|
||||||
|
(except [HyMacroExpansionError] true)
|
||||||
|
(else (assert false))))
|
||||||
|
|
||||||
(defn test-ap-each []
|
(defn test-ap-each []
|
||||||
"NATIVE: testing anaphoric each"
|
"NATIVE: testing anaphoric each"
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
(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_]])
|
[operator [or_]]
|
||||||
|
[hy.errors [HyTypeError]])
|
||||||
(import sys)
|
(import sys)
|
||||||
|
|
||||||
(import [hy._compat [PY33 PY34 PY35]])
|
(import [hy._compat [PY33 PY34 PY35]])
|
||||||
@ -60,6 +61,7 @@
|
|||||||
(setv (get foo 0) 12)
|
(setv (get foo 0) 12)
|
||||||
(assert (= (get foo 0) 12)))
|
(assert (= (get foo 0) 12)))
|
||||||
|
|
||||||
|
|
||||||
(defn test-setv-builtin []
|
(defn test-setv-builtin []
|
||||||
"NATIVE: test that setv doesn't work on builtins"
|
"NATIVE: test that setv doesn't work on builtins"
|
||||||
(try (eval '(setv False 1))
|
(try (eval '(setv False 1))
|
||||||
@ -93,6 +95,37 @@
|
|||||||
(except [e [TypeError]] (assert (in "`setv' needs an even number of arguments" (str e))))))
|
(except [e [TypeError]] (assert (in "`setv' needs an even number of arguments" (str e))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-store-errors []
|
||||||
|
"NATIVE: test that setv raises the correct errors when given wrong argument types"
|
||||||
|
(try
|
||||||
|
(do
|
||||||
|
(eval '(setv (do 1 2) 1))
|
||||||
|
(assert false))
|
||||||
|
(except [e HyTypeError]
|
||||||
|
(assert (= e.message "Can't assign or delete a non-expression"))))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(do
|
||||||
|
(eval '(setv 1 1))
|
||||||
|
(assert false))
|
||||||
|
(except [e HyTypeError]
|
||||||
|
(assert (= e.message "Can't assign or delete a HyInteger"))))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(do
|
||||||
|
(eval '(setv {1 2} 1))
|
||||||
|
(assert false))
|
||||||
|
(except [e HyTypeError]
|
||||||
|
(assert (= e.message "Can't assign or delete a HyDict"))))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(do
|
||||||
|
(eval '(del 1 1))
|
||||||
|
(assert false))
|
||||||
|
(except [e HyTypeError]
|
||||||
|
(assert (= e.message "Can't assign or delete a HyInteger")))))
|
||||||
|
|
||||||
|
|
||||||
(defn test-fn-corner-cases []
|
(defn test-fn-corner-cases []
|
||||||
"NATIVE: tests that fn/defn handles corner cases gracefully"
|
"NATIVE: tests that fn/defn handles corner cases gracefully"
|
||||||
(try (eval '(fn "foo"))
|
(try (eval '(fn "foo"))
|
||||||
@ -894,6 +927,15 @@
|
|||||||
(assert (= a 1)))
|
(assert (= a 1)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-xor []
|
||||||
|
"NATIVE: test the xor macro"
|
||||||
|
(let [xor-both-true (xor true true)
|
||||||
|
xor-both-false (xor false false)
|
||||||
|
xor-true-false (xor true false)]
|
||||||
|
(assert (= xor-both-true false))
|
||||||
|
(assert (= xor-both-false false))
|
||||||
|
(assert (= xor-true-false true))))
|
||||||
|
|
||||||
(defn test-if-return-branching []
|
(defn test-if-return-branching []
|
||||||
"NATIVE: test the if return branching"
|
"NATIVE: test the if return branching"
|
||||||
; thanks, algernon
|
; thanks, algernon
|
||||||
@ -965,7 +1007,6 @@
|
|||||||
|
|
||||||
(defn test-eval-failure []
|
(defn test-eval-failure []
|
||||||
"NATIVE: test eval failure modes"
|
"NATIVE: test eval failure modes"
|
||||||
(import [hy.errors [HyTypeError]])
|
|
||||||
; yo dawg
|
; yo dawg
|
||||||
(try (eval '(eval)) (except [e HyTypeError]) (else (assert False)))
|
(try (eval '(eval)) (except [e HyTypeError]) (else (assert False)))
|
||||||
(try (eval '(eval "snafu")) (except [e HyTypeError]) (else (assert False)))
|
(try (eval '(eval "snafu")) (except [e HyTypeError]) (else (assert False)))
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
|
|
||||||
(defn test-reader-macro []
|
(defn test-reader-macro []
|
||||||
"Test a basic redaer macro"
|
"Test a basic reader macro"
|
||||||
(defreader ^ [expr]
|
(defreader ^ [expr]
|
||||||
expr)
|
expr)
|
||||||
|
|
||||||
@ -37,6 +37,15 @@
|
|||||||
(assert (= (, 1 2 3) a)))
|
(assert (= (, 1 2 3) a)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-reader-macro-string-name []
|
||||||
|
"Test if defreader accepts a string as a macro name."
|
||||||
|
|
||||||
|
(defreader "." [expr]
|
||||||
|
expr)
|
||||||
|
|
||||||
|
(assert (= #."works" "works")))
|
||||||
|
|
||||||
|
|
||||||
(defn test-builtin-decorator-reader []
|
(defn test-builtin-decorator-reader []
|
||||||
(defn increment-arguments [func]
|
(defn increment-arguments [func]
|
||||||
"Increments each argument passed to the decorated function."
|
"Increments each argument passed to the decorated function."
|
||||||
@ -55,7 +64,7 @@
|
|||||||
(assert (= (, (, 2 3 4) {"quux" 5 "baz" 6})
|
(assert (= (, (, 2 3 4) {"quux" 5 "baz" 6})
|
||||||
(foo 1 2 3 :quux 4 :baz 5)))
|
(foo 1 2 3 :quux 4 :baz 5)))
|
||||||
|
|
||||||
;; @wraps preserved the doctstring and __name__
|
;; @wraps preserved the docstring and __name__
|
||||||
(assert (= "foo" (. foo --name--)))
|
(assert (= "foo" (. foo --name--)))
|
||||||
(assert (= "Bar." (. foo --doc--)))
|
(assert (= "Bar." (. foo --doc--)))
|
||||||
|
|
||||||
|
4
tox.ini
4
tox.ini
@ -1,11 +1,13 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py27,pypy,py33,flake8
|
envlist = py27,pypy,py33,py34,py35,flake8
|
||||||
skipsdist = True
|
skipsdist = True
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
commands =
|
commands =
|
||||||
pip install --allow-all-external -e .
|
pip install --allow-all-external -e .
|
||||||
nosetests
|
nosetests
|
||||||
|
passenv =
|
||||||
|
TERM
|
||||||
deps =
|
deps =
|
||||||
-rrequirements-dev.txt
|
-rrequirements-dev.txt
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user