Merge branch 'master' into pr/526
This commit is contained in:
commit
b1a928037e
13
.travis.yml
13
.travis.yml
@ -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:
|
||||
|
1
AUTHORS
1
AUTHORS
@ -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
80
NEWS
@ -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:
|
||||
|
40
bin/hy2py
40
bin/hy2py
@ -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))
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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>`_.
|
||||
|
@ -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.
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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])
|
||||
|
@ -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))
|
||||
|
@ -20,4 +20,4 @@
|
||||
|
||||
|
||||
__appname__ = "hy"
|
||||
__version__ = "0.9.12"
|
||||
__version__ = "0.10.0"
|
||||
|
@ -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
|
||||
|
@ -1,3 +0,0 @@
|
||||
# Check site / dev for more deps!
|
||||
flake8
|
||||
rply>=0.7.0
|
3
setup.py
3
setup.py
@ -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*']),
|
||||
|
@ -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))))
|
||||
|
@ -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 []
|
||||
|
@ -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)
|
||||
|
@ -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
37
tox.ini
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user