Merge branch 'master' into pr/526

This commit is contained in:
Tuukka Turto 2014-05-02 10:34:37 +03:00
commit b1a928037e
22 changed files with 423 additions and 225 deletions

View File

@ -1,19 +1,18 @@
language: python
python:
- "pypy"
- "2.6"
- "2.7"
- "3.2"
- "3.3"
- "2.6"
- "3.4"
# command to install dependencies
install:
- pip install -r requirements.txt
- pip install -r requirements-dev.txt
- pip install coveralls
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install argparse importlib unittest2 astor; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then pip install astor; fi
- if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then pip install astor; fi
- python setup.py -q install
# # command to run tests
- if [[ $TRAVIS_PYTHON_VERSION == '2.6' ]]; then pip install unittest2; fi # needs for running tests
- pip install --allow-all-external -e .
# command to run tests
script: make travis
after_success: coveralls
notifications:

View File

@ -45,3 +45,4 @@
* kirbyfan64 <kirbyfan64@users.noreply.github.com>
* Brendan Curran-Johnson <brendan@bcjbcj.ca>
* Ivan Kozik <ivan@ludios.org>
* Allison Kaptur <allison.kaptur@gmail.com>

80
NEWS
View File

@ -1,3 +1,83 @@
Changes from 0.9.12
0.10.0 - the "oh man I'm late for PyCon" release
Thanks to theanalyst (Abhi) for getting the release notes
together. You're the best!
- Hy Society
[ Breaking Changes ]
We're calling this release 0.10 because we broke
API. Sorry about that. We've removed kwapply in
favor of using `apply`. Please be sure to upgrade
all code to work with `apply`.
(apply function-call args kwargs) ; is the signature
[Thanks]
Major shoutout to Clinton Dreisbach for implementing loop/recur.
As always, massive hugs to olasd for the constant reviews and for
implementing HyCons cells. Thanks to @kenanb for redesigning the
new Hy logo.
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.
This release saw an increase of about 11 contributors for a point
release, you guys rock!
-Hy Society
[ Language Changes ]
* `for' revamped again (Last time, we hope!), this time using a saner
itertools.product when nesting
* `lisp-if'/`lif' added for the lisp-like everything is true if, giving
seasoned lispers a better if check (0 is a value, etc)
* Reader Macros are macros now!
* yield-from is now a proper yield from on Python 3. It also now breaks on
Python 2.x.
* Added if-not macro
* We finally have a lisp like cons cells
* Generator expressions, set & dict comprehensions are now supported
* (.) is a mini DSL for attribute access
* `macroexpand' & `macroexpand-1' added to core
* `disassemble' added to core, which dumps the AST or equivalent python code
* `coll?' added to core to check for a collection
* `identity' function added to core
[ Misc. Fixes ]
* Lots of doc fixes. Reorganization as well as better docs on Hy internals
* Universal Wheel Support
* Pygments > 1.6 supports Hy now. All codeblocks in docs have been changed
from clojure to hy
* Hy REPL supports invoking with --spy & -i options [reword]
* `first' and `rest' are functions and not macros anymore
* "clean" target added to Makefile
* hy2py supports a bunch of commandline options to show AST, source etc.
* Sub-object mangling: every identifier is split along the dots & mangled
seperately
[ Bug Fixes ]
* Empty MacroExpansions work as expected
* Python 3.4 port. Sorry this wasn't in a 3.4 release time, we forgot to do
a release. Whoops.
* eg/lxml/parse-tumblr.hy works with Python 3
* hy2py works on Windows
* Fixed unicode encoding issue in REPL during unicode exceptions
* Fixed handling of comments at end of input (#382)
[ Contrib changes ]
* Curry module added to contrib
* Loop/recur module added which provides TCO at tail position
* defmulti has been added - check out more in the docs -- thanks to Foxboron for this one!
* Walk module for walking the Hy AST, features a `macroexpand-all` as well
Changes from Hy 0.9.11
tl;dr:

View File

@ -1,40 +0,0 @@
#!/usr/bin/env python
from __future__ import print_function
from hy.importer import import_file_to_ast, import_file_to_hst
import argparse
import sys
import astor.codegen
module_name = "<STDIN>"
parser = argparse.ArgumentParser(
prog="hy2py",
usage="%(prog)s [options] FILE",
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--with-source", "-s", action="store_true",
help="Show the parsed source structure")
parser.add_argument("--with-ast", "-a", action="store_true",
help="Show the generated AST")
parser.add_argument("--without-python", "-np", action="store_true",
help="Do not show the python code generated from the AST")
parser.add_argument('args', nargs=argparse.REMAINDER, help=argparse.SUPPRESS)
options = parser.parse_args(sys.argv[1:])
if options.with_source:
hst = import_file_to_hst(options.args[0])
print(hst)
print()
print()
_ast = import_file_to_ast(options.args[0], module_name)
if options.with_ast:
print(astor.dump(_ast))
print()
print()
if not options.without_python:
print(astor.codegen.to_source(_ast))

View File

@ -96,7 +96,13 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
try:
import sphinx_rtd_theme
except ImportError:
html_theme = 'default'
else:
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the

View File

@ -92,6 +92,12 @@ Write docs---docs are good! Even this doc!
Core Development Rules
======================
Pull requests are good!
Before you submit a PR, please run the tests and check your code against the style guide. You can do both these things at once::
$ make d
All incoming changes need to be acked by 2 different members of Hylang's
core team. Additional review is clearly welcome, but we need a minimum of
2 signoffs for any change.

View File

@ -764,6 +764,36 @@ any numeric type, empty sequence and empty dictionary are considered `False`.
Everything else is considered `True`.
lisp-if / lif
-------------
.. versionadded:: 0.10.0
For those that prefer a more lisp-y if clause, we have lisp-if, or lif. This
*only* considers None/nil as false! All other values of python
"falseiness" are considered true.
.. 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"
; And, same thing
=> (lif True "true" "false")
"true"
=> (lif nil "true" "false")
"false"
import
------
@ -824,11 +854,15 @@ Just as in normal function definitions, if the first element of the
body is a string, it serves as docstring. This is useful for giving
class methods docstrings.
.. code-block:: clj
=> (setv times-three
... (fn [x]
... "Multiplies input by three and returns the result."
... (* x 3)))
Then test it via the Python built-in ``help`` function::
=> (help times-three)
Help on function times_three:
@ -1265,23 +1299,15 @@ infinite series without consuming infinite amount of memory.
=> (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]
.. _zipwith:
zipwith
-------
yield-from
----------
.. versionadded:: 0.10.0
.. versionadded:: 0.9.13
`zipwith` zips multiple lists and maps the given function over the result. It is
equilavent to calling ``zip``, followed by calling ``map`` on the result.
**PYTHON 3.3 AND UP ONLY!**
In the following example, `zipwith` is used to add the contents of two lists
together. The equilavent ``map`` and ``zip`` calls follow.
.. code-block:: clj
=> (import operator.add)
=> (zipwith operator.add [1 2 3] [4 5 6]) ; using zipwith
[5, 7, 9]
=> (map operator.add (zip [1 2 3] [4 5 6])) ; using map+zip
[5, 7, 9]
`yield-from` is used to call a subgenerator. This is useful if you
want your coroutine to be able to delegate its processes to another
coroutine, say if using something fancy like
`asyncio <http://docs.python.org/3.4/library/asyncio.html>`_.

View File

@ -2,6 +2,8 @@
Command Line Interface
======================
.. _hy:
hy
--
@ -46,6 +48,8 @@ Command line options
Print the Hy version number and exit.
.. _hyc:
hyc
---
@ -71,3 +75,29 @@ Command line options
$ hyc hyname.hy
$ python hyname.pyc
Hy Afroman!
.. _hy2py:
hy2py
-----
.. versionadded:: 0.10.1
Command line options
^^^^^^^^^^^^^^^^^^^^
.. cmdoption:: -s
--with-source
Show the parsed source structure.
.. cmdoption:: -a
--with-ast
Show the generated AST.
.. cmdoption:: -np
--without-python
Do not show the Python code generated from the AST.

View File

@ -495,8 +495,8 @@ nth
Usage: ``(nth coll n)``
Return the `nth` item in a collection, counting from 0. Unlike
``get``, ``nth`` works on both iterators and iterables. Returns ``None``
if the `n` is outside the range of `coll`.
``get``, ``nth`` works on both iterators and iterables. Raises ``IndexError``
if the `n` is outside the range of ``coll`` or ``ValueError`` if it's negative.
.. code-block:: hy
@ -506,8 +506,10 @@ if the `n` is outside the range of `coll`.
=> (nth [1 2 4 7] 3)
7
=> (none? (nth [1 2 4 7] 5))
True
=> (nth [1 2 4 7] 5)
Traceback (most recent call last):
...
IndexError: 5
=> (nth (take 3 (drop 2 [1 2 3 4 5 6])) 2))
5
@ -764,6 +766,7 @@ drop
Usage: ``(drop n coll)``
Return an iterator, skipping the first ``n`` members of ``coll``
Raises ``ValueError`` if ``n`` is negative.
.. code-block:: hy
@ -924,6 +927,7 @@ take
Usage: ``(take n coll)``
Return an iterator containing the first ``n`` members of ``coll``.
Raises ``ValueError`` if ``n`` is negative.
.. code-block:: hy
@ -979,3 +983,21 @@ Return an iterator from ``coll`` as long as predicate, ``pred`` returns True.
=> (list (take-while neg? [ 1 2 3 -4 5]))
[]
.. _zipwith:
zipwith
-------
.. versionadded:: 0.9.13
Usage: ``(zipwith fn coll ...)``
Equivalent to ``zip``, but uses a multi-argument function instead of creating a tuple.
If ``zipwith`` is called with N collections, then ``fn`` must accept N arguments.
.. code-block:: clojure
=> (import operator)
=> (list (zipwith operator.add [1 2 3] [4 5 6]))
[5, 7, 9]

