Merge branch 'master' into partition
This commit is contained in:
commit
7a839aee5d
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@
|
||||
dist
|
||||
.coverage
|
||||
build/
|
||||
.noseids
|
||||
|
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)`
|
||||
|
||||
|
@ -63,10 +63,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).
|
||||
|
||||
->
|
||||
@ -267,11 +267,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 +288,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.
|
||||
@ -357,7 +356,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:
|
||||
@ -365,9 +366,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")
|
||||
@ -378,10 +380,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:
|
||||
|
||||
@ -488,28 +490,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
|
||||
-------
|
||||
@ -571,31 +551,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!:
|
||||
|
||||
@ -835,7 +790,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
|
||||
|
||||
@ -881,47 +836,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
|
||||
@ -1275,45 +1222,45 @@ counted starting from the end of the list. Some example usage:
|
||||
[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.
|
||||
|
@ -672,21 +672,22 @@ Returns ``True`` if *x* is odd. Raises ``TypeError`` if
|
||||
False
|
||||
|
||||
|
||||
.. _pos?-fn:
|
||||
.. _partition-fn:
|
||||
|
||||
partition
|
||||
---------
|
||||
|
||||
Usage: ``(partition n coll)``
|
||||
|
||||
Chunks coll into tuples of length n. The remainder, if any, is not included.
|
||||
Chunks coll into tuples of length *n*. The remainder, if any, is not included.
|
||||
|
||||
.. code-block:: hy
|
||||
|
||||
=> (list (partition 3 (range 10)))
|
||||
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]
|
||||
|
||||
.. _partition-fn:
|
||||
|
||||
.. _pos?-fn:
|
||||
|
||||
pos?
|
||||
----
|
||||
@ -1071,7 +1072,7 @@ if *from-file* ends before a complete expression can be parsed.
|
||||
... (do
|
||||
... (print "OHY" exp)
|
||||
... (eval exp))))
|
||||
... (catch [e EOFError]
|
||||
... (except [e EOFError]
|
||||
... (print "EOF!"))))
|
||||
OHY ('print' 'hello')
|
||||
hello
|
||||
|
@ -477,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::
|
||||
@ -502,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]
|
||||
|
@ -81,7 +81,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
|
||||
@ -459,8 +459,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
|
||||
@ -728,15 +729,11 @@ class HyASTCompiler(object):
|
||||
|
||||
elist = [HySymbol("hy_eval")] + [expr[0]]
|
||||
if len(expr) >= 2:
|
||||
if not isinstance(expr[1], (HyDict, HySymbol)):
|
||||
raise HyTypeError(expr, "Globals must be a dictionary")
|
||||
elist.append(expr[1])
|
||||
else:
|
||||
elist.append(HyExpression([HySymbol("locals")]))
|
||||
|
||||
if len(expr) == 3:
|
||||
if not isinstance(expr[2], HyString):
|
||||
raise HyTypeError(expr, "Module name must be a string")
|
||||
elist.append(expr[2])
|
||||
else:
|
||||
elist.append(HyString(self.module_name))
|
||||
@ -748,15 +745,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:
|
||||
@ -828,7 +823,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"):
|
||||
@ -906,7 +901,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]))
|
||||
@ -1476,9 +1470,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(
|
||||
@ -1972,10 +1973,15 @@ class HyASTCompiler(object):
|
||||
|
||||
@builds("def")
|
||||
@builds("setv")
|
||||
@checkargs(min=2)
|
||||
def compile_def_expression(self, expression):
|
||||
expression.pop(0)
|
||||
if len(expression) == 2:
|
||||
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)
|
||||
@ -2007,6 +2013,10 @@ class HyASTCompiler(object):
|
||||
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:
|
||||
@ -2238,15 +2248,15 @@ class HyASTCompiler(object):
|
||||
|
||||
@builds("defclass")
|
||||
@checkargs(min=1)
|
||||
def compile_class_expression(self, expression):
|
||||
expression.pop(0) # class
|
||||
def compile_class_expression(self, expressions):
|
||||
expressions.pop(0) # class
|
||||
|
||||
class_name = expression.pop(0)
|
||||
class_name = expressions.pop(0)
|
||||
|
||||
if expression:
|
||||
base_list = expression.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:
|
||||
@ -2256,8 +2266,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
|
||||
@ -2266,31 +2276,25 @@ 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()
|
||||
if expressions and isinstance(expressions[0], HyList) \
|
||||
and not isinstance(expressions[0], HyExpression):
|
||||
expr = expressions.pop(0)
|
||||
body += self.compile(
|
||||
HyExpression([
|
||||
HySymbol("setv")
|
||||
] + expr).replace(expr)
|
||||
)
|
||||
|
||||
for expression in expressions:
|
||||
body += self.compile(macroexpand(expression, self.module_name))
|
||||
|
||||
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=[],
|
||||
@ -2373,7 +2377,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)
|
||||
@ -2382,7 +2386,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))
|
@ -121,3 +121,27 @@
|
||||
(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)))
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
;; DEALINGS IN THE SOFTWARE.
|
||||
|
||||
(defun Botsbuildbots () (Botsbuildbots))
|
||||
(defn Botsbuildbots () (Botsbuildbots))
|
||||
|
||||
(defmacro Botsbuildbots []
|
||||
"Build bots, repeatedly.^W^W^WPrint the AUTHORS, forever."
|
||||
@ -29,5 +29,5 @@
|
||||
(let [[r (requests.get
|
||||
"https://raw.githubusercontent.com/hylang/hy/master/AUTHORS")]]
|
||||
(repeat r.text)))
|
||||
(catch [e ImportError]
|
||||
(except [e ImportError]
|
||||
(repeat "Botsbuildbots requires `requests' to function."))))
|
||||
|
@ -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)
|
||||
|
@ -7,7 +7,7 @@
|
||||
{"methods" ~methods})]]
|
||||
(with-decorator deco
|
||||
(defn ~name ~params
|
||||
(progn ~@code)))))
|
||||
(do ~@code)))))
|
||||
|
||||
;; Some macro examples
|
||||
(defmacro route [name path params &rest code]
|
||||
|
@ -31,21 +31,12 @@
|
||||
`(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)))
|
||||
|
||||
|
||||
|
@ -222,8 +222,8 @@
|
||||
"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."
|
||||
@ -381,7 +381,7 @@
|
||||
(while true
|
||||
(def inn (str (.read from-file 1)))
|
||||
(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)))
|
||||
@ -414,7 +414,7 @@
|
||||
(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.
|
||||
@ -425,7 +425,7 @@
|
||||
(hyify value)
|
||||
(try
|
||||
(hyify (. value __name__))
|
||||
(catch [] (string value))))))
|
||||
(except [] (string value))))))
|
||||
|
||||
(def *exports*
|
||||
'[butlast calling-module-name coll? cons cons? cycle dec distinct disassemble
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
|
||||
(defmacro with [args &rest body]
|
||||
"shorthand for nested for* loops:
|
||||
"shorthand for nested with* loops:
|
||||
(with [[x foo] [y bar]] baz) ->
|
||||
(with* [x foo]
|
||||
(with* [y bar]
|
||||
@ -73,10 +73,11 @@
|
||||
"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 (< (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)
|
||||
@ -96,16 +97,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
|
||||
[(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])] ~@body))]))
|
||||
`(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] (do ~@body) ~@belse))]))
|
||||
|
||||
|
||||
(defmacro -> [head &rest rest]
|
||||
@ -149,11 +157,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))
|
||||
|
||||
@ -189,7 +197,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))
|
||||
@ -210,16 +218,6 @@
|
||||
(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))
|
||||
|
||||
(defreader @ [expr]
|
||||
(let [[decorators (cut expr nil -1)]
|
||||
[fndef (get expr -1)]]
|
||||
|
@ -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)
|
||||
|
||||
|
@ -289,7 +289,6 @@ def t_identifier(p):
|
||||
"true": "True",
|
||||
"false": "False",
|
||||
"nil": "None",
|
||||
"null": "None",
|
||||
}
|
||||
|
||||
if obj in table:
|
||||
@ -308,6 +307,9 @@ def t_identifier(p):
|
||||
if p.endswith("?") and p != "?":
|
||||
p = "is_%s" % (p[:-1])
|
||||
|
||||
if p.endswith("!") and p != "!":
|
||||
p = "%s_bang" % (p[:-1])
|
||||
|
||||
return p
|
||||
|
||||
obj = ".".join([mangle(part) for part in obj.split(".")])
|
||||
|
@ -7,13 +7,13 @@
|
||||
(setv *maintainer-line*
|
||||
" -- Alexander Artemenko <svetlyak.40wt@gmail.com> Thu, 30 Sep 2014 13:06:09 +0400")
|
||||
|
||||
(defun read-lines-from-file [filename]
|
||||
(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]
|
||||
(defn get-version-number [line]
|
||||
(let [[match (re.search r"Changes from.*(\d+\.\d+\.\d+)$" line)]]
|
||||
(if match
|
||||
(let [[version (.group match (int 1))]
|
||||
@ -26,7 +26,7 @@
|
||||
(.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,12 +35,12 @@
|
||||
[content line])
|
||||
|
||||
|
||||
(defun read-versions-from-file [filename]
|
||||
(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)]]
|
||||
@ -50,7 +50,7 @@
|
||||
(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")]
|
||||
|
@ -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():
|
||||
@ -470,6 +439,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 +494,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 +507,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 +529,25 @@ 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)")
|
||||
|
@ -326,6 +326,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]
|
||||
|
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)))
|
@ -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))
|
||||
|
@ -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,12 +2,11 @@
|
||||
|
||||
(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)]]
|
||||
|
@ -32,4 +32,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))))))))
|
||||
'(with* [a] (with* [b] (with* [c] (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,11 @@
|
||||
(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"
|
||||
@ -488,11 +488,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"
|
||||
@ -555,7 +555,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]))
|
||||
|
||||
@ -582,7 +582,7 @@
|
||||
(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 []
|
||||
|
@ -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,9 +31,9 @@
|
||||
(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)]]
|
||||
@ -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,26 @@
|
||||
|
||||
(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"))
|
||||
|
@ -34,6 +34,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])
|
||||
@ -43,25 +48,23 @@
|
||||
(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 []
|
||||
@ -72,29 +75,33 @@
|
||||
(setv y 0 x 1 y x)
|
||||
(assert y)
|
||||
(try (eval '(setv a 1 b))
|
||||
(catch [e [TypeError]] (assert (in "setv needs an even number of arguments" (str e))))))
|
||||
(except [e [TypeError]] (assert (in "setv needs an even number of arguments" (str e))))))
|
||||
|
||||
|
||||
(defn test-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-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)))))
|
||||
@ -115,21 +122,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.
|
||||
@ -224,7 +231,7 @@
|
||||
"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)]))
|
||||
|
||||
|
||||
(defn test-index []
|
||||
@ -365,22 +372,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
|
||||
@ -389,7 +396,7 @@
|
||||
|
||||
(try
|
||||
(get [1] 3)
|
||||
(catch [e [IndexError NameError]] (assert (isinstance e IndexError))))
|
||||
(except [e [IndexError NameError]] (assert (isinstance e IndexError))))
|
||||
|
||||
(try
|
||||
(print foobar42ofthebaz)
|
||||
@ -397,15 +404,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)
|
||||
@ -417,7 +424,7 @@
|
||||
|
||||
(try
|
||||
(print foobar42ofthebaz)
|
||||
(catch []
|
||||
(except []
|
||||
(setv foobar42ofthebaz 42)
|
||||
(assert (= foobar42ofthebaz 42))))
|
||||
|
||||
@ -669,6 +676,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 [])
|
||||
@ -754,7 +767,7 @@
|
||||
6))
|
||||
(try
|
||||
(assert (= x 42)) ; This ain't true
|
||||
(catch [e [NameError]] (assert e)))
|
||||
(except [e [NameError]] (assert e)))
|
||||
(assert (= y 123)))
|
||||
|
||||
|
||||
@ -867,18 +880,6 @@
|
||||
(assert (= None (eval (quote (print ""))))))
|
||||
|
||||
|
||||
(defmacro assert-throw [exc-type &rest body]
|
||||
`(try
|
||||
(do
|
||||
(eval ~@body)
|
||||
(assert False "we shouldn't have arrived here"))
|
||||
(catch [e Exception]
|
||||
(assert (instance? ~exc-type e)
|
||||
(.format "Expected exception of type {}, got {}: {}"
|
||||
(. ~exc-type --name--)
|
||||
(. (type e) --name--)
|
||||
(str e))))))
|
||||
|
||||
(defn test-eval-globals []
|
||||
"NATIVE: test eval with explicit global dict"
|
||||
(assert (= 'bar (eval (quote foo) {'foo 'bar})))
|
||||
@ -891,16 +892,17 @@
|
||||
; 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]])
|
||||
(assert-throw HyTypeError '(eval))
|
||||
(assert-throw HyTypeError '(eval "snafu"))
|
||||
(assert-throw HyTypeError '(eval 'false []))
|
||||
(assert-throw HyTypeError '(eval 'false {} 1)))
|
||||
; 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 []
|
||||
@ -991,7 +993,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))))
|
||||
|
||||
@ -1159,7 +1161,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 []
|
||||
@ -1183,7 +1185,7 @@
|
||||
(read stdin-buffer)
|
||||
(try
|
||||
(read stdin-buffer)
|
||||
(catch [e Exception]
|
||||
(except [e Exception]
|
||||
(assert (isinstance e EOFError)))))
|
||||
|
||||
(defn test-read-str []
|
||||
|
@ -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]
|
||||
@ -180,14 +180,14 @@
|
||||
product-of-test-matrices))
|
||||
;; Python <= 3.4
|
||||
(let [[matmul-attempt (try (@ first-test-matrix second-test-matrix)
|
||||
(catch [e [Exception]] e))]]
|
||||
(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))]]
|
||||
(except [e [Exception]] e))]]
|
||||
(if PY35
|
||||
(assert (= product-of-test-matrices matrix))
|
||||
(assert (isinstance matmul-attempt NameError)))))
|
||||
|
@ -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,7 +241,7 @@
|
||||
(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])))
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
(let [[kwonly-foo-no-default (fn [&kwonly foo] foo)]
|
||||
[attempt-to-omit-default (try
|
||||
(kwonly-foo-no-default)
|
||||
(catch [e [Exception]] e))]]
|
||||
(except [e [Exception]] e))]]
|
||||
;; works
|
||||
(assert (= (apply kwonly-foo-no-default [] {"foo" "quux"}) "quux"))
|
||||
;; raises TypeError with appropriate message if not supplied
|
||||
|
@ -3,8 +3,8 @@
|
||||
(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
|
||||
@ -24,8 +24,8 @@
|
||||
(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))))
|
||||
@ -44,8 +44,8 @@
|
||||
(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) [[< >=]
|
||||
[<= >]
|
||||
[= !=]]]
|
||||
|
@ -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,16 +1,13 @@
|
||||
(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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user