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