View File

@ -25,16 +25,21 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
from __future__ import print_function
import argparse
import code
import ast
import sys
import astor.codegen
import hy
from hy.lex import LexException, PrematureEndOfInput, tokenize
from hy.compiler import hy_compile, HyTypeError
from hy.importer import ast_compile, import_buffer_to_module
from hy.importer import (ast_compile, import_buffer_to_module,
import_file_to_ast, import_file_to_hst)
from hy.completer import completion
from hy.macros import macro, require
@ -66,7 +71,6 @@ builtins.exit = HyQuitter('exit')
def print_python_code(_ast):
import astor.codegen
# astor cannot handle ast.Interactive, so disguise it as a module
_ast_for_print = ast.Module()
_ast_for_print.body = _ast.body
@ -313,3 +317,43 @@ def hyc_main():
sys.stderr.write("hyc: Can't open file '%s': [Errno %d] %s\n" %
(x.filename, x.errno, x.strerror))
sys.exit(x.errno)
# entry point for cmd line script "hy2py"
def hy2py_main():
module_name = "<STDIN>"
options = dict(prog="hy2py", usage="%(prog)s [options] FILE",
formatter_class=argparse.RawDescriptionHelpFormatter)
parser = argparse.ArgumentParser(**options)
parser.add_argument("--with-source", "-s", action="store_true",
help="Show the parsed source structure")
parser.add_argument("--with-ast", "-a", action="store_true",
help="Show the generated AST")
parser.add_argument("--without-python", "-np", action="store_true",
help=("Do not show the Python code generated "
"from the AST"))
parser.add_argument('args', nargs=argparse.REMAINDER,
help=argparse.SUPPRESS)
options = parser.parse_args(sys.argv[1:])
if not options.args:
parser.exit(1, parser.format_help())
if options.with_source:
hst = import_file_to_hst(options.args[0])
print(hst)
print()
print()
_ast = import_file_to_ast(options.args[0], module_name)
if options.with_ast:
print(astor.dump(_ast))
print()
print()
if not options.without_python:
print(astor.codegen.to_source(_ast))
parser.exit(0)

