Merge branch 'master' into pr/864
This commit is contained in:
commit
5a34285b08
@ -6,6 +6,8 @@ omit =
|
||||
*/site-packages/nose/*
|
||||
*/pypy/*
|
||||
|
||||
|
||||
[report]
|
||||
exclude_lines =
|
||||
# Have to re-enable the standard pragma
|
||||
pragma: no cover
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@
|
||||
dist
|
||||
.coverage
|
||||
build/
|
||||
.noseids
|
||||
|
2
AUTHORS
2
AUTHORS
@ -63,3 +63,5 @@
|
||||
* Nicolas Pénet <z.nicolas@gmail.com>
|
||||
* Adrià Garriga Alonso <adria@monkingme.com>
|
||||
* Antony Woods <antony@teamwoods.org>
|
||||
* Matthew Egan Odendahl <github.gilch@xoxy.net>
|
||||
* Tim Martin <tim@asymptotic.co.uk>
|
||||
|
6
NEWS
6
NEWS
@ -7,7 +7,7 @@ Changes from 0.10.1
|
||||
* yield-from support for Python 2
|
||||
* with-decorator can now be applied to classes.
|
||||
* assert now accepts an optional assertion message.
|
||||
* Comparision operators can now be used with map, filter, and reduce.
|
||||
* Comparison operators can now be used with map, filter, and reduce.
|
||||
* new last function
|
||||
* new drop-last function
|
||||
* new lisp-if-not/lif-not macro
|
||||
@ -73,7 +73,7 @@ Changes from 0.10.0
|
||||
[ Misc. Fixes ]
|
||||
* Symbols like true, false, none can't be assigned
|
||||
* Set sys.argv default to [''] like Python does
|
||||
* REPL displays the the python version and platform at startup
|
||||
* REPL displays the python version and platform at startup
|
||||
* Dockerfile added for https://registry.hub.docker.com/_/hylang/
|
||||
|
||||
[ Contrib changes ]
|
||||
@ -328,7 +328,7 @@ Changes from Hy 0.9.7
|
||||
expand things in quotes.
|
||||
* kwapply now works with symbols as well as raw dicts. (ND)
|
||||
* Try / Except will now return properly again. (PT)
|
||||
* Bare-names sprinked around the AST won't show up anymore (ND)
|
||||
* Bare-names sprinkled around the AST won't show up anymore (ND)
|
||||
|
||||
[ Language Changes ]
|
||||
|
||||
|
@ -40,7 +40,8 @@ Project
|
||||
-------
|
||||
|
||||
* Code: https://github.com/hylang/hy
|
||||
* Docs: http://hylang.org/
|
||||
* Docs (latest, for use with bleeding-edge github version): http://hylang.org/
|
||||
* Docs (stable, for use with the PyPI version): http://docs.hylang.org/en/stable/
|
||||
* Quickstart: http://hylang.org/en/latest/quickstart.html
|
||||
* Bug reports: We have no bugs! Your bugs are your own! (https://github.com/hylang/hy/issues)
|
||||
* License: MIT (Expat)
|
||||
|
60
docs/contrib/alias.rst
Normal file
60
docs/contrib/alias.rst
Normal file
@ -0,0 +1,60 @@
|
||||
============
|
||||
Alias macros
|
||||
============
|
||||
|
||||
.. versionadded:: 0.12
|
||||
|
||||
The alias macro module provides the ``(defn-alias)`` and
|
||||
``(defmacro-alias)``, that were in Hy core previously.
|
||||
|
||||
|
||||
Macros
|
||||
======
|
||||
|
||||
|
||||
.. _defn-alias:
|
||||
|
||||
defn-alias
|
||||
------------------------
|
||||
|
||||
The ``defn-alias`` macro is much like ``defn``,
|
||||
with the distinction that instead of defining a function with a single
|
||||
name, these can also define aliases. Other than taking a list of
|
||||
symbols for function names as the first parameter, ``defn-alias``
|
||||
is no different from ``defn``.
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (defn-alias [main-name alias] []
|
||||
... (print "Hello!"))
|
||||
=> (main-name)
|
||||
"Hello!"
|
||||
=> (alias)
|
||||
"Hello!"
|
||||
|
||||
|
||||
.. _defmacro-alias:
|
||||
|
||||
defmacro-alias
|
||||
--------------
|
||||
|
||||
``defmacro-alias`` is used to define macros with multiple names
|
||||
(aliases). The general format is ``(defmacro-alias [names] [parameters]
|
||||
expr)``. It creates multiple macros with the same parameter list and
|
||||
body, under the specified list of names.
|
||||
|
||||
The following example defines two macros, both of which allow the user
|
||||
to write code in infix notation.
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (defmacro-alias [infix infi] [code]
|
||||
... (quasiquote (
|
||||
... (unquote (get code 1))
|
||||
... (unquote (get code 0))
|
||||
... (unquote (get code 2)))))
|
||||
|
||||
=> (infix (1 + 1))
|
||||
2
|
||||
=> (infi (1 + 1))
|
||||
2
|
@ -13,14 +13,11 @@ concise and easy to read.
|
||||
|
||||
-- Wikipedia (http://en.wikipedia.org/wiki/Anaphoric_macro)
|
||||
|
||||
Macros
|
||||
======
|
||||
|
||||
|
||||
.. _ap-if:
|
||||
|
||||
ap-if
|
||||
-------
|
||||
=====
|
||||
|
||||
Usage: ``(ap-if (foo) (print it))``
|
||||
|
||||
@ -31,7 +28,7 @@ true and false branches.
|
||||
.. _ap-each:
|
||||
|
||||
ap-each
|
||||
-------
|
||||
=======
|
||||
|
||||
Usage: ``(ap-each [1 2 3 4 5] (print it))``
|
||||
|
||||
@ -228,3 +225,24 @@ Returns a function which applies several forms in series from left to right. The
|
||||
=> (def op (ap-compose (+ it 1) (* it 3)))
|
||||
=> (op 2)
|
||||
9
|
||||
|
||||
.. _xi
|
||||
|
||||
xi
|
||||
==
|
||||
|
||||
Usage ``(xi body ...)``
|
||||
|
||||
Returns a function with parameters implicitly determined by the presence in the body of xi parameters. An xi symbol designates the ith parameter (1-based, e.g. x1, x2, x3, etc.), or all remaining parameters for xi itself. This is not a replacement for lambda. The xi forms cannot be nested.
|
||||
|
||||
This is similar to Clojure's anonymous function literals (``#()``).
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> ((xi identity [x1 x5 [x2 x3] xi x4]) 1 2 3 4 5 6 7 8)
|
||||
[1, 5, [2, 3,] (6, 7, 8), 4]
|
||||
=> (def add-10 (xi + 10 x1))
|
||||
=> (add-10 6)
|
||||
16
|
||||
|
||||
|
||||
|
@ -11,3 +11,4 @@ Contents:
|
||||
loop
|
||||
multi
|
||||
flow
|
||||
alias
|
||||
|
@ -37,7 +37,7 @@ loop
|
||||
``loop`` establishes a recursion point. With ``loop``, ``recur``
|
||||
rebinds the variables set in the recursion point and sends code
|
||||
execution back to that recursion point. If ``recur`` is used in a
|
||||
non-tail position, an exception is thrown.
|
||||
non-tail position, an exception is raised.
|
||||
|
||||
Usage: `(loop bindings &rest body)`
|
||||
|
||||
|
@ -31,6 +31,21 @@ languages.
|
||||
that symbols with dashes will shadow their underscore equivalents, and vice
|
||||
versa.
|
||||
|
||||
Notes on Syntax
|
||||
===============
|
||||
|
||||
integers
|
||||
--------
|
||||
|
||||
.. versionadded:: 0.11.1
|
||||
|
||||
In addition to regular numbers, standard notation from Python 3 for non-base 10
|
||||
integers is used. ``0x`` for Hex, ``0o`` for Octal, ``0b`` for Binary.
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
(print 0x80 0b11101 0o102 30)
|
||||
|
||||
|
||||
Built-Ins
|
||||
=========
|
||||
@ -63,10 +78,10 @@ Compiles down to:
|
||||
which to do the attribute dereference. It uses bare symbols as attributes
|
||||
to access (in the example, *bar*, *baz*, *frob*), and compiles the contents
|
||||
of lists (in the example, ``[(+ 1 2)]``) for indexation. Other arguments
|
||||
throw a compilation error.
|
||||
raise a compilation error.
|
||||
|
||||
Access to unknown attributes throws an :exc:`AttributeError`. Access to
|
||||
unknown keys throws an :exc:`IndexError` (on lists and tuples) or a
|
||||
Access to unknown attributes raises an :exc:`AttributeError`. Access to
|
||||
unknown keys raises an :exc:`IndexError` (on lists and tuples) or a
|
||||
:exc:`KeyError` (on dictionaries).
|
||||
|
||||
->
|
||||
@ -100,8 +115,10 @@ it appends it as the last argument. The following code demonstrates this:
|
||||
apply
|
||||
-----
|
||||
|
||||
``apply`` is used to apply an optional list of arguments and an optional
|
||||
dictionary of kwargs to a function.
|
||||
``apply`` is used to apply an optional list of arguments and an
|
||||
optional dictionary of kwargs to a function. The symbol mangling
|
||||
transformations will be applied to all keys in the dictionary of
|
||||
kwargs, provided the dictionary and its keys are defined in-place.
|
||||
|
||||
Usage: ``(apply fn-name [args] [kwargs])``
|
||||
|
||||
@ -127,6 +144,8 @@ Examples:
|
||||
(apply total-purchase [] {"price" 10 "amount" 15 "vat" 1.05})
|
||||
;=> 165.375
|
||||
|
||||
(apply total-purchase [] {:price 10 :amount 15 :vat 1.05})
|
||||
;=> 165.375
|
||||
|
||||
and
|
||||
---
|
||||
@ -194,17 +213,17 @@ Examples of usage:
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=>(let [[collection {}]]
|
||||
=>(let [collection {}]
|
||||
... (assoc collection "Dog" "Bark")
|
||||
... (print collection))
|
||||
{u'Dog': u'Bark'}
|
||||
|
||||
=>(let [[collection {}]]
|
||||
=>(let [collection {}]
|
||||
... (assoc collection "Dog" "Bark" "Cat" "Meow")
|
||||
... (print collection))
|
||||
{u'Cat': u'Meow', u'Dog': u'Bark'}
|
||||
|
||||
=>(let [[collection [1 2 3 4]]]
|
||||
=>(let [collection [1 2 3 4]]
|
||||
... (assoc collection 2 None)
|
||||
... (print collection))
|
||||
[1, 2, None, 4]
|
||||
@ -267,11 +286,10 @@ is only called on every other value in the list.
|
||||
;; collection is a list of numerical values
|
||||
|
||||
(for [x collection]
|
||||
(do
|
||||
(side-effect1 x)
|
||||
(if (% x 2)
|
||||
(continue))
|
||||
(side-effect2 x)))
|
||||
(side-effect1 x)
|
||||
(if (% x 2)
|
||||
(continue))
|
||||
(side-effect2 x))
|
||||
|
||||
|
||||
dict-comp
|
||||
@ -289,10 +307,10 @@ conditional expression.
|
||||
{1: 2, 3: 6, 9: 18, 5: 10, 7: 14}
|
||||
|
||||
|
||||
do / progn
|
||||
do
|
||||
----------
|
||||
|
||||
``do`` and `progn` are used to evaluate each of their arguments and return the
|
||||
``do`` is used to evaluate each of its arguments and return the
|
||||
last one. Return values from every other than the last argument are discarded.
|
||||
It can be used in ``lambda`` or ``list-comp`` to perform more complex logic as
|
||||
shown in one of the following examples.
|
||||
@ -334,6 +352,18 @@ For example:
|
||||
=> (counter [1 2 3 4 5 2 3] 2)
|
||||
2
|
||||
|
||||
They can be used to assign multiple variables at once:
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> (setv a 1 b 2)
|
||||
(1L, 2L)
|
||||
=> a
|
||||
1L
|
||||
=> b
|
||||
2L
|
||||
=>
|
||||
|
||||
|
||||
defclass
|
||||
--------
|
||||
@ -345,7 +375,9 @@ attributes of the new class as two item vectors.
|
||||
.. code-block:: clj
|
||||
|
||||
(defclass class-name [super-class-1 super-class-2]
|
||||
[[attribute value]])
|
||||
[attribute value]
|
||||
|
||||
(defn method [self] (print "hello!")))
|
||||
|
||||
Both values and functions can be bound on the new class as shown by the example
|
||||
below:
|
||||
@ -353,9 +385,10 @@ below:
|
||||
.. code-block:: clj
|
||||
|
||||
=> (defclass Cat []
|
||||
... [[age None]
|
||||
... [colour "white"]
|
||||
... [speak (fn [self] (print "Meow"))]])
|
||||
... [age None
|
||||
... colour "white"]
|
||||
...
|
||||
... (defn speak [self] (print "Meow")))
|
||||
|
||||
=> (def spot (Cat))
|
||||
=> (setv spot.colour "Black")
|
||||
@ -366,10 +399,10 @@ below:
|
||||
|
||||
.. _defn:
|
||||
|
||||
defn / defun
|
||||
defn
|
||||
------------
|
||||
|
||||
``defn`` and ``defun`` macros are used to define functions. They take three
|
||||
``defn`` macro is used to define functions. It takes three
|
||||
parameters: the *name* of the function to define, a vector of *parameters*,
|
||||
and the *body* of the function:
|
||||
|
||||
@ -430,8 +463,8 @@ Parameters may have the following keywords in front of them:
|
||||
.. code-block:: clj
|
||||
|
||||
=> (defn zig-zag-sum [&rest numbers]
|
||||
(let [[odd-numbers (list-comp x [x numbers] (odd? x))]
|
||||
[even-numbers (list-comp x [x numbers] (even? x))]]
|
||||
(let [odd-numbers (list-comp x [x numbers] (odd? x))
|
||||
even-numbers (list-comp x [x numbers] (even? x))]
|
||||
(- (sum odd-numbers) (sum even-numbers))))
|
||||
|
||||
=> (zig-zag-sum)
|
||||
@ -453,7 +486,7 @@ Parameters may have the following keywords in front of them:
|
||||
.. code-block:: clj
|
||||
|
||||
=> (defn compare [a b &kwonly keyfn [reverse false]]
|
||||
... (let [[result (keyfn a b)]]
|
||||
... (let [result (keyfn a b)]
|
||||
... (if (not reverse)
|
||||
... result
|
||||
... (- result))))
|
||||
@ -476,28 +509,6 @@ Parameters may have the following keywords in front of them:
|
||||
|
||||
Availability: Python 3.
|
||||
|
||||
.. _defn-alias / defun-alias:
|
||||
|
||||
defn-alias / defun-alias
|
||||
------------------------
|
||||
|
||||
.. versionadded:: 0.10.0
|
||||
|
||||
The ``defn-alias`` and ``defun-alias`` macros are much like `defn`_,
|
||||
with the distinction that instead of defining a function with a single
|
||||
name, these can also define aliases. Other than taking a list of
|
||||
symbols for function names as the first parameter, ``defn-alias`` and
|
||||
``defun-alias`` are no different from ``defn`` and ``defun``.
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (defn-alias [main-name alias] []
|
||||
... (print "Hello!"))
|
||||
=> (main-name)
|
||||
"Hello!"
|
||||
=> (alias)
|
||||
"Hello!"
|
||||
|
||||
|
||||
defmain
|
||||
-------
|
||||
@ -559,31 +570,6 @@ between the operands.
|
||||
=> (infix (1 + 1))
|
||||
2
|
||||
|
||||
.. _defmacro-alias:
|
||||
|
||||
defmacro-alias
|
||||
--------------
|
||||
|
||||
``defmacro-alias`` is used to define macros with multiple names
|
||||
(aliases). The general format is ``(defmacro-alias [names] [parameters]
|
||||
expr)``. It creates multiple macros with the same parameter list and
|
||||
body, under the specified list of names.
|
||||
|
||||
The following example defines two macros, both of which allow the user
|
||||
to write code in infix notation.
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (defmacro-alias [infix infi] [code]
|
||||
... (quasiquote (
|
||||
... (unquote (get code 1))
|
||||
... (unquote (get code 0))
|
||||
... (unquote (get code 2)))))
|
||||
|
||||
=> (infix (1 + 1))
|
||||
2
|
||||
=> (infi (1 + 1))
|
||||
2
|
||||
|
||||
.. _defmacro/g!:
|
||||
|
||||
@ -645,7 +631,7 @@ del
|
||||
=> (setv test (list (range 10)))
|
||||
=> test
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
=> (del (slice test 2 4)) ;; remove items from 2 to 4 excluded
|
||||
=> (del (cut test 2 4)) ;; remove items from 2 to 4 excluded
|
||||
=> test
|
||||
[0, 1, 4, 5, 6, 7, 8, 9]
|
||||
=> (setv dic {"foo" "bar"})
|
||||
@ -800,8 +786,8 @@ list. Example usage:
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (let [[animals {"dog" "bark" "cat" "meow"}]
|
||||
... [numbers ["zero" "one" "two" "three"]]]
|
||||
=> (let [animals {"dog" "bark" "cat" "meow"}
|
||||
... numbers ["zero" "one" "two" "three"]]
|
||||
... (print (get animals "dog"))
|
||||
... (print (get numbers 2)))
|
||||
bark
|
||||
@ -823,7 +809,7 @@ assign a value to a global symbol. Reading a global symbol does not require the
|
||||
|
||||
The following example shows how the global symbol ``a`` is assigned a value in a
|
||||
function and is later on printed in another function. Without the ``global``
|
||||
keyword, the second function would have thrown a ``NameError``.
|
||||
keyword, the second function would have raised a ``NameError``.
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
@ -869,47 +855,39 @@ an empty sequence, and an empty dictionary are considered ``False``; everything
|
||||
else is considered ``True``.
|
||||
|
||||
|
||||
lisp-if / lif and lisp-if-not / lif-not
|
||||
lif and lif-not
|
||||
---------------------------------------
|
||||
|
||||
.. versionadded:: 0.10.0
|
||||
|
||||
.. versionadded:: 0.11.0
|
||||
lisp-if-not / lif-not
|
||||
lif-not
|
||||
|
||||
For those that prefer a more Lispy ``if`` clause, we have ``lisp-if``, or
|
||||
For those that prefer a more Lispy ``if`` clause, we have
|
||||
``lif``. This *only* considers ``None`` / ``nil`` to be false! All other
|
||||
"false-ish" Python values are considered true. Conversely, we have
|
||||
``lisp-if-not`` and ``lif-not`` in parallel to ``if`` and ``if-not`` which
|
||||
``lif-not`` in parallel to ``if`` and ``if-not`` which
|
||||
reverses the comparison.
|
||||
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (lisp-if True "true" "false")
|
||||
"true"
|
||||
=> (lisp-if False "true" "false")
|
||||
"true"
|
||||
=> (lisp-if 0 "true" "false")
|
||||
"true"
|
||||
=> (lisp-if nil "true" "false")
|
||||
"false"
|
||||
=> (lisp-if None "true" "false")
|
||||
"false"
|
||||
=> (lisp-if-not nil "true" "false")
|
||||
"true"
|
||||
=> (lisp-if-not None "true" "false")
|
||||
"true"
|
||||
=> (lisp-if-not False "true" "false")
|
||||
"false"
|
||||
|
||||
; Equivalent but shorter
|
||||
=> (lif True "true" "false")
|
||||
"true"
|
||||
=> (lif False "true" "false")
|
||||
"true"
|
||||
=> (lif 0 "true" "false")
|
||||
"true"
|
||||
=> (lif nil "true" "false")
|
||||
"false"
|
||||
=> (lif None "true" "false")
|
||||
"false"
|
||||
=> (lif-not nil "true" "false")
|
||||
"true"
|
||||
=> (lif-not None "true" "false")
|
||||
"true"
|
||||
=> (lif-not False "true" "false")
|
||||
"false"
|
||||
|
||||
|
||||
import
|
||||
@ -1010,30 +988,24 @@ example showcases this behaviour:
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (let [[x 5]] (print x)
|
||||
... (let [[x 6]] (print x))
|
||||
=> (let [x 5] (print x)
|
||||
... (let [x 6] (print x))
|
||||
... (print x))
|
||||
5
|
||||
6
|
||||
5
|
||||
|
||||
The ``let`` macro takes two parameters: a vector defining *variables* and the
|
||||
*body* which gets executed. *variables* is a vector where each element is either
|
||||
a single variable or a vector defining a variable value pair. In the case of a
|
||||
single variable, it is assigned value ``None``; otherwise, the supplied value is
|
||||
used.
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (let [x [y 5]] (print x y))
|
||||
None 5
|
||||
The ``let`` macro takes two parameters: a vector defining *variables*
|
||||
and the *body* which gets executed. *variables* is a vector of
|
||||
variable and value pairs.
|
||||
|
||||
Note that the variable assignments are executed one by one, from left to right.
|
||||
The following example takes advantage of this:
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (let [[x 5] [y (+ x 1)]] (print x y))
|
||||
=> (let [x 5
|
||||
y (+ x 1)] (print x y))
|
||||
5 6
|
||||
|
||||
|
||||
@ -1072,15 +1044,15 @@ to modify variables through nested ``let`` or ``fn`` scopes:
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
(let [[x 0]]
|
||||
(let [x 0]
|
||||
(for [y (range 10)]
|
||||
(let [[z (inc y)]]
|
||||
(let [z (inc y)]
|
||||
(nonlocal x) ; allow the setv to "jump scope" to resolve x
|
||||
(setv x (+ x y))))
|
||||
x)
|
||||
|
||||
(defn some-function []
|
||||
(let [[x 0]]
|
||||
(let [x 0]
|
||||
(register-some-callback
|
||||
(fn [stuff]
|
||||
(nonlocal x)
|
||||
@ -1231,77 +1203,77 @@ expression.
|
||||
{1, 3, 5}
|
||||
|
||||
|
||||
slice
|
||||
cut
|
||||
-----
|
||||
|
||||
``slice`` can be used to take a subset of a list and create a new list from it.
|
||||
The form takes at least one parameter specifying the list to slice. Two
|
||||
``cut`` can be used to take a subset of a list and create a new list from it.
|
||||
The form takes at least one parameter specifying the list to cut. Two
|
||||
optional parameters can be used to give the start and end position of the
|
||||
subset. If they are not supplied, the default value of ``None`` will be used
|
||||
instead. The third optional parameter is used to control step between the elements.
|
||||
|
||||
``slice`` follows the same rules as its Python counterpart. Negative indices are
|
||||
``cut`` follows the same rules as its Python counterpart. Negative indices are
|
||||
counted starting from the end of the list. Some example usage:
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> (def collection (range 10))
|
||||
|
||||
=> (slice collection)
|
||||
=> (cut collection)
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
|
||||
=> (slice collection 5)
|
||||
=> (cut collection 5)
|
||||
[5, 6, 7, 8, 9]
|
||||
|
||||
=> (slice collection 2 8)
|
||||
=> (cut collection 2 8)
|
||||
[2, 3, 4, 5, 6, 7]
|
||||
|
||||
=> (slice collection 2 8 2)
|
||||
=> (cut collection 2 8 2)
|
||||
[2, 4, 6]
|
||||
|
||||
=> (slice collection -4 -2)
|
||||
=> (cut collection -4 -2)
|
||||
[6, 7]
|
||||
|
||||
|
||||
throw / raise
|
||||
raise
|
||||
-------------
|
||||
|
||||
The ``throw`` or ``raise`` forms can be used to raise an ``Exception`` at
|
||||
The ``raise`` form can be used to raise an ``Exception`` at
|
||||
runtime. Example usage:
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
(throw)
|
||||
(raise)
|
||||
; re-rase the last exception
|
||||
|
||||
(throw IOError)
|
||||
; Throw an IOError
|
||||
(raise IOError)
|
||||
; raise an IOError
|
||||
|
||||
(throw (IOError "foobar"))
|
||||
; Throw an IOError("foobar")
|
||||
(raise (IOError "foobar"))
|
||||
; raise an IOError("foobar")
|
||||
|
||||
|
||||
``throw`` can accept a single argument (an ``Exception`` class or instance)
|
||||
``raise`` can accept a single argument (an ``Exception`` class or instance)
|
||||
or no arguments to re-raise the last ``Exception``.
|
||||
|
||||
|
||||
try
|
||||
---
|
||||
|
||||
The ``try`` form is used to start a ``try`` / ``catch`` block. The form is
|
||||
The ``try`` form is used to start a ``try`` / ``except`` block. The form is
|
||||
used as follows:
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
(try
|
||||
(error-prone-function)
|
||||
(catch [e ZeroDivisionError] (print "Division by zero"))
|
||||
(except [e ZeroDivisionError] (print "Division by zero"))
|
||||
(else (print "no errors"))
|
||||
(finally (print "all done")))
|
||||
|
||||
``try`` must contain at least one ``catch`` block, and may optionally include
|
||||
an ``else`` or ``finally`` block. If an error is raised with a matching catch
|
||||
block during the execution of ``error-prone-function``, that ``catch`` block
|
||||
``try`` must contain at least one ``except`` block, and may optionally include
|
||||
an ``else`` or ``finally`` block. If an error is raised with a matching except
|
||||
block during the execution of ``error-prone-function``, that ``except`` block
|
||||
will be executed. If no errors are raised, the ``else`` block is executed. The
|
||||
``finally`` block will be executed last regardless of whether or not an error
|
||||
was raised.
|
||||
@ -1391,18 +1363,18 @@ manner. The archetypical example of using ``with`` is when processing files.
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
(with [[arg (expr)]] block)
|
||||
(with [arg (expr)] block)
|
||||
|
||||
(with [[(expr)]] block)
|
||||
(with [(expr)] block)
|
||||
|
||||
(with [[arg (expr)] [(expr)]] block)
|
||||
(with [arg (expr) (expr)] block)
|
||||
|
||||
The following example will open the ``NEWS`` file and print its content to the
|
||||
screen. The file is automatically closed after it has been processed.
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
(with [[f (open "NEWS")]] (print (.read f)))
|
||||
(with [f (open "NEWS")] (print (.read f)))
|
||||
|
||||
|
||||
with-decorator
|
||||
@ -1451,6 +1423,25 @@ will be 4 (``1+1 + 1+1``).
|
||||
8
|
||||
|
||||
|
||||
#@
|
||||
~~
|
||||
|
||||
.. versionadded:: 0.12.0
|
||||
|
||||
The :ref:`reader macro<reader-macros>` ``#@`` can be used as a shorthand
|
||||
for ``with-decorator``. With ``#@``, the previous example becomes:
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
=> #@(inc-decorator (defn addition [a b] (+ a b)))
|
||||
=> (addition 1 1)
|
||||
4
|
||||
=> #@(inc2-decorator inc-decorator
|
||||
... (defn addition [a b] (+ a b)))
|
||||
=> (addition 1 1)
|
||||
8
|
||||
|
||||
|
||||
.. _with-gensyms:
|
||||
|
||||
with-gensyms
|
||||
@ -1470,9 +1461,9 @@ expands to:
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
(let [[a (gensym)
|
||||
[b (gensym)
|
||||
[c (gensym)]]
|
||||
(let [a (gensym)
|
||||
b (gensym)
|
||||
c (gensym)]
|
||||
...)
|
||||
|
||||
.. seealso::
|
||||
|
@ -207,6 +207,26 @@ Returns ``True`` if *x* is a float.
|
||||
False
|
||||
|
||||
|
||||
.. _fraction-fn:
|
||||
|
||||
fraction
|
||||
--------
|
||||
|
||||
Returns a Python object of type ``fractions.Fraction``.
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> (fraction 1 2)
|
||||
Fraction(1, 2)
|
||||
|
||||
Note that Hy has a built-in fraction literal that does the same thing:
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> 1/2
|
||||
Fraction(1, 2)
|
||||
|
||||
|
||||
.. _even?-fn:
|
||||
|
||||
even?
|
||||
@ -416,6 +436,25 @@ themselves as an iterator when ``(iter x)`` is called. Contrast with
|
||||
=> (iterator? (iter {:a 1 :b 2 :c 3}))
|
||||
True
|
||||
|
||||
.. _keyword?-fn:
|
||||
|
||||
keyword?
|
||||
--------
|
||||
|
||||
.. versionadded:: 0.10.1
|
||||
|
||||
Usage: ``(keyword? foo)``
|
||||
|
||||
Check whether *foo* is a :ref:`keyword<HyKeyword>`.
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> (keyword? :foo)
|
||||
True
|
||||
|
||||
=> (setv foo 1)
|
||||
=> (keyword? foo)
|
||||
False
|
||||
|
||||
.. _list*-fn:
|
||||
|
||||
@ -651,6 +690,37 @@ Returns ``True`` if *x* is odd. Raises ``TypeError`` if
|
||||
=> (odd? 0)
|
||||
False
|
||||
|
||||
.. _partition-fn:
|
||||
|
||||
partition
|
||||
---------
|
||||
|
||||
Usage: ``(partition coll [n] [step] [fillvalue])``
|
||||
|
||||
Chunks *coll* into *n*-tuples (pairs by default).
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> (list (partition (range 10))) ; n=2
|
||||
[(, 0 1) (, 2 3) (, 4 5) (, 6 7) (, 8 9)]
|
||||
|
||||
The *step* defaults to *n*, but can be more to skip elements, or less for a sliding window with overlap.
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> (list (partition (range 10) 2 3))
|
||||
[(, 0 1) (, 3 4) (, 6 7)]
|
||||
=> (list (partition (range 5) 2 1))
|
||||
[(, 0 1) (, 1 2) (, 2 3) (, 3 4)])
|
||||
|
||||
The remainder, if any, is not included unless a *fillvalue* is specified.
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> (list (partition (range 10) 3))
|
||||
[(, 0 1 2) (, 3 4 5) (, 6 7 8)]
|
||||
=> (list (partition (range 10) 3 :fillvalue "x"))
|
||||
[(, 0 1 2) (, 3 4 5) (, 6 7 8) (, 9 "x" "x")]
|
||||
|
||||
.. _pos?-fn:
|
||||
|
||||
@ -1030,14 +1100,14 @@ if *from-file* ends before a complete expression can be parsed.
|
||||
=> ; assuming "example.hy" contains:
|
||||
=> ; (print "hello")
|
||||
=> ; (print "hyfriends!")
|
||||
=> (with [[f (open "example.hy")]]
|
||||
=> (with [f (open "example.hy")]
|
||||
... (try
|
||||
... (while true
|
||||
... (let [[exp (read f)]]
|
||||
... (let [exp (read f)]
|
||||
... (do
|
||||
... (print "OHY" exp)
|
||||
... (eval exp))))
|
||||
... (catch [e EOFError]
|
||||
... (except [e EOFError]
|
||||
... (print "EOF!"))))
|
||||
OHY ('print' 'hello')
|
||||
hello
|
||||
@ -1045,6 +1115,21 @@ if *from-file* ends before a complete expression can be parsed.
|
||||
hyfriends!
|
||||
EOF!
|
||||
|
||||
read-str
|
||||
--------
|
||||
|
||||
Usage: ``(read-str "string")``
|
||||
|
||||
This is essentially a wrapper around `read` which reads expressions from a
|
||||
string:
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> (read-str "(print 1)")
|
||||
(u'print' 1L)
|
||||
=> (eval (read-str "(print 1)"))
|
||||
1
|
||||
=>
|
||||
|
||||
.. _remove-fn:
|
||||
|
||||
@ -1168,21 +1253,3 @@ Returns an iterator from *coll* as long as *pred* returns ``True``.
|
||||
=> (list (take-while neg? [ 1 2 3 -4 5]))
|
||||
[]
|
||||
|
||||
.. _zipwith-fn:
|
||||
|
||||
zipwith
|
||||
-------
|
||||
|
||||
.. versionadded:: 0.9.13
|
||||
|
||||
Usage: ``(zipwith fn coll ...)``
|
||||
|
||||
Equivalent to ``zip``, but uses a multi-argument function instead of creating
|
||||
a tuple. If ``zipwith`` is called with N collections, then *fn* must accept
|
||||
N arguments.
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> (import operator)
|
||||
=> (list (zipwith operator.add [1 2 3] [4 5 6]))
|
||||
[5, 7, 9]
|
||||
|
@ -184,7 +184,7 @@ expressions are made of Python lists wrapped in a
|
||||
- ``(cons something some-list)`` is ``((type some-list) (+ [something]
|
||||
some-list))`` (if ``some-list`` inherits from ``list``).
|
||||
- ``(get (cons a b) 0)`` is ``a``
|
||||
- ``(slice (cons a b) 1)`` is ``b``
|
||||
- ``(cut (cons a b) 1)`` is ``b``
|
||||
|
||||
Hy supports a dotted-list syntax, where ``'(a . b)`` means ``(cons 'a
|
||||
'b)`` and ``'(a b . c)`` means ``(cons 'a (cons 'b 'c))``. If the
|
||||
@ -381,7 +381,7 @@ A first pass might be something like:
|
||||
.. code-block:: hy
|
||||
|
||||
(defmacro nif [expr pos-form zero-form neg-form]
|
||||
`(let [[obscure-name ~expr]]
|
||||
`(let [obscure-name ~expr]
|
||||
(cond [(pos? obscure-name) ~pos-form]
|
||||
[(zero? obscure-name) ~zero-form]
|
||||
[(neg? obscure-name) ~neg-form])))
|
||||
@ -396,8 +396,8 @@ such an occasion. A much better version of ``nif`` would be:
|
||||
.. code-block:: hy
|
||||
|
||||
(defmacro nif [expr pos-form zero-form neg-form]
|
||||
(let [[g (gensym)]]
|
||||
`(let [[~g ~expr]]
|
||||
(let [g (gensym)]
|
||||
`(let [~g ~expr]
|
||||
(cond [(pos? ~g) ~pos-form]
|
||||
[(zero? ~g) ~zero-form]
|
||||
[(neg? ~g) ~neg-form]))))
|
||||
@ -415,9 +415,9 @@ expands to:
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
(let [[a (gensym)
|
||||
[b (gensym)
|
||||
[c (gensym)]]
|
||||
(let [a (gensym)
|
||||
b (gensym)
|
||||
c (gensym)]
|
||||
...)
|
||||
|
||||
so our re-written ``nif`` would look like:
|
||||
@ -426,7 +426,7 @@ so our re-written ``nif`` would look like:
|
||||
|
||||
(defmacro nif [expr pos-form zero-form neg-form]
|
||||
(with-gensyms [g]
|
||||
`(let [[~g ~expr]]
|
||||
`(let [~g ~expr]
|
||||
(cond [(pos? ~g) ~pos-form]
|
||||
[(zero? ~g) ~zero-form]
|
||||
[(neg? ~g) ~neg-form]))))
|
||||
@ -440,7 +440,7 @@ Our final version of ``nif``, built with ``defmacro/g!`` becomes:
|
||||
.. code-block:: hy
|
||||
|
||||
(defmacro/g! nif [expr pos-form zero-form neg-form]
|
||||
`(let [[~g!res ~expr]]
|
||||
`(let [~g!res ~expr]
|
||||
(cond [(pos? ~g!res) ~pos-form]
|
||||
[(zero? ~g!res) ~zero-form]
|
||||
[(neg? ~g!res) ~neg-form]))))
|
||||
|
@ -61,8 +61,8 @@ Layout & Indentation
|
||||
;; Good (and preferred)
|
||||
(defn fib [n]
|
||||
(if (<= n 2)
|
||||
n
|
||||
(+ (fib (- n 1)) (fib (- n 2)))))
|
||||
n
|
||||
(+ (fib (- n 1)) (fib (- n 2)))))
|
||||
|
||||
;; Still okay
|
||||
(defn fib [n]
|
||||
@ -89,8 +89,8 @@ Layout & Indentation
|
||||
;; Good (and preferred)
|
||||
(defn fib [n]
|
||||
(if (<= n 2)
|
||||
n
|
||||
(+ (fib (- n 1)) (fib (- n 2)))))
|
||||
n
|
||||
(+ (fib (- n 1)) (fib (- n 2)))))
|
||||
|
||||
;; Hysterically ridiculous
|
||||
(defn fib [n]
|
||||
@ -105,8 +105,8 @@ Layout & Indentation
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
(let [[foo (bar)]
|
||||
[qux (baz)]]
|
||||
(let [foo (bar)]
|
||||
qux (baz)]
|
||||
(foo qux))
|
||||
|
||||
|
||||
|
@ -200,6 +200,10 @@ Hy. Let's experiment with this in the hy interpreter::
|
||||
(1, 2, 3)
|
||||
=> #{3 1 2}
|
||||
{1, 2, 3}
|
||||
=> 1/2
|
||||
Fraction(1, 2)
|
||||
|
||||
Notice the last two lines: Hy has a fraction literal like Clojure.
|
||||
|
||||
If you are familiar with other Lisps, you may be interested that Hy
|
||||
supports the Common Lisp method of quoting:
|
||||
@ -331,7 +335,7 @@ Python's context managers (``with`` statements) are used like this:
|
||||
|
||||
.. code-block:: clj
|
||||
|
||||
(with [[f (open "/tmp/data.in")]]
|
||||
(with [f (open "/tmp/data.in")]
|
||||
(print (.read f)))
|
||||
|
||||
which is equivalent to::
|
||||
@ -473,17 +477,14 @@ In Hy:
|
||||
|
||||
(defclass FooBar [object]
|
||||
"Yet Another Example Class"
|
||||
[[--init--
|
||||
(fn [self x]
|
||||
(setv self.x x)
|
||||
; Currently needed for --init-- because __init__ needs None
|
||||
; Hopefully this will go away :)
|
||||
None)]
|
||||
|
||||
[get-x
|
||||
(fn [self]
|
||||
"Return our copy of x"
|
||||
self.x)]])
|
||||
(defn --init-- [self x]
|
||||
(setv self.x x)
|
||||
None)
|
||||
|
||||
(defn get-x [self]
|
||||
"Return our copy of x"
|
||||
self.x))
|
||||
|
||||
|
||||
You can also do class-level attributes. In Python::
|
||||
@ -498,9 +499,9 @@ In Hy:
|
||||
.. code-block:: clj
|
||||
|
||||
(defclass Customer [models.Model]
|
||||
[[name (models.CharField :max-length 255})]
|
||||
[address (models.TextField)]
|
||||
[notes (models.TextField)]])
|
||||
[name (models.CharField :max-length 255})
|
||||
address (models.TextField)
|
||||
notes (models.TextField)])
|
||||
|
||||
Hy <-> Python interop
|
||||
=====================
|
||||
|
@ -16,7 +16,7 @@
|
||||
(defn parse-rfc822-stream [fd]
|
||||
"Parse an RFC822 stream"
|
||||
(setv bits {})
|
||||
(setv key null)
|
||||
(setv key None)
|
||||
(for [line fd]
|
||||
(if (in ":" line)
|
||||
(do (setv line (.split line ":" 1))
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
(try
|
||||
(import [urllib.request [urlopen]])
|
||||
(catch [ImportError]
|
||||
(except [ImportError]
|
||||
(import [urllib2 [urlopen]])))
|
||||
|
||||
(defn get-rss-feed-name [tumblr]
|
||||
@ -20,6 +20,6 @@
|
||||
(for [post (.xpath (get-rss-feed tumblr) "//item/title")]
|
||||
(print post.text)))
|
||||
|
||||
(if (slice argv 2)
|
||||
(if (cut argv 2)
|
||||
(print-posts (get argv 2))
|
||||
(print-posts "this-plt-life"))
|
||||
|
@ -27,7 +27,7 @@
|
||||
(reactor.stop))
|
||||
|
||||
(defn get-page [url]
|
||||
(let [[d (getPage url)]]
|
||||
(let [d (getPage url)]
|
||||
(d.addCallback get-page-size)
|
||||
(d.addErrback log-error)
|
||||
(d.addCallback finish)))
|
||||
|
@ -289,7 +289,7 @@ def cmdline_handler(scriptname, argv):
|
||||
parser.add_argument('args', nargs=argparse.REMAINDER,
|
||||
help=argparse.SUPPRESS)
|
||||
|
||||
# stash the hy exectuable in case we need it later
|
||||
# stash the hy executable in case we need it later
|
||||
# mimics Python sys.executable
|
||||
hy.executable = argv[0]
|
||||
|
||||
|
263
hy/compiler.py
263
hy/compiler.py
@ -38,6 +38,8 @@ from hy.models.cons import HyCons
|
||||
|
||||
from hy.errors import HyCompileError, HyTypeError
|
||||
|
||||
from hy.lex.parser import hy_symbol_mangle
|
||||
|
||||
import hy.macros
|
||||
from hy._compat import (
|
||||
str_type, long_type, PY27, PY33, PY3, PY34, PY35, raise_empty)
|
||||
@ -81,7 +83,7 @@ def load_stdlib():
|
||||
# keywords in Python 3.*
|
||||
def _is_hy_builtin(name, module_name):
|
||||
extras = ['True', 'False', 'None',
|
||||
'true', 'false', 'nil', 'null']
|
||||
'true', 'false', 'nil']
|
||||
if name in extras or keyword.iskeyword(name):
|
||||
return True
|
||||
# for non-Hy modules, check for pre-existing name in
|
||||
@ -370,6 +372,7 @@ def checkargs(exact=None, min=None, max=None, even=None, multiple=None):
|
||||
class HyASTCompiler(object):
|
||||
|
||||
def __init__(self, module_name):
|
||||
self.allow_builtins = False
|
||||
self.anon_fn_count = 0
|
||||
self.anon_var_count = 0
|
||||
self.imports = defaultdict(set)
|
||||
@ -459,8 +462,9 @@ class HyASTCompiler(object):
|
||||
try:
|
||||
value = next(exprs_iter)
|
||||
except StopIteration:
|
||||
msg = "Keyword argument {kw} needs a value"
|
||||
raise HyCompileError(msg.format(kw=str(expr)))
|
||||
raise HyTypeError(expr,
|
||||
"Keyword argument {kw} needs "
|
||||
"a value.".format(kw=str(expr[1:])))
|
||||
|
||||
compiled_value = self.compile(value)
|
||||
ret += compiled_value
|
||||
@ -723,6 +727,9 @@ class HyASTCompiler(object):
|
||||
def compile_eval(self, expr):
|
||||
expr.pop(0)
|
||||
|
||||
if not isinstance(expr[0], (HyExpression, HySymbol)):
|
||||
raise HyTypeError(expr, "expression expected as first argument")
|
||||
|
||||
elist = [HySymbol("hy_eval")] + [expr[0]]
|
||||
if len(expr) >= 2:
|
||||
elist.append(expr[1])
|
||||
@ -741,15 +748,13 @@ class HyASTCompiler(object):
|
||||
return ret
|
||||
|
||||
@builds("do")
|
||||
@builds("progn")
|
||||
def compile_progn(self, expression):
|
||||
def compile_do(self, expression):
|
||||
expression.pop(0)
|
||||
return self._compile_branch(expression)
|
||||
|
||||
@builds("throw")
|
||||
@builds("raise")
|
||||
@checkargs(multiple=[0, 1, 3])
|
||||
def compile_throw_expression(self, expr):
|
||||
def compile_raise_expression(self, expr):
|
||||
expr.pop(0)
|
||||
ret = Result()
|
||||
if expr:
|
||||
@ -821,7 +826,7 @@ class HyASTCompiler(object):
|
||||
if not len(e):
|
||||
raise HyTypeError(e, "Empty list not allowed in `try'")
|
||||
|
||||
if e[0] in (HySymbol("except"), HySymbol("catch")):
|
||||
if e[0] == HySymbol("except"):
|
||||
handler_results += self._compile_catch_expression(e, name)
|
||||
handlers.append(handler_results.stmts.pop())
|
||||
elif e[0] == HySymbol("else"):
|
||||
@ -899,7 +904,6 @@ class HyASTCompiler(object):
|
||||
return accumulated
|
||||
|
||||
@builds("except")
|
||||
@builds("catch")
|
||||
def magic_internal_form(self, expr):
|
||||
raise HyTypeError(expr,
|
||||
"Error: `%s' can't be used like that." % (expr[0]))
|
||||
@ -1293,9 +1297,15 @@ class HyASTCompiler(object):
|
||||
return ret
|
||||
|
||||
@builds("del")
|
||||
@checkargs(min=1)
|
||||
def compile_del_expression(self, expr):
|
||||
expr.pop(0)
|
||||
root = expr.pop(0)
|
||||
if not expr:
|
||||
result = Result()
|
||||
result += ast.Name(id='None', ctx=ast.Load(),
|
||||
lineno=root.start_line,
|
||||
col_offset=root.start_column)
|
||||
return result
|
||||
|
||||
ld_targets, ret, _ = self._compile_collect(expr)
|
||||
|
||||
del_targets = []
|
||||
@ -1307,9 +1317,9 @@ class HyASTCompiler(object):
|
||||
col_offset=expr.start_column,
|
||||
targets=del_targets)
|
||||
|
||||
@builds("slice")
|
||||
@builds("cut")
|
||||
@checkargs(min=1, max=4)
|
||||
def compile_slice_expression(self, expr):
|
||||
def compile_cut_expression(self, expr):
|
||||
expr.pop(0) # index
|
||||
val = self.compile(expr.pop(0)) # target
|
||||
|
||||
@ -1469,9 +1479,16 @@ class HyASTCompiler(object):
|
||||
# (list-comp expr (target iter) cond?)
|
||||
expr.pop(0)
|
||||
expression = expr.pop(0)
|
||||
gen_gen = expr[0]
|
||||
|
||||
if not isinstance(gen_gen, HyList):
|
||||
raise HyTypeError(gen_gen, "Generator expression must be a list.")
|
||||
|
||||
gen_res, gen = self._compile_generator_iterables(expr)
|
||||
|
||||
if len(gen) == 0:
|
||||
raise HyTypeError(gen_gen, "Generator expression cannot be empty.")
|
||||
|
||||
compiled_expression = self.compile(expression)
|
||||
ret = compiled_expression + gen_res
|
||||
ret += ast.ListComp(
|
||||
@ -1593,7 +1610,7 @@ class HyASTCompiler(object):
|
||||
|
||||
# We then pass the other arguments to the function
|
||||
expr[0] = HyExpression(
|
||||
[HySymbol("slice"), tempvar, HyInteger(1)]
|
||||
[HySymbol("cut"), tempvar, HyInteger(1)]
|
||||
).replace(expr[0])
|
||||
|
||||
ret += self.compile(call)
|
||||
@ -1625,7 +1642,21 @@ class HyASTCompiler(object):
|
||||
ret = stargs + ret
|
||||
|
||||
if expr:
|
||||
kwargs = self.compile(expr.pop(0))
|
||||
kwargs = expr.pop(0)
|
||||
if isinstance(kwargs, HyDict):
|
||||
new_kwargs = []
|
||||
for k, v in kwargs.items():
|
||||
if isinstance(k, HySymbol):
|
||||
pass
|
||||
elif isinstance(k, HyString):
|
||||
k = HyString(hy_symbol_mangle(str_type(k))).replace(k)
|
||||
elif isinstance(k, HyKeyword):
|
||||
sym = hy_symbol_mangle(str_type(k)[2:])
|
||||
k = HyString(sym).replace(k)
|
||||
new_kwargs += [k, v]
|
||||
kwargs = HyDict(new_kwargs).replace(kwargs)
|
||||
|
||||
kwargs = self.compile(kwargs)
|
||||
if PY35:
|
||||
kwargs_expr = kwargs.force_expr
|
||||
ret.expr.keywords.append(
|
||||
@ -1669,17 +1700,78 @@ class HyASTCompiler(object):
|
||||
|
||||
@builds("and")
|
||||
@builds("or")
|
||||
@checkargs(min=2)
|
||||
def compile_logical_or_and_and_operator(self, expression):
|
||||
ops = {"and": ast.And,
|
||||
"or": ast.Or}
|
||||
ops = {"and": (ast.And, "True"),
|
||||
"or": (ast.Or, "None")}
|
||||
operator = expression.pop(0)
|
||||
values, ret, _ = self._compile_collect(expression)
|
||||
opnode, default = ops[operator]
|
||||
root_line, root_column = operator.start_line, operator.start_column
|
||||
if len(expression) == 0:
|
||||
return ast.Name(id=default,
|
||||
ctx=ast.Load(),
|
||||
lineno=root_line,
|
||||
col_offset=root_column)
|
||||
elif len(expression) == 1:
|
||||
return self.compile(expression[0])
|
||||
ret = Result()
|
||||
values = list(map(self.compile, expression))
|
||||
has_stmt = any(value.stmts for value in values)
|
||||
if has_stmt:
|
||||
# Compile it to an if...else sequence
|
||||
var = self.get_anon_var()
|
||||
name = ast.Name(id=var,
|
||||
ctx=ast.Store(),
|
||||
lineno=root_line,
|
||||
col_offset=root_column)
|
||||
expr_name = ast.Name(id=var,
|
||||
ctx=ast.Load(),
|
||||
lineno=root_line,
|
||||
col_offset=root_column)
|
||||
|
||||
ret += ast.BoolOp(op=ops[operator](),
|
||||
lineno=operator.start_line,
|
||||
col_offset=operator.start_column,
|
||||
values=values)
|
||||
def make_assign(value, node=None):
|
||||
if node is None:
|
||||
line, column = root_line, root_column
|
||||
else:
|
||||
line, column = node.lineno, node.col_offset
|
||||
return ast.Assign(targets=[ast.Name(id=var,
|
||||
ctx=ast.Store(),
|
||||
lineno=line,
|
||||
col_offset=column)],
|
||||
value=value,
|
||||
lineno=line,
|
||||
col_offset=column)
|
||||
root = []
|
||||
current = root
|
||||
for i, value in enumerate(values):
|
||||
if value.stmts:
|
||||
node = value.stmts[0]
|
||||
current.extend(value.stmts)
|
||||
else:
|
||||
node = value.expr
|
||||
current.append(make_assign(value.force_expr, value.force_expr))
|
||||
if i == len(values)-1:
|
||||
# Skip a redundant 'if'.
|
||||
break
|
||||
if operator == "and":
|
||||
cond = expr_name
|
||||
elif operator == "or":
|
||||
cond = ast.UnaryOp(op=ast.Not(),
|
||||
operand=expr_name,
|
||||
lineno=node.lineno,
|
||||
col_offset=node.col_offset)
|
||||
current.append(ast.If(test=cond,
|
||||
body=[],
|
||||
lineno=node.lineno,
|
||||
col_offset=node.col_offset,
|
||||
orelse=[]))
|
||||
current = current[-1].body
|
||||
ret = sum(root, ret)
|
||||
ret += Result(expr=expr_name, temp_variables=[expr_name, name])
|
||||
else:
|
||||
ret += ast.BoolOp(op=opnode(),
|
||||
lineno=root_line,
|
||||
col_offset=root_column,
|
||||
values=[value.force_expr for value in values])
|
||||
return ret
|
||||
|
||||
@builds("=")
|
||||
@ -1714,8 +1806,6 @@ class HyASTCompiler(object):
|
||||
col_offset=e.start_column)
|
||||
|
||||
@builds("%")
|
||||
@builds("/")
|
||||
@builds("//")
|
||||
@builds("**")
|
||||
@builds("<<")
|
||||
@builds(">>")
|
||||
@ -1757,11 +1847,14 @@ class HyASTCompiler(object):
|
||||
|
||||
@builds("+")
|
||||
@builds("*")
|
||||
@builds("/")
|
||||
@builds("//")
|
||||
def compile_maths_expression_mul(self, expression):
|
||||
if len(expression) > 2:
|
||||
return self.compile_maths_expression(expression)
|
||||
else:
|
||||
id_op = {"+": HyInteger(0), "*": HyInteger(1)}
|
||||
id_op = {"+": HyInteger(0), "*": HyInteger(1), "/": HyInteger(1),
|
||||
"//": HyInteger(1)}
|
||||
|
||||
op = expression.pop(0)
|
||||
arg = expression.pop(0) if expression else id_op[op]
|
||||
@ -1903,23 +1996,52 @@ class HyASTCompiler(object):
|
||||
|
||||
@builds("def")
|
||||
@builds("setv")
|
||||
@checkargs(2)
|
||||
def compile_def_expression(self, expression):
|
||||
return self._compile_assign(expression[1], expression[2],
|
||||
expression.start_line,
|
||||
expression.start_column)
|
||||
root = expression.pop(0)
|
||||
if not expression:
|
||||
result = Result()
|
||||
result += ast.Name(id='None', ctx=ast.Load(),
|
||||
lineno=root.start_line,
|
||||
col_offset=root.start_column)
|
||||
return result
|
||||
elif len(expression) == 2:
|
||||
return self._compile_assign(expression[0], expression[1],
|
||||
expression.start_line,
|
||||
expression.start_column)
|
||||
elif len(expression) % 2 != 0:
|
||||
raise HyTypeError(expression,
|
||||
"`{}' needs an even number of arguments".format(
|
||||
root))
|
||||
else:
|
||||
result = Result()
|
||||
exprs = []
|
||||
for tgt, target in zip(expression[::2], expression[1::2]):
|
||||
item = self._compile_assign(tgt, target,
|
||||
tgt.start_line, tgt.start_column)
|
||||
result += item
|
||||
exprs.append(item.force_expr)
|
||||
|
||||
result += ast.Tuple(elts=exprs, lineno=expression.start_line,
|
||||
col_offset=expression.start_column,
|
||||
ctx=ast.Load())
|
||||
return result
|
||||
|
||||
def _compile_assign(self, name, result,
|
||||
start_line, start_column):
|
||||
|
||||
str_name = "%s" % name
|
||||
if _is_hy_builtin(str_name, self.module_name):
|
||||
if _is_hy_builtin(str_name, self.module_name) and \
|
||||
not self.allow_builtins:
|
||||
raise HyTypeError(name,
|
||||
"Can't assign to a builtin: `%s'" % str_name)
|
||||
|
||||
result = self.compile(result)
|
||||
ld_name = self.compile(name)
|
||||
|
||||
if isinstance(ld_name.expr, ast.Call):
|
||||
raise HyTypeError(name,
|
||||
"Can't assign to a callable: `%s'" % str_name)
|
||||
|
||||
if result.temp_variables \
|
||||
and isinstance(name, HyString) \
|
||||
and '.' not in name:
|
||||
@ -2047,7 +2169,8 @@ class HyASTCompiler(object):
|
||||
arglist = expression.pop(0)
|
||||
if not isinstance(arglist, HyList):
|
||||
raise HyTypeError(expression,
|
||||
"First argument to (fn) must be a list")
|
||||
"First argument to `{}' must be a list".format(
|
||||
called_as))
|
||||
|
||||
(ret, args, defaults, stararg,
|
||||
kwonlyargs, kwonlydefaults, kwargs) = self._parse_lambda_list(arglist)
|
||||
@ -2151,15 +2274,31 @@ class HyASTCompiler(object):
|
||||
|
||||
@builds("defclass")
|
||||
@checkargs(min=1)
|
||||
def compile_class_expression(self, expression):
|
||||
expression.pop(0) # class
|
||||
def compile_class_expression(self, expressions):
|
||||
def rewire_init(expr):
|
||||
new_args = []
|
||||
if expr[0] == HySymbol("setv"):
|
||||
pairs = expr[1:]
|
||||
while len(pairs) > 0:
|
||||
k, v = (pairs.pop(0), pairs.pop(0))
|
||||
if k == HySymbol("__init__"):
|
||||
v.append(HySymbol("None"))
|
||||
new_args.append(k)
|
||||
new_args.append(v)
|
||||
expr = HyExpression([
|
||||
HySymbol("setv")
|
||||
] + new_args).replace(expr)
|
||||
|
||||
class_name = expression.pop(0)
|
||||
return expr
|
||||
|
||||
if expression:
|
||||
base_list = expression.pop(0)
|
||||
expressions.pop(0) # class
|
||||
|
||||
class_name = expressions.pop(0)
|
||||
|
||||
if expressions:
|
||||
base_list = expressions.pop(0)
|
||||
if not isinstance(base_list, HyList):
|
||||
raise HyTypeError(expression,
|
||||
raise HyTypeError(expressions,
|
||||
"Bases class must be a list")
|
||||
bases_expr, bases, _ = self._compile_collect(base_list)
|
||||
else:
|
||||
@ -2169,8 +2308,8 @@ class HyASTCompiler(object):
|
||||
body = Result()
|
||||
|
||||
# grab the doc string, if there is one
|
||||
if expression and isinstance(expression[0], HyString):
|
||||
docstring = expression.pop(0)
|
||||
if expressions and isinstance(expressions[0], HyString):
|
||||
docstring = expressions.pop(0)
|
||||
symb = HySymbol("__doc__")
|
||||
symb.start_line = docstring.start_line
|
||||
symb.start_column = docstring.start_column
|
||||
@ -2179,31 +2318,29 @@ class HyASTCompiler(object):
|
||||
docstring.start_column)
|
||||
body += body.expr_as_stmt()
|
||||
|
||||
if expression:
|
||||
try:
|
||||
body_expression = iter(expression.pop(0))
|
||||
except TypeError:
|
||||
raise HyTypeError(
|
||||
expression,
|
||||
"Wrong argument type for defclass attributes definition.")
|
||||
for b in body_expression:
|
||||
if isinstance(b, HyExpression):
|
||||
b = macroexpand(b, self.module_name)
|
||||
if len(b) != 2:
|
||||
raise HyTypeError(
|
||||
expression,
|
||||
"Wrong number of argument in defclass attribute.")
|
||||
body += self._compile_assign(b[0], b[1],
|
||||
b.start_line, b.start_column)
|
||||
body += body.expr_as_stmt()
|
||||
allow_builtins = self.allow_builtins
|
||||
self.allow_builtins = True
|
||||
if expressions and isinstance(expressions[0], HyList) \
|
||||
and not isinstance(expressions[0], HyExpression):
|
||||
expr = expressions.pop(0)
|
||||
expr = HyExpression([
|
||||
HySymbol("setv")
|
||||
] + expr).replace(expr)
|
||||
body += self.compile(rewire_init(expr))
|
||||
|
||||
for expression in expressions:
|
||||
expr = rewire_init(macroexpand(expression, self.module_name))
|
||||
body += self.compile(expr)
|
||||
|
||||
self.allow_builtins = allow_builtins
|
||||
|
||||
if not body.stmts:
|
||||
body += ast.Pass(lineno=expression.start_line,
|
||||
col_offset=expression.start_column)
|
||||
body += ast.Pass(lineno=expressions.start_line,
|
||||
col_offset=expressions.start_column)
|
||||
|
||||
return bases + ast.ClassDef(
|
||||
lineno=expression.start_line,
|
||||
col_offset=expression.start_column,
|
||||
lineno=expressions.start_line,
|
||||
col_offset=expressions.start_column,
|
||||
decorator_list=[],
|
||||
name=ast_str(class_name),
|
||||
keywords=[],
|
||||
@ -2286,7 +2423,7 @@ class HyASTCompiler(object):
|
||||
|
||||
@builds("eval_and_compile")
|
||||
def compile_eval_and_compile(self, expression):
|
||||
expression[0] = HySymbol("progn")
|
||||
expression[0] = HySymbol("do")
|
||||
hy.importer.hy_eval(expression,
|
||||
compile_time_ns(self.module_name),
|
||||
self.module_name)
|
||||
@ -2295,7 +2432,7 @@ class HyASTCompiler(object):
|
||||
|
||||
@builds("eval_when_compile")
|
||||
def compile_eval_when_compile(self, expression):
|
||||
expression[0] = HySymbol("progn")
|
||||
expression[0] = HySymbol("do")
|
||||
hy.importer.hy_eval(expression,
|
||||
compile_time_ns(self.module_name),
|
||||
self.module_name)
|
||||
|
39
hy/contrib/alias.hy
Normal file
39
hy/contrib/alias.hy
Normal file
@ -0,0 +1,39 @@
|
||||
;; Copyright (c) 2014, 2015 Gergely Nagy
|
||||
;; Copyright (c) 2014, 2015 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.
|
||||
|
||||
(defmacro defmacro-alias [names lambda-list &rest body]
|
||||
"define one macro with several names"
|
||||
(setv ret `(do))
|
||||
(for* [name names]
|
||||
(.append ret
|
||||
`(defmacro ~name ~lambda-list ~@body)))
|
||||
ret)
|
||||
|
||||
|
||||
(defmacro defn-alias [names lambda-list &rest body]
|
||||
"define one function with several names"
|
||||
(let [main (first names)
|
||||
aliases (rest names)]
|
||||
(setv ret `(do (defn ~main ~lambda-list ~@body)))
|
||||
(for* [name aliases]
|
||||
(.append ret
|
||||
`(setv ~name ~main)))
|
||||
ret))
|
@ -26,7 +26,7 @@
|
||||
|
||||
|
||||
(defmacro ap-if (test-form &rest args)
|
||||
`(let [[it ~test-form]] (if it ~@args)))
|
||||
`(let [it ~test-form] (if it ~@args)))
|
||||
|
||||
|
||||
(defmacro ap-each [lst &rest body]
|
||||
@ -37,7 +37,7 @@
|
||||
(defmacro ap-each-while [lst form &rest body]
|
||||
"Evalutate the body form for each element in the list while the
|
||||
predicate form evaluates to True."
|
||||
`(let [[p (lambda [it] ~form)]]
|
||||
`(let [p (lambda [it] ~form)]
|
||||
(for [it ~lst]
|
||||
(if (p it)
|
||||
~@body
|
||||
@ -46,8 +46,9 @@
|
||||
|
||||
(defmacro ap-map [form lst]
|
||||
"Yield elements evaluated in the form for each element in the list."
|
||||
(let [[v (gensym 'v)] [f (gensym 'f)]]
|
||||
`(let [[~f (lambda [it] ~form)]]
|
||||
(let [v (gensym 'v)
|
||||
f (gensym 'f)]
|
||||
`(let [~f (lambda [it] ~form)]
|
||||
(for [~v ~lst]
|
||||
(yield (~f ~v))))))
|
||||
|
||||
@ -55,7 +56,7 @@
|
||||
(defmacro ap-map-when [predfn rep lst]
|
||||
"Yield elements evaluated for each element in the list when the
|
||||
predicate function returns True."
|
||||
`(let [[f (lambda [it] ~rep)]]
|
||||
`(let [f (lambda [it] ~rep)]
|
||||
(for [it ~lst]
|
||||
(if (~predfn it)
|
||||
(yield (f it))
|
||||
@ -64,7 +65,7 @@
|
||||
|
||||
(defmacro ap-filter [form lst]
|
||||
"Yield elements returned when the predicate form evaluates to True."
|
||||
`(let [[pred (lambda [it] ~form)]]
|
||||
`(let [pred (lambda [it] ~form)]
|
||||
(for [val ~lst]
|
||||
(if (pred val)
|
||||
(yield val)))))
|
||||
@ -85,7 +86,7 @@
|
||||
(defmacro ap-first [predfn lst]
|
||||
"Yield the first element that passes `predfn`"
|
||||
(with-gensyms [n]
|
||||
`(let [[~n None]]
|
||||
`(let [~n None]
|
||||
(ap-each ~lst (when ~predfn (setv ~n it) (break)))
|
||||
~n)))
|
||||
|
||||
@ -93,7 +94,7 @@
|
||||
(defmacro ap-last [predfn lst]
|
||||
"Yield the last element that passes `predfn`"
|
||||
(with-gensyms [n]
|
||||
`(let [[~n None]]
|
||||
`(let [~n None]
|
||||
(ap-each ~lst (none? ~n)
|
||||
(when ~predfn
|
||||
(setv ~n it)))
|
||||
@ -103,10 +104,10 @@
|
||||
(defmacro ap-reduce [form lst &optional [initial-value None]]
|
||||
"Anaphoric form of reduce, `acc' and `it' can be used for a form"
|
||||
(if (none? initial-value)
|
||||
`(let [[acc (car ~lst)]]
|
||||
`(let [acc (car ~lst)]
|
||||
(ap-each (cdr ~lst) (setv acc ~form))
|
||||
acc)
|
||||
`(let [[acc ~initial-value]]
|
||||
`(let [acc ~initial-value]
|
||||
(ap-each ~lst (setv acc ~form))
|
||||
acc)))
|
||||
|
||||
@ -115,9 +116,33 @@
|
||||
"Pushes a value through several forms.
|
||||
(Anaphoric version of -> and ->>)"
|
||||
(if (empty? forms) var
|
||||
`(ap-pipe (let [[it ~var]] ~(first forms)) ~@(rest forms))))
|
||||
`(ap-pipe (let [it ~var] ~(first forms)) ~@(rest forms))))
|
||||
|
||||
|
||||
(defmacro ap-compose [&rest forms]
|
||||
"Returns a function which is the composition of several forms."
|
||||
`(fn [var] (ap-pipe var ~@forms)))
|
||||
|
||||
(defmacro xi [&rest body]
|
||||
"Returns a function with parameters implicitly determined by the presence in
|
||||
the body of xi parameters. An xi symbol designates the ith parameter
|
||||
(1-based, e.g. x1, x2, x3, etc.), or all remaining parameters for xi itself.
|
||||
This is not a replacement for lambda. The xi forms cannot be nested. "
|
||||
(setv flatbody (flatten body))
|
||||
`(lambda [;; generate all xi symbols up to the maximum found in body
|
||||
~@(genexpr (HySymbol (+ "x"
|
||||
(str i)))
|
||||
[i (range 1
|
||||
;; find the maximum xi
|
||||
(inc (max (+ (list-comp (int (cdr a))
|
||||
[a flatbody]
|
||||
(and (symbol? a)
|
||||
(.startswith a 'x)
|
||||
(.isdigit (cdr a))))
|
||||
[0]))))])
|
||||
;; generate the &rest paremeter only if 'xi is present in body
|
||||
~@(if (in 'xi flatbody)
|
||||
'(&rest xi)
|
||||
'())]
|
||||
(~@body)))
|
||||
|
||||
|
33
hy/contrib/botsbuildbots.hy
Normal file
33
hy/contrib/botsbuildbots.hy
Normal file
@ -0,0 +1,33 @@
|
||||
;; Copyright (c) 2014, 2015 Gergely Nagy
|
||||
|
||||
;; 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.
|
||||
|
||||
(defn Botsbuildbots () (Botsbuildbots))
|
||||
|
||||
(defmacro Botsbuildbots []
|
||||
"Build bots, repeatedly.^W^W^WPrint the AUTHORS, forever."
|
||||
`(try
|
||||
(do
|
||||
(import [requests])
|
||||
|
||||
(let [r (requests.get
|
||||
"https://raw.githubusercontent.com/hylang/hy/master/AUTHORS")]
|
||||
(repeat r.text)))
|
||||
(except [e ImportError]
|
||||
(repeat "Botsbuildbots requires `requests' to function."))))
|
@ -2,8 +2,8 @@
|
||||
|
||||
|
||||
(defn curry [func]
|
||||
(let [[sig (.getargspec inspect func)]
|
||||
[count (len sig.args)]]
|
||||
(let [sig (.getargspec inspect func)
|
||||
count (len sig.args)]
|
||||
|
||||
(fn [&rest args]
|
||||
(if (< (len args) count)
|
||||
|
@ -58,7 +58,7 @@
|
||||
|
||||
|
||||
(defmacro/g! fnr [signature &rest body]
|
||||
(let [[new-body (recursive-replace 'recur g!recur-fn body)]]
|
||||
(let [new-body (recursive-replace 'recur g!recur-fn body)]
|
||||
`(do
|
||||
(import [hy.contrib.loop [--trampoline--]])
|
||||
(with-decorator
|
||||
@ -75,7 +75,7 @@
|
||||
|
||||
(defmacro/g! loop [bindings &rest body]
|
||||
;; Use inside functions like so:
|
||||
;; (defun factorial [n]
|
||||
;; (defn factorial [n]
|
||||
;; (loop [[i n]
|
||||
;; [acc 1]]
|
||||
;; (if (= i 0)
|
||||
@ -85,7 +85,7 @@
|
||||
;; If recur is used in a non-tail-call position, None is returned, which
|
||||
;; causes chaos. Fixing this to detect if recur is in a tail-call position
|
||||
;; and erroring if not is a giant TODO.
|
||||
(let [[fnargs (map (fn [x] (first x)) bindings)]
|
||||
[initargs (map second bindings)]]
|
||||
(let [fnargs (map (fn [x] (first x)) bindings)
|
||||
initargs (map second bindings)]
|
||||
`(do (defnr ~g!recur-fn [~@fnargs] ~@body)
|
||||
(~g!recur-fn ~@initargs))))
|
||||
|
@ -3,11 +3,11 @@
|
||||
|
||||
(defmacro route-with-methods [name path methods params &rest code]
|
||||
"Same as route but with an extra methods array to specify HTTP methods"
|
||||
`(let [[deco (apply app.route [~path]
|
||||
{"methods" ~methods})]]
|
||||
(with-decorator deco
|
||||
(defn ~name ~params
|
||||
(progn ~@code)))))
|
||||
`(let [deco (apply app.route [~path]
|
||||
{"methods" ~methods})]
|
||||
(with-decorator deco
|
||||
(defn ~name ~params
|
||||
(do ~@code)))))
|
||||
|
||||
;; Some macro examples
|
||||
(defmacro route [name path params &rest code]
|
||||
|
@ -31,42 +31,25 @@
|
||||
`(raise (hy.errors.HyMacroExpansionError ~location ~reason)))
|
||||
|
||||
|
||||
(defmacro defmacro-alias [names lambda-list &rest body]
|
||||
"define one macro with several names"
|
||||
(setv ret `(do))
|
||||
(for* [name names]
|
||||
(.append ret
|
||||
`(defmacro ~name ~lambda-list ~@body)))
|
||||
ret)
|
||||
|
||||
|
||||
(defmacro-alias [defn defun] [name lambda-list &rest body]
|
||||
(defmacro defn [name lambda-list &rest body]
|
||||
"define a function `name` with signature `lambda-list` and body `body`"
|
||||
(if (not (= (type name) HySymbol))
|
||||
(macro-error name "defn/defun takes a name as first argument"))
|
||||
(macro-error name "defn takes a name as first argument"))
|
||||
(if (not (isinstance lambda-list HyList))
|
||||
(macro-error name "defn/defun takes a parameter list as second argument"))
|
||||
(macro-error name "defn takes a parameter list as second argument"))
|
||||
`(setv ~name (fn ~lambda-list ~@body)))
|
||||
|
||||
|
||||
(defmacro let [variables &rest body]
|
||||
"Execute `body` in the lexical context of `variables`"
|
||||
(setv macroed_variables [])
|
||||
(if (not (isinstance variables HyList))
|
||||
(macro-error variables "let lexical context must be a list"))
|
||||
(for* [variable variables]
|
||||
(if (isinstance variable HyList)
|
||||
(do
|
||||
(if (!= (len variable) 2)
|
||||
(macro-error variable "let variable assignments must contain two items"))
|
||||
(.append macroed-variables `(setv ~(get variable 0) ~(get variable 1))))
|
||||
(if (isinstance variable HySymbol)
|
||||
(.append macroed-variables `(setv ~variable None))
|
||||
(macro-error variable "let lexical context element must be a list or symbol"))))
|
||||
`((fn []
|
||||
~@macroed-variables
|
||||
~@body)))
|
||||
|
||||
(if (= (len variables) 0)
|
||||
`((fn []
|
||||
~@body))
|
||||
`((fn []
|
||||
(setv ~@variables)
|
||||
~@body))))
|
||||
|
||||
(defmacro if-python2 [python2-form python3-form]
|
||||
"If running on python2, execute python2-form, else, execute python3-form"
|
||||
|
@ -26,7 +26,12 @@
|
||||
(import itertools)
|
||||
(import functools)
|
||||
(import collections)
|
||||
(import [fractions [Fraction :as fraction]])
|
||||
(import operator) ; shadow not available yet
|
||||
(import sys)
|
||||
(if-python2
|
||||
(import [StringIO [StringIO]])
|
||||
(import [io [StringIO]]))
|
||||
(import [hy._compat [long-type]]) ; long for python2, int for python3
|
||||
(import [hy.models.cons [HyCons]]
|
||||
[hy.models.symbol [HySymbol]]
|
||||
@ -79,49 +84,82 @@
|
||||
(defn distinct [coll]
|
||||
"Return a generator from the original collection with duplicates
|
||||
removed"
|
||||
(let [[seen (set)] [citer (iter coll)]]
|
||||
(for* [val citer]
|
||||
(if (not_in val seen)
|
||||
(do
|
||||
(yield val)
|
||||
(.add seen val))))))
|
||||
(let [seen (set)
|
||||
citer (iter coll)]
|
||||
(for* [val citer]
|
||||
(if (not_in val seen)
|
||||
(do
|
||||
(yield val)
|
||||
(.add seen val))))))
|
||||
|
||||
(if-python2
|
||||
(do
|
||||
(setv filterfalse itertools.ifilterfalse)
|
||||
(setv zip_longest itertools.izip_longest)
|
||||
(setv filter itertools.ifilter)
|
||||
(setv map itertools.imap)
|
||||
(setv zip itertools.izip)
|
||||
(setv range xrange)
|
||||
(setv input raw_input)
|
||||
(setv reduce reduce))
|
||||
(do
|
||||
(setv reduce functools.reduce)
|
||||
(setv filterfalse itertools.filterfalse)
|
||||
(setv zip_longest itertools.zip_longest)
|
||||
; Someone can import these directly from `hy.core.language`;
|
||||
; we'll make some duplicates.
|
||||
(setv filter filter)
|
||||
(setv map map)
|
||||
(setv zip zip)
|
||||
(setv range range)
|
||||
(setv input input)))
|
||||
(def
|
||||
remove itertools.ifilterfalse
|
||||
zip-longest itertools.izip_longest
|
||||
;; not builtin in Python3
|
||||
reduce reduce
|
||||
;; hy is more like Python3
|
||||
filter itertools.ifilter
|
||||
input raw_input
|
||||
map itertools.imap
|
||||
range xrange
|
||||
zip itertools.izip)
|
||||
(def
|
||||
remove itertools.filterfalse
|
||||
zip-longest itertools.zip_longest
|
||||
;; was builtin in Python2
|
||||
reduce functools.reduce
|
||||
;; Someone can import these directly from `hy.core.language`;
|
||||
;; we'll make some duplicates.
|
||||
filter filter
|
||||
input input
|
||||
map map
|
||||
range range
|
||||
zip zip))
|
||||
|
||||
(setv cycle itertools.cycle)
|
||||
(setv repeat itertools.repeat)
|
||||
(setv drop-while itertools.dropwhile)
|
||||
(setv take-while itertools.takewhile)
|
||||
(setv zipwith map)
|
||||
(setv remove filterfalse)
|
||||
;; infinite iterators
|
||||
(def
|
||||
count itertools.count
|
||||
cycle itertools.cycle
|
||||
repeat itertools.repeat)
|
||||
|
||||
;; shortest-terminating iterators
|
||||
(def
|
||||
*map itertools.starmap
|
||||
chain itertools.chain
|
||||
compress itertools.compress
|
||||
drop-while itertools.dropwhile
|
||||
group-by itertools.groupby
|
||||
islice itertools.islice
|
||||
take-while itertools.takewhile
|
||||
tee itertools.tee)
|
||||
|
||||
;; combinatoric iterators
|
||||
(def
|
||||
combinations itertools.combinations
|
||||
multicombinations itertools.combinations_with_replacement
|
||||
permutations itertools.permutations
|
||||
product itertools.product)
|
||||
|
||||
;; also from itertools, but not in Python2, and without func option until 3.3
|
||||
(defn accumulate [iterable &optional [func operator.add]]
|
||||
"accumulate(iterable[, func]) --> accumulate object
|
||||
|
||||
Return series of accumulated sums (or other binary function results)."
|
||||
(setv it (iter iterable)
|
||||
total (next it))
|
||||
(yield total)
|
||||
(for* [element it]
|
||||
(setv total (func total element))
|
||||
(yield total)))
|
||||
|
||||
(defn drop [count coll]
|
||||
"Drop `count` elements from `coll` and yield back the rest"
|
||||
(itertools.islice coll count nil))
|
||||
(islice coll count nil))
|
||||
|
||||
(defn drop-last [n coll]
|
||||
"Return a sequence of all but the last n elements in coll."
|
||||
(let [[iters (itertools.tee coll)]]
|
||||
(let [iters (tee coll)]
|
||||
(map first (apply zip [(get iters 0)
|
||||
(drop n (get iters 1))]))))
|
||||
|
||||
@ -173,7 +211,7 @@
|
||||
(setv _gensym_lock (Lock))
|
||||
|
||||
(defn gensym [&optional [g "G"]]
|
||||
(let [[new_symbol None]]
|
||||
(let [new_symbol None]
|
||||
(global _gensym_counter)
|
||||
(global _gensym_lock)
|
||||
(.acquire _gensym_lock)
|
||||
@ -192,7 +230,7 @@
|
||||
|
||||
(defn first [coll]
|
||||
"Return first item from `coll`"
|
||||
(nth coll 0))
|
||||
(next (iter coll) nil))
|
||||
|
||||
(defn identity [x]
|
||||
"Returns the argument unchanged"
|
||||
@ -218,16 +256,16 @@
|
||||
"Return True if char `x` parses as an integer"
|
||||
(try
|
||||
(integer? (int x))
|
||||
(catch [e ValueError] False)
|
||||
(catch [e TypeError] False)))
|
||||
(except [e ValueError] False)
|
||||
(except [e TypeError] False)))
|
||||
|
||||
(defn interleave [&rest seqs]
|
||||
"Return an iterable of the first item in each of seqs, then the second etc."
|
||||
(itertools.chain.from_iterable (apply zip seqs)))
|
||||
(chain.from-iterable (apply zip seqs)))
|
||||
|
||||
(defn interpose [item seq]
|
||||
"Return an iterable of the elements of seq separated by item"
|
||||
(drop 1 (interleave (itertools.repeat item) seq)))
|
||||
(drop 1 (interleave (repeat item) seq)))
|
||||
|
||||
(defn iterable? [x]
|
||||
"Return true if x is iterable"
|
||||
@ -245,7 +283,7 @@
|
||||
|
||||
(defn last [coll]
|
||||
"Return last item from `coll`"
|
||||
(get (list coll) -1))
|
||||
(get (tuple coll) -1))
|
||||
|
||||
(defn list* [hd &rest tl]
|
||||
"Return a dotted list construed from the elements of the argument"
|
||||
@ -273,15 +311,16 @@
|
||||
from the latter (left-to-right) will be combined with the mapping in
|
||||
the result by calling (f val-in-result val-in-latter)."
|
||||
(if (any maps)
|
||||
(let [[merge-entry (fn [m e]
|
||||
(let [[k (get e 0)] [v (get e 1)]]
|
||||
(if (in k m)
|
||||
(assoc m k (f (get m k) v))
|
||||
(assoc m k v)))
|
||||
m)]
|
||||
[merge2 (fn [m1 m2]
|
||||
(reduce merge-entry (.items m2) (or m1 {})))]]
|
||||
(reduce merge2 maps))))
|
||||
(let [merge-entry (fn [m e]
|
||||
(let [k (get e 0)
|
||||
v (get e 1)]
|
||||
(if (in k m)
|
||||
(assoc m k (f (get m k) v))
|
||||
(assoc m k v)))
|
||||
m)
|
||||
merge2 (fn [m1 m2]
|
||||
(reduce merge-entry (.items m2) (or m1 {})))]
|
||||
(reduce merge2 maps))))
|
||||
|
||||
(defn neg? [n]
|
||||
"Return true if n is < 0"
|
||||
@ -310,6 +349,18 @@
|
||||
(_numeric-check n)
|
||||
(= (% n 2) 1))
|
||||
|
||||
(def -sentinel (object))
|
||||
(defn partition [coll &optional [n 2] step [fillvalue -sentinel]]
|
||||
"Chunks coll into n-tuples (pairs by default). The remainder, if any, is not
|
||||
included unless a fillvalue is specified. The step defaults to n, but can be
|
||||
more to skip elements, or less for a sliding window with overlap."
|
||||
(setv
|
||||
step (or step n)
|
||||
slices (genexpr (itertools.islice coll start nil step) [start (range n)]))
|
||||
(if (is fillvalue -sentinel)
|
||||
(apply zip slices)
|
||||
(apply zip-longest slices {"fillvalue" fillvalue})))
|
||||
|
||||
(defn pos? [n]
|
||||
"Return true if n is > 0"
|
||||
(_numeric_check n)
|
||||
@ -347,18 +398,19 @@
|
||||
(defn take [count coll]
|
||||
"Take `count` elements from `coll`, or the whole set if the total
|
||||
number of entries in `coll` is less than `count`."
|
||||
(itertools.islice coll nil count))
|
||||
(islice coll nil count))
|
||||
|
||||
(defn take-nth [n coll]
|
||||
"Return every nth member of coll
|
||||
raises ValueError for (not (pos? n))"
|
||||
(if (pos? n)
|
||||
(let [[citer (iter coll)] [skip (dec n)]]
|
||||
(for* [val citer]
|
||||
(yield val)
|
||||
(for* [_ (range skip)]
|
||||
(next citer))))
|
||||
(raise (ValueError "n must be positive"))))
|
||||
(let [citer (iter coll)
|
||||
skip (dec n)]
|
||||
(for* [val citer]
|
||||
(yield val)
|
||||
(for* [_ (range skip)]
|
||||
(next citer))))
|
||||
(raise (ValueError "n must be positive"))))
|
||||
|
||||
(defn zero? [n]
|
||||
"Return true if n is 0"
|
||||
@ -373,7 +425,7 @@
|
||||
(while true
|
||||
(def inn (str (.readline from-file)))
|
||||
(if (= inn eof)
|
||||
(throw (EOFError "Reached end of file" )))
|
||||
(raise (EOFError "Reached end of file" )))
|
||||
(setv buff (+ buff inn))
|
||||
(try
|
||||
(def parsed (first (tokenize buff)))
|
||||
@ -381,13 +433,9 @@
|
||||
(else (if parsed (break)))))
|
||||
parsed)
|
||||
|
||||
(defun Botsbuildbots () (Botsbuildbots))
|
||||
|
||||
(defn zipwith [func &rest lists]
|
||||
"Zip the contents of several lists and map a function to the result"
|
||||
(do
|
||||
(import functools)
|
||||
(map (functools.partial (fn [f args] (apply f args)) func) (apply zip lists))))
|
||||
(defn read-str [input]
|
||||
"Reads and tokenizes first line of input"
|
||||
(read :from-file (StringIO input)))
|
||||
|
||||
(defn hyify [text]
|
||||
"Convert text to match hy identifier"
|
||||
@ -402,26 +450,26 @@
|
||||
(HyKeyword (+ ":" (hyify value)))
|
||||
(try
|
||||
(hyify (.__name__ value))
|
||||
(catch [] (HyKeyword (+ ":" (string value))))))))
|
||||
(except [] (HyKeyword (+ ":" (string value))))))))
|
||||
|
||||
(defn name [value]
|
||||
"Convert the given value to a string. Keyword special character will be stripped.
|
||||
String will be used as is. Even objects with the __name__ magic will work"
|
||||
(if (and (string? value) (value.startswith *keyword-prefix*))
|
||||
(hyify (slice value 2))
|
||||
(hyify (cut value 2))
|
||||
(if (string? value)
|
||||
(hyify value)
|
||||
(try
|
||||
(hyify (. value __name__))
|
||||
(catch [] (string value))))))
|
||||
(except [] (string value))))))
|
||||
|
||||
(def *exports* '[Botsbuildbots
|
||||
butlast calling-module-name coll? cons cons? cycle
|
||||
dec distinct disassemble drop drop-last drop-while empty? even?
|
||||
every? first filter filterfalse flatten float? gensym identity
|
||||
inc input instance? integer integer? integer-char? interleave
|
||||
interpose iterable? iterate iterator? keyword keyword? last list*
|
||||
macroexpand macroexpand-1 map merge-with name neg? nil? none?
|
||||
nth numeric? odd? pos? range read remove repeat repeatedly
|
||||
rest reduce second some string string? symbol? take take-nth
|
||||
take-while zero? zip zip_longest zipwith])
|
||||
(def *exports*
|
||||
'[*map accumulate butlast calling-module-name chain coll? combinations
|
||||
compress cons cons? count cycle dec distinct disassemble drop drop-last
|
||||
drop-while empty? even? every? first filter flatten float? fraction gensym
|
||||
group-by identity inc input instance? integer integer? integer-char?
|
||||
interleave interpose islice iterable? iterate iterator? keyword keyword?
|
||||
last list* macroexpand macroexpand-1 map merge-with multicombinations name
|
||||
neg? nil? none? nth numeric? odd? partition permutations pos? product range
|
||||
read read-str remove repeat repeatedly rest reduce second some string
|
||||
string? symbol? take take-nth take-while tee zero? zip zip-longest])
|
||||
|
@ -32,22 +32,22 @@
|
||||
|
||||
|
||||
(defmacro with [args &rest body]
|
||||
"shorthand for nested for* loops:
|
||||
(with [[x foo] [y bar]] baz) ->
|
||||
"shorthand for nested with* loops:
|
||||
(with [x foo y bar] baz) ->
|
||||
(with* [x foo]
|
||||
(with* [y bar]
|
||||
baz))"
|
||||
|
||||
(if (not (empty? args))
|
||||
(let [[primary (.pop args 0)]]
|
||||
(if (isinstance primary HyList)
|
||||
;;; OK. if we have a list, we can go ahead and unpack that
|
||||
;;; as the argument to with.
|
||||
`(with* [~@primary] (with ~args ~@body))
|
||||
;;; OK, let's just give it away. This may not be something we
|
||||
;;; can do, but that's really the programmer's problem.
|
||||
`(with* [~primary] (with ~args ~@body))))
|
||||
`(do ~@body)))
|
||||
(do
|
||||
(if (>= (len args) 2)
|
||||
(do
|
||||
(setv p1 (.pop args 0)
|
||||
p2 (.pop args 0)
|
||||
primary [p1 p2])
|
||||
`(with* [~@primary] (with ~args ~@body)))
|
||||
`(with* [~@args] ~@body)))
|
||||
`(do ~@body)))
|
||||
|
||||
|
||||
(defmacro car [thing]
|
||||
@ -57,7 +57,7 @@
|
||||
|
||||
(defmacro cdr [thing]
|
||||
"Get all the elements of a thing, except the first"
|
||||
`(slice ~thing 1))
|
||||
`(cut ~thing 1))
|
||||
|
||||
|
||||
(defmacro cond [&rest branches]
|
||||
@ -67,25 +67,29 @@
|
||||
bar
|
||||
(if baz
|
||||
quux))"
|
||||
(setv branches (iter branches))
|
||||
(setv branch (next branches))
|
||||
(defn check-branch [branch]
|
||||
"check `cond` branch for validity, return the corresponding `if` expr"
|
||||
(if (not (= (type branch) HyList))
|
||||
(macro-error branch "cond branches need to be a list"))
|
||||
(if (!= (len branch) 2)
|
||||
(macro-error branch "cond branches need two items: a test and a code branch"))
|
||||
(setv (, test thebranch) branch)
|
||||
`(if ~test ~thebranch))
|
||||
(if (empty? branches)
|
||||
nil
|
||||
(do
|
||||
(setv branches (iter branches))
|
||||
(setv branch (next branches))
|
||||
(defn check-branch [branch]
|
||||
"check `cond` branch for validity, return the corresponding `if` expr"
|
||||
(if (not (= (type branch) HyList))
|
||||
(macro-error branch "cond branches need to be a list"))
|
||||
(if (< (len branch) 2)
|
||||
(macro-error branch "cond branches need at least two items: a test and one or more code branches"))
|
||||
(setv test (car branch))
|
||||
(setv thebranch (cdr branch))
|
||||
`(if ~test (do ~@thebranch)))
|
||||
|
||||
(setv root (check-branch branch))
|
||||
(setv latest-branch root)
|
||||
(setv root (check-branch branch))
|
||||
(setv latest-branch root)
|
||||
|
||||
(for* [branch branches]
|
||||
(setv cur-branch (check-branch branch))
|
||||
(.append latest-branch cur-branch)
|
||||
(setv latest-branch cur-branch))
|
||||
root)
|
||||
(for* [branch branches]
|
||||
(setv cur-branch (check-branch branch))
|
||||
(.append latest-branch cur-branch)
|
||||
(setv latest-branch cur-branch))
|
||||
root)))
|
||||
|
||||
|
||||
(defmacro for [args &rest body]
|
||||
@ -96,16 +100,23 @@
|
||||
(for* [x foo]
|
||||
(for* [y bar]
|
||||
baz))"
|
||||
(cond
|
||||
(setv body (list body))
|
||||
(if (empty? body)
|
||||
(macro-error None "`for' requires a body to evaluate"))
|
||||
(setv lst (get body -1))
|
||||
(setv belse (if (and (isinstance lst HyExpression) (= (get lst 0) "else"))
|
||||
[(body.pop)]
|
||||
[]))
|
||||
(cond
|
||||
[(odd? (len args))
|
||||
(macro-error args "`for' requires an even number of args.")]
|
||||
[(empty? body)
|
||||
(macro-error None "`for' requires a body to evaluate")]
|
||||
[(empty? args) `(do ~@body)]
|
||||
[(= (len args) 2) `(for* [~@args] ~@body)]
|
||||
[true
|
||||
(let [[alist (slice args 0 nil 2)]]
|
||||
`(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] ~@body))]))
|
||||
[(empty? args) `(do ~@body ~@belse)]
|
||||
[(= (len args) 2) `(for* [~@args] (do ~@body) ~@belse)]
|
||||
[true
|
||||
(let [alist (cut args 0 nil 2)]
|
||||
`(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] (do ~@body) ~@belse))]))
|
||||
|
||||
|
||||
(defmacro -> [head &rest rest]
|
||||
@ -127,7 +138,7 @@
|
||||
(if (isinstance expression HyExpression)
|
||||
`(~(first expression) ~f ~@(rest expression))
|
||||
`(~expression ~f)))
|
||||
`(let [[~f ~form]]
|
||||
`(let [~f ~form]
|
||||
~@(map build-form expressions)
|
||||
~f))
|
||||
|
||||
@ -149,11 +160,11 @@
|
||||
`(if (not ~test) ~not-branch ~yes-branch)))
|
||||
|
||||
|
||||
(defmacro-alias [lisp-if lif] [test &rest branches]
|
||||
(defmacro lif [test &rest branches]
|
||||
"Like `if`, but anything that is not None/nil is considered true."
|
||||
`(if (is-not ~test nil) ~@branches))
|
||||
|
||||
(defmacro-alias [lisp-if-not lif-not] [test &rest branches]
|
||||
(defmacro lif-not [test &rest branches]
|
||||
"Like `if-not`, but anything that is not None/nil is considered true."
|
||||
`(if (is ~test nil) ~@branches))
|
||||
|
||||
@ -169,14 +180,25 @@
|
||||
|
||||
|
||||
(defmacro with-gensyms [args &rest body]
|
||||
`(let ~(HyList (map (fn [x] `[~x (gensym '~x)]) args))
|
||||
~@body))
|
||||
(setv syms [])
|
||||
(for* [arg args]
|
||||
(.extend syms `[~arg (gensym '~arg)]))
|
||||
`(let ~syms
|
||||
~@body))
|
||||
|
||||
(defmacro defmacro/g! [name args &rest body]
|
||||
(let [[syms (list (distinct (filter (fn [x] (and (hasattr x "startswith") (.startswith x "g!"))) (flatten body))))]]
|
||||
(let [syms (list
|
||||
(distinct
|
||||
(filter (fn [x]
|
||||
(and (hasattr x "startswith")
|
||||
(.startswith x "g!")))
|
||||
(flatten body))))
|
||||
gensyms []]
|
||||
(for* [sym syms]
|
||||
(.extend gensyms `[~sym (gensym (cut '~sym 2))]))
|
||||
`(defmacro ~name [~@args]
|
||||
(let ~(HyList (map (fn [x] `[~x (gensym (slice '~x 2))]) syms))
|
||||
~@body))))
|
||||
(let ~gensyms
|
||||
~@body))))
|
||||
|
||||
|
||||
(if-python2
|
||||
@ -189,7 +211,7 @@
|
||||
(try (if (isinstance ~g!iter types.GeneratorType)
|
||||
(setv ~g!message (yield (.send ~g!iter ~g!message)))
|
||||
(setv ~g!message (yield (next ~g!iter))))
|
||||
(catch [~g!e StopIteration]
|
||||
(except [~g!e StopIteration]
|
||||
(do (setv ~g!return (if (hasattr ~g!e "value")
|
||||
(. ~g!e value)
|
||||
nil))
|
||||
@ -200,9 +222,9 @@
|
||||
|
||||
(defmacro defmain [args &rest body]
|
||||
"Write a function named \"main\" and do the if __main__ dance"
|
||||
(let [[retval (gensym)]
|
||||
[mainfn `(fn [~@args]
|
||||
~@body)]]
|
||||
(let [retval (gensym)
|
||||
mainfn `(fn [~@args]
|
||||
~@body)]
|
||||
`(when (= --name-- "__main__")
|
||||
(import sys)
|
||||
(setv ~retval (apply ~mainfn sys.argv))
|
||||
@ -210,24 +232,7 @@
|
||||
(sys.exit ~retval)))))
|
||||
|
||||
|
||||
(defmacro-alias [defn-alias defun-alias] [names lambda-list &rest body]
|
||||
"define one function with several names"
|
||||
(let [[main (first names)]
|
||||
[aliases (rest names)]]
|
||||
(setv ret `(do (defn ~main ~lambda-list ~@body)))
|
||||
(for* [name aliases]
|
||||
(.append ret
|
||||
`(setv ~name ~main)))
|
||||
ret))
|
||||
|
||||
(defmacro Botsbuildbots []
|
||||
"Build bots, repeatedly.^W^W^WPrint the AUTHORS, forever."
|
||||
`(try
|
||||
(do
|
||||
(import [requests])
|
||||
|
||||
(let [[r (requests.get
|
||||
"https://raw.githubusercontent.com/hylang/hy/master/AUTHORS")]]
|
||||
(repeat r.text)))
|
||||
(catch [e ImportError]
|
||||
(repeat "Botsbuildbots requires `requests' to function."))))
|
||||
(defreader @ [expr]
|
||||
(let [decorators (cut expr nil -1)
|
||||
fndef (get expr -1)]
|
||||
`(with-decorator ~@decorators ~fndef)))
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
(defn + [&rest args]
|
||||
"Shadow + operator for when we need to import / map it against something"
|
||||
(let [[count (len args)]]
|
||||
(let [count (len args)]
|
||||
(if (zero? count)
|
||||
(raise (TypeError "Need at least 1 argument to add/concatenate"))
|
||||
(if (= count 1)
|
||||
@ -36,7 +36,7 @@
|
||||
|
||||
(defn - [&rest args]
|
||||
"Shadow - operator for when we need to import / map it against something"
|
||||
(let [[count (len args)]]
|
||||
(let [count (len args)]
|
||||
(if (= count 0)
|
||||
(raise (TypeError "Need at least 1 argument to subtract"))
|
||||
(if (= count 1)
|
||||
@ -53,7 +53,7 @@
|
||||
|
||||
(defn / [&rest args]
|
||||
"Shadow / operator for when we need to import / map it against something"
|
||||
(let [[count (len args)]]
|
||||
(let [count (len args)]
|
||||
(if (= count 0)
|
||||
(raise (TypeError "Need at least 1 argument to divide"))
|
||||
(if (= count 1)
|
||||
@ -67,7 +67,7 @@
|
||||
(raise (TypeError "Need at least 2 arguments to compare"))
|
||||
(reduce operator.and_
|
||||
(list-comp (op x y)
|
||||
[(, x y) (zip args (slice args 1))]))))
|
||||
[(, x y) (zip args (cut args 1))]))))
|
||||
(defn < [&rest args]
|
||||
"Shadow < operator for when we need to import / map it against something"
|
||||
(comp-op operator.lt args))
|
||||
|
@ -116,6 +116,6 @@ class HyMacroExpansionError(HyTypeError):
|
||||
class HyIOError(HyError, IOError):
|
||||
"""
|
||||
Trivial subclass of IOError and HyError, to distinguish between
|
||||
IOErrors thrown by Hy itself as opposed to Hy programs.
|
||||
IOErrors raised by Hy itself as opposed to Hy programs.
|
||||
"""
|
||||
pass
|
||||
|
@ -33,6 +33,7 @@ import os
|
||||
import __future__
|
||||
|
||||
from hy._compat import PY3, PY33, MAGIC, builtins, long_type, wr_long
|
||||
from hy._compat import string_types
|
||||
|
||||
|
||||
def ast_compile(ast, filename, mode):
|
||||
@ -108,6 +109,10 @@ def hy_eval(hytree, namespace, module_name):
|
||||
foo.start_column = 0
|
||||
foo.end_column = 0
|
||||
replace_hy_obj(hytree, foo)
|
||||
|
||||
if not isinstance(module_name, string_types):
|
||||
raise HyTypeError(foo, "Module name must be a string")
|
||||
|
||||
_ast, expr = hy_compile(hytree, module_name, get_expr=True)
|
||||
|
||||
# Spoof the positions in the generated ast...
|
||||
@ -119,6 +124,9 @@ def hy_eval(hytree, namespace, module_name):
|
||||
node.lineno = 1
|
||||
node.col_offset = 1
|
||||
|
||||
if not isinstance(namespace, dict):
|
||||
raise HyTypeError(foo, "Globals must be a dictionary")
|
||||
|
||||
# Two-step eval: eval() the body of the exec call
|
||||
eval(ast_compile(_ast, "<eval_body>", "exec"), namespace)
|
||||
|
||||
|
@ -35,3 +35,7 @@ def tokenize(buf):
|
||||
pos = e.getsourcepos()
|
||||
raise LexException("Could not identify the next token.",
|
||||
pos.lineno, pos.colno)
|
||||
except LexException as e:
|
||||
if e.source is None:
|
||||
e.source = buf
|
||||
raise
|
||||
|
@ -50,7 +50,7 @@ partial_string = r'''(?x)
|
||||
" # start string
|
||||
(?:
|
||||
| [^"\\] # non-quote or backslash
|
||||
| \\. # or escaped single character
|
||||
| \\(.|\n) # or escaped single character or newline
|
||||
| \\x[0-9a-fA-F]{2} # or escaped raw character
|
||||
| \\u[0-9a-fA-F]{4} # or unicode escape
|
||||
| \\U[0-9a-fA-F]{8} # or long unicode escape
|
||||
|
@ -45,6 +45,22 @@ pg = ParserGenerator(
|
||||
)
|
||||
|
||||
|
||||
def hy_symbol_mangle(p):
|
||||
if p.startswith("*") and p.endswith("*") and p not in ("*", "**"):
|
||||
p = p[1:-1].upper()
|
||||
|
||||
if "-" in p and p != "-":
|
||||
p = p.replace("-", "_")
|
||||
|
||||
if p.endswith("?") and p != "?":
|
||||
p = "is_%s" % (p[:-1])
|
||||
|
||||
if p.endswith("!") and p != "!":
|
||||
p = "%s_bang" % (p[:-1])
|
||||
|
||||
return p
|
||||
|
||||
|
||||
def set_boundaries(fun):
|
||||
@wraps(fun)
|
||||
def wrapped(p):
|
||||
@ -266,6 +282,14 @@ def t_identifier(p):
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if '/' in obj:
|
||||
try:
|
||||
lhs, rhs = obj.split('/')
|
||||
return HyExpression([HySymbol('fraction'), HyInteger(lhs),
|
||||
HyInteger(rhs)])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return HyFloat(obj)
|
||||
except ValueError:
|
||||
@ -281,7 +305,6 @@ def t_identifier(p):
|
||||
"true": "True",
|
||||
"false": "False",
|
||||
"nil": "None",
|
||||
"null": "None",
|
||||
}
|
||||
|
||||
if obj in table:
|
||||
@ -290,19 +313,7 @@ def t_identifier(p):
|
||||
if obj.startswith(":"):
|
||||
return HyKeyword(obj)
|
||||
|
||||
def mangle(p):
|
||||
if p.startswith("*") and p.endswith("*") and p not in ("*", "**"):
|
||||
p = p[1:-1].upper()
|
||||
|
||||
if "-" in p and p != "-":
|
||||
p = p.replace("-", "_")
|
||||
|
||||
if p.endswith("?") and p != "?":
|
||||
p = "is_%s" % (p[:-1])
|
||||
|
||||
return p
|
||||
|
||||
obj = ".".join([mangle(part) for part in obj.split(".")])
|
||||
obj = ".".join([hy_symbol_mangle(part) for part in obj.split(".")])
|
||||
|
||||
return HySymbol(obj)
|
||||
|
||||
|
40
hy/macros.py
40
hy/macros.py
@ -18,6 +18,7 @@
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
# DEALINGS IN THE SOFTWARE.
|
||||
|
||||
from inspect import getargspec, formatargspec
|
||||
from hy.models import replace_hy_obj, wrap_value
|
||||
from hy.models.expression import HyExpression
|
||||
from hy.models.string import HyString
|
||||
@ -60,7 +61,7 @@ def macro(name):
|
||||
|
||||
|
||||
def reader(name):
|
||||
"""Decorator to define a macro called `name`.
|
||||
"""Decorator to define a reader macro called `name`.
|
||||
|
||||
This stores the macro `name` in the namespace for the module where it is
|
||||
defined.
|
||||
@ -68,7 +69,7 @@ def reader(name):
|
||||
If the module where it is defined is in `hy.core`, then the macro is stored
|
||||
in the default `None` namespace.
|
||||
|
||||
This function is called from the `defmacro` special form in the compiler.
|
||||
This function is called from the `defreader` special form in the compiler.
|
||||
|
||||
"""
|
||||
def _(fn):
|
||||
@ -122,6 +123,16 @@ def load_macros(module_name):
|
||||
_import(module)
|
||||
|
||||
|
||||
def make_emtpy_fn_copy(fn):
|
||||
argspec = getargspec(fn)
|
||||
formatted_args = formatargspec(*argspec)
|
||||
fn_str = 'lambda {}: None'.format(
|
||||
formatted_args.lstrip('(').rstrip(')'))
|
||||
|
||||
empty_fn = eval(fn_str)
|
||||
return empty_fn
|
||||
|
||||
|
||||
def macroexpand(tree, module_name):
|
||||
"""Expand the toplevel macros for the `tree`.
|
||||
|
||||
@ -155,6 +166,14 @@ def macroexpand_1(tree, module_name):
|
||||
if m is None:
|
||||
m = _hy_macros[None].get(fn)
|
||||
if m is not None:
|
||||
try:
|
||||
m_copy = make_emtpy_fn_copy(m)
|
||||
m_copy(*ntree[1:])
|
||||
except TypeError as e:
|
||||
msg = "expanding `" + str(tree[0]) + "': "
|
||||
msg += str(e).replace("<lambda>()", "", 1).strip()
|
||||
raise HyMacroExpansionError(tree, msg)
|
||||
|
||||
try:
|
||||
obj = wrap_value(m(*ntree[1:]))
|
||||
|
||||
@ -176,14 +195,15 @@ def reader_macroexpand(char, tree, module_name):
|
||||
"""Expand the reader macro "char" with argument `tree`."""
|
||||
load_macros(module_name)
|
||||
|
||||
if char not in _hy_reader[module_name]:
|
||||
raise HyTypeError(
|
||||
char,
|
||||
"`{0}' is not a reader macro in module '{1}'".format(
|
||||
reader_macro = _hy_reader[module_name].get(char)
|
||||
if reader_macro is None:
|
||||
try:
|
||||
reader_macro = _hy_reader[None][char]
|
||||
except KeyError:
|
||||
raise HyTypeError(
|
||||
char,
|
||||
module_name,
|
||||
),
|
||||
)
|
||||
"`{0}' is not a defined reader macro.".format(char)
|
||||
)
|
||||
|
||||
expr = _hy_reader[module_name][char](tree)
|
||||
expr = reader_macro(tree)
|
||||
return replace_hy_obj(wrap_value(expr), tree)
|
||||
|
@ -19,7 +19,7 @@
|
||||
# DEALINGS IN THE SOFTWARE.
|
||||
|
||||
from hy.models import HyObject, _wrappers
|
||||
from hy._compat import long_type
|
||||
from hy._compat import long_type, str_type
|
||||
|
||||
import sys
|
||||
|
||||
@ -32,7 +32,19 @@ class HyInteger(HyObject, long_type):
|
||||
"""
|
||||
|
||||
def __new__(cls, number, *args, **kwargs):
|
||||
number = long_type(number)
|
||||
if isinstance(number, str_type):
|
||||
bases = {"0x": 16, "0o": 8, "0b": 2}
|
||||
for leader, base in bases.items():
|
||||
if number.startswith(leader):
|
||||
# We've got a string, known leader, set base.
|
||||
number = long_type(number, base=base)
|
||||
break
|
||||
else:
|
||||
# We've got a string, no known leader; base 10.
|
||||
number = long_type(number, base=10)
|
||||
else:
|
||||
# We've got a non-string; convert straight.
|
||||
number = long_type(number)
|
||||
return super(HyInteger, cls).__new__(cls, number)
|
||||
|
||||
|
||||
|
@ -7,26 +7,26 @@
|
||||
(setv *maintainer-line*
|
||||
" -- Alexander Artemenko <svetlyak.40wt@gmail.com> Thu, 30 Sep 2014 13:06:09 +0400")
|
||||
|
||||
(defun read-lines-from-file [filename]
|
||||
(let [[f (codecs.open filename "r" "utf-8")]]
|
||||
(fn [] (let [[line (.readline f) ]]
|
||||
line))))
|
||||
(defn read-lines-from-file [filename]
|
||||
(let [f (codecs.open filename "r" "utf-8")]
|
||||
(fn [] (let [line (.readline f) ]
|
||||
line))))
|
||||
|
||||
|
||||
(defun get-version-number [line]
|
||||
(let [[match (re.search r"Changes from.*(\d+\.\d+\.\d+)$" line)]]
|
||||
(if match
|
||||
(let [[version (.group match (int 1))]
|
||||
[numbered (list (map int (.split version "."))) ]
|
||||
[explicit-mapping {"0.9.12" "0.10.0"
|
||||
"0.8.2" "0.9.0"}]]
|
||||
(assoc numbered 2 (+ (get numbered 2) 1))
|
||||
(.get explicit-mapping
|
||||
version
|
||||
(.join "." (map str numbered)))))))
|
||||
(defn get-version-number [line]
|
||||
(let [match (re.search r"Changes from.*(\d+\.\d+\.\d+)$" line)]
|
||||
(if match
|
||||
(let [version (.group match (int 1))
|
||||
numbered (list (map int (.split version ".")))
|
||||
explicit-mapping {"0.9.12" "0.10.0"
|
||||
"0.8.2" "0.9.0"}]
|
||||
(assoc numbered 2 (+ (get numbered 2) 1))
|
||||
(.get explicit-mapping
|
||||
version
|
||||
(.join "." (map str numbered)))))))
|
||||
|
||||
|
||||
(defun read-version-content [reader]
|
||||
(defn read-version-content [reader]
|
||||
(setv line (reader))
|
||||
(setv content [])
|
||||
(while (and line (not (get-version-number line)))
|
||||
@ -35,22 +35,22 @@
|
||||
[content line])
|
||||
|
||||
|
||||
(defun read-versions-from-file [filename]
|
||||
(let [[reader (read-lines-from-file filename)]]
|
||||
(read-versions-rec (reader)
|
||||
reader)))
|
||||
(defn read-versions-from-file [filename]
|
||||
(let [reader (read-lines-from-file filename)]
|
||||
(read-versions-rec (reader)
|
||||
reader)))
|
||||
|
||||
(defun read-versions-rec [line reader]
|
||||
(defn read-versions-rec [line reader]
|
||||
(if line
|
||||
(let [[version (get-version-number line)]
|
||||
[[content next-line] (read-version-content reader)]]
|
||||
(let [version (get-version-number line)
|
||||
[content next-line] (read-version-content reader)]
|
||||
|
||||
(+ [{"from" version
|
||||
"content" content}]
|
||||
(read-versions-rec next-line reader)))
|
||||
[]))
|
||||
|
||||
(defun format-deb-version [version]
|
||||
(defn format-deb-version [version]
|
||||
(setv result [(.format "hy ({}) unstable; urgency=low"
|
||||
(get version "from"))])
|
||||
(for [line (get version "content")]
|
||||
@ -61,6 +61,6 @@
|
||||
|
||||
|
||||
(defmain [&rest args]
|
||||
(let ((versions (read-versions-from-file "NEWS")))
|
||||
(let [versions (read-versions-from-file "NEWS")]
|
||||
(for [version versions]
|
||||
(print (.encode (format-deb-version version) "utf-8")))))
|
||||
(print (.encode (format-deb-version version) "utf-8")))))
|
||||
|
@ -33,5 +33,5 @@
|
||||
(setv filename (os.path.abspath (os.path.join os.path.pardir
|
||||
"docs" "coreteam.rst")))
|
||||
|
||||
(with [[fobj (open filename "w+")]]
|
||||
(with [fobj (open filename "w+")]
|
||||
(fobj.write (+ (.join "\n" result) "\n")))
|
||||
|
@ -20,6 +20,7 @@ from .native_tests.contrib.meth import * # noqa
|
||||
from .native_tests.contrib.walk import * # noqa
|
||||
from .native_tests.contrib.multi import * # noqa
|
||||
from .native_tests.contrib.curry import * # noqa
|
||||
from .native_tests.contrib.botsbuildbots import * # noqa
|
||||
|
||||
if PY3:
|
||||
from .native_tests.py3_only_tests import * # noqa
|
||||
|
@ -111,17 +111,6 @@ def test_ast_good_do():
|
||||
can_compile("(do 1)")
|
||||
|
||||
|
||||
def test_ast_good_throw():
|
||||
"Make sure AST can compile valid throw"
|
||||
can_compile("(throw)")
|
||||
can_compile("(throw Exception)")
|
||||
|
||||
|
||||
def test_ast_bad_throw():
|
||||
"Make sure AST can't compile invalid throw"
|
||||
cant_compile("(throw Exception Exception)")
|
||||
|
||||
|
||||
def test_ast_good_raise():
|
||||
"Make sure AST can compile valid raise"
|
||||
can_compile("(raise)")
|
||||
@ -160,26 +149,6 @@ def test_ast_bad_try():
|
||||
cant_compile("(try 1 (else 1))")
|
||||
|
||||
|
||||
def test_ast_good_catch():
|
||||
"Make sure AST can compile valid catch"
|
||||
can_compile("(try 1 (catch))")
|
||||
can_compile("(try 1 (catch []))")
|
||||
can_compile("(try 1 (catch [Foobar]))")
|
||||
can_compile("(try 1 (catch [[]]))")
|
||||
can_compile("(try 1 (catch [x FooBar]))")
|
||||
can_compile("(try 1 (catch [x [FooBar BarFoo]]))")
|
||||
can_compile("(try 1 (catch [x [FooBar BarFoo]]))")
|
||||
|
||||
|
||||
def test_ast_bad_catch():
|
||||
"Make sure AST can't compile invalid catch"
|
||||
cant_compile("(catch 22)") # heh
|
||||
cant_compile("(try (catch 1))")
|
||||
cant_compile("(try (catch \"A\"))")
|
||||
cant_compile("(try (catch [1 3]))")
|
||||
cant_compile("(try (catch [x [FooBar] BarBar]))")
|
||||
|
||||
|
||||
def test_ast_good_except():
|
||||
"Make sure AST can compile valid except"
|
||||
can_compile("(try 1 (except))")
|
||||
@ -250,8 +219,8 @@ def test_ast_good_defclass():
|
||||
def test_ast_bad_defclass():
|
||||
"Make sure AST can't compile invalid defclass"
|
||||
cant_compile("(defclass)")
|
||||
cant_compile("(defclass a null)")
|
||||
cant_compile("(defclass a null null)")
|
||||
cant_compile("(defclass a None)")
|
||||
cant_compile("(defclass a None None)")
|
||||
|
||||
|
||||
def test_ast_good_lambda():
|
||||
@ -291,18 +260,18 @@ def test_ast_bad_get():
|
||||
cant_compile("(get 1)")
|
||||
|
||||
|
||||
def test_ast_good_slice():
|
||||
"Make sure AST can compile valid slice"
|
||||
can_compile("(slice x)")
|
||||
can_compile("(slice x y)")
|
||||
can_compile("(slice x y z)")
|
||||
can_compile("(slice x y z t)")
|
||||
def test_ast_good_cut():
|
||||
"Make sure AST can compile valid cut"
|
||||
can_compile("(cut x)")
|
||||
can_compile("(cut x y)")
|
||||
can_compile("(cut x y z)")
|
||||
can_compile("(cut x y z t)")
|
||||
|
||||
|
||||
def test_ast_bad_slice():
|
||||
"Make sure AST can't compile invalid slice"
|
||||
cant_compile("(slice)")
|
||||
cant_compile("(slice 1 2 3 4 5)")
|
||||
def test_ast_bad_cut():
|
||||
"Make sure AST can't compile invalid cut"
|
||||
cant_compile("(cut)")
|
||||
cant_compile("(cut 1 2 3 4 5)")
|
||||
|
||||
|
||||
def test_ast_good_take():
|
||||
@ -352,20 +321,18 @@ def test_ast_invalid_for():
|
||||
|
||||
def test_ast_valid_let():
|
||||
"Make sure AST can compile valid let"
|
||||
can_compile("(let [])")
|
||||
can_compile("(let [a b])")
|
||||
can_compile("(let [[a 1]])")
|
||||
can_compile("(let [[a 1] b])")
|
||||
can_compile("(let [a 1])")
|
||||
can_compile("(let [a 1 b nil])")
|
||||
|
||||
|
||||
def test_ast_invalid_let():
|
||||
"Make sure AST can't compile invalid let"
|
||||
cant_compile("(let 1)")
|
||||
cant_compile("(let [1])")
|
||||
cant_compile("(let [[a 1 2]])")
|
||||
cant_compile("(let [[]])")
|
||||
cant_compile("(let [[a]])")
|
||||
cant_compile("(let [[1]])")
|
||||
cant_compile("(let [a 1 2])")
|
||||
cant_compile("(let [a])")
|
||||
cant_compile("(let [1])")
|
||||
|
||||
|
||||
def test_ast_expression_basics():
|
||||
@ -470,6 +437,16 @@ def test_lambda_list_keywords_mixed():
|
||||
" (list x xs kwxs kwoxs))")
|
||||
|
||||
|
||||
def test_missing_keyword_argument_value():
|
||||
"""Ensure the compiler chokes on missing keyword argument values."""
|
||||
try:
|
||||
can_compile("((fn [x] x) :x)")
|
||||
except HyTypeError as e:
|
||||
assert(e.message == "Keyword argument :x needs a value.")
|
||||
else:
|
||||
assert(False)
|
||||
|
||||
|
||||
def test_ast_unicode_strings():
|
||||
"""Ensure we handle unicode strings correctly"""
|
||||
|
||||
@ -515,7 +492,7 @@ def test_for_compile_error():
|
||||
assert(False)
|
||||
|
||||
try:
|
||||
can_compile("(fn [] (for [x]))")
|
||||
can_compile("(fn [] (for [x] x))")
|
||||
except HyTypeError as e:
|
||||
assert(e.message == "`for' requires an even number of args.")
|
||||
else:
|
||||
@ -528,6 +505,13 @@ def test_for_compile_error():
|
||||
else:
|
||||
assert(False)
|
||||
|
||||
try:
|
||||
can_compile("(fn [] (for [x xx] (else 1)))")
|
||||
except HyTypeError as e:
|
||||
assert(e.message == "`for' requires a body to evaluate")
|
||||
else:
|
||||
assert(False)
|
||||
|
||||
|
||||
def test_attribute_access():
|
||||
"""Ensure attribute access compiles correctly"""
|
||||
@ -543,3 +527,39 @@ def test_attribute_access():
|
||||
def test_cons_correct():
|
||||
"""Ensure cons gets compiled correctly"""
|
||||
can_compile("(cons a b)")
|
||||
|
||||
|
||||
def test_invalid_list_comprehension():
|
||||
"""Ensure that invalid list comprehensions do not break the compiler"""
|
||||
cant_compile("(genexpr x [])")
|
||||
cant_compile("(genexpr [x [1 2 3 4]] x)")
|
||||
cant_compile("(list-comp None [])")
|
||||
cant_compile("(list-comp [x [1 2 3]] x)")
|
||||
|
||||
|
||||
def test_bad_setv():
|
||||
"""Ensure setv handles error cases"""
|
||||
cant_compile("(setv if 1)")
|
||||
cant_compile("(setv (a b) [1 2])")
|
||||
|
||||
|
||||
def test_defn():
|
||||
"""Ensure that defn works correctly in various corner cases"""
|
||||
cant_compile("(defn if [] 1)")
|
||||
cant_compile("(defn \"hy\" [] 1)")
|
||||
cant_compile("(defn :hy [] 1)")
|
||||
can_compile("(defn &hy [] 1)")
|
||||
|
||||
|
||||
def test_setv_builtins():
|
||||
"""Ensure that assigning to a builtin fails, unless in a class"""
|
||||
cant_compile("(setv nil 42)")
|
||||
cant_compile("(defn get [&rest args] 42)")
|
||||
can_compile("(defclass A [] (defn get [self] 42))")
|
||||
can_compile("""
|
||||
(defclass A []
|
||||
(defn get [self] 42)
|
||||
(defclass B []
|
||||
(defn get [self] 42))
|
||||
(defn if [self] 0))
|
||||
""")
|
||||
|
@ -98,8 +98,14 @@ def test_lex_symbols():
|
||||
|
||||
def test_lex_strings():
|
||||
""" Make sure that strings are valid expressions"""
|
||||
objs = tokenize("\"foo\" ")
|
||||
objs = tokenize('"foo"')
|
||||
assert objs == [HyString("foo")]
|
||||
# Make sure backslash-escaped newlines work (see issue #831)
|
||||
objs = tokenize(r"""
|
||||
"a\
|
||||
bc"
|
||||
""")
|
||||
assert objs == [HyString("abc")]
|
||||
|
||||
|
||||
def test_lex_integers():
|
||||
@ -108,6 +114,13 @@ def test_lex_integers():
|
||||
assert objs == [HyInteger(42)]
|
||||
|
||||
|
||||
def test_lex_fractions():
|
||||
""" Make sure that fractions are valid expressions"""
|
||||
objs = tokenize("1/2")
|
||||
assert objs == [HyExpression([HySymbol("fraction"), HyInteger(1),
|
||||
HyInteger(2)])]
|
||||
|
||||
|
||||
def test_lex_expression_float():
|
||||
""" Make sure expressions can produce floats """
|
||||
objs = tokenize("(foo 2.)")
|
||||
@ -319,6 +332,24 @@ def test_lex_mangling_qmark():
|
||||
assert entry == [HySymbol(".is_foo.bar.is_baz")]
|
||||
|
||||
|
||||
def test_lex_mangling_bang():
|
||||
"""Ensure that identifiers ending with a bang get mangled ok"""
|
||||
entry = tokenize("foo!")
|
||||
assert entry == [HySymbol("foo_bang")]
|
||||
entry = tokenize("!")
|
||||
assert entry == [HySymbol("!")]
|
||||
entry = tokenize("im!foo")
|
||||
assert entry == [HySymbol("im!foo")]
|
||||
entry = tokenize(".foo!")
|
||||
assert entry == [HySymbol(".foo_bang")]
|
||||
entry = tokenize("foo.bar!")
|
||||
assert entry == [HySymbol("foo.bar_bang")]
|
||||
entry = tokenize("foo!.bar")
|
||||
assert entry == [HySymbol("foo_bang.bar")]
|
||||
entry = tokenize(".foo!.bar.baz!")
|
||||
assert entry == [HySymbol(".foo_bang.bar.baz_bang")]
|
||||
|
||||
|
||||
def test_simple_cons():
|
||||
"""Check that cons gets tokenized correctly"""
|
||||
entry = tokenize("(a . b)")[0]
|
||||
|
@ -6,6 +6,7 @@ from hy.models.string import HyString
|
||||
from hy.models.list import HyList
|
||||
from hy.models.symbol import HySymbol
|
||||
from hy.models.expression import HyExpression
|
||||
from hy.errors import HyMacroExpansionError
|
||||
|
||||
|
||||
@macro("test")
|
||||
@ -35,3 +36,13 @@ def test_preprocessor_expression():
|
||||
obj = HyList([HyString("one"), HyString("two")])
|
||||
obj = tokenize('(shill ["one" "two"])')[0][1]
|
||||
assert obj == macroexpand(obj, '')
|
||||
|
||||
|
||||
def test_preprocessor_exceptions():
|
||||
""" Test that macro expansion raises appropriate exceptions"""
|
||||
try:
|
||||
macroexpand(tokenize('(defn)')[0], __name__)
|
||||
assert False
|
||||
except HyMacroExpansionError as e:
|
||||
assert "_hy_anon_fn_" not in str(e)
|
||||
assert "TypeError" not in str(e)
|
||||
|
8
tests/native_tests/contrib/alias.hy
Normal file
8
tests/native_tests/contrib/alias.hy
Normal file
@ -0,0 +1,8 @@
|
||||
(require hy.contrib.alias)
|
||||
|
||||
(defn test-defn-alias []
|
||||
(defn-alias [tda-main tda-a1 tda-a2] [] :bazinga)
|
||||
(assert (= (tda-main) :bazinga))
|
||||
(assert (= (tda-a1) :bazinga))
|
||||
(assert (= (tda-a2) :bazinga))
|
||||
(assert (= tda-main tda-a1 tda-a2)))
|
@ -55,7 +55,7 @@
|
||||
[3 6 9])
|
||||
(assert-equal (list (ap-map (* it 3) []))
|
||||
[])
|
||||
(assert-equal (let [[v 1] [f 1]] (list (ap-map (it v f) [(fn [a b] (+ a b))])))
|
||||
(assert-equal (let [v 1 f 1] (list (ap-map (it v f) [(fn [a b] (+ a b))])))
|
||||
[2]))
|
||||
|
||||
(defn test-ap-map-when []
|
||||
@ -79,9 +79,9 @@
|
||||
|
||||
(defn test-ap-dotimes []
|
||||
"NATIVE: testing anaphoric dotimes"
|
||||
(assert-equal (let [[n []]] (ap-dotimes 3 (.append n 3)) n)
|
||||
(assert-equal (let [n []] (ap-dotimes 3 (.append n 3)) n)
|
||||
[3 3 3])
|
||||
(assert-equal (let [[n []]] (ap-dotimes 3 (.append n it)) n)
|
||||
(assert-equal (let [n []] (ap-dotimes 3 (.append n it)) n)
|
||||
[0 1 2]))
|
||||
|
||||
(defn test-ap-first []
|
||||
@ -113,3 +113,29 @@
|
||||
"NATIVE: testing anaphoric compose"
|
||||
(assert-equal ((ap-compose (+ it 1) (* it 3)) 2) 9)
|
||||
(assert-equal ((ap-compose (list (rest it)) (len it)) [4 5 6 7]) 3))
|
||||
|
||||
(defn test-xi []
|
||||
"NATIVE: testing xi forms"
|
||||
;; test ordering
|
||||
(assert-equal ((xi / x1 x2) 2 4) 0.5)
|
||||
(assert-equal ((xi / x2 x1) 2 4) 2)
|
||||
(assert-equal ((xi identity (, x5 x4 x3 x2 x1)) 1 2 3 4 5) (, 5 4 3 2 1))
|
||||
(assert-equal ((xi identity (, x1 x2 x3 x4 x5)) 1 2 3 4 5) (, 1 2 3 4 5))
|
||||
(assert-equal ((xi identity (, x1 x5 x2 x3 x4)) 1 2 3 4 5) (, 1 5 2 3 4))
|
||||
;; test &rest
|
||||
(assert-equal ((xi sum xi) 1 2 3) 6)
|
||||
(assert-equal ((xi identity (, x1 xi)) 10 1 2 3) (, 10 (, 1 2 3)))
|
||||
;; no parameters
|
||||
(assert-equal ((xi list)) [])
|
||||
(assert-equal ((xi identity "Hy!")) "Hy!")
|
||||
(assert-equal ((xi identity "xi")) "xi")
|
||||
(assert-equal ((xi + "Hy " "world!")) "Hy world!")
|
||||
;; test skipped parameters
|
||||
(assert-equal ((xi identity [x3 x1]) 1 2 3) [3 1])
|
||||
;; test nesting
|
||||
(assert-equal ((xi identity [x1 (, x2 [x3] "Hy" [xi])]) 1 2 3 4 5)
|
||||
[1 (, 2 [3] "Hy" [(, 4 5)])])
|
||||
;; test arg as function
|
||||
(assert-equal ((xi x1 2 4) +) 6)
|
||||
(assert-equal ((xi x1 2 4) -) -2)
|
||||
(assert-equal ((xi x1 2 4) /) 0.5))
|
||||
|
5
tests/native_tests/contrib/botsbuildbots.hy
Normal file
5
tests/native_tests/contrib/botsbuildbots.hy
Normal file
@ -0,0 +1,5 @@
|
||||
(import [hy.contrib.botsbuildbots [*]])
|
||||
(require hy.contrib.botsbuildbots)
|
||||
|
||||
(defn test-botsbuildbots []
|
||||
(assert (> (len (first (Botsbuildbots))) 50)))
|
@ -18,7 +18,7 @@
|
||||
;; non-tco-sum should fail
|
||||
(try
|
||||
(setv n (non-tco-sum 100 10000))
|
||||
(catch [e RuntimeError]
|
||||
(except [e RuntimeError]
|
||||
(assert true))
|
||||
(else
|
||||
(assert false)))
|
||||
@ -26,7 +26,7 @@
|
||||
;; tco-sum should not fail
|
||||
(try
|
||||
(setv n (tco-sum 100 10000))
|
||||
(catch [e RuntimeError]
|
||||
(except [e RuntimeError]
|
||||
(assert false))
|
||||
(else
|
||||
(assert (= n 10100)))))
|
||||
@ -40,7 +40,7 @@
|
||||
|
||||
(try
|
||||
(bad-recur 3)
|
||||
(catch [e TypeError]
|
||||
(except [e TypeError]
|
||||
(assert true))
|
||||
(else
|
||||
(assert false))))
|
||||
|
@ -2,52 +2,51 @@
|
||||
|
||||
(defclass FakeMeth []
|
||||
"Mocking decorator class"
|
||||
[[rules {}]
|
||||
[route (fn [self rule &kwargs options]
|
||||
(fn [f]
|
||||
(assoc self.rules rule (, f options))
|
||||
f))]])
|
||||
|
||||
[rules {}]
|
||||
(defn route [self rule &kwargs options]
|
||||
(fn [f]
|
||||
(assoc self.rules rule (, f options))
|
||||
f)))
|
||||
|
||||
(defn test_route []
|
||||
(let [[app (FakeMeth)]]
|
||||
(let [app (FakeMeth)]
|
||||
(route get-index "/" [] (str "Hy world!"))
|
||||
(setv app-rules (getattr app "rules"))
|
||||
(assert (in "/" app-rules))
|
||||
(let [[(, rule-fun rule-opt) (get app-rules "/")]]
|
||||
(let [(, rule-fun rule-opt) (get app-rules "/")]
|
||||
(assert (not (empty? rule-opt)))
|
||||
(assert (in "GET" (get rule-opt "methods")))
|
||||
(assert (= (getattr rule-fun "__name__") "get_index"))
|
||||
(assert (= "Hy world!" (rule-fun))))))
|
||||
|
||||
(defn test_post_route []
|
||||
(let [[app (FakeMeth)]]
|
||||
(let [app (FakeMeth)]
|
||||
(post-route get-index "/" [] (str "Hy world!"))
|
||||
(setv app-rules (getattr app "rules"))
|
||||
(assert (in "/" app-rules))
|
||||
(let [[(, rule-fun rule-opt) (get app-rules "/")]]
|
||||
(let [(, rule-fun rule-opt) (get app-rules "/")]
|
||||
(assert (not (empty? rule-opt)))
|
||||
(assert (in "POST" (get rule-opt "methods")))
|
||||
(assert (= (getattr rule-fun "__name__") "get_index"))
|
||||
(assert (= "Hy world!" (rule-fun))))))
|
||||
|
||||
(defn test_put_route []
|
||||
(let [[app (FakeMeth)]]
|
||||
(let [app (FakeMeth)]
|
||||
(put-route get-index "/" [] (str "Hy world!"))
|
||||
(setv app-rules (getattr app "rules"))
|
||||
(assert (in "/" app-rules))
|
||||
(let [[(, rule-fun rule-opt) (get app-rules "/")]]
|
||||
(let [(, rule-fun rule-opt) (get app-rules "/")]
|
||||
(assert (not (empty? rule-opt)))
|
||||
(assert (in "PUT" (get rule-opt "methods")))
|
||||
(assert (= (getattr rule-fun "__name__") "get_index"))
|
||||
(assert (= "Hy world!" (rule-fun))))))
|
||||
|
||||
(defn test_delete_route []
|
||||
(let [[app (FakeMeth)]]
|
||||
(let [app (FakeMeth)]
|
||||
(delete-route get-index "/" [] (str "Hy world!"))
|
||||
(setv app-rules (getattr app "rules"))
|
||||
(assert (in "/" app-rules))
|
||||
(let [[(, rule-fun rule-opt) (get app-rules "/")]]
|
||||
(let [(, rule-fun rule-opt) (get app-rules "/")]
|
||||
(assert (not (empty? rule-opt)))
|
||||
(assert (in "DELETE" (get rule-opt "methods")))
|
||||
(assert (= (getattr rule-fun "__name__") "get_index"))
|
||||
|
@ -15,21 +15,21 @@
|
||||
walk-form)))
|
||||
|
||||
(defn test-walk []
|
||||
(let [[acc '()]]
|
||||
(let [acc '()]
|
||||
(assert (= (walk (partial collector acc) identity walk-form)
|
||||
[nil nil]))
|
||||
(assert (= acc walk-form)))
|
||||
(let [[acc []]]
|
||||
(let [acc []]
|
||||
(assert (= (walk identity (partial collector acc) walk-form)
|
||||
nil))
|
||||
(assert (= acc [walk-form]))))
|
||||
|
||||
(defn test-walk-iterators []
|
||||
(let [[acc []]]
|
||||
(let [acc []]
|
||||
(assert (= (walk (fn [x] (* 2 x)) (fn [x] x)
|
||||
(drop 1 [1 [2 [3 [4]]]]))
|
||||
[[2 [3 [4]] 2 [3 [4]]]]))))
|
||||
|
||||
(defn test-macroexpand-all []
|
||||
(assert (= (macroexpand-all '(with [a b c] (for [d c] foo)))
|
||||
'(with* [a] (with* [b] (with* [c] (do (for* [d c] foo))))))))
|
||||
(assert (= (macroexpand-all '(with [a 1 b 2 c 3] (for [d c] foo)))
|
||||
'(with* [a 1] (with* [b 2] (with* [c 3] (do (for* [d c] (do foo)))))))))
|
||||
|
@ -67,11 +67,11 @@
|
||||
(assert-equal -1 (dec 0))
|
||||
(assert-equal 0 (dec (dec 2)))
|
||||
(try (do (dec "foo") (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (dec []) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (dec None) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
|
||||
(defn test-setv []
|
||||
"NATIVE: testing setv mutation"
|
||||
@ -85,9 +85,9 @@
|
||||
(assert-equal (x y) 9)
|
||||
(assert-equal (y x) 9)
|
||||
(try (do (setv a.b 1) (assert False))
|
||||
(catch [e [NameError]] (assert (in "name 'a' is not defined" (str e)))))
|
||||
(except [e [NameError]] (assert (in "name 'a' is not defined" (str e)))))
|
||||
(try (do (setv b.a (fn [x] x)) (assert False))
|
||||
(catch [e [NameError]] (assert (in "name 'b' is not defined" (str e)))))
|
||||
(except [e [NameError]] (assert (in "name 'b' is not defined" (str e)))))
|
||||
(import itertools)
|
||||
(setv foopermutations (fn [x] (itertools.permutations x)))
|
||||
(setv p (set [(, 1 3 2) (, 3 2 1) (, 2 1 3) (, 3 1 2) (, 1 2 3) (, 2 3 1)]))
|
||||
@ -127,7 +127,7 @@
|
||||
(setv res (list (drop 0 [1 2 3 4 5])))
|
||||
(assert-equal res [1 2 3 4 5])
|
||||
(try (do (list (drop -1 [1 2 3 4 5])) (assert False))
|
||||
(catch [e [ValueError]] nil))
|
||||
(except [e [ValueError]] nil))
|
||||
(setv res (list (drop 6 (iter [1 2 3 4 5]))))
|
||||
(assert-equal res [])
|
||||
(setv res (list (take 5 (drop 2 (iterate inc 0)))))
|
||||
@ -174,11 +174,11 @@
|
||||
(assert-false (even? 1))
|
||||
(assert-true (even? 0))
|
||||
(try (even? "foo")
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (even? [])
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (even? None)
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
|
||||
(defn test-every? []
|
||||
"NATIVE: testing the every? function"
|
||||
@ -221,9 +221,9 @@
|
||||
(setv res (flatten (, 1 (, None 3))))
|
||||
(assert-equal res [1 None 3])
|
||||
(try (flatten "foo")
|
||||
(catch [e [TypeError]] (assert (in "not a collection" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a collection" (str e)))))
|
||||
(try (flatten 12.34)
|
||||
(catch [e [TypeError]] (assert (in "not a collection" (str e))))))
|
||||
(except [e [TypeError]] (assert (in "not a collection" (str e))))))
|
||||
|
||||
(defn test-float? []
|
||||
"NATIVE: testing the float? function"
|
||||
@ -264,11 +264,11 @@
|
||||
(assert-equal 3 (inc 2))
|
||||
(assert-equal 0 (inc -1))
|
||||
(try (do (inc "foo") (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (inc []) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (inc None) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
|
||||
(defn test-instance []
|
||||
"NATIVE: testing instance? function"
|
||||
@ -395,11 +395,11 @@
|
||||
(assert-false (neg? 1))
|
||||
(assert-false (neg? 0))
|
||||
(try (do (neg? "foo") (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (neg? []) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (neg? None) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
|
||||
(defn test-zero []
|
||||
"NATIVE: testing the zero? function"
|
||||
@ -407,11 +407,11 @@
|
||||
(assert-false (zero? 1))
|
||||
(assert-true (zero? 0))
|
||||
(try (do (zero? "foo") (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (zero? []) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (zero? None) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
|
||||
(defn test-none []
|
||||
"NATIVE: testing for `is None`"
|
||||
@ -438,7 +438,7 @@
|
||||
(assert-equal (nth [1 2 4 7] 5 "some default value")
|
||||
"some default value") ; with default specified
|
||||
(try (do (nth [1 2 4 7] -1) (assert False))
|
||||
(catch [e [ValueError]] nil))
|
||||
(except [e [ValueError]] nil))
|
||||
;; now for iterators
|
||||
(assert-equal 2 (nth (iter [1 2 4 7]) 1))
|
||||
(assert-equal 7 (nth (iter [1 2 4 7]) 3))
|
||||
@ -446,7 +446,7 @@
|
||||
(assert-equal (nth (iter [1 2 4 7]) 5 "some default value")
|
||||
"some default value") ; with default specified
|
||||
(try (do (nth (iter [1 2 4 7]) -1) (assert False))
|
||||
(catch [e [ValueError]] nil))
|
||||
(except [e [ValueError]] nil))
|
||||
(assert-equal 5 (nth (take 3 (drop 2 [1 2 3 4 5 6])) 2)))
|
||||
|
||||
(defn test-numeric? []
|
||||
@ -464,11 +464,36 @@
|
||||
(assert-true (odd? 1))
|
||||
(assert-false (odd? 0))
|
||||
(try (do (odd? "foo") (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (odd? []) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (odd? None) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
|
||||
(defn test-partition []
|
||||
"NATIVE: testing the partition function"
|
||||
(setv ten (range 10))
|
||||
;; no remainder
|
||||
(assert-equal (list (partition ten 3))
|
||||
[(, 0 1 2) (, 3 4 5) (, 6 7 8)])
|
||||
;; pair by default
|
||||
(assert-equal (list (partition ten))
|
||||
[(, 0 1) (, 2 3) (, 4 5) (, 6 7) (, 8 9)])
|
||||
;; length 1 is valid
|
||||
(assert-equal (list (partition ten 1))
|
||||
[(, 0) (, 1) (, 2) (, 3) (, 4) (, 5) (, 6) (, 7) (, 8) (, 9)])
|
||||
;; tuples of length < 1 don't crash
|
||||
(assert-equal (list (partition ten 0)) [])
|
||||
(assert-equal (list (partition ten -1)) [])
|
||||
;; keep remainder with a fillvalue
|
||||
(assert-equal (list (partition ten 3 :fillvalue "x"))
|
||||
[(, 0 1 2) (, 3 4 5) (, 6 7 8) (, 9 "x" "x")])
|
||||
;; skip elements with step > n
|
||||
(assert-equal (list (partition ten 2 3))
|
||||
[(, 0 1) (, 3 4) (, 6 7)])
|
||||
;; overlap with step < n
|
||||
(assert-equal (list (partition (range 5) 2 1))
|
||||
[(, 0 1) (, 1 2) (, 2 3) (, 3 4)]))
|
||||
|
||||
(defn test-pos []
|
||||
"NATIVE: testing the pos? function"
|
||||
@ -476,11 +501,11 @@
|
||||
(assert-false (pos? -1))
|
||||
(assert-false (pos? 0))
|
||||
(try (do (pos? "foo") (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (pos? []) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e)))))
|
||||
(try (do (pos? None) (assert False))
|
||||
(catch [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
(except [e [TypeError]] (assert (in "not a number" (str e))))))
|
||||
|
||||
(defn test-remove []
|
||||
"NATIVE: testing the remove function"
|
||||
@ -543,7 +568,7 @@
|
||||
(setv res (list (take 0 (repeat "s"))))
|
||||
(assert-equal res [])
|
||||
(try (do (list (take -1 (repeat "s"))) (assert False))
|
||||
(catch [e [ValueError]] nil))
|
||||
(except [e [ValueError]] nil))
|
||||
(setv res (list (take 6 [1 2 None 4])))
|
||||
(assert-equal res [1 2 None 4]))
|
||||
|
||||
@ -567,10 +592,10 @@
|
||||
(setv res (list (take-nth 3 [1 2 3 None 5 6])))
|
||||
(assert-equal res [1 None])
|
||||
;; using 0 should raise ValueError
|
||||
(let [[passed false]]
|
||||
(let [passed false]
|
||||
(try
|
||||
(setv res (list (take-nth 0 [1 2 3 4 5 6 7])))
|
||||
(catch [ValueError] (setv passed true)))
|
||||
(except [ValueError] (setv passed true)))
|
||||
(assert passed)))
|
||||
|
||||
(defn test-take-while []
|
||||
@ -584,14 +609,6 @@
|
||||
(setv res (list (take-while (fn [x] (not (none? x))) [1 2 3 4 None 5 6 None 7])))
|
||||
(assert-equal res [1 2 3 4]))
|
||||
|
||||
(defn test-zipwith []
|
||||
"NATIVE: testing the zipwith function"
|
||||
(import operator)
|
||||
(setv res (zipwith operator.add [1 2 3] [3 2 1]))
|
||||
(assert-equal (list res) [4 4 4])
|
||||
(setv res (zipwith operator.sub [3 7 9] [1 2 4]))
|
||||
(assert-equal (list res) [2 5 5]))
|
||||
|
||||
(defn test-doto []
|
||||
"NATIVE: testing doto macro"
|
||||
(setv collection [])
|
||||
@ -617,3 +634,12 @@
|
||||
"NATIVE: testing import of __init__.hy"
|
||||
(import tests.resources.bin)
|
||||
(assert (in "_null_fn_for_import_test" (dir tests.resources.bin))))
|
||||
|
||||
(defn test-accumulate []
|
||||
"NATIVE: testing the accumulate function"
|
||||
(assert-equal (list (accumulate ["a" "b" "c"]))
|
||||
["a" "ab" "abc"])
|
||||
(assert-equal (list (accumulate [1 2 3 4 5]))
|
||||
[1 3 6 10 15])
|
||||
(assert-equal (list (accumulate [1 -2 -3 -4 -5] -))
|
||||
[1 3 6 10 15]))
|
||||
|
@ -23,7 +23,7 @@
|
||||
(defn test-defclass-attrs []
|
||||
"NATIVE: test defclass attributes"
|
||||
(defclass A []
|
||||
[[x 42]])
|
||||
[x 42])
|
||||
(assert (= A.x 42))
|
||||
(assert (= (getattr (A) "x") 42)))
|
||||
|
||||
@ -31,12 +31,12 @@
|
||||
(defn test-defclass-attrs-fn []
|
||||
"NATIVE: test defclass attributes with fn"
|
||||
(defclass B []
|
||||
[[x 42]
|
||||
[y (fn [self value]
|
||||
(+ self.x value))]])
|
||||
[x 42
|
||||
y (fn [self value]
|
||||
(+ self.x value))])
|
||||
(assert (= B.x 42))
|
||||
(assert (= (.y (B) 5) 47))
|
||||
(let [[b (B)]]
|
||||
(let [b (B)]
|
||||
(setv B.x 0)
|
||||
(assert (= (.y b 1) 1))))
|
||||
|
||||
@ -44,17 +44,17 @@
|
||||
(defn test-defclass-dynamic-inheritance []
|
||||
"NATIVE: test defclass with dynamic inheritance"
|
||||
(defclass A [((fn [] (if true list dict)))]
|
||||
[[x 42]])
|
||||
[x 42])
|
||||
(assert (isinstance (A) list))
|
||||
(defclass A [((fn [] (if false list dict)))]
|
||||
[[x 42]])
|
||||
[x 42])
|
||||
(assert (isinstance (A) dict)))
|
||||
|
||||
|
||||
(defn test-defclass-no-fn-leak []
|
||||
"NATIVE: test defclass attributes with fn"
|
||||
(defclass A []
|
||||
[[x (fn [] 1)]])
|
||||
[x (fn [] 1)])
|
||||
(try
|
||||
(do
|
||||
(x)
|
||||
@ -64,13 +64,13 @@
|
||||
(defn test-defclass-docstring []
|
||||
"NATIVE: test defclass docstring"
|
||||
(defclass A []
|
||||
[[--doc-- "doc string"]
|
||||
[x 1]])
|
||||
[--doc-- "doc string"
|
||||
x 1])
|
||||
(setv a (A))
|
||||
(assert (= a.__doc__ "doc string"))
|
||||
(defclass B []
|
||||
"doc string"
|
||||
[[x 1]])
|
||||
[x 1])
|
||||
(setv b (B))
|
||||
(assert (= b.x 1))
|
||||
(assert (= b.__doc__ "doc string"))
|
||||
@ -78,7 +78,7 @@
|
||||
"begin a very long multi-line string to make
|
||||
sure that it comes out the way we hope
|
||||
and can span 3 lines end."
|
||||
[[x 1]])
|
||||
[x 1])
|
||||
(setv mL (MultiLine))
|
||||
(assert (= mL.x 1))
|
||||
(assert (in "begin" mL.__doc__))
|
||||
@ -86,8 +86,40 @@
|
||||
|
||||
(defn test-defclass-macroexpand []
|
||||
"NATIVE: test defclass with macro expand"
|
||||
(defmacro M [] `[x (fn [self x] (setv self._x x))])
|
||||
(defclass A [] [(M)])
|
||||
(defmacro M [] `(defn x [self x] (setv self._x x)))
|
||||
(defclass A [] (M))
|
||||
(setv a (A))
|
||||
(a.x 1)
|
||||
(assert (= a._x 1)))
|
||||
|
||||
(defn test-defclass-syntax []
|
||||
"NATIVE: test defclass syntax with properties and methods and side-effects"
|
||||
(setv foo 1)
|
||||
(defclass A []
|
||||
[x 1
|
||||
y 2]
|
||||
(global foo)
|
||||
(setv foo 2)
|
||||
(defn greet [self]
|
||||
"Greet the caller"
|
||||
|
||||
"hello!"))
|
||||
(setv a (A))
|
||||
(assert (= a.x 1))
|
||||
(assert (= a.y 2))
|
||||
(assert foo 2)
|
||||
(assert (.greet a) "hello"))
|
||||
|
||||
(defn test-defclass-implicit-nil-for-init []
|
||||
"NATIVE: test that defclass adds an implicit nil to --init--"
|
||||
(defclass A []
|
||||
[--init-- (fn [self] (setv self.x 1) 42)])
|
||||
(defclass B []
|
||||
(defn --init-- [self]
|
||||
(setv self.x 2)
|
||||
42))
|
||||
|
||||
(setv a (A))
|
||||
(setv b (B))
|
||||
(assert (= a.x 1))
|
||||
(assert (= b.x 2)))
|
||||
|
@ -12,6 +12,26 @@
|
||||
(assert (isinstance sys.argv list)))
|
||||
|
||||
|
||||
(defn test-hex []
|
||||
"NATIVE: test hex"
|
||||
(assert (= 0x80 128)))
|
||||
|
||||
|
||||
(defn test-octal []
|
||||
"NATIVE: test octal"
|
||||
(assert (= 0o1232 666)))
|
||||
|
||||
|
||||
(defn test-binary []
|
||||
"NATIVE: test binary"
|
||||
(assert (= 0b1011101 93)))
|
||||
|
||||
|
||||
(defn test-fractions []
|
||||
"NATIVE: test fractions"
|
||||
(assert (= 1/2 (fraction 1 2))))
|
||||
|
||||
|
||||
(defn test-lists []
|
||||
"NATIVE: test lists work right"
|
||||
(assert (= [1 2 3 4] (+ [1 2] [3 4]))))
|
||||
@ -29,6 +49,11 @@
|
||||
(assert (= #{} (set))))
|
||||
|
||||
|
||||
(defn test-setv-empty []
|
||||
"NATIVE: test setv works with no arguments"
|
||||
(assert (is (setv) nil)))
|
||||
|
||||
|
||||
(defn test-setv-get []
|
||||
"NATIVE: test setv works on a get expression"
|
||||
(setv foo [0 1 2])
|
||||
@ -38,46 +63,73 @@
|
||||
(defn test-setv-builtin []
|
||||
"NATIVE: test that setv doesn't work on builtins"
|
||||
(try (eval '(setv False 1))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv True 0))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv None 1))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv false 1))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv true 0))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv nil 1))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(setv null 1))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(defn defclass [] (print "hello")))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(defn get [] (print "hello")))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))
|
||||
(try (eval '(defn lambda [] (print "hello")))
|
||||
(catch [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))))
|
||||
(except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))))
|
||||
|
||||
|
||||
(defn test-setv-pairs []
|
||||
"NATIVE: test that setv works on pairs of arguments"
|
||||
(assert (= (setv a 1 b 2) (, 1 2)))
|
||||
(assert (= a 1))
|
||||
(assert (= b 2))
|
||||
(setv y 0 x 1 y x)
|
||||
(assert y)
|
||||
(try (eval '(setv a 1 b))
|
||||
(except [e [TypeError]] (assert (in "`setv' needs an even number of arguments" (str e))))))
|
||||
|
||||
|
||||
(defn test-fn-corner-cases []
|
||||
"NATIVE: tests that fn/defn handles corner cases gracefully"
|
||||
(try (eval '(fn "foo"))
|
||||
(catch [e [Exception]] (assert (in "to (fn) must be a list"
|
||||
(except [e [Exception]] (assert (in "to `fn' must be a list"
|
||||
(str e)))))
|
||||
(try (eval '(defn foo "foo"))
|
||||
(catch [e [Exception]]
|
||||
(except [e [Exception]]
|
||||
(assert (in "takes a parameter list as second" (str e))))))
|
||||
|
||||
|
||||
(defn test-alias-names-in-errors []
|
||||
"NATIVE: tests that native aliases show the correct names in errors"
|
||||
(try (eval '(lambda))
|
||||
(except [e [Exception]] (assert (in "lambda" (str e)))))
|
||||
(try (eval '(fn))
|
||||
(except [e [Exception]] (assert (in "fn" (str e)))))
|
||||
(try (eval '(setv 1 2 3))
|
||||
(except [e [Exception]] (assert (in "setv" (str e)))))
|
||||
(try (eval '(def 1 2 3))
|
||||
(except [e [Exception]] (assert (in "def" (str e))))))
|
||||
|
||||
|
||||
(defn test-for-loop []
|
||||
"NATIVE: test for loops"
|
||||
(setv count 0)
|
||||
(setv count1 0 count2 0)
|
||||
(for [x [1 2 3 4 5]]
|
||||
(setv count (+ count x)))
|
||||
(assert (= count 15))
|
||||
(setv count1 (+ count1 x))
|
||||
(setv count2 (+ count2 x)))
|
||||
(assert (= count1 15))
|
||||
(assert (= count2 15))
|
||||
(setv count 0)
|
||||
(for [x [1 2 3 4 5]
|
||||
y [1 2 3 4 5]]
|
||||
(setv count (+ count x y)))
|
||||
(assert (= count 150))
|
||||
(setv count (+ count x y))
|
||||
(else
|
||||
(+= count 1)))
|
||||
(assert (= count 151))
|
||||
(assert (= (list ((fn [] (for [x [[1] [2 3]] y x] (yield y)))))
|
||||
(list-comp y [x [[1] [2 3]] y x])))
|
||||
(assert (= (list ((fn [] (for [x [[1] [2 3]] y x z (range 5)] (yield z)))))
|
||||
@ -98,21 +150,21 @@
|
||||
(for [x (range 2)
|
||||
y (range 2)]
|
||||
(break)
|
||||
(else (throw Exception)))
|
||||
(else (raise Exception)))
|
||||
|
||||
;; OK. This next test will ensure that the else is hooked up to the
|
||||
;; "inner" iteration
|
||||
(for [x (range 2)
|
||||
y (range 2)]
|
||||
(if (= y 1) (break))
|
||||
(else (throw Exception)))
|
||||
(else (raise Exception)))
|
||||
|
||||
;; OK. This next test will ensure that the else is hooked up to the
|
||||
;; "outer" iteration
|
||||
(for [x (range 2)
|
||||
y (range 2)]
|
||||
(if (= x 1) (break))
|
||||
(else (throw Exception)))
|
||||
(else (raise Exception)))
|
||||
|
||||
;; OK. This next test will ensure that we call the else branch exactly
|
||||
;; once.
|
||||
@ -207,7 +259,8 @@
|
||||
"NATIVE: test if cond sorta works."
|
||||
(cond
|
||||
[(= 1 2) (assert (is true false))]
|
||||
[(is null null) (assert (is true true))]))
|
||||
[(is None None) (setv x true) (assert x)])
|
||||
(assert (= (cond) nil)))
|
||||
|
||||
|
||||
(defn test-index []
|
||||
@ -256,7 +309,10 @@
|
||||
(assert (= (apply sumit [] {"a" 1 "b" 1 "c" 2}) 4))
|
||||
(assert (= (apply sumit ((fn [] [1 1])) {"c" 1}) 3))
|
||||
(defn noargs [] [1 2 3])
|
||||
(assert (= (apply noargs) [1 2 3])))
|
||||
(assert (= (apply noargs) [1 2 3]))
|
||||
(defn sumit-mangle [an-a a-b a-c a-d] (+ an-a a-b a-c a-d))
|
||||
(def Z "a_d")
|
||||
(assert (= (apply sumit-mangle [] {"an-a" 1 :a-b 2 'a-c 3 Z 4}) 10)))
|
||||
|
||||
|
||||
(defn test-apply-with-methods []
|
||||
@ -299,7 +355,7 @@
|
||||
(try (do) (except [IOError]) (except))
|
||||
|
||||
;; Test correct (raise)
|
||||
(let [[passed false]]
|
||||
(let [passed false]
|
||||
(try
|
||||
(try
|
||||
(raise IndexError)
|
||||
@ -309,7 +365,7 @@
|
||||
(assert passed))
|
||||
|
||||
;; Test incorrect (raise)
|
||||
(let [[passed false]]
|
||||
(let [passed false]
|
||||
(try
|
||||
(raise)
|
||||
;; Python 2 raises TypeError
|
||||
@ -318,16 +374,15 @@
|
||||
(setv passed true)))
|
||||
(assert passed))
|
||||
|
||||
|
||||
;; Test (finally)
|
||||
(let [[passed false]]
|
||||
(let [passed false]
|
||||
(try
|
||||
(do)
|
||||
(finally (setv passed true)))
|
||||
(assert passed))
|
||||
|
||||
;; Test (finally) + (raise)
|
||||
(let [[passed false]]
|
||||
(let [passed false]
|
||||
(try
|
||||
(raise Exception)
|
||||
(except)
|
||||
@ -336,8 +391,8 @@
|
||||
|
||||
|
||||
;; Test (finally) + (raise) + (else)
|
||||
(let [[passed false]
|
||||
[not-elsed true]]
|
||||
(let [passed false
|
||||
not-elsed true]
|
||||
(try
|
||||
(raise Exception)
|
||||
(except)
|
||||
@ -348,22 +403,22 @@
|
||||
|
||||
(try
|
||||
(raise (KeyError))
|
||||
(catch [[IOError]] (assert false))
|
||||
(catch [e [KeyError]] (assert e)))
|
||||
(except [[IOError]] (assert false))
|
||||
(except [e [KeyError]] (assert e)))
|
||||
|
||||
(try
|
||||
(throw (KeyError))
|
||||
(raise (KeyError))
|
||||
(except [[IOError]] (assert false))
|
||||
(catch [e [KeyError]] (assert e)))
|
||||
(except [e [KeyError]] (assert e)))
|
||||
|
||||
(try
|
||||
(get [1] 3)
|
||||
(catch [IndexError] (assert true))
|
||||
(except [IndexError] (assert true))
|
||||
(except [IndexError] (do)))
|
||||
|
||||
(try
|
||||
(print foobar42ofthebaz)
|
||||
(catch [IndexError] (assert false))
|
||||
(except [IndexError] (assert false))
|
||||
(except [NameError] (do)))
|
||||
|
||||
(try
|
||||
@ -372,7 +427,7 @@
|
||||
|
||||
(try
|
||||
(get [1] 3)
|
||||
(catch [e [IndexError NameError]] (assert (isinstance e IndexError))))
|
||||
(except [e [IndexError NameError]] (assert (isinstance e IndexError))))
|
||||
|
||||
(try
|
||||
(print foobar42ofthebaz)
|
||||
@ -380,15 +435,15 @@
|
||||
|
||||
(try
|
||||
(print foobar42)
|
||||
(catch [[IndexError NameError]] (do)))
|
||||
(except [[IndexError NameError]] (do)))
|
||||
|
||||
(try
|
||||
(get [1] 3)
|
||||
(catch [[IndexError NameError]] (do)))
|
||||
(except [[IndexError NameError]] (do)))
|
||||
|
||||
(try
|
||||
(print foobar42ofthebaz)
|
||||
(catch))
|
||||
(except))
|
||||
|
||||
(try
|
||||
(print foobar42ofthebaz)
|
||||
@ -400,17 +455,17 @@
|
||||
|
||||
(try
|
||||
(print foobar42ofthebaz)
|
||||
(catch []
|
||||
(except []
|
||||
(setv foobar42ofthebaz 42)
|
||||
(assert (= foobar42ofthebaz 42))))
|
||||
|
||||
(let [[passed false]]
|
||||
(let [passed false]
|
||||
(try
|
||||
(try (do) (except) (else (bla)))
|
||||
(except [NameError] (setv passed true)))
|
||||
(assert passed))
|
||||
|
||||
(let [[x 0]]
|
||||
(let [x 0]
|
||||
(try
|
||||
(raise IOError)
|
||||
(except [IOError]
|
||||
@ -418,7 +473,7 @@
|
||||
(else (setv x 44)))
|
||||
(assert (= x 45)))
|
||||
|
||||
(let [[x 0]]
|
||||
(let [x 0]
|
||||
(try
|
||||
(raise KeyError)
|
||||
(except []
|
||||
@ -426,7 +481,7 @@
|
||||
(else (setv x 44)))
|
||||
(assert (= x 45)))
|
||||
|
||||
(let [[x 0]]
|
||||
(let [x 0]
|
||||
(try
|
||||
(try
|
||||
(raise KeyError)
|
||||
@ -505,7 +560,7 @@
|
||||
(defn test-yield-in-try []
|
||||
"NATIVE: test yield in try"
|
||||
(defn gen []
|
||||
(let [[x 1]]
|
||||
(let [x 1]
|
||||
(try (yield x)
|
||||
(finally (print x)))))
|
||||
(setv output (list (gen)))
|
||||
@ -519,11 +574,11 @@
|
||||
(assert (= (car [1 2 3 4 5]) 1)))
|
||||
|
||||
|
||||
(defn test-slice []
|
||||
"NATIVE: test slice"
|
||||
(assert (= (slice [1 2 3 4 5] 1) [2 3 4 5]))
|
||||
(assert (= (slice [1 2 3 4 5] 1 3) [2 3]))
|
||||
(assert (= (slice [1 2 3 4 5]) [1 2 3 4 5])))
|
||||
(defn test-cut []
|
||||
"NATIVE: test cut"
|
||||
(assert (= (cut [1 2 3 4 5] 1) [2 3 4 5]))
|
||||
(assert (= (cut [1 2 3 4 5] 1 3) [2 3]))
|
||||
(assert (= (cut [1 2 3 4 5]) [1 2 3 4 5])))
|
||||
|
||||
|
||||
(defn test-take []
|
||||
@ -552,14 +607,14 @@
|
||||
|
||||
(defn test-context []
|
||||
"NATIVE: test with"
|
||||
(with [[fd (open "README.md" "r")]] (assert fd))
|
||||
(with [[(open "README.md" "r")]] (do)))
|
||||
(with [fd (open "README.md" "r")] (assert fd))
|
||||
(with [(open "README.md" "r")] (do)))
|
||||
|
||||
|
||||
(defn test-with-return []
|
||||
"NATIVE: test that with returns stuff"
|
||||
(defn read-file [filename]
|
||||
(with [[fd (open filename "r")]] (.read fd)))
|
||||
(with [fd (open filename "r")] (.read fd)))
|
||||
(assert (!= 0 (len (read-file "README.md")))))
|
||||
|
||||
|
||||
@ -575,13 +630,13 @@
|
||||
|
||||
(defn test-for-else []
|
||||
"NATIVE: test for else"
|
||||
(let [[x 0]]
|
||||
(let [x 0]
|
||||
(for* [a [1 2]]
|
||||
(setv x (+ x a))
|
||||
(else (setv x (+ x 50))))
|
||||
(assert (= x 53)))
|
||||
|
||||
(let [[x 0]]
|
||||
(let [x 0]
|
||||
(for* [a [1 2]]
|
||||
(setv x (+ x a))
|
||||
(else))
|
||||
@ -652,6 +707,12 @@
|
||||
(assert (= 43 (my-fun 42))))
|
||||
|
||||
|
||||
(defn test-defn-lambdakey []
|
||||
"NATIVE: test defn with a &symbol function name"
|
||||
(defn &hy [] 1)
|
||||
(assert (= (&hy) 1)))
|
||||
|
||||
|
||||
(defn test-defn-do []
|
||||
"NATIVE: test defn evaluation order with do"
|
||||
(setv acc [])
|
||||
@ -689,28 +750,28 @@
|
||||
(defn test-let []
|
||||
"NATIVE: test let works rightish"
|
||||
;; TODO: test sad paths for let
|
||||
(assert (= (let [[x 1] [y 2] [z 3]] (+ x y z)) 6))
|
||||
(assert (= (let [[x 1] a [y 2] b] (if a 1 2)) 2))
|
||||
(assert (= (let [x] x) nil))
|
||||
(assert (= (let [[x "x not bound"]] (setv x "x bound by setv") x)
|
||||
(assert (= (let [x 1 y 2 z 3] (+ x y z)) 6))
|
||||
(assert (= (let [x 1 a nil y 2 b nil] (if a 1 2)) 2))
|
||||
(assert (= (let [x nil] x) nil))
|
||||
(assert (= (let [x "x not bound"] (setv x "x bound by setv") x)
|
||||
"x bound by setv"))
|
||||
(assert (= (let [[x "let nests scope correctly"]]
|
||||
(let [y] x))
|
||||
(assert (= (let [x "let nests scope correctly"]
|
||||
(let [y nil] x))
|
||||
"let nests scope correctly"))
|
||||
(assert (= (let [[x 999999]]
|
||||
(let [[x "x being rebound"]] x))
|
||||
(assert (= (let [x 999999]
|
||||
(let [x "x being rebound"] x))
|
||||
"x being rebound"))
|
||||
(assert (= (let [[x "x not being rebound"]]
|
||||
(let [[x 2]] nil)
|
||||
(assert (= (let [x "x not being rebound"]
|
||||
(let [x 2] nil)
|
||||
x)
|
||||
"x not being rebound"))
|
||||
(assert (= (let [[x (set [3 2 1 3 2])] [y x] [z y]] z) (set [1 2 3])))
|
||||
(assert (= (let [x (set [3 2 1 3 2]) y x z y] z) (set [1 2 3])))
|
||||
(import math)
|
||||
(let [[cos math.cos]
|
||||
[foo-cos (fn [x] (cos x))]]
|
||||
(let [cos math.cos
|
||||
foo-cos (fn [x] (cos x))]
|
||||
(assert (= (cos math.pi) -1.0))
|
||||
(assert (= (foo-cos (- math.pi)) -1.0))
|
||||
(let [[cos (fn [_] "cos has been locally rebound")]]
|
||||
(let [cos (fn [_] "cos has been locally rebound")]
|
||||
(assert (= (cos cos) "cos has been locally rebound"))
|
||||
(assert (= (-> math.pi (/ 3) foo-cos (round 2)) 0.5)))
|
||||
(setv cos (fn [_] "cos has been rebound by setv"))
|
||||
@ -730,65 +791,81 @@
|
||||
(defn test-let-scope []
|
||||
"NATIVE: test let works rightish"
|
||||
(setv y 123)
|
||||
(assert (= (let [[x 1]
|
||||
[y 2]
|
||||
[z 3]]
|
||||
(assert (= (let [x 1
|
||||
y 2
|
||||
z 3]
|
||||
(+ x y z))
|
||||
6))
|
||||
(try
|
||||
(assert (= x 42)) ; This ain't true
|
||||
(catch [e [NameError]] (assert e)))
|
||||
(except [e [NameError]] (assert e)))
|
||||
(assert (= y 123)))
|
||||
|
||||
|
||||
(defn test-symbol-utf-8 []
|
||||
"NATIVE: test symbol encoded"
|
||||
(let [[♥ "love"]
|
||||
[⚘ "flower"]]
|
||||
(let [♥ "love"
|
||||
⚘ "flower"]
|
||||
(assert (= (+ ⚘ ♥) "flowerlove"))))
|
||||
|
||||
|
||||
(defn test-symbol-dash []
|
||||
"NATIVE: test symbol encoded"
|
||||
(let [[♥-♥ "doublelove"]
|
||||
[-_- "what?"]]
|
||||
(let [♥-♥ "doublelove"
|
||||
-_- "what?"]
|
||||
(assert (= ♥-♥ "doublelove"))
|
||||
(assert (= -_- "what?"))))
|
||||
|
||||
|
||||
(defn test-symbol-question-mark []
|
||||
"NATIVE: test foo? -> is_foo behavior"
|
||||
(let [[foo? "nachos"]]
|
||||
(let [foo? "nachos"]
|
||||
(assert (= is_foo "nachos"))))
|
||||
|
||||
|
||||
(defn test-and []
|
||||
"NATIVE: test the and function"
|
||||
(let [[and123 (and 1 2 3)]
|
||||
[and-false (and 1 False 3)]]
|
||||
(let [and123 (and 1 2 3)
|
||||
and-false (and 1 False 3)
|
||||
and-true (and)
|
||||
and-single (and 1)]
|
||||
(assert (= and123 3))
|
||||
(assert (= and-false False))))
|
||||
(assert (= and-false False))
|
||||
(assert (= and-true True))
|
||||
(assert (= and-single 1)))
|
||||
; short circuiting
|
||||
(setv a 1)
|
||||
(and 0 (setv a 2))
|
||||
(assert (= a 1)))
|
||||
|
||||
|
||||
(defn test-or []
|
||||
"NATIVE: test the or function"
|
||||
(let [[or-all-true (or 1 2 3 True "string")]
|
||||
[or-some-true (or False "hello")]
|
||||
[or-none-true (or False False)]]
|
||||
(let [or-all-true (or 1 2 3 True "string")
|
||||
or-some-true (or False "hello")
|
||||
or-none-true (or False False)
|
||||
or-false (or)
|
||||
or-single (or 1)]
|
||||
(assert (= or-all-true 1))
|
||||
(assert (= or-some-true "hello"))
|
||||
(assert (= or-none-true False))))
|
||||
(assert (= or-none-true False))
|
||||
(assert (= or-false nil))
|
||||
(assert (= or-single 1)))
|
||||
; short circuiting
|
||||
(setv a 1)
|
||||
(or 1 (setv a 2))
|
||||
(assert (= a 1)))
|
||||
|
||||
|
||||
(defn test-if-return-branching []
|
||||
"NATIVE: test the if return branching"
|
||||
; thanks, algernon
|
||||
(assert (= 1 (let [[x 1]
|
||||
[y 2]]
|
||||
(assert (= 1 (let [x 1
|
||||
y 2]
|
||||
(if true
|
||||
2)
|
||||
1)))
|
||||
(assert (= 1 (let [[x 1] [y 2]]
|
||||
(assert (= 1 (let [x 1 y 2]
|
||||
(do)
|
||||
(do)
|
||||
((fn [] 1))))))
|
||||
@ -833,21 +910,32 @@
|
||||
(assert (= 27 (eval (+ (quote (*)) (* [(quote 3)] 3)))))
|
||||
(assert (= None (eval (quote (print ""))))))
|
||||
|
||||
|
||||
(defn test-eval-globals []
|
||||
"NATIVE: test eval with explicit global dict"
|
||||
(assert (= 'bar (eval (quote foo) {'foo 'bar})))
|
||||
(assert (= 1 (let [[d {}]] (eval '(setv x 1) d) (eval (quote x) d))))
|
||||
(let [[d1 {}]
|
||||
[d2 {}]]
|
||||
(assert (= 1 (let [d {}] (eval '(setv x 1) d) (eval (quote x) d))))
|
||||
(let [d1 {}
|
||||
d2 {}]
|
||||
(eval '(setv x 1) d1)
|
||||
(try
|
||||
(do
|
||||
; this should fail with a name error
|
||||
(eval (quote x) d2)
|
||||
(assert False "We shouldn't have arrived here"))
|
||||
(catch [e Exception]
|
||||
(except [e Exception]
|
||||
(assert (isinstance e NameError))))))
|
||||
|
||||
(defn test-eval-failure []
|
||||
"NATIVE: test eval failure modes"
|
||||
(import [hy.errors [HyTypeError]])
|
||||
; yo dawg
|
||||
(try (eval '(eval)) (except [e HyTypeError]) (else (assert False)))
|
||||
(try (eval '(eval "snafu")) (except [e HyTypeError]) (else (assert False)))
|
||||
(try (eval 'false []) (except [e HyTypeError]) (else (assert False)))
|
||||
(try (eval 'false {} 1) (except [e HyTypeError]) (else (assert False))))
|
||||
|
||||
|
||||
(defn test-import-syntax []
|
||||
"NATIVE: test the import syntax."
|
||||
|
||||
@ -909,7 +997,7 @@
|
||||
|
||||
(defn test-if-let-mixing []
|
||||
"NATIVE: test that we can now mix if and let"
|
||||
(assert (= 0 (if true (let [[x 0]] x) 42))))
|
||||
(assert (= 0 (if true (let [x 0] x) 42))))
|
||||
|
||||
(defn test-if-in-if []
|
||||
"NATIVE: test that we can use if in if"
|
||||
@ -936,7 +1024,7 @@
|
||||
"NATIVE: test requiring macros from python code"
|
||||
(try
|
||||
(assert (= "this won't happen" (qplah 1 2 3 4)))
|
||||
(catch [NameError]))
|
||||
(except [NameError]))
|
||||
(require tests.resources.tlib)
|
||||
(assert (= [1 2 3] (qplah 1 2 3))))
|
||||
|
||||
@ -1024,7 +1112,8 @@
|
||||
(del (get test 4))
|
||||
(assert (= test [0 1 2 3]))
|
||||
(del (get test 2))
|
||||
(assert (= test [0 1 3])))
|
||||
(assert (= test [0 1 3]))
|
||||
(assert (= (del) nil)))
|
||||
|
||||
|
||||
(defn test-macroexpand []
|
||||
@ -1104,7 +1193,7 @@
|
||||
"NATIVE: test lambda lists are only parsed in defn"
|
||||
(try
|
||||
(foo [&rest spam] 1)
|
||||
(catch [NameError] True)
|
||||
(except [NameError] True)
|
||||
(else (raise AssertionError))))
|
||||
|
||||
(defn test-read []
|
||||
@ -1128,9 +1217,13 @@
|
||||
(read stdin-buffer)
|
||||
(try
|
||||
(read stdin-buffer)
|
||||
(catch [e Exception]
|
||||
(except [e Exception]
|
||||
(assert (isinstance e EOFError)))))
|
||||
|
||||
(defn test-read-str []
|
||||
"NATIVE: test read-str"
|
||||
(assert (= (read-str "(print 1)") '(print 1))))
|
||||
|
||||
(defn test-keyword-creation []
|
||||
"NATIVE: Test keyword creation"
|
||||
(assert (= (keyword "foo") :foo))
|
||||
|
@ -69,73 +69,73 @@
|
||||
|
||||
(defn test-augassign-add []
|
||||
"NATIVE: test augassign add"
|
||||
(let [[x 1]]
|
||||
(let [x 1]
|
||||
(+= x 41)
|
||||
(assert (= x 42))))
|
||||
|
||||
(defn test-augassign-sub []
|
||||
"NATIVE: test augassign sub"
|
||||
(let [[x 1]]
|
||||
(let [x 1]
|
||||
(-= x 41)
|
||||
(assert (= x -40))))
|
||||
|
||||
(defn test-augassign-mult []
|
||||
"NATIVE: test augassign mult"
|
||||
(let [[x 1]]
|
||||
(let [x 1]
|
||||
(*= x 41)
|
||||
(assert (= x 41))))
|
||||
|
||||
(defn test-augassign-div []
|
||||
"NATIVE: test augassign div"
|
||||
(let [[x 42]]
|
||||
(let [x 42]
|
||||
(/= x 2)
|
||||
(assert (= x 21))))
|
||||
|
||||
(defn test-augassign-floordiv []
|
||||
"NATIVE: test augassign floordiv"
|
||||
(let [[x 42]]
|
||||
(let [x 42]
|
||||
(//= x 2)
|
||||
(assert (= x 21))))
|
||||
|
||||
(defn test-augassign-mod []
|
||||
"NATIVE: test augassign mod"
|
||||
(let [[x 42]]
|
||||
(let [x 42]
|
||||
(%= x 2)
|
||||
(assert (= x 0))))
|
||||
|
||||
(defn test-augassign-pow []
|
||||
"NATIVE: test augassign pow"
|
||||
(let [[x 2]]
|
||||
(let [x 2]
|
||||
(**= x 3)
|
||||
(assert (= x 8))))
|
||||
|
||||
(defn test-augassign-lshift []
|
||||
"NATIVE: test augassign lshift"
|
||||
(let [[x 2]]
|
||||
(let [x 2]
|
||||
(<<= x 2)
|
||||
(assert (= x 8))))
|
||||
|
||||
(defn test-augassign-rshift []
|
||||
"NATIVE: test augassign rshift"
|
||||
(let [[x 8]]
|
||||
(let [x 8]
|
||||
(>>= x 1)
|
||||
(assert (= x 4))))
|
||||
|
||||
(defn test-augassign-bitand []
|
||||
"NATIVE: test augassign bitand"
|
||||
(let [[x 8]]
|
||||
(let [x 8]
|
||||
(&= x 1)
|
||||
(assert (= x 0))))
|
||||
|
||||
(defn test-augassign-bitor []
|
||||
"NATIVE: test augassign bitand"
|
||||
(let [[x 0]]
|
||||
(let [x 0]
|
||||
(|= x 2)
|
||||
(assert (= x 2))))
|
||||
|
||||
(defn test-augassign-bitxor []
|
||||
"NATIVE: test augassign bitand"
|
||||
(let [[x 1]]
|
||||
(let [x 1]
|
||||
(^= x 1)
|
||||
(assert (= x 0))))
|
||||
|
||||
@ -145,21 +145,21 @@
|
||||
|
||||
|
||||
(defclass HyTestMatrix [list]
|
||||
[[--matmul--
|
||||
(fn [self other]
|
||||
(let [[n (len self)]
|
||||
[m (len (. other [0]))]
|
||||
[result []]]
|
||||
(for [i (range m)]
|
||||
(let [[result-row []]]
|
||||
(for [j (range n)]
|
||||
(let [[dot-product 0]]
|
||||
(for [k (range (len (. self [0])))]
|
||||
(+= dot-product (* (. self [i] [k])
|
||||
(. other [k] [j]))))
|
||||
(.append result-row dot-product)))
|
||||
(.append result result-row)))
|
||||
result))]])
|
||||
[--matmul--
|
||||
(fn [self other]
|
||||
(let [n (len self)
|
||||
m (len (. other [0]))
|
||||
result []]
|
||||
(for [i (range m)]
|
||||
(let [result-row []]
|
||||
(for [j (range n)]
|
||||
(let [dot-product 0]
|
||||
(for [k (range (len (. self [0])))]
|
||||
(+= dot-product (* (. self [i] [k])
|
||||
(. other [k] [j]))))
|
||||
(.append result-row dot-product)))
|
||||
(.append result result-row)))
|
||||
result))])
|
||||
|
||||
(def first-test-matrix (HyTestMatrix [[1 2 3]
|
||||
[4 5 6]
|
||||
@ -179,15 +179,15 @@
|
||||
(assert (= (@ first-test-matrix second-test-matrix)
|
||||
product-of-test-matrices))
|
||||
;; Python <= 3.4
|
||||
(let [[matmul-attempt (try (@ first-test-matrix second-test-matrix)
|
||||
(catch [e [Exception]] e))]]
|
||||
(let [matmul-attempt (try (@ first-test-matrix second-test-matrix)
|
||||
(except [e [Exception]] e))]
|
||||
(assert (isinstance matmul-attempt NameError)))))
|
||||
|
||||
(defn test-augassign-matmul []
|
||||
"NATIVE: test augmented-assignment matrix multiplication"
|
||||
(let [[matrix first-test-matrix]
|
||||
[matmul-attempt (try (@= matrix second-test-matrix)
|
||||
(catch [e [Exception]] e))]]
|
||||
(let [matrix first-test-matrix
|
||||
matmul-attempt (try (@= matrix second-test-matrix)
|
||||
(except [e [Exception]] e))]
|
||||
(if PY35
|
||||
(assert (= product-of-test-matrices matrix))
|
||||
(assert (isinstance matmul-attempt NameError)))))
|
||||
|
@ -107,8 +107,8 @@
|
||||
(import [astor.codegen [to_source]])
|
||||
(import [hy.importer [import_buffer_to_ast]])
|
||||
(setv macro1 "(defmacro nif [expr pos zero neg]
|
||||
(let [[g (gensym)]]
|
||||
`(let [[~g ~expr]]
|
||||
(let [g (gensym)]
|
||||
`(let [~g ~expr]
|
||||
(cond [(pos? ~g) ~pos]
|
||||
[(zero? ~g) ~zero]
|
||||
[(neg? ~g) ~neg]))))
|
||||
@ -133,7 +133,7 @@
|
||||
(import [hy.importer [import_buffer_to_ast]])
|
||||
(setv macro1 "(defmacro nif [expr pos zero neg]
|
||||
(with-gensyms [a]
|
||||
`(let [[~a ~expr]]
|
||||
`(let [~a ~expr]
|
||||
(cond [(pos? ~a) ~pos]
|
||||
[(zero? ~a) ~zero]
|
||||
[(neg? ~a) ~neg]))))
|
||||
@ -155,7 +155,7 @@
|
||||
(import [astor.codegen [to_source]])
|
||||
(import [hy.importer [import_buffer_to_ast]])
|
||||
(setv macro1 "(defmacro/g! nif [expr pos zero neg]
|
||||
`(let [[~g!res ~expr]]
|
||||
`(let [~g!res ~expr]
|
||||
(cond [(pos? ~g!res) ~pos]
|
||||
[(zero? ~g!res) ~zero]
|
||||
[(neg? ~g!res) ~neg])))
|
||||
@ -188,51 +188,39 @@
|
||||
:yes)))
|
||||
|
||||
|
||||
(defn test-lisp-if []
|
||||
"test that lisp-if works as expected"
|
||||
(defn test-lif []
|
||||
"test that lif works as expected"
|
||||
; nil is false
|
||||
(assert (= (lisp-if None "true" "false") "false"))
|
||||
(assert (= (lisp-if nil "true" "false") "false"))
|
||||
(assert (= (lif None "true" "false") "false"))
|
||||
(assert (= (lif nil "true" "false") "false"))
|
||||
|
||||
; But everything else is True! Even falsey things.
|
||||
(assert (= (lisp-if True "true" "false") "true"))
|
||||
(assert (= (lisp-if False "true" "false") "true"))
|
||||
(assert (= (lisp-if 0 "true" "false") "true"))
|
||||
(assert (= (lisp-if "some-string" "true" "false") "true"))
|
||||
(assert (= (lisp-if "" "true" "false") "true"))
|
||||
(assert (= (lisp-if (+ 1 2 3) "true" "false") "true"))
|
||||
|
||||
; Just to be sure, test the alias lif
|
||||
(assert (= (lif True "true" "false") "true"))
|
||||
(assert (= (lif False "true" "false") "true"))
|
||||
(assert (= (lif 0 "true" "false") "true"))
|
||||
(assert (= (lif "some-string" "true" "false") "true"))
|
||||
(assert (= (lif "" "true" "false") "true"))
|
||||
(assert (= (lif (+ 1 2 3) "true" "false") "true"))
|
||||
(assert (= (lif nil "true" "false") "false"))
|
||||
(assert (= (lif 0 "true" "false") "true")))
|
||||
|
||||
(defn test-lisp-if-not []
|
||||
"test that lisp-if-not works as expected"
|
||||
(defn test-lif-not []
|
||||
"test that lif-not works as expected"
|
||||
; nil is false
|
||||
(assert (= (lisp-if-not None "false" "true") "false"))
|
||||
(assert (= (lisp-if-not nil "false" "true") "false"))
|
||||
(assert (= (lif-not None "false" "true") "false"))
|
||||
(assert (= (lif-not nil "false" "true") "false"))
|
||||
|
||||
; But everything else is True! Even falsey things.
|
||||
(assert (= (lisp-if-not True "false" "true") "true"))
|
||||
(assert (= (lisp-if-not False "false" "true") "true"))
|
||||
(assert (= (lisp-if-not 0 "false" "true") "true"))
|
||||
(assert (= (lisp-if-not "some-string" "false" "true") "true"))
|
||||
(assert (= (lisp-if-not "" "false" "true") "true"))
|
||||
(assert (= (lisp-if-not (+ 1 2 3) "false" "true") "true"))
|
||||
|
||||
; Just to be sure, test the alias lif-not
|
||||
(assert (= (lif-not True "false" "true") "true"))
|
||||
(assert (= (lif-not False "false" "true") "true"))
|
||||
(assert (= (lif-not 0 "false" "true") "true"))
|
||||
(assert (= (lif-not "some-string" "false" "true") "true"))
|
||||
(assert (= (lif-not "" "false" "true") "true"))
|
||||
(assert (= (lif-not (+ 1 2 3) "false" "true") "true"))
|
||||
(assert (= (lif-not nil "false" "true") "false"))
|
||||
(assert (= (lif-not 0 "false" "true") "true")))
|
||||
|
||||
|
||||
(defn test-defn-alias []
|
||||
(defn-alias [tda-main tda-a1 tda-a2] [] :bazinga)
|
||||
(defun-alias [tda-main tda-a1 tda-a2] [] :bazinga)
|
||||
(assert (= (tda-main) :bazinga))
|
||||
(assert (= (tda-a1) :bazinga))
|
||||
(assert (= (tda-a2) :bazinga))
|
||||
(assert (= tda-main tda-a1 tda-a2)))
|
||||
|
||||
(defn test-yield-from []
|
||||
"NATIVE: testing yield from"
|
||||
(defn yield-from-test []
|
||||
@ -253,13 +241,10 @@
|
||||
(yield i))
|
||||
(try
|
||||
(yield-from (yield-from-subgenerator-test))
|
||||
(catch [e AssertionError]
|
||||
(except [e AssertionError]
|
||||
(yield 4))))
|
||||
(assert (= (list (yield-from-test)) [0 1 2 1 2 3 4])))
|
||||
|
||||
(defn test-botsbuildbots []
|
||||
(assert (> (len (first (Botsbuildbots))) 50)))
|
||||
|
||||
|
||||
(defn test-defmain []
|
||||
"NATIVE: make sure defmain is clean"
|
||||
|
@ -1,4 +1,4 @@
|
||||
;; Tests where the emited code relies on Python 3.
|
||||
;; Tests where the emitted code relies on Python 3.
|
||||
;; Conditionally included in nosetests runs.
|
||||
|
||||
(import [hy._compat [PY33]])
|
||||
@ -15,14 +15,14 @@
|
||||
(defn test-kwonly []
|
||||
"NATIVE: test keyword-only arguments"
|
||||
;; keyword-only with default works
|
||||
(let [[kwonly-foo-default-false (fn [&kwonly [foo false]] foo)]]
|
||||
(let [kwonly-foo-default-false (fn [&kwonly [foo false]] foo)]
|
||||
(assert (= (apply kwonly-foo-default-false) false))
|
||||
(assert (= (apply kwonly-foo-default-false [] {"foo" true}) true)))
|
||||
;; keyword-only without default ...
|
||||
(let [[kwonly-foo-no-default (fn [&kwonly foo] foo)]
|
||||
[attempt-to-omit-default (try
|
||||
(kwonly-foo-no-default)
|
||||
(catch [e [Exception]] e))]]
|
||||
(let [kwonly-foo-no-default (fn [&kwonly foo] foo)
|
||||
attempt-to-omit-default (try
|
||||
(kwonly-foo-no-default)
|
||||
(except [e [Exception]] e))]
|
||||
;; works
|
||||
(assert (= (apply kwonly-foo-no-default [] {"foo" "quux"}) "quux"))
|
||||
;; raises TypeError with appropriate message if not supplied
|
||||
@ -30,9 +30,9 @@
|
||||
(assert (in "missing 1 required keyword-only argument: 'foo'"
|
||||
(. attempt-to-omit-default args [0]))))
|
||||
;; keyword-only with other arg types works
|
||||
(let [[function-of-various-args
|
||||
(fn [a b &rest args &kwonly foo &kwargs kwargs]
|
||||
(, a b args foo kwargs))]]
|
||||
(let [function-of-various-args
|
||||
(fn [a b &rest args &kwonly foo &kwargs kwargs]
|
||||
(, a b args foo kwargs))]
|
||||
(assert (= (apply function-of-various-args
|
||||
[1 2 3 4] {"foo" 5 "bar" 6 "quux" 7})
|
||||
(, 1 2 (, 3 4) 5 {"bar" 6 "quux" 7})))))
|
||||
|
@ -1,3 +1,6 @@
|
||||
(import [functools [wraps]])
|
||||
|
||||
|
||||
(defn test-reader-macro []
|
||||
"Test a basic redaer macro"
|
||||
(defreader ^ [expr]
|
||||
@ -34,3 +37,34 @@
|
||||
(assert (= (, 1 2 3) a)))
|
||||
|
||||
|
||||
(defn test-builtin-decorator-reader []
|
||||
(defn increment-arguments [func]
|
||||
"Increments each argument passed to the decorated function."
|
||||
#@((wraps func)
|
||||
(defn wrapper [&rest args &kwargs kwargs]
|
||||
(apply func
|
||||
(map inc args)
|
||||
(dict-comp k (inc v) [[k v] (.items kwargs)])))))
|
||||
|
||||
#@(increment-arguments
|
||||
(defn foo [&rest args &kwargs kwargs]
|
||||
"Bar."
|
||||
(, args kwargs)))
|
||||
|
||||
;; The decorator did what it was supposed to
|
||||
(assert (= (, (, 2 3 4) {"quux" 5 "baz" 6})
|
||||
(foo 1 2 3 :quux 4 :baz 5)))
|
||||
|
||||
;; @wraps preserved the doctstring and __name__
|
||||
(assert (= "foo" (. foo --name--)))
|
||||
(assert (= "Bar." (. foo --doc--)))
|
||||
|
||||
;; We can use the #@ reader macro to apply more than one decorator
|
||||
#@(increment-arguments
|
||||
increment-arguments
|
||||
(defn double-foo [&rest args &kwargs kwargs]
|
||||
"Bar."
|
||||
(, args kwargs)))
|
||||
|
||||
(assert (= (, (, 3 4 5) {"quux" 6 "baz" 7})
|
||||
(double-foo 1 2 3 :quux 4 :baz 5))))
|
||||
|
@ -1,10 +1,10 @@
|
||||
(defn test-shadow-addition []
|
||||
"NATIVE: test shadow addition"
|
||||
(let [[x +]]
|
||||
(let [x +]
|
||||
(assert (try
|
||||
(x)
|
||||
(catch [TypeError] True)
|
||||
(else (throw AssertionError))))
|
||||
(except [TypeError] True)
|
||||
(else (raise AssertionError))))
|
||||
(assert (= (x 1 2 3 4) 10))
|
||||
(assert (= (x 1 2 3 4 5) 15))
|
||||
; with strings
|
||||
@ -21,11 +21,11 @@
|
||||
|
||||
(defn test-shadow-subtraction []
|
||||
"NATIVE: test shadow subtraction"
|
||||
(let [[x -]]
|
||||
(let [x -]
|
||||
(assert (try
|
||||
(x)
|
||||
(catch [TypeError] True)
|
||||
(else (throw AssertionError))))
|
||||
(except [TypeError] True)
|
||||
(else (raise AssertionError))))
|
||||
(assert (= (x 1) -1))
|
||||
(assert (= (x 2 1) 1))
|
||||
(assert (= (x 2 1 1) 0))))
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
(defn test-shadow-multiplication []
|
||||
"NATIVE: test shadow multiplication"
|
||||
(let [[x *]]
|
||||
(let [x *]
|
||||
(assert (= (x) 1))
|
||||
(assert (= (x 3) 3))
|
||||
(assert (= (x 3 3) 9))))
|
||||
@ -41,11 +41,11 @@
|
||||
|
||||
(defn test-shadow-division []
|
||||
"NATIVE: test shadow division"
|
||||
(let [[x /]]
|
||||
(let [x /]
|
||||
(assert (try
|
||||
(x)
|
||||
(catch [TypeError] True)
|
||||
(else (throw AssertionError))))
|
||||
(except [TypeError] True)
|
||||
(else (raise AssertionError))))
|
||||
(assert (= (x 1) 1))
|
||||
(assert (= (x 8 2) 4))
|
||||
(assert (= (x 8 2 2) 2))
|
||||
@ -57,12 +57,12 @@
|
||||
(for [x [< <= = != >= >]]
|
||||
(assert (try
|
||||
(x)
|
||||
(catch [TypeError] True)
|
||||
(else (throw AssertionError))))
|
||||
(except [TypeError] True)
|
||||
(else (raise AssertionError))))
|
||||
(assert (try
|
||||
(x 1)
|
||||
(catch [TypeError] True)
|
||||
(else (throw AssertionError)))))
|
||||
(except [TypeError] True)
|
||||
(else (raise AssertionError)))))
|
||||
(for [(, x y) [[< >=]
|
||||
[<= >]
|
||||
[= !=]]]
|
||||
@ -71,12 +71,12 @@
|
||||
[1 1]
|
||||
[2 2]]]
|
||||
(assert (= (apply x args) (not (apply y args))))))
|
||||
(let [[s-lt <]
|
||||
[s-gt >]
|
||||
[s-le <=]
|
||||
[s-ge >=]
|
||||
[s-eq =]
|
||||
[s-ne !=]]
|
||||
(let [s-lt <
|
||||
s-gt >
|
||||
s-le <=
|
||||
s-ge >=
|
||||
s-eq =
|
||||
s-ne !=]
|
||||
(assert (apply s-lt [1 2 3]))
|
||||
(assert (not (apply s-lt [3 2 1])))
|
||||
(assert (apply s-gt [3 2 1]))
|
||||
|
@ -3,8 +3,8 @@
|
||||
(assert (= (unless false 1) 1))
|
||||
(assert (= (unless false 1 2) 2))
|
||||
(assert (= (unless false 1 3) 3))
|
||||
(assert (= (unless true 2) null))
|
||||
(assert (= (unless true 2) None))
|
||||
(assert (= (unless true 2) nil))
|
||||
(assert (= (unless (!= 1 2) 42) null))
|
||||
(assert (= (unless (!= 1 2) 42) None))
|
||||
(assert (= (unless (!= 1 2) 42) nil))
|
||||
(assert (= (unless (!= 2 2) 42) 42)))
|
||||
|
@ -3,8 +3,8 @@
|
||||
(assert (= (when true 1) 1))
|
||||
(assert (= (when true 1 2) 2))
|
||||
(assert (= (when true 1 3) 3))
|
||||
(assert (= (when false 2) null))
|
||||
(assert (= (when (= 1 2) 42) null))
|
||||
(assert (= (when false 2) None))
|
||||
(assert (= (when (= 1 2) 42) None))
|
||||
(assert (= (when false 2) nil))
|
||||
(assert (= (when (= 1 2) 42) nil))
|
||||
(assert (= (when (= 2 2) 42) 42)))
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
(with-decorator bardec
|
||||
(defclass cls []
|
||||
[[my_attr 456]]))
|
||||
[my_attr 456]))
|
||||
|
||||
(defn test-decorator-clobbing []
|
||||
"NATIVE: Tests whether nested decorators work"
|
||||
|
@ -1,44 +1,41 @@
|
||||
(defclass WithTest [object]
|
||||
[(--init--
|
||||
(fn [self val]
|
||||
(setv self.val val)
|
||||
None))
|
||||
(defn --init-- [self val]
|
||||
(setv self.val val)
|
||||
None)
|
||||
|
||||
(--enter--
|
||||
(fn [self]
|
||||
self.val))
|
||||
(defn --enter-- [self]
|
||||
self.val)
|
||||
|
||||
(--exit--
|
||||
(fn [self type value traceback]
|
||||
(setv self.val None)))])
|
||||
(defn --exit-- [self type value traceback]
|
||||
(setv self.val None)))
|
||||
|
||||
(defn test-single-with []
|
||||
"NATIVE: test a single with"
|
||||
(with [[t (WithTest 1)]]
|
||||
(assert (= t 1))))
|
||||
(with [t (WithTest 1)]
|
||||
(assert (= t 1))))
|
||||
|
||||
(defn test-two-with []
|
||||
"NATIVE: test two withs"
|
||||
(with [[t1 (WithTest 1)]
|
||||
[t2 (WithTest 2)]]
|
||||
(assert (= t1 1))
|
||||
(assert (= t2 2))))
|
||||
(with [t1 (WithTest 1)
|
||||
t2 (WithTest 2)]
|
||||
(assert (= t1 1))
|
||||
(assert (= t2 2))))
|
||||
|
||||
(defn test-thrice-with []
|
||||
"NATIVE: test three withs"
|
||||
(with [[t1 (WithTest 1)]
|
||||
[t2 (WithTest 2)]
|
||||
[t3 (WithTest 3)]]
|
||||
(assert (= t1 1))
|
||||
(assert (= t2 2))
|
||||
(assert (= t3 3))))
|
||||
(with [t1 (WithTest 1)
|
||||
t2 (WithTest 2)
|
||||
t3 (WithTest 3)]
|
||||
(assert (= t1 1))
|
||||
(assert (= t2 2))
|
||||
(assert (= t3 3))))
|
||||
|
||||
(defn test-quince-with []
|
||||
"NATIVE: test four withs, one with no args"
|
||||
(with [[t1 (WithTest 1)]
|
||||
[t2 (WithTest 2)]
|
||||
[t3 (WithTest 3)]
|
||||
[(WithTest 4)]]
|
||||
(assert (= t1 1))
|
||||
(assert (= t2 2))
|
||||
(assert (= t3 3))))
|
||||
(defn test-quince-with []
|
||||
"NATIVE: test four withs, one with no args"
|
||||
(with [t1 (WithTest 1)
|
||||
t2 (WithTest 2)
|
||||
t3 (WithTest 3)
|
||||
_ (WithTest 4)]
|
||||
(assert (= t1 1))
|
||||
(assert (= t2 2))
|
||||
(assert (= t3 3))))
|
||||
|
Loading…
Reference in New Issue
Block a user