Merge branch 'master' into multimethod
Conflicts: docs/contrib/multi.rst
This commit is contained in:
commit
77bc767907
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
/hy/version.py
|
||||||
*.pyc
|
*.pyc
|
||||||
*swp
|
*swp
|
||||||
*hy*egg*
|
*hy*egg*
|
||||||
|
@ -4,6 +4,8 @@ matrix:
|
|||||||
include:
|
include:
|
||||||
- python: 3.5
|
- python: 3.5
|
||||||
env: TOXENV=py35
|
env: TOXENV=py35
|
||||||
|
- python: 3.6-dev
|
||||||
|
env: TOXENV=py36
|
||||||
env:
|
env:
|
||||||
- TOXENV=py27
|
- TOXENV=py27
|
||||||
- TOXENV=py33
|
- TOXENV=py33
|
||||||
|
1
AUTHORS
1
AUTHORS
@ -69,3 +69,4 @@
|
|||||||
* Andrew Savchyn <dev@scorpil.com>
|
* Andrew Savchyn <dev@scorpil.com>
|
||||||
* Lev Kravinsky <kravinskylev@gmail.com>
|
* Lev Kravinsky <kravinskylev@gmail.com>
|
||||||
* Luna Lunapiena <lunacodes@gmail.com>
|
* Luna Lunapiena <lunacodes@gmail.com>
|
||||||
|
* Jakub Wilk <jwilk@jwilk.net>
|
||||||
|
@ -7,7 +7,9 @@ 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 would like to
|
||||||
|
contribute but don't know how to begin, the `good-first-bug`_ label
|
||||||
|
of the `issue tracker`_ is the place to go.
|
||||||
(If you're new to Git: `Start Here`_)
|
(If you're new to Git: `Start Here`_)
|
||||||
|
|
||||||
- All incoming features should be accompanied with tests.
|
- All incoming features should be accompanied with tests.
|
||||||
@ -36,7 +38,7 @@ Pull requests are great! We love them; here is a quick guide:
|
|||||||
+ Try sticking to the 50 character limit for the first line of Git
|
+ Try sticking to the 50 character limit for the first line of Git
|
||||||
commit messages.
|
commit messages.
|
||||||
|
|
||||||
+ For more detail/explainations, follow this up with a blank line and
|
+ For more detail/explanations, follow this up with a blank line and
|
||||||
continue describing the commit in detail.
|
continue describing the commit in detail.
|
||||||
|
|
||||||
- Finally, add yourself to the AUTHORS file (as a separate commit): you
|
- Finally, add yourself to the AUTHORS file (as a separate commit): you
|
||||||
@ -93,4 +95,5 @@ 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
|
.. _issue tracker: https://github.com/hylang/hy/issues
|
||||||
.. _Fork the Repo: https://help.github.com/articles/fork-a-repo/
|
.. _Fork the Repo: https://help.github.com/articles/fork-a-repo/
|
||||||
.. _Start Here: http://rogerdudler.github.io/git-guide/)
|
.. _Start Here: http://rogerdudler.github.io/git-guide/
|
||||||
|
.. _good-first-bug: http://github.com/hylang/hy/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-bug
|
||||||
|
6
Makefile
6
Makefile
@ -23,7 +23,7 @@ all:
|
|||||||
@echo ""
|
@echo ""
|
||||||
|
|
||||||
docs:
|
docs:
|
||||||
make -C docs html
|
$(MAKE) -C docs html
|
||||||
|
|
||||||
upload: r
|
upload: r
|
||||||
python setup.py sdist upload
|
python setup.py sdist upload
|
||||||
@ -72,10 +72,10 @@ coveralls:
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
@find . -name "*.pyc" -exec rm {} \;
|
@find . -name "*.pyc" -exec rm {} \;
|
||||||
@find -name __pycache__ -delete
|
@find . -name __pycache__ -delete
|
||||||
@${RM} -r -f .tox
|
@${RM} -r -f .tox
|
||||||
@${RM} -r -f dist
|
@${RM} -r -f dist
|
||||||
@${RM} -r -f *.egg-info
|
@${RM} -r -f *.egg-info
|
||||||
@${RM} -r -f docs/_build
|
@${RM} -r -f docs/_build
|
||||||
|
|
||||||
.PHONY: docs
|
.PHONY: all docs upload full venv dev test tox flake clear d diff r python coveralls clean
|
||||||
|
2
NEWS
2
NEWS
@ -280,7 +280,7 @@ Changes from Hy 0.9.10
|
|||||||
* Clarified rest / cdr, cleaned up require
|
* Clarified rest / cdr, cleaned up require
|
||||||
* Make with return the last expression from its branch
|
* Make with return the last expression from its branch
|
||||||
* Fix yielding to not suck (#151)
|
* Fix yielding to not suck (#151)
|
||||||
* Make assoc accept multiple values, also added a even/odd check for
|
* Make assoc accept multiple values, also added an even/odd check for
|
||||||
checkargs
|
checkargs
|
||||||
* Added ability to parse doc strings set in defclass declarations,
|
* Added ability to parse doc strings set in defclass declarations,
|
||||||
* Provide bin scripts for both Windows and *nix
|
* Provide bin scripts for both Windows and *nix
|
||||||
|
@ -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)](https://xkcd.com/224/)
|
<a href="https://xkcd.com/224/"><img title="We lost the documentation on quantum mechanics. You'll have to decode the regexes yourself." alt="XKCD #224" src="https://raw.github.com/hylang/shyte/18f6925e08684b0e1f52b2cc2c803989cd62cd91/imgs/xkcd.png"></a>
|
||||||
|
|
||||||
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/).
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@ concise and easy to read.
|
|||||||
deliberately captures some form supplied to the macro which may be
|
deliberately captures some form supplied to the macro which may be
|
||||||
referred to by an anaphor (an expression referring to another).
|
referred to by an anaphor (an expression referring to another).
|
||||||
|
|
||||||
-- Wikipedia (http://en.wikipedia.org/wiki/Anaphoric_macro)
|
-- Wikipedia (https://en.wikipedia.org/wiki/Anaphoric_macro)
|
||||||
|
|
||||||
To use these macros you need to require the hy.contrib.anaphoric module like so:
|
To use these macros you need to require the hy.contrib.anaphoric module like so:
|
||||||
|
|
||||||
``(require hy.contrib.anaphoric)``
|
``(require [hy.contrib.anaphoric [*]])``
|
||||||
|
|
||||||
.. _ap-if:
|
.. _ap-if:
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ Example:
|
|||||||
|
|
||||||
.. code-block:: hy
|
.. code-block:: hy
|
||||||
|
|
||||||
(require hy.contrib.flow)
|
(require [hy.contrib.flow [case]])
|
||||||
|
|
||||||
(defn temp-commenter [temp]
|
(defn temp-commenter [temp]
|
||||||
(case temp
|
(case temp
|
||||||
@ -48,7 +48,7 @@ Example:
|
|||||||
|
|
||||||
.. code-block:: hy
|
.. code-block:: hy
|
||||||
|
|
||||||
(require hy.contrib.flow)
|
(require [hy.contrib.flow [switch]])
|
||||||
|
|
||||||
(defn temp-commenter [temp]
|
(defn temp-commenter [temp]
|
||||||
(switch temp
|
(switch temp
|
||||||
|
@ -7,8 +7,9 @@ Contents:
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 3
|
:maxdepth: 3
|
||||||
|
|
||||||
|
alias
|
||||||
anaphoric
|
anaphoric
|
||||||
|
flow
|
||||||
loop
|
loop
|
||||||
multi
|
multi
|
||||||
flow
|
walk
|
||||||
alias
|
|
||||||
|
@ -24,7 +24,7 @@ tail-call optimization (TCO) in their Hy code.
|
|||||||
position to be implemented as efficiently as goto statements, thus
|
position to be implemented as efficiently as goto statements, thus
|
||||||
allowing efficient structured programming.
|
allowing efficient structured programming.
|
||||||
|
|
||||||
-- Wikipedia (http://en.wikipedia.org/wiki/Tail_call)
|
-- Wikipedia (https://en.wikipedia.org/wiki/Tail_call)
|
||||||
|
|
||||||
Macros
|
Macros
|
||||||
======
|
======
|
||||||
@ -39,13 +39,13 @@ rebinds the variables set in the recursion point and sends code
|
|||||||
execution back to that recursion point. If ``recur`` is used in a
|
execution back to that recursion point. If ``recur`` is used in a
|
||||||
non-tail position, an exception is raised.
|
non-tail position, an exception is raised.
|
||||||
|
|
||||||
Usage: `(loop bindings &rest body)`
|
Usage: ``(loop bindings &rest body)``
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: hy
|
.. code-block:: hy
|
||||||
|
|
||||||
(require hy.contrib.loop)
|
(require [hy.contrib.loop [loop]])
|
||||||
|
|
||||||
(defn factorial [n]
|
(defn factorial [n]
|
||||||
(loop [[i n] [acc 1]]
|
(loop [[i n] [acc 1]]
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
defmulti
|
defmulti
|
||||||
========
|
========
|
||||||
|
|
||||||
.. versionadded:: 0.10.0
|
.. versionadded:: 0.11.0
|
||||||
|
|
||||||
``defmulti``, ``defmethod`` and ``default-method`` lets you define
|
``defmulti``, ``defmethod`` and ``default-method`` lets you define
|
||||||
multimethods where a dispatching function is used to select between different
|
multimethods where a dispatching function is used to select between different
|
||||||
@ -11,7 +11,7 @@ on the code by `Adam Bard`_.
|
|||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
=> (require hy.contrib.multi)
|
=> (require [hy.contrib.multi [defmulti defmethod]])
|
||||||
=> (defmulti area [shape]
|
=> (defmulti area [shape]
|
||||||
... "calculate area of a shape"
|
... "calculate area of a shape"
|
||||||
... (:type shape))
|
... (:type shape))
|
||||||
@ -59,7 +59,7 @@ different implementations can narrow them down.
|
|||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
=> (require hy.contrib.multi)
|
=> (require [hy.contrib.multi [defmulti defmethod]])
|
||||||
=> (defmulti fun [&rest args]
|
=> (defmulti fun [&rest args]
|
||||||
... (len args))
|
... (len args))
|
||||||
|
|
||||||
|
94
docs/contrib/walk.rst
Normal file
94
docs/contrib/walk.rst
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
====
|
||||||
|
walk
|
||||||
|
====
|
||||||
|
|
||||||
|
.. versionadded:: 0.11.0
|
||||||
|
|
||||||
|
Functions
|
||||||
|
=========
|
||||||
|
|
||||||
|
.. _walk:
|
||||||
|
|
||||||
|
walk
|
||||||
|
-----
|
||||||
|
|
||||||
|
Usage: `(walk inner outer form)`
|
||||||
|
|
||||||
|
``walk`` traverses ``form``, an arbitrary data structure. Applies
|
||||||
|
``inner`` to each element of form, building up a data structure of the
|
||||||
|
same type. Applies ``outer`` to the result.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (import [hy.contrib.walk [walk]])
|
||||||
|
=> (setv a '(a b c d e f))
|
||||||
|
=> (walk ord identity a)
|
||||||
|
(97 98 99 100 101 102)
|
||||||
|
=> (walk ord first a)
|
||||||
|
97
|
||||||
|
|
||||||
|
postwalk
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. _postwalk:
|
||||||
|
|
||||||
|
Usage: `(postwalk f form)`
|
||||||
|
|
||||||
|
Performs depth-first, post-order traversal of ``form``. Calls ``f`` on
|
||||||
|
each sub-form, uses ``f`` 's return value in place of the original.
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (import [hy.contrib.walk [postwalk]])
|
||||||
|
=> (def trail '([1 2 3] [4 [5 6 [7]]]))
|
||||||
|
=> (defn walking [x]
|
||||||
|
(print "Walking:" x)
|
||||||
|
x )
|
||||||
|
=> (postwalk walking trail)
|
||||||
|
Walking: 1
|
||||||
|
Walking: 2
|
||||||
|
Walking: 3
|
||||||
|
Walking: (1 2 3)
|
||||||
|
Walking: 4
|
||||||
|
Walking: 5
|
||||||
|
Walking: 6
|
||||||
|
Walking: 7
|
||||||
|
Walking: (7)
|
||||||
|
Walking: (5 6 [7])
|
||||||
|
Walking: (4 [5 6 [7]])
|
||||||
|
Walking: ([1 2 3] [4 [5 6 [7]]])
|
||||||
|
([1 2 3] [4 [5 6 [7]]])
|
||||||
|
|
||||||
|
prewalk
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. _prewalk:
|
||||||
|
|
||||||
|
Usage: `(prewalk f form)`
|
||||||
|
|
||||||
|
Performs depth-first, pre-order traversal of ``form``. Calls ``f`` on
|
||||||
|
each sub-form, uses ``f`` 's return value in place of the original.
|
||||||
|
|
||||||
|
.. code-block:: hy
|
||||||
|
|
||||||
|
=> (import [hy.contrib.walk [prewalk]])
|
||||||
|
=> (def trail '([1 2 3] [4 [5 6 [7]]]))
|
||||||
|
=> (defn walking [x]
|
||||||
|
(print "Walking:" x)
|
||||||
|
x )
|
||||||
|
=> (prewalk walking trail)
|
||||||
|
Walking: ([1 2 3] [4 [5 6 [7]]])
|
||||||
|
Walking: [1 2 3]
|
||||||
|
Walking: 1
|
||||||
|
Walking: 2
|
||||||
|
Walking: 3
|
||||||
|
Walking: [4 [5 6 [7]]]
|
||||||
|
Walking: 4
|
||||||
|
Walking: [5 6 [7]]
|
||||||
|
Walking: 5
|
||||||
|
Walking: 6
|
||||||
|
Walking: [7]
|
||||||
|
Walking: 7
|
||||||
|
([1 2 3] [4 [5 6 [7]]])
|
@ -32,7 +32,7 @@ Do this:
|
|||||||
|
|
||||||
$ . venv/bin/activate
|
$ . venv/bin/activate
|
||||||
|
|
||||||
or use `virtualenvwrapper <http://virtualenvwrapper.readthedocs.org/en/latest/#introduction>`_
|
or use `virtualenvwrapper <https://virtualenvwrapper.readthedocs.io/en/latest/#introduction>`_
|
||||||
to create and manage your virtual environment::
|
to create and manage your virtual environment::
|
||||||
|
|
||||||
$ mkvirtualenv hy
|
$ mkvirtualenv hy
|
||||||
@ -63,7 +63,7 @@ Test!
|
|||||||
=====
|
=====
|
||||||
|
|
||||||
Tests are located in ``tests/``. We use `nose
|
Tests are located in ``tests/``. We use `nose
|
||||||
<https://nose.readthedocs.org/en/latest/>`_.
|
<https://nose.readthedocs.io/en/latest/>`_.
|
||||||
|
|
||||||
To run the tests::
|
To run the tests::
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ languages.
|
|||||||
string. For example, ``foo`` will become ``FOO``.
|
string. For example, ``foo`` will become ``FOO``.
|
||||||
|
|
||||||
* UTF-8 entities will be encoded using
|
* UTF-8 entities will be encoded using
|
||||||
`punycode <http://en.wikipedia.org/wiki/Punycode>`_ and prefixed with
|
`punycode <https://en.wikipedia.org/wiki/Punycode>`_ and prefixed with
|
||||||
``hy_``. For instance, ``⚘`` will become ``hy_w7h``, ``♥`` will become
|
``hy_``. For instance, ``⚘`` will become ``hy_w7h``, ``♥`` will become
|
||||||
``hy_g6h``, and ``i♥u`` will become ``hy_iu_t0x``.
|
``hy_g6h``, and ``i♥u`` will become ``hy_iu_t0x``.
|
||||||
|
|
||||||
@ -179,6 +179,79 @@ other case, the first false value will be returned. Example usage:
|
|||||||
False
|
False
|
||||||
|
|
||||||
|
|
||||||
|
as->
|
||||||
|
----
|
||||||
|
|
||||||
|
.. versionadded:: 0.12.0
|
||||||
|
|
||||||
|
Expands to sequence of assignments to the provided name, starting with head.
|
||||||
|
The previous result is thus available in the subsequent form. Returns the final
|
||||||
|
result, and leaves the name bound to it in the local scope. This behaves much
|
||||||
|
like the other threading macros, but requires you to specify the threading
|
||||||
|
point per form via the name instead of always the first or last argument.
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
;; example how -> and as-> relate
|
||||||
|
|
||||||
|
=> (as-> 0 it
|
||||||
|
... (inc it)
|
||||||
|
... (inc it))
|
||||||
|
2
|
||||||
|
|
||||||
|
=> (-> 0 inc inc)
|
||||||
|
2
|
||||||
|
|
||||||
|
;; create data for our cuttlefish database
|
||||||
|
|
||||||
|
=> (setv data [{:name "hooded cuttlefish"
|
||||||
|
... :classification {:subgenus "Acanthosepion"
|
||||||
|
... :species "Sepia prashadi"}
|
||||||
|
... :discovered {:year 1936
|
||||||
|
... :name "Ronald Winckworth"}}
|
||||||
|
... {:name "slender cuttlefish"
|
||||||
|
... :classification {:subgenus "Doratosepion"
|
||||||
|
... :species "Sepia braggi"}
|
||||||
|
... :discovered {:year 1907
|
||||||
|
... :name "Sir Joseph Cooke Verco"}}])
|
||||||
|
|
||||||
|
;; retrieve name of first entry
|
||||||
|
=> (as-> (first data) it
|
||||||
|
... (:name it))
|
||||||
|
'hooded cuttlefish'
|
||||||
|
|
||||||
|
;; retrieve species of first entry
|
||||||
|
=> (as-> (first data) it
|
||||||
|
... (:classification it)
|
||||||
|
... (:species it))
|
||||||
|
'Sepia prashadi'
|
||||||
|
|
||||||
|
;; find out who discovered slender cuttlefish
|
||||||
|
=> (as-> (filter (fn [entry] (= (:name entry)
|
||||||
|
... "slender cuttlefish")) data) it
|
||||||
|
... (first it)
|
||||||
|
... (:discovered it)
|
||||||
|
... (:name it))
|
||||||
|
'Sir Joseph Cooke Verco'
|
||||||
|
|
||||||
|
;; more convoluted example to load web page and retrieve data from it
|
||||||
|
=> (import [urllib.request [urlopen]])
|
||||||
|
=> (as-> (urlopen "http://docs.hylang.org/en/stable/") it
|
||||||
|
... (.read it)
|
||||||
|
... (.decode it "utf-8")
|
||||||
|
... (drop (.index it "Welcome") it)
|
||||||
|
... (take 30 it)
|
||||||
|
... (list it)
|
||||||
|
... (.join "" it))
|
||||||
|
'Welcome to Hy’s documentation!
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
In these examples, the REPL will report a tuple (e.g. `('Sepia prashadi',
|
||||||
|
'Sepia prashadi')`) as the result, but only a single value is actually
|
||||||
|
returned.
|
||||||
|
|
||||||
|
|
||||||
assert
|
assert
|
||||||
------
|
------
|
||||||
|
|
||||||
@ -953,11 +1026,20 @@ that ``import`` can be used.
|
|||||||
(import [sys :as systest])
|
(import [sys :as systest])
|
||||||
|
|
||||||
;; You can list as many imports as you like of different types.
|
;; You can list as many imports as you like of different types.
|
||||||
|
;;
|
||||||
|
;; Python:
|
||||||
|
;; from tests.resources import kwtest, function_with_a_dash
|
||||||
|
;; from os.path import exists, isdir as is_dir, isfile as is_file
|
||||||
|
;; import sys as systest
|
||||||
(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 :as dir?
|
||||||
|
isfile :as file?]]
|
||||||
[sys :as systest])
|
[sys :as systest])
|
||||||
|
|
||||||
;; Import all module functions into current namespace
|
;; Import all module functions into current namespace
|
||||||
|
;;
|
||||||
|
;; Python: from sys import *
|
||||||
(import [sys [*]])
|
(import [sys [*]])
|
||||||
|
|
||||||
|
|
||||||
@ -1201,16 +1283,84 @@ alternatively be written using the apostrophe (``'``) symbol.
|
|||||||
require
|
require
|
||||||
-------
|
-------
|
||||||
|
|
||||||
``require`` is used to import macros from a given module. It takes at least one
|
``require`` is used to import macros from one or more given modules. It allows
|
||||||
parameter specifying the module which macros should be imported. Multiple
|
parameters in all the same formats as ``import``. The ``require`` form itself
|
||||||
modules can be imported with a single ``require``.
|
produces no code in the final program: its effect is purely at compile-time, for
|
||||||
|
the benefit of macro expansion. Specifically, ``require`` imports each named
|
||||||
|
module and then makes each requested macro available in the current module.
|
||||||
|
|
||||||
The following example will import macros from ``module-1`` and ``module-2``:
|
The following are all equivalent ways to call a macro named ``foo`` in the module ``mymodule``:
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
(require module-1 module-2)
|
(require mymodule)
|
||||||
|
(mymodule.foo 1)
|
||||||
|
|
||||||
|
(require [mymodule :as M])
|
||||||
|
(M.foo 1)
|
||||||
|
|
||||||
|
(require [mymodule [foo]])
|
||||||
|
(foo 1)
|
||||||
|
|
||||||
|
(require [mymodule [*]])
|
||||||
|
(foo 1)
|
||||||
|
|
||||||
|
(require [mymodule [foo :as bar]])
|
||||||
|
(bar 1)
|
||||||
|
|
||||||
|
Macros that call macros
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
One aspect of ``require`` that may be surprising is what happens when one
|
||||||
|
macro's expansion calls another macro. Suppose ``mymodule.hy`` looks like this:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(defmacro repexpr [n expr]
|
||||||
|
; Evaluate the expression n times
|
||||||
|
; and collect the results in a list.
|
||||||
|
`(list (map (fn [_] ~expr) (range ~n))))
|
||||||
|
|
||||||
|
(defmacro foo [n]
|
||||||
|
`(repexpr ~n (input "Gimme some input: ")))
|
||||||
|
|
||||||
|
And then, in your main program, you write:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(require [mymodule [foo]])
|
||||||
|
|
||||||
|
(print (mymodule.foo 3))
|
||||||
|
|
||||||
|
Running this raises ``NameError: name 'repexpr' is not defined``, even though
|
||||||
|
writing ``(print (foo 3))`` in ``mymodule`` works fine. The trouble is that your
|
||||||
|
main program doesn't have the macro ``repexpr`` available, since it wasn't
|
||||||
|
imported (and imported under exactly that name, as opposed to a qualified name).
|
||||||
|
You could do ``(require [mymodule [*]])`` or ``(require [mymodule [foo
|
||||||
|
repexpr]])``, but a less error-prone approach is to change the definition of
|
||||||
|
``foo`` to require whatever sub-macros it needs:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(defmacro foo [n]
|
||||||
|
`(do
|
||||||
|
(require mymodule)
|
||||||
|
(mymodule.repexpr ~n (raw-input "Gimme some input: "))))
|
||||||
|
|
||||||
|
It's wise to use ``(require mymodule)`` here rather than ``(require [mymodule
|
||||||
|
[repexpr]])`` to avoid accidentally shadowing a function named ``repexpr`` in
|
||||||
|
the main program.
|
||||||
|
|
||||||
|
Qualified macro names
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Note that in the current implementation, there's a trick in qualified macro
|
||||||
|
names, like ``mymodule.foo`` and ``M.foo`` in the above example. These names
|
||||||
|
aren't actually attributes of module objects; they're just identifiers with
|
||||||
|
periods in them. In fact, ``mymodule`` and ``M`` aren't defined by these
|
||||||
|
``require`` forms, even at compile-time. None of this will hurt you unless try
|
||||||
|
to do introspection of the current module's set of defined macros, which isn't
|
||||||
|
really supported anyway.
|
||||||
|
|
||||||
rest / cdr
|
rest / cdr
|
||||||
----------
|
----------
|
||||||
|
@ -35,7 +35,7 @@ Command Line Options
|
|||||||
|
|
||||||
.. cmdoption:: --spy
|
.. cmdoption:: --spy
|
||||||
|
|
||||||
Print equivalent Python code before executing. For example::
|
Print equivalent Python code before executing in REPL. For example::
|
||||||
|
|
||||||
=> (defn salutationsnm [name] (print (+ "Hy " name "!")))
|
=> (defn salutationsnm [name] (print (+ "Hy " name "!")))
|
||||||
def salutationsnm(name):
|
def salutationsnm(name):
|
||||||
@ -45,6 +45,7 @@ Command Line Options
|
|||||||
Hy YourName!
|
Hy YourName!
|
||||||
=>
|
=>
|
||||||
|
|
||||||
|
`--spy` only works on REPL mode.
|
||||||
.. versionadded:: 0.9.11
|
.. versionadded:: 0.9.11
|
||||||
|
|
||||||
.. cmdoption:: --show-tracebacks
|
.. cmdoption:: --show-tracebacks
|
||||||
|
@ -141,7 +141,7 @@ is ``True``, the function prints Python code instead.
|
|||||||
print('Hello World!')
|
print('Hello World!')
|
||||||
|
|
||||||
|
|
||||||
.. _emtpy?-fn:
|
.. _empty?-fn:
|
||||||
|
|
||||||
empty?
|
empty?
|
||||||
------
|
------
|
||||||
|
@ -170,7 +170,7 @@ Cons Cells
|
|||||||
cells`_. Cons cells are especially useful to mimic features of "usual"
|
cells`_. Cons cells are especially useful to mimic features of "usual"
|
||||||
LISP variants such as Scheme or Common Lisp.
|
LISP variants such as Scheme or Common Lisp.
|
||||||
|
|
||||||
.. _cons cells: http://en.wikipedia.org/wiki/Cons
|
.. _cons cells: https://en.wikipedia.org/wiki/Cons
|
||||||
|
|
||||||
A cons cell is a 2-item object, containing a ``car`` (head) and a
|
A cons cell is a 2-item object, containing a ``car`` (head) and a
|
||||||
``cdr`` (tail). In some Lisp variants, the cons cell is the fundamental
|
``cdr`` (tail). In some Lisp variants, the cons cell is the fundamental
|
||||||
|
@ -13,7 +13,7 @@ Quickstart
|
|||||||
1. Create a `Virtual Python Environment
|
1. Create a `Virtual Python Environment
|
||||||
<https://pypi.python.org/pypi/virtualenv>`_.
|
<https://pypi.python.org/pypi/virtualenv>`_.
|
||||||
2. Activate your Virtual Python Environment.
|
2. Activate your Virtual Python Environment.
|
||||||
3. Install `hy from PyPI <https://pypi.python.org/pypi/hy>`_ with ``pip install hy``.
|
3. Install `hy from GitHub <https://github.com/hylang/hy>`_ with ``$ pip install git+https://github.com/hylang/hy.git``.
|
||||||
4. Start a REPL with ``hy``.
|
4. Start a REPL with ``hy``.
|
||||||
5. Type stuff in the REPL::
|
5. Type stuff in the REPL::
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ Layout & Indentation
|
|||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
(let [foo (bar)]
|
(let [foo (bar)
|
||||||
qux (baz)]
|
qux (baz)]
|
||||||
(foo qux))
|
(foo qux))
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ In Hy, you would do:
|
|||||||
[true
|
[true
|
||||||
(print "That variable is jussssst right!")])
|
(print "That variable is jussssst right!")])
|
||||||
|
|
||||||
What you'll notice is that ``cond`` switches off between a some statement
|
What you'll notice is that ``cond`` switches off between a statement
|
||||||
that is executed and checked conditionally for true or falseness, and
|
that is executed and checked conditionally for true or falseness, and
|
||||||
then a bit of code to execute if it turns out to be true. You'll also
|
then a bit of code to execute if it turns out to be true. You'll also
|
||||||
notice that the ``else`` is implemented at the end simply by checking
|
notice that the ``else`` is implemented at the end simply by checking
|
||||||
@ -292,7 +292,7 @@ You can do the following:
|
|||||||
(if (try-some-thing)
|
(if (try-some-thing)
|
||||||
(do
|
(do
|
||||||
(print "this is if true")
|
(print "this is if true")
|
||||||
(print "and why not, let's keep talking about how true it is!))
|
(print "and why not, let's keep talking about how true it is!"))
|
||||||
(print "this one's still simply just false"))
|
(print "this one's still simply just false"))
|
||||||
|
|
||||||
You can see that we used ``do`` to wrap multiple statements. If you're
|
You can see that we used ``do`` to wrap multiple statements. If you're
|
||||||
@ -568,15 +568,18 @@ 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
|
What if you want to use a macro that's defined in a different
|
||||||
``import`` the module, because importing happens at run-time, while we
|
module? The special form ``import`` won't help, because it merely
|
||||||
would need macros at compile-time. Instead of importing the module
|
translates to a Python ``import`` statement that's executed at
|
||||||
with macros, ``require`` must be used:
|
run-time, and macros are expanded at compile-time, that is,
|
||||||
|
during the translate from Hy to Python. Instead, use ``require``,
|
||||||
|
which imports the module and makes macros available at
|
||||||
|
compile-time. ``require`` uses the same syntax as ``import``.
|
||||||
|
|
||||||
.. code-block:: clj
|
.. code-block:: clj
|
||||||
|
|
||||||
=> (require tutorial.macros)
|
=> (require tutorial.macros)
|
||||||
=> (rev (1 2 3 +))
|
=> (tutorial.macros.rev (1 2 3 +))
|
||||||
6
|
6
|
||||||
|
|
||||||
Hy <-> Python interop
|
Hy <-> Python interop
|
||||||
|
@ -19,7 +19,11 @@
|
|||||||
# DEALINGS IN THE SOFTWARE.
|
# DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
from hy.version import __version__, __appname__ # NOQA
|
__appname__ = 'hy'
|
||||||
|
try:
|
||||||
|
from hy.version import __version__
|
||||||
|
except ImportError:
|
||||||
|
__version__ = 'unknown'
|
||||||
|
|
||||||
|
|
||||||
from hy.models.expression import HyExpression # NOQA
|
from hy.models.expression import HyExpression # NOQA
|
||||||
|
@ -173,8 +173,8 @@ def ideas_macro():
|
|||||||
|
|
||||||
""")])
|
""")])
|
||||||
|
|
||||||
require("hy.cmdline", "__console__")
|
require("hy.cmdline", "__console__", all_macros=True)
|
||||||
require("hy.cmdline", "__main__")
|
require("hy.cmdline", "__main__", all_macros=True)
|
||||||
|
|
||||||
SIMPLE_TRACEBACKS = True
|
SIMPLE_TRACEBACKS = True
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ def cmdline_handler(scriptname, argv):
|
|||||||
parser.add_argument("--spy", action="store_true",
|
parser.add_argument("--spy", action="store_true",
|
||||||
help="print equivalent Python code before executing")
|
help="print equivalent Python code before executing")
|
||||||
|
|
||||||
parser.add_argument("-v", action="version", version=VERSION)
|
parser.add_argument("-v", "--version", action="version", version=VERSION)
|
||||||
|
|
||||||
parser.add_argument("--show-tracebacks", action="store_true",
|
parser.add_argument("--show-tracebacks", action="store_true",
|
||||||
help="show complete tracebacks for Hy exceptions")
|
help="show complete tracebacks for Hy exceptions")
|
||||||
|
@ -503,19 +503,13 @@ class HyASTCompiler(object):
|
|||||||
for expr in exprs:
|
for expr in exprs:
|
||||||
|
|
||||||
if expr in ll_keywords:
|
if expr in ll_keywords:
|
||||||
if expr == "&rest" and lambda_keyword is None:
|
if expr == "&optional":
|
||||||
lambda_keyword = expr
|
|
||||||
elif expr == "&optional":
|
|
||||||
if len(defaults) > 0:
|
if len(defaults) > 0:
|
||||||
raise HyTypeError(expr,
|
raise HyTypeError(expr,
|
||||||
"There can only be &optional "
|
"There can only be &optional "
|
||||||
"arguments or one &key argument")
|
"arguments or one &key argument")
|
||||||
lambda_keyword = expr
|
lambda_keyword = expr
|
||||||
elif expr == "&key":
|
elif expr in ("&rest", "&key", "&kwonly", "&kwargs"):
|
||||||
lambda_keyword = expr
|
|
||||||
elif expr == "&kwonly":
|
|
||||||
lambda_keyword = expr
|
|
||||||
elif expr == "&kwargs":
|
|
||||||
lambda_keyword = expr
|
lambda_keyword = expr
|
||||||
else:
|
else:
|
||||||
raise HyTypeError(expr,
|
raise HyTypeError(expr,
|
||||||
@ -1516,7 +1510,8 @@ class HyASTCompiler(object):
|
|||||||
gen.append(ast.comprehension(
|
gen.append(ast.comprehension(
|
||||||
target=target,
|
target=target,
|
||||||
iter=gen_res.force_expr,
|
iter=gen_res.force_expr,
|
||||||
ifs=[]))
|
ifs=[],
|
||||||
|
is_async=False))
|
||||||
|
|
||||||
if cond.expr:
|
if cond.expr:
|
||||||
gen[-1].ifs.append(cond.expr)
|
gen[-1].ifs.append(cond.expr)
|
||||||
@ -1742,10 +1737,45 @@ class HyASTCompiler(object):
|
|||||||
"unimport" it after we've completed `thing' so that we don't pollute
|
"unimport" it after we've completed `thing' so that we don't pollute
|
||||||
other envs.
|
other envs.
|
||||||
"""
|
"""
|
||||||
expression.pop(0)
|
for entry in expression[1:]:
|
||||||
for entry in expression:
|
if isinstance(entry, HySymbol):
|
||||||
__import__(entry) # Import it fo' them macros.
|
# e.g., (require foo)
|
||||||
require(entry, self.module_name)
|
__import__(entry)
|
||||||
|
require(entry, self.module_name, all_macros=True,
|
||||||
|
prefix=entry)
|
||||||
|
elif isinstance(entry, HyList) and len(entry) == 2:
|
||||||
|
# e.g., (require [foo [bar baz :as MyBaz bing]])
|
||||||
|
# or (require [foo [*]])
|
||||||
|
module, names = entry
|
||||||
|
if not isinstance(names, HyList):
|
||||||
|
raise HyTypeError(names,
|
||||||
|
"(require) name lists should be HyLists")
|
||||||
|
__import__(module)
|
||||||
|
if '*' in names:
|
||||||
|
if len(names) != 1:
|
||||||
|
raise HyTypeError(names, "* in a (require) name list "
|
||||||
|
"must be on its own")
|
||||||
|
require(module, self.module_name, all_macros=True)
|
||||||
|
else:
|
||||||
|
assignments = {}
|
||||||
|
while names:
|
||||||
|
if len(names) > 1 and names[1] == HyKeyword(":as"):
|
||||||
|
k, _, v = names[:3]
|
||||||
|
del names[:3]
|
||||||
|
assignments[k] = v
|
||||||
|
else:
|
||||||
|
symbol = names.pop(0)
|
||||||
|
assignments[symbol] = symbol
|
||||||
|
require(module, self.module_name, assignments=assignments)
|
||||||
|
elif (isinstance(entry, HyList) and len(entry) == 3
|
||||||
|
and entry[1] == HyKeyword(":as")):
|
||||||
|
# e.g., (require [foo :as bar])
|
||||||
|
module, _, prefix = entry
|
||||||
|
__import__(module)
|
||||||
|
require(module, self.module_name, all_macros=True,
|
||||||
|
prefix=prefix)
|
||||||
|
else:
|
||||||
|
raise HyTypeError(entry, "unrecognized (require) syntax")
|
||||||
return Result()
|
return Result()
|
||||||
|
|
||||||
@builds("and")
|
@builds("and")
|
||||||
@ -1910,7 +1940,6 @@ class HyASTCompiler(object):
|
|||||||
col_offset=child.start_column)
|
col_offset=child.start_column)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@builds("+")
|
|
||||||
@builds("*")
|
@builds("*")
|
||||||
@builds("/")
|
@builds("/")
|
||||||
@builds("//")
|
@builds("//")
|
||||||
@ -1918,8 +1947,7 @@ class HyASTCompiler(object):
|
|||||||
if len(expression) > 2:
|
if len(expression) > 2:
|
||||||
return self.compile_maths_expression(expression)
|
return self.compile_maths_expression(expression)
|
||||||
else:
|
else:
|
||||||
id_op = {"+": HyInteger(0), "*": HyInteger(1), "/": HyInteger(1),
|
id_op = {"*": HyInteger(1), "/": HyInteger(1), "//": HyInteger(1)}
|
||||||
"//": HyInteger(1)}
|
|
||||||
|
|
||||||
op = expression.pop(0)
|
op = expression.pop(0)
|
||||||
arg = expression.pop(0) if expression else id_op[op]
|
arg = expression.pop(0) if expression else id_op[op]
|
||||||
@ -1930,20 +1958,34 @@ class HyASTCompiler(object):
|
|||||||
]).replace(expression)
|
]).replace(expression)
|
||||||
return self.compile_maths_expression(expr)
|
return self.compile_maths_expression(expr)
|
||||||
|
|
||||||
@builds("-")
|
def compile_maths_expression_additive(self, expression):
|
||||||
@checkargs(min=1)
|
|
||||||
def compile_maths_expression_sub(self, expression):
|
|
||||||
if len(expression) > 2:
|
if len(expression) > 2:
|
||||||
return self.compile_maths_expression(expression)
|
return self.compile_maths_expression(expression)
|
||||||
else:
|
else:
|
||||||
arg = expression[1]
|
op = {"+": ast.UAdd, "-": ast.USub}[expression.pop(0)]()
|
||||||
|
arg = expression.pop(0)
|
||||||
ret = self.compile(arg)
|
ret = self.compile(arg)
|
||||||
ret += ast.UnaryOp(op=ast.USub(),
|
ret += ast.UnaryOp(op=op,
|
||||||
operand=ret.force_expr,
|
operand=ret.force_expr,
|
||||||
lineno=arg.start_line,
|
lineno=arg.start_line,
|
||||||
col_offset=arg.start_column)
|
col_offset=arg.start_column)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@builds("+")
|
||||||
|
def compile_maths_expression_add(self, expression):
|
||||||
|
if len(expression) == 1:
|
||||||
|
# Nullary +
|
||||||
|
return ast.Num(n=long_type(0),
|
||||||
|
lineno=expression.start_line,
|
||||||
|
col_offset=expression.start_column)
|
||||||
|
else:
|
||||||
|
return self.compile_maths_expression_additive(expression)
|
||||||
|
|
||||||
|
@builds("-")
|
||||||
|
@checkargs(min=1)
|
||||||
|
def compile_maths_expression_sub(self, expression):
|
||||||
|
return self.compile_maths_expression_additive(expression)
|
||||||
|
|
||||||
@builds("+=")
|
@builds("+=")
|
||||||
@builds("/=")
|
@builds("/=")
|
||||||
@builds("//=")
|
@builds("//=")
|
||||||
@ -2449,6 +2491,9 @@ class HyASTCompiler(object):
|
|||||||
raise HyTypeError(name, ("received a `%s' instead of a symbol "
|
raise HyTypeError(name, ("received a `%s' instead of a symbol "
|
||||||
"for macro name" % type(name).__name__))
|
"for macro name" % type(name).__name__))
|
||||||
name = HyString(name).replace(name)
|
name = HyString(name).replace(name)
|
||||||
|
for kw in ("&kwonly", "&kwargs", "&key"):
|
||||||
|
if kw in expression[0]:
|
||||||
|
raise HyTypeError(name, "macros cannot use %s" % kw)
|
||||||
new_expression = HyExpression([
|
new_expression = HyExpression([
|
||||||
HySymbol("with_decorator"),
|
HySymbol("with_decorator"),
|
||||||
HyExpression([HySymbol("hy.macros.macro"), name]),
|
HyExpression([HySymbol("hy.macros.macro"), name]),
|
||||||
|
@ -17,4 +17,5 @@
|
|||||||
|
|
||||||
|
|
||||||
(defmacro defnc [name args &rest body]
|
(defmacro defnc [name args &rest body]
|
||||||
`(def ~name (fnc [~@args] ~@body)))
|
`(do (require hy.contrib.curry)
|
||||||
|
(def ~name (hy.contrib.curry.fnc [~@args] ~@body))))
|
||||||
|
@ -70,7 +70,8 @@
|
|||||||
(defmacro defnr [name lambda-list &rest body]
|
(defmacro defnr [name lambda-list &rest body]
|
||||||
(if (not (= (type name) HySymbol))
|
(if (not (= (type name) HySymbol))
|
||||||
(macro-error name "defnr takes a name as first argument"))
|
(macro-error name "defnr takes a name as first argument"))
|
||||||
`(setv ~name (fnr ~lambda-list ~@body)))
|
`(do (require hy.contrib.loop)
|
||||||
|
(setv ~name (hy.contrib.loop.fnr ~lambda-list ~@body))))
|
||||||
|
|
||||||
|
|
||||||
(defmacro/g! loop [bindings &rest body]
|
(defmacro/g! loop [bindings &rest body]
|
||||||
@ -87,5 +88,6 @@
|
|||||||
;; and erroring if not is a giant TODO.
|
;; and erroring if not is a giant TODO.
|
||||||
(let [fnargs (map (fn [x] (first x)) bindings)
|
(let [fnargs (map (fn [x] (first x)) bindings)
|
||||||
initargs (map second bindings)]
|
initargs (map second bindings)]
|
||||||
`(do (defnr ~g!recur-fn [~@fnargs] ~@body)
|
`(do (require hy.contrib.loop)
|
||||||
|
(hy.contrib.loop.defnr ~g!recur-fn [~@fnargs] ~@body)
|
||||||
(~g!recur-fn ~@initargs))))
|
(~g!recur-fn ~@initargs))))
|
||||||
|
@ -9,19 +9,23 @@
|
|||||||
(defn ~name ~params
|
(defn ~name ~params
|
||||||
(do ~@code)))))
|
(do ~@code)))))
|
||||||
|
|
||||||
|
(defn rwm [name path method params code]
|
||||||
|
`(do (require hy.contrib.meth)
|
||||||
|
(hy.contrib.meth.route-with-methods ~name ~path ~method ~params ~@code)))
|
||||||
|
|
||||||
;; Some macro examples
|
;; Some macro examples
|
||||||
(defmacro route [name path params &rest code]
|
(defmacro route [name path params &rest code]
|
||||||
"Get request"
|
"Get request"
|
||||||
`(route-with-methods ~name ~path ["GET"] ~params ~@code))
|
(rwm name path ["GET"] params code))
|
||||||
|
|
||||||
(defmacro post-route [name path params &rest code]
|
(defmacro post-route [name path params &rest code]
|
||||||
"Post request"
|
"Post request"
|
||||||
`(route-with-methods ~name ~path ["POST"] ~params ~@code))
|
(rwm name path ["POST"] params code))
|
||||||
|
|
||||||
(defmacro put-route [name path params &rest code]
|
(defmacro put-route [name path params &rest code]
|
||||||
"Put request"
|
"Put request"
|
||||||
`(route-with-methods ~name ~path ["PUT"] ~params ~@code))
|
(rwm name path ["PUT"] params code))
|
||||||
|
|
||||||
(defmacro delete-route [name path params &rest code]
|
(defmacro delete-route [name path params &rest code]
|
||||||
"Delete request"
|
"Delete request"
|
||||||
`(route-with-methods ~name ~path ["DELETE"] ~params ~@code))
|
(rwm name path ["DELETE"] params code))
|
||||||
|
@ -39,10 +39,6 @@
|
|||||||
(import [hy.lex [LexException PrematureEndOfInput tokenize]])
|
(import [hy.lex [LexException PrematureEndOfInput tokenize]])
|
||||||
(import [hy.compiler [HyASTCompiler]])
|
(import [hy.compiler [HyASTCompiler]])
|
||||||
|
|
||||||
(defn _numeric-check [x]
|
|
||||||
(if (not (numeric? x))
|
|
||||||
(raise (TypeError (.format "{0!r} is not a number" x)))))
|
|
||||||
|
|
||||||
(defn butlast [coll]
|
(defn butlast [coll]
|
||||||
"Returns coll except of last element."
|
"Returns coll except of last element."
|
||||||
(drop-last 1 coll))
|
(drop-last 1 coll))
|
||||||
@ -66,7 +62,6 @@
|
|||||||
|
|
||||||
(defn dec [n]
|
(defn dec [n]
|
||||||
"Decrement n by 1"
|
"Decrement n by 1"
|
||||||
(_numeric-check n)
|
|
||||||
(- n 1))
|
(- n 1))
|
||||||
|
|
||||||
(defn disassemble [tree &optional [codegen false]]
|
(defn disassemble [tree &optional [codegen false]]
|
||||||
@ -170,7 +165,6 @@
|
|||||||
|
|
||||||
(defn even? [n]
|
(defn even? [n]
|
||||||
"Return true if n is an even number"
|
"Return true if n is an even number"
|
||||||
(_numeric-check n)
|
|
||||||
(= (% n 2) 0))
|
(= (% n 2) 0))
|
||||||
|
|
||||||
(defn every? [pred coll]
|
(defn every? [pred coll]
|
||||||
@ -239,7 +233,6 @@
|
|||||||
|
|
||||||
(defn inc [n]
|
(defn inc [n]
|
||||||
"Increment n by 1"
|
"Increment n by 1"
|
||||||
(_numeric-check n)
|
|
||||||
(+ n 1))
|
(+ n 1))
|
||||||
|
|
||||||
(defn instance? [klass x]
|
(defn instance? [klass x]
|
||||||
@ -325,7 +318,6 @@
|
|||||||
|
|
||||||
(defn neg? [n]
|
(defn neg? [n]
|
||||||
"Return true if n is < 0"
|
"Return true if n is < 0"
|
||||||
(_numeric-check n)
|
|
||||||
(< n 0))
|
(< n 0))
|
||||||
|
|
||||||
(defn none? [x]
|
(defn none? [x]
|
||||||
@ -347,7 +339,6 @@
|
|||||||
|
|
||||||
(defn odd? [n]
|
(defn odd? [n]
|
||||||
"Return true if n is an odd number"
|
"Return true if n is an odd number"
|
||||||
(_numeric-check n)
|
|
||||||
(= (% n 2) 1))
|
(= (% n 2) 1))
|
||||||
|
|
||||||
(def -sentinel (object))
|
(def -sentinel (object))
|
||||||
@ -364,7 +355,6 @@
|
|||||||
|
|
||||||
(defn pos? [n]
|
(defn pos? [n]
|
||||||
"Return true if n is > 0"
|
"Return true if n is > 0"
|
||||||
(_numeric_check n)
|
|
||||||
(> n 0))
|
(> n 0))
|
||||||
|
|
||||||
(defn rest [coll]
|
(defn rest [coll]
|
||||||
@ -415,7 +405,6 @@
|
|||||||
|
|
||||||
(defn zero? [n]
|
(defn zero? [n]
|
||||||
"Return true if n is 0"
|
"Return true if n is 0"
|
||||||
(_numeric_check n)
|
|
||||||
(= n 0))
|
(= n 0))
|
||||||
|
|
||||||
(defn read [&optional [from-file sys.stdin]
|
(defn read [&optional [from-file sys.stdin]
|
||||||
|
@ -30,6 +30,16 @@
|
|||||||
[hy.models.symbol [HySymbol]]
|
[hy.models.symbol [HySymbol]]
|
||||||
[hy._compat [PY33 PY34]])
|
[hy._compat [PY33 PY34]])
|
||||||
|
|
||||||
|
(defmacro as-> [head name &rest rest]
|
||||||
|
"Expands to sequence of assignments to the provided name, starting with head.
|
||||||
|
The previous result is thus available in the subsequent form. Returns the
|
||||||
|
final result, and leaves the name bound to it in the local scope. This behaves
|
||||||
|
much like the other threading macros, but requires you to specify the threading
|
||||||
|
point per form via the name instead of always the first or last argument."
|
||||||
|
`(do (setv
|
||||||
|
~name ~head
|
||||||
|
~@(interleave (repeat name) rest))
|
||||||
|
~name))
|
||||||
|
|
||||||
(defmacro with [args &rest body]
|
(defmacro with [args &rest body]
|
||||||
"shorthand for nested with* loops:
|
"shorthand for nested with* loops:
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
(if (zero? count)
|
(if (zero? count)
|
||||||
(raise (TypeError "Need at least 1 argument to add/concatenate"))
|
(raise (TypeError "Need at least 1 argument to add/concatenate"))
|
||||||
(if (= count 1)
|
(if (= count 1)
|
||||||
(get args 0)
|
(operator.pos (get args 0))
|
||||||
(reduce operator.add args)))))
|
(reduce operator.add args)))))
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,12 +45,12 @@ def ast_compile(ast, filename, mode):
|
|||||||
|
|
||||||
|
|
||||||
def import_buffer_to_hst(buf):
|
def import_buffer_to_hst(buf):
|
||||||
"""Import content from buf and return an Hy AST."""
|
"""Import content from buf and return a Hy AST."""
|
||||||
return tokenize(buf + "\n")
|
return tokenize(buf + "\n")
|
||||||
|
|
||||||
|
|
||||||
def import_file_to_hst(fpath):
|
def import_file_to_hst(fpath):
|
||||||
"""Import content from fpath and return an Hy AST."""
|
"""Import content from fpath and return a Hy AST."""
|
||||||
try:
|
try:
|
||||||
with open(fpath, 'r', encoding='utf-8') as f:
|
with open(fpath, 'r', encoding='utf-8') as f:
|
||||||
return import_buffer_to_hst(f.read())
|
return import_buffer_to_hst(f.read())
|
||||||
@ -89,6 +89,15 @@ def import_file_to_module(module_name, fpath):
|
|||||||
return mod
|
return mod
|
||||||
|
|
||||||
|
|
||||||
|
def import_file_to_globals(env, module_name, fpath):
|
||||||
|
""" Import content from fpath and puts it into the dict provided
|
||||||
|
(e.g., for use in a REPL)
|
||||||
|
"""
|
||||||
|
mod = import_file_to_module(module_name, fpath)
|
||||||
|
for k, v in mod.__dict__.items():
|
||||||
|
env[k] = v
|
||||||
|
|
||||||
|
|
||||||
def import_buffer_to_module(module_name, buf):
|
def import_buffer_to_module(module_name, buf):
|
||||||
try:
|
try:
|
||||||
_ast = import_buffer_to_ast(buf, module_name)
|
_ast = import_buffer_to_ast(buf, module_name)
|
||||||
|
36
hy/macros.py
36
hy/macros.py
@ -84,22 +84,36 @@ def reader(name):
|
|||||||
return _
|
return _
|
||||||
|
|
||||||
|
|
||||||
def require(source_module, target_module):
|
def require(source_module, target_module,
|
||||||
"""Load the macros from `source_module` in the namespace of
|
all_macros=False, assignments={}, prefix=""):
|
||||||
`target_module`.
|
"""Load macros from `source_module` in the namespace of
|
||||||
|
`target_module`. `assignments` maps old names to new names, but is
|
||||||
|
ignored if `all_macros` is true. If `prefix` is nonempty, it is
|
||||||
|
prepended to the name of each imported macro. (This means you get
|
||||||
|
macros named things like "mymacromodule.mymacro", which looks like
|
||||||
|
an attribute of a module, although it's actually just a symbol
|
||||||
|
with a period in its name.)
|
||||||
|
|
||||||
This function is called from the `require` special form in the compiler.
|
This function is called from the `require` special form in the compiler.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
macros = _hy_macros[source_module]
|
|
||||||
refs = _hy_macros[target_module]
|
|
||||||
for name, macro in macros.items():
|
|
||||||
refs[name] = macro
|
|
||||||
|
|
||||||
readers = _hy_reader[source_module]
|
seen_names = set()
|
||||||
reader_refs = _hy_reader[target_module]
|
if prefix:
|
||||||
for name, reader in readers.items():
|
prefix += "."
|
||||||
reader_refs[name] = reader
|
|
||||||
|
for d in _hy_macros, _hy_reader:
|
||||||
|
for name, macro in d[source_module].items():
|
||||||
|
seen_names.add(name)
|
||||||
|
if all_macros:
|
||||||
|
d[target_module][prefix + name] = macro
|
||||||
|
elif name in assignments:
|
||||||
|
d[target_module][prefix + assignments[name]] = macro
|
||||||
|
|
||||||
|
if not all_macros:
|
||||||
|
unseen = frozenset(assignments.keys()).difference(seen_names)
|
||||||
|
if unseen:
|
||||||
|
raise ImportError("cannot require names: " + repr(list(unseen)))
|
||||||
|
|
||||||
|
|
||||||
def load_macros(module_name):
|
def load_macros(module_name):
|
||||||
|
@ -18,19 +18,16 @@
|
|||||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
# DEALINGS IN THE SOFTWARE.
|
# DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
from hy.models import _wrappers, wrap_value
|
||||||
from hy.models.list import HyList
|
from hy.models.list import HyList
|
||||||
from functools import reduce
|
|
||||||
|
|
||||||
|
|
||||||
class HySet(HyList):
|
class HySet(HyList):
|
||||||
"""
|
"""
|
||||||
Hy set (actually a list that pretends to be a set)
|
Hy set (just a representation of a set)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, items):
|
|
||||||
items = sorted(items)
|
|
||||||
items = list(reduce(lambda r, v: v in r and r or r+[v], items, []))
|
|
||||||
super(HySet, self).__init__(items)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "#{%s}" % (" ".join([repr(x) for x in self]))
|
return "#{%s}" % (" ".join([repr(x) for x in self]))
|
||||||
|
|
||||||
|
_wrappers[set] = lambda s: HySet(wrap_value(x) for x in s)
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
# copy of this software and associated documentation files (the "Software"),
|
|
||||||
# to deal in the Software without restriction, including without limitation
|
|
||||||
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
||||||
# and/or sell copies of the Software, and to permit persons to whom the
|
|
||||||
# Software is furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in
|
|
||||||
# all copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
||||||
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
# DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
|
|
||||||
__appname__ = "hy"
|
|
||||||
__version__ = "0.11.0"
|
|
23
setup.py
23
setup.py
@ -22,24 +22,23 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
|
os.chdir(os.path.split(os.path.abspath(__file__))[0])
|
||||||
|
|
||||||
PKG = "hy"
|
PKG = "hy"
|
||||||
VERSIONFILE = os.path.join(PKG, "version.py")
|
VERSIONFILE = os.path.join(PKG, "version.py")
|
||||||
verstr = "unknown"
|
|
||||||
try:
|
try:
|
||||||
verstrline = open(VERSIONFILE, "rt").read()
|
__version__ = (subprocess.check_output
|
||||||
except EnvironmentError:
|
(["git", "describe", "--tags", "--dirty"])
|
||||||
pass # Okay, there is no version file.
|
.decode('ASCII').strip()
|
||||||
else:
|
.replace('-', '+', 1).replace('-', '.'))
|
||||||
VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
|
with open(VERSIONFILE, "wt") as o:
|
||||||
mo = re.search(VSRE, verstrline, re.M)
|
o.write("__version__ = {!r}\n".format(__version__))
|
||||||
if mo:
|
except subprocess.CalledProcessError:
|
||||||
__version__ = mo.group(1)
|
__version__ = "unknown"
|
||||||
else:
|
|
||||||
msg = "if %s.py exists, it is required to be well-formed" % VERSIONFILE
|
|
||||||
raise RuntimeError(msg)
|
|
||||||
|
|
||||||
long_description = """Hy is a Python <--> Lisp layer. It helps
|
long_description = """Hy is a Python <--> Lisp layer. It helps
|
||||||
make things work nicer, and lets Python and the Hy lisp variant play
|
make things work nicer, and lets Python and the Hy lisp variant play
|
||||||
|
@ -249,6 +249,20 @@ def test_ast_good_import_from():
|
|||||||
can_compile("(import [x [y]])")
|
can_compile("(import [x [y]])")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_require():
|
||||||
|
"Make sure AST respects (require) syntax"
|
||||||
|
can_compile("(require tests.resources.tlib)")
|
||||||
|
can_compile("(require [tests.resources.tlib [qplah parald]])")
|
||||||
|
can_compile("(require [tests.resources.tlib [*]])")
|
||||||
|
can_compile("(require [tests.resources.tlib :as foobar])")
|
||||||
|
can_compile("(require [tests.resources.tlib [qplah :as quiz]])")
|
||||||
|
can_compile("(require [tests.resources.tlib [qplah :as quiz parald]])")
|
||||||
|
cant_compile("(require [tests.resources.tlib])")
|
||||||
|
cant_compile("(require [tests.resources.tlib [* qplah]])")
|
||||||
|
cant_compile("(require [tests.resources.tlib [qplah *]])")
|
||||||
|
cant_compile("(require [tests.resources.tlib [* *]])")
|
||||||
|
|
||||||
|
|
||||||
def test_ast_good_get():
|
def test_ast_good_get():
|
||||||
"Make sure AST can compile valid get"
|
"Make sure AST can compile valid get"
|
||||||
can_compile("(get x y)")
|
can_compile("(get x y)")
|
||||||
@ -397,6 +411,7 @@ def test_lambda_list_keywords_rest():
|
|||||||
""" Ensure we can compile functions with lambda list keywords."""
|
""" Ensure we can compile functions with lambda list keywords."""
|
||||||
can_compile("(fn (x &rest xs) (print xs))")
|
can_compile("(fn (x &rest xs) (print xs))")
|
||||||
cant_compile("(fn (x &rest xs &rest ys) (print xs))")
|
cant_compile("(fn (x &rest xs &rest ys) (print xs))")
|
||||||
|
can_compile("(fn (&optional a &rest xs) (print xs))")
|
||||||
|
|
||||||
|
|
||||||
def test_lambda_list_keywords_key():
|
def test_lambda_list_keywords_key():
|
||||||
@ -410,6 +425,7 @@ def test_lambda_list_keywords_kwargs():
|
|||||||
""" Ensure we can compile functions with &kwargs."""
|
""" Ensure we can compile functions with &kwargs."""
|
||||||
can_compile("(fn (x &kwargs kw) (list x kw))")
|
can_compile("(fn (x &kwargs kw) (list x kw))")
|
||||||
cant_compile("(fn (x &kwargs xs &kwargs ys) (list x xs ys))")
|
cant_compile("(fn (x &kwargs xs &kwargs ys) (list x xs ys))")
|
||||||
|
can_compile("(fn (&optional x &kwargs kw) (list x kw))")
|
||||||
|
|
||||||
|
|
||||||
def test_lambda_list_keywords_kwonly():
|
def test_lambda_list_keywords_kwonly():
|
||||||
|
@ -230,6 +230,16 @@ def test_sets():
|
|||||||
HyExpression([HySymbol("baz"), HySymbol("quux")])
|
HyExpression([HySymbol("baz"), HySymbol("quux")])
|
||||||
])]
|
])]
|
||||||
|
|
||||||
|
# Duplicate items in a literal set should be okay (and should
|
||||||
|
# be preserved).
|
||||||
|
objs = tokenize("#{1 2 1 1 2 1}")
|
||||||
|
assert objs == [HySet([HyInteger(n) for n in [1, 2, 1, 1, 2, 1]])]
|
||||||
|
assert len(objs[0]) == 6
|
||||||
|
|
||||||
|
# https://github.com/hylang/hy/issues/1120
|
||||||
|
objs = tokenize("#{a 1}")
|
||||||
|
assert objs == [HySet([HySymbol("a"), HyInteger(1)])]
|
||||||
|
|
||||||
|
|
||||||
def test_nospace():
|
def test_nospace():
|
||||||
""" Ensure we can tokenize without spaces if we have to """
|
""" Ensure we can tokenize without spaces if we have to """
|
||||||
|
@ -5,4 +5,4 @@ hyset = HySet([3, 1, 2, 2])
|
|||||||
|
|
||||||
|
|
||||||
def test_set():
|
def test_set():
|
||||||
assert hyset == [1, 2, 3]
|
assert hyset == [3, 1, 2, 2]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(require hy.contrib.alias)
|
(require [hy.contrib.alias [defn-alias]])
|
||||||
|
|
||||||
(defn test-defn-alias []
|
(defn test-defn-alias []
|
||||||
(defn-alias [tda-main tda-a1 tda-a2] [] :bazinga)
|
(defn-alias [tda-main tda-a1 tda-a2] [] :bazinga)
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
;; DEALINGS IN THE SOFTWARE.
|
;; DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
(import [hy.errors [HyMacroExpansionError]])
|
(import [hy.errors [HyMacroExpansionError]])
|
||||||
(require hy.contrib.anaphoric)
|
(require [hy.contrib.anaphoric [*]])
|
||||||
|
|
||||||
;;;; some simple helpers
|
;;;; some simple helpers
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
(import [hy.contrib.botsbuildbots [*]])
|
(require [hy.contrib.botsbuildbots [Botsbuildbots]])
|
||||||
(require hy.contrib.botsbuildbots)
|
|
||||||
|
|
||||||
(defn test-botsbuildbots []
|
(defn test-botsbuildbots []
|
||||||
(assert (> (len (first (Botsbuildbots))) 50)))
|
(assert (> (len (first (Botsbuildbots))) 50)))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(require hy.contrib.curry)
|
(require [hy.contrib.curry [defnc]])
|
||||||
|
|
||||||
|
|
||||||
(defnc s [x y z] ((x z) (y z))) ; λxyz.xz(yz)
|
(defnc s [x y z] ((x z) (y z))) ; λxyz.xz(yz)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(require hy.contrib.loop)
|
(require [hy.contrib.loop [loop]])
|
||||||
(import sys)
|
(import sys)
|
||||||
|
|
||||||
(defn tco-sum [x y]
|
(defn tco-sum [x y]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
(require hy.contrib.meth)
|
(require [hy.contrib.meth [route post-route put-route delete-route]])
|
||||||
|
|
||||||
(defclass FakeMeth []
|
(defclass FakeMeth []
|
||||||
"Mocking decorator class"
|
"Mocking decorator class"
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
;; 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.
|
||||||
|
|
||||||
(require hy.contrib.multi)
|
(require [hy.contrib.multi [defmulti]])
|
||||||
|
|
||||||
|
|
||||||
(defn test-different-signatures []
|
(defn test-different-signatures []
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
;; 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.
|
||||||
|
|
||||||
|
(import [hy._compat [PY3]])
|
||||||
|
|
||||||
;;;; some simple helpers
|
;;;; some simple helpers
|
||||||
|
|
||||||
(defn assert-true [x]
|
(defn assert-true [x]
|
||||||
@ -33,6 +35,12 @@
|
|||||||
(defn assert-nil [x]
|
(defn assert-nil [x]
|
||||||
(assert (is x nil)))
|
(assert (is x nil)))
|
||||||
|
|
||||||
|
(defn assert-requires-num [f]
|
||||||
|
(for [x ["foo" [] None]]
|
||||||
|
(try (f x)
|
||||||
|
(except [TypeError] True)
|
||||||
|
(else (assert False)))))
|
||||||
|
|
||||||
(defn test-coll? []
|
(defn test-coll? []
|
||||||
"NATIVE: testing coll?"
|
"NATIVE: testing coll?"
|
||||||
(assert-true (coll? [1 2 3]))
|
(assert-true (coll? [1 2 3]))
|
||||||
@ -66,12 +74,7 @@
|
|||||||
(assert-equal 0 (dec 1))
|
(assert-equal 0 (dec 1))
|
||||||
(assert-equal -1 (dec 0))
|
(assert-equal -1 (dec 0))
|
||||||
(assert-equal 0 (dec (dec 2)))
|
(assert-equal 0 (dec (dec 2)))
|
||||||
(try (do (dec "foo") (assert False))
|
(assert-requires-num dec))
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (do (dec []) (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (do (dec None) (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
|
||||||
|
|
||||||
(defn test-setv []
|
(defn test-setv []
|
||||||
"NATIVE: testing setv mutation"
|
"NATIVE: testing setv mutation"
|
||||||
@ -173,12 +176,7 @@
|
|||||||
(assert-true (even? -2))
|
(assert-true (even? -2))
|
||||||
(assert-false (even? 1))
|
(assert-false (even? 1))
|
||||||
(assert-true (even? 0))
|
(assert-true (even? 0))
|
||||||
(try (even? "foo")
|
(assert-requires-num even?))
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (even? [])
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (even? None)
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
|
||||||
|
|
||||||
(defn test-every? []
|
(defn test-every? []
|
||||||
"NATIVE: testing the every? function"
|
"NATIVE: testing the every? function"
|
||||||
@ -263,12 +261,11 @@
|
|||||||
"NATIVE: testing the inc function"
|
"NATIVE: testing the inc function"
|
||||||
(assert-equal 3 (inc 2))
|
(assert-equal 3 (inc 2))
|
||||||
(assert-equal 0 (inc -1))
|
(assert-equal 0 (inc -1))
|
||||||
(try (do (inc "foo") (assert False))
|
(assert-requires-num inc)
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (do (inc []) (assert False))
|
(defclass X [object]
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
[__add__ (fn [self other] (.format "__add__ got {}" other))])
|
||||||
(try (do (inc None) (assert False))
|
(assert-equal (inc (X)) "__add__ got 1"))
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
|
||||||
|
|
||||||
(defn test-instance []
|
(defn test-instance []
|
||||||
"NATIVE: testing instance? function"
|
"NATIVE: testing instance? function"
|
||||||
@ -394,24 +391,14 @@
|
|||||||
(assert-true (neg? -2))
|
(assert-true (neg? -2))
|
||||||
(assert-false (neg? 1))
|
(assert-false (neg? 1))
|
||||||
(assert-false (neg? 0))
|
(assert-false (neg? 0))
|
||||||
(try (do (neg? "foo") (assert False))
|
(when PY3
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
(assert-requires-num neg?)))
|
||||||
(try (do (neg? []) (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (do (neg? None) (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
|
||||||
|
|
||||||
(defn test-zero []
|
(defn test-zero []
|
||||||
"NATIVE: testing the zero? function"
|
"NATIVE: testing the zero? function"
|
||||||
(assert-false (zero? -2))
|
(assert-false (zero? -2))
|
||||||
(assert-false (zero? 1))
|
(assert-false (zero? 1))
|
||||||
(assert-true (zero? 0))
|
(assert-true (zero? 0)))
|
||||||
(try (do (zero? "foo") (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (do (zero? []) (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (do (zero? None) (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
|
||||||
|
|
||||||
(defn test-none []
|
(defn test-none []
|
||||||
"NATIVE: testing for `is None`"
|
"NATIVE: testing for `is None`"
|
||||||
@ -463,12 +450,7 @@
|
|||||||
(assert-true (odd? -3))
|
(assert-true (odd? -3))
|
||||||
(assert-true (odd? 1))
|
(assert-true (odd? 1))
|
||||||
(assert-false (odd? 0))
|
(assert-false (odd? 0))
|
||||||
(try (do (odd? "foo") (assert False))
|
(assert-requires-num odd?))
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (do (odd? []) (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (do (odd? None) (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
|
||||||
|
|
||||||
(defn test-partition []
|
(defn test-partition []
|
||||||
"NATIVE: testing the partition function"
|
"NATIVE: testing the partition function"
|
||||||
@ -500,12 +482,8 @@
|
|||||||
(assert-true (pos? 2))
|
(assert-true (pos? 2))
|
||||||
(assert-false (pos? -1))
|
(assert-false (pos? -1))
|
||||||
(assert-false (pos? 0))
|
(assert-false (pos? 0))
|
||||||
(try (do (pos? "foo") (assert False))
|
(when PY3
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
(assert-requires-num pos?)))
|
||||||
(try (do (pos? []) (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
|
||||||
(try (do (pos? None) (assert False))
|
|
||||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
|
||||||
|
|
||||||
(defn test-remove []
|
(defn test-remove []
|
||||||
"NATIVE: testing the remove function"
|
"NATIVE: testing the remove function"
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
(defn test-sets []
|
(defn test-sets []
|
||||||
"NATIVE: test sets work right"
|
"NATIVE: test sets work right"
|
||||||
(assert (= #{1 2 3 4} (| #{1 2} #{3 4})))
|
(assert (= #{1 2 3 4} (| #{1 2} #{3 4})))
|
||||||
|
(assert (= (type #{1 2 3 4}) set))
|
||||||
(assert (= #{} (set))))
|
(assert (= #{} (set))))
|
||||||
|
|
||||||
|
|
||||||
@ -587,6 +588,29 @@
|
|||||||
["X" "B" "C" "D"])))
|
["X" "B" "C" "D"])))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-as-threading []
|
||||||
|
"NATIVE: test as threading macro"
|
||||||
|
(setv data [{:name "hooded cuttlefish"
|
||||||
|
:classification {:subgenus "Acanthosepion"
|
||||||
|
:species "Sepia prashadi"}
|
||||||
|
:discovered {:year 1936
|
||||||
|
:name "Ronald Winckworth"}}
|
||||||
|
{:name "slender cuttlefish"
|
||||||
|
:classification {:subgenus "Doratosepion"
|
||||||
|
:species "Sepia braggi"}
|
||||||
|
:discovered {:year 1907
|
||||||
|
:name "Sir Joseph Cooke Verco"}}])
|
||||||
|
(assert (= (as-> (first data) x
|
||||||
|
(:name x))
|
||||||
|
"hooded cuttlefish"))
|
||||||
|
(assert (= (as-> (filter (fn [entry] (= (:name entry)
|
||||||
|
"slender cuttlefish")) data) x
|
||||||
|
(first x)
|
||||||
|
(:discovered x)
|
||||||
|
(:name x))
|
||||||
|
"Sir Joseph Cooke Verco")))
|
||||||
|
|
||||||
|
|
||||||
(defn test-assoc []
|
(defn test-assoc []
|
||||||
"NATIVE: test assoc"
|
"NATIVE: test assoc"
|
||||||
(setv vals {"one" "two"})
|
(setv vals {"one" "two"})
|
||||||
@ -1100,11 +1124,34 @@
|
|||||||
|
|
||||||
(defn test-require []
|
(defn test-require []
|
||||||
"NATIVE: test requiring macros from python code"
|
"NATIVE: test requiring macros from python code"
|
||||||
(try
|
(try (qplah 1 2 3 4)
|
||||||
(assert (= "this won't happen" (qplah 1 2 3 4)))
|
(except [NameError] True)
|
||||||
(except [NameError]))
|
(else (assert False)))
|
||||||
|
(try (parald 1 2 3 4)
|
||||||
|
(except [NameError] True)
|
||||||
|
(else (assert False)))
|
||||||
|
(require [tests.resources.tlib [qplah]])
|
||||||
|
(assert (= (qplah 1 2 3) [8 1 2 3]))
|
||||||
|
(try (parald 1 2 3 4)
|
||||||
|
(except [NameError] True)
|
||||||
|
(else (assert False)))
|
||||||
(require tests.resources.tlib)
|
(require tests.resources.tlib)
|
||||||
(assert (= [1 2 3] (qplah 1 2 3))))
|
(assert (= (tests.resources.tlib.parald 1 2 3) [9 1 2 3]))
|
||||||
|
(try (parald 1 2 3 4)
|
||||||
|
(except [NameError] True)
|
||||||
|
(else (assert False)))
|
||||||
|
(require [tests.resources.tlib :as T])
|
||||||
|
(assert (= (T.parald 1 2 3) [9 1 2 3]))
|
||||||
|
(try (parald 1 2 3 4)
|
||||||
|
(except [NameError] True)
|
||||||
|
(else (assert False)))
|
||||||
|
(require [tests.resources.tlib [parald :as p]])
|
||||||
|
(assert (= (p 1 2 3) [9 1 2 3]))
|
||||||
|
(try (parald 1 2 3 4)
|
||||||
|
(except [NameError] True)
|
||||||
|
(else (assert False)))
|
||||||
|
(require [tests.resources.tlib [*]])
|
||||||
|
(assert (= (parald 1 2 3) [9 1 2 3])))
|
||||||
|
|
||||||
|
|
||||||
(defn test-require-native []
|
(defn test-require-native []
|
||||||
@ -1124,7 +1171,7 @@
|
|||||||
(assert (= x [3 2 1]))
|
(assert (= x [3 2 1]))
|
||||||
"success")
|
"success")
|
||||||
(except [NameError] "failure"))))
|
(except [NameError] "failure"))))
|
||||||
(require tests.native_tests.native_macros)
|
(require [tests.native_tests.native_macros [rev]])
|
||||||
(assert (= "success"
|
(assert (= "success"
|
||||||
(try
|
(try
|
||||||
(do (setv x [])
|
(do (setv x [])
|
||||||
|
@ -28,6 +28,18 @@
|
|||||||
(assert (= 0 (+)))))
|
(assert (= 0 (+)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-add-unary []
|
||||||
|
"NATIVE: test that unary + calls __pos__"
|
||||||
|
|
||||||
|
(defclass X [object]
|
||||||
|
[__pos__ (fn [self] "called __pos__")])
|
||||||
|
(assert (= (+ (X)) "called __pos__"))
|
||||||
|
|
||||||
|
; Make sure the shadowed version works, too.
|
||||||
|
(setv f +)
|
||||||
|
(assert (= (f (X)) "called __pos__")))
|
||||||
|
|
||||||
|
|
||||||
(setv test_div (fn []
|
(setv test_div (fn []
|
||||||
"NATIVE: Test division"
|
"NATIVE: Test division"
|
||||||
(assert (= 25 (/ 100 2 2)))
|
(assert (= 25 (/ 100 2 2)))
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
(import [hy.errors [HyTypeError]])
|
||||||
|
|
||||||
(defmacro rev [&rest body]
|
(defmacro rev [&rest body]
|
||||||
"Execute the `body` statements in reverse"
|
"Execute the `body` statements in reverse"
|
||||||
(quasiquote (do (unquote-splice (list (reversed body))))))
|
(quasiquote (do (unquote-splice (list (reversed body))))))
|
||||||
@ -37,6 +39,9 @@
|
|||||||
(defmacro a-dict [] {1 2})
|
(defmacro a-dict [] {1 2})
|
||||||
(assert (= (a-dict) {1 2}))
|
(assert (= (a-dict) {1 2}))
|
||||||
|
|
||||||
|
(defmacro a-set [] #{1 2})
|
||||||
|
(assert (= (a-set) #{1 2}))
|
||||||
|
|
||||||
(defmacro a-none [])
|
(defmacro a-none [])
|
||||||
(assert (= (a-none) None))
|
(assert (= (a-none) None))
|
||||||
|
|
||||||
@ -48,6 +53,26 @@
|
|||||||
(defmacro bar [x y]
|
(defmacro bar [x y]
|
||||||
(foo x y))
|
(foo x y))
|
||||||
|
|
||||||
|
(defn test-macro-kw []
|
||||||
|
"NATIVE: test that an error is raised when &kwonly, &kwargs, or &key is used in a macro"
|
||||||
|
(try
|
||||||
|
(eval '(defmacro f [&kwonly a b]))
|
||||||
|
(except [e HyTypeError]
|
||||||
|
(assert (= e.message "macros cannot use &kwonly")))
|
||||||
|
(else (assert false)))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(eval '(defmacro f [&kwargs kw]))
|
||||||
|
(except [e HyTypeError]
|
||||||
|
(assert (= e.message "macros cannot use &kwargs")))
|
||||||
|
(else (assert false)))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(eval '(defmacro f [&key {"kw" "xyz"}]))
|
||||||
|
(except [e HyTypeError]
|
||||||
|
(assert (= e.message "macros cannot use &key")))
|
||||||
|
(else (assert false))))
|
||||||
|
|
||||||
(defn test-fn-calling-macro []
|
(defn test-fn-calling-macro []
|
||||||
"NATIVE: test macro calling a plain function"
|
"NATIVE: test macro calling a plain function"
|
||||||
(assert (= 3 (bar 1 2))))
|
(assert (= 3 (bar 1 2))))
|
||||||
|
@ -8,13 +8,9 @@
|
|||||||
(assert (= (x 1 2 3 4) 10))
|
(assert (= (x 1 2 3 4) 10))
|
||||||
(assert (= (x 1 2 3 4 5) 15))
|
(assert (= (x 1 2 3 4 5) 15))
|
||||||
; with strings
|
; with strings
|
||||||
(assert (= (x "a")
|
|
||||||
"a"))
|
|
||||||
(assert (= (x "a" "b" "c")
|
(assert (= (x "a" "b" "c")
|
||||||
"abc"))
|
"abc"))
|
||||||
; with lists
|
; with lists
|
||||||
(assert (= (x ["a"])
|
|
||||||
["a"]))
|
|
||||||
(assert (= (x ["a"] ["b"] ["c"])
|
(assert (= (x ["a"] ["b"] ["c"])
|
||||||
["a" "b" "c"]))))
|
["a" "b" "c"]))))
|
||||||
|
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
from hy.macros import macro
|
from hy.macros import macro
|
||||||
from hy import HyList
|
from hy import HyList, HyInteger
|
||||||
|
|
||||||
|
|
||||||
@macro("qplah")
|
@macro("qplah")
|
||||||
def tmac(*tree):
|
def tmac(*tree):
|
||||||
return HyList(tree)
|
return HyList((HyInteger(8), ) + tree)
|
||||||
|
|
||||||
|
|
||||||
|
@macro("parald")
|
||||||
|
def tmac2(*tree):
|
||||||
|
return HyList((HyInteger(9), ) + tree)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user