View File

@ -732,25 +732,10 @@ class HyASTCompiler(object):
handler_results += self._compile_catch_expression(e, name)
handlers.append(handler_results.stmts.pop())
elif e[0] == HySymbol("else"):
if orelse:
raise HyTypeError(
e,
"`try' cannot have more than one `else'")
else:
orelse = self._compile_branch(e[1:])
# XXX tempvar magic
orelse += orelse.expr_as_stmt()
orelse = orelse.stmts
orelse = self.try_except_helper(e, HySymbol("else"), orelse)
elif e[0] == HySymbol("finally"):
if finalbody:
raise HyTypeError(
e,
"`try' cannot have more than one `finally'")
else:
finalbody = self._compile_branch(e[1:])
# XXX tempvar magic
finalbody += finalbody.expr_as_stmt()
finalbody = finalbody.stmts
finalbody = self.try_except_helper(e, HySymbol("finally"),
finalbody)
else:
raise HyTypeError(e, "Unknown expression in `try'")
@ -768,8 +753,8 @@ class HyASTCompiler(object):
col_offset=expr.start_column,
type=None,
name=None,
body=[ast.Pass(lineno=expr.start_line,
col_offset=expr.start_column)])]
body=[ast.Raise(lineno=expr.start_line,
col_offset=expr.start_column)])]
ret = handler_results
@ -809,6 +794,17 @@ class HyASTCompiler(object):
body=body,
orelse=orelse) + returnable
def try_except_helper(self, hy_obj, symbol, accumulated):
if accumulated:
raise HyTypeError(
hy_obj,
"`try' cannot have more than one `%s'" % symbol)
else:
accumulated = self._compile_branch(hy_obj[1:])
accumulated += accumulated.expr_as_stmt()
accumulated = accumulated.stmts
return accumulated
@builds("except")
@builds("catch")
def magic_internal_form(self, expr):
@ -1017,6 +1013,28 @@ class HyASTCompiler(object):
return ret
@builds("yield_from")
@checkargs(max=1)
def compile_yield_from_expression(self, expr):
if not PY33:
raise HyCompileError(
"yield-from only supported in python 3.3+!")
expr.pop(0)
ret = Result(contains_yield=True)
value = None
if expr != []:
ret += self.compile(expr.pop(0))
value = ret.force_expr
ret += ast.YieldFrom(
value=value,
lineno=expr.start_line,
col_offset=expr.start_column)
return ret
@builds("import")
def compile_import_expression(self, expr):
def _compile_import(expr, module, names=None, importer=ast.Import):

View File

@ -23,7 +23,9 @@
;;;; to make functional programming slightly easier.
;;;;
(import itertools)
(import functools)
(import collections)
(import [hy._compat [long-type]]) ; long for python2, int for python3
(import [hy.models.cons [HyCons]])
@ -44,15 +46,11 @@
"Check whether c can be used as a cons object"
(instance? HyCons c))
(defn cycle [coll]
"Yield an infinite repetition of the items in coll"
(setv seen [])
(for* [x coll]
(yield x)
(.append seen x))
(while seen
(for* [x seen]
(yield x))))
(defn keyword? [k]
"Check whether k is a keyword"
(and (instance? (type :foo) k)
(.startswith k (get :foo 0))))
(defn dec [n]
"Decrement n by 1"
@ -82,22 +80,36 @@
(yield val)
(.add seen val))))))
(if-python2
(do
(setv filterfalse itertools.ifilterfalse)
(setv zip_longest itertools.izip_longest)
(setv filter itertools.ifilter)
(setv map itertools.imap)
(setv zip itertools.izip)
(setv range xrange)
(setv input raw_input))
(do
(setv reduce functools.reduce)
(setv filterfalse itertools.filterfalse)
(setv zip_longest itertools.zip_longest)
; Someone can import these directly from `hy.core.language`;
; we'll make some duplicates.
(setv filter filter)
(setv map map)
(setv zip zip)
(setv range range)
(setv input input)))
(setv cycle itertools.cycle)
(setv repeat itertools.repeat)
(setv drop-while itertools.dropwhile)
(setv take-while itertools.takewhile)
(setv zipwith map)
(defn drop [count coll]
"Drop `count` elements from `coll` and yield back the rest"
(let [[citer (iter coll)]]
(try (for* [i (range count)]
(next citer))
(catch [StopIteration]))
citer))
(defn drop-while [pred coll]
"Drop all elements of `coll` until `pred` is False"
(let [[citer (iter coll)]]
(for* [val citer]
(if (not (pred val))
(do (yield val) (break))))
(for* [val citer]
(yield val))))
(itertools.islice coll count nil))
(defn empty? [coll]
"Return True if `coll` is empty"
@ -121,13 +133,6 @@
(if (not (hasattr tree attr))
(setattr tree attr 1))))
(defn filter [pred coll]
"Return all elements from `coll` that pass `pred`"
(let [[citer (iter coll)]]
(for* [val citer]
(if (pred val)
(yield val)))))
(defn flatten [coll]
"Return a single flat list expanding all members of coll"
(if (coll? coll)
@ -169,7 +174,7 @@
(defn first [coll]
"Return first item from `coll`"
(get coll 0))
(nth coll 0))
(defn identity [x]
"Returns the argument unchanged"
@ -194,14 +199,13 @@
(defn integer-char? [x]
"Return True if char `x` parses as an integer"
(try
(integer? (int x))
(catch [e ValueError] False)
(catch [e TypeError] False)))
(integer? (int x))
(catch [e ValueError] False)
(catch [e TypeError] False)))
(defn iterable? [x]
"Return true if x is iterable"
(try (do (iter x) true)
(catch [Exception] false)))
(isinstance x collections.Iterable))
(defn iterate [f x]
(setv val x)
@ -211,8 +215,7 @@
(defn iterator? [x]
"Return true if x is an iterator"
(try (= x (iter x))
(catch [TypeError] false)))
(isinstance x collections.Iterator))
(defn list* [hd &rest tl]
"Return a dotted list construed from the elements of the argument"
@ -253,13 +256,9 @@
(defn nth [coll index]
"Return nth item in collection or sequence, counting from 0"
(if (not (neg? index))
(if (iterable? coll)
(try (get (list (take 1 (drop index coll))) 0)
(catch [IndexError] None))
(try (get coll index)
(catch [IndexError] None)))
None))
(try
(next (drop index coll))
(catch [e StopIteration] (raise (IndexError index)))))
(defn odd? [n]
"Return true if n is an odd number"
@ -280,14 +279,7 @@
(defn rest [coll]
"Get all the elements of a coll, except the first."
(slice coll 1))
(defn repeat [x &optional n]
"Yield x forever or optionally n times"
(if (none? n)
(setv dispatch (fn [] (while true (yield x))))
(setv dispatch (fn [] (for* [_ (range n)] (yield x)))))
(dispatch))
(drop 1 coll))
(defn repeatedly [func]
"Yield result of running func repeatedly"
@ -296,7 +288,7 @@
(defn second [coll]
"Return second item from `coll`"
(get coll 1))
(nth coll 1))
(defn some [pred coll]
"Return true if (pred x) is logical true for any x in coll, else false"
@ -317,9 +309,7 @@
(defn take [count coll]
"Take `count` elements from `coll`, or the whole set if the total
number of entries in `coll` is less than `count`."
(let [[citer (iter coll)]]
(for* [_ (range count)]
(yield (next citer)))))
(itertools.islice coll nil count))
(defn take-nth [n coll]
"Return every nth member of coll
@ -332,29 +322,15 @@
(next citer))))
(raise (ValueError "n must be positive"))))
(defn take-while [pred coll]
"Take all elements while `pred` is true"
(let [[citer (iter coll)]]
(for* [val citer]
(if (pred val)
(yield val)
(break)))))
(defn zero? [n]
"Return true if n is 0"
(_numeric_check n)
(= n 0))
(defn zipwith [func &rest lists]
"Zip the contents of several lists and map a function to the result"
(do
(import functools)
(map (functools.partial (fn [f args] (apply f args)) func) (apply zip lists))))
(def *exports* '[calling-module-name coll? cons cons? cycle dec distinct
disassemble drop drop-while empty? even? every? first filter
flatten float? gensym identity inc instance? integer
integer? integer-char? iterable? iterate iterator?
list* macroexpand macroexpand-1 neg? nil? none? nth
numeric? odd? pos? remove repeat repeatedly rest second
some string string? take take-nth take-while zero? zipwith])
integer? integer-char? iterable? iterate iterator? keyword?
list* macroexpand macroexpand-1 map neg? nil? none? nth
numeric? odd? pos? range remove repeat repeatedly rest second
some string string? take take-nth take-while zero? zip zipwith])

View File

@ -27,8 +27,8 @@
(import [hy.models.list [HyList]]
[hy.models.symbol [HySymbol]])
[hy.models.symbol [HySymbol]]
[hy._compat [PY33 PY34]])
(defmacro for [args &rest body]
@ -145,6 +145,11 @@
`(if (not ~test) ~not-branch ~yes-branch)))
(defmacro-alias [lisp-if lif] [test &rest branches]
"Like `if`, but anything that is not None/nil is considered true."
`(if (is-not ~test nil) ~@branches))
(defmacro when [test &rest body]
"Execute `body` when `test` is true"
`(if ~test (do ~@body)))
@ -155,12 +160,6 @@
`(if-not ~test (do ~@body)))
(defmacro yield-from [iterable]
"Yield all the items from iterable"
(let [[x (gensym)]]
`(for* [~x ~iterable]
(yield ~x))))
(defmacro with-gensyms [args &rest body]
`(let ~(HyList (map (fn [x] `[~x (gensym '~x)]) args))
~@body))

View File

@ -20,4 +20,4 @@
__appname__ = "hy"
__version__ = "0.9.12"
__version__ = "0.10.0"

View File

@ -1,6 +1,12 @@
-r requirements.txt
tox
# test tools
nose
tox
# code quality
flake8
coverage
# documentation
Pygments>=1.6
Sphinx
coverage
sphinx_rtd_theme

View File

@ -1,3 +0,0 @@
# Check site / dev for more deps!
flake8
rply>=0.7.0

View File

@ -59,7 +59,8 @@ setup(
entry_points={
'console_scripts': [
'hy = hy.cmdline:hy_main',
'hyc = hy.cmdline:hyc_main'
'hyc = hy.cmdline:hyc_main',
'hy2py = hy.cmdline:hy2py_main',
]
},
packages=find_packages(exclude=['tests*']),

View File

@ -82,8 +82,8 @@
(assert-equal res [None 4 5])
(setv res (list (drop 0 [1 2 3 4 5])))
(assert-equal res [1 2 3 4 5])
(setv res (list (drop -1 [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))
(setv res (list (drop 6 (iter [1 2 3 4 5]))))
(assert-equal res [])
(setv res (list (take 5 (drop 2 (iterate inc 0)))))
@ -335,12 +335,15 @@
"NATIVE: testing the nth function"
(assert-equal 2 (nth [1 2 4 7] 1))
(assert-equal 7 (nth [1 2 4 7] 3))
(assert-true (none? (nth [1 2 4 7] 5)))
(assert-true (none? (nth [1 2 4 7] -1)))
(try (do (nth [1 2 4 7] 5) (assert False))
(catch [e [IndexError]] nil))
(try (do (nth [1 2 4 7] -1) (assert False))
(catch [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))
(assert-true (none? (nth (iter [1 2 4 7]) -1)))
(try (do (nth (iter [1 2 4 7]) -1) (assert False))
(catch [e [ValueError]] nil))
(assert-equal 5 (nth (take 3 (drop 2 [1 2 3 4 5 6])) 2)))
(defn test-numeric? []
@ -429,8 +432,8 @@
(assert-equal res ["s" "s" "s" "s"])
(setv res (list (take 0 (repeat "s"))))
(assert-equal res [])
(setv res (list (take -1 (repeat "s"))))
(assert-equal res [])
(try (do (list (take -1 (repeat "s"))) (assert False))
(catch [e [ValueError]] nil))
(setv res (list (take 6 [1 2 None 4])))
(assert-equal res [1 2 None 4]))
@ -478,3 +481,14 @@
(assert-equal (list res) [4 4 4])
(setv res (zipwith operator.sub [3 7 9] [1 2 4]))
(assert-equal (list res) [2 5 5]))
(defn test-is-keyword []
"NATIVE: testing the keyword? function"
(assert (keyword? ':bar))
(assert (keyword? ':baz))
(assert (keyword? :bar))
(assert (keyword? :baz))
(assert (not (keyword? "foo")))
(assert (not (keyword? ":foo")))
(assert (not (keyword? 1)))
(assert (not (keyword? nil))))

View File

@ -236,6 +236,11 @@
"NATIVE: test do"
(do))
(defn test-bare-try [] (try
(try (raise ValueError))
(except [ValueError])
(else (assert false))))
(defn test-exceptions []
"NATIVE: test Exceptions"
@ -469,7 +474,7 @@
(defn test-rest []
"NATIVE: test rest"
(assert (= (rest [1 2 3 4 5]) [2 3 4 5])))
(assert (= (list (rest [1 2 3 4 5])) [2 3 4 5])))
(defn test-importas []

View File

@ -1,3 +1,6 @@
(import [hy._compat [PY33]])
(import [hy.errors [HyCompileError]])
(defmacro rev [&rest body]
"Execute the `body` statements in reverse"
(quasiquote (do (unquote-splice (list (reversed body))))))
@ -99,11 +102,18 @@
(defn test-yield-from []
"NATIVE: testing yield from"
(defn yield-from-test []
(for* [i (range 3)]
(yield i))
(yield-from [1 2 3]))
(assert (= (list (yield-from-test)) [0 1 2 1 2 3])))
(try
(eval
'(do (defn yield-from-test []
(for* [i (range 3)]
(yield i))
(yield-from [1 2 3]))
(assert (= (list (yield-from-test)) [0 1 2 1 2 3]))))
(catch [e HyCompileError]
;; Yup, this should happen on non-Python3.3 thingies
(assert (not PY33)))
(else (assert PY33))))
(defn test-if-python2 []
(import sys)
@ -191,6 +201,25 @@
:yes)))
(defn test-lisp-if []
"test that lisp-if works as expected"
; nil is false
(assert (= (lisp-if None "true" "false") "false"))
(assert (= (lisp-if 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 nil "true" "false") "false"))
(assert (= (lif 0 "true" "false") "true")))
(defn test-defn-alias []
(defn-alias [tda-main tda-a1 tda-a2] [] :bazinga)
(defun-alias [tda-main tda-a1 tda-a2] [] :bazinga)

View File

@ -129,7 +129,7 @@ def test_hy2py():
for f in filenames:
if f.endswith(".hy"):
i += 1
ret = run_cmd("python bin/hy2py -s -a "
ret = run_cmd("hy2py -s -a "
+ os.path.join(dirpath, f))
assert ret[0] == 0, f
assert len(ret[1]) > 1, f

37
tox.ini
View File

@ -1,39 +1,18 @@
[tox]
envlist = py27,pypy,py32,py33,py26,flake8
envlist = py26,py27,pypy,py32,py33,flake8
skipsdist = True
[testenv]
commands = nosetests
commands =
pip install --allow-all-external -e .
nosetests
deps =
nose
setuptools
rply
[testenv:pypy]
commands = nosetests
deps =
astor
nose
setuptools
rply
[testenv:py27]
commands = nosetests
deps =
astor
nose
setuptools
rply
-rrequirements-dev.txt
[testenv:py26]
deps =
astor
nose
setuptools
{[testenv]deps}
unittest2
importlib
rply
[testenv:flake8]
deps =
flake8
rply
commands = flake8 hy bin tests