pax_global_header00006660000000000000000000000064130417176520014520gustar00rootroot0000000000000052 comment=7a4a2ca6687da381a2b67598b90a2e28beeceaed hy-0.12.1/000077500000000000000000000000001304171765200122215ustar00rootroot00000000000000hy-0.12.1/.coveragerc000066400000000000000000000003211304171765200143360ustar00rootroot00000000000000[run] omit = */python?.?/* */lib-python/?.?/*.py */lib_pypy/_*.py */site-packages/nose/* */pypy/* [report] exclude_lines = # Have to re-enable the standard pragma pragma: no coverhy-0.12.1/.dockerignore000066400000000000000000000000051304171765200146700ustar00rootroot00000000000000.git hy-0.12.1/.gitignore000066400000000000000000000001421304171765200142060ustar00rootroot00000000000000/hy/version.py *.pyc *swp *hy*egg* *pyreadline*egg* .tox *pycache* dist .coverage build/ .noseids hy-0.12.1/.mailmap000066400000000000000000000014611304171765200136440ustar00rootroot00000000000000Paul R. Tagliamonte Paul Tagliamonte Paul R. Tagliamonte Paul Tagliamonte Paul R. Tagliamonte Paul Tagliamonte Paul R. Tagliamonte Paul Tagliamonte Morten Linderud Foxboron James King agentultra James King J Kenneth King Abhishek L Bob Tolbert Bob Tolbert Guillermo Vaya Guillermo Vaya Gergely Nagy Gergely Nagy hy-0.12.1/.travis.yml000066400000000000000000000010531304171765200143310ustar00rootroot00000000000000sudo: false language: python matrix: include: - python: 3.5 env: TOXENV=py35 - python: 3.6-dev env: TOXENV=py36 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: - paultag@gmail.com irc: channels: - "irc.freenode.net#woo-city-commits" - "irc.freenode.net#hy" on_success: change on_failure: change use_notice: false hy-0.12.1/AUTHORS000066400000000000000000000060131304171765200132710ustar00rootroot00000000000000* Paul Tagliamonte * Thomas Mashek * Amrut Joshi * Christopher Allan Webber * Will Kahn-Greene * James King * Julien Danjou * Nicolas Dandrimont * Gergely Nagy * Konrad Hinsen * Vladimir Gorbunov * John Jacobsen * rogererens * Thomas Ballinger * Morten Linderud * Guillermo Vayá * Bob Tolbert * Ralph Möritz * Josh McLaughlin * Berker Peksag * Henrique Carvalho Alves * Joe Hakim Rahme * Kenan Bölükbaşı * Abhishek L * Christopher Browne * Clinton N. Dreisbach * D. Joe * Duncan McGreggor * E. Anders Lannerback * Jack * Johan Euphrosine * Kevin Zita * Matt Fenwick * Sean B. Palmer * Thom Neale * Tuukka Turto * Vasudev Kamath * Yuval Langer * Fatih Kadir Akın * Jack Hooper * Brian McKenna * Halit Alptekin * Richard Parsons * han semaj * Ryan Gonzalez * Brendan Curran-Johnson * Ivan Kozik * Allison Kaptur * Matthew Wampler-Doty * Tianon Gravi * Ian Denhardt * Ruslan Prokopiev * Alexander Artemenko * Ed Singleton * Kevin Yap * Matthías Páll Gissurarson * Nathan Woodrow * Adam Schwalm * Ilia Choly * Shrayas Rajagopal * Shenyang Zhao * Zack M. Davis * Nicolas Pénet * Adrià Garriga Alonso * Antony Woods * Matthew Egan Odendahl * Tim Martin * Johnathon Mlady * Andrew Savchyn * Lev Kravinsky * Luna Lunapiena * Jakub Wilk * Kodi Arfer * Karan Sharma * Sergey Sobko * Philip Xu hy-0.12.1/CONTRIBUTING.rst000066400000000000000000000107321304171765200146650ustar00rootroot00000000000000Contributor Guidelines ====================== Contributions are welcome & greatly appreciated, every little bit 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 making changes directly on the master branch. If you would like to contribute but don't know how to begin, the `good-first-bug`_ label of the `issue tracker`_ is the place to go. (If you're new to Git: `Start Here`_) - Before contributing make sure you check the docs. There are two versions of docs available: + `latest`_, for use with the bleeding-edge GitHub version. + `stable`_, for use with the PyPI version. - 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:: $ make d - Make commits into logical units, so that it is easier to track & navigate later. Before submitting a PR, try squashing the commits into changesets that are easy to come back to later. Also, make sure you don't leave spurious whitespace in the changesets; this avoids creation of whitespace fix commits later. - As far as commit messages go, try to adhere to the following: + Try sticking to the 50 character limit for the first line of Git commit messages. + For more detail/explanations, follow this up with a blank line and continue describing the commit in detail. - Finally, add yourself to the AUTHORS file (as a separate commit): you deserve it :) - 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. - If a core member is sending in a PR, please find 2 core members that doesn't include the PR submitter. The idea here is that one can work with the PR author, and a second acks the entire change set. - For documentation & other trivial changes, we're good to merge after one ACK. We've got low coverage, so it'd be great to keep that barrier low. Contributor Code of Conduct =========================== As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. This Code of Conduct is adapted from the `Contributor Covenant`_, 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/ .. _good-first-bug: http://github.com/hylang/hy/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-bug .. _latest: http://hylang.org/ .. _stable: http://docs.hylang.org/en/stable/ hy-0.12.1/Dockerfile000066400000000000000000000002561304171765200142160ustar00rootroot00000000000000# Base image # # VERSION 0.2 FROM python:3 MAINTAINER Paul R. Tagliamonte ADD . /opt/hylang/hy RUN pip3 install -e /opt/hylang/hy CMD ["hy"] hy-0.12.1/LICENSE000066400000000000000000000020001304171765200132160ustar00rootroot00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. hy-0.12.1/MANIFEST.in000066400000000000000000000000771304171765200137630ustar00rootroot00000000000000include AUTHORS include LICENSE include NEWS include README.md hy-0.12.1/Makefile000066400000000000000000000025541304171765200136670ustar00rootroot00000000000000pip_url=https://bootstrap.pypa.io/get-pip.py python=python pip=pip coveralls=coveralls nose=nosetests all: @echo "No default step. Use setup.py" @echo "" @echo " Other targets:" @echo "" @echo " - docs" @echo " - full" @echo "" @echo " - dev (test & flake)" @echo " - flake" @echo " - test" @echo " - diff" @echo " - tox" @echo " - d" @echo " - r" @echo " - clean" @echo "" docs: $(MAKE) -C docs html upload: r python setup.py sdist upload full: d tox docs venv: ifeq (,$(findstring hy,$(VIRTUAL_ENV))) @echo "You're not in a Hy virtualenv. FOR SHAME" exit 1 else @echo "We're properly in a virtualenv. Going ahead." endif dev: test flake test: venv nosetests -sv tox: venv tox flake: flake8 hy tests --ignore=E121,E123,E126,E226,E24,E704,W503,E305 clear: clear d: clear dev diff: git diff --color | less -r r: d tox diff python: ifeq (Python 2.6,$(findstring Python 2.6,$(shell python -V 2>&1))) $(pip) install unittest2 endif $(pip) install -r requirements-travis.txt $(pip) install coveralls $(pip) install --allow-all-external -e . coveralls: $(coveralls) clean: @find . -name "*.pyc" -exec rm {} \; @find . -name __pycache__ -delete @${RM} -r -f .tox @${RM} -r -f dist @${RM} -r -f *.egg-info @${RM} -r -f docs/_build .PHONY: all docs upload full venv dev test tox flake clear d diff r python coveralls clean hy-0.12.1/NEWS000066400000000000000000000532721304171765200127310ustar00rootroot00000000000000Changes from 0.11.0 This release brings some quite significant changes on the language and as a result very large portions of previously written Hy programs will require changes. At the same time, documentation and error messages were improved, hopefully making the language easier to use. [ Language Changes ] * New syntax for let, with and defclass * defmacro will raise an error on &kwonly, &kwargs and &key arguments * Keyword argument labels to functions are required to be strings * slice replaced with cut to stop overloading the python built-in * removed reduntant throw, catch, progn, defun, lisp-if, lisp-if-not, filterfalse, true, false and nil * global now takes multiple arguments * Nonlocal keyword (Python 3 only) * Set literals (#{1 2 3}) * Keyword-only arguments (Python 3 only) * Setv can assign multiple variables at once * Empty form allowed for setv, del and cond * One-argument division, rationals and comparison operators (=, !=, <, >, <=, >=) * partition form for chunking collection to n-sized tuples * defn-alias and demacro-alias moved into hy.contrib.alias * None is returned instead of the last form in --init-- * for and cond can take a multi-expression body * Hex and octal support for integer literals * Apply now mangles strings and keywords according to Hy mangling rules * Variadic if * defreader can use strings as macro names * as-> macro added * require syntax changed and now supports same features as import * defmulti changed to work with dispatching function * old defmulti renamed to defn * Lazy sequences added to contrib * defmacro! added for once-only evaluation for parameters * comp, constantly, complement and juxt added * keyword arguments allowed in method calls before the object [ Bug Fixes ] * Better error when for doesn't have body * Better error detection with list comprehensions in Python 2.7 * Setting value to callable will raise an error * defclass can have properties / methods with built-in names * Better error messages on invalid macro arguments * Better error messages with hy2py and hyc * Cmdline error to string conversion. * In python 3.3+, generator functions always return a value * &rest can be used after &optional [ Misc. Improvements ] * Version information includes SHA1 of current commit * Improved Python 3.5 support * Allow specification of global table and module name for (eval ...) * General documentation improvements * Contrib.walk: Coerce non-list iterables into list form * Flow macros (case and switch) * ap-pipe and ap-compose macros * #@ reader macro for with-decorator * Type check `eval` parameters * `and` and `or` short-circuit * `and` and `or` accept zero or more arguments * read-str for tokenizing a line * botsbuildbots moved to contrib * Trailing bangs on symbols are mangled * xi forms (anonymous function literals) * if form optimizations in some cases * xor operator * Overhauled macros to allow macros to ref the Compiler * ap-if requires then branch * Parameters for numeric operations (inc, dec, odd?, even?, etc.) aren't type checked * import_file_to_globals added for use in emacs inferior lisp mode * hy.core.reserved added for querying reserved words * hy2py can use standard input instead of a file * alias, curry, flow and meth removed from contrib * contrib.anaphoric moved to hy.extra Changes from 0.10.1 [ Language Changes ] * new keyword-argument call syntax * Function argument destructuring has been added. * Macro expansion inside of class definitions is now supported. * yield-from support for Python 2 * with-decorator can now be applied to classes. * assert now accepts an optional assertion message. * Comparison operators can now be used with map, filter, and reduce. * new last function * new drop-last function * new lisp-if-not/lif-not macro * new symbol? function * butlast can now handle lazy sequences. * Python 3.2 support has been dropped. * Support for the @ matrix-multiplication operator (forthcoming in Python 3.5) has been added. [ Bug Fixes ] * Nested decorators now work correctly. * Importing hy modules under Python >=3.3 has been fixed. * Some bugs involving macro unquoting have been fixed. * Misleading tracebacks when Hy programs raise IOError have been corrected. [ Misc. Improvements ] * attribute completion in REPL * new -m command-line flag for running a module * new -i command-line flag for running a file * improved error messaging for attempted function definitions without argument lists * Macro expansion error messages are no longer truncated. * Error messaging when trying to bind to a non-list non-symbol in a let form has been improved. Changes from 0.10.0 This release took some time (sorry, all my fault) but it's got a bunch of really nice features. We hope you enjoy hacking with Hy as much as we enjoy hacking on Hy. In other news, we're Dockerized as an official library image! $ docker run -it --rm hylang hy 0.10.0 using CPython(default) 3.4.1 on Linux => ((lambda [] (print "Hello, World!"))) Hello, World! - Hy Society [ Language Changes ] * Implement raise :from, Python 3 only. * defmain macro * name & keyword functions added to core * (read) added to core * shadow added to core * New functions interleave interpose zip_longest added to core * nth returns default value when out of bounds * merge-with added * doto macro added * keyword? to find out keywords * setv no longer allows "." in names [Internals ] * Builtins reimplemented in terms of python stdlib * gensyms (defmacro/g!) handles non-string types better [Tools] * Added hy2py to installed scripts [ Misc. Fixes ] * Symbols like true, false, none can't be assigned * Set sys.argv default to [''] like Python does * REPL displays the python version and platform at startup * Dockerfile added for https://registry.hub.docker.com/_/hylang/ [ Contrib changes ] * Fix ap-first and ap-last for failure conditions 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 prettifies 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 separately [ 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: 0.9.12 comes with some massive changes, We finally took the time to implement gensym, as well as a few other bits that help macro writing. Check the changelog for what exactly was added. The biggest feature, Reader Macros, landed later in the cycle, but were big enough to warrant a release on its own. A huge thanks goes to Foxboron for implementing them and a massive hug goes out to olasd for providing ongoing reviews during the development. Welcome to the new Hy contributors, Henrique Carvalho Alves, Kevin Zita and Kenan Bölükbaşı. Thanks for your work so far, folks! Hope y'all enjoy the finest that 2013 has to offer, - Hy Society * Special thanks goes to Willyfrog, Foxboron and theanalyst for writing 0.9.12's NEWS. Thanks, y'all! (PT) [ Language Changes ] * Translate foo? -> is_foo, for better Python interop. (PT) * Reader Macros! * Operators + and * now can work without arguments * Define kwapply as a macro * Added apply as a function * Instant symbol generation with gensym * Allow macros to return None * Add a method for casting into byte string or unicode depending on python version * flatten function added to language * Add a method for casting into byte string or unicode depending on python version * Added type coercing to the right integer for the platform [ Misc. Fixes ] * Added information about core team members * Documentation fixed and extended * Add astor to install_requires to fix hy --spy failing on hy 0.9.11. * Convert stdout and stderr to UTF-8 properly in the run_cmd helper. * Update requirements.txt and setup.py to use rply upstream. * tryhy link added in documentation and README * Command line options documented * Adding support for coverage tests at coveralls.io * Added info about tox, so people can use it prior to a PR * Added the start of hacking rules * Halting Problem removed from example as it was nonfree * Fixed PyPI is now behind a CDN. The --use-mirrors option is deprecated. * Badges for pypi version and downloads. [ Syntax Fixes ] * get allows multiple arguments [ Bug Fixes ] * OSX: Fixes for readline Repl problem which caused HyREPL not allowing 'b' * Fix REPL completions on OSX * Make HyObject.replace more resilient to prevent compiler breakage. [ Contrib changes ] * Anaphoric macros added to contrib * Modified eg/twisted to follow the newer hy syntax * Added (experimental) profile module Changes from Hy 0.9.10 * Many thanks to Guillermo Vayá (Willyfrog) for preparing this release's release notes. Major shout-out. (PT) [ Misc. Fixes ] * Many many many documentation fixes * Change virtualenv name to be `hy' * Rewrite language.hy not to require hy.core.macros * Rewrite the bootstrap macros in hy * Cleanup the hy.macros module * Add comments to the functions and reorder them * Translation of meth from Python to Hy * PY3 should really check for Python >= 3 * Add hy._compat module to unify all Python 2 and 3 compatibility codes. * Import future.print_statement in hy code * Coerce the contents of unquote-splice'd things to a list * Various setup.py enhancements. * PEP8 fixes * Use setuptools.find_packages() * Update PyPI classifiers * Update website URL * Install the argparse module in Python 2.6 and before * Delete the duplicate rply in install_requires. With the PyPI version, tests are failed. * Finally fixed access to hy.core.macros here. have to explicitly require them. [ Language Changes ] * Slightly cleaner version of drop-while, could use yield-from when ready * Added many native core functions * Add zero? predicate to check if an object is zero * Macro if-python2 for compile-time choice between Python 2 and Python 3 code branches * Added new travis make target to skip flake8 on pypy but run it on all others * Add "spy mode" to REPL * Add CL handling to hyc * Add yield from via macro magic. * Add some machinery to avoid importing hy in setup.py * Add a rply-based parser and lexer * Allow quoting lambda list keywords. * Clarified rest / cdr, cleaned up require * Make with return the last expression from its branch * Fix yielding to not suck (#151) * Make assoc accept multiple values, also added an even/odd check for checkargs * Added ability to parse doc strings set in defclass declarations, * Provide bin scripts for both Windows and *nix * Removes setf in favor of setv Changes from Hy 0.9.9 [ Stupid Fixes ] * I forgot to include hy.core.language in the sdist. (PT) Changes from Hy 0.9.8 [ Syntax Fixes ] * Macros are now module-specific, and must be required when used. (KH) * Added a few more string escapes to the compiler (Thomas Ballinger) * Keywords are pseudo-callable again, to get the value out of a dict. (PT) * Empty expression is now the same as an empty vector. (Guillermo Vaya) [ Language Changes ] * HyDicts (quoted dicts or internal HST repr) are now lists that compiled down to dicts by the Compiler later on. (ND) * Macros can be constants as well. (KH) * Add eval-when-compile and eval-and-compile (KH) * Add break and continue to Hy (Morten Linderud) * Core language libraries added. As example, I've included `take` and `drop` in this release. More to come (PT) * Importing a broken module's behavior now matches Python's more closely. (Morten Linderud) [ Misc. Fixes ] * Ensure compiler errors are always "user friendly" (JD) * Hy REPL quitter repr adjusted to match Hy syntax (Morten Linderud) * Windows will no longer break due to missing readline (Ralph Moritz) Changes from Hy 0.9.7 [ Syntax Fixes ] * Quasi-quoting now exists long with quoting. Macros will also not expand things in quotes. * kwapply now works with symbols as well as raw dicts. (ND) * Try / Except will now return properly again. (PT) * Bare-names sprinkled around the AST won't show up anymore (ND) [ Language Changes ] * Added a new (require) form, to import macros for that module (PT) * Native macros exist and work now! (ND) * (fn) and (lambda) have been merged (ND) * New (defclass) builtin for class definitions (JD) * Add unquote-splicing (ND) [ Errata ] * Paul was an idiot and marked the j-related bug as a JD fix, it was actually ND. My bad. Changes from Hy 0.9.6 [ Syntax Fixes ] * UTF-8 encoded hy symbols are now hy_... rather than __hy_..., it's silly to prefex them as such. (PT) * `j' is no longer always interpreted as a complex number; we use it much more as a symbol. (ND) * (decorate-with) has been moved to (with-decorate) (JD) * New (unless) macro (JD) * New (when) macro (JD) * New (take) macro (@eigenhombre) * New (drop) macro (@eigenhombre) * import-from and import-as finally removed. (GN) * Allow bodyless functions (JD) * Allow variable without value in `let' declaration (JD) * new (global) builtin (@eal) * new lambda-list syntax for function defs, for var-arity, kwargs. (JK) [ Language Changes ] * *HUGE* rewrite of the compiler. Massive thanks go to olasd and jd for making this happen. This solves just an insane number of bugs. (ND, PT, JD) * Eval no longer sucks with statements (ND) * New magic binary flags / mis fixes with the hy interpreter (WKG + @eigenhombre) Changes from Hy 0.9.5 [ Syntax Fixes ] * .pyc generation routines now work on Python 3. (Vladimir Gorbunov) * Allow empty (do) forms (JD) * The `else' form is now supported in `try' statements. (JD) * Allow `(raise)', which, like Python, will re-raise the last Exception. (JD) * Strings, bools, symbols are now valid top-level entries. (Konrad Hinsen) * UTF-8 strings will no longer get punycode encoded. (ND) * bare (yield) is now valid. (PT) * (try) now supports the (finally) form. (JD) * Add in the missing operators and AugAssign operators. (JD) * (foreach) now supports the (else) form. (JD) [ Language Changes ] =============== WARNING: WARNING: READ ME: READ ME: =================== From here on out, we will only support "future division" as part of hy. This is actually quite a pain for us, but it's going to be quite an amazing feature. This also normalizes behavior from Py 2 --> Py 3. Thank you so much, Konrad Hinsen. ======================================================================= * (pass) has been removed from the language; it's a wart that comes from a need to create valid Python syntax without breaking the whitespace bits. (JD) * We've moved to a new import style, (import-from) and (import-as) will be removed before 1.0. (GN) * Prototypes for quoted forms (PT) * Prototypes for eval (PT) * Enhance tracebacks from language breakage coming from the compiler (JD) * The REPL no longer bails out if the internals break (Konrad Hinsen) * We now support float and complex numbers. (Konrad Hinsen) * Keywords (such as :foo) are now valid and loved. (GN) Changes from Hy 0.9.4 [ Syntax Fixes ] * `try' now accepts `else': (JD) (try BODY (except [] BODY) (else BODY)) Changes from Hy 0.9.4 [ Syntax Fixes ] * Statements in the `fn' path early will not return anymore. (PT) * Added "not" as the inline "not" operator. It's advised to still use "not-in" or "is-not" rather than nesting. (JD) * `let' macro added (PT) * Added "~" as the "invert" operator. (JD) * `catch' now accepts a new format: (JD) (catch [] BODY) (catch [Exception] BODY) (catch [e Exception] BODY) (catch [e [Exception1 Exception2]] BODY) * With's syntax was fixed to match the rest of the code. It's now: (PT) (with [name context-managed-fn] BODY) (with [context-managed-fn] BODY) [ Language Changes ] * Added `and' and `or' (GN) * Added the tail threading macro (->>) (PT) * UTF encoded symbols are allowed, but mangled. All Hy source is now presumed to be UTF-8. (JD + PT) * Better builtin signature checking (JD) * If hoisting (for things like printing the return of an if statement) have been added. '(print (if true true true))' (PT) [ Documentation ] * Initial documentation added to the source tree. (PT) Changes from Hy 0.9.3 [ Syntax Fixes ] * Nested (do) expressions no longer break Hy (PT) * `progn' is now a valid alias for `do' (PT) * `defun' is now a valid alias for `defn' (PT) * Added two new escapes for \ and " (PT) [ Language Changes ] * Show a traceback when a compile-error bubbles up in the Hy REPL (PT) * `setf' / `setv' added, the behavior of `def` may change in the future. * `print' no longer breaks in Python 3.x (PT) * Added `list-comp' list comprehensions. (PT) * Function hoisting (for things like inline invocation of functions, e.g. '((fn [] (print "hi!")))' has been added. (PT) * `while' form added. (ND) (while [CONDITIONAL] BODY) [ Documentation ] * Initial docs added. (WKG + CW) Changes from Hy 0.9.2 [ General Enhancements ] * hy.__main__ added, `python -m hy' will now allow a hy shim into existing Python scripts. (PT) [ Language Changes ] * `import-as' added to allow for importing modules. (Amrut Joshi) * `slice' added to slice up arrays. (PT) * `with-as' added to allow for context managed bits. (PT) * `%' added to do Modulo. (PT) * Tuples added with the '(, foo bar)' syntax. (PT) * `car' / `first' added. (PT) * `cdr' / `rest' added. (PT) * hy --> .pyc compiler added. (PT) * Completer added for the REPL Readline autocompletion. (PT) * Merge the `meth' macros into hy.contrib. (PT) * Changed __repr__ to match Hy source conventions. (PT) * 2.6 support restored. (PT) Changes from Hy 0.9.1 [ General Enhancements ] * Hy REPL added. (PT) * Doc templates added. (PT) [ Language Changes ] * Add `pass' (PT) * Add `yield' (PT) * Moved `for' to a macro, and move `foreach' to old `for'. (PT) * Add the threading macro (`->'). (PT) * Add "earmufs" in. (tenach) * Add comments in (PT) Changes from Hy 0.9.0 [ Language Changes ] * Add `throw' (PT) * Add `try' (PT) * add `catch' (PT) Changes from Hy 0.8.2 [ Notes ] * Complete rewrite of old-hy. (PT) hy-0.12.1/README.md000066400000000000000000000037571304171765200135140ustar00rootroot00000000000000Hy == [![Build Status](https://img.shields.io/travis/hylang/hy/master.svg)](https://travis-ci.org/hylang/hy) [![Downloads](https://img.shields.io/pypi/dm/hy.svg)](https://pypi.python.org/pypi/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 Lisp and Python should love each other. Let's make it happen. [Try it](http://try-hy.appspot.com/). Hylarious Hacks --------------- * [Django + Lisp](https://github.com/paultag/djlisp/tree/master/djlisp) * [Python `sh` Fun](https://twitter.com/paultag/status/314925996442796032) * [Hy IRC Bot](https://github.com/hylang/hygdrop) * [miniKanren in Hy](https://github.com/algernon/adderall) OK, so, why? ------------ Well. Python is awesome. So awesome, that we have so many tools to alter the language in a *core* way, but we never use them. Why? Well, I wrote Hy to help people realize one thing about Python: It's really awesome. Oh, and lisps are neat. ![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)) Project ------- * Code: https://github.com/hylang/hy * Docs (latest, for use with bleeding-edge github version): http://hylang.org/ * Docs (stable, for use with the PyPI version): http://docs.hylang.org/en/stable/ * Quickstart: http://hylang.org/en/latest/quickstart.html * Bug reports: We have no bugs! Your bugs are your own! (https://github.com/hylang/hy/issues) * License: MIT (Expat) * [Contributor Guidelines & Code of Conduct](https://github.com/hylang/hy/blob/master/CONTRIBUTING.rst) * IRC: Join #hy on [freenode](https://webchat.freenode.net/) hy-0.12.1/bin/000077500000000000000000000000001304171765200127715ustar00rootroot00000000000000hy-0.12.1/bin/py2ast000077500000000000000000000001511304171765200141360ustar00rootroot00000000000000#!/usr/bin/env python import sys import ast print(ast.dump(ast.parse(open(sys.argv[1], 'r').read()))) hy-0.12.1/docs/000077500000000000000000000000001304171765200131515ustar00rootroot00000000000000hy-0.12.1/docs/.gitignore000066400000000000000000000000071304171765200151360ustar00rootroot00000000000000_build hy-0.12.1/docs/Makefile000066400000000000000000000126541304171765200146210ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/hy.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/hy.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/hy" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/hy" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." hy-0.12.1/docs/_static/000077500000000000000000000000001304171765200145775ustar00rootroot00000000000000hy-0.12.1/docs/_static/.keepme000066400000000000000000000000001304171765200160340ustar00rootroot00000000000000hy-0.12.1/docs/_static/CC0_1.0.txt000066400000000000000000000156101304171765200162660ustar00rootroot00000000000000Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. hy-0.12.1/docs/_static/cuddles-transparent-small.png000066400000000000000000001123261304171765200224020ustar00rootroot00000000000000PNG  IHDR@P tEXtSoftwareAdobe ImageReadyqe<hiTXtXML:com.adobe.xmp boIDATx}dUyr&0 i$ +`uQd +]oUD+ H&+ǗW3ӡѕջ;;ְ5fK` kX5aְZkX5a ְ5,Zha kX51}a`|_$eݖU=nyP5 |T49D:"V (^RTN]s9 GyHw]vK m"\U[6 67}/NVs2uzN|}RR!QwZі;osn C5O_ H}mvIG|I|#*G,%Cɾӹsœgwx~ץeC 0gvA`! l>N; gѡe͗ӵzmzC@ϑsϦo?s歨AO8]iR(קdu5>}) &]GABRF3G %FJI`W;G"x, TKZcLӴ< 7&}=f i OiLj;I 3 uʴt/9jGP{?lYc -A˟" LQu*d|F#[#>ۣ (8z1 Okn{avhdmUZQߋM%(tl1(@5]{7һy^sz(ڔOKV5KZ`e`$k8^{&T|9譡L)leӱSv[M@i?gh_ hX!T2XFERϣ[CPe' j;[[9+m۬'2MiYo6vll;'KA$PBj4jQ<Yj@JH}[/T*Xdk,[K5dZ@X'2i%ظ68B4,2Ѭ@zSZRRuJ\`&{ UC "j]A:d璅J>p:iXWaU~M׿.-em@[O'2IeN~iP&d~IW)9$0 NŠz漒22贵 ^+^!k 6ilvFiA4#$*KD+N93J% t;HΨsߝ;A{G?wbXXXg1#+63pߋE-N0FxF}SJ~~aTA? GӸnsY :<(,YRk. Z0th]˨UKeYhal<).I+%P?zo`%NV QS&ɓ08ÒJQnNStfZVěC-Id e"ÉRdMEwB~ iLFZx ؑbΪݻ"b0bgQ}l ~T3 [~e %f)閌ޚսM=xsʃB 5Q@쀼0O3yɁ56mFdl&m Y$ڵ.%)dF; XcUyz@4`[*cD"-^*3\>hGl+a|P'ICLKёmEvf1l?uQen1gmw%3Tu}p~5,ОIͅH)铡ԂB1dk7J/9L;Ǚ:s*7+M$%{NZ8(A ׸"a,mǎޟu8-l$()X {C.,ͦHIIՖ20p-h (-gve֖E(1ʽtuk)4 Ӥ T[[wv*VV.Q5RKWT͑Zc8.#Ѵ+\ _ d܊ &r'ljQ5GAK9WphZ:fW&0іso2@"3l@~3HMHʱhJ6jk1-Y72 I$#tEJv %b!󁳍e0iC<ʥf9ʌ G8Hd2Y;pJL$-::¹}XZA{6C ;?&ki% {p tu3<}7OfXp 32fm'LRjc}Yd.LQjc^bn\x; 8/jLHH-ME$%hQu}T9%' -COBKK7sB [!あNȒ¢ S ^ޫ)T(!Tny6)BIIM˿A*\{+zr,x ;1fzށ@R Up8l% 2F]pV_%dUUA%e훴3Dtn 5rrVP"".dvw8Y;X0%%d fbkI>M'k+XbFQ }0Oe48;.h_2?ꆱؤv+;O}KdmTYW.0$p{œKxxPR:G&i@Э oSO@=x|fRcRS@ifEENJy'")j\Ȝ;zgUUP\i`DEm'Z-#O~q'mF;r%rdPϣ'ԮS l6G u~+:1$%@GPlB3IzElϽ6і =ʺ֘MVǻEɣ%"Apm׋ꦯ#q>_*HA;#IhZVep_uC; I?wM,Q-z8 5ʎ&=K~*[qJ+4ɑ2VAٮ$86~޷,)]H^ʼn5IɄ-FRVU7.3Dp̮d mތr]M1P3jԠ <22D32t?!zqu&"waEx`؆3iX(?P!*ԏ4<9k`΢ZhF"ŒHwSIU' vEc>թ9jgd|){v0B6,a4͠;DjJ*{!1Q h~2%+ `y#-j<{K11$U鵬$шƵb)f S4㭣9 jvKi ~ƛ3}+Q6U3Zmi")*XN{DHZqƳ{mO i'P̾]쟇;s 8KN?h E쏦B)'bxR3P{-nu<7Ѿ=_%%_akvZ@K2iY&'%>\[R`->4ڛ#)B7<dr[An|?y&){%,XȚ5<oeǕԘ&61GGAW gD]OɌz3bEbҁ.LNɟH.7klٍ؉.6a H$Vmm -$rPRz,Q>O$QYR/LK%E:},r6g-j<-ٶTyDS۞rJI/ສ̇Y͜ƅfo`Y& =)9+¡8c Ұ(Wmsrl}Q LMߖQCiE|WEĀ8{cy~U1zg;,\`̹CGGK"ȷOY.@>El> Lr x$)#z!va$)5Vdi{6y_폥'2>OYLi 2LJ7lbvsV6Qm˃h=4YNB1^M=/f%=redȆf%< dR7wƖxnI=*r>r/J22ڼqz#$!6O8)})q .rC S1K TRޞ .?AЎB ?.pg:> #Grg0qaF,Vjs!c)`bI._* B XGFVMon2_j( dZ!I&dG"|sZ6^,,αl_P^|jA%T 5/jp{?vX# (\Ս-bv {YԴ,tPƗ,1m۸:hֹy]W9gK|GU`H 㟘D,R :3H}nɗAsUr(_;߄7hUM[NŸ,u7g-M;@K17hqݨU .v7nCcsݶ<_TR])GQUV7"Yb SI+WFQor9^1oZmA[x^M-'edVl&;-o_m_,ĩ5*&63Vg9+ocRd ( he(ûiAk8jے$MK(Pf$\4ʒ)9+IH]PВJk$dv-k7siCXͽP/*[3( v-OpI&)n0>vM{!'mkǣx$5+e$ Rp\s;q&M0tkIgǰ5@= _2-6mV#Vd߾~ [sM󗰦AТ"b MKQqA+n'.@v\b+:l`񶔬\('A~ &K˲Ƽ,Z5e PZYy"h:'|vEQ[Ԓ)m+ി-mEP!au 0˙h00m;Pt;L3L@cJA;lKd\Eaimη䇅YkH:*06]jCk|[JK! T.|SRMxqipkoMkFN96{)7mBSr EbՔ|Y)/`̃؄b3,{vރ֌SƍCtm8YqEhǿAHSLnͱsژgDyIgMZQ#(8%IR@< S! {Kt!hZ 0m6X]*cb-RkԺb6e>Ű ZYiHR`BMYc4ﶋQT=khYPϯ A3՟JJҊv}6 -kZ`4L ic@z|[4EӖ>37hchL L]93u( AXRn,5j< 1)hԋі}w>!dX-MRX PHaEz$%=Tݰ@;9$n4%x i&\1 ]xZPь &,j$;5eGͳʜV7SnfWAM%?I>Rח&fJsUt90laSq\o'zԢAȘLɪbK{0MBZZ~ylϢyrL4In:m T/ZӚ#zlJY+*j J|".fp[5ڼAA\IY3vd{P=HeR@;@knm 8b}iY.TAhZy^$AFF)kGa@!1@Qעvcj,ʪٽ]Q_'s{MC-/k%3zfYbU/.?ORcQMfe=r`p0by4rnsҟE)U/Md"p>P{JF7 PXas(55&K,ˡh> s?^'oH~A* HnAt签>{ 8_?oEr8) \#dnV|в8V? K1pEXt #-}h>S^%[M綖P6s`Թ~-^ e2g@Keel".Z_b]'ڵDxޢs۞5XwƅTE3rBfQz/2y.HZh_5mۊJ_6yگX7POI5!Y {LQTq|?~f[JAs֖Je,a{rdJe`_t0/,^P< pdqK=Ji"+*%wsўpvۓ^m#Λ E=(wµiY,Cs lW"ETsTPt5ƹhcTE]S (4"&%HkVylMΟE4q'6ᵲ=w,'A*?+ACP`si"aYJC:b 0&c!ȶ*x4UY̅=Q>v5xMUnmK(Ĺ;)QtExF~5Jʵg|hڳVҬz|?:57@  Š8y^T33 ,]y>lXBI5Xb~AEVDG~i [|tlnLzL{:>*hcgFV A5*|4CHY0)[C1HdX`AE~fJ)NNA CU;n5s_$tTTLNu8=WŸ~s+wXR&BI=Wo  $y'Ȓ*ԴFL%?}{1Jlrm^.2nu3(!ZOvv#ЂSi:qEQAC/}\9Ens?u6q <ɋ\QcدN|?lgPUYwqg? k׮~m_h[Hw?_|巆;ᮻ:pNihu :PÒ=VOeIHQp<249f֖NPiA$bn .-xz\BR'- ēn `DךiJFFSdcW{ض8 _߀/}Kp;_xsx<ڶҶy Cد;,m?½ sرjkkx4 c%ЂVUmVR yJF]|iX;/택{C2fN'ZjMӍc3Lh&\NL(aV@XZ8Ex7߃ Oo3^|i'YJ .e\`_|1|[:]m¾HxI!i(vC-Ƕt,`N"[x^} z~?FRO=cb9m]N o 5h*gQd xV8ƔGrvfYvAט ?]}Hw+xl! <=FЎwiDѤ6N r6y=N'0;XėwԬ)-IJvT ) O ͉ME  2 ڇ 7t#\z饣~Q3{ \k=pGvC,d%Xd Ӭgvbg<~}/.XbKDǢNԪ:l?r#Y\^&ݽA`J74=Saf=ZCD3.r#gK\MŝeD.GH"~m_qŕc~sl= 'V1/H'b&m6d=5^5qL: ͆1Pȑ?N`l$Q}яڵDN*>YBYy/N /ݎUDғMd&o/CԠ#Ҿ~ߌwIFfyj򝁡,lAn+>vtjrceIam⒉E,Ph2)Q e[:oj)gdh4.r04KAԌ#g'% ~F;i9JI 1dB~WVdy|;?sGvApy) KΤAv{1x衇F MSW`>QI*G8efTZRgo 1-0QbӃb Ǟx o;|Gnmikd@ve)f1cT<0wTwa]`ZlNYSyvB㮽'X}45m,3%b͠ %  > :wS\GOA2v:w,_m飯 _ℿctn̷Ny684nvsO聧(`4,fk&-3_9h១Q9xk99}PtP ri YdLٮE5uڋ؎@kRqyV<+b>[#~>yb::g*(4&\a wY_Wc"ɯilЙ-ОC39)2kPviEϰku];d W4#6{{ijZL.{X9l ں)%gdO8KݢEc]£EB"g mR$k 8]NGIʟ5qlA4&wNTahOkB~T)bmh%cWuMmI`uEm׾p ciMey^p!/n Y6C[x~4|rN;./r a&Ү4δ{oF#Ipۿ\鱟/ >Q(QFH{ E}ϪnѵRɞYagĢmJs" Qkt)KղH7EaA-eU^oY$(B(г  Y0G3$/5CU^mN_Ts}iFIBzZBC_`hD8 X6+xJرFMxGhP)iLF*+CxGqC۵2FzlEMMyU돛ԭ[N}[ A3[H֘'v_=έ;i-8<,2ʪiY6KՍ!^h m8I[?Ĥ_I2 n .VXbH'bNΤX o\r#@7΋MW5BӚ `+`- У!3"$}ͺ[Xϳ0avf3`# hzbͲ ^OGҺWaX֎H#AEm.Ͱxzhp R/3R>m~8x>p$L%Ow^6%W8^6d-`?{T@UIBjɎeyKe߻|/wEӬ0(eQ:fAk< /ݼǻOPvK8;SK'*L|!Yg g ?3 4 v[gBaeRI;W{8s݂L 6SL: Kՙc*D> dFl\u^aiCxزm$~EdUP8H<}P0Xm qf<3\xt:DTY#ϳTϊFTDשhZ*eQ:3/&ҳؑn!彟EMkX-b+QPyt TtB^JW-ۥev6IQ2-W.O껻ŒUNmCE)Ē?&”nL2&v[Fc8~uš`Ұbwگ ЎdӒ{W75MᏋ*録H[WZrf@&*!im#]n?؜NֳrC"m57mU(MLY+H "\iͫC,IVH-k>I& ncڲxXc*.- L{ :ZBMRT72 #MI lwE)d孀փpէU/dNokO~k9 Uq`-Ў?Mi^f~isYQVj_ *j` Ýc.[חPpٜcJvL B:co.z3:iF%/=nS'`8LҶiIa'ݫ`-ОI j?$osw*.Sm}( 5 EԒ }U^BA:t%ö{ =%KԹ(ijlAZW׉T9(J-DpF)I^T_U0µB(dMᢞ-[Ғ52t+#,qpZKU\Kdآ ^^Q-PuźO"+Bhߒvn?ۼ/zӶa7# mTFqn{{p2<.;ƹT(+"?id]@EQ ~)SSAD95c5κyYo@[ ,_\  @ƅ@@] hSv @6hܹuwbe*JZn<.o`='#];L0TW:ycgfԑ} (eTX/?ŋf1hG@*B)lGJSs_!ԸmV/٬oHIY4,EN,nYzPp?6pTQ?wi5hj=A:趬$Բ=?mׁF!4(r =hkOh ?J4*pn+Rsq_Ka pY? c`UN{VL m/SW"Es96\| k Aˁm׳8鉜Zx{>:Kq(~#Of{uwMm]f~pմ#o #{Ww}s{ߵlW4gh?3i\m>Q&ô/ _[ ˳ icq=˞|ؑ`^ݪR;mbiRoUC{og X{Nf2:4/P[/c2ΧXhSg":>}p .o;z~w5Í,Жu@I myͧ׹"xP:/7 i _ Wv@GpNg~3Bڛ?-fjoPaJGl+@[^E]/m}?m=NR2LL/j[ ɢ(Nk 4 0{OUl)(> PYUas/i4_r}aλYV6^yq)'veÆft^n=`g϶wEXz3+e:ZpɓL!{u2In&sS|Vp)cXuzmWs FѢ8aoz;NP?<~J H%leٚ"%Ӳsk6]v٣m7B|m`4C[r#JLAtt M}]v۬CmeB僟gt-.sOۑ3Ka̽L5mj4ˀkāP4zב/(է`~Nj[[]_⾶rԝuUl5!\ (/wphv`@MK|߼%3 ƬAQlwߵbQ+97 JӐ؃4fJ%Ko{u~q\LyS1TœRcm:&)ّ j37* [s>':5y3 sjZi탟c{;LY-*V.@G! %VM!YlympӢ9lKP9%.LZ1&ȉ R5"鬃80Cl/ JƵ|uCU~7"SDSZ1-..C-=Ne(ZQ5sCumH7TYj áhb_wp#Ycn "pt8s&|u& ٶIPvFd2m޲VEL}!પ iNX:;8:pz뫫]_Ŕ7hS%U?I\LkME E'R|T^^YnJZ:/ Eӓ]jEZ3ZtŊpѥa7՚c,[W-COuעٹo%m(%㍝}ዉzX-Nt sˤ]!KӲ k;SdEC, K)5& IĿ/}D߲\aԢt-xΤel]v5'Q)Ҳlv}c Š@0"Uӷ^Rw1tզ{<veC**@<EV^)hWMk%SdfmNBZ\_4dNx#뻢f_*b+ABkQF&NGBWg/th?كcMwVRWt27I\m+ҫf sdXq:i[_.4Dc Aia.[.|~5j>btd^TMz5I@H^sfȬ1Kf^vmS0z=^s߸ߒ("ю '7h>Q]\rc AK>Z"5h|c`%ϙit1}K0ZT]P{֯_ ]xlal4 Bj첬1:ȆeL#K(aCZv?v {0P|_|FMw+9|ZZ:4 ˷xUgLl<ӌOR)=C<5H?Ĝ+At׽|QP+D)`|MJR /qxAY 0iO4Γ nq?lb l` ~ٝkoڣ6}©*y?et7ow94:>-k`ɲNeƥn]KڇkF!tſ:eO"p$U ~>4׼A9[>.z}n;K~r 'ܼe͢g{cLrfdu5as׍>Oy&88ZhfI# /.tr2)s$g[AdYԴO-\!k|PhTiQ/b4X JcC l8<`a&3fߞcL"@EjouՍ .n&o7h_{yS:DQI\-29M>%PP1Iͫ?{q DIԌ۶韣@s[!E î^K4+,=l”˅n rSGoFCY;jYY~ݏk8Oejº hZPڕ~s@!BmiY2ˉ" _dk{>F m {~yKi/+IUK*Ab2~vū^9xg_xypL /RIiLy. PM,IC=&sNa,j2uK8nB2Qp,mz?:h6/j >'lZP}q}Ş֮ [D31r]#;kԅށ ~(~`$]f47=7X ҟAm؛f%Ӯbh,Z| QP!Ko\1fZ%%WЩL6vӖcLx B=& !Lh)n7Ge {ޱ(fz=хuWYPuUk/:<EYH\$65 hPPj7\'^:me)'WPB5AAkK q4(i9ڲue'DmTz3rV/zTԼf3Bk@;]eE?k|?[2X#!هW{xϷkr  վ[;Ut,"(e&?2h*H1HÊE5+x#|FV5X6Y>GSP'ksn|{PP ohK(%ʇ4AY%;~ɖ.[LvX#'mE L078PBǘ*Nӈeu~\X\Su':_@R_?Nv ݄i%mQDy$ɮCJhݨL"#@'U ?XWHo+ޥ QDb4] Cht|#mYX @m}* eBMwJԢ;T&ȕԓi4VݷC=52*>!M>Eu\N{ Fp:BK>}片(&D{9{RRΡ7^ʷCfy ;}o_0bz˲v&;Q~)Q%;P--BɌ\E?ZhCj!5m3"':A/ۀi.(4U;xIH$ɤ3(37?u)m:t\a]D4\m{OD5VbH_!cؑ6K/ۜ@M93'zD RW[*/+FOR']U'+??{,YO%wEjJKTK>yq0o^JTYrBzƅP,̀FO?z< IϿ1]؅ M˨4D!]HA-+IVi#bI7j}{9d4Z|]uʗlǴA`ӼDx^n|#t/cs&;Ow߆S 7Xp7F";f_'ZJ{*; HD’;Xpr@}aݨ[)y=`cJl:> J Z{g0F ̮b4A'K>Vs~q9fPDTGoh2\ Ț' X6Ӊ"C QW* 3 Dsm  qh BAlZ}b F/%QjD%Z5T ':(3K.^:y ܉@GBj?OfxȏQvFXgTqHCMN@9QD (ڎG;럞|/.Ytm}MS#>-4˱g0ȁ7Ƣ h=o[[.\>*[h+icOAK)h$׀ҷ}$I'/( mjbRۍUk G0 _3$S-͌Bm[e,0pVhS/?*c+^:] = Dc+XȬ|ZPyƦ9hhfZp%ug]Z]n'v8 )e-t 3i;LK@; i`h2m)ıxEmtt}ι,Kֵ-]/95tus{?L՟[.[.^;8׉Ypp໢tT}yH/+,zZz^!);bL/GF= KHP55/F z Z|x 3YąjvTkx+VYqWh?Lp?ur _e)V9N7ju5GQE,JYxxM5GV)wh9@Jauį@[LGt߿to m[!zbsI_pPC?T]" 6ACɺq ]P6q2ѥ5Bĵ#+=dm%b<7[xuN|GbXl g,>Gf&'kko>K Vv50\ =u 5YY\wM(,#,mIps5 16nI†%QG'|(iv3M_8ަkZFiR"<:7ܻZȪ=38#xJQKl;oV2uRxϩTcrv7oKŏVc0ZI>@Fxsp'ә|=${ZZ3?OG8榁rkgͦ=iY|y9OϷ6ɋJߣ/0 vdpl1>V]'Rn@85qѮkuh3ѩKNőqB:ዅ[,P_QߗX DVdGpH3 '8L$"V9E׺e|c9S諏L"1TË逿+9~Z 1E-i?CK+_({e>(to2٥#SM.˻ȯxb_2 ԂBKhk4˧/VAR]md\{,̘]IѐB<ŷX*a" ZˀFeY虪ז$I+G m$I]6ӫXjuD224p@yըDޠA8]R=>͊+$Dnm+n`hCGߥ ` ;@ XEP:w> Wm2A |nhә^4XEv5`& uY\ʹI]O4j(jX<:A{\ոiEu>DpoN.,?U#Fbh*GKɐo:(ѨzEfInnfa&{޿1;=Zb4h'__6ӕbwsWfq-1=fmHhl6qZMCyqi~{5;KBQ8Tm.Fpjub6I6b35U8t:rC5ꥱdiK%KfG:TʭCJ޽.:сRPI<[eV m)5],m->,^]oŌZ8pNщb`pL&R<d_Ie ZCX&tv;ys3Ii,Y|UTʒ;2hGli W墨x;0k|ągnhduB_-EdN:ë(e%eЂ4̐kMV,ʋx{FraÇ/玥Y6]ssx8>y(H=?ߥ39Ƚ6Q gjM1BO&М\j$Y3Qyfo$w +UiWbg|HZoB-,,MdEa!vXHnLqZR{|_8,xdbPw^N2ᜫ^p0 qlPx\ul X&qy9ehJꩵ3!lf%إ+MR˙duIhϮdh.m{dwF߽t %ݝ |@>j2lm|: oOnN] j(B124% ڢ{ྶ?s͓KxӠ(ͭy}Sz=D 6"d-;[EJ` A*i8Dv2^~,'Te@%3rbbaZ@M5DK61>E}]Pj uf<~#뼣w?NU2eSYvUqvjCB̸#|p0VSw!DX[ ?G,/_äF;txgzD,`wc.*ojP*f;c 'qVo}'AHCcV-\e Mxu6_ [ih ~ghZ\Ú+Qa$7i#єQ%Y䉆OV^B =G}o IwwҪxWFxy}vQa {q\t&?vaxb5h|NdJ:2/opu=5.636/% v6M&p7 ȗ'c RW̨BMrllˆ教N&n坲 (6-GR' "?FCиvr|>qniR&V+إPX9?Kg u{uvxJ5Q;3spVK7ᶋn?gRWp>ņ E`B7T"U=&fޱjjgk_LD'Xc8M$+ !2\s( f^el^!f 篌͐g*;)`vv4|X[pGD)<]dɤn įZZ0‰#2Y&iK8P2˜)LC=,ެ *0" j\^ul-^nV'|N yV|U>~ csw2{piїN%89 ( :!VЮUgu&7Ol0D}c-+?~]E'Uj5Oydf*r-5dTq U[yd%"FtzS㴼ﳹr|-i;ȧ-a nxZTH̥JG1h-,iW{Dmh"噟SN۠Յ{{Jv1Kzn1(d{JG]8mkt\47/N}TNV ȟ)zz[#g[ťq-1uYi. !{Tjj.LUrq o$E̴ :lfi3/o5KyLǿwՉ=M,/r=v,:[jiCid I ŻtpD~82~U[!1Ao%%RM[Uj+ 2Sgs@e7 {pCXE^ƙZmO'SpbW$勍dP8AFWEˠF.ImrK#4hڴ?G8 &1٨eXs/Ȏ#XZ.TjQ+$3#BnoM{8B,)*|f E8#DڮZG![ K0ϳK\ t` ˥+[diTL~O܀{.M}(4D=jON=J@9xd_[Rb~3]ǢѠKmmwϟDNC$ eꋥ*f26z׀nKd:ƞ[$P>il c \?qXf.U+K 8fy@P$8ŭD]Jr-HEr1³$']&[S.]y,w}6D]I&Zl. vN54uxrctSX1{£Uk e@IQ"Ż2Юm6!XgRz^gDrG 7hFn2hzr{m=Y m}N~Er6JR2OrlÓ?]TPT\MWu^7Oseoϛk} Z\RF_ZzUOj2$[5N C @ ݤ' ܐϮFK$=nxA AΎ AS4ONJjV%ҞolA1k[̆L# nh2m b4Hb !ڱ>Wj 5L'/aqvX`#hA_]Qf/R}hKIrw|J] ͞^<t7Գ%^l$b4hFb2Hf>0~k:/&D'?;1\U1,-A%TRj'/i 8LGv*6t=g<ƢZƶ|=9?GT;ܨ+%eg]{ 1`Evv~_;#Sƺ{D<0v;']\Bf.gZaG'8ð^*Yntx*3~ژI{+64Lfq9ˬ'A~qy ֺV%DieJv2Hd 54 OS[ MOwe Mِ75 znӪ.})yc/simfH7Hcώvt9Gl$jt s25+H=AZ<bرiaDOWn3]J ǠQ-%L%q{2x9Z!/baK--X=*ٵDwi{wcᬲz#zK[pXtvŃGIT0?s_\8{y9+?,Z;ڪxڿ"9PopbXZ}KēVUAY7%P h~!}cO8Jᴋ풒 'Cv sI٭UFsIĉ}z"dk>q8@!qF?GS㳡\g猟Bg#Ѫ=Ki7/둝O8r+n8,jKCxj7CWaih*Pe%(ML ad6a#a$+J~1=5Ϗr/}jptAxoJ[$90:s*g=OfBo0WYwh7;YQئSCjh"mBW˩XVdP$їOYfJnֺuEŜd۷aeqP@BՃL0<nwe<8㾵۽@Cȁ:B{z+Ei&pAѼowelA+ D̡ 71L#G7>a?,.b[ ,q嶋X]@,s$s3>,u \%%=_w% fA L\{}/OZb僄Yt\)aocVj:dYDs?|/OH(,n^h jNFtjz"IŻQ0_"s{w3a[oh'χD`aAF'L n;T~V=;ZI M:fKUrXd]FYyŕU@[Z$EGSw>cDxS (DSrkSl^iWCnt!@@ҿyYj7HO̮c6KN48jܖ_wpqK:n72t$9̬Vvd*\(i<L=a:h^&<6N-S-[]d!Fwɝlt?X}b_[թY'9V$ H`Y7:$јW aɮxF\_P+ jJm1bPZ1od1$ 4ۥ_)䡞h( Rm=e,Xbjqw<+y =FVTIb]Z8ij?ɺ^RYӷ$fYA]/XXF c ֻH6dd]q|-HxmuSV! CU]Nwaqo$2!S[z2=GV#g7zJ~#@/FKm,ϓ{~}ow%XZees, #J՚&bc$`M_\0*$XZ'1KӛƋo~2ٓl;Z*U@ f¢4n-oU;0 bwS:P ^*kU!&VѐdB1ۅyb!w-ݝ F>GY h$ `àUU(JP0a>50yCIo\((XUuRh0szmy6VqކMV/_[~I!C+*1ēd#s pla1t H4ɖJ&'Թ]sup-nGD+J,Jo~ˮB(:-l,KjN֓D_K^Z-4KE)-M +1X ։ jv[-mVl|5/AwxUòqo2cRC>s!?:Ӂ04e@Y h>&#kD.dZ%zClzqaZ֪¦gqHC1?ϟb,c\ htIM5ݪYց'fAPvR#?貛z?< rz2X (:;z:&q ,[@{AY֫  j72Bb:Ve"8S"E-ekʮr>/!>xۃc*K;$MksBq[(cCpx}f:i $0~.g.p1s)(S@{& %5n61^:7K<ls6j [[ %U`~&i  Œ*Q#Xb$%R6X.i5 ?UI,\0_~j1bUxK<7`aqHeˏAY h+c˛% GѴme <֩Py3rCɩ1+Zu\UcOg"1( yrnQC$BhJN{E\͙'Ep%pb6\0 1I?>:8Le'RD*(a5MnȊ9p@uQnE,Vk [D2#mEXZO \J( lprblO!,7>أ~Z34fL$qb. e)&ك{jTjV5A9$ُp&½1Juu5gG/@0Ngz}HlӤ-r3sQvB(4U-lowG%l>z˃ؔVUĠU}Sh h]-5w1؅\6/ZZkC,/Exb*dUm63TZni"+ƒ勣6}$ՍEAR@ҁkY,V"% zx/<|e 2jx7.,)c <IDATx pu{z_@cH AD)Z(KB&ۑ26WVt^Lj"H`츱2{CUQƤ$%Bר~uS+m$m`DT7fO0G"9.YT)OHU*rpG4 " døգDZURHT@ˢR*#joШ-u:e Ȃg,fQS8 aF$kץרlz4D,Ҭ5\dKn.[i`v g.IaMNaJS*`ײNrh %W.x]aNt EDܻv6aT@eo7ZD n${G1$@dA Z,Xa-J)Q;4! y{v82M;MX&fŤ0Ȃj`1.{܁H[2 .`u DT(|޺ @&kᅶwp=}0@dApyϖk4VǤGs~4`RɏlJ5k0hZL˨ DȐwv_4q9)H0@H|F#S$"} qUT֨HӒAKZjijRIA @N,m!WDSsfs_ZZ͍u!rj*ߤSOE-ȂXpԴb&D4dۄb~8mjj{N- lvwٚ J8|",HaCS "j3*ow78=1qWl&dƢ1r4?ge($ңժ:;^BTn4ivƭͬw\E%8bs\i~~YdÄÍ'h.dnܜMuQ"[pզ%Ot7vfE,LkkvޠB<};iV/oM؎~*{8A`,47gu1} ^]*ne(b٪9vhV^VgMaѕz9T"[\u[݁+Urb"ubB~0joo>вUk6hzW lڭpZNѫn{wn?rZH9z* [+ӂ[ύҢ)>ᒌlr=d9 -Oöù>"[-jnh W:F&QX7e .}=X>&CF^?"+cu82rL[KK5'"Ay :vwRWWy#Y2D;qʆ7ƭ'H/ lR9|WhԴgO7u1' Z ̕bgkb]-UX.&@yxط:%-O<4<+ '<'^W{^N2X["jow7uwTjqxV-Ȃ;lH4nN@\^Zӭs*]ǻwwUmj@dpQ y EbrU]EIP2ͶA[2TWk -[jl_FsWw /'q]8Yi||n]>PYp -Tut4WrFtn`ltq7f-YE΅B QqPVQ8E,D-G)9%hzz& 5L]I-  Il 1l aW /7U\d ,A`kܚe;[MM-lVQ"[p;p\.)9[Y|--t,6g+X`%xU]sJb)?,DJx}l/풣Iצ xfֶF+YF>'ek @d+3Zò lZkmѲLH)jݻIoVrO{DWlCt,6U1˾g Nvu|*Z!u:3%"+sOڎ:Ayk#Xl+lOOSMBˁQ-&è c1;'+z]`Ε(_+76eW\~U\Mգ+b~80 "+ϫuk\Nak6_ FImJϡMkv7Ȗ Vn9罖3\8F sq:Ķ^}kDD3| H}u*Ǩq+ZOE^2 6bt2H&&-tFl{ + )z4ҍb,S9,%705 v="ҊWX41/\6a9+=d1{ )v&S^_L .TZbo{pDvѕuWr>:@' {Gn7 c:n9*f?'PQ  *1C@dKswTU`E]b:J7SS F:Ҽb"["򊅊Y* ΝP՜?[I^1ksXe NKDN9Z1L"[ciAZ,uAo#KT ʹf,$\IJ0SD3P " ˆh%?,kORVMsVYR!K]el.AU)mpxk.sȖZe")T7;9auFdeٲQL+'8azzQ_Պ) bձW @d@GK5k_v 71nx~[4?\IzD/Ś`'b#lAplE/^1\Q݂}5kҫ*{8# _ *|aܷN*M in֊vb+>[ U t gU|~ 칙Ңb V,fozr-Q:.J+GvW b/fM %+Aݦ,q/f_j"#wt7ZK:>V,Du[<^71ɁFK_V~*b10pd%(2(Y>Yn<.zj6Zypo:bm.q xR(^.v*bUEGfB<';]<.)`Î^=BjogȨUc$|l87n= Fz !33Kun ::p̍&!e{Fv讖˸"fv,N$6 5ܭgjzP9gj{NC`D.( 䨨|@7y_\t"~߾Q.@dK ('x!Y p:ɚ="[\+֣]i7)4 V18x=~㼌Y"в5^,2eo,YdQ|AP yYpҋDXHtVl*G,H 8@z8|qN|J&a/{0"[.ce2 ,8nDPgR,|IlқD,BGi Wq"}Gfu( |--9m Joͦf/XVVl67;9P:cͧ@:uZa-XX87SĢ1ј=oK964W BX^x~LQ [ak[a7Q(rz)B'{O w\a͑W.X&^( |qq".2f 4;'y5!x*p9S>t m$ffjlޞzS=˻ ̢h^T:v?ޯQ٭y}l餋'wrT#@p/!@dװ ETenhX\X&W8 7bmP";2운ynF܇bcQ 'U{+18Y}sz,9",7OY/ҦcA]o֒8/k N T<.0C!4`iN&2t|)I`$vF FTȾ;c\:{ݮJ@Rs܄^ڋ {,N7ow9>Ȗrzs-* $L(UfK΢ll^w܁H?ٛ+ƒ6}$ gsClUbšmj/5Hi)Wj4*d9~jdp&UMQ+w|b(@\YkQV6U^5*Y'^sMF\X9&%SP "Ygo Y9zܢ4FÉ +O) ,'Z 9+T7`'s4.išM͛aie+%˹ UpbˍeqW'*qHxaYaȞx(Mz;bxsc=~ˆD"l6ȉ#ͤ*6OY'l^ 7Ecq#).Ql ’TfPWבVbƭ~+>^p(rjA-YyK~-zzNʝjwl0X*_ХbժM>ڳ>ȖŹ?[V!]d<T&|s=c6.YRE#֗/<:\!lIْ!Rt<3T8lV4֊N/:ڱW "[T'rF9ݘ,l*p%?yK68^<\%lѰ[exQ0q|lV"(m+RyDv+;[.nLV,z+6يseʩV NzD65h\L LD57 [gV^E,D67\Q"ECSj.|쫇@L0o%vajZq;*; eP$Z 8=g͆*侯 (Fc11Xdc1DPKpq2?\lhpu7ϨZv C>@dflbzFڭ}\ *% 3-s{ۇ6{#[4ΪUOClY`cYGs=W:QEӗfv_X(}=\VpJF'K\Fv gv6q鰱ygtbOQRٸ.UJIwANْqGw#W8yʜ&m4(*+;!!D]rq gՍ|nz ChbE&C\`^.iLl93Aɪ-r4,`CZ[QqF;Q4Gzkz r~sĘ=k6gWadEVbvJTt)Ⱥ07%D@QE6+XbxDtBX8'7[gXa5[wPs"}Zd(z4H @  -  ;/Bdke d-Z:Yܛ \BB'pSdo,́pՅGXJ\y@Rdn  a<(bOY$T*e[l^\u#1sq_glAaƱW d%hV%;W(%{0@6jp4^GBdEV*wrCde8\Q(YdUH",{0ٲx40fhոKl4nf/F"[6Ɩڱ- ˾xV*|7Qp-`k)=ْ0ajeڽ Q)l"[tҟŮJR#VSR{؋w7V)+ A'Y`/{0٢ :픠Fq:\}%/-f}8 W45g0:.a@9KۛTd/ZCXkh2,LYjvS*řl9`o:@d .zlwZ>Ppd|B^=-pK67Fw0|cD \Z>'dQ@dYʺf{p% -tAJPor ّygWgo*E>2`{pE b:*'+vUduzPh4dlʰPpceEb+p+>+ltbo{pe 9qiޟH`cPC ѨQp F8lX3JXOxL?PC ZYa{p YqcmN_ɕӒRFg3©{j,I'"J%a>~fD֨Z? #J" ڀWzd{q ((&8~1D6≭;휖EN,evF{/ (VuuQP"kDV&AO̚ Y9ziζT;\X.AOz"RᯔA FP͋r%P"Q)bg3ʊuy?Xm BV*efq8??ɱ 0[ A* (z١J>5p. @"4zbyD6{#Ҏ,2uT):ɒS{TJ  vB4v%ވfT!luJ^@͌٨ qg2D#w@ubA+7?Ad@WE25Aȗ:E;n\clɭ7 hh,ՆN/P b_ qsz$HV9QB'XW ":\u:uL~Ң,Ue :=UHd f;T zP 3 YfCeDJ2\Sw4y{^?\-lܻV$G/FO,Fzwѡ>@;Y 2}ν4ܺJaɊ]5x+͡hPN_T9\?KMM" gv_P,xw%'LHB?]:]8od,h4Ė񓟦|/zjÂ{ksg8WPVo:?|@rr>OMdUIOYLlz4 _(U(6ϵ|]<&} 榮ӛ/>K3W)PBTS}-(Jv /h,ŇSlLf/pt?F{vSfb_TS.\7lXt4ϖ|Xa0ݾX˱\Ohqn@ƻ-jhl+gn^aƯiys.f:iL&c<=*V]-1S`M-y6o([DBSJKKv6MX/O}njҎ] JjoHYGXOJL F:pO.CQpvO[}3T ^L W2[pEWiGQ`u?>zjll^H6|>_Zawܾ6%XE_~M󸧧iddN'E"y. =9ukZ\Ť|тY*JdגbZ>(u;W(EN)gX/>Jkk+}S;wV zg啅jb7~}~#֠s(>w9(m8v-*:D| 500@?詧k׮M<|Q21O455Mx)UPDrl `vMR LuÃŲlyl6]i=!鮻'O +`Ղf0;}Ξ=Kݎ食ԹcYPTX gF?G[7Yt9F^Mŵ;?H/|wZ()9MuQX  |ʕFeO[Y7OpwAx`r} _$ څtq`xoң>*וR o>z796X݀Mz3uL -7Ҽ/'G ,~19d2ё#G1ŋJ:e_yZfI\[aɲ:90^Ŭ\ ]7Do =f[[W4KϊX~˿K:~xT/Rly9m,(;>ro]^bo}[|dˈ^>9g?+6)==Ҝ-I:R Z2dԎ@׏jAaP"<~B;c%sz@>pGbgE{ҟٟѱcDztBhGo}n6|>OK'?I!ș67hTQWz~ zը B7qptNsXl/| 2M(mڔ/sy,(8-o~ƦE?f8j׮]i=߾sqGs9B ,o; [`Ќ) lͲєNYZX\]xExqF;.z?x,( ")/. _hӏCz~D,MlaOwbkP˛u\|Mݽ-Uf<9g6[صy5 wmGdrN8f6(&D7-sb939ot_g}6+ș ,ЩB>9g!k 2sfƯ֎;DS؊tRZK"_(kLsNFy/--eYdLYȚ6)qɊe/:fA>7JB$l6 /N_ Vdٽ%q\ڑ#@n^^9" V%NZd^#֙2֊l!`"w4MK7^ֹ~+4vMݸ{"B8 Rp2՚]_q/peP*SwMn6W, c.ݬcr݌1pz3ތ W@ds@Vڲ T Btf9>#傓{-ևWX ۀ )|ݿ"?cGk7Kd_Kk*C(Ι=S^@d.{Ohlo.U=@DLJ:?uc\K$l*`<3<) w&8U^/jEdm.8!x̮b- 3A"âMX"YgZ v9u'GO? (cVHƜY?(ݣo5^"#[MqEOLk˛BܸG sqT N(G;Œ!M6\^L#l~;y^^z-?c+isS,hwi:lч9PXLWNBzXE] $7Vm[hrzM~=HeI(=kDzwO$jǂHRc}vyEUv#/HnP #{fҵF*BO*hHxJnrW˛q`2yšW*?#!e|IkS*VX(U,vGo_z%(\Զ0Cƥ튇k3. Y$ن )hk9#d '`:[ + לu. Pdá@H~4`%lRbJ e C'\WF1DŽ+ф#Y#QtFeRhoPQhY5u De-l J\]k~L*I6w O])ir {;z&N.l4*ٜz*Yqɒ fV~! lR\ˤɪ)30ձO*ۅ y2i9jpm. eѕn|>J(eFD+ ?D&; A,9"]kNA9sBh&t-و&m|6jF9.uͮXN=cD@7A3F9lP-bamډY`E0dY^K-<7iPDvzAgclw Ңd*A/F;ԀYF7Co#-}sd2Bw)[a/49"7kVVZ˕w-=e?eW;y#Z;{3>أ-b&ޠd("[(nn1/(rpsA sRw 77UZzBH"~Ө(|DotZ2O(n*l9u?1iݗ6:\F:tޘb0Qh;uвp7]2[䧖e,殁%bPQLYI+o/ eMlEG+I XK߾1{vy5}:+vA\Dvb&f' ͍_p((R2&jr=)$n_W"e_2}ƒ E=e^}c ud"bk'O~x`g DϽSK$hfGhZZq. K7& n"'JCzLfj)v; ވ@HkI(P/*@qBBOTc|ɨۿՏg/]fD ,_|.9j V++~ c:cws"//M| cT(6.z%97ȃ6.\pciv]%.~_gnB$ʿoW;J!,(/|_ߘ^ePY;q9I~0 i[m7H"x57u*p@&!慶.})vcKVho?QY ӯ_{:zn64Rw~az% X,, q/9RP К"$2+y!'~ѸB]C565$%dG!/Ί7d)y,g=s# @6luYjFT*O<Ηm׾(Y /vh<|w*eǂj;zv.~ ŨcZ^nV"Y #lҏwǸDȎ9}dpjmPSjjimAڗ!= jYUvW1%g0 " dg?pl:]`k)1P@fם֊4#ͲΊhtԷ."X@dΠl[wIl. VÝ}'FD۩mG՚x7OO=:؊@d,Cw|\U糜۱s@DЭk&P ɵ(Zw掲#xܾ` oO}璘=}Q T_1 BwE\3 pqZ^I]B?u Kf|4qm/L*PƺOQkW{Z8/='7y^cd,Y uޮk QQ qΗ"HK#1q0u=.nŒ{ Q8=h89{?S6Dȃwx͞JB'5wvDz޺,kX+]\x-\xbXo$ޚ#Q[VIp \\l=ǛꍣzWBw[Wxk|PѭX>L^kſw((׶vr`(b~ķ:sµCP-`5fmƉǸi=M9VE S. y]:Om; k) b5Z:pank%~{Ƿ>uoaTDw^X]yލv5<6m]h#t3 CL^Mp0@cɾ4~'z2 ߼:9@%w tc=s7f I"%KhY׻r Yhb՝$z#~pcwlǩK} `ܜY\w #uKD$A!=FA!?[([XV}랗GI+V S@x`/]z룿Ys˚X\s![`;=B y o?a}$/۾Iӑ>Bub_p{Y)]65^Lr5suށCԽkߺbQzNޮۘyǥZE ܐޓΝT!/ʘ~ _y}7e@ux]41$mh49u7REz'j*紷f߿8T (X&o>`sD2+H!v j՚W৅1r./pͭ"'' EKR,O!ј-jPx.o|# `7w~dp4Dm[iZye]1DgEMbFӋF={hwdU*T4j>|] =Ĭ1y4+n;m(l-p Wms< Or@>Tȩ?{h]C|Fpw%DfR_#=ꌺ:b>Π6J_6xoN /b7 K[rChKi*oITmS|T.Nckk2n3`_ lsΎ(=|oZwȱ?V/__>t4`45gt}QZ~}%GgJBӮ<}^v#U{/wp9 VV=r@68bjXƈJ"Dmd7R$." hX4JH0! [TCTcx򅷿!Tk|W%sFqy߼y\ RIFAmmͤjx<.5PH\/@vm CoxWPsΒAdYa),=)YUly敩oMM.NQSo_7F~%='KaQOuDmM^?-X47( opeČo\de?ȡ.i{~܏`$/h4fiz;0Jg9e3ֵ_K{zmZxy,-N\:`s\vwwc1K/q~ ٭Ikew/G-_9e\{^VhKK#ux?uwVٶ6%`7k@|s/h>/cܛ߃Ȗk _ " *W|Γ1:ߘYpDuC_Ss(^ uٕܽ>vZۚ6 9_xl}V,xc( {=s {4*kڟށ^cJx$Y"p"X)l gGT ) @eq60؟+o7kV}"8IVc!m29) 1]57ȉZצ;;-29X '@El.6NYp|"A ҧ؆$vՂ]+<9jC{5ɹWC3 dEjO.H0usf%D7eJ@KO=#V#[ϻ"` W،=Q؆JiTJ!vk; PKkcAVaAJ-[)M\2<%}Ȗ./u ,(a[:"A/m4^"gONdz%]C(mekZ8%\9 ,:b,޲IׯKNm'vFTDZL !i` 5̻JTf2h/(ᇱ 7}EcfNQ 7>fɍ%s\yѝ ]</+LO7R7NqYJy_ DE7 eZEmӿo"M'`"^<{f+; {ɐ:/z+_htdl)BZTmNOc02yϿr$\c vXsܺ>IKVǦk^LOۓmMuzn׮6%m]_?j~/c !ipyA,O#d]rbe:=MOYĹm-_nuxc&e/^ytRY%qƩ9M`C3zun}~N./>m=54ᮢJL-PkkKCBFطzarmZZ4Ȏfʋdn7ؗS[j"O-ނ+{Ͼ3-6"B`5(wW7Q2"$ww~W Ŏ7?U@f.-, !M _)lQk>֜~}iEٺ?oW㵠 hiq9xpw?{"1Ȧ"ȑr wޅ襅DN[ _|4L;@\}HJe[,r9=3e8SD?kV|cߞfuJNJymQ P\EppI"@<q'L$}|ϻ>/[ܜg]b*CFeei=N_B{S2Ž6i*!*n(ͺ=4FpWYO#{^,uŜl @X<@O6+c KXDwGXu8x 1$Zzj;Q)_vRK\T/݃d3(8#k0aXQZ"ɦ>ej9nF # 200:)຀a6fCh{/B=_4fSAwz E26:TKJ-Ӊ:pBg'*Q$Yl @h%ƳZ+OQ{nS/;򰠯=rSO!zlGc I6=т%ZXD8ġ=u?i;澧cVȕ+RC?ܬ,ab]l 5u4LW dѓkn2n6\.UZ0qmӤZuvTx`];?CvWZR8+=lR,V׶Wg6̧W[Cա1}u(W d "dk‘X*Yt[h 39;̣xw:#ɦJ)s*dTg@?z}MOMQJE͛ôѻբc[}~\]٤N&=~83x#=3G&]3J:y5lrffsrH?S&Z!x=Nzyb0hV |^. {bnm$o62(\qb[}o$40T 9@`<ӟ¨;27& y:b1iiEf^m*G\fvzWZ p obPPg'&01 m;lƢݪ?moydZO87OZKodh8!arxKûfLP(Lv@+db W[n NfUdЫIYE), z҉labLV*I65U =k~خ 6C !S]`\Npf ?y kH4b'DLjk+RXHWLD؏XMܳWcS\8/k$7H;@c݃-g $/~_P'+: gl#1XX-U1r͐y/`>BXw$ Pj]UFJ$dWnx^6=Tܸ9,>躣 _{o Z Z"&EWt}pl@y#uF`(&iahk(ONHQW;@џf V H0:9xPOcѡ(&ÿåײy[N69JNb~67@a)Zk\ ÊΟF"R"Wp\l DFnOúPX$ T]5ݸ8K/ u|g߳V\1 z]9vHs͊Ǔ/vtjH2ӛL&=^,cIvhCmo id3@M4SC(5t.l YiͭӞ~fG<~W5.."e ?c/^a1-;z}dzeXhܵG^g[AILy`G6oMkesR"?>qDs 04 lfb0j9bN؄'[O"!YnCS/d6#;^4c`{C1|(6ց_/l$+냮|#ӟʤ4T,9/;11:暒B$ R[H|Ɨne6 {YI- BxҽQ U恂(N5(tF.Edjh|X6FbfXըΖڲwdjΗYq%rV?rV0-zкk`FH./٭D྅8qƞbVqmtsu {d@GSlyث ?~qmd_6衎 ̾te> O8.؂3T);^CL&XER.`lU[J2=-T\;@gpS% s0`O-;+yc[N֖ˬ Jϊ?QٴXFTqI;0mܱPoZW&@{j^anvCEx^cS w n(aHL籥/ Ul_'' H)CM5X E޺=fͶ7)ԾY!1R[*<\@J%L &g{|PumL,-=^_gA6#u*}ks|oN&}E,!{bJ8_a$VXGEdE%"7eUZ{W6 : D"m DT7Ɛ!!lt*|PL&#:bƉ%`.Y jdYᑽObؘ`n8c3iI^zdjjN!-jҪ+Oy0`'gڶrgb,Xܺ iOG'aG6 bs{.p49*Xb<[L,GOac̶t7ːkbf#%n+,ߺ=L.'dz޷OHy}pp:o4L.HIO͓d]d9^-5Vo֛M>|_iQ-bfgfhkx-DQӶ#=Y{tF M'=7&Sެ7uyi݉Edz*V*dnPCE䌇4=+In3q35:JNJ㉱,!?y @A &gϮ>ޞ=bT a M[VqY{j(d9cwkU"1fO$e9-"4v[XXcl%fRu߃c}e^,CQsr9L2׀Pp?T&ghH v\gHyv^jᤞMK!.Gm.}wm,''Tۘ^TM? @KJk9<0F&OpyYMW2XzY[w$qrI wDyp%rG κ8 sx E6l!ch<ƦLВk '0ugvuhd`o[Bf$x+@՗,h$Fg[F;b(1D #Yk!"1Sن&BώM/HHkUH>qձ'w@(쳫YW63ެe,̶3Aby k+F*5-5FWOvF\\B0u'*OY"_>I`O[9s6`<Κ]w,{jHH 8+2=B0ʡҘx"+X&/h4F<X[HoI$6`S 94֖{D#piqdɪrD" b/վgF\sG )T^$YD^achưq zYW¤~߳%^jAjj+,B7G3=6Ux2[F‘Kc|z_^ٷ d:Wydž! S=¾Wujad7)N$2k>km)uI=?Hj.鈽8%^*b*q=1C %Tl2RU $ݕYwKL HbGSE/ljauaҢ djͧkH| zfWdrWhe!CA⧕9T.=[Ʌ+\ |l,'^o5+.'${l{n>A5!ެן]8sl=~ʿU7ԛ\nȶRդW & ^9W FEyPD4Lҵ$[Y^ٳkA4VXln0|{D"!%D-`8jГy+ 8]sGriu? CB|l$ .U6:lE+̃${ZWjo(KanRFϸ܋]~ƛ=-YgH6Y PRjɋ_Ȁ_6\堐4)OSهa1uK !jfmD쫰.$5ȩn3W*C^;Q*ŵ$7eR<W+P嵑}`ĞT̵ө'td]E[$xu6^"ٿJC0jQ_i W7"`Z@fec@(^ ._Esjl_*O "/3x^/;J%ݦ/ڢ'$-Dsu{gS /PTܨK3y_N<%)dab~ΐ,䰊 Hzm`"+(43)r:u87ECC@~6$-#֨Em k6lɶdޫRYA怀C"R }Vdq8nLIbtR'2^+YV^A|PПGEl)}WKVɺA1fi|pNAuFrHAּ,l1Մ؇م 2׮ Sp};~r"Ք;KO=XLVCQcd 6[aNxKa"Nʟcp̚)z'}fXlƢ*ZZNƩ9TCsԧTH]`!" m~rbdE`"M x\}chҞ߁bKiRKQC#O2y5ߞ*C1F"2"HH@[ݹb 'R'H9 : [_?d,r'FK7̬qƆ /B^ȃ~qms_ۊ; ʽ$oU.^,\`cݝh7:/dy]͕KJDV6X,s:,` ғ(rkƓf)zP,Jٹ/ރ|tY)< w _W TvU[nyOr$قE׮%d30w)Z qC4ǔ RN)d*UUf,ha/ӛo\p9>b<ۑvZJHi5o2pCQ27ˤ@-x7$=#I;Da$Z)wIX`(L$ D֋e;cpd-X,K(5|ryå׸W[C!t傧\@oIi<ŋdHwo?,/=WQb}qmdߙ?_<\ ߲rj's5j+ZWEn Nf?2 C}"܈kq>|}5?^8AB)B+7J~6盳T_e Ѯ ~K~ɔGB. :Ei6bPe< *=a621{8;q-'s=_C Z5))5gT@ fݩBOuIV$ya4%drݍD[|zC8| 百 b@ٷd#٬2l%<}0ԌmAH'R;cޞz. [r0DSnx>3F ~vϝ#M6`yl|E,fŨs U@$ gGp,vAF7?nmxΆH!z\,ZflazOQ6 ڿ@!16#_8Y/]>!w-w<NwU,䫕 ٳ(.dB #D1f U͗q̳ ,xAltN]p ԃK+"%!tLAo1$I "~. MZ'DLh RCϑ" xS}X3}n"qKp:c^nEO,xb Y럹/] =7}wt "l%eY<`|ޖڲw 8W@ .ރSoR@.xD,GF#lRCIbt!;u\,![NmC^>g (ε֕pyN: Bݿ\SMBRұt޷4s@ED"1gZ 0߻D0]&i#DpV$+]o$uIitaxKy߯,+V}UaNW&Qx܌hC!˙7o>16+.-RRf%5KaKZ ;3C0=|쭌7뜜?RE%BSa+Ɩj)=_Qz]7uK٫)n^Kw3}Z< bn"i;+›aaKY^Ywa >1V80}lt7! Q-ɂ_hҽصX)HKs5iV.ﲾ QŊŢhcuI>nVKm|c;{ zU]JaPy7-n|$E^\^FPtXg#oDjm dYH(J‹tYתt6.IYVBO5+Hl%UDQ o95 ^Z?J-$daN %_Zlxd,CfrF!?'a5%90\+ʨv7X<ˢX,F&'$/V[v]53fnϚہ!m;lXcIx!Ƌ㡀Z[[ Y)V,4r{9 4M$@骚pT1fo\xY׬F^l6pk%oĻ@6*ы#řy_g%bfumu'nzf!ш4+)<ɦ\ 'S E\\cn8SjafhA(xHѧYsγ>V\o.d?CP:dbO*AWC(VuE )L2݇$I ~ w4UldѸ!աvf=?IY])4,啜iఛDv3\,SڲctW rfjrC;^ǝ~|q@x8jj+b̈`ih dE*TϊY-uYA+U J 81rY-z¬pv<Or7Aeq0S'Lة,Kkb'pJ%mUH|#Y#yX ȵdraE#1rKAej!`6Gf'l% ܯe2O]7TxWH̺Y{}(MMus+_Y"摩'OܺT!QƘw? یvF=/EY`ԖJ*ܽYB_ad5|%SdAբ}){`OV,Y "&4/.~`<W mz  ^,Csj9I;J{6q 쟻LȕEeP8rWɹ,aƙy:%{Ju Bo;g lyp݅Xs XUrW> xJLp^1k~0JV[=c-[(}H<#٫}/ Cj.-ɥCZP cb5ZErʋ,0^l4,Wȥ(uXn {Q,nv1\[Rv*iZvQ]d?zkfŖZ5 Q}ٵ=8ۇ1q%Pda<^] -%\Ha;ۈDBvW!N=b@ŦTZ|wl? ay'溴W2K^`X\E]뒥v_Yww$ bإ]{_8.>"Ap#OVo0^!a^ڊU7zກ!(Kd"##Wh\]_D50T)abAޔ wP;J'dgøJ [vE 0GPODM Xl"u4Ul:b@BDX"Y=AK΋M~.صMoG31[k&_,ʌgݑ=/nlҭ3]]FQl vPa)>g_ .2n0g=X<.!Wȗ32lˀ?8,ޱW: PJI CFjbAKڍk3̣Ԫ±_';4-x-l&9^\2PxQTbA. B+Y> DH߭ۂOLuX-|#;w{Q-7TΊ\e)jqr 3PG{`D+024\s8,:e¯tjp6%^Y>vlju|R8G\da^b᳦bFGɖI}kޅk#o2`NЮlF;2-,rKb*--؅TW$+HY(s%8f٥Pv hv)Icrv}ԜQVsY[d} i.,R*t]ٗTRyϟo냮7&y;ha&YjW: 6ǹ/6].y[ d+}-@P_$nF2׋\&@㭾_[n9n $ټ?>S7+J ߣ,Ó8/ %7+XYrN.pV<Y{>fv,W!l;*@`4[l_ xz^[+iTlf]7hLW1mHH`ҩ{:H Jh[$sDž +?ޡmF'ʑ@Uʬ8yN&zֽb].'+CˑtF2:;+xPU<`]Ӝ.ko ;RT| b:y<#1ZJmҩzV9?HYHc[}K)cCP/\ƪYKe'+^C{ Ӻ9A{򧞗W'g617oD+ΰZ hXK y?| cɂ#f[]\!!7e\06.]EzONТ`,~Cr WT$=#sG|nݞ:!x]]/yW daRx3kgY&0Ap_[ [c6j&-;چD,Z7\3׎r -j5Rs2VMGM.,P@l=yTy3z?=S-N6or ၨ퉹^P)@RuN,q}|e|~z9OE,I/P۪ (vAxZ1]EP%ڸY@{7"ڕY_+_An*^Uj:IU,L## `KpR_"&j;ze:e'f%kt?`[\Ϯ=Xj Q(v@vI6h3=-10ާJش7 9zx(_1ڧfDȁr&=mXM@ nw d؞QΆdhU_ 6Gw<IRR|:T)3^/@^UG ;c]3BqTLLg@ H cD)Hc|l"<rb68ϲ\ryVWLXY\CJf9u#6իHzdoCj@>v54Y71D~gl6D9<qwYNd!l _PiH:RS[A YF Fkb\G|' u-O~?śδ+k =ǨM@ fO׮!<ܸ6HΦSj-!(h"evJ{P8`W斲WC5<`gÙ|[#VP*ڛٻwb@n8T&u=PW"3h! rY RȿBopC&ވ`{UkW@]3p\& G6r+hP7./1 ov  tzLzgBe!,e$ཎNmםjg _r#|`G{ܲGI{F-E Г<mzbPz<=dxxD›S3:ppeUL2!XLM͒+z@O9N}FjȁGOyzQl&B.ܷqR*x!~OEwxz}+T 'TCTjŦr`]vp`VF#1hBUՐJi$D;w^dU36=\]⾗.Ny;G5C{C}_,韨{4Ѥ^w !䅾^ୂZS4.V?`< >o"ؐ `Ю׏}|tbGEI+$zjQ)֕Rɡ?^^}33 HZQKl~!ZCd0J Uz4 QbP0l4%j#(R}ǷZ,C4Q,Q+\G+8\l=/o6z.gGfr) 0t7D"&jAz~ו(ؚduzjÑM7X7Awosto~@(,T[Nq@ n >s_^y-74@H*Y!\fȤh! 61>Cf E9%[xO+^+!l2R5_MOٮV^!l+{*nOYׇ7ᨵnNLwn*IvKqwC?t/vAeR J5VEd2Yb+*]sfG-EYX ^7 -c$˞7|!‚N8H)Z򘣕ПL//z/KiVI_xc@(CEGY,KaX%CjPD$I2m[yCaڇThBK !`9*kZSr=I] І!V>?H\!Lα;*N$Bfx|oJBO>@ WӞb3Tb#C ÕHh2r7vWP NeY2 5BwG=V7V܎ʣjvj|^Qog *0\Ƴ/>y $_\5̜w_.""/&J6r֪B3X}H2_Ku3_WzR!g<\CJл Km6? Zb]Ty@gBˏ; ~P1,$+H[O]p03"+Rw½eOt bN$"M,)AQ|M,Cy~iUQb<}5'/o O=׫5JR9RSƣ @6}Ƨ#1+^Q! #{˥IPe;谝ې7Ȣ/"`oPB*4C H910:o%KW¹Bx ]j]pgj Zѕ|R̄` Z+<AZF99d5wta1 COtJPenN qFM7'yq$)Fgs@b}o]waG$7q./Ս>QNT£QʝzrW ΎxǦ!o<^BK U"^XQ:HA1Zzw47I.)8X,EhyMyh@)RGuR\jܥTowm%Z{po%$ E0j[j@ErXpHSv ͮ_GE b\D!#`>,`;qgd-̜o`ažpW$Y |hJJуQ @E 7&hg55=OڱRUIS@=ѓ£DE dB$ٖ$O.l4= b,Qpc2Cp,`y#%sQ@ " d;_B8Xe;w=;@ dˋ!]UЎq,@NQ&:[^?z@ECcnY,/X"\\y`,G'$(S䮽mկ$@EdB (5= #$Y'eBAe :Y$%&OV$"vәA;"S@ dEJ߰p,`֫{K.d,`ԩzIxF J'"$YDxneF/4@EjW*dn\i$(:8J)w˙+IQy<B;2@E%0)_x$q,(Qf՟hPh F\sGq,H=Ym:q,(UBG.Ž.4@E%6ù|yhp+IQ(ϋY(~qUF HDULw`?~IQth-s_6H[?Q@ dE;@0'%>xz[al6&1ɻ'7[Z7]]Wi.""C{޷ݹf!H]}ٹJD9=YO;IEe)J׽N"`$YౣT"Κ6Kf3]ʻH[,^CȎ]ͤCU!).x}#gnϲ͊VٔL.%&PHId ~^F6J}7I0]^݃;@ "}ǧyTB-eEIB8n%*Pφ Brw @E x֪љW&^^[ƈA&I be!$ut)R ZZժ~y\O3+ $@ O|^<8^ܷWxD* ɉIphʔ@ GDs{pD'M!'@ "Bκ{ƇPdzȭa-o1 GI$b:4w (` !nk%IQm DrЀ`>䨋 D⯾ͤw @E x'xQf:KMd'HC%(zmĘw#J!:$@DY{!bq$ Tr2#7k7oBuUvk;!UDz~v7o> К\M: Ks=>2AFI0#8S@E _]1U0k!o:xrLC:[^Vq,(psxWM-z-mёIvqsM):!$YD_W+/Jgռ' $YD{C~1658s$bqf8]u?T*NIX O<>9 DRF5_W򮠕3I]>8198h"P$jKhH8*尛`Q@E b@ "$@ I@ $Y@ d@ "$@ ,@ $Y@ d@E $@ ,@ H@ d@E I@ ,@  4渜IENDB`hy-0.12.1/docs/_static/cuddles.png000066400000000000000000001321621304171765200167350ustar00rootroot00000000000000PNG  IHDRoM.tEXtSoftwareAdobe ImageReadyqe<hiTXtXML:com.adobe.xmp ZHIDATxipcy콵u˲-knlIJrCjfjRTe*_?%UI%3ɭM;lŊےmYKK-n8:Zl Ab#WEI<}%  AeAA@APAAeAA@APAAd @2 Bw ;XDzmv?oG%E|C{HX~>RwOH r|1,[7m0e5S5,Ӷ ӶǶ{ߩOHG 1$MSAXp%A`hwbA@H?f$-'jf gSI=gqaYw gdlGND:38"qNA@ vd,JZV@ o<8~c~.|P d @I ÙV@\1AfP Lw /iɒ`{!eDό4n>@P~Aֲ y۪uqt-0G8Fe! eCA@@.{jY뚡(|nUC  ˴rE3ϱXehrɞoj2$T 8!(LE͊i@𮩺,ka-[U5RUo &yxxG".y`z`4E6<e=YSe%QTMPK!"* nv+$qL Pl,xA> (H/IZ  ] 0,M%QE\ K B?Hp|<xYQ??Q ۔U +]Tkfg]7E+RI+2|(+^`&3,TX A@i]$kٶ]*IiA/#Xc MReiShШdYK&slIT~\$I¾sPlM~xɐmA@akJ(wn?p8ax< J0$H$pj*p4Dp' hTTc9].HP[T,V6֓ X(rl,<0r=08F|A@I$НdV,Ʒ\XՎ3$ޅ{ vA ئ0vEK%sxNoM^aԭ# "cόA@=Q5ֳbtϗcbbCԐ@FGCgB"ōfR/Cw0JI;%3z2B쉓ӣT/hXf"^ |@Vڶ].IX&)bvumHBz/~?Ϡ)@PD rtZ͖VbGΜ!=5pAn OYS h'Ed20 =8 }NBOP 0x%20؎SxQNպx5M_YN C>A GF ooz3f#^<A.4JЀF&:ˢ(/-޾"n?y칹p 6w^% xn20 dIi)O% O +۪5oE}s/LNMuvP˺$ ?q9)20@`+Ȣj4 #E@hHnUx6.TaS:@`*,rRe`L{3'j˜0~Ѐv4-CΫDssS#թ(LT5ד!a6[7AJRe/*Vz{;35: XS'NwN <{gf#^p8@ >v||F;wbtaJDԔ陙ٱNWQ$DXA[tJ3Z,c8 CNp‰&‰/$2ЇDm Eӧ8Bc(۷*/Q7fg^/ x7 A'%F4 *l'DQ+^%`Yh9 -xb2ṕ*)[y]8A6S\^ޖe/;=p?rscc{ F\㑖~Iַ r^TͮBKZ&J/LOOG{>O੖! y>bċ[%vmԀ.q'ق̍&B.&E@z I7E9UV4- [),ѶJOpjzjj<hsoO A1 &ݼ궮cAQe03#D M049w+e=^Ar ݹ' 0cS 8 SaQ Pg#f Awvu ,Lo'Qzǟ93; -$(` <b2t ݴ3 &sG7պkkV5 "ROud`: !6(HM@I1Iar=Dumh<[C /h38h]'6P!^  ()+EYzd/mtr[ϜzyXڐ-,VC@e;9QK\5J$mI$skq\z .,L{<xu8P#('K(8N2[[K(w 4?=̎<9q q\㬏gޱ A(HV͜X{ :jگ899770UQ?7G:F@@1,0Gܼ5گ,GiX/hwx:ey=y=!@߉WVWe K_̩ӓ#=-D쉨4)@@@dQdTh(XX/ܙӳc㶙-t(]$͌dI1[6ѕ_RHxKΜ }* \7p SQt M. u]}0߻˕#s~eوw2 %h EY,5-`Vl+ϗ]IDh2us-+e* bӫB]LtJщF }^e_ D .ȷS%xQ ݴ׳b^lvI>hu&8N2XOl2?Qe0:LҜxQ|at^;L`}U.i6e`(zE5Ieuk+-IX=t(0 km=Q, QoddU8&Ai(0YL=WEml(e;`cT,f6.2rr"a@  9qWN 'X2>.2 @ȀiEzkrI)h`Q !87p07rbreٕl]t݌og~غ7tVY쩐@taXv/$(y<]7 JţQcmI4{YwMT쮝KYV%I iSy};]j[ n'Ue;EEKzCDJ.W,̀XeYM#9`k'̍G%E7pl%QߏNgG@S.!Ȥ-&1 l7 -`pʞ$BQe\#+| A+3N)FV*e<] ΉZ eulH yH܎eP+7vKqr?XSt=1AN\G#k@Uj.HS*b ODԱ`;=@5} n}C5@ZQEdA]7|(g 8(t2F|Q7F oŲbxZҢ/Ki S,!-oPag}_3P xXu1n{ՉeZ劌Ɛ0lzNT{}`G k5SGŻ0+--PupΐAp϶S,ZXJ;R((@7{BׄPU@EٶԢ|~6:Xv\K2fd݄s(l@(b6 Ф Jν^1^;k ѭlUiT'ix+*81 nS|Z^%컎yQ=+ӽc99dpg*C?K'L<a2ВE9]VCo б"QZ!_DWjkʋXed*jbϹ1]l۶GK,Xt V =z i&Xm׀]Oh!(*(nJ z˸vep `9MZv ĪȠiizvʮѡo!҇lEKc3аHhpރUj^V[v%[^2,nʮ $,m&4ŝqbdTUk:E6+sJ P撗]Qrks.˲+* 0KMZ#bOվ|` tY9DjܶKB &'@}(ؼF׍bI{LbAS0 z7}( 5#]Vvn p%5mP,T߻]T-GJ<ǹbSjiHj}a70 \& !}v-@pO@ո.E@(JfQPHQ G(lhLD3 9#[`}e : $(?3T` H(֎D`^0X=epq,yfԯ+j^jpLAj~ӾԫtQC!!eKLE5'cc% 9N NS䨟 Gf1rvwtYVTS-D!SMn!/+ @h51Bk+/1h @ xoA Q?yPj _ @ c ,l ԰,whar& A!3OqA@H<鱀iEYoDX[:,3s#>0,2H4xVd֊ W׌Q(VZ;rJnAaGpA2dzl 2(#iF ˪;qFoje!& =)DEF 'KQ]9*j&EhD쒬 Ƕ zn{ a޴X`>X`Z O%C4 Y3N߿$8K vy$0` ƴŰz!TN$C ^O>oL?X({d{Ybddw?/8.2 -D8K `^TY ԑ<) @e7+#xaIf2seaAr ۛci:6 O ӕa9 Գ]v,K|8= ^/ם?Pd遠#[_aC!@I~u tFwXeljP$1|\3@ZꑫItE(`!X!I쾟 e`_h!K( 20 `S82p!ɐWo]6A0]@h/$^ <4X |OV@@jF7 4 Gs#>6+%bkC A༽,>}(tT ( GEObB8<{TMAG۔'4nrA(vwnbw[枣q eHŵËaU dB'v y/`|3@3.z);B %+!ϳ:bV }W 8ʅƣCNCCR&p$F8e84߈făC7Ip3M9QT:Jc/dyDQPʅJ1a9/ ^a m+R9^{\Hbԉ ?~ikRњ hԡϏ8_9x /DmӀYQl tB  ؂Q:C7V$ImmoܺVSc{a}k?E.- ;_m:ϓo/cg8u OHp? tvd*JNTg7Օx,nXX;?A+>? z xhb{olw&щٯ?+r{H\&E#>D($1N/NFEBa|lITEzoWRxF$nw`rU+K~eGxQ}>s܅gƃԀ@!^{bei𡐀Iv nŊG}/վy~ttt||ܲ,4M-C:yOd߽ڿ;FU,,,<裲,S^%}öH$05g&B܈;-RK׍pKxE7 =q "QT0' ?~o]%Wβ,?s\:`ǟ֛47޸Aq@zw~ַ*)C 1 {$oq~>c" ʹ*KYo gu8܌*}I x~gԯ2࣮+/}ri[Y?y>9 {ſG>M "/ollL%&~#N^C;cϐA) EX&Y5ť)%U=X+o_JQ~_?i0D?ϝ;wʕl6{  Nh,;AR4ӧo@ Ihe{ڵRJ쩋P?==ڢ7q߉o<(n J^fshӑZ,3 blz,O==ug%@ mxǻ2GΎ2??k__Thr]ѭ D3S_H`!B@'g0.LZTȤ fﲩMgΜ'xb :@ W|ٶm,߿*D__җTw뗿eЉFIƝWy]Aߑ'Y<3|dvd< @?ӂ)L`sԛ~ʏSU计P~ ?p)[eOwK!koo/SSS_ hΞ={ɺ-݆ |iA|>ho'0`Xc2J0JK~|"rpV8 Ko ;t/of3yYSQ@Ko{oq]Un]{4>u#<f-Om,u G̑qB fe`@7;Z%#I"~@@qOu_j}_ a,--AdujjkobߪS.d[+;<|>X,X5_3`f!`F ! l+!)8fd$OlZ]}533SO5uOu~n~4LbRf4G (R)޵~KKo7ôL˹[ `:T+F!*+nVڙ-9owܱ'K&BP{ʕ+X?2ѼޗF VA( E<}hthŢ뷤Jao ,//{߫[3`OR)BVn*l;q{r-d`o܄^,BWjSgIbq!wST 2fq({툪 G1a Gd߸CZp@o[Ӏ;IoUJy}eYbvOO{EQ l6d-aFdY5 ܁S+F𼁖dhs_Eņ=rqOxiޕi=H46 +dS't`j1{nzz#40n޼ {?N;N!˅5G5M7Ќl8BpX.㔊"tF;yGԽ]ǿ;c7$zQ%]˶( AȀ1K7/JJ-..&S)U9GS+im۱ ϾWz`;=Pf بs&6 ~yO}S𝥥o~W\ifZx/L" %`3,Ӑr#Q*-*Gغf8nr bߡ+Š4UM)4]0  CԾ}jUY3sItʾуR7޽8XtLöQD*D)ܻq67PKXxP_ y[Ն*86sH д0sx\Mo@&f&(2!!|!4'!zғi];ҎEj>µn]i6aYf?YvSoW E4Q;ҚާFN~\-W2Х$KEqmFee`V 9Mwc?޵w ?KQayhn,jI\-20$^b?i_4$P1a&賜pwV`hFZ LݞںjK-,Ia対t2|4!8p]]0ʨ(C$</7i9`Mw/2:՝B#GpohV041`XA 4MN)C '<Op0:yU"SXxAx7c nc# FFy'a8ȳᑉ$Ca?%![|Sg'sQexy3 ,/L<סBP*\l)X0mhH˷l£S 9 L CcM(B&Ba/۠;H`dİS?c)zuǑ#/3_`xHD> +rg. Yɐpa*tLLQ$}XA!fs'?VayG} NEgm[\q3C.>nd&h] Vo瘅TH5F !>~q#O}W-A]#/}OCգ`_&(HM~DTxvwpZn1~O}]<ȗEq8ayǞkssWgc\#̃HY_\2GShșx@zi8C?RSz!ERg> Bc%BGFY`mc`vl/Aw Y0Ϻ%Ⱥ)دJETJt|ܣO|e۲Ͻ¥}."H…~oʕ];P0AIB{S()qT`g> ފiP];ىS=I5WYyڪXJƭkeOEӂ7GǦO.\;0' F#/?{ia*g eQOnHVc-Z]ܼs`ٖ4^?4DoErmLh)mYǡH C|{_ 3QB|A G`՟qwʽʃI<ا&Nw4( [LT E™}d~r4`] '"Scv.*ʊn, xݟ*V+d! vmL<ݩ}y?}ڛ8Nm}g%ߺ;#Ep8 y'ɩhgQCS㡉#g31)m% ٢XU0ﭜX|B6@_9~(jO?ٯ6 j:m8B~~f< ~jft|ϱ>q' s,J$*J,$( jQD695U0Sʅlj6BFOԆ;Iݱ%7n^gy/^jİ'KxXFfh6}p@!p̙g_ޏ}=|>/dTI \m {VO?@Lg9} 'x!En5PPSB:v"Q)/h*20,ۛ\QDfTgerW_J9{jĉ4֖{>HT5`9~0ZxZH`Ĝ.95;:GjKJ|&MwcZ>̻S,*8chAga^O (mw8#Ua"SypacfA+ |P: cVz{MW厾m䦸vC`d8_&7Q !(EO\|a߳>[#c3hm\ɧ 펾*g>ԉ8~ 20,'NF|q CS۫F;`B&^&Y=&~{rO+XA!/}~/ ӵ`R[+l^KSڢws _?{?y{#&20@=;3p0Ag}FKJR.M߳ .G& OeIv+߻έX$Y`CS#g~lsq!%Hl_{o`%I8Vc^1QRQ Ac?~t^8uC4վM2ۚ)[l"qZùN=4>0bOnose#M7)} 3QO 8(?ҍweI$s sD-[W YMl-y۰KO.ghHd;?zrB7LB7CuU3ӥߺ{FKw.,\XYZ;U#s`Gi~ [D{bSEg ? 6￲s5mFC'>\K~bDZJ;?-S;GB#㗟/go/?!tqIJbY~'uݚ騵CK$y'ϭ߾v"X{ocS?*qZy5Xȳ_=MR8&Y͕Bҡ@nZOm[d'ۉku}g9{;XZ[ʕuMY_zkw{H:g(q 2R,:RXaXQ^?=t=eكM̩S' c~KWonN41wßHs=JrW]ӉcA萉lGWnH73 x>"l*@@s^x|4E\5 G'>K96ub-hrbϣN@zt7_xdˁ/}H=wYG*r9j~2B&Ϟs]>쩋Tܸ42U3w%^~s#3;pR.+ŌVCW3wƭ]5鼾_/ ơ0wEkŽ'pW %_Y6v/̞E]~f|4t,\\߸# /G0-nE*>|.B@-{+U+To.r՟>o= ǍNGf8^Pr|V}R A#wy'ݥAH~婐(H^~-۠x9$.d/=7ˋo';U@'~?̟C,- τ^(H1-{=]C h9YV^SxIk"N/\觿/YO`ygk":jƋ-oQ>²rCM]1ۆ@_(+f<.fK,~/pX>l~&:3 ,EG e+>j }fHO} mON v ܯlW˛QVm/I,C:rbl\=@l|bEND_0F RT[XNӍ6[PhG;;VFpP7@[PT/Ub "ІEqy+ b`qݰ70-;7O>qfb$@. ,Mϡ }݌o??c.KYR.mT$I@T!I¹;btyôn܉3?~S^(}m;kְr/_rյΥdˉlז6f:8EQl|V׆d-L0LUUES!W'[Td{ J+wWˢWgފq!ďjf$P?0366° `{mpu4]|TUlrWTeM7|*;\XYe+D~t{ z<`f'-۝ ~+77t C>9?A-8GEf&EQN&2۱aX__  c B2T$u#a5y3ʏ߼ }-d>p(҇ ~j,6>P:$ Pp~2P "kv'nUļnZyA n% Մ@ Cjt~zz#$)2𞿸cg.MDL*Mt]Tzi5` CgΞ)wEP;@dP(K2: ;'mY\M^!+:e%QP0,CtüOnT,.'jɈw8=~~fnnӵ*e)reQ݊tneKmN:95raaܷJ)@P5c=p@! MY.Ih wM.- 4๗oT:˾wj3SE(+[L&kUV\gcAYV!c{߰ĀJYT/̳, V2$m5Ml [!&ܰhK+7 (1[x~lt4bEnQT׶~DdQQ zj`b; NL Z*g$)BP(K4̗婱`\ô7XPt.lj,jf"ш˳@BC̈1 0!q `m>P˲V>WqBv eٲv??Y7@Q{ ^>JТ %es=ϑdי(gwL ǐ)ԮËxً؈ۈ}J I ݐ}ByҾY=@ 7`*; -UijhJ LJDClE>9LJwڕX=L'%CЗc`6zj|AqkPRqv2OO,KOG~j` Q=LTmYzZ"e (J\\|#0TTR\OuHqDZWN@QJrO+5h06k1 @E!#sfh(;ij{Twf:T*"Q8 yGjUyQlP`Ǘ}:4Cݸz1qyxV;1 XSU}4"5p3:=b"w @&gzBpj|7l_,uHXX ?\q󓁿{M; HR͝GF <bej:4ճa!%j~!4U861ł4w=l4x\ {׃>Gz`DW˗-j^uȤɣLOs$Td~Q;3_Ajl_>}V~W!-LP<8IL+4%ӊ_̉C40,$^l4043 Fb=z~|;-.oeH͹!ʊ6ޮ5_}mxIs`1sdIΤ Oo87c(DH 5R_}U*Uuˡh`H_:Cs&8N{B~L0'o N  yUV t:g6%ZM*ZG@u(l773n7,o.śV%X4r4ຳ6Î2EPm%N4hEQJQfKzc&*.q2V{!ds39C%iPt M~qEq78ڵoxW8ts{&+z$A*KXpb2q 8nsj&lDQ%>V(ɏ7O=):;H.[[b*-wb+sanX}9PА_՞~\ O޽6\PiX567nD?YC0PSxUx|"?xv5Q,¹P74 %tQ0φO^2ilhp&P-:f㍣)Mo?kAR[N\$s*Th`x4+B=ɥ7lL;ʉ\ |_~t+w ^&i\ܠlf7=A^VJᰬ̅Ֆ#bPDAQ/WJ=H`Rktc|cera"pul+8<~HS'P(z—Ov^b4MEbAzU}j}gPs sa2:ѩAH WaӃ:Oj9l/d UqIలa$|tjg'}K 4GݎAuQeִ^-D4p {l窍WO9|y:r,R bcf<:5z$ IST,'$Q0n-D}.h'4 A@gU 6Ȗ>{SvAQLU$p}/dR~c.÷޳ ;Of22YQz2:8])Jfub[ fu~ yO7t(:֭KHo{Gl)Q z"0Ow6hS6Nz/z  )2@?5eH;΃%~+8`ID 61a8F02py~8T]M }Ld,vna"@FY)D#8ml䲦 ޥ(W}lT6DZƍKG@REQwKߜL܆s0݌oJu)z!p3`@* l݅ɀq!LиOL儬$n%O)by:4yr Oc%O$= >jomTj u cYv8--*Ţ>c٘H,Q.ˑ?.:) Kt*v;VV :`Yڍ)hIVg|xKY+өaPiF! zsir]Ufxy&t<Auܜ6^*+˽ +G_ L l+QDu FIZyYCS!AX~Uk;ڄ H߮&j9uoyxlB!ߝ8~q?\;PMGv+c[xAFY -?"pfX xZm㘉hFn`>{sk/huw?P zfN&JaV| S b Bv")vw[N1k1ŰOBTE@e,U %\`" VZh:ԍTMfӒGyʹ2 Dh\Mr,OMG>%XR72X44v X :n@:8 yhfRirπFLmD%P^̐qH,ɇzA9e̾@iO6Jvѐ H A)o4 +|e/D`>(n#D`c|o[ h!0c0+嫧{RzESSAvB}.V HOútmm@j؍纗XcZjfj4^ ],^QQ]Qg*(GR"0.p!Dk+*=S 8-Sue|8f_=Io'*c/\6c]$s6*~-7=-5 DN7^^9tq e h@`(;3^jT=dJKAˊ4R(JKkjm"ԩa5.cP0YνD";]SEE^Hcj"6f`р￾` +&{ 2?;2tFs^_3{7ҵzXqFer]2Xx ߫8j̓U kcs9c_E4` 4;L,Mo/F1jfm"VºX:|(k]klS6`X9y{5_HUk~ L_T> dupdcR<'ldzW l5(y I܎|O^,CY9cGf jzJ?ᴑ@YS.Uװ 8Gߙ|'Y{Ѳ 0`O.N6W(J v 5`lOb,PI$|8~zCuuԗ&9h:rɗ[SEΰy 4Lb!d2k<,GɈ7^L& 4u:ij{G\= j۬Յ՝dGpVXo!%2 T̔k޷ &vJ3C2}_]W*,T$ G/NsRl\SǧgcV+gޥ(kGbw';M.;gZlڐ 0U#r;,EX^9pQDe˗$H4rx滖.,N p}7]z #Èؒ^"׏{is?-QѦ  e]\P(9@k1 $p JY MĈ$Zte% /C 8cՈ H:5ܣ_єJ}bhu'"DJe}=<<#jd/CKqcJ;x\CZRJ#Ca7|TjOQttXZ-v p4Cn6LB-mR4_˪c kFKp0[mhhG-%N,sFЭB^G,blQ=1k Ibk"!;6h3GkuvO0GH GʺWQ+ `.L.k=2C=_44|Cx%z( GŔ&d-_,!V΀ndRm(o8vȮTǍia4E4` K`/APrO%xD8_yn N(.i4Ek*G!d0/YP*S(dh L~]US/IVijwnu">R>WE[hj3Bk(EŰxv}/5@B{~!oT Bu6nepcA4`&\,!86ӏbT1-cdW\ȟ,Ev87a&0R Z)cʒӽR1Y4b p UtLkSŖ~2XIXoߚ,YC b Wrc񉉰Ǔ5#%u^P:k6 ciEƒ.pAOzmhc}P$˥ֱqj|FӄO,0{y1/ k4t~/JI:Ym\$jir rn?%+oވc:徜Q.a]RUS8ft1hTLc3Qإp 0;9R(>'|^nhv=TwqᴱF7sೡQ7 um@Ghd Iр8w:0E*л=ː!CNjBN5ZXmU.Lf]h@F)ƾxCr ٨o*~~ehFV kF˴ ba)6~Ƣe@vSx3 4ЇWGp,uK{?I%YHӊ%w2Cp jS$iqf0ZԪ- v)TDfHyCʘB˶;RmH}f;cJ&B,T\."4Ž٣/kun(w,eR VZOPS9,,m р;gV֤ׯ°mX#(YYʝxOehd4ոQZ4q3HEk~L gw]ڀy1Q 2~26Kb7C^uv}Œ#Ada4ZOɱd% [5h^tBFm!kϑ U3k;T,8``ehPnϼ.Y"03 nBd.Mct`(`'gZk[|kwXis͢Q|֥VXPg*/?{AD-Lz|k?=2!k5H{ݿT0$c{EAD{ofr():Y_pS zV&[`|w_?r[V2ZBu.GvW6Shmb8Nڦ.੗da}?wEY;wٿ]2CS|%ҤN#VU o1/i^Y" M,7&*]ƅ}\:6sk8[[fϾ] ؋C:)@󴨎lX9c}(Puw 4v9|? AX4t8HAm`p`ɬj شdh@F?):SӁor*%W^:}) ny:{UZu % "Nv$7jGpب mv$_wk[yS24ʬւoº^=8g1B!jL.A86Z9_Dh27;+, R;PSoӜ^Z<4 k5vdY6FY8ᰲW&+c5(rz&j9;Eh{;qd;k0Юφ'n3F4I>~ŚN|0 <Jk%^c yvhSрPݱTʭOSΝâ( t~--fz)䴱`ϩJj)Ω |>Jdi}{}eξyM+MKO\W^ hH+IUuuZ$:HWE eShqX9S=ǟ5vN$sełnDDz1L.K2@daLCk tΕe=5 R@¾ Gg3ltS@}[kQ"O߻nU]Au&XA՘[-1fRJ%^,xYRr" hQڃC]5Sx*2f#JSn+ [bM#)YLu^g$ր!uiqg| ޽;w-< A$`X'.4̓ :E0;x~GDPyʴ W3w9Zi"H+: GS%l&}$D6 Lo ^}g\ؿxa{~h om߻6~s>Ҧ4 IaD}F{TxBEQ2jI*ȭ:['^3 U|X;QcȦӥQY'y#kޙ.cz&:;6IPgT[3LpiT^QeiÆ `^SdꙣpƂ\r59^ݎSBfTeyg M7cA9)! ͛Sq>1r"p@sA\>MG"egNh(I*l"ˡ\b)ZZdHvDɣ6ʱwuED4`V$(WRMw0[^P:R!Qׅev!|ݍiUu^y1)36CWouDc򺬰 kͩQ 7,o6E3sRdXZ`C>ǟuWdR'c6/u#,$YI˂gi#޵<:Ewj ٦!(ISgy]p-9 nUv2y,86> Sg٪vjlm:\J븬phb.} (-d!E+ƴ%# [P jgaz ^i\j^ aRsDM_,I\ ޿7dVgs^ͬP0) V!,T߻I2Q \(t[DZԉo&2jw `NV'#9! zv s JLqҖijbgLj]puZ.}-+|V\3!4ǝi3eBZ@ri:7*:?oMop?^Xp)mGV'x:+xwyӗ2/[\mPSP+[G 'I(>P5/ ?\rS9ƱZ8Fx,@@C]5`\PC܄8i`/L|7ᓇiղwaij7לL6'J" ؄ޝ] XtE4!|씇)Ӗv;K<hA2?6t- AZ%t*m󹭧}lZ8YbVWZ k7qT>Ƈi?~|b\ӌ"Ir|"4=,[MQjuX('Y+z)Coτ}=W,SHi6i3*Ipf$}Rn2[v8hԔZR) LFC o+hhFkGQh+;+aiꍛS31?AF09yL4 2L0s N('@BvR౿~}ry:NWjj_NDfڱdm%Ԇs!{{8EݥZs7ЌZ'u/ҥfhySѸ\060 yvɗkr׽^LqR}5>/4 (J98 8ݯ^naߘ4n$qm^99Krُ6PT5P>I[vmr*ҥߙɗKU4AϩG=&2&. pBtȦ@Yq:{j]84ױc}vg'U$PU"/,J ~z|5G̍^_d t1ESd4\t8̣=0ӄ@Mjw_sB7arzO*7$}φGYǏnmgxVji׶)v&:NSMF?$kffa[l!N(T57`3i?<+siah2 ؠ±{d¶HX5rr })S |F>Τ 1l{v&0y7,Fh 舊ũD ͣT8*+͇")Zn[*00=ln8T h4Һ_Q ,NP'dEb,Jv|;拵mˎws831+{G;e=Cr^<][_aSPyMɵܸG뇩\#]E(0'KSaci*wg"ɠ`(6NjajTJg4ax[՝$l n%vrW_ںu~o0-oT'O%[F.{V wٸt |L&sb3k綂 ; рZ&sZu:(<i N{0;D΀>^R'C >37eu\@XT2[أ~[@ƙBP劵RQnSr 'B;uR qBH4aVUu&DG8p2Ho7r9jpɮZcRMt:+Rjt mQua)n-FAu09´:p;,1"Aj T%B^7uآ\mTj> G[;9C>|Vq y nneX<4WR {O= is{z$>wٹ7V,PWw;s l$Th1Tgه2融f AZ"w)`Ҽuu'MyPmlBA*(Ųj(Tjfr/W/J/# l&.qX$[rv'C`Say؈q=V,7*6Ũ͎Y,vEI~v0rR~?tߘ\\+ň6.R]5zMX&G40h\ cʩ:6sΒGLQd0dڴ5/`J~z8b H犭+'lp*# /(m\p,}g1qY$j06Ia\vsBz)4ca.bV?}t`@.$߮ 'Ci̎w%N]J:O8gShz]" ~l?y`Z`XşeC&V v3 A&N%j]0іSMvOLh"Aa =>rDKJP%K.:icJLApf[>:}ȫG9PmK0P45 ;ࡺf ϶ KK2:v j&[0w2AVDÇTäm6e?h.$;lTF1*'TӔT Ol 嶣Թ.IY@ROl3,LnGQdB!c2~VSNH1`/t99A&(DFWRH 6қH0EY?6x΋jAQ.gcLjaY^{͚;>~s粝-6l`s}EG [M5 W\6D …#bҿ@$^ir|N݌ύ&B\ԠÃ^HWfBg.䀭=KXKe_;'xp Jj1yKq}6|{1# cܘp,;l!O O/qff/G;ȩh,r@/Y\{x9,?Ri{k$IOgX~ r2|[% {'zՉogg. n fuꏇmc$ۋ18X1;C (hS?r[rM'~~a0ue {lA.;c6uf.xhnq/ b&?O4S :!tCSX̖~}Go/4,h\L흟m%jXqmeΡ*ѧs RuscZjLM-[L}QTjd>*\ܡ5ĝ z%_?_~+v^; [@mjEg @N6" B֪&g3/?{47?`O*(rb2V sz6v;tuRW*+dt`zߝٻ㭹n%$#s@ a󽻳^(d (~'|fƝ.;uOT?G@:/HRۀx/M-gĪymwعNT#h20a|u  fe52X{?L]\ C{as_AYAhm &_6sw_OOUoܘダh@tvrRl,6 IZQFYl,>[NKb"r8ml(N&7;:ߛ[ ] ro1ƺpCSoݚ<偢)JG;?ީNrc@{G4|r IQhg}"vMw{N 7 @sb9$+ک2u}&te*sCծ$?Uk&*I',oC~m'o6EsiMDiqW_Qr:%RO#fQ`x " f>twQ ;C?`%j>JV*AOT_>{cj\;˱Q\ܭu `X,?~ 1:  $ISRM؋>n8 "Lx*W[״{-KQh~4\}@חT#M༞ hum&4;w9r7Ϸٗ]RAGo,.N 4U4^O`!Y_Kqp7xO5ENVV루2͍'aI|DB nX m[˳1DW .Ah=Tp/>KUAO+C>L=!neɑEQtR3J.q1ۭtp:-TaW/xQT4aMe)?t\Vb Ȕdc r9,D؍v>0 K\ xl@ J#W&d>-=u12Je&;H/E8acj)aL v{h# @zd rϗB!SdrF.VRz$앲EdVAs|N >2CKPuX#_$^11Œ" 0@^4^e:zCˀ$Q5ZW?j >4fEI+Vg | I$1͍ s,L:Ml JX7'eZ Z:m}_V3Bb15%Tn6FߥE¿MJ%9)s?~TGyA\0P]WMC;v0DFʖ X;KhҿVJպfmO?97.RPqY[3Q/F@4pd%WJlkǰSDAC~LJ/,N/Ph@ŪA.&u7bADC/jc䗁aX48(7 JƏ#D'߻uZQ<(OYׅ8IGF"K6sha%߷9|b 6 8h hL{gc( B@40hMU 8o,^Ah@ zXmÛS'0# @K@ohaa_}| GX҄p1߰4ZyDalw}eGo-34 f\[wR$@\p쀟~p8`0\^EKwQ@(U40vqJ:٘[ӈ ujрp x:oح 5F@@4``#> 01\Zcs~L$Hy Rc i#bœ a,C!@@@4`&`fh $66sIQƪu^A h\`.E*Ckhd`>N<+Ɉ \6<ĩ\Rk%E@@4`&s6 VWN3\m'hI V [ }@dB^6EQv٣t-)3 \Wj|!!#ysevZUDaN9?8r ! @0WR<̗jha p,wxsy5Iw?Kʨ  aa\"TeO6 ^B#AvrϷT>GJ:^A0`O?} z #wىgv7-,2-N`xG;i"0JB>_~p+pr?rk?}SmCM,C٭!cr=_`H3A@40T<[g1lq*]: \VAB~:Z({)X' @@aALHaKwSo 2 qk<*O,$<^Wt $y7p"\ƃVJvk1cS8g}~A|׻a]1 y㇩|X9l,B@40\m$̈́Vw@xjhvDc@CQdߡ?-B° _6̖*5^S j^d:>H|'Y\OR ^ &c,MDS;D'ũ^$R[ a GrZ `o~clva,vCRTi! @@A06Ʊ;gb"]zð UBP˧Ozq,,NV} Վ#ǷUZzDFGx_V4aS3Qk8ޞ bY$ZeݝJ~8x]?X8XxtC8` 5/K7FlZͅ~xȍ?kI!a("ܨ7uvw/+ Dq񌍌.TD5]HI[ѦEBuƙ8B i@~3grz\asSn0W~PSOGH ntzh5B܉!KA fV^tWy{|iN ZQD:q'\B p(i%qherY+BI# &@JY wfg0wy+\z}ߗjE)V̄4d[݁2>ǣ95"v?{@p2XcZӜR:ޅ"!|~ETH ?0@, 2 2 2 2J_ $tIENDB`hy-0.12.1/docs/_static/hy-logo-full.png000066400000000000000000001323621304171765200176320ustar00rootroot00000000000000PNG  IHDR  phsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxwBR""F,ML,ј21)M5=11}o4[b[b Ҥw-3wny?`ܙ3{DSS""""""Pw"""""R9THQ""""""DDDDDD F ) """""R0*@DDDDD`THĝH,۩<7kJ`]O^DD%AD$2c0E_ g|L12x{<㊈- "RV,LG`F2 i>0 |DDJe;݁pjcM*՛.;8dObN'Ss{}s>"""DDJe;]s16L!roƝHgXr"r3ܝq'#""% "R,8>l f {wn;(bN,S`PTI$`@݀45mj3 ; 76 Gs vWP""Eòy}G0q C={AMUvq6l3M*xa>E[,nn,)*@D$vqj༉fyuzaHO.=wV$EDDBDD"eYiB3?\}YQ?jD`'k໾Fs<HX{^myoomv Xpizt*apMJz3Rwɀ ɛe;]ىWo}wj%pÑmӛ|G!""' "3vt#F]jÈV:/_<<3rIDDrbَh>.;.B{; r]|8 wiDDbρŒ{ 3bi kݻѐW vGx*@D$#~vO gvµܺUDD* ie;݀o_:Ipfn&S9 ૾YлHQ""i5w1 0< G<46E/-,=YDD* Ia(QO$LgD|l>3;_?=7%""RqTH+ =tL>sVrU>ED,,۩\O;;nWYټ`REe ""eC`N_"rthQޡ| |Vn--7+,DDpt^Gyq{CMUw)oK6u–?\s7ƚ,`$ۈ#_{o 9~xɲ}bBDDJTgEy^]ۧ@Qޥr4xtY0xٲq'"""GHlS Qޣ9.1E9pe;7D5cgwL G? ".bEDLDyI{y-:v0 ϯf"V |& DDJWNТB)Egzw))*@D*ϗ ~!NrgΨ.""%EHYUyژ5Ňǚ"" "z`yA{to`I<ȑݾ{lwD[\v܋'aGl]y, ˭@<V{xnpIЩֶ"" "J`{ApQ/{,m""RTT(sSs ƘG*DDdlsqpa"a+ɐ ʖWr$@Skߣ6E~) *@D*sp _:6DDl E*#G)GOdEDl/8f'T$*YG}]Id)K*@D${HTHT•DŽv'УHYS""Y8j GI?N/Ԑ=P#HS""H$ Q"QdJwC$""Et#GjG 8:P! "rD&'%Gm"p[8وHQ"R, dA0o I\6tSAɕ vb'Jpy\:T "-d0_ԩH1ӥ 7$*@D*e;297.3H0=KgDT "wtR9J.%W/;IJWTT vgrBmu Iq9~HP"R hUT[Y_ve;_ )s*@D*e;=290w IQ8qߜYe;Z"""YQ"RyndrWD>{x֗UwXsPHR"RA,۹4s{u1۴J将&xȲg$""HHl`PGAlgوH9 kh2;ӥ,;܌DDܨ)s[prva9~bp3rDYxuG% >26X2rDLY p|I4ffiX9 n΍EDDʒ 2dN_IlIJˀp谼< PDDP"Rv,9 x8, jIJө9jNHYR"R&,۩ls\h$M{B&""%MHlg< ㇆r+@B*Ʀ !!""%FHi[S-B\mV"""9P"R,ܙ˵%Ԇ "-;BD*FSSDDDJ g7zm!&#%!!""%FH lDr9)X[34TDD)Qn٠DrH5pixH)Q"RD*sT "%ȲaR"ڔ,yd"""DHiF  6""RJT ؔsC9`+7APB}+(""R2TdC}>P-92h""RT1a ͤTօPHQS"Rz ;`o&wv:QDD b`GqUHB;-F*@DJKӯm%jτQDD 2(`զ("K9Z-۩ = "eET5 K2ѦDD,*"%XdODD Ҳk[ET)G {FYDD {`UZMZ.XɃ 4a("K9Y 6n,|"HP"Rz*K,⽕7""RTۣ 沨"KfD]DD {[Q~gi2'Μ |V""@Hi- hH ۾F7ED4D2V1S@$k`Wc$EYDD { (bk!/3""RTT:o vT)Es$% "%amvT),@_ \zT)j*@DJW:UrlᗴHQ"R|m@ ?Xg"ILH1HqS"R|}vq5 "-}=pEEDd))̘oh7,i!6&""HH=_Ê,$NM PW;m@-P]7P} {t?Mav+XKaBx qpcc,HS"RF|mlB pfm̭i MNڳug{)п{B~u C&""%ISDʌ ǁo e+gZ75ܸ ΅k0Ӂ$﭂7hi ⅳ})P"HIS"R|m=Q\dS4_?7xm{Vw5Hf-=X)XjF7|J$)i*@Dʘ﹯;rE{dzۺwx\tVϟ~ƭ/ABj@8HQ"R|ϭ=o66o7e}35  GafߜG?}m; "l/h\ߤoPH?XW!L8@H%MӇȂ]/GkPE[y~6+ "%@V6o4g[^!6XwC6oySq`^aoTsiKHey9L460F@2w8 Aǎ)4Wy%$""eIHeoyz, #XVxbfIHdΊH  "~ 7 g)[ËWiqSt}gJu<tTTsWP]K6kBzsZ2elC2sﹷ! "'ymG@HRtSѥ&W+ "\x*ۮ {ޢƫ׶tccYHQ"RyءmF'M$ nJѭSztNZ-?=7}""RTT s/sWlj|psԆRl`Eusteif#""JHpW~- {nCk4:l7CDDʕ  {2i;hcnH ^*P<4 ^_d񡍔ED$c*@D*/hiܺb<&ҌNSƦn{5%CDDrD8 Xy-w:z 'G8obq*V1wO~4Lݪ`;Ut""  "wHۍcvzv+`Npv Ø?ηZ/h7? RN {} .""1 "Ӂ]A](B>eA<M 'eGK>|y^n=1o;=ps5ODS>òˀ6~(|O~&{|t\2,z,ye1)jXhӋ:i;|}$dEDV,۹1۰OYojfW#ٴ6y}䱭[3:8#IXDD* Iaη1SnZSXaRhխ4ƌ|3+%r,$ C3LBiVve.""@l#-s w M앦yNMaŕ^]}p \+OhuhHDD* ɉe;}-e_ED$;{{-\|Y0a@5?zƒTH(|]{/˒f2!R\M9vĐT  "׀`s6rh?ivR_  ^@mI~Ca)|vlG5]Ako@_;"mt~ " v`6_^;_3p JDDʕ ɛe;~cXp΄r}f-|n|s %MXiZǍVQjw=Sg83"""7HN,I?nhy|)M/u)/kbHIDDʈ ɚe;݀ny|A)гsT|HҾSM!vYx6~GS|!<--pHQ'tͲighȋ$rH˲z[?dV_֒ 6o-?lٯ{01~XCYDDʐ i@-mv?1>lUVS[1e; Vcc]kc& ٺOρ9Z֥.qt8b0!]-"RTHKO~1qg*R^}`݇:~.,9m}.NI>Oq:pP>pt31$]vK|*("4[5_7.t"ATHKw4:*O2 ߣU2$s.+UpI[p˩<YDNS<8 MyWE.vѺ(IX{زiC O>߫o;'KE)P>+$$\y 6LὕT4o.߇WD(uuVk h~=wcR""Iݓ1)jR >y{5|DJEde;ozLIS""I0IMMkioB(@>v-4>Nw[JUe;0Ts5PBF"@,ͮKG} @^>jǙ-;r Xf{pdpkU|HE\<l6v>iNX;IR""--K~TK%$sqeȢ7S`3$K a|2)y} {5 nSVd7 "/^ ubքLw$n5V0; x;7筁kSMMЬLv<eq'#C8P%) wPb Q {t[3#&&RW?Ǟ!hV"p9nmuVlK` oq'#S""x"|K 4Z/7>>\< ~ pgw$`e;r4I{Ð,6}}I1kxt2y\ǀw,۹β֎I R""AJ~f*S0k'1$*\q74Epn}ϝygyỤ#/D\7'Lv9  r0`N7n}3/Ja6[~xe1\-Ԭj`^l͚'R4wWs "ܝ{'b1ydjM5[է+3xn5F8:Qwi7Q?4`A#㇘m-`$MDBw!e;WZBhI6`>@NA{ebޚkE8|}3S䡷c*=z3o.O!#y+`dAjfX~RTH (Egv=3`ˎ5Upǟ;xo_fDf["݃;D> * <ȲfJ][cL *VD`^l焸hXf$A8txmmk ~pHg嗭>];͚k% GXv )+{v Xl<֎Ί,2(gUq'"Q""iyow fGo{d3]pK#Qj{S=A'ecޚc/{`)5o-۹ղ;x̎Xs6̠A݆m `j3Fi}nzƼaK)Xl'xL:hHiu?O7J[/Kg-b⥔ ".s˓X SƘPΙw|oBSS>Q;jAUS]4StEmvz~ >6_ ?hV(";xͲIq'"Q""=tX0;4}氎[^vp#uk0&;| ~$-amvo=H-hu56Yk|D$cC,۹$D$*@D$S_V /ŜM >H)iFA{^H$i<ԡF">nNcPkʵ90IAӯ=H jONDDD2{zgއ7D.`?kL/xA ]mW;pV9]F IC?DJu\w "1sI>).bۭG.p7m K-LLӀobXt54/$=-gIDrCviRTH6fĜM>9sf, ~ pZiX+r)WGol\hL:ٲ4 lg)&X|B@7M7l缸ܨ!Yfav:l8yFK=G?Æ_\X|ƴ_Tr۱TW]6nk}lc[~%R,95D${*@D$yog*8atM_ ݔRakm"0^U|:(@ iX |~  fLDJR-pe;GƝdGdF HFQiiEL֤$py =p -I3]vo'K{F2"R4[A Z)*@D$k| YcM_b4OFBݭzuI},Ç$?:<-Qv.H>?<ն@\HysY᧮Hk^;&%@d̲v\G4OoO^dW}Z?c @Nߐ/X 6=Ӗd|-Upj;k35 lqY) *@D$#> S69 Z7m>EOZ)u/vx ]j'> a_$v@[ն@Lv^"QC P@RqʤӰԚI;amG&흺&%)O?1ʳ'e;WW%O=Sz,PE$gZF#T iW¾ht{Vԙy͞=G{m rLL9}A5s)4xd <͜εl'퟾e;6f0qpn&Xբ30xW"ϖdІVDDҲld`0,}l&|d2 cgid.bZns /~)L_>e;,L>;ifY>O?Dq'!@\ <;/R25-4o: c\Ų3,lv|໘8xiG3[v+򻏈,ɩDOhTxc[CK) 3 AZH{ [Hpձ0!A`́-O8b\vDy܂wzqY#"evr[DDvlֲ`>ۿ^ #Jx2-@v6n0 i#}wŷ =%eHm5|0h%M$<77H-$$  < ͲK,Eaox#gvJ 18 LZ HO49p0 V5b՛"Ȝbq'!t|:vZnMx)pe;k1=n2oDEuUfSoXjֲt)y¾o6nF _{qaiQfZʹW?5f ˡa҈̋L3 ן1pxҲܥq'" 2g/ lIzަ/08EeZi=|􀃇W{g&ƶe|# ]|TWͣPVlǤkH\G^C/M)c NE^KcxoG={Ly%:`>~g4uYs^& ¢ID皛JP"R, 'O΀kO*\.OΆmiZu}^[ MiL;[V~_zNqvҊMf+߾icL).7NB  "eȲN}A'? ;4c\lmg/ړm^Eզ3z mB5"jv=ȲfT[38$DH:|rPڢGQ$KiiX'!t7 G8` r 3%PD*Vڸ "/vw|j 악_:5! @[5#T늧+t0U"7 )1R"Rf,ۙLN>x5BO.zTeSoF3u'ǻkf-wfy{臈NH=ѹ* xW-۳Q#aS}+e6&zWDZe;r)#$Ϗosx#wcy+ҿ֫y%/@}DVHM۩VĝD%S"R^F=O>26vn{T홽2¥u pkSlzxHQq, ,D4 Wr6.Ks,@LGb(#TT""zgƝDR"R^I~1o(T:.P|#jl},( MMॅS6m_?T*@DdOMYﱭ/L-)@YkUtv&i$|"~H8ŲvڹJTTSFKR z: Vӊt$'"ؕ,lMMe""jOŝD%R"R&, n^B"7>X l})(iX]2X֎;gO.""0* '{LwbNآܲv:t8yVo]ş8)slk?Z ۏnΘ4*@Dʀe;<#i`;IzEa})3q|@Yù"i̱!oYq,am[Ӱvg[sTSYay]وH t T "%β/<֥l[h &}8(h0si8Z^slDsUn}ɼ`]81d /7=$rPeQwDH lg<Ƕۛ~tԨهt|Nwz@8dh9-}DbvsW*I7H,I z=dho[^; Ӵ?>:.0#WI뷚#F7Wik_7dp(9W]Y[<~_;F"_dvL i4=wMs,-gىĦgG/n^VlN)MHb&W[3y[{tfV.sf$"0EYQl4Q }nQR*@DJe;Á;?u[{GWL/0$cGÅp)9N0op۪7# Q\{Rt3ʔC]] .Nͣ>]͏F8V'R|] vLْw"TL+)E$fwtnU|՛L?| L}YgOy-?;txph)?bo֝O=Qײ*`4~ 2.`9X ,^=΋vlQ7{n}gJ^4"R:n&Ԙ+M1=;;+̴f;1.WwR/\|, 7zBiϬen=;y KGg`#X,=wW!rTܼ9m1T:cl9D5++@d² 0뷿66LQ/ s,9x y{).sjtz|ϝ|Hw"Eb?ॸ(g%Rd^=Vn'gY~$,mS {={@fdNرɯ7oE`:XLQv}<":nΗ1$}rʥC}JCED*e;S{{}I3 "EƲ/['p7E9S:Ȓ pYuro<{n?-۹ LtqFmEf}Ki^0s+DDZl.ܸ({NI3M)"~E; iٻ§S7kGy?uQ\c 929Ȫx7ϰLeGm2~a`p W31MC+րDL# "EIJ'yS;>u;fmŞ=ړ`T÷62&We;0HNM?.{!~VcҔ. cFD$ɲƝG̶5:*@De;B}.X,2o0=Cx_)|w'c}6m͏@mֿ{NB[s׃0N2ytܖ`#cf{qms{ =wqI+ "E0ݵ{Åqӯhkxi*gS]~/}h^fd?ث {kS)l+ͯVaF>6aaѲH>zD熳ɲHv^;L12y[vc }"sFGHl>G76~X[c;?|4J_w=cTGJN>2pf՝]18r1w"%G j>\˷lI?Q,k7w>o8}6@ r>K77:ޛbYս2_j@D2q>L=^KSmf;nfdr֏[YBR.&9dt2s8YգȠ-w9a՝7O[G@ HԀd,9=7fMqKwR_~xڽ^~8)ꎹd[·}f3DR7E왒k^;<ᾎ6KnZ04j@D{`-n(K?X^U}V̷ܴnN ~~x}z֝w_Qo48x~Kk8c6ԀÁs8~f}j2k,f@:DdʜGai6򵼑|>~3;Ik|;2C;X$w3s0%)V׾ 5 5 "S| `=(prէrp>n9G}JWe$ad{5z}%Xҗt c=t/p`p*~OAϜiXsú緝֧yd\O4!̀Lpd+|X8zJr>bA׆.>$Úꛍs2LaSӲn 0] PQ<9vɝ8,k!5 "~`!z)V?u>'u9؜|6;Blg@3%+Z%137GXM˯1Sq/"4ӱq tbݿHi+!zӜp>FJG %R:|x9OzꞩX 5 "r>8+w8,Ga·:.ΡߗI"jHZN}鐖`toP>]tPY?O: s~h "UxpQG,H#;GO< bA·=O{| Gց rW>86*wx8-.Hs^ϒ:Q4j@O3 R"ҍw/'ޝbuq?=iI lϒېfzr>l%{a-5 bN 1ÖH.W9XFe~bJ,Z7'O0dj@Dg`!zS|8ص˟#|xqR15 /¨N,w!S"by z_=p6_|xpu?G8#w)Ws葹sL,X`ԀKz7Pl}Ϩ] )ΘFeݝVEcm@4!5 "FGaQ`QS]w>l|X Qh|0|Mi g@ ,̀tH ;@vm]nX|q\2&+7ƗLYîsd`1AR!5 "StQ;p=.Ko#2XY+N'F{?d~·Ql.K<8,w)Xg,f@܀hCj@D/`Ko:غa+ l/ݒ~˦a_`92 T"P"2 )wQ׬6#/^f][z8fCH1ܐZ@y`uH Yw.> j8_!5ΑO hD:Dd/~#w}·?β+1Qo8>wL6zNf-J׺tϬʠ|!wn̍]Fuڀ<žEP"2·CQMºֵePgKop>l;GF?4Q7Xu>%e@:z?XỲ-u~Vݵ()ˢ-W0Ydݼg͘_ a'{ȊYw;@0=.K(9vD'ỲYs(M?Xu>i6"t ibȘ̀tl"J- :vڲ.srn:j@3j@D֒uas/ZlF? lnYWFg/|x9Oco `uL =q|i㡆n03yY 5 "kjtǪiO, :eM(4QϷy6YN ]uآ2Nd^;D݀0ُC 5p>qߨ:S/ra!sZ~UA17 wX=;ЩY?tlX]Aݿ6젮׆)CHw'Q;R~nPg -p>}̣.|p""ht|<㽵{&W0{detT[tT[dUs><'w75D3 SD|Ư_XҺaw늬!s|X;GA݀86|Jܓr 5 "Kb";-&=c&2OZ;X[ɝ@=q늬77{@NntB6Ԩy1jQm>as9 6}Ԁ5{~;w':o]Wd4O'QD3 25j@Dꋬ0Qc:-.^|xY8Yl@A> PHz訮\eG;Q[S~bPgs> ܚ;Ęl;HN·WQwQ뢶ԃOrX7N=/ә.3sQWdlbTG?o=<"iƪp>l4(F a2. ;^F٬= \ c3ga/`9 rk7 >wQ"c8e⿦XuLG{?3s(̼g? ԩQr>l zh{'vQ{d>#piӹÈLKs|sFuހܟbu{cDmֹC;|=qt>r@C)Vͷa;yL@꽹6]v>섖NՓKޠCFN۬f? ,0Wf@dt/ϝ0bLGذCv"ac9 8רؗ_f@ mѴ6=`K?^Cl;DAb#ZckCf@dT/Ν0ýE;g=, -l30r> lQǾbXcD=hoGuQf]|8%ADJ|82w,.0WZ~^d4wQIzضC8Q͇, s(ȧS~nTK 6gDL`! . ;AeWCd6~fraC꣍N3 h }˗DkH!DJ|?wG}V!ZgPOn>N}5w1 mF՗:}[. J/e2hѻ&wty:;_H)VQыZ· Es\K ہ-s(H] )VO0p`! c^dQ#35 2XF;ŃrǦXݟ;Z ! rAIO%)VˌjiVN ٛQ./|pl{n9sYҼ%sd=!9z_1vj@dtn[>})V>;@a4?]'f-{/sNLofj@dGQ.|!0le>Y*nxa!FD _쇖_4Q5 2T:zˋߏ^CX-d4 Ҧ)p>X_ٻ*w ]f?E1s(}_v4^27Sn(\ȻE{j0NցeN ]<ZSb>R˝ ;1ij쇽/X=;a҈|[':6n@doaDw;9B#3-D:iU!ԀȠ8^!w.NQw)V?y@'N ·Mr05xm_Nۢa'u@ DF{?ږtxn_}2j0)V?̝ [1DͥoZǣcҡdw2 s((|8p]: M{q ! 4pa=-}'#s(7;ُ?M7wD#vC R~fQ9@˯ DD˯ںx!:Qeo]hN{Ĉac9 cyձL HAԀ 4;Āk| 8Ԣh0j@d(uTеfӦnFoKöQsrڣg¨s> VR"}vُ_6v\buk]2w|"wRv{W iՄ奎bH a=DjXu>urJz4wl^։atpȊXj>chzԀH_ wbdu^A>|r(ai4l;Da,/<ư^}&J3R"}nޝ WQ;#jھmwZ}WS"|86w|.6·}gs(A.sٽ"ُ2 !D `! ُm;DA Mk`! fV+L _MG·Y9d60ϝwJ IDAT {;^;Do iXpj@Wɝ NZAwY|xNY;@ar·Cr(䣬 N+~L,>d]!oss(a.+wzil;DA0pa=m>x|vԀH 8wt1)Mcjz|'Bb)1C#{Z[G9u^ˡa9 s~3ZSB֞)ݨWpauul 5whV؟]R &D`z}$wY7j@XI2GQS,|8ҲȌ%WRnn̝ ;^;DFh3zz|'/v)P"%[|^@9[[Q͂%+c'!vŎ2j@d^{Yt>lWs(9! 9*ultl_f/;0 +ZbebN`3c#W)V?ƸQ.#QM)V1wa!dݩRK2Q=˜{QW{{[PgԀHFHeAÁYhLQc#SB,_mleԀHqkُwwPsRh4w2f˩s+)V?(|Xz~Ŏ2Ej@DZS?͛GB4E/s>:whVXÁQ ;.vS"Eq>,Nɝ WX̸;mo,/kCԡ@3yiUA}rL_9i·s(Asd=!| 86w|.>B·,[Kw;ʔhg5^b\Sj 0Cl;Da,Gt,IZ;̝)a 9 $)|-_jX} -w!:'O2v]S"%98wX/zpeMxsr(6 %#L\bE![,j w/v ԀHI46qk3lBʹ8wœ:4Y.Zl`X|"8v̝ ,S5QHmi9η=DzkS2j@g-~a5ekIM˰| 'w\bE!k-j WSBO/|RA})5)VwYzɄΥPSj'9M,7HmP"9|:̺^~:]lHzT8:w 3r(O Y2a}dDJc5 8mq>4wN?xA9sޜ/5פXݛ;P"Y5'œ;GA.JzԪXjyj'. G8€~g\"4FՊ6``! b]k9Y2z)VOQCG9 sgu'[%35 F&>g\7{p@iXm}y`! c9Ba2!Ď Rx2b·ZՓ9K/P7R{a!A۳iUwj`ԀHNQWN}$sJbZGh)6#2, 9BG3=JLD X}Ϫa}DͤeXm}}JE&,S %V;J9ԀH·#r(Q5eni.;s%·}sN-ۦWDrYxRYR!5͂jaW`9 s}՝/`Qk ~\;S"hgh·GZՓy9'TCczoc˯t|V;JYԀ9v^;GA|nX&wlO}_O_wi;GA6NbuSs(%Y~5`j@d46qK׬9^ nUO|xU2ÁQ˚fj -)VBD%Y~7]:5>bSj8J^>Yz>6~ ^Vd0nwZՓ,jZ^sm}pz+| 86w<\aQ|5 j@N LFx&I۰ޱ I7v ZV3`! s"|۾bu[-5 2·-cr(6W/SbU@/t>hsbq)eٗrH1yB3h(ią)V {&޻M˰Nw>|zWXѹ)Vˌjm*!{9v̝ f˯}T(wN)V_ɝ /~Wg|,w5 2 ߵg\cXx`{z2;t„^:ڊx)u>;GanKEf>߉1QʧB"L 1é{_7%ӳ> , '9J3gl;X=;Laosr >G#gJmK}(gP(W·"̈́^&bua>{r(6~vHE&nHըցF. CE:ӌyo&1z2}_2KI5R;mƟٴ;OZ;LNC)`U1ݭI6gvj6)VO`x?,N''[3\JiȨ.ig eXKy12\POE&b#Z[.mP"p>lB}^[J'ԨO|j|5l˯t1o,j@+Q 띀>!9Pr#-_`'%9쁧 , 5zbQk bߙ'KOs·#r(U[ՓbaoX}v~gmZ~5Rj@ r(}Նt0yVCD mSi &:Q#3&Z !yEFR1?i#t,LP{*E·i f.MQEݞ87!$5 b;9 bJw Fss(S9M˯W#D l)V;˰MiV[Vk==3*B·_^mQk QzF XS2ayCB! ranOzڨtȩ3·r(Խ6Rh@lJ0/9=WXS"4 eXKʵUCD˰ںz<}CZB·/5צX wK p>,DKfzR<-c4:||رmIrZZ~զDl;D!c؀P4C j)pnY<;c-k+zhyLO!+A>Nzc\v@3^3iV%2qsՍFRBS"|8&w/5;GAq>eXOkYn>6-@ 88wBn ͂ͫyhce(̖6io)V)w)^e46ۛMw(w , '96_>buQcb3siQ"s|xEbM/Q_L(-_lag @ ̇^&.7?·=r(^b >zL<\dQ-pE&!,j@dN]uE)VOZ5L9đ·ml[-N ,j@dv ˯2%FsdCnI5-feԀ\h>stċQS %·o5X=;G 3&vיKzƨQ?yGCîwi6%' J8$d9ua-SQe Zh9,}dV˯&G'*RLnhGQ39zEb,j Ĺ)VO!eR"pD2-j)V;GAp>v-3;O?Khu2d dԀȺZD}CԴJh6Om jOd)e~ՍR;K +N|;?v507P3C}ò9V78g%M R"k;9 bJl;Daܬ9 \z̦Y;M }M,lǁR߳"75 HMm+mP=L_9֣^,SnBʦDօR2`[ZCXlh)LOQcglJQj dԀZq>(dRSf6֗Y^&)V̝ R_f+;ϦWX ;O -=x8Ϣ9;JۯDDj{9 jPVlP"Kh7N5WX=;O QG9 j<ǨP<O/m! rar j lmTkDvCD˯uy/V-iKZь@O$rl8Ex,w}Ro@Y#h~/O?Jv 0>O"K- 5 N\bC!dr>l3]bQFAUgoӾFW9*Þhhe2ܣpQ!3Z֚Ys(Խ_v~ՓϨHF'{CH˯q!?ԀȚhu! Bero50|ljvdM7/}ǯanG}˜X-BC'Y%sՌίEԗ]hMKl)V_͝CvnFN605z6:Q"s:I˯8jM']]NODj;tÄ^du6W7Xݔ;^.eu4:q/pE!]$7_(lb! r.E"+-:B7X5ԀJ9^;GAKzƨFf!{k6 4 B?;lZ%Z 5 *zinڗHm_CD hD&ǹCHYqeC09#h.Pc~|.sj@M˯L_9PyI[#h+9=9pl(pguGCH D5 |x-9 r{׌jbTk(4)2Fm߹lB·=c=]̩POXM넪˩H-·s(ݹ1!dxԀa!Z""WP(mSAk?BLP2q:.w|+{FCn0|ז4۴ bu?9Č·YeM/+j@I˯,_VqqHm_Kr(᰾CkR~; q>l 9 ·M,j 3Y+~ܵidR!VZ~5F]:d|N6 W lfTk(N7֗g99dެ8Ё ǁ sR2>Z~զWvP7s|x}Qwq+JgԀa7`9 KFAmGXǰ ڦeXζ*<Ï7jХSj@E7]bQ j %)VeΰzNmֹ^s 3Y:)N:d\ԀiUX:wg IDATlK]jGe>l\O˯&M]9)5 #|85w\eQ#pEL diV#F@~W&[ln\;GA6N su 9YԐTr(-)V߰(L;ZrKUbRm W#n sZ ưށ.nq2j@Ai[%_X.;Qge>be9cWקXݞ;s>lNi9#<Dsd=8`Zr}XFCes]b3z볥Cx>riU}oܚ;GA^|xe)wW~lyC˯&Lz w5 |x>ppy8Ϣa=we)>%M'V[R hozUгQJ Ȱ<)V:ѨP\b!`1:ruӚfzRR~=f26D2 YMvGR~\;GAvB3;썦ga3hZr!֑^2۴ b}ksȯX~ lo\,,Ԁ Fw,ZҶ8Ūo'KE}+R{A/ez)+^_tcMC8t?Ŋt`zW wl;DAO!kxt:·oUozP2<^;DA,f0ZrCr#}iV#~9|թF5jpN2^j@G˯,O)>ay%CϿCkR~;q>O}Ԟ^JaE˯ڞ>;\5V4vFx$w3h,klJ Ȱ <7w\,7.{s' }eX_1Ra'.BM Ȱh4`a!Z7s(n·QԒ5iUo.Mdd QGPXޚ^24 29@v1gzIvj@(`! ra{{[KR'H!J}N=uC7kjsQ2Z~զ?5PtKm;! 2|)pe͞;7JwHvj@9 #zZ~v!%M˰)V;H;DA_ُ;:WקXݞ;ȳԀM,v>۶ x9fIY7C 9^ eY@KQԀa`9 rMՏ, 96N5 צXݙ;D%ݦӰ)V1wx iR!DfRoC(`KzC0ϝ p>Ή db|4{7ӕ)V!2~vqBzl۞bJ٦Y+10_:8d#kiR5 =|ĥ)VXr>lxZry/rsӝRԈOKϵja!DV/6]8hFR͝ ;QlA&8sX)R2q?izl.bFp% H#wh5O62gzIԀa_`9 9ButJbdSv|$wh-Z~5q@S ArI`t#h)V?p,-cr(&:[- :^޲f-NZ;ʨf3)sѩVܵ|)wL٦Ӱ)V,;cwGaR,5 s0C1{:^.v\9)Vs2! vCD/ws=*˂·hL7Xݔ;Ȫmn| 8 ]츢ў{ w,+%޳6b\ KԀa}9 rm 멹k!{Cd/6-jXL= }G5jpN"_bltVB/ 2wQQ?XҲaS$˚=wMՏsY5 r\y 8߰f?ڞ>;Dn2ڦYKGsgq+ IԀ_M\jE H)VQ};@)r葋S~A]~5(s"P·g\~gKw#r(·r(V֞ѻ·3bX"k?jArzh{ H/mZ5q5!z/wP `ՇsYj@C˯&oHbG-vFf2R;0w47M~Zێjĭ)V!6Ԁag5s䙃Ŏ+h e>;GAޒ;DA7zZu>xu~ĝ4醵>t6-jX}n)VOuP쫧~N5 nu>lhQk@X=;D.L/c[Q͂ܓ6wi]ǮɅ'j@ |ؒz,27zZG}&dpd`XAӀ-;WZ~%|oٳRn1ӯnIFS֦eX~/Q wnC 5 ˻?67z^s(A·r(ھ1l>uXӹC 5 k(;G!;԰^-QKC9tuuovTJzG H6W#KS۵)Vwn2ђgE{3}%!D֕ QgöaVB/k)ks(·WQW6`f?,apLX \fXd4J9SyC|x>YQmm>%\(2 j@ʵ/YפX°ۮ0|@eNs>wr(GR.|xu !Db_% 9vhUo t:J.ẅ+j.d9 jky_Io)߭-.1X`X. m̛ЭOXj]5pu;#=@·]Q/X԰_bcCl;`! юjkMϥԀQWxU,~úni 8;G!̖_ov2wb(}4Qς`! w}30fvo!bA HYDSWݹ:!F3Jmm@o͝ 7Xuun>o hU)V7Yr>,N5 zY6ޘ;GAvw>.wk· ɝ0~8v`ʬhUD HYtar[Щb3=\;@k,Q%~AGs·=s(N%)V1PPP,E͌ 8^9 898$X9-AQR7PRaQXSmHՏQ#r4RA{fz `G^Q>=[d`ԀC˯j1wb e^;DaXQn_ݜ'2j@ МuNΒgrs(1·s>QEQþ]eٹCXSRWYr>l@|R.͝ '1W)zg 3G)ͧSQm~]%")߭]beD0-V{kdyQIa 5 ePRxz> ܟ;DAnN?ȝ@קX}EGtsgs̜o̝?>oQ#R[,b,R͝ ѳîexe ;HWԀF`! pifT=ӵ)Vw120gMDM@-;G ^;4wBhՔX} -w\W^/8g]9!D$PG05)!FJ_[6ptXQ];Gˀ;HԀdܮe)VOZ)"Cݴތtp:9 WdWw.KA"]6:;ZCI·vΝ /I/?Q.\)+$/-oҢUK-j ăCޝGUFႌE"EQ".[QuEʵ ( b!8&0_0LCq~>3|^k=+)],W1/[gW6x7?a L[bWYɭ=u,vZX؄[D:No4سOs ŃKwT@li~b+Q)fu^Y Wֵp4[.l:-=bs\hnkC4+}Xgir ŃKtj ~u:+",q9i;WP|w>^1G3Ń ޕQ28:D"pEy myus}!DovG hV:HS\Sɖ/2EwWT@  h ufiCd"#2ѻ :HT@ll^~:?{!(Wz&9!D|*ny]cc]<0~H蛲 nվ-hR " lo8gSX"uS?mZ_Io | X8N[]O=v!Տ}rn1:HT@l<c!(A-h0:H\Q | 88N\8&6K[ENf(_ laXՏ :H]\Qt i n_c+]rn b[RQ!* |pa~%r{>jkr|Տs-yqE1tƣ!DrpEfR lu/s vE.`[oCXQ_19X)kB+}і%CU.666v^~!ZX܏XR+ʕwX0jt_ˁ'C < <`WE=ޕz X: +5d;b7X(MrR ~VZXϴ!bI^}?rsvڪ!0>:X,`W;ѻ"mknN0G󍠥?:o12&!bM^}_h |cӬC ʕXK(ޙcvYiz ZK+ClKY^;5DZX1[C4 H3ޅNo{l\2H2a(Fw^-ɱDB&(7ֵaDOڴjcӭCPRm۸fkcqa)"Ii̧-7;# 9,snXi!\x{,]4CH*RcgՏ]u&Q ލ̾lBƋä^r uE?C-w?D-XOw&{]jRuE*s;!DF>}^.E[R75*R32fV?D@(`P?VO %*t:Lr!eꡮ(|-:HcK`uC)NX=.NCw?kdfZY zyls:.1۳IRrz+=/!T* Sc3ѹ]i!r+U!Zy* H* 08:1xgu餛q~xKmwS ?C4 H=2tYnR V$2~l |=ѭ"B$3W-sJ6`L9mN;.puIE8 X3ܶ8:Hө9uC) _ 2@*)_I=tWߖ I0G'`!oL9')gv]/C H~[0tg}ZSވ? \aCZ! s@Vy%ǥ~FT@:/Qa} ]QfʙryN$T@1J9m6>-9r>uibf{" sK!DB$JQ@6K04gb/Cd<@u?GR(wN=#~nBMT@ pސ`Fױ)kpH ٔC]QrfǜcBMT@k1fœFO0d 8:Hۨ-Xw%cCZ1񩇺<(SbC H~}]#ќ>LO!T@eYnꡮ(7=#ښ&BT@2rE=1Ds>{np9&K=hceI=Cw?DV H^}~D9}] kBAET6ࣙ~>5ܮ&DV H^}~\QE]nBa,@" z'e(|-!Q"}W HMh+=bZF;+J~>X:]d8` gTm4CH44ufwhuHdh* yid8}=puEK>|sc+!'!v* y Ջ}ݲE9b?1[sGYk8}|{pui$*u3IDATpWro!* yudf s2.dI.t2Z)>m2!DB$TwqDOeb 9V,<8,r ~uPɫ$п)1۬CHc/W{g!/!%* y$dOOβ w-]/%vLW;cr}FG!5* ye ged.puisH6E g9?Ts:o!5* y"$lYM6)uim,燸xmoY"!epVJY&ӐuIE->;~rCI<@Rnud̈́{$D3!Uu$=?%?#:XD2Pɫ$ Ȕ|]n%i<խգ |)_ T(W.v:1!DJ[R^ N2x_JB|:b:>#@UE$Z@F -pwY (pui%7.?Zz`? dQ|Rt]WVDFSmb(|_'[:i HSlY!1sRhc)[5 8:H%T@r T3 !! ybw>~ Vgw1uH&"* D7^'c^~Ȱzh# 41,\AoX miJ9,:gkBmP(Sf1mX>6~NJ] % "}קuo[3<n}09u鄳/Xo}+ʷP]2&-v| f"}`hOH=׈_I1aGn:YM15|u pu H^ӭʱu`Sa6ed" |:D U ~u~x2T[f[\@6pEi Cc#(?lrv.φ7Q ΍Jǝarcty ?_oB+Wbi$Pme2=T>u-"}L.?+8X#d4d"fePtL?dg\Qڂt K^ʹ"W* y}dWGf(C;r}NBbCH'M~ bF?Rm2!E(pޭ뛟b(bH$u]ks~H .`'W!Pۯ$tWsۘ_4nn?gj9\88~Ok{Y;!syY ]Qnh?SmlS@4vח Ǎ-m_itE p:/uc/XQ###:T(,1->΃7R̬Ų4_ߗuI >;1"'އKsg_,/rnrڿ?kBDT@rE 0<|.zrE?_cxgSDZQP6y6uQڇcDDI\Q Fu$ql%!De6 _gDD \QB8]wʇHhi~wYho ^-WovEy"i|"0RY` ""uo7y 1/8ZN +OX+\QIub*!*97?:,N+ ida|ppgH縢kՎՌ4Dt Vf(G/[gibZIap;,1hDDL([hUBD\QtOTjWA31SCe=&uEaDD^+71pX6,*"ͧReak]Q r4+uGtjѿ"-X5pE!uWbWY~rE -UmJt""N&(oGZɱ95]. an;imը,08+1Tb%:k!.Z+ʏBW77`b]``~]9![\J1:,;x:GG< << <3zx0Hjc ;dpd41z,`X,44>""GF(o!"18?}A(@RHAӓz]m@DZe#fhHʇH{kuiCh%]6(r* x:(7vH 1yD,APQ EW9DUF&mXfӁb3pT@wuiT۰.@'I;snPC!DUvqECb3#Ru٠HwlpYX":'mX6?:bC?JU@&'%?ZT@ mCDZm(v`yDrt ^7&t ."+Z X ^w׈t q<"*Ia%b𳬃H* FbPDdYm%Ui>1x-a*  "j8Dn`SAD$/C1끋sHr԰Cb H {"""<6ޕhaI<??:CX 9DUR K@/gb[41DUtECbO!A"Po""Ri˭sHkha9GcX4VADdy: b@I_bDDl4D : "\m!1 ,1x1f*,}6,LADĖ H'[H :DDI{>&X{* spui\k!1`l<"Kr7! H>MOVD䕬haI*:4 H:BmX1;R8x_ q ",* u'F"jrD " :4 HCgZgFh9KfI?)D ~ui&8:4)CɊ{v""ͦ|n!"nW$mX"voDDOmEDk%DO4KN`DDAbSOPYTa&%p-k  "* -?8:4֎(ߜhaɲ8v󧬃HH g?[J2:0 x8,g ~uiuiT۰S̒ιx Qi#3CHlfhtvdF H Gd p[YzE$l8:4J@@/ >?:t H ^:4ƛ\Qh8`$,iwgQisv,/פ%r9] GvT@: <RDc(S}6xT ~aDT@:"??(q{͚讇l?:t H';w[gSa= \b4T`!1ǬÈH?tP V`G ,"b森($;AT'\]bFDEbӁ{&u10=, pu ~\ ~u Q##zg\Q~լH?b+ |6,18pi`m*I?: pfɊyW!,Y+-/Dt\/b;FCSNKqY"W7#"| )@YZ:#q$T@\ժqDd]WA(N1Kh6p!p:pn+Qer%C݌6?0 WkkJ^0 0qlT@d܉jEC=692bA(>bVO͢ 1ep(H穀 <?A`]D"*n'9^)f-Te b3󈈘P$\Q 6,Ŗ1r4 *W6#"* +_F8wt \QbVˍP] MS4 dT[vlGu;) 4"gXh7M%""* Rv e.y{ \QF+FNz^joMDV  ::rs2*ɆT OJugC$>i6<8ł%?mRDT@1bӀiE{H֣*$/FՓVR=9tysy_9bோ^BD9KDDDDDj--"""""R FDDDDDDj""""""QڨHmT@DDDDD6* """""R?`p&IENDB`hy-0.12.1/docs/_static/hy-logo-small.png000066400000000000000000000454251304171765200200030ustar00rootroot00000000000000PNG  IHDRXsRGB pHYs B(xtIME14 bC IDATxw\e?3[ z %3WagvLb^^ zի*v)݀"V$3zZH${ $ d^ ۦߧ?Jes[t&ܰRs #OT}M1(U..ybsuRYܼ&@^+S"+|A2kF*kd|>ѻRgڌeW LnOs$m>DƷ8}Fc Ǹ]HgsKM4RGpi0'ԾaOfa:qX{C7Ů{$7`33 S\{OK*]hnv /uYo+~F:۹KM: 61KltX[ |fMOijXk$Z|]e⽽݅n%逧엂}-Rx蘉xS 7,1?*Z0@Ărwqq:ۉ=o&@v^ǀ a@[ {:(8a6of$5<208|X)> .؁VbgS&ّ.죂ˀ$U3&K? ;6l|Xim-p~X/$0Љ` uÎ~hyOegj]pdrT$3ʝn}Sėa 80oAƒWG/A R ޞƒLrw3(Ϙߞg@md<OWTxpJxOa0$!P?ӵ,ɨ/o/6,I}8d7_3p`f$$}G ]_-zjTtS s, %vm&@Fu%O_@oOf<}'v[= ݁vy,{"R᏿w0}۔X߸vy}?Ͽ͏RQ?33@o3 Ky*Eii Kx:l T᷽n֚Xv'NjMO:UZ՘6㻕mdr$'CMxA]c[׽P. Lm-Ǖ?dz Q3@8xx@ZL؆վ 7!6:xYE֮\I Qu{Vkm]tZe[D6lSg829I[y'߲П66#hϵ/C<M<6{,ֹp^Оv`|43>ݵ~&8v =k뽯I`%hmȬ3-iK`UԾ_>׼;J(/8G.춖\ʼnO>ԃs"HkwKKnOk~s4x6MIer[<ྦྷ۾>(3A'ݹ@ϛW|8E&,B~)û]L zÐD|19,?{O~Lv2֖@<w ke*ă?TsVfv75;@%N3+XΣܤ޹[||Ɖoc)7 f/<>wwM?Y*~p+?O\/`HL;.\=“Ig7/[rwaH 餏X:bWa&<pĘ6GaɽF,9eaƶ: *_mafoRܒp@* ZkgB#Z t1|J/*?\~79aКObM xUߏ;;|^!}ISB*qd2/%ikfW |[7U9>  7>ou~ïz$:U¾9@[̄wy=/_ȄXaZ=G41y zU% L&>%?ϛ|< CM6,-v՝'D,;ڠx>|\޼EZl?q# NmkO >L> |oY5n5ݵ ȗk23O vY(\;!|j{%!%p-09^3vmΉn|^H80]xm[7݄)v6n2Ot6?( 69=oM󚽷*}z! Z9QRLrOldG r7>u76諟\ljo=_D G̥[ nx0a88xW1׈50|6Uackq8GN[;-dѧNX-HhVJz{/ZqV9AqR^Es{͏uW؜/q:ʙ5n+oq4A3Bj~iq74o?`}YҚpٍ o6a$1'Ց䘳啷CSٓɱ,h/A:y8ՠWW}ϖZds9 7p'{OkҘA8(gݼ"`Qm}Hef>;OcϘL1ƵBd{Yky9sMlfw)옴#RST_ЩdGӒ?"S-ܿ " xG3Ӹ <ʦO.SZGx̒ @B6´ Τi^(AD8mCpԦ45ȶZ{ 856޻Cx|v؍@FB]{ "xb6 vx718zZp[4>sW{;9kp4=ƶQW-;a !Y h7i g|d}oΰzkʏHQ _}5jp=wl>a|ah,c˫<#AQ`-Q_dH:vT3y z3"K+ìAG0\y oNW C@d?|wcpW gp~e ]dhkIcYI I0'XR^'\ O<[ϖH +|oƴqjhsQyf!a}+Aa̐`Ċwjްtƭd|-{K?%`U} ԟu-CPrЦ*uƇ&*3*F_.-۟e6v.N1Kj[g1̶u>~VaFPX% {XZ*<H$6y%aU_z8\mm cbtGzU'9 TnӘVѿMC̤OY"ϛqCx=94}Lmh76lѕ>]2#hK@qOca\}fwr| \. lݖ~Y3/ӧm7Uo m-Dn_T-0t \xdf܇No*Ͱc~m}mu;Y`6}7V2]O|Ωf:q8j]^:{~%`%AaI4{ok;s ,}.ٕ< >Z3\~Y{2p'm\w3v=d 1hMw?)[sC@swn隺d0C6yYuF{?sϋ:`hT*ۉ0/||F\0ւ>tomwiMexz}8<@n:] -T t/"ɽ qi#+t}~d86ӕ Cڱg#0qUkY7'JX8q~{Mw摼j L|p^cJ'fHBf!*;ĩTs mMR;bfnR)ܑ%|-8*s= a*=^N;Hv,/r}Rv p-T7sζ:vLe.I]z #^Ȳ\^S*7Ysq<: @n}aw`Q gg!{ rO8AR؃ Z@!5X[y՟icʵZxd yBK=/m7 l/HgsI:_oo´'3mHS QѠv~֧/,h%dbl_ԣ]O'3'D=q^a5aRL[8N.b1cr}sR}|[Tz7d&?NةE{ʓ![Ծhh2RT|s5*W|)EV%7 3'M,ܽ8Ee2aF(̤2 }LR{PcVΣ~zJnNeDoMct r=vƤT&U$^`GT++G-o!VYF֟~Yit&3h-2k]N` ]('2Kerq4 k,FaHLv$5,ęLjR=>7bUwtG~7;A*yZow I^U}B¹j)$Sa.l/~?(O1m`}I (yy065MaP78=DfXv̮Mg5F@ߗW}XBbVcvTuaG/Is9g@ymg0cdv6!FDy*9 ȉȟ3=]̂Lbjޚ&@A q8qlbГfۖJ/ok F~vi;{56E{#eGhȁ݉QfrcEM<Ǽ1cA k؎-qt]z|eTV+Rj4Vtl=:P.-^VfvQPEsO9&@WE|\uQю|dJOa#~=O>Qw XoԎ׿ o{ASK*=]kkڿs,0/.5e]M668Bq$?~tN`p'.uS,įS1Hf6h:3=#xYIπZ+'@*T0&s(&Hg5TuF56B/#u/Lz2ITy [aݘh2xY/"YO X~ލnXjpFɌ5k %D/O|`v&`՘ܠ-w/z 5so/I垮 ]w˘LHd >eFBIf ;ppPi^;졑u}пmVg#ZޣKϻ_x90Se=#o~ߪHm}GXL0)֘LqqHlbS. w%rv_:c:?H FtKf[0IfY'`o5pHh3<1i;Efg̫ӄHXZZv3y(;}˞oۋ?Aafv ہ!M,dC&TۇI* Ւ#}^rH`w naĦD[^(_YBgHg\ OHZZOJSX mEo3#M3a7..<8?NO)ZH)VG z'B*"x%~t?9AHg;_81!Fumr;Q2IM"WP-N7+n>6# &C:*A8zcf*ީע]~K9@~)idǹ{z^ȑ}{xs^; I tgUwľLV3io2o:Fy*B)nZS8fuf;\ Mz-_5C"n1{s#xtldU׺$={̽bfr,Z\,Al:-}rzA[SMPAMܙ&mn7d3i0u_ AW)iX:x@>55!ͽѰaoF Nܺ&YMLX=d fT+.:s\ .]]Bn-Z2yb6KWlμ;2舴H}JO׆&@ {И`I/I*"$e̞Ϛi13CL5/U~lCS\lVM> 0. >\GȚl,Pt'HeI|b,t9܅[e6$?:-2;!5a>ۀݒέn'F Io4BHT^s eJv_Pd\Z=|%in\)/do2[^Z;D-Τ]Wom4={V&Jf[#=C$#U9q[91˸!ѣzfmJO6MEkZldq TVZa)qY{ޗr*j yHJgr H[L[\^q3kY]|0߅%~ »ln_dyDqzֻ Jd ]਎b-v+m28,(ȵr$&tG~VhoƢ8|Dz'+ŋt舀&4ZN6=I-GנP#,` s2R3.>sa+fV1W/ ial4ƝRa~`1Tg *=eSia4(g)"` x_ 4]0 5pe3L z.pV` "e*#͏{K{4qHu7tG>u~ҐJh8dW|wrVm/VԄG((2畞bH=hD"-3hTJŏਔ+餘#x,+1HjSZ#b ;|TN~~2;f5 L$ǂ|T*6mHh';rs% "u~c 3 Û@7:$rS\g7+Y.\_wO 3[?8Lݒ&_3MSaX}q 0voȖouw 4`0x…7.ᰕ+Ç|aTzws `0F.:Iݮn05>3,k/ءg~e9s~xHj7*ka g ta 9j&~ye::O \2Ǐ_w1i7j;f~nV!6Rèk9( iKʿ }}l P4ғŰڱ g3kWR\><툣;}$q@V/~oQSKgcbj8R肣A:v4PФ0ȃ\.p =yڢO K o5/OqPɝ} +ڰJO=[ړ]{Ar`2 hd䰀 kGIlo6^^@c ]vuHQy)O{CɇRȶDsrwaMLg; ;HXT9kD&V:I3i[ rQ垮4d6S8AX-ӝCI_]iKD'9ό=M[ lZ_]E_nkFؿ_5cQq3*" Cº~s`#-r{i*g.N[}ʰ4i]|qm;5yZչfw,.rI|$|Ez_gRX]sҙN*EL9vƽߗ\?σ mx5!XZ6 .PZC$-kb93OHsyW*lrfO[t^ ;̅*oUI]Z%²k߇|Z\"Fxge9z)"l![diЊT6WՔ%G -4!=]XB7_uIwkhw]X4RِE#7Ϧ>AϾ˥"Lޞe>xh; &vW=viۏEx63[f+]Q1:&1OQ  h1pk rߕu/o-_s~ykwdˌ{mIz̖nq:_ K` }_NI]PR8S\7IYtG~`f,.ѡνLt tl2g_ә/ Ħm婻IS򔻋队07mek|m7^VEȹ{,zUTX:8,8Kj" EKbi,Zf 8Jrւ$((0wTTsDYLVDԱgHMu?XQɗS- ]ޙS9aI}cMZZ6);~7fkY-0b)d5F=?=;81w+ 7^yI 7񭍪6wfW ,ΉR)Tc{0{,DG qvT7rMޜ=3δJfsB X=K`m79#?d]1*Gf[*:_A!b! bh$o>fHkBWbГV(=?$'B13 "f샹~(C5Bï*>1%hW, ~uDoY!~ܻeJhk\ݵ̮ǨZt/oq?C+O~pFa|M"JÌĆCb5u/hz8!0|+?N~dQe:^g"a_7cM\O. q!]1gM¯ŋȼVOk:/]LT6w &v6"պ1Շ5T'=]k\ծvLtх#FDc+_3: %n_?]dM ݞ$jTZWdwC#"ᤴѹU( MD1E001c)z´6>q5_H "(_i@9L1ћ€VHJʢP&ϋ+fYT:zތLf^kU}08ӹ\_!B3iA Q<5+ſ9ӻ T&O"1f$0Gؽ'e$Șb1G[kKn{3ߵ K VpyNIT˯!O] |FEVK/ӂ~B2;QTP2N#0[ -t=nw<6gp]F+ ^E $%( Y@Jery<}y74-'pay8pfqx}Bq=km͚`Yd #$4 η"5K$_m4 {ӣiZF${20D ^ʒ8=Sk:4Vj0X-ǷAYAn#zx^)2qPl4z7]# ltGx/4)*uW!/=rH["ii() \6(/궼ЛCvÆM!w'ŽºRTs}RhfHTb0 +RT60WژDn^^kDck2!v6_9M/FR"n1b`)Ʃ2?Z=lfY@tva\'YEϯ>tb|Lha}rwae*JMǟ Ms\Ss[H#R`8eXxRzh$=S^\!CS0֒ ^hXvB {(-[x¡ɎQ[# 6d^ X[ #⃄w'Ě]}`YG 7FG#ɑ=l~lN7i #?\rw\`Rhw- irݲ%? p]o&ְA Z!=9{8c])Rjyt6?9;>H>-LnÁm0$0Kv!9$;Ivi[I%F a({ ֗k$nY? ƨ|wEɸq%\c:cYCdRDwl\*<iXo8ѤȎt [X 9Jx-I &}`N6ϲifv9 ZS Q/s< ".Q &9~N&7tl؃9l7¹/UpjnB'F+R)RvG:]Ug2qaryowaYw39ҧ[ cDs_#߼Yfj]~y,w c"R0Sf+~dg44'BIXgc#7I|lҎn M]-_wת7taHd!Mȿl6Yո1?Rگo pnAԼ7 \*@_|io3|(lx]P)KR9*IvtOh^ ̂(&}&@6SD A߅" 9UnjMO45clŁW^|ɸIfV-Wzr*=E>s'>cpDǕ:`$^{"fw& E xִ3L1lJd6.ɾǝ=3 IDAT'~\vki-垮\X%+3PH$peNnz GF qqZw??0)\PԸ\*;ʓCoRXowp>vk5 IgroNsj4ZK'L%18J6A ݑJ%9'=3?K WGDfªT6Oa&K 'ƒ锎߁ɨwځI2垀4 ưdJwWP۞kax׽`8U57TJGѹ?Riaf{xwcN}" &6z]xцh wvN}^!c 4]&epoy2Hngw0Rʕc ;]Xaz>vRNgvvAG?0e؆< ['J-rO;Þos>%i~<;7,Vۉ5g}AoWorÕȷ1 CLF,6&'gWCyV-#lyo+mWHy]9qD)t.D2 ?7;ُ7]9;bWA`[HuU8cMP7MBE랁@29 ޤ)è5rCp6 tqs挸B9^9|hm`Vyd#,@AnizcY_"s&FBvAgLI[0a|뢡!֭{O#JF!`(ѮԒ;-M0zlA'w"h!\>"0(bZR>Eu. @B '؅T}W!}ڍ؜Gj#(P\ $} &HǠT1q~G %q:FNc"WZL!#ʐl{"i)=9?,z>AG \k4 c0=])_m.Z"]n/+ Js/| Uu0Xj J<@SAL5Ͻ|jƿ+Q)wO1.Z`dRwk]Zb~IENDB`hy-0.12.1/docs/_static/hy-logo.svg000066400000000000000000000330551304171765200167040ustar00rootroot00000000000000 image/svg+xml hy-0.12.1/docs/_static/hy_logo-about.txt000066400000000000000000000015141304171765200201110ustar00rootroot00000000000000Hy Logo is TeXGyreBonum font with the two parentheses, and two copies of the lambda character all flipped around and rotated! Aside from the font design (which was not done by any Hy authors!) the Hy logo is authored by Christopher Allan Webber in 2013 and released into the public domain under CC0... see CC0_1.0.txt! To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this logo to the public domain worldwide. This software is distributed without any warranty. You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see . The new Hy logo is Copyright CC-BY-SA 4.0 Kenan Bölükbaşı, thanks, Kenan! http://www.kenanb.com/posts/Hy-Programming-Language-Logo.html hy-0.12.1/docs/_static/hy_logo-paths.svg000066400000000000000000000142401304171765200200760ustar00rootroot00000000000000 image/svg+xml hy-0.12.1/docs/_static/hy_logo-smaller.png000066400000000000000000000074211304171765200204060ustar00rootroot00000000000000PNG  IHDRrdZRdsBIT|d pHYsmmtEXtSoftwarewww.inkscape.org<IDATxyU?Rq\p)Kq+. ѶZ6m[Fqkijk.ՊZEuAH*vǹ3}_~3wΜy;ۙ33Kg+B9h$h$h$h$h$h$h$ .8d`ͪ:CtI숈}TƨCDz?~lxu{lU: ,`^~f|[UuftJ#Ed `|cY7 ' P DM@0ZD6nRN|P;("~Z``kg\ l|#򡪹 @Sbҭo̭\τHw|UUA5 s*VS}x oLz8HEp44@{eCOkL:UkfcRlZEdg๪7TuPY732fCW/Fgt}Z $/o2^Op-^ ٩D V [~\ie_sYF.Hoi}EdiT^+ŁʰV(K`EDf`&,"r|GDzGAU^8|VGY"qdHeX <_C;ۊXsе<: 3 |8  &ˇa%Wc dޓP:XuwevBB|^#k K']@'u6A ~9D^"y2;@OqZFK:r G;ywp г& U-V^%W@¤@{))"#QgPթpi`:A[%{Q؀5PXW`mPg7N}ke7=<݀asU!"GD.ؼ<Y("&;jlmDd"}D.  KGث "]D$l01k6ymSl4[D*[ܞ"B}D|VSI%Tά4czE2HcBdt[gOĜ^:U.P؇vIV u̵3=sȑpg69*\ey C@DcVzmY5}/Ⱦ:Wv^G_+߰ѫ`h%rl|_Aw 2௘nYŚj -":Or*>/8I꿓,pEsdȮsObSw`)iC+;DȤ;hXSiU="R9=Ivh+H$i}8(VoӪMk6%-SU5RSZ<<(W6<܋>U"rz .|~^)􍎨"iqOm^'yxCGDbvjuQgp@gYs@d{qCDd!3"z Z0oZ+@j9kTOΉyD@xWQnfxa !v^[yT`:SK∊Pgn'RUq"5v (^+]JmmvJ2^1B쨒< 7ǯGd<{"_f?*2?q=hqb|,!SV-Q' Zj/,N4kH>%/Ff"">dzЩ꫘3%2<x%|6I\$W޼W0+X-RǞs n׼Dj^sD"+i$fȌQ)D>"u(qD q8WsX&м꛸2D-2}Hi^c|3,*&nc.H%U+Gd>O |LJ껄z5Jl"bJdHfoL1zP?YJpրj9? .hi^(_F9y sEZO'gN_ȹ)D>n f@T; xVt<;o#u>ji9]>Usz[+S;Pmľ6ZdЩ$,JD "͵.lOyxR;,o߂^3U-E$j~\'[;vr+m~y xR|sP~?yt S(w>:GJ1It7Ug; mH'͙6}ZƬ;{v D`c+.$2#UC@Z}ZuEdNW6y_V`jGUqD29Q<:,dzI(Pr?H3"<гp#z^#HŁ<$_ࢪKD+{jLdvq)T aMæQW?"fׄ AcڨkHZp8/5>gtϦ#lW!.B 2F TnעBۧ Z. $"7Y"r\."/bǽ[.oySI:Xn,ULD`\+#"pl+ =pOI>'\2}cG"6kvv붺ж6Ջ9|? niW*<$҉kG7۪:Z敹hIηBTEacE,A N&gvl8C;=H?Fܷ@QzpڝRBU4U}0DL"2[Dn udr]淔#vP+|6kvփXKH<l0NG:d_WT3 ׏oi\"u.P|Gԥj"µ쿮94yU̧9T#߲,\ƈu:!t%>u)vF*=;Bjȗ "23?nxm F#ع5>xFUK 5F`~Ai˜Sx}Aa_D Uxw h>fBsz +vx蔎Me+ƱDHp9K۱E¨S rT9}[m̈́6-ӕGV) s{}-u!`ܕ҉̔9suczW #ȶVv OG\՝=+fNאYLnΉŻmRk9DdsUØPu5r$KY: 7M!GH_>`\ݡvB "WffGէ7::-tZD6 ZD6 ZD6 ZD6 ZD6 ZD6 `ܯn=ƤZIENDB`hy-0.12.1/docs/_static/hy_logo.png000066400000000000000000000353361304171765200167570ustar00rootroot00000000000000PNG  IHDRv-KQsBIT|d pHYsnu>tEXtSoftwarewww.inkscape.org< IDATxwU?ߐB%@ ]RDP"(ꌢeԱ 8XAtTd RH {MY?x唵'pZ޼wגQ( Hll_Owy\jf+Xvϡ"B$ xp &`M= ef,)^(:B b~!ߚٳ ,E B|3Lnkfgh 17} mkfxEkhE ˆHZn4I^z5%U/dvI+)Y ~0)`Ê3sdvI;;, ]!i-B)byxTBĸ$  6n cfwWUX8Qђz1u!K jue)} 7Nzm>,I+V::b 㐿+BC`'༘%k oa/ńvx'Iӫ^H$vIo#E) ?bߖ^Gl \7waS`Mqk $4-3,z!U*Nڝ.Bh)&pvI+Vk_v4~Ҫ׀Zޕ = Bij:fIa-6V1B3h|KRU˲uKIˁ-|fkW Bri3ͺ x X,Mb-r]?Li`pu8. 13)`"p%p=1$M h6~h[Gߨz!*bU0˵l #i{i/ggfvc II~ʟ63[:v\(Cl?:Tv^oJ:6@,^(f}en! `ՋHIG{vO#x=նBx$M 8<U$tE[E ̞4wνTrOzu>DՁ[mP1'|_PA$}}fN'/-^(0/xߐ45V.iv;=4v. %8zla/?*^(F3Sw=vo]63:x_Pb%-fSEi'bE hcG+ZŽ^UowZvI =a:P(fvIg+J{hmPwBЇ٩T "iNJ|2f]D`jfuBП+p5~#ut&'uBЧCTe88Ѵ"o]P()fwo|}TL|$ZLfa + 5 ). cEo3Q .0{V3ua,a? E B|Idg-Qػ:kP(mh+L:a={ Ba0? %mZ߮K;.[( cf_OWkvI[ta{P=P튑"nu(^(1/UzJ] F]؝mfWuBPx72Xf1KE쒦ӝ/nBfBW#Vi åbvfl6 Ba8~TC+1 {8LP(3[ |ׯ^~;"E~_/ 5 4;ώyӦvi{PH->Ww 34b6Z) 9]yofBK^(bNn&Pa]"B=NfmK`:&F$IIZ_ IS+eev;8$϶y䩤` 3;N!ie`+e1+ yM&` A$mH8 i5N'.q=*l|M\_\\֤#Ӆ$||ȭ2}FmBKJ`b̷'w1u@'%!bBa>8s=CvzxZAi"$BvH (zfvGF-3@`'}I30nI09@1vTB! .+ϖJߦbMذ KvM atDŽE(^B#fv Į~<^0ڤcRg@{:;j;20ؙGK,-"W'IO"/W$>h83mq)ڔ-vLhPʉ&g7")`fɉO'NEn"E 02^R*aoj/uxr0 of01J9cXƑF~if9ګ3[df_'"*~л-D`S)pU,YcH-FG[H' a$ؾqy3 gMm zI#Ћl^6ᆎmw2[)ƙY>؅BKH:8>% 3݌ HccvOo{k(FTੌ&UB;4Gؽ(^P84AT;f ՓULVGx4IRyy7A>"j&T͗L> 8Y=p#+)}Y`DXCaӁI\*Ęٳə_Ra*mJ!)FU/Ftkrg/]ؽ$m !騲C{u*ad6]K^!&H0PTg{1IfMǤْRSzྲྀ zIN~tg)Rpp|  ;1O7O:^4$QrD7'H*|'ϊLR ;ƴ*8 B-o~S"fbf ms-Sݗ"!W+PSh&Of/֯{a3[,-TGh5xFO; X*S҅fvFk(tY _frI}1gRIirۚz3Cһbaj %dRJmfwe[3{Jҹޙ\#<6¾vlϻSdObfWK_cf4SD=23̾kfo | .aRA6Lvo:[اHJ1f(asfOzsfS`sBt4땶N,Nrfv8Rݟ{(S "i} $O 3,82.(~$%)6O<Y(nJn"> \:FfkIۉA3~Hőf1G{-!imaia_#=)qY6k(8"i ઌ.NYP2pn 1+[K x)ʆt1K#I2ݳ`fOrI;=2j́Հ]͞af#bfWK|SߦR@=5[uvO܏ ~;{6uv1_GICsIcf$0U+i3K"UpU{GBah¾N|I% D_ԇc"&KF] $}R |'̞!XKK mW1wJOt9.L&D?Ji|I3{@"Hya3u PRTTQ׈}>HIkȇUJ^P788**X@-DVž-l ?®+IJ΂J٭oaߨ&]2{q@oÿp2NPJHZ .!_C"VΒު%%4Œ^n\loէ!܃]|n]R[f7p0~#X>v5b<}I߫I6'tH< 9ˉj7wˑaQ4 OWz!C Ewƃ7fv'+HOcr zfd.+c$mDuώK){{ܵHZ=߮gK`z5B^6P#}sΛΙL}mtU "b(ygB)fhfl piG"\K^Ly?¿B B#^[/j!fv y[> lm4wV%MNH}p6p(gfGEf`փ_ e`f|xCU}m_mpǿp"V3=fՁ.83ۂО DSrO]12&6;%N<z1J$.? r+lbf*wKo&CIu=6,fva'+RT#=Y0g7C~Nx_3$=?dYScpdfs״f}ֻwYoHOc]o񫅰 ]4s58"l _eFZ`x2+fv2vBe'&53)aj$wS0tPaUS;a7f73PO5ۚYtذٯ ṡ72>)w6ۋޫ%q9SX_To"E|r'XͼN5mF~6SۃSEkXevnFxPqif/1KMIW죳i6RBu){N 5"&4'5bDl dkӕ1q3\ز[#K {K7O%Nd;5qIm;Apk#ƥcFu^ܭYN!wSz\)ΒM[اRyOM",dF173f6bgRbfInjN=u朅1PaAX}ٍU5Q'a1'.OzM{91Wwc`Xapl-iJ&_Hx : A%$l[g8W>Eo :;Kc56)=]ϝx%FW}c `4Tx_ix:&yWK5%rM_m 7⿹X+aF]uz=tg{Mد"Lgqs{_Kc1 ӝnM$߾jxoՄzZg=ROeq&cDaKF6Q{OBmoaB6[7[Ox%;<2/h3 lS"W<`gU}Lf9&u: ng7мuRoFK5c ]&_}6uY8Jg[?Nふ\S Q=QwѨM@[اIf*JCRu_rF3%9ѯyہǝm6>\PS1*@S>Z*cm]oU&s?hK2gMII`/'/?1uq8s_"v׆` dOzIؽ vlU=w4vj֘nfs;NoaQ"]՝m;j%a}yIyCoأFJtCFD/ͪ u_rJǴ*91k0ω T3{D!Ӿ+˶2uvI٣ uɳ{ j;xGKZ٦;155C2&;SmsF$m߰#f|ll3y#/7PF#̳C}~P29gMɳ{ 4I;>!ZVv邙-2YĞ?;nQaW8m^tL˙g_[:c}S[nf?l`4^%ibF#3*i-gUї51E}]4go~ۗʝ3dXlb Jex ZulA`/fvi4b$/P xf~̳o3ZGN#vOF`^@5bgMǜmJ:&,FbHaq^-O~iOIDAT\/6Nnjԅxf{Eؽ5`_*g>bӭl/WF_#WHx {R!x/cZ;8643P7ށ?UՔt&6aƑa'n"v_Su}N*oM쁙=}S`^H\O؎SneFحۥ<;{CTN&{wlާp)an}ene3ւ;tL'j;">Nz|p2v45ܻ$imgh~ɝcIgoL:N%DQḘu\w@HxҔg"9} fKId¾bΛ4)mMh;'9xpg [ !3`f8/)~#a9%=Kef^l3)fF{Chk= IKaTҲ^/ddWևcP2SrW%v%17?cZ l&%v<с~̗I;#KL[$хbpGRcHZ)Ges9EҊf-t&] g;Ir.0$݄n"R _J3;o-J#⺓Z\qIok2)>:}G]0{doJ7,>hfcm{ d`)Ȳ#γolj fv3!Ǵ *w{fv3UŁgF`un2W}X}2hpB͂Iɿt#fvR+bPEvfew-ӔZפ4Ow>fvѹU.3|_@M 9{m6twԛ{)aM"fI"X=[}Ct Jd; f(g!֑kW̬'0eC T~9yC 0+E_#퀓୒%lf-`=c/iK[٥] r&p51@NaQr̻z {"'1Oh?fI8e^$‰ΜF!io:NH7ǍB<`j"Y|~e2ح u^Lrvs+aiyQܑt=@_6O;KTOe Mv4c - WxP7'ʑAgЯ"^#ԕHxei'鷄9^bfw IG%2EafLyӁ䝿ZhfNΑt}?1s^Gx^JRnf< wuvH4y(%,iľ }(kW%i75WfWhryp-%M>z?vDb?cfߗ~nfgh_bڼf:{IWKzW IHG)9Yg6mf%TAMe-1ol.>K$}JJZGO%t^PO}=݋7@kߖ74`7ҵ-t}[.~54~_5 ^8"ۿ&# Ah+5%f6WVH:)U{_^(z;w[]\ /)B٘z GJJuWNLvd{oS쯄\UŁk]쑪Rs=n=a7b"bkfveՋi,wX;K a ò}. &⥴M7nL8|k! cf ];Fh0; a7I/E:Za7;3-阆Er 2s03녽ܬl1g{=aN#iJf޸x'_b&&c&wjK,M`Oxy.F{eRDU.fv7nK:ՄCm&Mјldf?-A ara>I+eYp1;o!̏Lo "xb~k[| :6Ϳ2+$BkC$^.,e鐴_,ߤM؀|﫵xhfJ@{`fggHz1Aw!0Z_C8 rws>p]o}[$@%݃oj!+KZdYHLȿoTU ]>C ղ;m8 {]r'cb<\3̮7{oa?^.nwWaM=F](M.&4Ӳ)!{,#[/} Yv WV#<='lfs[a66ƷxWZ*;ms(E -Z{0I'5}Z&7TL==;#u 7;;HgsV$mh3^x PCa[g>0GFvs_>h*z?bF.mHgLϒ^v2$r5q0!챃O3-v΋ j#M 8^x BDz {Z'L~/ }tM&j%tL#%}N$-C?hf) /.eY6Q M\S)&'> =>GDh$vIIk6tWY vm{#nE[> } 7_5!i<&>k{8 yO%NХu{vIb3˖,q/_.e ]aQRʓ- I;vab MTΓ 82'^hٹU/ $l؅c݃)9vzd ,fISƒG<=_4&bg~RB#ٓpWaE4۹kI4aLh;5뫁=t $ VQK3Irl4NcR1f4 \oA._(d1#l3GS C̣^16>VD})["vx~Px-PXQJIϝ_<;2|3{IG -6M$p@ffU<1 c;;M/n'",wþ#B:3{ɰv*/"}]Pn6139BRbt?X0byN#Q%{z8G(t)fa6QV'̎oP!y݀u6L6OEw} - n]D,fv% \GhT( ЍT 7YljfWP(4ѽ:;>146b0+?Tz BBP] *-쑪zCRQ(:4/ ]JX?5-P(wۀ1V5^# Ȋ| "i)N-zB?T. `:;\y7ΘGʵ 8^Һ/ fl+rǡH:I "LT/G °HzAZG8it+K;T;hK  sHV=H:8%|̾YBPC$ ,["7Z! C{+_(/G#Ѓ;Rͤ|̾U B }6(!Z7bĎjZ 曒>[ B=:h-Q$\ TRGP$M%]_ͷ6d`OFfvѪAgxm^HP/Ҿә=Pqm`_!Bl$mIh-Lo=:a\,WZ"?ofTBIvhmقH:vBD EtNe_P[ֻ}I/}'6Aؤh"WWBcc3;=\Z4)h¾8.vڗ`f$ k{IdfbPȈ~VA`7B{Xc B5 ̎L尯 8굴II ` ?þv8z/v`4zB%įodf S:,1fv:ŒrIӪ^DPLν15E؇`f'/z-pvR(Z$`3Yi8B+^W_NIPP]A< p:0S 1("fҾX%K/Ÿ́ BSM$- H(Wzy\: {HؓP+| :-P()E؝4X{d___ n,İIENDB`hy-0.12.1/docs/_static/hy_logo.svg000066400000000000000000000117651304171765200167720ustar00rootroot00000000000000 image/svg+xml λ λ ( ) hy-0.12.1/docs/conf.py000066400000000000000000000177321304171765200144620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # hy documentation build configuration file, created by # sphinx-quickstart on Tue Mar 12 22:52:58 2013. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import os import sys import time sys.path.append(os.path.abspath("..")) import hy # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.todo'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'hy' copyright = u'2013-%s, Paul Tagliamonte' % time.strftime('%Y') # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = ".".join(hy.__version__.split(".")[:-1]) # The full version, including alpha/beta/rc tags. release = hy.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build', 'coreteam.rst'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. 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 # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'hydoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', # Stuff for unicode characters 'utf8extra': r''' \DeclareUnicodeCharacter{2698}{FLOWER} \DeclareUnicodeCharacter{2665}{HEART} ''', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'hy.tex', u'hy Documentation', u'Paul Tagliamonte', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'hy', u'hy Documentation', [u'Paul Tagliamonte'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'hy', u'hy Documentation', u'Paul Tagliamonte', 'hy', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' hy-0.12.1/docs/contrib/000077500000000000000000000000001304171765200146115ustar00rootroot00000000000000hy-0.12.1/docs/contrib/index.rst000066400000000000000000000004651304171765200164570ustar00rootroot00000000000000========================= Contributor Modules Index ========================= These modules are experimental additions to Hy. Once deemed mature, they will be moved to the ``hy.extra`` namespace or loaded by default. Contents: .. toctree:: :maxdepth: 3 loop multi profile sequences walk hy-0.12.1/docs/contrib/loop.rst000066400000000000000000000034451304171765200163220ustar00rootroot00000000000000========== loop/recur ========== .. versionadded:: 0.10.0 The ``loop`` / ``recur`` macro gives programmers a simple way to use tail-call optimization (TCO) in their Hy code. A tail call is a subroutine call that happens inside another procedure as its final action; it may produce a return value which is then immediately returned by the calling procedure. If any call that a subroutine performs, such that it might eventually lead to this same subroutine being called again down the call chain, is in tail position, such a subroutine is said to be tail-recursive, which is a special case of recursion. Tail calls are significant because they can be implemented without adding a new stack frame to the call stack. Most of the frame of the current procedure is not needed any more, and it can be replaced by the frame of the tail call. The program can then jump to the called subroutine. Producing such code instead of a standard call sequence is called tail call elimination, or tail call optimization. Tail call elimination allows procedure calls in tail position to be implemented as efficiently as goto statements, thus allowing efficient structured programming. -- Wikipedia (https://en.wikipedia.org/wiki/Tail_call) Macros ====== .. _loop: loop ----- ``loop`` establishes a recursion point. With ``loop``, ``recur`` rebinds the variables set in the recursion point and sends code execution back to that recursion point. If ``recur`` is used in a non-tail position, an exception is raised. Usage: ``(loop bindings &rest body)`` Example: .. code-block:: hy (require [hy.contrib.loop [loop]]) (defn factorial [n] (loop [[i n] [acc 1]] (if (zero? i) acc (recur (dec i) (* acc i))))) (factorial 1000) hy-0.12.1/docs/contrib/multi.rst000066400000000000000000000055721304171765200165060ustar00rootroot00000000000000======== defmulti ======== defn ---- .. versionadded:: 0.10.0 ``defn`` lets you arity-overload a function by the given number of args and/or kwargs. This version of ``defn`` works with regular syntax and with the arity overloaded one. Inspired by Clojures take on ``defn``. .. code-block:: clj => (require [hy.contrib.multi [defn]]) => (defn fun ... ([a] "a") ... ([a b] "a b") ... ([a b c] "a b c")) => (fun 1) "a" => (fun 1 2) "a b" => (fun 1 2 3) "a b c" => (defn add [a b] ... (+ a b)) => (add 1 2) 3 defmulti -------- .. versionadded:: 0.12.0 ``defmulti``, ``defmethod`` and ``default-method`` lets you define multimethods where a dispatching function is used to select between different implementations of the function. Inspired by Clojure's multimethod and based on the code by `Adam Bard`_. .. code-block:: clj => (require [hy.contrib.multi [defmulti defmethod default-method]]) => (defmulti area [shape] ... "calculate area of a shape" ... (:type shape)) => (defmethod area "square" [square] ... (* (:width square) ... (:height square))) => (defmethod area "circle" [circle] ... (* (** (:radius circle) 2) ... 3.14)) => (default-method area [shape] ... 0) => (area {:type "circle" :radius 0.5}) 0.785 => (area {:type "square" :width 2 :height 2}) 4 => (area {:type "non-euclid rhomboid"}) 0 ``defmulti`` is used to define the initial multimethod with name, signature and code that selects between different implementations. In the example, multimethod expects a single input that is type of dictionary and contains at least key :type. The value that corresponds to this key is returned and is used to selected between different implementations. ``defmethod`` defines a possible implementation for multimethod. It works otherwise in the same way as ``defn``, but has an extra parameters for specifying multimethod and which calls are routed to this specific implementation. In the example, shapes with "square" as :type are routed to first function and shapes with "circle" as :type are routed to second function. ``default-method`` specifies default implementation for multimethod that is called when no other implementation matches. Interfaces of multimethod and different implementation don't have to be exactly identical, as long as they're compatible enough. In practice this means that multimethod should accept the broadest range of parameters and different implementations can narrow them down. .. code-block:: clj => (require [hy.contrib.multi [defmulti defmethod]]) => (defmulti fun [&rest args] ... (len args)) => (defmethod fun 1 [a] ... a) => (defmethod fun 2 [a b] ... (+ a b)) => (fun 1) 1 => (fun 1 2) 3 .. _Adam Bard: https://adambard.com/blog/implementing-multimethods-in-python/ hy-0.12.1/docs/contrib/profile.rst000066400000000000000000000021621304171765200170040ustar00rootroot00000000000000========== Profile ========== .. versionadded:: 0.10.0 The ``profile`` macros make it easier to find bottlenecks. Macros ====== .. _profile/calls: .. _profile/cpu: profile/calls -------------- ``profile/calls`` allows you to create a call graph visualization. **Note:** You must have `Graphviz `_ installed for this to work. Usage: `(profile/calls (body))` Example: .. code-block:: hy (require [hy.contrib.profile [profile/calls]]) (profile/calls (print "hey there")) profile/cpu ------------ ``profile/cpu`` allows you to profile a bit of code. Usage: `(profile/cpu (body))` Example: .. code-block:: hy (require [hy.contrib.profile [profile/cpu]]) (profile/cpu (print "hey there")) .. code-block:: bash hey there 2 function calls in 0.000 seconds Random listing order was used ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 1 0.000 0.000 0.000 0.000 {print} hy-0.12.1/docs/contrib/sequences.rst000066400000000000000000000043331304171765200173410ustar00rootroot00000000000000============== Lazy sequences ============== .. versionadded:: 0.12.0 The sequences module contains a few macros for declaring sequences that are evaluated only as much as the client code requires. Unlike generators, they allow accessing the same element multiple times. They cache calculated values, and the implementation allows for recursive definition of sequences without resulting in recursive computation. To use these macros, you need to require them and import some other names like so: .. code-block:: hy (require [hy.contrib.sequences [defseq seq]]) (import [hy.contrib.sequences [Sequence end-sequence]]) The simplest sequence can be defined as ``(seq [n] n)``. This defines a sequence that starts as ``[0 1 2 3 ...]`` and continues forever. In order to define a finite sequence, you need to call ``end-sequence`` to signal the end of the sequence: .. code-block:: hy (seq [n] "sequence of 5 integers" (cond [(< n 5) n] [True (end-sequence)])) This creates the following sequence: ``[0 1 2 3 4]``. For such a sequence, ``len`` returns the amount of items in the sequence and negative indexing is supported. Because both of these require evaluating the whole sequence, calling one on an infinite sequence would take forever (or at least until available memory has been exhausted). Sequences can be defined recursively. For example, the Fibonacci sequence could be defined as: .. code-block:: hy (defseq fibonacci [n] "infinite sequence of fibonacci numbers" (cond [(= n 0) 0] [(= n 1) 1] [True (+ (get fibonacci (- n 1)) (get fibonacci (- n 2)))])) This results in the sequence ``[0 1 1 2 3 5 8 13 21 34 ...]``. .. _seq: seq === Usage: ``(seq [n] (* n n)`` Creates a sequence defined in terms of ``n``. .. _defseq: defseq ====== Usage: ``(defseq numbers [n] n)`` Creates a sequence defined in terms of ``n`` and assigns it to a given name. .. _end-sequence: end-sequence ============ Usage: ``(seq [n] (if (< n 5) n (end-sequence)))`` Signals the end of a sequence when an iterator reaches the given point of the sequence. Internally, this is done by raising ``IndexError``, catching that in the iterator, and raising ``StopIteration``. hy-0.12.1/docs/contrib/walk.rst000066400000000000000000000033711304171765200163050ustar00rootroot00000000000000==== walk ==== .. versionadded:: 0.11.0 Functions ========= .. _walk: walk ----- Usage: `(walk inner outer form)` ``walk`` traverses ``form``, an arbitrary data structure. Applies ``inner`` to each element of form, building up a data structure of the same type. Applies ``outer`` to the result. Example: .. code-block:: hy => (import [hy.contrib.walk [walk]]) => (setv a '(a b c d e f)) => (walk ord identity a) (97 98 99 100 101 102) => (walk ord first a) 97 postwalk --------- .. _postwalk: Usage: `(postwalk f form)` Performs depth-first, post-order traversal of ``form``. Calls ``f`` on each sub-form, uses ``f`` 's return value in place of the original. .. code-block:: hy => (import [hy.contrib.walk [postwalk]]) => (def trail '([1 2 3] [4 [5 6 [7]]])) => (defn walking [x] (print "Walking:" x) x ) => (postwalk walking trail) Walking: 1 Walking: 2 Walking: 3 Walking: (1 2 3) Walking: 4 Walking: 5 Walking: 6 Walking: 7 Walking: (7) Walking: (5 6 [7]) Walking: (4 [5 6 [7]]) Walking: ([1 2 3] [4 [5 6 [7]]]) ([1 2 3] [4 [5 6 [7]]]) prewalk -------- .. _prewalk: Usage: `(prewalk f form)` Performs depth-first, pre-order traversal of ``form``. Calls ``f`` on each sub-form, uses ``f`` 's return value in place of the original. .. code-block:: hy => (import [hy.contrib.walk [prewalk]]) => (def trail '([1 2 3] [4 [5 6 [7]]])) => (defn walking [x] (print "Walking:" x) x ) => (prewalk walking trail) Walking: ([1 2 3] [4 [5 6 [7]]]) Walking: [1 2 3] Walking: 1 Walking: 2 Walking: 3 Walking: [4 [5 6 [7]]] Walking: 4 Walking: [5 6 [7]] Walking: 5 Walking: 6 Walking: [7] Walking: 7 ([1 2 3] [4 [5 6 [7]]]) hy-0.12.1/docs/coreteam.rst000066400000000000000000000015231304171765200155030ustar00rootroot00000000000000* `Julien Danjou `_ * `Morten Linderud `_ * `J Kenneth King `_ * `Gergely Nagy `_ * `Tuukka Turto `_ * `Karen Rustad `_ * `Abhishek L `_ * `Christopher Allan Webber `_ * `Konrad Hinsen `_ * `Will Kahn-Greene `_ * `Paul Tagliamonte `_ * `Nicolas Dandrimont `_ * `Berker Peksag `_ * `Clinton N. Dreisbach `_ * `han semaj `_ * `Zack M. Davis `_ * `Kodi Arfer `_ hy-0.12.1/docs/extra/000077500000000000000000000000001304171765200142745ustar00rootroot00000000000000hy-0.12.1/docs/extra/anaphoric.rst000066400000000000000000000120401304171765200167670ustar00rootroot00000000000000================ Anaphoric Macros ================ .. versionadded:: 0.9.12 The anaphoric macros module makes functional programming in Hy very concise and easy to read. An anaphoric macro is a type of programming macro that deliberately captures some form supplied to the macro which may be referred to by an anaphor (an expression referring to another). -- Wikipedia (https://en.wikipedia.org/wiki/Anaphoric_macro) To use these macros you need to require the ``hy.extra.anaphoric`` module like so: ``(require [hy.extra.anaphoric [*]])`` .. _ap-if: ap-if ===== Usage: ``(ap-if (foo) (print it))`` Evaluates the first form for truthiness, and bind it to ``it`` in both the true and false branches. .. _ap-each: ap-each ======= Usage: ``(ap-each [1 2 3 4 5] (print it))`` Evaluate the form for each element in the list for side-effects. .. _ap-each-while: ap-each-while ============= Usage: ``(ap-each-while list pred body)`` Evaluate the form for each element where the predicate form returns ``True``. .. code-block:: hy => (ap-each-while [1 2 3 4 5 6] (< it 4) (print it)) 1 2 3 .. _ap-map: ap-map ====== Usage: ``(ap-map form list)`` The anaphoric form of map works just like regular map except that instead of a function object it takes a Hy form. The special name ``it`` is bound to the current object from the list in the iteration. .. code-block:: hy => (list (ap-map (* it 2) [1 2 3])) [2, 4, 6] .. _ap-map-when: ap-map-when =========== Usage: ``(ap-map-when predfn rep list)`` Evaluate a mapping over the list using a predicate function to determin when to apply the form. .. code-block:: hy => (list (ap-map-when odd? (* it 2) [1 2 3 4])) [2, 2, 6, 4] => (list (ap-map-when even? (* it 2) [1 2 3 4])) [1, 4, 3, 8] .. _ap-filter: ap-filter ========= Usage: ``(ap-filter form list)`` As with ``ap-map`` we take a special form instead of a function to filter the elements of the list. The special name ``it`` is bound to the current element in the iteration. .. code-block:: hy => (list (ap-filter (> (* it 2) 6) [1 2 3 4 5])) [4, 5] .. _ap-reject: ap-reject ========= Usage: ``(ap-reject form list)`` This function does the opposite of ``ap-filter``, it rejects the elements passing the predicate . The special name ``it`` is bound to the current element in the iteration. .. code-block:: hy => (list (ap-reject (> (* it 2) 6) [1 2 3 4 5])) [1, 2, 3] .. _ap-dotimes: ap-dotimes ========== Usage ``(ap-dotimes n body)`` This function evaluates the body *n* times, with the special variable ``it`` bound from *0* to *1-n*. It is useful for side-effects. .. code-block:: hy => (setv n []) => (ap-dotimes 3 (.append n it)) => n [0, 1, 2] .. _ap-first: ap-first ======== Usage ``(ap-first predfn list)`` This function returns the first element that passes the predicate or ``None``, with the special variable ``it`` bound to the current element in iteration. .. code-block:: hy =>(ap-first (> it 5) (range 10)) 6 .. _ap-last: ap-last ======== Usage ``(ap-last predfn list)`` This function returns the last element that passes the predicate or ``None``, with the special variable ``it`` bound to the current element in iteration. .. code-block:: hy =>(ap-last (> it 5) (range 10)) 9 .. _ap-reduce: ap-reduce ========= Usage ``(ap-reduce form list &optional initial-value)`` This function returns the result of applying form to the first 2 elements in the body and applying the result and the 3rd element etc. until the list is exhausted. Optionally an initial value can be supplied so the function will be applied to initial value and the first element instead. This exposes the element being iterated as ``it`` and the current accumulated value as ``acc``. .. code-block:: hy =>(ap-reduce (+ it acc) (range 10)) 45 .. _ap-pipe: ap-pipe ========= Usage ``(ap-pipe value form1 form2 ...)`` Applies several forms in series to a value from left to right. The special variable ``ìt`` in each form is replaced by the result of the previous form. .. code-block:: hy => (ap-pipe 3 (+ it 1) (/ 5 it)) 1.25 => (ap-pipe [4 5 6 7] (list (rest it)) (len it)) 3 .. _ap-compose: ap-compose ========= Usage ``(ap-compose form1 form2 ...)`` Returns a function which applies several forms in series from left to right. The special variable ``ìt`` in each form is replaced by the result of the previous form. .. code-block:: hy => (def op (ap-compose (+ it 1) (* it 3))) => (op 2) 9 .. _xi xi == Usage ``(xi body ...)`` Returns a function with parameters implicitly determined by the presence in the body of xi parameters. An xi symbol designates the ith parameter (1-based, e.g. x1, x2, x3, etc.), or all remaining parameters for xi itself. This is not a replacement for lambda. The xi forms cannot be nested. This is similar to Clojure's anonymous function literals (``#()``). .. code-block:: hy => ((xi identity [x1 x5 [x2 x3] xi x4]) 1 2 3 4 5 6 7 8) [1, 5, [2, 3,] (6, 7, 8), 4] => (def add-10 (xi + 10 x1)) => (add-10 6) 16 hy-0.12.1/docs/extra/index.rst000066400000000000000000000004201304171765200161310ustar00rootroot00000000000000=================== Extra Modules Index =================== These modules are considered no less stable than Hy's built-in functions and macros, but they need to be loaded with ``(import ...)`` or ``(require ...)``. Contents: .. toctree:: :maxdepth: 3 anaphoric hy-0.12.1/docs/hacking.rst000066400000000000000000000034541304171765200153150ustar00rootroot00000000000000=============== Hacking on Hy =============== .. highlight:: bash Join our Hyve! ============== Please come hack on Hy! Please come hang out with us on ``#hy`` on ``irc.freenode.net``! Please talk about it on Twitter with the ``#hy`` hashtag! Please blog about it! Please don't spraypaint it on your neighbor's fence (without asking nicely)! Hack! ===== Do this: 1. Create a `virtual environment `_:: $ virtualenv venv and activate it:: $ . venv/bin/activate or use `virtualenvwrapper `_ to create and manage your virtual environment:: $ mkvirtualenv hy $ workon hy 2. Get the source code:: $ git clone https://github.com/hylang/hy.git or use your fork:: $ git clone git@github.com:/hy.git 3. Install for hacking:: $ cd hy/ $ pip install -e . 4. Install other develop-y requirements:: $ pip install -r requirements-dev.txt 5. Do awesome things; make someone shriek in delight/disgust at what you have wrought. Test! ===== Tests are located in ``tests/``. We use `nose `_. To run the tests:: $ nosetests Write tests---tests are good! Also, it is good to run the tests for all the platforms supported and for PEP 8 compliant code. You can do so by running tox:: $ tox Document! ========= Documentation is located in ``docs/``. We use `Sphinx `_. To build the docs in HTML:: $ cd docs $ make html Write docs---docs are good! Even this doc! Contributing ============ .. include:: ../CONTRIBUTING.rst Core Team ========= The core development team of Hy consists of following developers: .. include:: coreteam.rst hy-0.12.1/docs/index.rst000066400000000000000000000015771304171765200150240ustar00rootroot00000000000000Welcome to Hy's documentation! ============================== .. image:: _static/hy-logo-small.png :alt: Hy :align: left :Try Hy: https://try-hy.appspot.com :PyPI: https://pypi.python.org/pypi/hy :Source: https://github.com/hylang/hy :List: `hylang-discuss `_ :IRC: ``#hy`` on Freenode :Build status: .. image:: https://secure.travis-ci.org/hylang/hy.png :alt: Travis CI :target: http://travis-ci.org/hylang/hy Hy is a wonderful dialect of Lisp that's embedded in Python. Since Hy transforms its Lisp code into the Python Abstract Syntax Tree, you have the whole beautiful world of Python at your fingertips, in Lisp form! Documentation Index =================== Contents: .. toctree:: :maxdepth: 3 quickstart tutorial style-guide language/index extra/index contrib/index hacking hy-0.12.1/docs/language/000077500000000000000000000000001304171765200147345ustar00rootroot00000000000000hy-0.12.1/docs/language/api.rst000066400000000000000000001306271304171765200162500ustar00rootroot00000000000000================= Hy (the language) ================= .. warning:: This is incomplete; please consider contributing to the documentation effort. Theory of Hy ============ Hy maintains, over everything else, 100% compatibility in both directions with Python itself. All Hy code follows a few simple rules. Memorize this, as it's going to come in handy. These rules help ensure that Hy code is idiomatic and interfaceable in both languages. * Symbols in earmufs will be translated to the upper-cased version of that string. For example, ``foo`` will become ``FOO``. * UTF-8 entities will be encoded using `punycode `_ and prefixed with ``hy_``. For instance, ``⚘`` will become ``hy_w7h``, ``♥`` will become ``hy_g6h``, and ``i♥u`` will become ``hy_iu_t0x``. * Symbols that contain dashes will have them replaced with underscores. For example, ``render-template`` will become ``render_template``. This means that symbols with dashes will shadow their underscore equivalents, and vice versa. Notes on Syntax =============== integers -------- .. versionadded:: 0.11.1 In addition to regular numbers, standard notation from Python 3 for non-base 10 integers is used. ``0x`` for Hex, ``0o`` for Octal, ``0b`` for Binary. .. code-block:: clj (print 0x80 0b11101 0o102 30) Built-Ins ========= Hy features a number of special forms that are used to help generate correct Python AST. The following are "special" forms, which may have behavior that's slightly unexpected in some situations. . - .. versionadded:: 0.10.0 ``.`` is used to perform attribute access on objects. It uses a small DSL to allow quick access to attributes and items in a nested data structure. For instance, .. code-block:: clj (. foo bar baz [(+ 1 2)] frob) Compiles down to: .. code-block:: python foo.bar.baz[1 + 2].frob ``.`` compiles its first argument (in the example, *foo*) as the object on which to do the attribute dereference. It uses bare symbols as attributes to access (in the example, *bar*, *baz*, *frob*), and compiles the contents of lists (in the example, ``[(+ 1 2)]``) for indexation. Other arguments raise a compilation error. Access to unknown attributes raises an :exc:`AttributeError`. Access to unknown keys raises an :exc:`IndexError` (on lists and tuples) or a :exc:`KeyError` (on dictionaries). -> -- ``->`` (or the *threading macro*) is used to avoid nesting of expressions. The threading macro inserts each expression into the next expression's first argument place. The following code demonstrates this: .. code-block:: clj => (defn output [a b] (print a b)) => (-> (+ 4 6) (output 5)) 10 5 ->> --- ``->>`` (or the *threading tail macro*) is similar to the *threading macro*, but instead of inserting each expression into the next expression's first argument, it appends it as the last argument. The following code demonstrates this: .. code-block:: clj => (defn output [a b] (print a b)) => (->> (+ 4 6) (output 5)) 5 10 apply ----- ``apply`` is used to apply an optional list of arguments and an optional dictionary of kwargs to a function. The symbol mangling transformations will be applied to all keys in the dictionary of kwargs, provided the dictionary and its keys are defined in-place. Usage: ``(apply fn-name [args] [kwargs])`` Examples: .. code-block:: clj (defn thunk [] "hy there") (apply thunk) ;=> "hy there" (defn total-purchase [price amount &optional [fees 1.05] [vat 1.1]] (* price amount fees vat)) (apply total-purchase [10 15]) ;=> 173.25 (apply total-purchase [10 15] {"vat" 1.05}) ;=> 165.375 (apply total-purchase [] {"price" 10 "amount" 15 "vat" 1.05}) ;=> 165.375 (apply total-purchase [] {:price 10 :amount 15 :vat 1.05}) ;=> 165.375 and --- ``and`` is used in logical expressions. It takes at least two parameters. If all parameters evaluate to ``True``, the last parameter is returned. In any other case, the first false value will be returned. Example usage: .. code-block:: clj => (and True False) False => (and True True) True => (and True 1) 1 => (and True [] False True) [] .. note:: ``and`` short-circuits and stops evaluating parameters as soon as the first false is encountered. .. code-block:: clj => (and False (print "hello")) False as-> ---- .. versionadded:: 0.12.0 Expands to sequence of assignments to the provided name, starting with head. The previous result is thus available in the subsequent form. Returns the final result, and leaves the name bound to it in the local scope. This behaves much like the other threading macros, but requires you to specify the threading point per form via the name instead of always the first or last argument. .. code-block:: clj ;; example how -> and as-> relate => (as-> 0 it ... (inc it) ... (inc it)) 2 => (-> 0 inc inc) 2 ;; create data for our cuttlefish database => (setv data [{:name "hooded cuttlefish" ... :classification {:subgenus "Acanthosepion" ... :species "Sepia prashadi"} ... :discovered {:year 1936 ... :name "Ronald Winckworth"}} ... {:name "slender cuttlefish" ... :classification {:subgenus "Doratosepion" ... :species "Sepia braggi"} ... :discovered {:year 1907 ... :name "Sir Joseph Cooke Verco"}}]) ;; retrieve name of first entry => (as-> (first data) it ... (:name it)) 'hooded cuttlefish' ;; retrieve species of first entry => (as-> (first data) it ... (:classification it) ... (:species it)) 'Sepia prashadi' ;; find out who discovered slender cuttlefish => (as-> (filter (fn [entry] (= (:name entry) ... "slender cuttlefish")) data) it ... (first it) ... (:discovered it) ... (:name it)) 'Sir Joseph Cooke Verco' ;; more convoluted example to load web page and retrieve data from it => (import [urllib.request [urlopen]]) => (as-> (urlopen "http://docs.hylang.org/en/stable/") it ... (.read it) ... (.decode it "utf-8") ... (drop (.index it "Welcome") it) ... (take 30 it) ... (list it) ... (.join "" it)) 'Welcome to Hy’s documentation! .. note:: In these examples, the REPL will report a tuple (e.g. `('Sepia prashadi', 'Sepia prashadi')`) as the result, but only a single value is actually returned. assert ------ ``assert`` is used to verify conditions while the program is running. If the condition is not met, an :exc:`AssertionError` is raised. ``assert`` may take one or two parameters. The first parameter is the condition to check, and it should evaluate to either ``True`` or ``False``. The second parameter, optional, is a label for the assert, and is the string that will be raised with the :exc:`AssertionError`. For example: .. code-block:: clj (assert (= variable expected-value)) (assert False) ; AssertionError (assert (= 1 2) "one should equal two") ; AssertionError: one should equal two assoc ----- ``assoc`` is used to associate a key with a value in a dictionary or to set an index of a list to a value. It takes at least three parameters: the *data structure* to be modified, a *key* or *index*, and a *value*. If more than three parameters are used, it will associate in pairs. Examples of usage: .. code-block:: clj =>(let [collection {}] ... (assoc collection "Dog" "Bark") ... (print collection)) {u'Dog': u'Bark'} =>(let [collection {}] ... (assoc collection "Dog" "Bark" "Cat" "Meow") ... (print collection)) {u'Cat': u'Meow', u'Dog': u'Bark'} =>(let [collection [1 2 3 4]] ... (assoc collection 2 None) ... (print collection)) [1, 2, None, 4] .. note:: ``assoc`` modifies the datastructure in place and returns ``None``. break ----- ``break`` is used to break out from a loop. It terminates the loop immediately. The following example has an infinite ``while`` loop that is terminated as soon as the user enters *k*. .. code-block:: clj (while True (if (= "k" (raw-input "? ")) (break) (print "Try again"))) cond ---- ``cond`` can be used to build nested ``if`` statements. The following example shows the relationship between the macro and its expansion: .. code-block:: clj (cond [condition-1 result-1] [condition-2 result-2]) (if condition-1 result-1 (if condition-2 result-2)) As shown below, only the first matching result block is executed. .. code-block:: clj => (defn check-value [value] ... (cond [(< value 5) (print "value is smaller than 5")] ... [(= value 5) (print "value is equal to 5")] ... [(> value 5) (print "value is greater than 5")] ... [True (print "value is something that it should not be")])) => (check-value 6) value is greater than 5 continue -------- ``continue`` returns execution to the start of a loop. In the following example, ``(side-effect1)`` is called for each iteration. ``(side-effect2)``, however, is only called on every other value in the list. .. code-block:: clj ;; assuming that (side-effect1) and (side-effect2) are functions and ;; collection is a list of numerical values (for [x collection] (side-effect1 x) (if (% x 2) (continue)) (side-effect2 x)) dict-comp --------- ``dict-comp`` is used to create dictionaries. It takes three or four parameters. The first two parameters are for controlling the return value (key-value pair) while the third is used to select items from a sequence. The fourth and optional parameter can be used to filter out some of the items in the sequence based on a conditional expression. .. code-block:: hy => (dict-comp x (* x 2) [x (range 10)] (odd? x)) {1: 2, 3: 6, 9: 18, 5: 10, 7: 14} do ---------- ``do`` is used to evaluate each of its arguments and return the last one. Return values from every other than the last argument are discarded. It can be used in ``lambda`` or ``list-comp`` to perform more complex logic as shown in one of the following examples. Some example usage: .. code-block:: clj => (if True ... (do (print "Side effects rock!") ... (print "Yeah, really!"))) Side effects rock! Yeah, really! ;; assuming that (side-effect) is a function that we want to call for each ;; and every value in the list, but whose return value we do not care about => (list-comp (do (side-effect x) ... (if (< x 5) (* 2 x) ... (* 4 x))) ... (x (range 10))) [0, 2, 4, 6, 8, 20, 24, 28, 32, 36] ``do`` can accept any number of arguments, from 1 to n. def / setv ---------- ``def`` and ``setv`` are used to bind a value, object, or function to a symbol. For example: .. code-block:: clj => (def names ["Alice" "Bob" "Charlie"]) => (print names) [u'Alice', u'Bob', u'Charlie'] => (setv counter (fn [collection item] (.count collection item))) => (counter [1 2 3 4 5 2 3] 2) 2 They can be used to assign multiple variables at once: .. code-block:: hy => (setv a 1 b 2) (1L, 2L) => a 1L => b 2L => defclass -------- New classes are declared with ``defclass``. It can takes two optional parameters: a vector defining a possible super classes and another vector containing attributes of the new class as two item vectors. .. code-block:: clj (defclass class-name [super-class-1 super-class-2] [attribute value] (defn method [self] (print "hello!"))) Both values and functions can be bound on the new class as shown by the example below: .. code-block:: clj => (defclass Cat [] ... [age None ... colour "white"] ... ... (defn speak [self] (print "Meow"))) => (def spot (Cat)) => (setv spot.colour "Black") 'Black' => (.speak spot) Meow .. _defn: defn ---- ``defn`` macro is used to define functions. It takes three parameters: the *name* of the function to define, a vector of *parameters*, and the *body* of the function: .. code-block:: clj (defn name [params] body) Parameters may have the following keywords in front of them: &optional Parameter is optional. The parameter can be given as a two item list, where the first element is parameter name and the second is the default value. The parameter can be also given as a single item, in which case the default value is ``None``. .. code-block:: clj => (defn total-value [value &optional [value-added-tax 10]] ... (+ (/ (* value value-added-tax) 100) value)) => (total-value 100) 110.0 => (total-value 100 1) 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. The following code examples defines a function that will print all keyword arguments and their values. .. code-block:: clj => (defn print-parameters [&kwargs kwargs] ... (for [(, k v) (.items kwargs)] (print k v))) => (print-parameters :parameter-1 1 :parameter-2 2) parameter_1 1 parameter_2 2 ; to avoid the mangling of '-' to '_', use apply: => (apply print-parameters [] {"parameter-1" 1 "parameter-2" 2}) parameter-1 1 parameter-2 2 &rest Parameter will contain 0 or more positional arguments. No other positional arguments may be specified after this one. The following code example defines a function that can be given 0 to n numerical parameters. It then sums every odd number and subtracts every even number. .. code-block:: clj => (defn zig-zag-sum [&rest numbers] (let [odd-numbers (list-comp x [x numbers] (odd? x)) even-numbers (list-comp x [x numbers] (even? x))] (- (sum odd-numbers) (sum even-numbers)))) => (zig-zag-sum) 0 => (zig-zag-sum 3 9 4) 8 => (zig-zag-sum 1 2 3 4 5 6) -3 &kwonly .. versionadded:: 0.12.0 Parameters that can only be called as keywords. Mandatory keyword-only arguments are declared with the argument's name; optional keyword-only arguments are declared as a two-element list containing the argument name followed by the default value (as with `&optional` above). .. code-block:: clj => (defn compare [a b &kwonly keyfn [reverse false]] ... (let [result (keyfn a b)] ... (if (not reverse) ... result ... (- result)))) => (apply compare ["lisp" "python"] ... {"keyfn" (fn [x y] ... (reduce - (map (fn [s] (ord (first s))) [x y])))}) -4 => (apply compare ["lisp" "python"] ... {"keyfn" (fn [x y] ... (reduce - (map (fn [s] (ord (first s))) [x y]))) ... "reverse" True}) 4 .. code-block:: python => (compare "lisp" "python") Traceback (most recent call last): File "", line 1, in TypeError: compare() missing 1 required keyword-only argument: 'keyfn' Availability: Python 3. defmain ------- .. versionadded:: 0.10.1 The ``defmain`` macro defines a main function that is immediately called with ``sys.argv`` as arguments if and only if this file is being executed as a script. In other words, this: .. code-block:: clj (defmain [&rest args] (do-something-with args)) is the equivalent of:: def main(*args): do_something_with(args) return 0 if __name__ == "__main__": import sys retval = main(*sys.argv) if isinstance(retval, int): sys.exit(retval) Note that as you can see above, if you return an integer from this function, this will be used as the exit status for your script. (Python defaults to exit status 0 otherwise, which means everything's okay!) Since ``(sys.exit 0)`` is not run explicitly in the case of a non-integer return from ``defmain``, it's a good idea to put ``(defmain)`` as the last piece of code in your file. If you want fancy command-line arguments, you can use the standard Python module ``argparse`` in the usual way: .. code-block:: clj (import argparse) (defmain [&rest _] (setv parser (argparse.ArgumentParser)) (.add-argument parser "STRING" :help "string to replicate") (.add-argument parser "-n" :type int :default 3 :help "number of copies") (setv args (parser.parse_args)) (print (* args.STRING args.n)) 0) .. _defmacro: defmacro -------- ``defmacro`` is used to define macros. The general format is ``(defmacro name [parameters] expr)``. The following example defines a macro that can be used to swap order of elements in code, allowing the user to write code in infix notation, where operator is in between the operands. .. code-block:: clj => (defmacro infix [code] ... (quasiquote ( ... (unquote (get code 1)) ... (unquote (get code 0)) ... (unquote (get code 2))))) => (infix (1 + 1)) 2 .. _defmacro/g!: defmacro/g! ------------ .. versionadded:: 0.9.12 ``defmacro/g!`` is a special version of ``defmacro`` that is used to automatically generate :ref:`gensym` for any symbol that starts with ``g!``. For example, ``g!a`` would become ``(gensym "a")``. .. seealso:: Section :ref:`using-gensym` .. _defmacro!: defmacro! --------- ``defmacro!`` is like ``defmacro/g!`` plus automatic once-only evaluation for ``o!`` parameters, which are available as the equivalent ``g!`` symbol. For example, .. code-block:: clj => (defn expensive-get-number [] (print "spam") 14) => (defmacro triple-1 [n] `(+ n n n)) => (triple-1 (expensive-get-number)) ; evals n three times spam spam spam 42 => (defmacro/g! triple-2 [n] `(do (setv ~g!n ~n) (+ ~g!n ~g!n ~g!n))) => (triple-2 (expensive-get-number)) ; avoid repeats with a gensym spam 42 => (defmacro! triple-3 [o!n] `(+ ~g!n ~g!n ~g!n)) => (triple-3 (expensive-get-number)) ; easier with defmacro! spam 42 defreader --------- .. versionadded:: 0.9.12 ``defreader`` defines a reader macro, enabling you to restructure or modify syntax. .. code-block:: clj => (defreader ^ [expr] (print expr)) => #^(1 2 3 4) (1 2 3 4) => #^"Hello" "Hello" .. seealso:: Section :ref:`Reader Macros ` del --- .. versionadded:: 0.9.12 ``del`` removes an object from the current namespace. .. code-block:: clj => (setv foo 42) => (del foo) => foo Traceback (most recent call last): File "", line 1, in NameError: name 'foo' is not defined ``del`` can also remove objects from mappings, lists, and more. .. code-block:: clj => (setv test (list (range 10))) => test [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] => (del (cut test 2 4)) ;; remove items from 2 to 4 excluded => test [0, 1, 4, 5, 6, 7, 8, 9] => (setv dic {"foo" "bar"}) => dic {"foo": "bar"} => (del (get dic "foo")) => dic {} doto ---- .. versionadded:: 0.10.1 ``doto`` is used to simplify a sequence of method calls to an object. .. code-block:: clj => (doto [] (.append 1) (.append 2) .reverse) [2 1] .. code-block:: clj => (setv collection []) => (.append collection 1) => (.append collection 2) => (.reverse collection) => collection [2 1] eval ---- ``eval`` evaluates a quoted expression and returns the value. The optional second and third arguments specify the dictionary of globals to use and the module name. The globals dictionary defaults to ``(local)`` and the module name defaults to the name of the current module. .. code-block:: clj => (eval '(print "Hello World")) "Hello World" If you want to evaluate a string, use ``read-str`` to convert it to a form first: .. code-block:: clj => (eval (read-str "(+ 1 1)")) 2 eval-and-compile ---------------- eval-when-compile ----------------- first / car ----------- ``first`` and ``car`` are macros for accessing the first element of a collection: .. code-block:: clj => (first (range 10)) 0 for --- ``for`` is used to call a function for each element in a list or vector. The results of each call are discarded and the ``for`` expression returns ``None`` instead. The example code iterates over *collection* and for each *element* in *collection* calls the ``side-effect`` function with *element* as its argument: .. code-block:: clj ;; assuming that (side-effect) is a function that takes a single parameter (for [element collection] (side-effect element)) ;; for can have an optional else block (for [element collection] (side-effect element) (else (side-effect-2))) The optional ``else`` block is only executed if the ``for`` loop terminates normally. If the execution is halted with ``break``, the ``else`` block does not execute. .. code-block:: clj => (for [element [1 2 3]] (if (< element 3) ... (print element) ... (break)) ... (else (print "loop finished"))) 1 2 => (for [element [1 2 3]] (if (< element 4) ... (print element) ... (break)) ... (else (print "loop finished"))) 1 2 3 loop finished genexpr ------- ``genexpr`` is used to create generator expressions. It takes two or three parameters. The first parameter is the expression controlling the return value, while the second is used to select items from a list. The third and optional parameter can be used to filter out some of the items in the list based on a conditional expression. ``genexpr`` is similar to ``list-comp``, except it returns an iterable that evaluates values one by one instead of evaluating them immediately. .. code-block:: hy => (def collection (range 10)) => (def filtered (genexpr x [x collection] (even? x))) => (list filtered) [0, 2, 4, 6, 8] .. _gensym: gensym ------ .. versionadded:: 0.9.12 ``gensym`` is used to generate a unique symbol that allows macros to be written without accidental variable name clashes. .. code-block:: clj => (gensym) u':G_1235' => (gensym "x") u':x_1236' .. seealso:: Section :ref:`using-gensym` get --- ``get`` is used to access single elements in lists and dictionaries. ``get`` takes two parameters: the *data structure* and the *index* or *key* of the item. It will then return the corresponding value from the dictionary or the list. Example usage: .. code-block:: clj => (let [animals {"dog" "bark" "cat" "meow"} ... numbers ["zero" "one" "two" "three"]] ... (print (get animals "dog")) ... (print (get numbers 2))) bark two .. note:: ``get`` raises a KeyError if a dictionary is queried for a non-existing key. .. note:: ``get`` raises an IndexError if a list or a tuple is queried for an index that is out of bounds. global ------ ``global`` can be used to mark a symbol as global. This allows the programmer to assign a value to a global symbol. Reading a global symbol does not require the ``global`` keyword -- only assigning it does. The following example shows how the global symbol ``a`` is assigned a value in a function and is later on printed in another function. Without the ``global`` keyword, the second function would have raised a ``NameError``. .. code-block:: clj (defn set-a [value] (global a) (setv a value)) (defn print-a [] (print a)) (set-a 5) (print-a) if / if* / if-not ----------------- .. versionadded:: 0.10.0 if-not ``if / if* / if-not`` respect Python *truthiness*, that is, a *test* fails if it evaluates to a "zero" (including values of ``len`` zero, ``None``, and ``False``), and passes otherwise, but values with a ``__bool__`` method (``__nonzero__`` in Python 2) can overrides this. The ``if`` macro is for conditionally selecting an expression for evaluation. The result of the selected expression becomes the result of the entire ``if`` form. ``if`` can select a group of expressions with the help of a ``do`` block. ``if`` takes any number of alternating *test* and *then* expressions, plus an optional *else* expression at the end, which defaults to ``None``. ``if`` checks each *test* in turn, and selects the *then* corresponding to the first passed test. ``if`` does not evaluate any expressions following its selection, similar to the ``if/elif/else`` control structure from Python. If no tests pass, ``if`` selects *else*. The ``if*`` special form is restricted to 2 or 3 arguments, but otherwise works exactly like ``if`` (which expands to nested ``if*`` forms), so there is generally no reason to use it directly. ``if-not`` is similar to ``if*`` but the second expression will be executed when the condition fails while the third and final expression is executed when the test succeeds -- the opposite order of ``if*``. The final expression is again optional and defaults to ``None``. Example usage: .. code-block:: clj (print (if (< n 0.0) "negative" (= n 0.0) "zero" (> n 0.0) "positive" "not a number")) (if* (money-left? account) (print "let's go shopping") (print "let's go and work")) (if-not (money-left? account) (print "let's go and work") (print "let's go shopping")) lif and lif-not --------------------------------------- .. versionadded:: 0.10.0 .. versionadded:: 0.11.0 lif-not For those that prefer a more Lispy ``if`` clause, we have ``lif``. This *only* considers ``None`` to be false! All other "false-ish" Python values are considered true. Conversely, we have ``lif-not`` in parallel to ``if`` and ``if-not`` which reverses the comparison. .. code-block:: clj => (lif True "true" "false") "true" => (lif False "true" "false") "true" => (lif 0 "true" "false") "true" => (lif None "true" "false") "false" => (lif-not None "true" "false") "true" => (lif-not False "true" "false") "false" import ------ ``import`` is used to import modules, like in Python. There are several ways that ``import`` can be used. .. code-block:: clj ;; Imports each of these modules ;; ;; Python: ;; import sys ;; import os.path (import sys os.path) ;; Import from a module ;; ;; Python: from os.path import exists, isdir, isfile (import [os.path [exists isdir isfile]]) ;; Import with an alias ;; ;; Python: import sys as systest (import [sys :as systest]) ;; You can list as many imports as you like of different types. ;; ;; Python: ;; from tests.resources import kwtest, function_with_a_dash ;; from os.path import exists, isdir as is_dir, isfile as is_file ;; import sys as systest (import [tests.resources [kwtest function-with-a-dash]] [os.path [exists isdir :as dir? isfile :as file?]] [sys :as systest]) ;; Import all module functions into current namespace ;; ;; Python: from sys import * (import [sys [*]]) lambda / fn ----------- ``lambda`` and ``fn`` can be used to define an anonymous function. The parameters are similar to ``defn``: the first parameter is vector of parameters and the rest is the body of the function. ``lambda`` returns a new function. In the following example, an anonymous function is defined and passed to another function for filtering output. .. code-block:: clj => (def people [{:name "Alice" :age 20} ... {:name "Bob" :age 25} ... {:name "Charlie" :age 50} ... {:name "Dave" :age 5}]) => (defn display-people [people filter] ... (for [person people] (if (filter person) (print (:name person))))) => (display-people people (fn [person] (< (:age person) 25))) Alice Dave Just as in normal function definitions, if the first element of the body is a string, it serves as a 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))) This can be confirmed via Python's built-in ``help`` function:: => (help times-three) Help on function times_three: times_three(x) Multiplies input by three and returns result (END) last ----------- .. versionadded:: 0.11.0 ``last`` can be used for accessing the last element of a collection: .. code-block:: clj => (last [2 4 6]) 6 let --- ``let`` is used to create lexically scoped variables. They are created at the beginning of the ``let`` form and cease to exist after the form. The following example showcases this behaviour: .. code-block:: clj => (let [x 5] (print x) ... (let [x 6] (print x)) ... (print x)) 5 6 5 The ``let`` macro takes two parameters: a vector defining *variables* and the *body* which gets executed. *variables* is a vector of variable and value pairs. Note that the variable assignments are executed one by one, from left to right. The following example takes advantage of this: .. code-block:: clj => (let [x 5 y (+ x 1)] (print x y)) 5 6 list-comp --------- ``list-comp`` performs list comprehensions. It takes two or three parameters. The first parameter is the expression controlling the return value, while the second is used to select items from a list. The third and optional parameter can be used to filter out some of the items in the list based on a conditional expression. Some examples: .. code-block:: clj => (def collection (range 10)) => (list-comp x [x collection]) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] => (list-comp (* x 2) [x collection]) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] => (list-comp (* x 2) [x collection] (< x 5)) [0, 2, 4, 6, 8] nonlocal -------- .. versionadded:: 0.11.1 **PYTHON 3.0 AND UP ONLY!** ``nonlocal`` can be used to mark a symbol as not local to the current scope. The parameters are the names of symbols to mark as nonlocal. This is necessary to modify variables through nested ``let`` or ``fn`` scopes: .. code-block:: clj (let [x 0] (for [y (range 10)] (let [z (inc y)] (nonlocal x) ; allow the setv to "jump scope" to resolve x (setv x (+ x y)))) x) (defn some-function [] (let [x 0] (register-some-callback (fn [stuff] (nonlocal x) (setv x stuff))))) In the first example, without the call to ``(nonlocal x)``, this code would result in an UnboundLocalError being raised during the call to ``setv``. In the second example, without the call to ``(nonlocal x)``, the inner function would redefine ``x`` to ``stuff`` inside its local scope instead of overwriting the ``x`` in the outer function See `PEP3104 `_ for further information. not --- ``not`` is used in logical expressions. It takes a single parameter and returns a reversed truth value. If ``True`` is given as a parameter, ``False`` will be returned, and vice-versa. Example usage: .. code-block:: clj => (not True) False => (not False) True => (not None) True or -- ``or`` is used in logical expressions. It takes at least two parameters. It will return the first non-false parameter. If no such value exists, the last parameter will be returned. .. code-block:: clj => (or True False) True => (and False False) False => (and False 1 True False) 1 .. note:: ``or`` short-circuits and stops evaluating parameters as soon as the first true value is encountered. .. code-block:: clj => (or True (print "hello")) True print ----- ``print`` is used to output on screen. Example usage: .. code-block:: clj (print "Hello world!") .. note:: ``print`` always returns ``None``. quasiquote ---------- ``quasiquote`` allows you to quote a form, but also selectively evaluate expressions. Expressions inside a ``quasiquote`` can be selectively evaluated using ``unquote`` (``~``). The evaluated form can also be spliced using ``unquote-splice`` (``~@``). Quasiquote can be also written using the backquote (`````) symbol. .. code-block:: clj ;; let `qux' be a variable with value (bar baz) `(foo ~qux) ; equivalent to '(foo (bar baz)) `(foo ~@qux) ; equivalent to '(foo bar baz) quote ----- ``quote`` returns the form passed to it without evaluating it. ``quote`` can alternatively be written using the apostrophe (``'``) symbol. .. code-block:: clj => (setv x '(print "Hello World")) ; variable x is set to expression & not evaluated => x (u'print' u'Hello World') => (eval x) Hello World require ------- ``require`` is used to import macros from one or more given modules. It allows parameters in all the same formats as ``import``. The ``require`` form itself produces no code in the final program: its effect is purely at compile-time, for the benefit of macro expansion. Specifically, ``require`` imports each named module and then makes each requested macro available in the current module. The following are all equivalent ways to call a macro named ``foo`` in the module ``mymodule``: .. code-block:: clj (require mymodule) (mymodule.foo 1) (require [mymodule :as M]) (M.foo 1) (require [mymodule [foo]]) (foo 1) (require [mymodule [*]]) (foo 1) (require [mymodule [foo :as bar]]) (bar 1) Macros that call macros ~~~~~~~~~~~~~~~~~~~~~~~ One aspect of ``require`` that may be surprising is what happens when one macro's expansion calls another macro. Suppose ``mymodule.hy`` looks like this: .. code-block:: clj (defmacro repexpr [n expr] ; Evaluate the expression n times ; and collect the results in a list. `(list (map (fn [_] ~expr) (range ~n)))) (defmacro foo [n] `(repexpr ~n (input "Gimme some input: "))) And then, in your main program, you write: .. code-block:: clj (require [mymodule [foo]]) (print (mymodule.foo 3)) Running this raises ``NameError: name 'repexpr' is not defined``, even though writing ``(print (foo 3))`` in ``mymodule`` works fine. The trouble is that your main program doesn't have the macro ``repexpr`` available, since it wasn't imported (and imported under exactly that name, as opposed to a qualified name). You could do ``(require [mymodule [*]])`` or ``(require [mymodule [foo repexpr]])``, but a less error-prone approach is to change the definition of ``foo`` to require whatever sub-macros it needs: .. code-block:: clj (defmacro foo [n] `(do (require mymodule) (mymodule.repexpr ~n (raw-input "Gimme some input: ")))) It's wise to use ``(require mymodule)`` here rather than ``(require [mymodule [repexpr]])`` to avoid accidentally shadowing a function named ``repexpr`` in the main program. Qualified macro names ~~~~~~~~~~~~~~~~~~~~~ Note that in the current implementation, there's a trick in qualified macro names, like ``mymodule.foo`` and ``M.foo`` in the above example. These names aren't actually attributes of module objects; they're just identifiers with periods in them. In fact, ``mymodule`` and ``M`` aren't defined by these ``require`` forms, even at compile-time. None of this will hurt you unless try to do introspection of the current module's set of defined macros, which isn't really supported anyway. rest / cdr ---------- ``rest`` and ``cdr`` return the collection passed as an argument without the first element: .. code-block:: clj => (rest (range 10)) [1, 2, 3, 4, 5, 6, 7, 8, 9] set-comp -------- ``set-comp`` is used to create sets. It takes two or three parameters. The first parameter is for controlling the return value, while the second is used to select items from a sequence. The third and optional parameter can be used to filter out some of the items in the sequence based on a conditional expression. .. code-block:: hy => (setv data [1 2 3 4 5 2 3 4 5 3 4 5]) => (set-comp x [x data] (odd? x)) {1, 3, 5} cut ----- ``cut`` can be used to take a subset of a list and create a new list from it. The form takes at least one parameter specifying the list to cut. Two optional parameters can be used to give the start and end position of the subset. If they are not supplied, the default value of ``None`` will be used instead. The third optional parameter is used to control step between the elements. ``cut`` follows the same rules as its Python counterpart. Negative indices are counted starting from the end of the list. Some example usage: .. code-block:: clj => (def collection (range 10)) => (cut collection) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] => (cut collection 5) [5, 6, 7, 8, 9] => (cut collection 2 8) [2, 3, 4, 5, 6, 7] => (cut collection 2 8 2) [2, 4, 6] => (cut collection -4 -2) [6, 7] raise ------------- The ``raise`` form can be used to raise an ``Exception`` at runtime. Example usage: .. code-block:: clj (raise) ; re-rase the last exception (raise IOError) ; raise an IOError (raise (IOError "foobar")) ; raise an IOError("foobar") ``raise`` can accept a single argument (an ``Exception`` class or instance) or no arguments to re-raise the last ``Exception``. try --- The ``try`` form is used to start a ``try`` / ``except`` block. The form is used as follows: .. code-block:: clj (try (error-prone-function) (except [e ZeroDivisionError] (print "Division by zero")) (else (print "no errors")) (finally (print "all done"))) ``try`` must contain at least one ``except`` block, and may optionally include an ``else`` or ``finally`` block. If an error is raised with a matching except block during the execution of ``error-prone-function``, that ``except`` block will be executed. If no errors are raised, the ``else`` block is executed. The ``finally`` block will be executed last regardless of whether or not an error was raised. unless ------ The ``unless`` macro is a shorthand for writing an ``if`` statement that checks if the given conditional is ``False``. The following shows the expansion of this macro. .. code-block:: clj (unless conditional statement) (if conditional None (do statement)) unquote ------- Within a quasiquoted form, ``unquote`` forces evaluation of a symbol. ``unquote`` is aliased to the tilde (``~``) symbol. .. code-block:: clj (def name "Cuddles") (quasiquote (= name (unquote name))) ;=> (u'=' u'name' u'Cuddles') `(= name ~name) ;=> (u'=' u'name' u'Cuddles') unquote-splice -------------- ``unquote-splice`` forces the evaluation of a symbol within a quasiquoted form, much like ``unquote``. ``unquote-splice`` can only be used when the symbol being unquoted contains an iterable value, as it "splices" that iterable into the quasiquoted form. ``unquote-splice`` is aliased to the ``~@`` symbol. .. code-block:: clj (def nums [1 2 3 4]) (quasiquote (+ (unquote-splice nums))) ;=> (u'+' 1L 2L 3L 4L) `(+ ~@nums) ;=> (u'+' 1L 2L 3L 4L) when ---- ``when`` is similar to ``unless``, except it tests when the given conditional is ``True``. It is not possible to have an ``else`` block in a ``when`` macro. The following shows the expansion of the macro. .. code-block:: clj (when conditional statement) (if conditional (do statement)) while ----- ``while`` is used to execute one or more blocks as long as a condition is met. The following example will output "Hello world!" to the screen indefinitely: .. code-block:: clj (while True (print "Hello world!")) with ---- ``with`` is used to wrap the execution of a block within a context manager. The context manager can then set up the local system and tear it down in a controlled manner. The archetypical example of using ``with`` is when processing files. ``with`` can bind context to an argument or ignore it completely, as shown below: .. code-block:: clj (with [arg (expr)] block) (with [(expr)] block) (with [arg (expr) (expr)] block) The following example will open the ``NEWS`` file and print its content to the screen. The file is automatically closed after it has been processed. .. code-block:: clj (with [f (open "NEWS")] (print (.read f))) with-decorator -------------- ``with-decorator`` is used to wrap a function with another. The function performing the decoration should accept a single value: the function being decorated, and return a new function. ``with-decorator`` takes a minimum of two parameters: the function performing decoration and the function being decorated. More than one decorator function can be applied; they will be applied in order from outermost to innermost, ie. the first decorator will be the outermost one, and so on. Decorators with arguments are called just like a function call. .. code-block:: clj (with-decorator decorator-fun (defn some-function [] ...) (with-decorator decorator1 decorator2 ... (defn some-function [] ...) (with-decorator (decorator arg) .. (defn some-function [] ...) In the following example, ``inc-decorator`` is used to decorate the function ``addition`` with a function that takes two parameters and calls the decorated function with values that are incremented by 1. When the decorated ``addition`` is called with values 1 and 1, the end result will be 4 (``1+1 + 1+1``). .. code-block:: clj => (defn inc-decorator [func] ... (fn [value-1 value-2] (func (+ value-1 1) (+ value-2 1)))) => (defn inc2-decorator [func] ... (fn [value-1 value-2] (func (+ value-1 2) (+ value-2 2)))) => (with-decorator inc-decorator (defn addition [a b] (+ a b))) => (addition 1 1) 4 => (with-decorator inc2-decorator inc-decorator ... (defn addition [a b] (+ a b))) => (addition 1 1) 8 #@ ~~ .. versionadded:: 0.12.0 The :ref:`reader macro` ``#@`` can be used as a shorthand for ``with-decorator``. With ``#@``, the previous example becomes: .. code-block:: clj => #@(inc-decorator (defn addition [a b] (+ a b))) => (addition 1 1) 4 => #@(inc2-decorator inc-decorator ... (defn addition [a b] (+ a b))) => (addition 1 1) 8 .. _with-gensyms: with-gensyms ------------- .. versionadded:: 0.9.12 ``with-gensym`` is used to generate a set of :ref:`gensym` for use in a macro. The following code: .. code-block:: hy (with-gensyms [a b c] ...) expands to: .. code-block:: hy (let [a (gensym) b (gensym) c (gensym)] ...) .. seealso:: 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 ----- ``yield`` is used to create a generator object that returns one or more values. The generator is iterable and therefore can be used in loops, list comprehensions and other similar constructs. The function ``random-numbers`` shows how generators can be used to generate infinite series without consuming infinite amount of memory. .. code-block:: clj => (defn multiply [bases coefficients] ... (for [(, base coefficient) (zip bases coefficients)] ... (yield (* base coefficient)))) => (multiply (range 5) (range 5)) => (list-comp value [value (multiply (range 10) (range 10))]) [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] => (import random) => (defn random-numbers [low high] ... (while True (yield (.randint random low high)))) => (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] yield-from ---------- .. versionadded:: 0.9.13 **PYTHON 3.3 AND UP ONLY!** ``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 `_. hy-0.12.1/docs/language/cli.rst000066400000000000000000000036411304171765200162410ustar00rootroot00000000000000====================== Command Line Interface ====================== .. _hy: hy -- Command Line Options ^^^^^^^^^^^^^^^^^^^^ .. cmdoption:: -c Execute the Hy code in *command*. .. code-block:: bash $ hy -c "(print (+ 2 2))" 4 .. cmdoption:: -i Execute the Hy code in *command*, then stay in REPL. .. cmdoption:: -m Execute the Hy code in *module*, including ``defmain`` if defined. The :option:`-m` flag terminates the options list so that all arguments after the *module* name are passed to the module in ``sys.argv``. .. versionadded:: 0.11.0 .. cmdoption:: --spy Print equivalent Python code before executing in REPL. For example:: => (defn salutationsnm [name] (print (+ "Hy " name "!"))) def salutationsnm(name): return print(((u'Hy ' + name) + u'!')) => (salutationsnm "YourName") salutationsnm(u'YourName') Hy YourName! => `--spy` only works on REPL mode. .. versionadded:: 0.9.11 .. cmdoption:: --show-tracebacks Print extended tracebacks for Hy exceptions. .. versionadded:: 0.9.12 .. cmdoption:: -v Print the Hy version number and exit. .. _hyc: hyc --- Command Line Options ^^^^^^^^^^^^^^^^^^^^ .. cmdoption:: file[, fileN] Compile Hy code to Python bytecode. For example, save the following code as ``hyname.hy``: .. code-block:: hy (defn hy-hy [name] (print (+ "Hy " name "!"))) (hy-hy "Afroman") Then run: .. code-block:: bash $ 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. hy-0.12.1/docs/language/core.rst000066400000000000000000000532271304171765200164270ustar00rootroot00000000000000======= Hy Core ======= Core Functions ============== .. _butlast-fn: butlast ------- Usage: ``(butlast coll)`` Returns an iterator of all but the last item in *coll*. .. code-block:: hy => (list (butlast (range 10))) [0, 1, 2, 3, 4, 5, 6, 7, 8] => (list (butlast [1])) [] => (list (butlast [])) [] => (list (take 5 (butlast (count 10)))) [10, 11, 12, 13, 14] .. _is-coll-fn: coll? ----- .. versionadded:: 0.10.0 Usage: ``(coll? x)`` Returns ``True`` if *x* is iterable and not a string. .. code-block:: hy => (coll? [1 2 3 4]) True => (coll? {"a" 1 "b" 2}) True => (coll? "abc") False .. _comp: comp ---- Usage: ``(comp f g)`` Compose zero or more functions into a new function. The new function will chain the given functions together, so ``((comp g f) x)`` is equivalent to ``(g (f x))``. Called without arguments, ``comp`` returns ``identity``. .. code-block:: hy => (def example (comp str +)) => (example 1 2 3) "6" => (def simple (comp)) => (simple "hello") "hello" .. _complement: complement ---------- .. versionadded:: 0.12.0 Usage: ``(complement f)`` Returns a new function that returns the same thing as ``f``, but logically inverted. So, ``((complement f) x)`` is equivalent to ``(not (f x))``. .. code-block:: hy => (def inverse (complement identity)) => (inverse True) False => (inverse 1) False => (inverse False) True cons ---- .. versionadded:: 0.10.0 Usage: ``(cons a b)`` Returns a fresh :ref:`cons cell ` with car *a* and cdr *b*. .. code-block:: hy => (setv a (cons 'hd 'tl)) => (= 'hd (car a)) True => (= 'tl (cdr a)) True cons? ----- .. versionadded:: 0.10.0 Usage: ``(cons? foo)`` Checks whether *foo* is a :ref:`cons cell `. .. code-block:: hy => (setv a (cons 'hd 'tl)) => (cons? a) True => (cons? None) False => (cons? [1 2 3]) False .. _constantly: constantly ---------- .. versionadded:: 0.12.0 Usage ``(constantly 42)`` Create a new function that always returns the given value, regardless of the arguments given to it. .. code-block:: hy => (def answer (constantly 42)) => (answer) 42 => (answer 1 2 3) 42 => (answer 1 :foo 2) 42 .. _dec-fn: dec --- Usage: ``(dec x)`` Returns one less than *x*. Equivalent to ``(- x 1)``. Raises ``TypeError`` if ``(not (numeric? x))``. .. code-block:: hy => (dec 3) 2 => (dec 0) -1 => (dec 12.3) 11.3 .. _disassemble-fn: disassemble ----------- .. versionadded:: 0.10.0 Usage: ``(disassemble tree &optional [codegen false])`` Dump the Python AST for given Hy *tree* to standard output. If *codegen* is ``True``, the function prints Python code instead. .. code-block:: hy => (disassemble '(print "Hello World!")) Module( body=[ Expr(value=Call(func=Name(id='print'), args=[Str(s='Hello World!')], keywords=[], starargs=None, kwargs=None))]) => (disassemble '(print "Hello World!") True) print('Hello World!') .. _empty?-fn: empty? ------ Usage: ``(empty? coll)`` Returns ``True`` if *coll* is empty. Equivalent to ``(= 0 (len coll))``. .. code-block:: hy => (empty? []) True => (empty? "") True => (empty? (, 1 2)) False .. _every?-fn: every? ------ .. versionadded:: 0.10.0 Usage: ``(every? pred coll)`` Returns ``True`` if ``(pred x)`` is logical true for every *x* in *coll*, otherwise ``False``. Return ``True`` if *coll* is empty. .. code-block:: hy => (every? even? [2 4 6]) True => (every? even? [1 3 5]) False => (every? even? [2 4 5]) False => (every? even? []) True .. _float?-fn: float? ------- Usage: ``(float? x)`` Returns ``True`` if *x* is a float. .. code-block:: hy => (float? 3.2) True => (float? -2) False .. _fraction-fn: fraction -------- Returns a Python object of type ``fractions.Fraction``. .. code-block:: hy => (fraction 1 2) Fraction(1, 2) Note that Hy has a built-in fraction literal that does the same thing: .. code-block:: hy => 1/2 Fraction(1, 2) .. _even?-fn: even? ----- Usage: ``(even? x)`` Returns ``True`` if *x* is even. Raises ``TypeError`` if ``(not (numeric? x))``. .. code-block:: hy => (even? 2) True => (even? 13) False => (even? 0) True .. _identity-fn: identity -------- Usage: ``(identity x)`` Returns the argument supplied to the function. .. code-block:: hy => (identity 4) 4 => (list (map identity [1 2 3 4])) [1 2 3 4] .. _inc-fn: inc --- Usage: ``(inc x)`` Returns one more than *x*. Equivalent to ``(+ x 1)``. Raises ``TypeError`` if ``(not (numeric? x))``. .. code-block:: hy => (inc 3) 4 => (inc 0) 1 => (inc 12.3) 13.3 .. _instance?-fn: instance? --------- Usage: ``(instance? class x)`` Returns ``True`` if *x* is an instance of *class*. .. code-block:: hy => (instance? float 1.0) True => (instance? int 7) True => (instance? str (str "foo")) True => (defclass TestClass [object]) => (setv inst (TestClass)) => (instance? TestClass inst) True .. _integer?-fn: integer? -------- Usage: ``(integer? x)`` Returns `True` if *x* is an integer. For Python 2, this is either ``int`` or ``long``. For Python 3, this is ``int``. .. code-block:: hy => (integer? 3) True => (integer? -2.4) False .. _interleave-fn: interleave ---------- .. versionadded:: 0.10.1 Usage: ``(interleave seq1 seq2 ...)`` Returns an iterable of the first item in each of the sequences, then the second, etc. .. code-block:: hy => (list (interleave (range 5) (range 100 105))) [0, 100, 1, 101, 2, 102, 3, 103, 4, 104] => (list (interleave (range 1000000) "abc")) [0, 'a', 1, 'b', 2, 'c'] .. _interpose-fn: interpose --------- .. versionadded:: 0.10.1 Usage: ``(interpose item seq)`` Returns an iterable of the elements of the sequence separated by the item. .. code-block:: hy => (list (interpose "!" "abcd")) ['a', '!', 'b', '!', 'c', '!', 'd'] => (list (interpose -1 (range 5))) [0, -1, 1, -1, 2, -1, 3, -1, 4] .. _iterable?-fn: iterable? --------- Usage: ``(iterable? x)`` Returns ``True`` if *x* is iterable. Iterable objects return a new iterator when ``(iter x)`` is called. Contrast with :ref:`iterator?-fn`. .. code-block:: hy => ;; works for strings => (iterable? (str "abcde")) True => ;; works for lists => (iterable? [1 2 3 4 5]) True => ;; works for tuples => (iterable? (, 1 2 3)) True => ;; works for dicts => (iterable? {:a 1 :b 2 :c 3}) True => ;; works for iterators/generators => (iterable? (repeat 3)) True .. _iterator?-fn: iterator? --------- Usage: ``(iterator? x)`` Returns ``True`` if *x* is an iterator. Iterators are objects that return themselves as an iterator when ``(iter x)`` is called. Contrast with :ref:`iterable?-fn`. .. code-block:: hy => ;; doesn't work for a list => (iterator? [1 2 3 4 5]) False => ;; but we can get an iter from the list => (iterator? (iter [1 2 3 4 5])) True => ;; doesn't work for dict => (iterator? {:a 1 :b 2 :c 3}) False => ;; create an iterator from the dict => (iterator? (iter {:a 1 :b 2 :c 3})) True .. _juxt-fn: juxt ---- .. versionadded:: 0.12.0 Usage: ``(juxt f &rest fs)`` Return a function that applies each of the supplied functions to a single set of arguments and collects the results into a list. .. code-block:: hy => ((juxt min max sum) (range 1 101)) [1, 100, 5050] => (dict (map (juxt identity ord) "abcdef")) {'f': 102, 'd': 100, 'b': 98, 'e': 101, 'c': 99, 'a': 97} => ((juxt + - * /) 24 3) [27, 21, 72, 8.0] .. _keyword-fn: keyword ------- .. versionadded:: 0.10.1 Usage: ``(keyword "foo")`` Create a keyword from the given value. Strings, numbers, and even objects with the `__name__` magic will work. .. code-block:: hy => (keyword "foo") u'\ufdd0:foo' => (keyword 1) u'\ufdd0:1' .. _keyword?-fn: keyword? -------- .. versionadded:: 0.10.1 Usage: ``(keyword? foo)`` Check whether *foo* is a :ref:`keyword`. .. code-block:: hy => (keyword? :foo) True => (setv foo 1) => (keyword? foo) False .. _list*-fn: list* ----- Usage: ``(list* head &rest tail)`` Generates a chain of nested cons cells (a dotted list) containing the arguments. If the argument list only has one element, return it. .. code-block:: hy => (list* 1 2 3 4) (1 2 3 . 4) => (list* 1 2 3 [4]) [1, 2, 3, 4] => (list* 1) 1 => (cons? (list* 1 2 3 4)) True .. _macroexpand-fn: macroexpand ----------- .. versionadded:: 0.10.0 Usage: ``(macroexpand form)`` Returns the full macro expansion of *form*. .. code-block:: hy => (macroexpand '(-> (a b) (x y))) (u'x' (u'a' u'b') u'y') => (macroexpand '(-> (a b) (-> (c d) (e f)))) (u'e' (u'c' (u'a' u'b') u'd') u'f') .. _macroexpand-1-fn: macroexpand-1 ------------- .. versionadded:: 0.10.0 Usage: ``(macroexpand-1 form)`` Returns the single step macro expansion of *form*. .. code-block:: hy => (macroexpand-1 '(-> (a b) (-> (c d) (e f)))) (u'_>' (u'a' u'b') (u'c' u'd') (u'e' u'f')) .. _merge-with-fn: merge-with ---------- .. versionadded:: 0.10.1 Usage: ``(merge-with f &rest maps)`` Returns a map that consist of the rest of the maps joined onto first. If a key occurs in more than one map, the mapping(s) from the latter (left-to-right) will be combined with the mapping in the result by calling ``(f val-in-result val-in-latter)``. .. code-block:: hy => (merge-with (fn [x y] (+ x y)) {"a" 10 "b" 20} {"a" 1 "c" 30}) {u'a': 11L, u'c': 30L, u'b': 20L} .. _name-fn: name ---- .. versionadded:: 0.10.1 Usage: ``(name :keyword)`` Convert the given value to a string. Keyword special character will be stripped. Strings will be used as is. Even objects with the `__name__` magic will work. .. code-block:: hy => (name :foo) u'foo' .. _neg?-fn: neg? ---- Usage: ``(neg? x)`` Returns ``True`` if *x* is less than zero. Raises ``TypeError`` if ``(not (numeric? x))``. .. code-block:: hy => (neg? -2) True => (neg? 3) False => (neg? 0) False .. _none?-fn: none? ----- Usage: ``(none? x)`` Returns ``True`` if *x* is ``None``. .. code-block:: hy => (none? None) True => (none? 0) False => (setf x None) => (none? x) True => ;; list.append always returns None => (none? (.append [1 2 3] 4)) True .. _nth-fn: nth --- Usage: ``(nth coll n &optional [default None])`` Returns the *n*-th item in a collection, counting from 0. Return the default value, ``None``, if out of bounds (unless specified otherwise). Raises ``ValueError`` if *n* is negative. .. code-block:: hy => (nth [1 2 4 7] 1) 2 => (nth [1 2 4 7] 3) 7 => (none? (nth [1 2 4 7] 5)) True => (nth [1 2 4 7] 5 "default") 'default' => (nth (take 3 (drop 2 [1 2 3 4 5 6])) 2)) 5 => (nth [1 2 4 7] -1) Traceback (most recent call last): ... ValueError: Indices for islice() must be None or an integer: 0 <= x <= sys.maxsize. .. _numeric?-fn: numeric? -------- Usage: ``(numeric? x)`` Returns ``True`` if *x* is a numeric, as defined in Python's ``numbers.Number`` class. .. code-block:: hy => (numeric? -2) True => (numeric? 3.2) True => (numeric? "foo") False .. _odd?-fn: odd? ---- Usage: ``(odd? x)`` Returns ``True`` if *x* is odd. Raises ``TypeError`` if ``(not (numeric? x))``. .. code-block:: hy => (odd? 13) True => (odd? 2) False => (odd? 0) False .. _partition-fn: partition --------- Usage: ``(partition coll [n] [step] [fillvalue])`` Chunks *coll* into *n*-tuples (pairs by default). .. code-block:: hy => (list (partition (range 10))) ; n=2 [(, 0 1) (, 2 3) (, 4 5) (, 6 7) (, 8 9)] The *step* defaults to *n*, but can be more to skip elements, or less for a sliding window with overlap. .. code-block:: hy => (list (partition (range 10) 2 3)) [(, 0 1) (, 3 4) (, 6 7)] => (list (partition (range 5) 2 1)) [(, 0 1) (, 1 2) (, 2 3) (, 3 4)]) The remainder, if any, is not included unless a *fillvalue* is specified. .. code-block:: hy => (list (partition (range 10) 3)) [(, 0 1 2) (, 3 4 5) (, 6 7 8)] => (list (partition (range 10) 3 :fillvalue "x")) [(, 0 1 2) (, 3 4 5) (, 6 7 8) (, 9 "x" "x")] .. _pos?-fn: pos? ---- Usage: ``(pos? x)`` Returns ``True`` if *x* is greater than zero. Raises ``TypeError`` if ``(not (numeric? x))``. .. code-block:: hy => (pos? 3) True => (pos? -2) False => (pos? 0) False .. _second-fn: second ------ Usage: ``(second coll)`` Returns the second member of *coll*. Equivalent to ``(get coll 1)``. .. code-block:: hy => (second [0 1 2]) 1 .. _some-fn: some ---- .. versionadded:: 0.10.0 Usage: ``(some pred coll)`` Returns the first logically-true value of ``(pred x)`` for any ``x`` in *coll*, otherwise ``None``. Return ``None`` if *coll* is empty. .. code-block:: hy => (some even? [2 4 6]) True => (none? (some even? [1 3 5])) True => (none? (some identity [0 "" []])) True => (some identity [0 "non-empty-string" []]) 'non-empty-string' => (none? (some even? [])) True .. _string?-fn: string? ------- Usage: ``(string? x)`` Returns ``True`` if *x* is a string. .. code-block:: hy => (string? "foo") True => (string? -2) False .. _symbol?-fn: symbol? ------- Usage: ``(symbol? x)`` Returns ``True`` if *x* is a symbol. .. code-block:: hy => (symbol? 'foo) True => (symbol? '[a b c]) False .. _zero?-fn: zero? ----- Usage: ``(zero? x)`` Returns ``True`` if *x* is zero. .. code-block:: hy => (zero? 3) False => (zero? -2) False => (zero? 0) True Sequence Functions ================== Sequence functions can either create or operate on a potentially infinite sequence without requiring the sequence be fully realized in a list or similar container. They do this by returning a Python iterator. We can use the canonical infinite Fibonacci number generator as an example of how to use some of these functions. .. code-block:: hy (defn fib [] (setv a 0) (setv b 1) (while True (yield a) (setv (, a b) (, b (+ a b))))) Note the ``(while True ...)`` loop. If we run this in the REPL, .. code-block:: hy => (fib) Calling the function only returns an iterator, but does no work until we consume it. Trying something like this is not recommend as the infinite loop will run until it consumes all available RAM, or in this case until I killed it. .. code-block:: hy => (list (fib)) [1] 91474 killed hy To get the first 10 Fibonacci numbers, use :ref:`take-fn`. Note that :ref:`take-fn` also returns a generator, so I create a list from it. .. code-block:: hy => (list (take 10 (fib))) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] To get the Fibonacci number at index 9, (starting from 0): .. code-block:: hy => (nth (fib) 9) 34 .. _cycle-fn: cycle ----- Usage: ``(cycle coll)`` Returns an infinite iterator of the members of coll. .. code-block:: clj => (list (take 7 (cycle [1 2 3]))) [1, 2, 3, 1, 2, 3, 1] => (list (take 2 (cycle [1 2 3]))) [1, 2] .. _distinct-fn: distinct -------- Usage: ``(distinct coll)`` Returns an iterator containing only the unique members in *coll*. .. code-block:: hy => (list (distinct [ 1 2 3 4 3 5 2 ])) [1, 2, 3, 4, 5] => (list (distinct [])) [] => (list (distinct (iter [ 1 2 3 4 3 5 2 ]))) [1, 2, 3, 4, 5] .. _drop-fn: drop ---- Usage: ``(drop n coll)`` Returns an iterator, skipping the first *n* members of *coll*. Raises ``ValueError`` if *n* is negative. .. code-block:: hy => (list (drop 2 [1 2 3 4 5])) [3, 4, 5] => (list (drop 4 [1 2 3 4 5])) [5] => (list (drop 0 [1 2 3 4 5])) [1, 2, 3, 4, 5] => (list (drop 6 [1 2 3 4 5])) [] .. _drop-last-fn: drop-last --------- Usage: ``(drop-last n coll)`` Returns an iterator of all but the last *n* items in *coll*. Raises ``ValueError`` if *n* is negative. .. code-block:: hy => (list (drop-last 5 (range 10 20))) [10, 11, 12, 13, 14] => (list (drop-last 0 (range 5))) [0, 1, 2, 3, 4] => (list (drop-last 100 (range 100))) [] => (list (take 5 (drop-last 100 (count 10)))) [10, 11, 12, 13, 14] .. _drop-while-fn: drop-while ----------- Usage: ``(drop-while pred coll)`` Returns an iterator, skipping members of *coll* until *pred* is ``False``. .. code-block:: hy => (list (drop-while even? [2 4 7 8 9])) [7, 8, 9] => (list (drop-while numeric? [1 2 3 None "a"]))) [None, u'a'] => (list (drop-while pos? [2 4 7 8 9])) [] .. _filter-fn: filter ------ Usage: ``(filter pred coll)`` Returns an iterator for all items in *coll* that pass the predicate *pred*. See also :ref:`remove-fn`. .. code-block:: hy => (list (filter pos? [1 2 3 -4 5 -7])) [1, 2, 3, 5] => (list (filter even? [1 2 3 -4 5 -7])) [2, -4] .. _flatten-fn: flatten ------- .. versionadded:: 0.9.12 Usage: ``(flatten coll)`` Returns a single list of all the items in *coll*, by flattening all contained lists and/or tuples. .. code-block:: hy => (flatten [1 2 [3 4] 5]) [1, 2, 3, 4, 5] => (flatten ["foo" (, 1 2) [1 [2 3] 4] "bar"]) ['foo', 1, 2, 1, 2, 3, 4, 'bar'] .. _iterate-fn: iterate ------- Usage: ``(iterate fn x)`` Returns an iterator of *x*, *fn(x)*, *fn(fn(x))*, etc. .. code-block:: hy => (list (take 5 (iterate inc 5))) [5, 6, 7, 8, 9] => (list (take 5 (iterate (fn [x] (* x x)) 5))) [5, 25, 625, 390625, 152587890625] .. _read-fn: read ---- Usage: ``(read &optional [from-file eof])`` Reads the next Hy expression from *from-file* (defaulting to ``sys.stdin``), and can take a single byte as EOF (defaults to an empty string). Raises ``EOFError`` if *from-file* ends before a complete expression can be parsed. .. code-block:: hy => (read) (+ 2 2) ('+' 2 2) => (eval (read)) (+ 2 2) 4 => (import io) => (def buffer (io.StringIO "(+ 2 2)\n(- 2 1)")) => (eval (apply read [] {"from_file" buffer})) 4 => (eval (apply read [] {"from_file" buffer})) 1 => ; assuming "example.hy" contains: => ; (print "hello") => ; (print "hyfriends!") => (with [f (open "example.hy")] ... (try ... (while True ... (let [exp (read f)] ... (do ... (print "OHY" exp) ... (eval exp)))) ... (except [e EOFError] ... (print "EOF!")))) OHY ('print' 'hello') hello OHY ('print' 'hyfriends!') hyfriends! EOF! read-str -------- Usage: ``(read-str "string")`` This is essentially a wrapper around `read` which reads expressions from a string: .. code-block:: hy => (read-str "(print 1)") (u'print' 1L) => (eval (read-str "(print 1)")) 1 => .. _remove-fn: remove ------ Usage: ``(remove pred coll)`` Returns an iterator from *coll* with elements that pass the predicate, *pred*, removed. See also :ref:`filter-fn`. .. code-block:: hy => (list (remove odd? [1 2 3 4 5 6 7])) [2, 4, 6] => (list (remove pos? [1 2 3 4 5 6 7])) [] => (list (remove neg? [1 2 3 4 5 6 7])) [1, 2, 3, 4, 5, 6, 7] .. _repeat-fn: repeat ------ Usage: ``(repeat x)`` Returns an iterator (infinite) of ``x``. .. code-block:: hy => (list (take 6 (repeat "s"))) [u's', u's', u's', u's', u's', u's'] .. _repeatedly-fn: repeatedly ---------- Usage: ``(repeatedly fn)`` Returns an iterator by calling *fn* repeatedly. .. code-block:: hy => (import [random [randint]]) => (list (take 5 (repeatedly (fn [] (randint 0 10))))) [6, 2, 0, 6, 7] .. _take-fn: take ---- Usage: ``(take n coll)`` Returns an iterator containing the first *n* members of *coll*. Raises ``ValueError`` if *n* is negative. .. code-block:: hy => (list (take 3 [1 2 3 4 5])) [1, 2, 3] => (list (take 4 (repeat "s"))) [u's', u's', u's', u's'] => (list (take 0 (repeat "s"))) [] .. _take-nth-fn: take-nth -------- Usage: ``(take-nth n coll)`` Returns an iterator containing every *n*-th member of *coll*. .. code-block:: hy => (list (take-nth 2 [1 2 3 4 5 6 7])) [1, 3, 5, 7] => (list (take-nth 3 [1 2 3 4 5 6 7])) [1, 4, 7] => (list (take-nth 4 [1 2 3 4 5 6 7])) [1, 5] => (list (take-nth 10 [1 2 3 4 5 6 7])) [1] .. _take-while-fn: take-while ---------- Usage: ``(take-while pred coll)`` Returns an iterator from *coll* as long as *pred* returns ``True``. .. code-block:: hy => (list (take-while pos? [ 1 2 3 -4 5])) [1, 2, 3] => (list (take-while neg? [ -4 -3 1 2 5])) [-4, -3] => (list (take-while neg? [ 1 2 3 -4 5])) [] Other Built-Ins =============== hy.core.reserved ---------------- Usage: ``(hy.core.reserved.names)`` This module can be used to get a list (actually, a ``frozenset``) of the names of Hy's built-in functions, macros, and special forms. The output also includes all Python reserved words. All names are in unmangled form (e.g., ``list-comp`` rather than ``list_comp``). .. code-block:: hy => (import hy) => (in "defclass" (hy.core.reserved.names)) True Included itertools ================== count cycle repeat accumulate chain compress drop-while remove group-by islice *map take-while tee zip-longest product permutations combinations multicombinations --------- All of Python's `itertools `_ are available. Some of their names have been changed: - ``starmap`` has been changed to ``*map`` - ``combinations_with_replacement`` has been changed to ``multicombinations`` - ``groupby`` has been changed to ``group-by`` - ``takewhile`` has been changed to ``take-while`` - ``dropwhile`` has been changed to ``drop-while`` - ``filterfalse`` has been changed to ``remove`` hy-0.12.1/docs/language/index.rst000066400000000000000000000002061304171765200165730ustar00rootroot00000000000000 Documentation Index =================== Contents: .. toctree:: :maxdepth: 3 cli api core readermacros internals hy-0.12.1/docs/language/internals.rst000066400000000000000000000363371304171765200175010ustar00rootroot00000000000000========================= Internal Hy Documentation ========================= .. note:: These bits are mostly useful for folks who hack on Hy itself, but can also be used for those delving deeper in macro programming. .. _models: Hy Models ========= Introduction to Hy Models ------------------------- Hy models are a very thin layer on top of regular Python objects, representing Hy source code as data. Models only add source position information, and a handful of methods to support clean manipulation of Hy source code, for instance in macros. To achieve that goal, Hy models are mixins of a base Python class and :ref:`HyObject`. .. _hyobject: HyObject ~~~~~~~~ ``hy.models.HyObject`` is the base class of Hy models. It only implements one method, ``replace``, which replaces the source position of the current object with the one passed as argument. This allows us to keep track of the original position of expressions that get modified by macros, be that in the compiler or in pure hy macros. ``HyObject`` is not intended to be used directly to instantiate Hy models, but only as a mixin for other classes. Compound Models --------------- Parenthesized and bracketed lists are parsed as compound models by the Hy parser. .. _hylist: HyList ~~~~~~ ``hy.models.list.HyList`` is the base class of "iterable" Hy models. Its basic use is to represent bracketed ``[]`` lists, which, when used as a top-level expression, translate to Python list literals in the compilation phase. Adding a HyList to another iterable object reuses the class of the left-hand-side object, a useful behavior when you want to concatenate Hy objects in a macro, for instance. .. _hyexpression: HyExpression ~~~~~~~~~~~~ ``hy.models.expression.HyExpression`` inherits :ref:`HyList` for parenthesized ``()`` expressions. The compilation result of those expressions depends on the first element of the list: the compiler dispatches expressions between compiler special-forms, user-defined macros, and regular Python function calls. .. _hydict: HyDict ~~~~~~ ``hy.models.dict.HyDict`` inherits :ref:`HyList` for curly-bracketed ``{}`` expressions, which compile down to a Python dictionary literal. The decision of using a list instead of a dict as the base class for ``HyDict`` allows easier manipulation of dicts in macros, with the added benefit of allowing compound expressions as dict keys (as, for instance, the :ref:`HyExpression` Python class isn't hashable). Atomic Models ------------- In the input stream, double-quoted strings, respecting the Python notation for strings, are parsed as a single token, which is directly parsed as a :ref:`HyString`. An uninterrupted string of characters, excluding spaces, brackets, quotes, double-quotes and comments, is parsed as an identifier. Identifiers are resolved to atomic models during the parsing phase in the following order: - :ref:`HyInteger ` - :ref:`HyFloat ` - :ref:`HyComplex ` (if the atom isn't a bare ``j``) - :ref:`HyKeyword` (if the atom starts with ``:``) - :ref:`HySymbol` .. _hystring: HyString ~~~~~~~~ ``hy.models.string.HyString`` is the base class of string-equivalent Hy models. It also represents double-quoted string literals, ``""``, which compile down to unicode string literals in Python. ``HyStrings`` inherit unicode objects in Python 2, and string objects in Python 3 (and are therefore not encoding-dependent). ``HyString`` based models are immutable. Hy literal strings can span multiple lines, and are considered by the parser as a single unit, respecting the Python escapes for unicode strings. .. _hy_numeric_models: Numeric Models ~~~~~~~~~~~~~~ ``hy.models.integer.HyInteger`` represents integer literals (using the ``long`` type on Python 2, and ``int`` on Python 3). ``hy.models.float.HyFloat`` represents floating-point literals. ``hy.models.complex.HyComplex`` represents complex literals. Numeric models are parsed using the corresponding Python routine, and valid numeric python literals will be turned into their Hy counterpart. .. _hysymbol: HySymbol ~~~~~~~~ ``hy.models.symbol.HySymbol`` is the model used to represent symbols in the Hy language. It inherits :ref:`HyString`. ``HySymbol`` objects are mangled in the parsing phase, to help Python interoperability: - Symbols surrounded by asterisks (``*``) are turned into uppercase; - Dashes (``-``) are turned into underscores (``_``); - One trailing question mark (``?``) is turned into a leading ``is_``. Caveat: as the mangling is done during the parsing phase, it is possible to programmatically generate HySymbols that can't be generated with Hy source code. Such a mechanism is used by :ref:`gensym` to generate "uninterned" symbols. .. _hykeyword: HyKeyword ~~~~~~~~~ ``hy.models.keyword.HyKeyword`` represents keywords in Hy. Keywords are symbols starting with a ``:``. The class inherits :ref:`HyString`. To distinguish :ref:`HyKeywords ` from :ref:`HySymbols `, without the possibility of (involuntary) clashes, the private-use unicode character ``"\uFDD0"`` is prepended to the keyword literal before storage. .. _hycons: Cons Cells ========== ``hy.models.cons.HyCons`` is a representation of Python-friendly `cons cells`_. Cons cells are especially useful to mimic features of "usual" LISP variants such as Scheme or Common Lisp. .. _cons cells: https://en.wikipedia.org/wiki/Cons A cons cell is a 2-item object, containing a ``car`` (head) and a ``cdr`` (tail). In some Lisp variants, the cons cell is the fundamental 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`` mimics the behavior of "usual" Lisp variants thusly: - ``(cons something None)`` is ``(HyExpression [something])`` - ``(cons something some-list)`` is ``((type some-list) (+ [something] some-list))`` (if ``some-list`` inherits from ``list``). - ``(get (cons a b) 0)`` is ``a`` - ``(cut (cons a b) 1)`` is ``b`` Hy supports a dotted-list syntax, where ``'(a . b)`` means ``(cons 'a 'b)`` and ``'(a b . c)`` means ``(cons 'a (cons 'b 'c))``. If the compiler encounters a cons cell at the top level, it raises a compilation error. ``HyCons`` wraps the passed arguments (car and cdr) in Hy types, to ease the manipulation of cons cells in a macro context. Hy Internal Theory ================== .. _overview: Overview -------- The Hy internals work by acting as a front-end to Python bytecode, so that Hy itself compiles down to Python Bytecode, allowing an unmodified Python runtime to run Hy code, without even noticing it. The way we do this is by translating Hy into an internal Python AST datastructure, and building that AST down into Python bytecode using modules from the Python standard library, so that we don't have to duplicate all the work of the Python internals for every single Python release. Hy works in four stages. The following sections will cover each step of Hy from source to runtime. .. _lexing: Steps 1 and 2: Tokenizing and Parsing ------------------------------------- The first stage of compiling Hy is to lex the source into tokens that we can deal with. We use a project called rply, which is a really nice (and fast) parser, written in a subset of Python called rpython. The lexing code is all defined in ``hy.lex.lexer``. This code is mostly just defining the Hy grammar, and all the actual hard parts are taken care of by rply -- we just define "callbacks" for rply in ``hy.lex.parser``, which takes the tokens generated, and returns the Hy models. You can think of the Hy models as the "AST" for Hy, it's what Macros operate on (directly), and it's what the compiler uses when it compiles Hy down. .. seealso:: Section :ref:`models` for more information on Hy models and what they mean. .. _compiling: Step 3: Hy Compilation to Python AST ------------------------------------ This is where most of the magic in Hy happens. This is where we take Hy AST (the models), and compile them into Python AST. A couple of funky things happen here to work past a few problems in AST, and working in the compiler is some of the most important work we do have. The compiler is a bit complex, so don't feel bad if you don't grok it on the first shot, it may take a bit of time to get right. The main entry-point to the Compiler is ``HyASTCompiler.compile``. This method is invoked, and the only real "public" method on the class (that is to say, we don't really promise the API beyond that method). In fact, even internally, we don't recurse directly hardly ever, we almost always force the Hy tree through ``compile``, and will often do this with sub-elements of an expression that we have. It's up to the Type-based dispatcher to properly dispatch sub-elements. All methods that preform a compilation are marked with the ``@builds()`` decorator. You can either pass the class of the Hy model that it compiles, or you can use a string for expressions. I'll clear this up in a second. First Stage Type-Dispatch ~~~~~~~~~~~~~~~~~~~~~~~~~ Let's start in the ``compile`` method. The first thing we do is check the Type of the thing we're building. We look up to see if we have a method that can build the ``type()`` that we have, and dispatch to the method that can handle it. If we don't have any methods that can build that type, we raise an internal ``Exception``. For instance, if we have a ``HyString``, we have an almost 1-to-1 mapping of Hy AST to Python AST. The ``compile_string`` method takes the ``HyString``, and returns an ``ast.Str()`` that's populated with the correct line-numbers and content. Macro-Expand ~~~~~~~~~~~~ If we get a ``HyExpression``, we'll attempt to see if this is a known Macro, and push to have it expanded by invoking ``hy.macros.macroexpand``, then push the result back into ``HyASTCompiler.compile``. Second Stage Expression-Dispatch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The only special case is the ``HyExpression``, since we need to create different AST depending on the special form in question. For instance, when we hit an ``(if True True False)``, we need to generate a ``ast.If``, and properly compile the sub-nodes. This is where the ``@builds()`` with a String as an argument comes in. For the ``compile_expression`` (which is defined with an ``@builds(HyExpression)``) will dispatch based on the string of the first argument. If, for some reason, the first argument is not a string, it will properly handle that case as well (most likely by raising an ``Exception``). If the String isn't known to Hy, it will default to create an ``ast.Call``, which will try to do a runtime call (in Python, something like ``foo()``). Issues Hit with Python AST ~~~~~~~~~~~~~~~~~~~~~~~~~~ Python AST is great; it's what's enabled us to write such a powerful project on top of Python without having to fight Python too hard. Like anything, we've had our fair share of issues, and here's a short list of the common ones you might run into. *Python differentiates between Statements and Expressions*. This might not sound like a big deal -- in fact, to most Python programmers, this will shortly become a "Well, yeah" moment. In Python, doing something like: ``print for x in range(10): pass``, because ``print`` prints expressions, and ``for`` isn't an expression, it's a control flow statement. Things like ``1 + 1`` are Expressions, as is ``lambda x: 1 + x``, but other language features, such as ``if``, ``for``, or ``while`` are statements. Since they have no "value" to Python, this makes working in Hy hard, since doing something like ``(print (if True True False))`` is not just common, it's expected. As a result, we auto-mangle things using a ``Result`` object, where we offer up any ``ast.stmt`` that need to get run, and a single ``ast.expr`` that can be used to get the value of whatever was just run. Hy does this by forcing assignment to things while running. As example, the Hy:: (print (if True True False)) Will turn into:: if True: _mangled_name_here = True else: _mangled_name_here = False print _mangled_name_here OK, that was a bit of a lie, since we actually turn that statement into:: print True if True else False By forcing things into an ``ast.expr`` if we can, but the general idea holds. Step 4: Python Bytecode Output and Runtime ------------------------------------------ After we have a Python AST tree that's complete, we can try and compile it to Python bytecode by pushing it through ``eval``. From here on out, we're no longer in control, and Python is taking care of everything. This is why things like Python tracebacks, pdb and django apps work. Hy Macros ========= .. _using-gensym: Using gensym for Safer Macros ----------------------------- When writing macros, one must be careful to avoid capturing external variables or using variable names that might conflict with user code. We will use an example macro ``nif`` (see http://letoverlambda.com/index.cl/guest/chap3.html#sec_5 for a more complete description.) ``nif`` is an example, something like a numeric ``if``, where based on the expression, one of the 3 forms is called depending on if the expression is positive, zero or negative. A first pass might be something like: .. code-block:: hy (defmacro nif [expr pos-form zero-form neg-form] `(let [obscure-name ~expr] (cond [(pos? obscure-name) ~pos-form] [(zero? obscure-name) ~zero-form] [(neg? obscure-name) ~neg-form]))) 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. The method :ref:`gensym` is designed to generate a new, unique symbol for just such an occasion. A much better version of ``nif`` would be: .. code-block:: hy (defmacro nif [expr pos-form zero-form neg-form] (let [g (gensym)] `(let [~g ~expr] (cond [(pos? ~g) ~pos-form] [(zero? ~g) ~zero-form] [(neg? ~g) ~neg-form])))) This is an easy case, since there is only one symbol. But if there is a need for several gensym's there is a second macro :ref:`with-gensyms` that basically expands to a series of ``let`` statements: .. code-block:: hy (with-gensyms [a b c] ...) expands to: .. code-block:: hy (let [a (gensym) b (gensym) c (gensym)] ...) so our re-written ``nif`` would look like: .. code-block:: hy (defmacro nif [expr pos-form zero-form neg-form] (with-gensyms [g] `(let [~g ~expr] (cond [(pos? ~g) ~pos-form] [(zero? ~g) ~zero-form] [(neg? ~g) ~neg-form])))) Finally, though we can make a new macro that does all this for us. :ref:`defmacro/g!` will take all symbols that begin with ``g!`` and automatically call ``gensym`` with the remainder of the symbol. So ``g!a`` would become ``(gensym "a")``. Our final version of ``nif``, built with ``defmacro/g!`` becomes: .. code-block:: hy (defmacro/g! nif [expr pos-form zero-form neg-form] `(let [~g!res ~expr] (cond [(pos? ~g!res) ~pos-form] [(zero? ~g!res) ~zero-form] [(neg? ~g!res) ~neg-form])))) Checking Macro Arguments and Raising Exceptions ----------------------------------------------- Hy Compiler Built-Ins ===================== .. todo:: Write this. hy-0.12.1/docs/language/readermacros.rst000066400000000000000000000032751304171765200201440ustar00rootroot00000000000000.. _reader-macros: .. highlight:: clj ============= Reader Macros ============= Reader macros gives Lisp the power to modify and alter syntax on the fly. You don't want Polish notation? A reader macro can easily do just that. Want Clojure's way of having a regex? Reader macros can also do this easily. Syntax ====== :: => (defreader ^ [expr] (print expr)) => #^(1 2 3 4) (1 2 3 4) => #^"Hello" "Hello" => #^1+2+3+4+3+2 1+2+3+4+3+2 Hy has no literal for tuples. Lets say you dislike `(, ...)` and want something else. This is a problem reader macros are able to solve in a neat way. :: => (defreader t [expr] `(, ~@expr)) => #t(1 2 3) (1, 2, 3) You could even do it like Clojure and have a literal for regular expressions! :: => (import re) => (defreader r [expr] `(re.compile ~expr)) => #r".*" <_sre.SRE_Pattern object at 0xcv7713ph15#> Implementation ============== ``defreader`` takes a single character as symbol name for the reader macro; anything longer will return an error. Implementation-wise, ``defreader`` expands into a lambda covered with a decorator. This decorator saves the lambda in a dictionary with its module name and symbol. :: => (defreader ^ [expr] (print expr)) ;=> (with_decorator (hy.macros.reader ^) (fn [expr] (print expr))) ``#`` expands into ``(dispatch_reader_macro ...)`` where the symbol and expression is passed to the correct function. :: => #^() ;=> (dispatch_reader_macro ^ ()) => #^"Hello" "Hello" .. warning:: Because of a limitation in Hy's lexer and parser, reader macros can't redefine defined syntax such as ``()[]{}``. This will most likely be addressed in the future. hy-0.12.1/docs/make.bat000066400000000000000000000144631304171765200145660ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\hy.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\hy.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end hy-0.12.1/docs/quickstart.rst000066400000000000000000000022411304171765200160740ustar00rootroot00000000000000========== Quickstart ========== .. image:: _static/cuddles-transparent-small.png :alt: Karen Rustard's Cuddles (Thanks to Karen Rustad for Cuddles!) **HOW TO GET HY REAL FAST**: 1. Create a `Virtual Python Environment `_. 2. Activate your Virtual Python Environment. 3. Install `hy from GitHub `_ with ``$ pip install git+https://github.com/hylang/hy.git``. 4. Start a REPL with ``hy``. 5. Type stuff in the REPL:: => (print "Hy!") Hy! => (defn salutationsnm [name] (print (+ "Hy " name "!"))) => (salutationsnm "YourName") Hy YourName! etc 6. Hit CTRL-D when you're done. *OMG! That's amazing! I want to write a Hy program.* 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. Make it executable:: chmod +x awesome.hy 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. hy-0.12.1/docs/style-guide.rst000066400000000000000000000135031304171765200161400ustar00rootroot00000000000000============== Hy Style Guide ============== “You know, Minister, I disagree with Dumbledore on many counts…but you cannot deny he’s got style…” — Phineas Nigellus Black, *Harry Potter and the Order of the Phoenix* 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 interoperability. Prelude ======= The Tao of Hy ------------- .. code-block:: none Ummon asked the head monk, "What sutra are you lecturing on?" "The Nirvana Sutra." "The Nirvana Sutra has the Four Virtues, hasn't it?" "It has." Ummon asked, picking up a cup, "How many virtues has this?" "None at all," said the monk. "But ancient people said it had, didn't they?" said Ummon. "What do you think of what they said?" Ummon struck the cup and asked, "You understand?" "No," said the monk. "Then," said Ummon, "You'd better go on with your lectures on the sutra." — the (koan) macro The following illustrates a brief list of design decisions that went into the making of Hy. + Look like a Lisp; DTRT with it (e.g. dashes turn to underscores, earmuffs turn to all-caps). + We're still Python. Most of the internals translate 1:1 to Python internals. + Use Unicode everywhere. + Fix the bad decisions in Python 2 when we can (see ``true_division``). + When in doubt, defer to Python. + If you're still unsure, defer to Clojure. + If you're even more unsure, defer to Common Lisp. + Keep in mind we're not Clojure. We're not Common Lisp. We're Homoiconic Python, with extra bits that make sense. Layout & Indentation ==================== + Avoid trailing spaces. They suck! + Indentation shall be 2 spaces (no hard tabs), except when matching the indentation of the previous line. .. code-block:: clj ;; Good (and preferred) (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) ;; Still okay (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) ;; Still okay (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) ;; Hysterically ridiculous (defn fib [n] (if (<= n 2) n ;; yes, I love randomly hitting the space key (+ (fib (- n 1)) (fib (- n 2))))) + Parentheses must *never* be left alone, sad and lonesome on their own line. .. code-block:: clj ;; Good (and preferred) (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) ;; Hysterically ridiculous (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))) ) ) ; GAH, BURN IT WITH FIRE + Vertically align ``let`` blocks. .. code-block:: clj (let [foo (bar) qux (baz)] (foo qux)) + Inline comments shall be two spaces from the end of the code; they must always have a space between the comment character and the start of the comment. Also, try to not comment the obvious. .. code-block:: clj ;; Good (setv ind (dec x)) ; indexing starts from 0 ;; Style-compliant but just states the obvious (setv ind (dec x)) ; sets index to x-1 ;; Bad (setv ind (dec x));typing words for fun Coding Style ============ + As a convention, try not to use ``def`` for anything other than global variables; use ``setv`` inside functions, loops, etc. .. code-block:: clj ;; Good (and preferred) (def *limit* 400000) (defn fibs [a b] (while True (yield a) (setv (, a b) (, b (+ a b))))) ;; Bad (and not preferred) (defn fibs [a b] (while True (yield a) (def (, a b) (, b (+ a b))))) + Do not use s-expression syntax where vector syntax is intended. For instance, the fact that the former of these two examples works is just because the compiler isn't overly strict. In reality, the correct syntax in places such as this is the latter. .. code-block:: clj ;; Bad (and evil) (defn foo (x) (print x)) (foo 1) ;; Good (and preferred) (defn foo [x] (print x)) (foo 1) + Use the threading macro or the threading tail macros when encountering deeply nested s-expressions. However, be judicious when using them. Do use them when clarity and readability improves; do not construct convoluted, hard to understand expressions. .. code-block:: clj ;; Preferred (def *names* (with [f (open "names.txt")] (-> (.read f) (.strip) (.replace "\"" "") (.split ",") (sorted)))) ;; Not so good (def *names* (with [f (open "names.txt")] (sorted (.split "," (.replace "\"" "" (.strip (.read f))))))) ;; Probably not a good idea (defn square? [x] (->> 2 (pow (int (sqrt x))) (= x))) + Clojure-style dot notation is preferred over the direct call of the object's method, though both will continue to be supported. .. code-block:: clj ;; Good (with [fd (open "/etc/passwd")] (print (.readlines fd))) ;; Not so good (with [fd (open "/etc/passwd")] (print (fd.readlines))) Conclusion ========== “Fashions fade, style is eternal” —Yves Saint Laurent This guide is just a set of community guidelines, and obviously, community guidelines do not make sense without an active community. Contributions are welcome. Join us at #hy in freenode, blog about it, tweet about it, and most importantly, have fun with Hy. Thanks ====== + This guide is heavily inspired from `@paultag`_ 's blog post `Hy Survival Guide`_ + The `Clojure Style Guide`_ .. _`Hy Survival Guide`: http://notes.pault.ag/hy-survival-guide/ .. _`Clojure Style Guide`: https://github.com/bbatsov/clojure-style-guide .. _`@paultag`: https://github.com/paultag hy-0.12.1/docs/tutorial.rst000066400000000000000000000441631304171765200155560ustar00rootroot00000000000000======== Tutorial ======== .. TODO .. .. - How do I index into arrays or dictionaries? .. - How do I do array ranges? e.g. x[5:] or y[2:10] .. - Blow your mind with macros! .. - Where's my banana??? .. - Mention that you can import .hy files in .py files and vice versa! Welcome to the Hy tutorial! In a nutshell, Hy is a Lisp dialect, but one that converts its structure into Python ... literally a conversion into Python's abstract syntax tree! (Or to put it in more crude terms, Hy is lisp-stick on a Python!) This is pretty cool because it means Hy is several things: - A Lisp that feels very Pythonic - For Lispers, a great way to use Lisp's crazy powers but in the wide world of Python's libraries (why yes, you now can write a Django application in Lisp!) - For Pythonistas, a great way to start exploring Lisp, from the comfort of Python! - For everyone: a pleasant language that has a lot of neat ideas! Basic intro to Lisp for Pythonistas =================================== Okay, maybe you've never used Lisp before, but you've used Python! A "hello world" program in Hy is actually super simple. Let's try it: .. code-block:: clj (print "hello world") See? Easy! As you may have guessed, this is the same as the Python version of:: print "hello world" To add up some super simple math, we could do: .. code-block:: clj (+ 1 3) Which would return 4 and would be the equivalent of: .. code-block:: clj 1 + 3 What you'll notice is that the first item in the list is the function being called and the rest of the arguments are the arguments being passed in. In fact, in Hy (as with most Lisps) we can pass in multiple arguments to the plus operator: .. code-block:: clj (+ 1 3 55) Which would return 59. Maybe you've heard of Lisp before but don't know much about it. Lisp isn't as hard as you might think, and Hy inherits from Python, so Hy is a great way to start learning Lisp. The main thing that's obvious about Lisp is that there's a lot of parentheses. This might seem confusing at first, but it isn't so hard. Let's look at some simple math that's wrapped in a bunch of parentheses that we could enter into the Hy interpreter: .. code-block:: clj (setv result (- (/ (+ 1 3 88) 2) 8)) This would return 38. But why? Well, we could look at the equivalent expression in python:: result = ((1 + 3 + 88) / 2) - 8 If you were to try to figure out how the above were to work in python, you'd of course figure out the results by solving each inner parenthesis. That's the same basic idea in Hy. Let's try this exercise first in Python:: result = ((1 + 3 + 88) / 2) - 8 # simplified to... result = (92 / 2) - 8 # simplified to... result = 46 - 8 # simplified to... result = 38 Now let's try the same thing in Hy: .. code-block:: clj (setv result (- (/ (+ 1 3 88) 2) 8)) ; simplified to... (setv result (- (/ 92 2) 8)) ; simplified to... (setv result (- 46 8)) ; simplified to... (setv result 38) As you probably guessed, this last expression with ``setv`` means to assign the variable "result" to 38. See? Not too hard! This is the basic premise of Lisp. Lisp stands for "list 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 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:: def simple_conversation(): print "Hello! I'd like to get to know you. Tell me about yourself!" name = raw_input("What is your name? ") age = raw_input("What is your age? ") print "Hello " + name + "! I see you are " + age + " years old." simple_conversation() If we ran this program, it might go like:: Hello! I'd like to get to know you. Tell me about yourself! What is your name? Gary What is your age? 38 Hello Gary! I see you are 38 years old. Now let's look at the equivalent Hy program: .. code-block:: clj (defn simple-conversation [] (print "Hello! I'd like to get to know you. Tell me about yourself!") (setv name (raw-input "What is your name? ")) (setv age (raw-input "What is your age? ")) (print (+ "Hello " name "! I see you are " age " years old."))) (simple-conversation) If you look at the above program, as long as you remember that the first element in each list of the program is the function (or macro... we'll get to those later) being called and that the rest are the arguments, it's pretty easy to figure out what this all means. (As you probably also guessed, ``defn`` is the Hy method of defining methods.) Still, lots of people find this confusing at first because there's so many parentheses, but there are plenty of things that can help make this easier: keep indentation nice and use an editor with parenthesis matching (this will help you figure out what each parenthesis pairs up with) and things will start to feel comfortable. 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 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.) Another implication of this is macros: if a program's structure is a simple data structure, that means you can write code that can write code very easily, meaning that implementing entirely new language features can be very fast. Previous to Hy, this wasn't very possible for Python programmers ... now you too can make use of macros' incredible power (just be careful to not aim them footward)! Hy is a Lisp-flavored Python ============================ Hy converts to Python's own abstract syntax tree, so you'll soon start to find that all the familiar power of python is at your fingertips. You have full access to Python's data types and standard library in Hy. Let's experiment with this in the hy interpreter:: => [1 2 3] [1, 2, 3] => {"dog" "bark" ... "cat" "meow"} ... {'dog': 'bark', 'cat': 'meow'} => (, 1 2 3) (1, 2, 3) => #{3 1 2} {1, 2, 3} => 1/2 Fraction(1, 2) Notice the last two lines: Hy has a fraction literal like Clojure. If you are familiar with other Lisps, you may be interested that Hy supports the Common Lisp method of quoting: .. code-block:: clj => '(1 2 3) (1L 2L 3L) You also have access to all the built-in types' nice methods:: => (.strip " fooooo ") "fooooo" What's this? Yes indeed, this is precisely the same as:: " fooooo ".strip() That's right---Lisp with dot notation! If we have this string assigned as a variable, we can also do the following: .. code-block:: clj (setv this-string " fooooo ") (this-string.strip) What about conditionals?: .. code-block:: clj (if (try-some-thing) (print "this is if true") (print "this is if false")) As you can tell above, the first argument to ``if`` is a truth test, the second argument is the body if true, and the third argument (optional!) is if false (ie. ``else``). If you need to do more complex conditionals, you'll find that you don't have ``elif`` available in Hy. Instead, you should use something called ``cond``. In Python, you might do something like:: somevar = 33 if somevar > 50: print "That variable is too big!" elif somevar < 10: print "That variable is too small!" else: print "That variable is jussssst right!" In Hy, you would do: .. code-block:: clj (setv somevar 33) (cond [(> somevar 50) (print "That variable is too big!")] [(< somevar 10) (print "That variable is too small!")] [True (print "That variable is jussssst right!")]) What you'll notice is that ``cond`` switches off between a statement that is executed and checked conditionally for true or falseness, and then a bit of code to execute if it turns out to be true. You'll also notice that the ``else`` is implemented at the end simply by checking for ``True`` -- that's because ``True`` will always be true, so if we get this far, we'll always run that one! You might notice above that if you have code like: .. code-block:: clj (if some-condition (body-if-true) (body-if-false)) But wait! What if you want to execute more than one statement in the body of one of these? You can do the following: .. code-block:: clj (if (try-some-thing) (do (print "this is if true") (print "and why not, let's keep talking about how true it is!")) (print "this one's still simply just false")) You can see that we used ``do`` to wrap multiple statements. If you're familiar with other Lisps, this is the equivalent of ``progn`` elsewhere. Comments start with semicolons: .. code-block:: clj (print "this will run") ; (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:: for i in range(10): print "'i' is now at " + str(i) The equivalent in Hy would be: .. code-block:: clj (for [i (range 10)] (print (+ "'i' is now at " (str i)))) You can also import and make use of various Python libraries. For example: .. code-block:: clj (import os) (if (os.path.isdir "/tmp/somedir") (os.mkdir "/tmp/somedir/anotherdir") (print "Hey, that path isn't there!")) Python's context managers (``with`` statements) are used like this: .. code-block:: clj (with [f (open "/tmp/data.in")] (print (.read f))) which is equivalent to:: with open("/tmp/data.in") as f: print f.read() And yes, we do have List comprehensions! In Python you might do:: odds_squared = [ pow(num, 2) for num in range(100) if num % 2 == 1] In Hy, you could do these like: .. code-block:: clj (setv odds-squared (list-comp (pow num 2) (num (range 100)) (= (% num 2) 1))) .. code-block:: clj ; And, an example stolen shamelessly from a Clojure page: ; Let's list all the blocks of a Chessboard: (list-comp (, x y) (x (range 8) y "ABCDEFGH")) ; [(0, 'A'), (0, 'B'), (0, 'C'), (0, 'D'), (0, 'E'), (0, 'F'), (0, 'G'), (0, 'H'), ; (1, 'A'), (1, 'B'), (1, 'C'), (1, 'D'), (1, 'E'), (1, 'F'), (1, 'G'), (1, 'H'), ; (2, 'A'), (2, 'B'), (2, 'C'), (2, 'D'), (2, 'E'), (2, 'F'), (2, 'G'), (2, 'H'), ; (3, 'A'), (3, 'B'), (3, 'C'), (3, 'D'), (3, 'E'), (3, 'F'), (3, 'G'), (3, 'H'), ; (4, 'A'), (4, 'B'), (4, 'C'), (4, 'D'), (4, 'E'), (4, 'F'), (4, 'G'), (4, 'H'), ; (5, 'A'), (5, 'B'), (5, 'C'), (5, 'D'), (5, 'E'), (5, 'F'), (5, 'G'), (5, 'H'), ; (6, 'A'), (6, 'B'), (6, 'C'), (6, 'D'), (6, 'E'), (6, 'F'), (6, 'G'), (6, 'H'), ; (7, 'A'), (7, 'B'), (7, 'C'), (7, 'D'), (7, 'E'), (7, 'F'), (7, 'G'), (7, 'H')] Python has support for various fancy argument and keyword arguments. In Python we might see:: >>> def optional_arg(pos1, pos2, keyword1=None, keyword2=42): ... return [pos1, pos2, keyword1, keyword2] ... >>> optional_arg(1, 2) [1, 2, None, 42] >>> optional_arg(1, 2, 3, 4) [1, 2, 3, 4] >>> optional_arg(keyword1=1, pos2=2, pos1=3, keyword2=4) [3, 2, 1, 4] The same thing in Hy:: => (defn optional-arg [pos1 pos2 &optional keyword1 [keyword2 42]] ... [pos1 pos2 keyword1 keyword2]) => (optional-arg 1 2) [1 2 None 42] => (optional-arg 1 2 3 4) [1 2 3 4] If you're running a version of Hy past 0.10.1 (eg, git master), there's also a nice new keyword argument syntax:: => (optional-arg :keyword1 1 ... :pos2 2 ... :pos1 3 ... :keyword2 4) [3, 2, 1, 4] Otherwise, you can always use `apply`. But what's `apply`? Are you familiar with passing in `*args` and `**kwargs` in Python?:: >>> args = [1 2] >>> kwargs = {"keyword2": 3 ... "keyword1": 4} >>> optional_arg(*args, **kwargs) We can reproduce this with `apply`:: => (setv args [1 2]) => (setv kwargs {"keyword2" 3 ... "keyword1" 4}) => (apply optional-arg args kwargs) [1, 2, 4, 3] There's also a dictionary-style keyword arguments construction that looks like: .. code-block:: clj (defn another-style [&key {"key1" "val1" "key2" "val2"}] [key1 key2]) The difference here is that since it's a dictionary, you can't rely on any specific ordering to the arguments. Hy also supports ``*args`` and ``**kwargs``. In Python:: def some_func(foo, bar, *args, **kwargs): import pprint pprint.pprint((foo, bar, args, kwargs)) The Hy equivalent: .. code-block:: clj (defn some-func [foo bar &rest args &kwargs kwargs] (import pprint) (pprint.pprint (, foo bar args kwargs))) Finally, of course we need classes! In Python, we might have a class like:: class FooBar(object): """ Yet Another Example Class """ def __init__(self, x): self.x = x def get_x(self): """ Return our copy of x """ return self.x In Hy: .. code-block:: clj (defclass FooBar [object] "Yet Another Example Class" (defn --init-- [self x] (setv self.x x)) (defn get-x [self] "Return our copy of x" self.x)) You can also do class-level attributes. In Python:: class Customer(models.Model): name = models.CharField(max_length=255) address = models.TextField() notes = models.TextField() In Hy: .. code-block:: clj (defclass Customer [models.Model] [name (models.CharField :max-length 255}) address (models.TextField) notes (models.TextField)]) Macros ====== 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 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 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. This macro writes a piece of program that looks like this (provided that we used "Tuukka" as parameter): .. code-block:: clj (print "Hello there," Tuukka) We can also manipulate code with macros: .. code-block:: clj => (defmacro rev [code] ... (let [op (last code) params (list (butlast code))] ... `(~op ~@params))) => (rev (1 2 3 +)) 6 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 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): .. code-block:: clj => (defreader ↻ [code] ... (let [op (last code) params (list (butlast code))] ... `(~op ~@params))) => #↻(1 2 3 +) 6 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 ``->``. What if you want to use a macro that's defined in a different module? The special form ``import`` won't help, because it merely translates to a Python ``import`` statement that's executed at run-time, and macros are expanded at compile-time, that is, during the translate from Hy to Python. Instead, use ``require``, which imports the module and makes macros available at compile-time. ``require`` uses the same syntax as ``import``. .. code-block:: clj => (require tutorial.macros) => (tutorial.macros.rev (1 2 3 +)) 6 Hy <-> Python interop ===================== By importing Hy, you can use Hy directly from Python! If you save the following in ``greetings.hy``: .. code-block:: clj (defn greet [name] (print "hello from hy," name)) Then you can use it directly from python, by importing hy before importing the module. In Python:: import hy import greetings greetings.greet("Foo") You can also declare a function in python (or even a class!) and use it in Hy! If you save the following in ``greetings.py`` in Python:: def greet(name): print("hello, %s" % (name)) You can use it in Hy: .. code-block:: clj (import greetings) (.greet greetings "foo") To use keyword arguments, you can use in ``greetings.py``:: def greet(name, title="Sir"): print("Greetings, %s %s" % (title,name)) .. code-block:: clj (import greetings) (.greet greetings "Foo") (.greet greetings "Foo" "Darth") (apply (. greetings greet) ["Foo"] {:title "Lord"}) Which would output:: Greetings, Sir Foo Greetings, Darth Foo Greetings, Lord Foo Protips! ======== Hy also features something known as the "threading macro", a really neat feature of Clojure's. The "threading macro" (written as ``->``) is used to avoid deep nesting of expressions. The threading macro inserts each expression into the next expression's first argument place. Let's take the classic: .. code-block:: clj (loop (print (eval (read)))) Rather than write it like that, we can write it as follows: .. code-block:: clj (-> (read) (eval) (print) (loop)) Now, using `python-sh `_, we can show how the threading macro (because of python-sh's setup) can be used like a pipe: .. code-block:: clj => (import [sh [cat grep wc]]) => (-> (cat "/usr/share/dict/words") (grep "-E" "^hy") (wc "-l")) 210 Which, of course, expands out to: .. code-block:: clj (wc (grep (cat "/usr/share/dict/words") "-E" "^hy") "-l") Much more readable, no? Use the threading macro! hy-0.12.1/hy/000077500000000000000000000000001304171765200126415ustar00rootroot00000000000000hy-0.12.1/hy/__init__.py000066400000000000000000000033771304171765200147640ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. __appname__ = 'hy' try: from hy.version import __version__ except ImportError: __version__ = 'unknown' from hy.models.expression import HyExpression # NOQA from hy.models.integer import HyInteger # NOQA from hy.models.keyword import HyKeyword # NOQA from hy.models.complex import HyComplex # NOQA from hy.models.string import HyString # NOQA from hy.models.symbol import HySymbol # NOQA from hy.models.float import HyFloat # NOQA from hy.models.dict import HyDict # NOQA from hy.models.list import HyList # NOQA from hy.models.set import HySet # NOQA from hy.models.cons import HyCons # NOQA import hy.importer # NOQA # we import for side-effects. hy-0.12.1/hy/__main__.py000066400000000000000000000026751304171765200147450ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. import hy # NOQA import imp import sys # This just mocks the normalish behavior of the Python interp. Helpful to aid # with shimming existing apps that don't really "work" with Hy. # # You could say this script helps Hyjack a file. # if len(sys.argv) > 1: sys.argv.pop(0) imp.load_source("__main__", sys.argv[0]) sys.exit(0) # right? hy-0.12.1/hy/_compat.py000066400000000000000000000044001304171765200146330ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # Copyright (c) 2013 Julien Danjou # Copyright (c) 2013 Berker Peksag # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. try: import __builtin__ as builtins except ImportError: import builtins # NOQA try: from py_compile import MAGIC, wr_long except ImportError: # py_compile.MAGIC removed and imp.get_magic() deprecated in Python 3.4 from importlib.util import MAGIC_NUMBER as MAGIC # NOQA def wr_long(f, x): """Internal; write a 32-bit int to a file in little-endian order.""" f.write(bytes([x & 0xff, (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff])) import sys PY27 = sys.version_info >= (2, 7) PY3 = sys.version_info[0] >= 3 PY33 = sys.version_info >= (3, 3) PY34 = sys.version_info >= (3, 4) PY35 = sys.version_info >= (3, 5) if PY3: str_type = str else: str_type = unicode # NOQA if PY3: long_type = int else: long_type = long # NOQA if PY3: string_types = str, else: string_types = basestring, # NOQA if PY3: exec('def raise_empty(t, *args): raise t(*args) from None') else: def raise_empty(t, *args): raise t(*args) hy-0.12.1/hy/cmdline.py000066400000000000000000000327051304171765200146350ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # Copyright (c) 2013 Gergely Nagy # Copyright (c) 2013 James King # Copyright (c) 2013 Julien Danjou # Copyright (c) 2013 Konrad Hinsen # Copyright (c) 2013 Thom Neale # Copyright (c) 2013 Will Kahn-Greene # Copyright (c) 2013 Bob Tolbert # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from __future__ import print_function import argparse import code import ast import sys import os 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, import_file_to_ast, import_file_to_hst, import_buffer_to_ast, import_buffer_to_hst) from hy.completer import completion from hy.completer import Completer from hy.errors import HyIOError from hy.macros import macro, require from hy.models.expression import HyExpression from hy.models.string import HyString from hy.models.symbol import HySymbol from hy._compat import builtins, PY3 class HyQuitter(object): def __init__(self, name): self.name = name def __repr__(self): return "Use (%s) or Ctrl-D (i.e. EOF) to exit" % (self.name) __str__ = __repr__ def __call__(self, code=None): try: sys.stdin.close() except: pass raise SystemExit(code) builtins.quit = HyQuitter('quit') builtins.exit = HyQuitter('exit') def print_python_code(_ast): # astor cannot handle ast.Interactive, so disguise it as a module _ast_for_print = ast.Module() _ast_for_print.body = _ast.body print(astor.codegen.to_source(_ast_for_print)) class HyREPL(code.InteractiveConsole): def __init__(self, spy=False, locals=None, filename=""): self.spy = spy code.InteractiveConsole.__init__(self, locals=locals, filename=filename) def runsource(self, source, filename='', symbol='single'): global SIMPLE_TRACEBACKS try: tokens = tokenize(source) except PrematureEndOfInput: return True except LexException as e: if e.source is None: e.source = source e.filename = filename print(e, file=sys.stderr) return False try: _ast = hy_compile(tokens, "__console__", root=ast.Interactive) if self.spy: print_python_code(_ast) code = ast_compile(_ast, filename, symbol) except HyTypeError as e: if e.source is None: e.source = source e.filename = filename if SIMPLE_TRACEBACKS: print(e, file=sys.stderr) else: self.showtraceback() return False except Exception: self.showtraceback() return False self.runcode(code) return False @macro("koan") def koan_macro(): return HyExpression([HySymbol('print'), HyString(""" Ummon asked the head monk, "What sutra are you lecturing on?" "The Nirvana Sutra." "The Nirvana Sutra has the Four Virtues, hasn't it?" "It has." Ummon asked, picking up a cup, "How many virtues has this?" "None at all," said the monk. "But ancient people said it had, didn't they?" said Ummon. "What do you think of what they said?" Ummon struck the cup and asked, "You understand?" "No," said the monk. "Then," said Ummon, "You'd better go on with your lectures on the sutra." """)]) @macro("ideas") def ideas_macro(): return HyExpression([HySymbol('print'), HyString(r""" => (import [sh [figlet]]) => (figlet "Hi, Hy!") _ _ _ _ _ _ | | | (_) | | | |_ _| | | |_| | | | |_| | | | | | | _ | |_ | _ | |_| |_| |_| |_|_( ) |_| |_|\__, (_) |/ |___/ ;;; string things (.join ", " ["what" "the" "heck"]) ;;; this one plays with command line bits (import [sh [cat grep]]) (-> (cat "/usr/share/dict/words") (grep "-E" "bro$")) ;;; filtering a list w/ a lambda (filter (lambda [x] (= (% x 2) 0)) (range 0 10)) ;;; swaggin' functional bits (Python rulez) (max (map (lambda [x] (len x)) ["hi" "my" "name" "is" "paul"])) """)]) require("hy.cmdline", "__console__", all_macros=True) require("hy.cmdline", "__main__", all_macros=True) SIMPLE_TRACEBACKS = True def pretty_error(func, *args, **kw): try: return func(*args, **kw) except (HyTypeError, LexException) as e: if SIMPLE_TRACEBACKS: print(e, file=sys.stderr) sys.exit(1) raise def run_command(source): pretty_error(import_buffer_to_module, "__main__", source) return 0 def run_module(mod_name): from hy.importer import MetaImporter pth = MetaImporter().find_on_path(mod_name) if pth is not None: sys.argv = [pth] + sys.argv return run_file(pth) 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 pretty_error(import_file_to_module, "__main__", filename) return 0 def run_repl(hr=None, spy=False): import platform sys.ps1 = "=> " sys.ps2 = "... " namespace = {'__name__': '__console__', '__doc__': ''} with completion(Completer(namespace)): if not hr: hr = HyREPL(spy, namespace) hr.interact("{appname} {version} using " "{py}({build}) {pyversion} on {os}".format( appname=hy.__appname__, version=hy.__version__, py=platform.python_implementation(), build=platform.python_build()[0], pyversion=platform.python_version(), os=platform.system() )) return 0 def run_icommand(source, spy=False): hr = HyREPL(spy) if os.path.exists(source): with open(source, "r") as f: source = f.read() filename = source else: filename = '' hr.runsource(source, filename=filename, symbol='single') return run_repl(hr) USAGE = "%(prog)s [-h | -i cmd | -c cmd | -m module | file | -] [arg] ..." VERSION = "%(prog)s " + hy.__version__ EPILOG = """ file program read from script module module to execute as main - program read from stdin [arg] ... arguments passed to program in sys.argv[1:] """ def cmdline_handler(scriptname, argv): parser = argparse.ArgumentParser( prog="hy", usage=USAGE, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=EPILOG) parser.add_argument("-c", dest="command", help="program passed in as a string") parser.add_argument("-m", dest="mod", help="module to run, passed in as a string") parser.add_argument( "-i", dest="icommand", help="program passed in as a string, then stay in REPL") parser.add_argument("--spy", action="store_true", help="print equivalent Python code before executing") parser.add_argument("-v", "--version", action="version", version=VERSION) parser.add_argument("--show-tracebacks", action="store_true", help="show complete tracebacks for Hy exceptions") # this will contain the script/program name and any arguments for it. parser.add_argument('args', nargs=argparse.REMAINDER, help=argparse.SUPPRESS) # stash the hy executable in case we need it later # mimics Python sys.executable hy.executable = argv[0] # need to split the args if using "-m" # all args after the MOD are sent to the module # in sys.argv module_args = [] if "-m" in argv: mloc = argv.index("-m") if len(argv) > mloc+2: module_args = argv[mloc+2:] argv = argv[:mloc+2] options = parser.parse_args(argv[1:]) if options.show_tracebacks: global SIMPLE_TRACEBACKS SIMPLE_TRACEBACKS = False # reset sys.argv like Python sys.argv = options.args + module_args or [""] if options.command: # User did "hy -c ..." return run_command(options.command) if options.mod: # User did "hy -m ..." return run_module(options.mod) if options.icommand: # User did "hy -i ..." return run_icommand(options.icommand, spy=options.spy) if options.args: if options.args[0] == "-": # Read the program from stdin return run_command(sys.stdin.read()) else: # User did "hy " try: return run_file(options.args[0]) except HyIOError as e: 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! return run_repl(spy=options.spy) # entry point for cmd line script "hy" def hy_main(): sys.exit(cmdline_handler("hy", sys.argv)) # entry point for cmd line script "hyc" def hyc_main(): from hy.importer import write_hy_as_pyc parser = argparse.ArgumentParser(prog="hyc") parser.add_argument("files", metavar="FILE", nargs='+', help="file to compile") parser.add_argument("-v", action="version", version=VERSION) options = parser.parse_args(sys.argv[1:]) for file in options.files: try: print("Compiling %s" % file) pretty_error(write_hy_as_pyc, file) except IOError as x: 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) # entry point for cmd line script "hy2py" def hy2py_main(): import platform module_name = "" options = dict(prog="hy2py", usage="%(prog)s [options] [FILE]", formatter_class=argparse.RawDescriptionHelpFormatter) parser = argparse.ArgumentParser(**options) parser.add_argument("FILE", type=str, nargs='?', help="Input Hy code (use STDIN if \"-\" or " "not provided)") 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")) options = parser.parse_args(sys.argv[1:]) stdin_text = None if options.FILE is None or options.FILE == '-': stdin_text = sys.stdin.read() if options.with_source: hst = (pretty_error(import_file_to_hst, options.FILE) if stdin_text is None else pretty_error(import_buffer_to_hst, stdin_text)) # need special printing on Windows in case the # codepage doesn't support utf-8 characters if PY3 and platform.system() == "Windows": for h in hst: try: print(h) except: print(str(h).encode('utf-8')) else: print(hst) print() print() _ast = (pretty_error(import_file_to_ast, options.FILE, module_name) if stdin_text is None else pretty_error(import_buffer_to_ast, stdin_text, module_name)) if options.with_ast: if PY3 and platform.system() == "Windows": _print_for_windows(astor.dump(_ast)) else: print(astor.dump(_ast)) print() print() if not options.without_python: if PY3 and platform.system() == "Windows": _print_for_windows(astor.codegen.to_source(_ast)) else: print(astor.codegen.to_source(_ast)) parser.exit(0) # need special printing on Windows in case the # codepage doesn't support utf-8 characters def _print_for_windows(src): for line in src.split("\n"): try: print(line) except: print(line.encode('utf-8')) hy-0.12.1/hy/compiler.py000066400000000000000000002754511304171765200150430ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # # Copyright (c) 2013, 2014 Paul Tagliamonte # Copyright (c) 2013 Julien Danjou # Copyright (c) 2013 Nicolas Dandrimont # Copyright (c) 2013 James King # Copyright (c) 2013, 2014 Bob Tolbert # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models.expression import HyExpression from hy.models.keyword import HyKeyword from hy.models.integer import HyInteger from hy.models.complex import HyComplex from hy.models.string import HyString from hy.models.symbol import HySymbol from hy.models.float import HyFloat from hy.models.list import HyList from hy.models.set import HySet from hy.models.dict import HyDict from hy.models.cons import HyCons from hy.errors import HyCompileError, HyTypeError from hy.lex.parser import hy_symbol_mangle import hy.macros from hy._compat import ( str_type, long_type, PY27, PY33, PY3, PY34, PY35, raise_empty) from hy.macros import require, macroexpand, reader_macroexpand import hy.importer import traceback import importlib import codecs import ast import sys import keyword from collections import defaultdict _compile_time_ns = {} def compile_time_ns(module_name): ns = _compile_time_ns.get(module_name) if ns is None: ns = {'hy': hy, '__name__': module_name} _compile_time_ns[module_name] = ns return ns _stdlib = {} def load_stdlib(): import hy.core for module in hy.core.STDLIB: mod = importlib.import_module(module) for e in mod.EXPORTS: _stdlib[e] = module # True, False and None included here since they # are assignable in Python 2.* but become # keywords in Python 3.* def _is_hy_builtin(name, module_name): extras = ['True', 'False', 'None'] if name in extras or keyword.iskeyword(name): return True # for non-Hy modules, check for pre-existing name in # _compile_table if not module_name.startswith("hy."): return name in _compile_table return False _compile_table = {} def ast_str(foobar): if PY3: return str(foobar) try: return str(foobar) except UnicodeEncodeError: pass enc = codecs.getencoder('punycode') foobar, _ = enc(foobar) return "hy_%s" % (str(foobar).replace("-", "_")) def builds(_type): unpythonic_chars = ["-"] really_ok = ["-"] if any(x in unpythonic_chars for x in str_type(_type)): if _type not in really_ok: raise TypeError("Dear Hypster: `build' needs to be *post* " "translated strings... `%s' sucks." % (_type)) def _dec(fn): _compile_table[_type] = fn return fn return _dec def builds_if(_type, condition): if condition: return builds(_type) else: return lambda fn: fn class Result(object): """ Smart representation of the result of a hy->AST compilation This object tries to reconcile the hy world, where everything can be used as an expression, with the Python world, where statements and expressions need to coexist. To do so, we represent a compiler result as a list of statements `stmts`, terminated by an expression context `expr`. The expression context is used when the compiler needs to use the result as an expression. Results are chained by addition: adding two results together returns a Result representing the succession of the two Results' statements, with the second Result's expression context. We make sure that a non-empty expression context does not get clobbered by adding more results, by checking accesses to the expression context. We assume that the context has been used, or deliberately ignored, if it has been accessed. The Result object is interoperable with python AST objects: when an AST object gets added to a Result object, it gets converted on-the-fly. """ __slots__ = ("imports", "stmts", "temp_variables", "_expr", "__used_expr", "contains_yield") def __init__(self, *args, **kwargs): if args: # emulate kw-only args for future bits. raise TypeError("Yo: Hacker: don't pass me real args, dingus") self.imports = defaultdict(set) self.stmts = [] self.temp_variables = [] self._expr = None self.contains_yield = False self.__used_expr = False # XXX: Make sure we only have AST where we should. for kwarg in kwargs: if kwarg not in ["imports", "contains_yield", "stmts", "expr", "temp_variables"]: raise TypeError( "%s() got an unexpected keyword argument '%s'" % ( self.__class__.__name__, kwarg)) setattr(self, kwarg, kwargs[kwarg]) @property def expr(self): self.__used_expr = True return self._expr @expr.setter def expr(self, value): self.__used_expr = False self._expr = value def add_imports(self, mod, imports): """Autoimport `imports` from `mod`""" self.imports[mod].update(imports) def is_expr(self): """Check whether I am a pure expression""" return self._expr and not (self.imports or self.stmts) @property def force_expr(self): """Force the expression context of the Result. If there is no expression context, we return a "None" expression. """ if self.expr: return self.expr # Spoof the position of the last statement for our generated None lineno = 0 col_offset = 0 if self.stmts: lineno = self.stmts[-1].lineno col_offset = self.stmts[-1].col_offset return ast.Name(id=ast_str("None"), arg=ast_str("None"), ctx=ast.Load(), lineno=lineno, col_offset=col_offset) # XXX: Likely raise Exception here - this will assertionfail # pypy since the ast will be out of numerical order. def expr_as_stmt(self): """Convert the Result's expression context to a statement This is useful when we want to use the stored expression in a statement context (for instance in a code branch). We drop ast.Names if they are appended to statements, as they can't have any side effect. "Bare" names still get converted to statements. If there is no expression context, return an empty result. """ if self.expr and not (isinstance(self.expr, ast.Name) and self.stmts): return Result() + ast.Expr(lineno=self.expr.lineno, col_offset=self.expr.col_offset, value=self.expr) return Result() def rename(self, new_name): """Rename the Result's temporary variables to a `new_name`. We know how to handle ast.Names and ast.FunctionDefs. """ new_name = ast_str(new_name) for var in self.temp_variables: if isinstance(var, ast.Name): var.id = new_name var.arg = new_name elif isinstance(var, ast.FunctionDef): var.name = new_name else: raise TypeError("Don't know how to rename a %s!" % ( var.__class__.__name__)) self.temp_variables = [] def __add__(self, other): # If we add an ast statement, convert it first if isinstance(other, ast.stmt): return self + Result(stmts=[other]) # If we add an ast expression, clobber the expression context if isinstance(other, ast.expr): return self + Result(expr=other) if isinstance(other, ast.excepthandler): return self + Result(stmts=[other]) if not isinstance(other, Result): raise TypeError("Can't add %r with non-compiler result %r" % ( self, other)) # Check for expression context clobbering if self.expr and not self.__used_expr: traceback.print_stack() print("Bad boy clobbered expr %s with %s" % ( ast.dump(self.expr), ast.dump(other.expr))) # Fairly obvious addition result = Result() result.imports = other.imports result.stmts = self.stmts + other.stmts result.expr = other.expr result.temp_variables = other.temp_variables result.contains_yield = False if self.contains_yield or other.contains_yield: result.contains_yield = True return result def __str__(self): return ( "Result(imports=[%s], stmts=[%s], " "expr=%s, contains_yield=%s)" ) % ( ", ".join(ast.dump(x) for x in self.imports), ", ".join(ast.dump(x) for x in self.stmts), ast.dump(self.expr) if self.expr else None, self.contains_yield ) def _branch(results): """Make a branch out of a list of Result objects This generates a Result from the given sequence of Results, forcing each expression context as a statement before the next result is used. We keep the expression context of the last argument for the returned Result """ results = list(results) ret = Result() for result in results[:-1]: ret += result ret += result.expr_as_stmt() for result in results[-1:]: ret += result return ret def _raise_wrong_args_number(expression, error): raise HyTypeError(expression, error % (expression.pop(0), len(expression))) def checkargs(exact=None, min=None, max=None, even=None, multiple=None): def _dec(fn): def checker(self, expression): if exact is not None and (len(expression) - 1) != exact: _raise_wrong_args_number( expression, "`%%s' needs %d arguments, got %%d" % exact) if min is not None and (len(expression) - 1) < min: _raise_wrong_args_number( expression, "`%%s' needs at least %d arguments, got %%d." % (min)) if max is not None and (len(expression) - 1) > max: _raise_wrong_args_number( expression, "`%%s' needs at most %d arguments, got %%d" % (max)) is_even = not((len(expression) - 1) % 2) if even is not None and is_even != even: even_str = "even" if even else "odd" _raise_wrong_args_number( expression, "`%%s' needs an %s number of arguments, got %%d" % (even_str)) if multiple is not None: if not (len(expression) - 1) in multiple: choices = ", ".join([str(val) for val in multiple[:-1]]) choices += " or %s" % multiple[-1] _raise_wrong_args_number( expression, "`%%s' needs %s arguments, got %%d" % choices) return fn(self, expression) return checker return _dec class HyASTCompiler(object): def __init__(self, module_name): self.allow_builtins = False self.anon_fn_count = 0 self.anon_var_count = 0 self.imports = defaultdict(set) self.module_name = module_name self.temp_if = None if not module_name.startswith("hy.core"): # everything in core needs to be explicit. load_stdlib() def get_anon_var(self): self.anon_var_count += 1 return "_hy_anon_var_%s" % self.anon_var_count def get_anon_fn(self): self.anon_fn_count += 1 return "_hy_anon_fn_%d" % self.anon_fn_count def update_imports(self, result): """Retrieve the imports from the result object""" for mod in result.imports: self.imports[mod].update(result.imports[mod]) def imports_as_stmts(self, expr): """Convert the Result's imports to statements""" ret = Result() for module, names in self.imports.items(): if None in names: ret += self.compile([ HyExpression([ HySymbol("import"), HySymbol(module), ]).replace(expr) ]) names = sorted(name for name in names if name) if names: ret += self.compile([ HyExpression([ HySymbol("import"), HyList([ HySymbol(module), HyList([HySymbol(name) for name in names]) ]) ]).replace(expr) ]) self.imports = defaultdict(set) return ret.stmts def compile_atom(self, atom_type, atom): if atom_type in _compile_table: ret = _compile_table[atom_type](self, atom) if not isinstance(ret, Result): ret = Result() + ret return ret def compile(self, tree): try: _type = type(tree) ret = self.compile_atom(_type, tree) if ret: self.update_imports(ret) return ret except HyCompileError: # compile calls compile, so we're going to have multiple raise # nested; so let's re-raise this exception, let's not wrap it in # another HyCompileError! raise except HyTypeError as e: raise except Exception as e: raise_empty(HyCompileError, e, sys.exc_info()[2]) raise HyCompileError(Exception("Unknown type: `%s'" % _type)) def _compile_collect(self, exprs, with_kwargs=False): """Collect the expression contexts from a list of compiled expression. This returns a list of the expression contexts, and the sum of the Result objects passed as arguments. """ compiled_exprs = [] ret = Result() keywords = [] exprs_iter = iter(exprs) for expr in exprs_iter: if with_kwargs and isinstance(expr, HyKeyword): try: value = next(exprs_iter) except StopIteration: raise HyTypeError(expr, "Keyword argument {kw} needs " "a value.".format(kw=str(expr[1:]))) compiled_value = self.compile(value) ret += compiled_value # no unicode for py2 in ast names keyword = str(expr[2:]) if "-" in keyword and keyword != "-": keyword = keyword.replace("-", "_") keywords.append(ast.keyword(arg=keyword, value=compiled_value.force_expr, lineno=expr.start_line, col_offset=expr.start_column)) else: ret += self.compile(expr) compiled_exprs.append(ret.force_expr) return compiled_exprs, ret, keywords def _compile_branch(self, exprs): return _branch(self.compile(expr) for expr in exprs) def _parse_lambda_list(self, exprs): """ Return FunctionDef parameter values from lambda list.""" ll_keywords = ("&rest", "&optional", "&key", "&kwonly", "&kwargs") ret = Result() args = [] defaults = [] varargs = None kwonlyargs = [] kwonlydefaults = [] kwargs = None lambda_keyword = None for expr in exprs: if expr in ll_keywords: if expr == "&optional": if len(defaults) > 0: raise HyTypeError(expr, "There can only be &optional " "arguments or one &key argument") lambda_keyword = expr elif expr in ("&rest", "&key", "&kwonly", "&kwargs"): lambda_keyword = expr else: raise HyTypeError(expr, "{0} is in an invalid " "position.".format(repr(expr))) # we don't actually care about this token, so we set # our state and continue to the next token... continue if lambda_keyword is None: args.append(expr) elif lambda_keyword == "&rest": if varargs: raise HyTypeError(expr, "There can only be one " "&rest argument") varargs = expr elif lambda_keyword == "&key": if type(expr) != HyDict: raise HyTypeError(expr, "There can only be one &key " "argument") else: if len(defaults) > 0: raise HyTypeError(expr, "There can only be &optional " "arguments or one &key argument") # As you can see, Python has a funny way of # 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) elif lambda_keyword == "&optional": if isinstance(expr, HyList): if not len(expr) == 2: raise HyTypeError(expr, "optional args should be bare names " "or 2-item lists") k, v = expr 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) elif lambda_keyword == "&kwonly": if not PY3: raise HyTypeError(expr, "keyword-only arguments are only " "available under Python 3") if isinstance(expr, HyList): if len(expr) != 2: raise HyTypeError(expr, "keyword-only args should be bare " "names or 2-item lists") k, v = expr kwonlyargs.append(k) ret += self.compile(v) kwonlydefaults.append(ret.force_expr) else: k = expr kwonlyargs.append(k) kwonlydefaults.append(None) elif lambda_keyword == "&kwargs": if kwargs: raise HyTypeError(expr, "There can only be one " "&kwargs argument") kwargs = expr return ret, args, defaults, varargs, kwonlyargs, kwonlydefaults, kwargs 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 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(expr, x, func)) new_name = typ(elts=new_elts) elif isinstance(name, ast.Name): new_name = ast.Name(id=name.id, arg=name.arg) elif isinstance(name, ast.Subscript): new_name = ast.Subscript(value=name.value, slice=name.slice) elif isinstance(name, ast.Attribute): new_name = ast.Attribute(value=name.value, attr=name.attr) else: raise HyTypeError(expr, "Can't assign or delete a %s" % type(expr).__name__) new_name.ctx = func() ast.copy_location(new_name, name) return new_name @builds(list) def compile_raw_list(self, entries): ret = self._compile_branch(entries) ret += ret.expr_as_stmt() return ret def _render_quoted_form(self, form, level): """ Render a quoted form as a new HyExpression. `level` is the level of quasiquoting of the current form. We can unquote if level is 0. Returns a three-tuple (`imports`, `expression`, `splice`). The `splice` return value is used to mark `unquote-splice`d forms. We need to distinguish them as want to concatenate them instead of just nesting them. """ if level == 0: if isinstance(form, HyExpression): if form and form[0] in ("unquote", "unquote_splice"): if len(form) != 2: raise HyTypeError(form, ("`%s' needs 1 argument, got %s" % form[0], len(form) - 1)) return set(), form[1], (form[0] == "unquote_splice") if isinstance(form, HyExpression): if form and form[0] == "quasiquote": level += 1 if form and form[0] in ("unquote", "unquote_splice"): level -= 1 name = form.__class__.__name__ imports = set([name]) if isinstance(form, (HyList, HyDict, HySet)): if not form: contents = HyList() else: # If there are arguments, they can be spliced # so we build a sum... contents = HyExpression([HySymbol("+"), HyList()]) for x in form: f_imports, f_contents, splice = self._render_quoted_form(x, level) imports.update(f_imports) if splice: to_add = HyExpression([HySymbol("list"), f_contents]) else: to_add = HyList([f_contents]) contents.append(to_add) return imports, HyExpression([HySymbol(name), contents]).replace(form), False elif isinstance(form, HyCons): ret = HyExpression([HySymbol(name)]) nimport, contents, splice = self._render_quoted_form(form.car, level) if splice: raise HyTypeError(form, "Can't splice dotted lists yet") imports.update(nimport) ret.append(contents) nimport, contents, splice = self._render_quoted_form(form.cdr, level) if splice: raise HyTypeError(form, "Can't splice the cdr of a cons") imports.update(nimport) ret.append(contents) return imports, ret.replace(form), False elif isinstance(form, HySymbol): return imports, HyExpression([HySymbol(name), HyString(form)]).replace(form), False return imports, HyExpression([HySymbol(name), form]).replace(form), False @builds("quote") @builds("quasiquote") @checkargs(exact=1) def compile_quote(self, entries): if entries[0] == "quote": # Never allow unquoting level = float("inf") else: level = 0 imports, stmts, splice = self._render_quoted_form(entries[1], level) ret = self.compile(stmts) ret.add_imports("hy", imports) return ret @builds("unquote") @builds("unquote_splicing") def compile_unquote(self, expr): raise HyTypeError(expr, "`%s' can't be used at the top-level" % expr[0]) @builds("eval") @checkargs(min=1, max=3) def compile_eval(self, expr): expr.pop(0) if not isinstance(expr[0], (HyExpression, HySymbol)): raise HyTypeError(expr, "expression expected as first argument") elist = [HySymbol("hy_eval")] + [expr[0]] if len(expr) >= 2: elist.append(expr[1]) else: elist.append(HyExpression([HySymbol("locals")])) if len(expr) == 3: elist.append(expr[2]) else: elist.append(HyString(self.module_name)) ret = self.compile(HyExpression(elist).replace(expr)) ret.add_imports("hy.importer", ["hy_eval"]) return ret @builds("do") def compile_do(self, expression): expression.pop(0) return self._compile_branch(expression) @builds("raise") @checkargs(multiple=[0, 1, 3]) def compile_raise_expression(self, expr): expr.pop(0) ret = Result() if expr: ret += self.compile(expr.pop(0)) cause = None if len(expr) == 2 and expr[0] == HyKeyword(":from"): if not PY3: raise HyCompileError( "raise from only supported in python 3") expr.pop(0) cause = self.compile(expr.pop(0)) cause = cause.expr # Use ret.expr to get a literal `None` ret += ast.Raise( lineno=expr.start_line, col_offset=expr.start_column, type=ret.expr, exc=ret.expr, inst=None, tback=None, cause=cause) return ret @builds("try") def compile_try_expression(self, expr): expr.pop(0) # try try: body = expr.pop(0) except IndexError: body = [] # (try something…) body = self.compile(body) var = self.get_anon_var() name = ast.Name(id=ast_str(var), arg=ast_str(var), ctx=ast.Store(), lineno=expr.start_line, col_offset=expr.start_column) expr_name = ast.Name(id=ast_str(var), arg=ast_str(var), ctx=ast.Load(), lineno=expr.start_line, col_offset=expr.start_column) returnable = Result(expr=expr_name, temp_variables=[expr_name, name], contains_yield=body.contains_yield) body += ast.Assign(targets=[name], value=body.force_expr, lineno=expr.start_line, col_offset=expr.start_column) body = body.stmts if not body: body = [ast.Pass(lineno=expr.start_line, col_offset=expr.start_column)] orelse = [] finalbody = [] handlers = [] handler_results = Result() for e in expr: if not len(e): raise HyTypeError(e, "Empty list not allowed in `try'") if e[0] == HySymbol("except"): handler_results += self._compile_catch_expression(e, name) handlers.append(handler_results.stmts.pop()) elif e[0] == HySymbol("else"): orelse = self.try_except_helper(e, HySymbol("else"), orelse) elif e[0] == HySymbol("finally"): finalbody = self.try_except_helper(e, HySymbol("finally"), finalbody) else: raise HyTypeError(e, "Unknown expression in `try'") # Using (else) without (except) is verboten! if orelse and not handlers: raise HyTypeError( e, "`try' cannot have `else' without `except'") # (try) or (try BODY) # Generate a default handler for Python >= 3.3 and pypy if not handlers and not finalbody and not orelse: handlers = [ast.ExceptHandler( lineno=expr.start_line, col_offset=expr.start_column, type=None, name=None, body=[ast.Raise(lineno=expr.start_line, col_offset=expr.start_column)])] ret = handler_results if PY33: # Python 3.3 features a merge of TryExcept+TryFinally into Try. return ret + ast.Try( lineno=expr.start_line, col_offset=expr.start_column, body=body, handlers=handlers, orelse=orelse, finalbody=finalbody) + returnable if finalbody: if handlers: return ret + ast.TryFinally( lineno=expr.start_line, col_offset=expr.start_column, body=[ast.TryExcept( lineno=expr.start_line, col_offset=expr.start_column, handlers=handlers, body=body, orelse=orelse)], finalbody=finalbody) + returnable return ret + ast.TryFinally( lineno=expr.start_line, col_offset=expr.start_column, body=body, finalbody=finalbody) + returnable return ret + ast.TryExcept( lineno=expr.start_line, col_offset=expr.start_column, handlers=handlers, 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") def magic_internal_form(self, expr): raise HyTypeError(expr, "Error: `%s' can't be used like that." % (expr[0])) def _compile_catch_expression(self, expr, var): catch = expr.pop(0) # catch try: exceptions = expr.pop(0) except IndexError: exceptions = HyList() # exceptions catch should be either: # [[list of exceptions]] # or # [variable [list of exceptions]] # or # [variable exception] # or # [exception] # or # [] if not isinstance(exceptions, HyList): raise HyTypeError(exceptions, "`%s' exceptions list is not a list" % catch) if len(exceptions) > 2: raise HyTypeError(exceptions, "`%s' exceptions list is too long" % catch) # [variable [list of exceptions]] # let's pop variable and use it as name if len(exceptions) == 2: name = exceptions.pop(0) if not isinstance(name, HySymbol): raise HyTypeError( exceptions, "Exception storage target name must be a symbol.") if PY3: # Python3 features a change where the Exception handler # moved the name from a Name() to a pure Python String type. # # We'll just make sure it's a pure "string", and let it work # it's magic. name = ast_str(name) else: # Python2 requires an ast.Name, set to ctx Store. name = self._storeize(name, self.compile(name)) else: name = None try: exceptions_list = exceptions.pop(0) except IndexError: exceptions_list = [] if isinstance(exceptions_list, list): if len(exceptions_list): # [FooBar BarFoo] → catch Foobar and BarFoo exceptions elts, _type, _ = self._compile_collect(exceptions_list) _type += ast.Tuple(elts=elts, lineno=expr.start_line, col_offset=expr.start_column, ctx=ast.Load()) else: # [] → all exceptions caught _type = Result() elif isinstance(exceptions_list, HySymbol): _type = self.compile(exceptions_list) else: raise HyTypeError(exceptions, "`%s' needs a valid exception list" % catch) body = self._compile_branch(expr) body += ast.Assign(targets=[var], value=body.force_expr, lineno=expr.start_line, col_offset=expr.start_column) body += body.expr_as_stmt() body = body.stmts if not body: body = [ast.Pass(lineno=expr.start_line, col_offset=expr.start_column)] # use _type.expr to get a literal `None` return _type + ast.ExceptHandler( lineno=expr.start_line, col_offset=expr.start_column, type=_type.expr, name=name, body=body) @builds("if*") @checkargs(min=2, max=3) def compile_if(self, expression): expression.pop(0) cond = self.compile(expression.pop(0)) body = self.compile(expression.pop(0)) orel = Result() nested = root = False if expression: orel_expr = expression.pop(0) if isinstance(orel_expr, HyExpression) and isinstance(orel_expr[0], HySymbol) and orel_expr[0] == 'if*': # Nested ifs: don't waste temporaries root = self.temp_if is None nested = True self.temp_if = self.temp_if or self.get_anon_var() orel = self.compile(orel_expr) if not cond.stmts and isinstance(cond.force_expr, ast.Name): name = cond.force_expr.id branch = None if name == 'True': branch = body elif name in ('False', 'None'): branch = orel if branch is not None: if self.temp_if and branch.stmts: name = ast.Name(id=ast_str(self.temp_if), arg=ast_str(self.temp_if), ctx=ast.Store(), lineno=expression.start_line, col_offset=expression.start_column) branch += ast.Assign(targets=[name], value=body.force_expr, lineno=expression.start_line, col_offset=expression.start_column) return branch # We want to hoist the statements from the condition ret = cond if body.stmts or orel.stmts: # We have statements in our bodies # Get a temporary variable for the result storage var = self.temp_if or self.get_anon_var() name = ast.Name(id=ast_str(var), arg=ast_str(var), ctx=ast.Store(), lineno=expression.start_line, col_offset=expression.start_column) # Store the result of the body body += ast.Assign(targets=[name], value=body.force_expr, lineno=expression.start_line, col_offset=expression.start_column) # and of the else clause if not nested or not orel.stmts or (not root and var != self.temp_if): orel += ast.Assign(targets=[name], value=orel.force_expr, lineno=expression.start_line, col_offset=expression.start_column) # Then build the if ret += ast.If(test=ret.force_expr, body=body.stmts, orelse=orel.stmts, lineno=expression.start_line, col_offset=expression.start_column) # And make our expression context our temp variable expr_name = ast.Name(id=ast_str(var), arg=ast_str(var), ctx=ast.Load(), lineno=expression.start_line, col_offset=expression.start_column) ret += Result(expr=expr_name, temp_variables=[expr_name, name]) else: # Just make that an if expression ret += ast.IfExp(test=ret.force_expr, body=body.force_expr, orelse=orel.force_expr, lineno=expression.start_line, col_offset=expression.start_column) if root: self.temp_if = None return ret @builds("break") def compile_break_expression(self, expr): ret = ast.Break(lineno=expr.start_line, col_offset=expr.start_column) return ret @builds("continue") def compile_continue_expression(self, expr): ret = ast.Continue(lineno=expr.start_line, col_offset=expr.start_column) return ret @builds("assert") @checkargs(min=1, max=2) def compile_assert_expression(self, expr): expr.pop(0) # assert e = expr.pop(0) if len(expr) == 1: msg = self.compile(expr.pop(0)).force_expr else: msg = None ret = self.compile(e) ret += ast.Assert(test=ret.force_expr, msg=msg, lineno=e.start_line, col_offset=e.start_column) return ret @builds("global") @checkargs(min=1) def compile_global_expression(self, expr): expr.pop(0) # global names = [] while len(expr) > 0: identifier = expr.pop(0) name = ast_str(identifier) names.append(name) if not isinstance(identifier, HySymbol): raise HyTypeError(identifier, "(global) arguments must " " be Symbols") return ast.Global(names=names, lineno=expr.start_line, col_offset=expr.start_column) @builds("nonlocal") @checkargs(min=1) def compile_nonlocal_expression(self, expr): if not PY3: raise HyCompileError( "nonlocal only supported in python 3!") expr.pop(0) # nonlocal names = [] while len(expr) > 0: identifier = expr.pop(0) name = ast_str(identifier) names.append(name) if not isinstance(identifier, HySymbol): raise HyTypeError(identifier, "(nonlocal) arguments must " "be Symbols.") return ast.Nonlocal(names=names, lineno=expr.start_line, col_offset=expr.start_column) @builds("yield") @checkargs(max=1) def compile_yield_expression(self, expr): expr.pop(0) if PY33: ret = Result(contains_yield=False) else: ret = Result(contains_yield=True) value = None if expr != []: ret += self.compile(expr.pop(0)) value = ret.force_expr ret += ast.Yield( value=value, lineno=expr.start_line, col_offset=expr.start_column) 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): if not names: names = [ast.alias(name=ast_str(module), asname=None)] ret = importer(lineno=expr.start_line, col_offset=expr.start_column, module=ast_str(module), names=names, level=0) return Result() + ret expr.pop(0) # index rimports = Result() while len(expr) > 0: iexpr = expr.pop(0) if not isinstance(iexpr, (HySymbol, HyList)): raise HyTypeError(iexpr, "(import) requires a Symbol " "or a List.") if isinstance(iexpr, HySymbol): rimports += _compile_import(expr, iexpr) continue if isinstance(iexpr, HyList) and len(iexpr) == 1: rimports += _compile_import(expr, iexpr.pop(0)) continue if isinstance(iexpr, HyList) and iexpr: module = iexpr.pop(0) entry = iexpr[0] if isinstance(entry, HyKeyword) and entry == HyKeyword(":as"): if not len(iexpr) == 2: raise HyTypeError(iexpr, "garbage after aliased import") iexpr.pop(0) # :as alias = iexpr.pop(0) names = [ast.alias(name=ast_str(module), asname=ast_str(alias))] rimports += _compile_import(expr, ast_str(module), names) continue if isinstance(entry, HyList): names = [] while entry: sym = entry.pop(0) if entry and isinstance(entry[0], HyKeyword): entry.pop(0) alias = ast_str(entry.pop(0)) else: alias = None names.append(ast.alias(name=ast_str(sym), asname=alias)) rimports += _compile_import(expr, module, names, ast.ImportFrom) continue raise HyTypeError( entry, "Unknown entry (`%s`) in the HyList" % (entry) ) return rimports @builds("get") @checkargs(min=2) def compile_index_expression(self, expr): expr.pop(0) # index val = self.compile(expr.pop(0)) slices, ret, _ = self._compile_collect(expr) if val.stmts: ret += val for sli in slices: val = Result() + ast.Subscript( lineno=expr.start_line, col_offset=expr.start_column, value=val.force_expr, slice=ast.Index(value=sli), ctx=ast.Load()) return ret + val @builds(".") @checkargs(min=1) def compile_attribute_access(self, expr): expr.pop(0) # dot ret = self.compile(expr.pop(0)) for attr in expr: if isinstance(attr, HySymbol): ret += ast.Attribute(lineno=attr.start_line, col_offset=attr.start_column, value=ret.force_expr, attr=ast_str(attr), ctx=ast.Load()) elif type(attr) == HyList: if len(attr) != 1: raise HyTypeError( attr, "The attribute access DSL only accepts HySymbols " "and one-item lists, got {0}-item list instead".format( len(attr), ), ) compiled_attr = self.compile(attr.pop(0)) ret = compiled_attr + ret + ast.Subscript( lineno=attr.start_line, col_offset=attr.start_column, value=ret.force_expr, slice=ast.Index(value=compiled_attr.force_expr), ctx=ast.Load()) else: raise HyTypeError( attr, "The attribute access DSL only accepts HySymbols " "and one-item lists, got {0} instead".format( type(attr).__name__, ), ) return ret @builds("del") def compile_del_expression(self, expr): root = expr.pop(0) if not expr: result = Result() result += ast.Name(id='None', ctx=ast.Load(), lineno=root.start_line, col_offset=root.start_column) return result del_targets = [] 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, col_offset=expr.start_column, targets=del_targets) @builds("cut") @checkargs(min=1, max=4) def compile_cut_expression(self, expr): expr.pop(0) # index val = self.compile(expr.pop(0)) # target low = Result() if expr != []: low = self.compile(expr.pop(0)) high = Result() if expr != []: high = self.compile(expr.pop(0)) step = Result() if expr != []: step = self.compile(expr.pop(0)) # use low.expr, high.expr and step.expr to use a literal `None`. return val + low + high + step + ast.Subscript( lineno=expr.start_line, col_offset=expr.start_column, value=val.force_expr, slice=ast.Slice(lower=low.expr, upper=high.expr, step=step.expr), ctx=ast.Load()) @builds("assoc") @checkargs(min=3, even=False) def compile_assoc_expression(self, expr): expr.pop(0) # assoc # (assoc foo bar baz) => foo[bar] = baz target = self.compile(expr.pop(0)) ret = target i = iter(expr) for (key, val) in ((self.compile(x), self.compile(y)) for (x, y) in zip(i, i)): ret += key + val + ast.Assign( lineno=expr.start_line, col_offset=expr.start_column, targets=[ ast.Subscript( lineno=expr.start_line, col_offset=expr.start_column, value=target.force_expr, slice=ast.Index(value=key.force_expr), ctx=ast.Store())], value=val.force_expr) return ret @builds("with_decorator") @checkargs(min=1) def compile_decorate_expression(self, expr): expr.pop(0) # with-decorator fn = self.compile(expr.pop(-1)) if not fn.stmts or not (isinstance(fn.stmts[-1], ast.FunctionDef) or isinstance(fn.stmts[-1], ast.ClassDef)): raise HyTypeError(expr, "Decorated a non-function") decorators, ret, _ = self._compile_collect(expr) fn.stmts[-1].decorator_list = decorators + fn.stmts[-1].decorator_list return ret + fn @builds("with*") @checkargs(min=2) def compile_with_expression(self, expr): expr.pop(0) # with* args = expr.pop(0) if not isinstance(args, HyList): raise HyTypeError(expr, "with expects a list, received `{0}'".format( type(args).__name__)) if len(args) < 1: raise HyTypeError(expr, "with needs [[arg (expr)]] or [[(expr)]]]") args.reverse() ctx = self.compile(args.pop(0)) thing = None if args != []: thing = self._storeize(args[0], self.compile(args.pop(0))) body = self._compile_branch(expr) var = self.get_anon_var() name = ast.Name(id=ast_str(var), arg=ast_str(var), ctx=ast.Store(), lineno=expr.start_line, col_offset=expr.start_column) # Store the result of the body in a tempvar body += ast.Assign(targets=[name], value=body.force_expr, lineno=expr.start_line, col_offset=expr.start_column) the_with = ast.With(context_expr=ctx.force_expr, lineno=expr.start_line, col_offset=expr.start_column, optional_vars=thing, body=body.stmts) if PY33: the_with.items = [ast.withitem(context_expr=ctx.force_expr, optional_vars=thing)] ret = ctx + the_with # And make our expression context our temp variable expr_name = ast.Name(id=ast_str(var), arg=ast_str(var), ctx=ast.Load(), lineno=expr.start_line, col_offset=expr.start_column) ret += Result(expr=expr_name, temp_variables=[expr_name, name]) return ret @builds(",") def compile_tuple(self, expr): expr.pop(0) elts, ret, _ = self._compile_collect(expr) ret += ast.Tuple(elts=elts, lineno=expr.start_line, col_offset=expr.start_column, ctx=ast.Load()) return ret def _compile_generator_iterables(self, trailers): """Helper to compile the "trailing" parts of comprehensions: generators and conditions""" generators = trailers.pop(0) cond = self.compile(trailers.pop(0)) if trailers != [] else Result() gen_it = iter(generators) paired_gens = zip(gen_it, gen_it) gen_res = Result() gen = [] for target, iterable in paired_gens: comp_target = self.compile(target) target = self._storeize(target, comp_target) gen_res += self.compile(iterable) gen.append(ast.comprehension( target=target, iter=gen_res.force_expr, ifs=[], is_async=False)) if cond.expr: gen[-1].ifs.append(cond.expr) return gen_res + cond, gen @builds("list_comp") @checkargs(min=2, max=3) def compile_list_comprehension(self, expr): # (list-comp expr (target iter) cond?) expr.pop(0) expression = expr.pop(0) gen_gen = expr[0] if not isinstance(gen_gen, HyList): raise HyTypeError(gen_gen, "Generator expression must be a list.") gen_res, gen = self._compile_generator_iterables(expr) if len(gen) == 0: raise HyTypeError(gen_gen, "Generator expression cannot be empty.") compiled_expression = self.compile(expression) ret = compiled_expression + gen_res ret += ast.ListComp( lineno=expr.start_line, col_offset=expr.start_column, elt=compiled_expression.force_expr, generators=gen) return ret @builds("set_comp") @checkargs(min=2, max=3) def compile_set_comprehension(self, expr): if PY27: ret = self.compile_list_comprehension(expr) expr = ret.expr ret.expr = ast.SetComp( lineno=expr.lineno, col_offset=expr.col_offset, elt=expr.elt, generators=expr.generators) return ret expr[0] = HySymbol("list_comp").replace(expr[0]) expr = HyExpression([HySymbol("set"), expr]).replace(expr) return self.compile(expr) @builds("dict_comp") @checkargs(min=3, max=4) def compile_dict_comprehension(self, expr): if PY27: expr.pop(0) # dict-comp key = expr.pop(0) value = expr.pop(0) gen_res, gen = self._compile_generator_iterables(expr) compiled_key = self.compile(key) compiled_value = self.compile(value) ret = compiled_key + compiled_value + gen_res ret += ast.DictComp( lineno=expr.start_line, col_offset=expr.start_column, key=compiled_key.force_expr, value=compiled_value.force_expr, generators=gen) return ret # In Python 2.6, turn (dict-comp key value [foo]) into # (dict (list-comp (, key value) [foo])) expr[0] = HySymbol("list_comp").replace(expr[0]) expr[1:3] = [HyExpression( [HySymbol(",")] + expr[1:3] ).replace(expr[1])] expr = HyExpression([HySymbol("dict"), expr]).replace(expr) return self.compile(expr) @builds("genexpr") def compile_genexpr(self, expr): ret = self.compile_list_comprehension(expr) expr = ret.expr ret.expr = ast.GeneratorExp( lineno=expr.lineno, col_offset=expr.col_offset, elt=expr.elt, generators=expr.generators) return ret @builds("apply") @checkargs(min=1, max=3) def compile_apply_expression(self, expr): expr.pop(0) # apply ret = Result() fun = expr.pop(0) # We actually defer the compilation of the function call to # @builds(HyExpression), allowing us to work on method calls call = HyExpression([fun]).replace(fun) if isinstance(fun, HySymbol) and fun.startswith("."): # (apply .foo lst) needs to work as lst[0].foo(*lst[1:]) if not expr: raise HyTypeError( expr, "apply of a method needs to have an argument" ) # We need to grab the arguments, and split them. # Assign them to a variable if they're not one already if type(expr[0]) == HyList: if len(expr[0]) == 0: raise HyTypeError( expr, "apply of a method needs to have an argument" ) call.append(expr[0].pop(0)) else: if isinstance(expr[0], HySymbol): tempvar = expr[0] else: tempvar = HySymbol(self.get_anon_var()).replace(expr[0]) assignment = HyExpression( [HySymbol("setv"), tempvar, expr[0]] ).replace(expr[0]) # and add the assignment to our result ret += self.compile(assignment) # The first argument is the object on which to call the method # So we translate (apply .foo args) to (.foo (get args 0)) call.append(HyExpression( [HySymbol("get"), tempvar, HyInteger(0)] ).replace(tempvar)) # We then pass the other arguments to the function expr[0] = HyExpression( [HySymbol("cut"), tempvar, HyInteger(1)] ).replace(expr[0]) ret += self.compile(call) if not isinstance(ret.expr, ast.Call): raise HyTypeError( fun, "compiling the application of `{}' didn't return a " "function call, but `{}'".format(fun, type(ret.expr).__name__) ) if ret.expr.starargs or ret.expr.kwargs: raise HyTypeError( expr, "compiling the function application returned a function " "call with arguments" ) if expr: stargs = expr.pop(0) if stargs is not None: stargs = self.compile(stargs) if PY35: stargs_expr = stargs.force_expr ret.expr.args.append( ast.Starred(stargs_expr, ast.Load(), lineno=stargs_expr.lineno, col_offset=stargs_expr.col_offset) ) else: ret.expr.starargs = stargs.force_expr ret = stargs + ret if expr: kwargs = expr.pop(0) if isinstance(kwargs, HyDict): new_kwargs = [] for k, v in kwargs.items(): if isinstance(k, HySymbol): pass elif isinstance(k, HyString): k = HyString(hy_symbol_mangle(str_type(k))).replace(k) elif isinstance(k, HyKeyword): sym = hy_symbol_mangle(str_type(k)[2:]) k = HyString(sym).replace(k) new_kwargs += [k, v] kwargs = HyDict(new_kwargs).replace(kwargs) kwargs = self.compile(kwargs) if PY35: kwargs_expr = kwargs.force_expr ret.expr.keywords.append( ast.keyword(None, kwargs_expr, lineno=kwargs_expr.lineno, col_offset=kwargs_expr.col_offset) ) else: ret.expr.kwargs = kwargs.force_expr ret = kwargs + ret return ret @builds("not") @builds("~") @checkargs(1) def compile_unary_operator(self, expression): ops = {"not": ast.Not, "~": ast.Invert} operator = expression.pop(0) operand = self.compile(expression.pop(0)) operand += ast.UnaryOp(op=ops[operator](), operand=operand.expr, lineno=operator.start_line, col_offset=operator.start_column) return operand @builds("require") def compile_require(self, expression): """ TODO: keep track of what we've imported in this run and then "unimport" it after we've completed `thing' so that we don't pollute other envs. """ for entry in expression[1:]: if isinstance(entry, HySymbol): # e.g., (require foo) __import__(entry) require(entry, self.module_name, all_macros=True, prefix=entry) elif isinstance(entry, HyList) and len(entry) == 2: # e.g., (require [foo [bar baz :as MyBaz bing]]) # or (require [foo [*]]) module, names = entry if not isinstance(names, HyList): raise HyTypeError(names, "(require) name lists should be HyLists") __import__(module) if '*' in names: if len(names) != 1: raise HyTypeError(names, "* in a (require) name list " "must be on its own") require(module, self.module_name, all_macros=True) else: assignments = {} while names: if len(names) > 1 and names[1] == HyKeyword(":as"): k, _, v = names[:3] del names[:3] assignments[k] = v else: symbol = names.pop(0) assignments[symbol] = symbol require(module, self.module_name, assignments=assignments) elif (isinstance(entry, HyList) and len(entry) == 3 and entry[1] == HyKeyword(":as")): # e.g., (require [foo :as bar]) module, _, prefix = entry __import__(module) require(module, self.module_name, all_macros=True, prefix=prefix) else: raise HyTypeError(entry, "unrecognized (require) syntax") return Result() @builds("and") @builds("or") def compile_logical_or_and_and_operator(self, expression): ops = {"and": (ast.And, "True"), "or": (ast.Or, "None")} operator = expression.pop(0) opnode, default = ops[operator] root_line, root_column = operator.start_line, operator.start_column if len(expression) == 0: return ast.Name(id=default, ctx=ast.Load(), lineno=root_line, col_offset=root_column) elif len(expression) == 1: return self.compile(expression[0]) ret = Result() values = list(map(self.compile, expression)) has_stmt = any(value.stmts for value in values) if has_stmt: # Compile it to an if...else sequence var = self.get_anon_var() name = ast.Name(id=var, ctx=ast.Store(), lineno=root_line, col_offset=root_column) expr_name = ast.Name(id=var, ctx=ast.Load(), lineno=root_line, col_offset=root_column) temp_variables = [name, expr_name] def make_assign(value, node=None): if node is None: line, column = root_line, root_column else: line, column = node.lineno, node.col_offset positioned_name = ast.Name(id=var, ctx=ast.Store(), lineno=line, col_offset=column) temp_variables.append(positioned_name) return ast.Assign(targets=[positioned_name], value=value, lineno=line, col_offset=column) root = [] current = root for i, value in enumerate(values): if value.stmts: node = value.stmts[0] current.extend(value.stmts) else: node = value.expr current.append(make_assign(value.force_expr, value.force_expr)) if i == len(values)-1: # Skip a redundant 'if'. break if operator == "and": cond = expr_name elif operator == "or": cond = ast.UnaryOp(op=ast.Not(), operand=expr_name, lineno=node.lineno, col_offset=node.col_offset) current.append(ast.If(test=cond, body=[], lineno=node.lineno, col_offset=node.col_offset, orelse=[])) current = current[-1].body ret = sum(root, ret) ret += Result(expr=expr_name, temp_variables=temp_variables) else: ret += ast.BoolOp(op=opnode(), lineno=root_line, col_offset=root_column, values=[value.force_expr for value in values]) return ret def _compile_compare_op_expression(self, expression): ops = {"=": ast.Eq, "!=": ast.NotEq, "<": ast.Lt, "<=": ast.LtE, ">": ast.Gt, ">=": ast.GtE, "is": ast.Is, "is_not": ast.IsNot, "in": ast.In, "not_in": ast.NotIn} inv = expression.pop(0) op = ops[inv] ops = [op() for x in range(1, len(expression))] e = expression[0] exprs, ret, _ = self._compile_collect(expression) return ret + ast.Compare(left=exprs[0], ops=ops, comparators=exprs[1:], lineno=e.start_line, col_offset=e.start_column) @builds("=") @builds("!=") @builds("<") @builds("<=") @builds(">") @builds(">=") @checkargs(min=1) def compile_compare_op_expression(self, expression): if len(expression) == 2: rval = "True" if expression[0] == "!=": rval = "False" return ast.Name(id=rval, ctx=ast.Load(), lineno=expression.start_line, col_offset=expression.start_column) return self._compile_compare_op_expression(expression) @builds("is") @builds("in") @builds("is_not") @builds("not_in") @checkargs(min=2) def compile_compare_op_expression_coll(self, expression): return self._compile_compare_op_expression(expression) @builds("%") @builds("**") @builds("<<") @builds(">>") @builds("|") @builds("^") @builds("&") @builds_if("@", PY35) @checkargs(min=2) def compile_maths_expression(self, expression): ops = {"+": ast.Add, "/": ast.Div, "//": ast.FloorDiv, "*": ast.Mult, "-": ast.Sub, "%": ast.Mod, "**": ast.Pow, "<<": ast.LShift, ">>": ast.RShift, "|": ast.BitOr, "^": ast.BitXor, "&": ast.BitAnd} if PY35: ops.update({"@": ast.MatMult}) inv = expression.pop(0) op = ops[inv] ret = self.compile(expression.pop(0)) for child in expression: left_expr = ret.force_expr ret += self.compile(child) right_expr = ret.force_expr ret += ast.BinOp(left=left_expr, op=op(), right=right_expr, lineno=child.start_line, col_offset=child.start_column) return ret @builds("*") @builds("/") @builds("//") def compile_maths_expression_mul(self, expression): if len(expression) > 2: return self.compile_maths_expression(expression) else: id_op = {"*": HyInteger(1), "/": HyInteger(1), "//": HyInteger(1)} op = expression.pop(0) arg = expression.pop(0) if expression else id_op[op] expr = HyExpression([ HySymbol(op), id_op[op], arg ]).replace(expression) return self.compile_maths_expression(expr) def compile_maths_expression_additive(self, expression): if len(expression) > 2: return self.compile_maths_expression(expression) else: op = {"+": ast.UAdd, "-": ast.USub}[expression.pop(0)]() arg = expression.pop(0) ret = self.compile(arg) ret += ast.UnaryOp(op=op, operand=ret.force_expr, lineno=arg.start_line, col_offset=arg.start_column) return ret @builds("+") def compile_maths_expression_add(self, expression): if len(expression) == 1: # Nullary + return ast.Num(n=long_type(0), lineno=expression.start_line, col_offset=expression.start_column) else: return self.compile_maths_expression_additive(expression) @builds("-") @checkargs(min=1) def compile_maths_expression_sub(self, expression): return self.compile_maths_expression_additive(expression) @builds("+=") @builds("/=") @builds("//=") @builds("*=") @builds("_=") @builds("%=") @builds("**=") @builds("<<=") @builds(">>=") @builds("|=") @builds("^=") @builds("&=") @builds_if("@=", PY35) @checkargs(2) def compile_augassign_expression(self, expression): ops = {"+=": ast.Add, "/=": ast.Div, "//=": ast.FloorDiv, "*=": ast.Mult, "_=": ast.Sub, "%=": ast.Mod, "**=": ast.Pow, "<<=": ast.LShift, ">>=": ast.RShift, "|=": ast.BitOr, "^=": ast.BitXor, "&=": ast.BitAnd} if PY35: ops.update({"@=": ast.MatMult}) op = ops[expression[0]] target = self._storeize(expression[1], self.compile(expression[1])) ret = self.compile(expression[2]) ret += ast.AugAssign( target=target, value=ret.force_expr, op=op(), lineno=expression.start_line, col_offset=expression.start_column) return ret @checkargs(1) def _compile_keyword_call(self, expression): expression.append(expression.pop(0)) expression.insert(0, HySymbol("get")) return self.compile(expression) @builds(HyExpression) def compile_expression(self, expression): # Perform macro expansions expression = macroexpand(expression, self) if not isinstance(expression, HyExpression): # Go through compile again if the type changed. return self.compile(expression) if expression == []: return self.compile_list(expression) fn = expression[0] func = None if isinstance(fn, HyKeyword): return self._compile_keyword_call(expression) if isinstance(fn, HyString): ret = self.compile_atom(fn, expression) if ret: return ret if fn.startswith("."): # (.split "test test") -> "test test".split() # (.a.b.c x) -> (.c (. x a b)) -> x.a.b.c() # Get the method name (the last named attribute # in the chain of attributes) attrs = [HySymbol(a).replace(fn) for a in fn.split(".")[1:]] fn = attrs.pop() # Get the object we're calling the method on # (extracted with the attribute access DSL) i = 1 if len(expression) != 2: # If the expression has only one object, # always use that as the callee. # Otherwise, hunt for the first thing that # isn't a keyword argument or its value. while i < len(expression): if isinstance(expression[i], HyKeyword): # Skip the keyword argument and its value. i += 1 else: # Use expression[i]. break i += 1 else: raise HyTypeError(expression, "attribute access requires object") func = self.compile(HyExpression( [HySymbol(".").replace(fn), expression.pop(i)] + attrs)) # And get the method func += ast.Attribute(lineno=fn.start_line, col_offset=fn.start_column, value=func.force_expr, attr=ast_str(fn), ctx=ast.Load()) if not func: func = self.compile(fn) # An exception for pulling together keyword args is if we're doing # a typecheck, eg (type :foo) if fn in ("type", "HyKeyword", "keyword", "name", "is_keyword"): with_kwargs = False else: with_kwargs = True args, ret, kwargs = self._compile_collect(expression[1:], with_kwargs) ret += ast.Call(func=func.expr, args=args, keywords=kwargs, starargs=None, kwargs=None, lineno=expression.start_line, col_offset=expression.start_column) return func + ret @builds("def") @builds("setv") def compile_def_expression(self, expression): root = expression.pop(0) if not expression: result = Result() result += ast.Name(id='None', ctx=ast.Load(), lineno=root.start_line, col_offset=root.start_column) return result elif len(expression) == 2: return self._compile_assign(expression[0], expression[1], expression.start_line, expression.start_column) elif len(expression) % 2 != 0: raise HyTypeError(expression, "`{}' needs an even number of arguments".format( root)) else: result = Result() exprs = [] for tgt, target in zip(expression[::2], expression[1::2]): item = self._compile_assign(tgt, target, tgt.start_line, tgt.start_column) result += item exprs.append(item.force_expr) result += ast.Tuple(elts=exprs, lineno=expression.start_line, col_offset=expression.start_column, ctx=ast.Load()) return result def _compile_assign(self, name, result, start_line, start_column): str_name = "%s" % name if _is_hy_builtin(str_name, self.module_name) and \ not self.allow_builtins: raise HyTypeError(name, "Can't assign to a builtin: `%s'" % str_name) result = self.compile(result) ld_name = self.compile(name) if isinstance(ld_name.expr, ast.Call): raise HyTypeError(name, "Can't assign to a callable: `%s'" % str_name) if result.temp_variables \ and isinstance(name, HyString) \ and '.' not in name: result.rename(name) else: st_name = self._storeize(name, ld_name) result += ast.Assign( lineno=start_line, col_offset=start_column, targets=[st_name], value=result.force_expr) result += ld_name return result @builds("for*") @checkargs(min=1) def compile_for_expression(self, expression): expression.pop(0) # for args = expression.pop(0) if not isinstance(args, HyList): raise HyTypeError(expression, "for expects a list, received `{0}'".format( type(args).__name__)) try: target_name, iterable = args except ValueError: raise HyTypeError(expression, "for requires two forms in the list") target = self._storeize(target_name, self.compile(target_name)) ret = Result() orel = Result() # (for* [] body (else …)) if expression and expression[-1][0] == HySymbol("else"): else_expr = expression.pop() if len(else_expr) > 2: raise HyTypeError( else_expr, "`else' statement in `for' is too long") elif len(else_expr) == 2: orel += self.compile(else_expr[1]) orel += orel.expr_as_stmt() ret += self.compile(iterable) body = self._compile_branch(expression) body += body.expr_as_stmt() ret += ast.For(lineno=expression.start_line, col_offset=expression.start_column, target=target, iter=ret.force_expr, body=body.stmts, orelse=orel.stmts) ret.contains_yield = body.contains_yield return ret @builds("while") @checkargs(min=2) def compile_while_expression(self, expr): expr.pop(0) # "while" ret = self.compile(expr.pop(0)) body = self._compile_branch(expr) body += body.expr_as_stmt() ret += ast.While(test=ret.force_expr, body=body.stmts, orelse=[], lineno=expr.start_line, col_offset=expr.start_column) ret.contains_yield = body.contains_yield return ret @builds(HyList) def compile_list(self, expression): elts, ret, _ = self._compile_collect(expression) ret += ast.List(elts=elts, ctx=ast.Load(), lineno=expression.start_line, col_offset=expression.start_column) return ret @builds(HySet) def compile_set(self, expression): elts, ret, _ = self._compile_collect(expression) if PY27: ret += ast.Set(elts=elts, ctx=ast.Load(), lineno=expression.start_line, col_offset=expression.start_column) else: ret += ast.Call(func=ast.Name(id='set', ctx=ast.Load(), lineno=expression.start_line, col_offset=expression.start_column), args=[ ast.List(elts=elts, ctx=ast.Load(), lineno=expression.start_line, col_offset=expression.start_column)], keywords=[], starargs=None, kwargs=None, lineno=expression.start_line, col_offset=expression.start_column) return ret @builds("lambda") @builds("fn") @checkargs(min=1) def compile_function_def(self, expression): called_as = expression.pop(0) arglist = expression.pop(0) if not isinstance(arglist, HyList): raise HyTypeError(expression, "First argument to `{}' must be a list".format( called_as)) (ret, args, defaults, stararg, kwonlyargs, kwonlydefaults, kwargs) = self._parse_lambda_list(arglist) for i, arg in enumerate(args): if isinstance(arg, HyList): # Destructuring argument if not arg: raise HyTypeError(arglist, "Cannot destruct empty list") args[i] = var = HySymbol(self.get_anon_var()) expression = HyExpression([ HyExpression([ HyString("setv"), arg, var ])] ) + expression expression = expression.replace(arg[0]) if PY34: # Python 3.4+ requires that args are an ast.arg object, rather # than an ast.Name or bare string. args = [ast.arg(arg=ast_str(x), annotation=None, # Fix me! lineno=x.start_line, col_offset=x.start_column) for x in args] kwonlyargs = [ast.arg(arg=ast_str(x), annotation=None, lineno=x.start_line, col_offset=x.start_column) for x in kwonlyargs] # XXX: Beware. Beware. This wasn't put into the parse lambda # list because it's really just an internal parsing thing. if kwargs: kwargs = ast.arg(arg=ast_str(kwargs), annotation=None, lineno=kwargs.start_line, col_offset=kwargs.start_column) if stararg: 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: args = [ast.Name(arg=ast_str(x), id=ast_str(x), ctx=ast.Param(), lineno=x.start_line, col_offset=x.start_column) for x in args] if PY3: kwonlyargs = [ast.Name(arg=ast_str(x), id=ast_str(x), ctx=ast.Param(), lineno=x.start_line, 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, kwarg=kwargs, kwonlyargs=kwonlyargs, kw_defaults=kwonlydefaults, defaults=defaults) body = self._compile_branch(expression) if not body.stmts and called_as == "lambda": ret += ast.Lambda( lineno=expression.start_line, col_offset=expression.start_column, args=args, body=body.force_expr) return ret if body.expr: 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, lineno=body.expr.lineno, col_offset=body.expr.col_offset) if not body.stmts: body += ast.Pass(lineno=expression.start_line, col_offset=expression.start_column) name = self.get_anon_fn() ret += ast.FunctionDef(name=name, lineno=expression.start_line, col_offset=expression.start_column, args=args, body=body.stmts, decorator_list=[]) ast_name = ast.Name(id=name, arg=name, ctx=ast.Load(), lineno=expression.start_line, col_offset=expression.start_column) ret += Result(expr=ast_name, temp_variables=[ast_name, ret.stmts[-1]]) return ret @builds("defclass") @checkargs(min=1) def compile_class_expression(self, expressions): def rewire_init(expr): new_args = [] if expr[0] == HySymbol("setv"): pairs = expr[1:] while len(pairs) > 0: k, v = (pairs.pop(0), pairs.pop(0)) if k == HySymbol("__init__"): v.append(HySymbol("None")) new_args.append(k) new_args.append(v) expr = HyExpression([ HySymbol("setv") ] + new_args).replace(expr) return expr expressions.pop(0) # class class_name = expressions.pop(0) if expressions: base_list = expressions.pop(0) if not isinstance(base_list, HyList): raise HyTypeError(expressions, "Bases class must be a list") bases_expr, bases, _ = self._compile_collect(base_list) else: bases_expr = [] bases = Result() body = Result() # grab the doc string, if there is one if expressions and isinstance(expressions[0], HyString): docstring = expressions.pop(0) symb = HySymbol("__doc__") symb.start_line = docstring.start_line symb.start_column = docstring.start_column body += self._compile_assign(symb, docstring, docstring.start_line, docstring.start_column) body += body.expr_as_stmt() allow_builtins = self.allow_builtins self.allow_builtins = True if expressions and isinstance(expressions[0], HyList) \ and not isinstance(expressions[0], HyExpression): expr = expressions.pop(0) expr = HyExpression([ HySymbol("setv") ] + expr).replace(expr) body += self.compile(rewire_init(expr)) for expression in expressions: expr = rewire_init(macroexpand(expression, self)) body += self.compile(expr) self.allow_builtins = allow_builtins if not body.stmts: body += ast.Pass(lineno=expressions.start_line, col_offset=expressions.start_column) return bases + ast.ClassDef( lineno=expressions.start_line, col_offset=expressions.start_column, decorator_list=[], name=ast_str(class_name), keywords=[], starargs=None, kwargs=None, bases=bases_expr, body=body.stmts) def _compile_time_hack(self, expression): """Compile-time hack: we want to get our new macro now We must provide __name__ in the namespace to make the Python compiler set the __module__ attribute of the macro function.""" hy.importer.hy_eval(expression, compile_time_ns(self.module_name), self.module_name) # We really want to have a `hy` import to get hy.macro in ret = self.compile(expression) ret.add_imports('hy', [None]) return ret @builds("defmacro") @checkargs(min=1) def compile_macro(self, expression): expression.pop(0) name = expression.pop(0) if not isinstance(name, HySymbol): raise HyTypeError(name, ("received a `%s' instead of a symbol " "for macro name" % type(name).__name__)) name = HyString(name).replace(name) for kw in ("&kwonly", "&kwargs", "&key"): if kw in expression[0]: raise HyTypeError(name, "macros cannot use %s" % kw) new_expression = HyExpression([ HySymbol("with_decorator"), HyExpression([HySymbol("hy.macros.macro"), name]), HyExpression([HySymbol("fn")] + expression), ]).replace(expression) ret = self._compile_time_hack(new_expression) return ret @builds("defreader") @checkargs(min=2) def compile_reader(self, expression): expression.pop(0) name = expression.pop(0) 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) and not isinstance(name, HyString): raise HyTypeError(name, ("received a `%s' instead of a symbol " "for reader macro name" % type(name).__name__)) name = HyString(name).replace(name) new_expression = HyExpression([ HySymbol("with_decorator"), HyExpression([HySymbol("hy.macros.reader"), name]), HyExpression([HySymbol("fn")] + expression), ]).replace(expression) ret = self._compile_time_hack(new_expression) return ret @builds("dispatch_reader_macro") @checkargs(exact=2) def compile_dispatch_reader_macro(self, expression): expression.pop(0) # dispatch-reader-macro str_char = expression.pop(0) if not type(str_char) == HyString: raise HyTypeError( str_char, "Trying to expand a reader macro using `{0}' instead " "of string".format(type(str_char).__name__), ) expr = reader_macroexpand(str_char, expression.pop(0), self) return self.compile(expr) @builds("eval_and_compile") def compile_eval_and_compile(self, expression): expression[0] = HySymbol("do") hy.importer.hy_eval(expression, compile_time_ns(self.module_name), self.module_name) expression.pop(0) return self._compile_branch(expression) @builds("eval_when_compile") def compile_eval_when_compile(self, expression): expression[0] = HySymbol("do") hy.importer.hy_eval(expression, compile_time_ns(self.module_name), self.module_name) return Result() @builds(HyCons) def compile_cons(self, cons): raise HyTypeError(cons, "Can't compile a top-level cons cell") @builds(HyInteger) def compile_integer(self, number): return ast.Num(n=long_type(number), lineno=number.start_line, col_offset=number.start_column) @builds(HyFloat) def compile_float(self, number): return ast.Num(n=float(number), lineno=number.start_line, col_offset=number.start_column) @builds(HyComplex) def compile_complex(self, number): return ast.Num(n=complex(number), lineno=number.start_line, col_offset=number.start_column) @builds(HySymbol) def compile_symbol(self, symbol): if "." in symbol: glob, local = symbol.rsplit(".", 1) if not glob: raise HyTypeError(symbol, 'cannot access attribute on ' 'anything other than a name ' '(in order to get attributes of' 'expressions, use ' '`(. {attr})` or ' '`(.{attr} )`)'.format( attr=local)) if not local: raise HyTypeError(symbol, 'cannot access empty attribute') glob = HySymbol(glob).replace(symbol) ret = self.compile_symbol(glob) ret = ast.Attribute( lineno=symbol.start_line, col_offset=symbol.start_column, value=ret, attr=ast_str(local), ctx=ast.Load() ) return ret if symbol in _stdlib: self.imports[_stdlib[symbol]].add(symbol) return ast.Name(id=ast_str(symbol), arg=ast_str(symbol), ctx=ast.Load(), lineno=symbol.start_line, col_offset=symbol.start_column) @builds(HyString) def compile_string(self, string): return ast.Str(s=str_type(string), lineno=string.start_line, col_offset=string.start_column) @builds(HyKeyword) def compile_keyword(self, keyword): return ast.Str(s=str_type(keyword), lineno=keyword.start_line, col_offset=keyword.start_column) @builds(HyDict) def compile_dict(self, m): keyvalues, ret, _ = self._compile_collect(m) ret += ast.Dict(lineno=m.start_line, col_offset=m.start_column, keys=keyvalues[::2], values=keyvalues[1::2]) return ret def hy_compile(tree, module_name, root=ast.Module, get_expr=False): """ Compile a HyObject tree into a Python AST Module. If `get_expr` is True, return a tuple (module, last_expression), where `last_expression` is the. """ body = [] expr = None if tree: compiler = HyASTCompiler(module_name) result = compiler.compile(tree) expr = result.force_expr if not get_expr: result += result.expr_as_stmt() if isinstance(tree, list): spoof_tree = tree[0] else: spoof_tree = tree body = compiler.imports_as_stmts(spoof_tree) + result.stmts ret = root(body=body) if get_expr: expr = ast.Expression(body=expr) ret = (ret, expr) return ret hy-0.12.1/hy/completer.py000066400000000000000000000115721304171765200152130ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # Copyright (c) 2013 Gergely Nagy # Copyright (c) 2013 James King # Copyright (c) 2013 Julien Danjou # Copyright (c) 2013 Konrad Hinsen # Copyright (c) 2013 Thom Neale # Copyright (c) 2013 Will Kahn-Greene # Copyright (c) 2013 Ralph Moritz # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. import contextlib import os import re import sys import hy.macros import hy.compiler from hy._compat import builtins, string_types docomplete = True try: import readline except ImportError: try: import pyreadline.rlmain import pyreadline.unicode_helper # NOQA import readline except ImportError: docomplete = False if sys.platform == 'darwin' and 'libedit' in readline.__doc__: readline_bind = "bind ^I rl_complete" else: readline_bind = "tab: complete" class Completer(object): def __init__(self, namespace={}): if not isinstance(namespace, dict): raise TypeError('namespace must be a dictionary') self.namespace = namespace self.path = [hy.compiler._compile_table, builtins.__dict__, hy.macros._hy_macros[None], namespace] self.reader_path = [hy.macros._hy_reader[None]] if '__name__' in namespace: module_name = namespace['__name__'] self.path.append(hy.macros._hy_macros[module_name]) self.reader_path.append(hy.macros._hy_reader[module_name]) def attr_matches(self, text): # Borrowed from IPython's completer m = re.match(r"(\S+(\.[\w-]+)*)\.([\w-]*)$", text) if m: expr, attr = m.group(1, 3) attr = attr.replace("-", "_") expr = expr.replace("-", "_") else: return [] try: obj = eval(expr, self.namespace) words = dir(obj) except Exception: return [] n = len(attr) matches = [] for w in words: if w[:n] == attr: matches.append("{}.{}".format( expr.replace("_", "-"), w.replace("_", "-"))) return matches def global_matches(self, text): matches = [] for p in self.path: for k in p.keys(): if isinstance(k, string_types): k = k.replace("_", "-") if k.startswith(text): matches.append(k) return matches def reader_matches(self, text): text = text[1:] matches = [] for p in self.reader_path: for k in p.keys(): if isinstance(k, string_types): if k.startswith(text): matches.append("#{}".format(k)) return matches def complete(self, text, state): if text.startswith("#"): matches = self.reader_matches(text) elif "." in text: matches = self.attr_matches(text) else: matches = self.global_matches(text) try: return matches[state] except IndexError: return None @contextlib.contextmanager def completion(completer=None): delims = "()[]{} " if not completer: completer = Completer() if docomplete: readline.set_completer(completer.complete) readline.set_completer_delims(delims) history = os.path.expanduser("~/.hy-history") readline.parse_and_bind("set blink-matching-paren on") try: readline.read_history_file(history) except IOError: open(history, 'a').close() readline.parse_and_bind(readline_bind) yield if docomplete: readline.write_history_file(history) hy-0.12.1/hy/contrib/000077500000000000000000000000001304171765200143015ustar00rootroot00000000000000hy-0.12.1/hy/contrib/__init__.py000066400000000000000000000000001304171765200164000ustar00rootroot00000000000000hy-0.12.1/hy/contrib/botsbuildbots.hy000066400000000000000000000027431304171765200175300ustar00rootroot00000000000000;; Copyright (c) 2014, 2015 Gergely Nagy ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. (defn Botsbuildbots () (Botsbuildbots)) (defmacro Botsbuildbots [] "Build bots, repeatedly.^W^W^WPrint the AUTHORS, forever." `(try (do (import [requests]) (let [r (requests.get "https://raw.githubusercontent.com/hylang/hy/master/AUTHORS")] (repeat r.text))) (except [e ImportError] (repeat "Botsbuildbots requires `requests' to function.")))) hy-0.12.1/hy/contrib/loop.hy000066400000000000000000000072061304171765200156210ustar00rootroot00000000000000;;; Hy tail-call optimization ;; ;; Copyright (c) 2014 Clinton Dreisbach ;; Copyright (c) 2014 Paul R. Tagliamonte ;; ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. ;; ;;; The loop/recur macro allows you to construct functions that use tail-call ;;; optimization to allow arbitrary levels of recursion. (defn --trampoline-- [f] "Wrap f function and make it tail-call optimized." ;; Takes the function "f" and returns a wrapper that may be used for tail- ;; recursive algorithms. Note that the returned function is not side-effect ;; free and should not be called from anywhere else during tail recursion. (setv result None) ;; We have to put this in a list because of Python's ;; weirdness around local variables. ;; Assigning directly to it later would cause it to ;; shadow in a new scope. (setv active [False]) (setv accumulated []) (fn [&rest args] (.append accumulated args) (when (not (first active)) (assoc active 0 True) (while (> (len accumulated) 0) (setv result (apply f (.pop accumulated)))) (assoc active 0 False) result))) (defn recursive-replace [old-term new-term body] "Recurses through lists of lists looking for old-term and replacing it with new-term." ((type body) (list-comp (cond [(= term old-term) new-term] [(instance? hy.HyList term) (recursive-replace old-term new-term term)] [True term]) [term body]))) (defmacro/g! fnr [signature &rest body] (let [new-body (recursive-replace 'recur g!recur-fn body)] `(do (import [hy.contrib.loop [--trampoline--]]) (with-decorator --trampoline-- (def ~g!recur-fn (fn [~@signature] ~@new-body))) ~g!recur-fn))) (defmacro defnr [name lambda-list &rest body] (if (not (= (type name) HySymbol)) (macro-error name "defnr takes a name as first argument")) `(do (require hy.contrib.loop) (setv ~name (hy.contrib.loop.fnr ~lambda-list ~@body)))) (defmacro/g! loop [bindings &rest body] ;; Use inside functions like so: ;; (defn factorial [n] ;; (loop [[i n] ;; [acc 1]] ;; (if (= i 0) ;; acc ;; (recur (dec i) (* acc i))))) ;; ;; If recur is used in a non-tail-call position, None is returned, which ;; causes chaos. Fixing this to detect if recur is in a tail-call position ;; and erroring if not is a giant TODO. (let [fnargs (map (fn [x] (first x)) bindings) initargs (map second bindings)] `(do (require hy.contrib.loop) (hy.contrib.loop.defnr ~g!recur-fn [~@fnargs] ~@body) (~g!recur-fn ~@initargs)))) hy-0.12.1/hy/contrib/multi.hy000066400000000000000000000107461304171765200160050ustar00rootroot00000000000000;; Hy Arity-overloading ;; Copyright (c) 2014 Morten Linderud ;; Copyright (c) 2016 Tuukka Turto ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. (import [collections [defaultdict]] [hy.models.expression [HyExpression]] [hy.models.list [HyList]] [hy.models.string [HyString]]) (defclass MultiDispatch [object] [ _fns (defaultdict dict) __init__ (fn [self f] (setv self.f f) (setv self.__doc__ f.__doc__) (unless (in f.__name__ (.keys (get self._fns f.__module__))) (setv (get self._fns f.__module__ f.__name__) {})) (setv values f.__code__.co_varnames) (setv (get self._fns f.__module__ f.__name__ values) f)) fn? (fn [self v args kwargs] "Compare the given (checked fn) to the called fn" (setv com (+ (list args) (list (.keys kwargs)))) (and (= (len com) (len v)) (.issubset (frozenset (.keys kwargs)) com))) __call__ (fn [self &rest args &kwargs kwargs] (setv output None) (for [[i f] (.items (get self._fns self.f.__module__ self.f.__name__))] (when (.fn? self i args kwargs) (setv output (apply f args kwargs)) (break))) (if output output (raise (TypeError "No matching functions with this signature"))))]) (defn multi-decorator [dispatch-fn] (setv inner (fn [&rest args &kwargs kwargs] (setv dispatch-key (apply dispatch-fn args kwargs)) (if (in dispatch-key inner.--multi--) (apply (get inner.--multi-- dispatch-key) args kwargs) (apply inner.--multi-default-- args kwargs)))) (setv inner.--multi-- {}) (setv inner.--doc-- dispatch-fn.--doc--) (setv inner.--multi-default-- (fn [&rest args &kwargs kwargs] None)) inner) (defn method-decorator [dispatch-fn &optional [dispatch-key None]] (setv apply-decorator (fn [func] (if (is dispatch-key None) (setv dispatch-fn.--multi-default-- func) (assoc dispatch-fn.--multi-- dispatch-key func)) dispatch-fn)) apply-decorator) (defmacro defmulti [name params &rest body] `(do (import [hy.contrib.multi [multi-decorator]]) (with-decorator multi-decorator (defn ~name ~params ~@body)))) (defmacro defmethod [name multi-key params &rest body] `(do (import [hy.contrib.multi [method-decorator]]) (with-decorator (method-decorator ~name ~multi-key) (defn ~name ~params ~@body)))) (defmacro default-method [name params &rest body] `(do (import [hy.contrib.multi [method-decorator]]) (with-decorator (method-decorator ~name) (defn ~name ~params ~@body)))) (defmacro defn [name &rest bodies] (def arity-overloaded? (fn [bodies] (if (isinstance (first bodies) HyString) (arity-overloaded? (rest bodies)) (isinstance (first bodies) HyExpression)))) (if (arity-overloaded? bodies) (do (def comment (HyString)) (if (= (type (first bodies)) HyString) (do (def comment (car bodies)) (def bodies (cdr bodies)))) (def ret `(do)) (.append ret '(import [hy.contrib.multi [MultiDispatch]])) (for [body bodies] (def let-binds (car body)) (def body (cdr body)) (.append ret `(with-decorator MultiDispatch (defn ~name ~let-binds ~comment ~@body)))) ret) (do (setv lambda-list (first bodies)) (setv body (rest bodies)) `(setv ~name (fn ~lambda-list ~@body))))) hy-0.12.1/hy/contrib/profile.hy000066400000000000000000000036321304171765200163070ustar00rootroot00000000000000;;; Hy profiling macros ;; ;; Copyright (c) 2013 Paul R. Tagliamonte ;; ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. ;; ;;; These macros make debugging where bottlenecks exist easier. (defmacro profile/calls [&rest body] `(do (import [pycallgraph [PyCallGraph]] [pycallgraph.output [GraphvizOutput]]) (with* [(apply PyCallGraph [] {"output" (GraphvizOutput)})] ~@body))) (defmacro/g! profile/cpu [&rest body] " Profile a bit of code " `(do (import cProfile pstats) (if-python2 (import [StringIO [StringIO]]) (import [io [StringIO]])) (setv ~g!hy-pr (.Profile cProfile)) (.enable ~g!hy-pr) (do ~@body) (.disable ~g!hy-pr) (setv ~g!hy-s (StringIO)) (setv ~g!hy-ps (.sort-stats (apply pstats.Stats [~g!hy-pr] {"stream" ~g!hy-s}))) (.print-stats ~g!hy-ps) (print (.getvalue ~g!hy-s)))) hy-0.12.1/hy/contrib/sequences.hy000066400000000000000000000071071304171765200166430ustar00rootroot00000000000000;; Copyright (c) 2016 Tuukka Turto ;; ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. ;; (defclass Sequence [] [--init-- (fn [self func] "initialize a new sequence with a function to compute values" (setv (. self func) func) (setv (. self cache) []) (setv (. self high-water) -1)) --getitem-- (fn [self n] "get nth item of sequence" (if (hasattr n "start") (genexpr (get self x) [x (range n.start n.stop (or n.step 1))]) (do (when (neg? n) ; Call (len) to force the whole ; sequence to be evaluated. (len self)) (if (<= n (. self high-water)) (get (. self cache) n) (do (while (< (. self high-water) n) (setv (. self high-water) (inc (. self high-water))) (.append (. self cache) (.func self (. self high-water)))) (get self n)))))) --iter-- (fn [self] "create iterator for this sequence" (setv index 0) (try (while True (yield (get self index)) (setv index (inc index))) (except [_ IndexError] (raise StopIteration)))) --len-- (fn [self] "length of the sequence, dangerous for infinite sequences" (setv index (. self high-water)) (try (while True (get self index) (setv index (inc index))) (except [_ IndexError] (len (. self cache))))) max-items-in-repr 10 --str-- (fn [self] "string representation of this sequence" (setv items (list (take (inc self.max-items-in-repr) self))) (.format (if (> (len items) self.max-items-in-repr) "[{0}, ...]" "[{0}]") (.join ", " (map str items)))) --repr-- (fn [self] "string representation of this sequence" (.--str-- self))]) (defmacro seq [param &rest seq-code] `(Sequence (fn ~param (do ~@seq-code)))) (defmacro defseq [seq-name param &rest seq-code] `(def ~seq-name (Sequence (fn ~param (do ~@seq-code))))) (defn end-sequence [] "raise IndexError exception to signal end of sequence" (raise (IndexError "list index out of range"))) hy-0.12.1/hy/contrib/walk.hy000066400000000000000000000046661304171765200156150ustar00rootroot00000000000000;;; Hy AST walker ;; ;; Copyright (c) 2014, 2015 Gergely Nagy ;; ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. (import [hy [HyExpression HyDict]] [functools [partial]]) (defn walk [inner outer form] "Traverses form, an arbitrary data structure. Applies inner to each element of form, building up a data structure of the same type. Applies outer to the result." (cond [(instance? HyExpression form) (outer (HyExpression (map inner form)))] [(instance? HyDict form) (HyDict (outer (HyExpression (map inner form))))] [(cons? form) (outer (cons (inner (first form)) (inner (rest form))))] [(instance? list form) ((type form) (outer (HyExpression (map inner form))))] [(coll? form) (walk inner outer (list form))] [True (outer form)])) (defn postwalk [f form] "Performs depth-first, post-order traversal of form. Calls f on each sub-form, uses f's return value in place of the original." (walk (partial postwalk f) f form)) (defn prewalk [f form] "Performs depth-first, pre-order traversal of form. Calls f on each sub-form, uses f's return value in place of the original." (walk (partial prewalk f) identity (f form))) (defn macroexpand-all [form] "Recursively performs all possible macroexpansions in form." (prewalk (fn [x] (if (instance? HyExpression x) (macroexpand x) x)) form)) hy-0.12.1/hy/core/000077500000000000000000000000001304171765200135715ustar00rootroot00000000000000hy-0.12.1/hy/core/__init__.py000066400000000000000000000001331304171765200156770ustar00rootroot00000000000000from . import reserved # noqa STDLIB = [ "hy.core.language", "hy.core.shadow" ] hy-0.12.1/hy/core/bootstrap.hy000066400000000000000000000052231304171765200161520ustar00rootroot00000000000000;;; Hy bootstrap macros ;; ;; Copyright (c) 2013 Nicolas Dandrimont ;; Copyright (c) 2013 Paul Tagliamonte ;; Copyright (c) 2013 Konrad Hinsen ;; ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. ;; ;;; These macros are the essential hy macros. ;;; They are automatically required everywhere, even inside hy.core modules. (defmacro if [&rest args] "if with elif" (setv n (len args)) (if* n (if* (= n 1) (get args 0) `(if* ~(get args 0) ~(get args 1) (if ~@(cut args 2)))))) (defmacro macro-error [location reason] "error out properly within a macro" `(raise (hy.errors.HyMacroExpansionError ~location ~reason))) (defmacro defn [name lambda-list &rest body] "define a function `name` with signature `lambda-list` and body `body`" (if (not (= (type name) HySymbol)) (macro-error name "defn takes a name as first argument")) (if (not (isinstance lambda-list HyList)) (macro-error name "defn takes a parameter list as second argument")) `(setv ~name (fn ~lambda-list ~@body))) (defmacro let [variables &rest body] "Execute `body` in the lexical context of `variables`" (if (not (isinstance variables HyList)) (macro-error variables "let lexical context must be a list")) (if (= (len variables) 0) `((fn [] ~@body)) `((fn [] (setv ~@variables) ~@body)))) (defmacro if-python2 [python2-form python3-form] "If running on python2, execute python2-form, else, execute python3-form" (import sys) (if (< (get sys.version_info 0) 3) python2-form python3-form)) hy-0.12.1/hy/core/language.hy000066400000000000000000000344121304171765200157220ustar00rootroot00000000000000;; Copyright (c) 2013 Paul Tagliamonte ;; Copyright (c) 2013 Bob Tolbert ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. ;;;; This contains some of the core Hy functions used ;;;; to make functional programming slightly easier. ;;;; (import itertools) (import functools) (import collections) (import [fractions [Fraction :as fraction]]) (import operator) ; shadow not available yet (import sys) (if-python2 (import [StringIO [StringIO]]) (import [io [StringIO]])) (import [hy._compat [long-type]]) ; long for python2, int for python3 (import [hy.models.cons [HyCons]] [hy.models.symbol [HySymbol]] [hy.models.keyword [HyKeyword *keyword-prefix*]]) (import [hy.lex [LexException PrematureEndOfInput tokenize]]) (import [hy.compiler [HyASTCompiler]]) (defn butlast [coll] "Returns coll except of last element." (drop-last 1 coll)) (defn coll? [coll] "Checks whether item is a collection" (and (iterable? coll) (not (string? coll)))) (defn comp [&rest fs] "Function composition" (if (not fs) identity (= 1 (len fs)) (first fs) (do (setv rfs (reversed fs) first-f (next rfs) fs (tuple rfs)) (fn [&rest args &kwargs kwargs] (setv res (apply first-f args kwargs)) (for* [f fs] (setv res (f res))) res)))) (defn complement [f] "Create a function that reverses truth value of another function" (fn [&rest args &kwargs kwargs] (not (apply f args kwargs)))) (defn cons [a b] "Return a fresh cons cell with car = a and cdr = b" (HyCons a b)) (defn cons? [c] "Check whether c can be used as a cons object" (instance? HyCons c)) (defn constantly [value] "Create a function that always returns the same value" (fn [&rest args &kwargs kwargs] value)) (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" (- n 1)) (defn disassemble [tree &optional [codegen False]] "Return the python AST for a quoted Hy tree as a string. If the second argument is true, generate python code instead." (import astor) (import hy.compiler) (fake-source-positions tree) (setv compiled (hy.compiler.hy_compile tree (calling-module-name))) ((if codegen astor.codegen.to_source astor.dump) compiled)) (defn distinct [coll] "Return a generator from the original collection with duplicates removed" (let [seen (set) citer (iter coll)] (for* [val citer] (if (not_in val seen) (do (yield val) (.add seen val)))))) (if-python2 (def remove itertools.ifilterfalse zip-longest itertools.izip_longest ;; not builtin in Python3 reduce reduce ;; hy is more like Python3 filter itertools.ifilter input raw_input map itertools.imap range xrange zip itertools.izip) (def remove itertools.filterfalse zip-longest itertools.zip_longest ;; was builtin in Python2 reduce functools.reduce ;; Someone can import these directly from `hy.core.language`; ;; we'll make some duplicates. filter filter input input map map range range zip zip)) ;; infinite iterators (def count itertools.count cycle itertools.cycle repeat itertools.repeat) ;; shortest-terminating iterators (def *map itertools.starmap chain itertools.chain compress itertools.compress drop-while itertools.dropwhile group-by itertools.groupby islice itertools.islice take-while itertools.takewhile tee itertools.tee) ;; combinatoric iterators (def combinations itertools.combinations multicombinations itertools.combinations_with_replacement permutations itertools.permutations product itertools.product) ;; also from itertools, but not in Python2, and without func option until 3.3 (defn accumulate [iterable &optional [func operator.add]] "accumulate(iterable[, func]) --> accumulate object Return series of accumulated sums (or other binary function results)." (setv it (iter iterable) total (next it)) (yield total) (for* [element it] (setv total (func total element)) (yield total))) (defn drop [count coll] "Drop `count` elements from `coll` and yield back the rest" (islice coll count None)) (defn drop-last [n coll] "Return a sequence of all but the last n elements in coll." (let [iters (tee coll)] (map first (apply zip [(get iters 0) (drop n (get iters 1))])))) (defn empty? [coll] "Return True if `coll` is empty" (= 0 (len coll))) (defn even? [n] "Return true if n is an even number" (= (% n 2) 0)) (defn every? [pred coll] "Return true if (pred x) is logical true for every x in coll, else false" (all (map pred coll))) (defn fake-source-positions [tree] "Fake the source positions for a given tree" (if (coll? tree) (for* [subtree tree] (fake-source-positions subtree))) (for* [attr '[start-line end-line start-column end-column]] (if (not (hasattr tree attr)) (setattr tree attr 1)))) (defn flatten [coll] "Return a single flat list expanding all members of coll" (if (coll? coll) (_flatten coll []) (raise (TypeError (.format "{0!r} is not a collection" coll))))) (defn _flatten [coll result] (if (coll? coll) (do (for* [b coll] (_flatten b result))) (.append result coll)) result) (defn float? [x] "Return True if x is float" (isinstance x float)) (defn symbol? [s] "Check whether s is a symbol" (instance? HySymbol s)) (import [threading [Lock]]) (setv _gensym_counter 1234) (setv _gensym_lock (Lock)) (defn gensym [&optional [g "G"]] (let [new_symbol None] (global _gensym_counter) (global _gensym_lock) (.acquire _gensym_lock) (try (do (setv _gensym_counter (inc _gensym_counter)) (setv new_symbol (HySymbol (.format ":{0}_{1}" g _gensym_counter)))) (finally (.release _gensym_lock))) new_symbol)) (defn calling-module-name [&optional [n 1]] "Get the name of the module calling `n` levels up the stack from the `calling-module-name` function call (by default, one level up)" (import inspect) (setv f (get (.stack inspect) (+ n 1) 0)) (get f.f_globals "__name__")) (defn first [coll] "Return first item from `coll`" (next (iter coll) None)) (defn identity [x] "Returns the argument unchanged" x) (defn inc [n] "Increment n by 1" (+ n 1)) (defn instance? [klass x] (isinstance x klass)) (defn integer [x] "Return Hy kind of integer" (long-type x)) (defn integer? [x] "Return True if x is an integer" (isinstance x (, int long-type))) (defn integer-char? [x] "Return True if char `x` parses as an integer" (try (integer? (int x)) (except [ValueError] False) (except [TypeError] False))) (defn interleave [&rest seqs] "Return an iterable of the first item in each of seqs, then the second etc." (chain.from-iterable (apply zip seqs))) (defn interpose [item seq] "Return an iterable of the elements of seq separated by item" (drop 1 (interleave (repeat item) seq))) (defn iterable? [x] "Return true if x is iterable" (isinstance x collections.Iterable)) (defn iterate [f x] (setv val x) (while True (yield val) (setv val (f val)))) (defn iterator? [x] "Return true if x is an iterator" (isinstance x collections.Iterator)) (defn juxt [f &rest fs] "Return a function that applies each of the supplied functions to a single set of arguments and collects the results into a list." (setv fs (cons f fs)) (fn [&rest args &kwargs kwargs] (list-comp (apply f args kwargs) [f fs]))) (defn last [coll] "Return last item from `coll`" (get (tuple coll) -1)) (defn list* [hd &rest tl] "Return a dotted list construed from the elements of the argument" (if (not tl) hd (cons hd (apply list* tl)))) (defn macroexpand [form] "Return the full macro expansion of form" (import hy.macros) (setv name (calling-module-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 (HyASTCompiler name))) (defn merge-with [f &rest maps] "Returns a map that consists of the rest of the maps joined onto the first. If a key occurs in more than one map, the mapping(s) from the latter (left-to-right) will be combined with the mapping in the result by calling (f val-in-result val-in-latter)." (if (any maps) (let [merge-entry (fn [m e] (let [k (get e 0) v (get e 1)] (if (in k m) (assoc m k (f (get m k) v)) (assoc m k v))) m) merge2 (fn [m1 m2] (reduce merge-entry (.items m2) (or m1 {})))] (reduce merge2 maps)))) (defn neg? [n] "Return true if n is < 0" (< n 0)) (defn none? [x] "Return true if x is None" (is x None)) (defn numeric? [x] (import numbers) (instance? numbers.Number x)) (defn nth [coll n &optional [default None]] "Return nth item in collection or sequence, counting from 0. Return None if out of bounds unless specified otherwise." (next (drop n coll) default)) (defn odd? [n] "Return true if n is an odd number" (= (% n 2) 1)) (def -sentinel (object)) (defn partition [coll &optional [n 2] step [fillvalue -sentinel]] "Chunks coll into n-tuples (pairs by default). The remainder, if any, is not included unless a fillvalue is specified. The step defaults to n, but can be more to skip elements, or less for a sliding window with overlap." (setv step (or step n) slices (genexpr (itertools.islice coll start None step) [start (range n)])) (if (is fillvalue -sentinel) (apply zip slices) (apply zip-longest slices {"fillvalue" fillvalue}))) (defn pos? [n] "Return true if n is > 0" (> n 0)) (defn rest [coll] "Get all the elements of a coll, except the first." (drop 1 coll)) (defn repeatedly [func] "Yield result of running func repeatedly" (while True (yield (func)))) (defn second [coll] "Return second item from `coll`" (nth coll 1)) (defn some [pred coll] "Return the first logical true value of (pred x) for any x in coll, else None" (first (filter None (map pred coll)))) (defn string [x] "Cast x as current string implementation" (if-python2 (unicode x) (str x))) (defn string? [x] "Return True if x is a string" (if-python2 (isinstance x (, str unicode)) (isinstance x str))) (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`." (islice coll None count)) (defn take-nth [n coll] "Return every nth member of coll raises ValueError for (not (pos? n))" (if (pos? n) (let [citer (iter coll) skip (dec n)] (for* [val citer] (yield val) (for* [_ (range skip)] (next citer)))) (raise (ValueError "n must be positive")))) (defn zero? [n] "Return true if n is 0" (= n 0)) (defn read [&optional [from-file sys.stdin] [eof ""]] "Read from input and returns a tokenized string. Can take a given input buffer to read from" (def buff "") (while True (def inn (str (.readline from-file))) (if (= inn eof) (raise (EOFError "Reached end of file" ))) (setv buff (+ buff inn)) (try (def parsed (first (tokenize buff))) (except [e [PrematureEndOfInput IndexError]]) (else (if parsed (break))))) parsed) (defn read-str [input] "Reads and tokenizes first line of input" (read :from-file (StringIO input))) (defn hyify [text] "Convert text to match hy identifier" (.replace (string text) "_" "-")) (defn keyword [value] "Create a keyword from the given value. Strings numbers and even objects with the __name__ magic will work" (if (and (string? value) (value.startswith *keyword-prefix*)) (hyify value) (if (string? value) (HyKeyword (+ ":" (hyify value))) (try (hyify (.__name__ value)) (except [] (HyKeyword (+ ":" (string value)))))))) (defn name [value] "Convert the given value to a string. Keyword special character will be stripped. String will be used as is. Even objects with the __name__ magic will work" (if (and (string? value) (value.startswith *keyword-prefix*)) (hyify (cut value 2)) (if (string? value) (hyify value) (try (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 comp complement compress cons cons? constantly count cycle dec distinct disassemble drop drop-last drop-while empty? even? every? first filter flatten float? fraction gensym group-by identity inc input instance? integer integer? integer-char? interleave interpose islice iterable? iterate iterator? juxt keyword keyword? last list* macroexpand macroexpand-1 map merge-with multicombinations name neg? 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 xor tee zero? zip zip-longest]) hy-0.12.1/hy/core/macros.hy000066400000000000000000000206001304171765200154150ustar00rootroot00000000000000;;; Hy core macros ;; ;; Copyright (c) 2013 Nicolas Dandrimont ;; Copyright (c) 2013 Paul Tagliamonte ;; Copyright (c) 2013 Konrad Hinsen ;; ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. ;; ;;; These macros form the hy language ;;; They are automatically required in every module, except inside hy.core (import [hy.models.list [HyList]] [hy.models.symbol [HySymbol]] [hy._compat [PY33 PY34]]) (defmacro as-> [head name &rest rest] "Expands to sequence of assignments to the provided name, starting with head. The previous result is thus available in the subsequent form. Returns the final result, and leaves the name bound to it in the local scope. This behaves much like the other threading macros, but requires you to specify the threading point per form via the name instead of always the first or last argument." `(do (setv ~name ~head ~@(interleave (repeat name) rest)) ~name)) (defmacro with [args &rest body] "shorthand for nested with* loops: (with [x foo y bar] baz) -> (with* [x foo] (with* [y bar] baz))" (if (not (empty? args)) (do (if (>= (len args) 2) (do (setv p1 (.pop args 0) p2 (.pop args 0) primary [p1 p2]) `(with* [~@primary] (with ~args ~@body))) `(with* [~@args] ~@body))) `(do ~@body))) (defmacro car [thing] "Get the first element of a list/cons" `(get ~thing 0)) (defmacro cdr [thing] "Get all the elements of a thing, except the first" `(cut ~thing 1)) (defmacro cond [&rest branches] "shorthand for nested ifs: (cond [foo bar] [baz quux]) -> (if foo bar (if baz quux))" (if (empty? branches) None (do (setv branches (iter branches)) (setv branch (next branches)) (defn check-branch [branch] "check `cond` branch for validity, return the corresponding `if` expr" (if (not (= (type branch) HyList)) (macro-error branch "cond branches need to be a list")) (if (< (len branch) 2) (macro-error branch "cond branches need at least two items: a test and one or more code branches")) (setv test (car branch)) (setv thebranch (cdr branch)) `(if ~test (do ~@thebranch))) (setv root (check-branch branch)) (setv latest-branch root) (for* [branch branches] (setv cur-branch (check-branch branch)) (.append latest-branch cur-branch) (setv latest-branch cur-branch)) root))) (defmacro for [args &rest body] "shorthand for nested for loops: (for [x foo y bar] baz) -> (for* [x foo] (for* [y bar] baz))" (setv body (list body)) (if (empty? body) (macro-error None "`for' requires a body to evaluate")) (setv lst (get body -1)) (setv belse (if (and (isinstance lst HyExpression) (= (get lst 0) "else")) [(body.pop)] [])) (cond [(odd? (len args)) (macro-error args "`for' requires an even number of args.")] [(empty? body) (macro-error None "`for' requires a body to evaluate")] [(empty? args) `(do ~@body ~@belse)] [(= (len args) 2) `(for* [~@args] (do ~@body) ~@belse)] [True (let [alist (cut args 0 None 2)] `(for* [(, ~@alist) (genexpr (, ~@alist) [~@args])] (do ~@body) ~@belse))])) (defmacro -> [head &rest rest] "Threads the head through the rest of the forms. Inserts head as the second item in the first form of rest. If there are more forms, inserts the first form as the second item in the second form of rest, etc." (setv ret head) (for* [node rest] (if (not (isinstance node HyExpression)) (setv node `(~node))) (.insert node 1 ret) (setv ret node)) ret) (defmacro doto [form &rest expressions] "Performs a sequence of potentially mutating actions on an initial object, returning the resulting object" (setv f (gensym)) (defn build-form [expression] (if (isinstance expression HyExpression) `(~(first expression) ~f ~@(rest expression)) `(~expression ~f))) `(let [~f ~form] ~@(map build-form expressions) ~f)) (defmacro ->> [head &rest rest] "Threads the head through the rest of the forms. Inserts head as the last item in the first form of rest. If there are more forms, inserts the first form as the last item in the second form of rest, etc." (setv ret head) (for* [node rest] (if (not (isinstance node HyExpression)) (setv node `(~node))) (.append node ret) (setv ret node)) ret) (defmacro if-not [test not-branch &optional yes-branch] "Like `if`, but execute the first branch when the test fails" `(if* (not ~test) ~not-branch ~yes-branch)) (defmacro lif [&rest args] "Like `if`, but anything that is not None is considered true." (setv n (len args)) (if* n (if* (= n 1) (get args 0) `(if* (is-not ~(get args 0) None) ~(get args 1) (lif ~@(cut args 2)))))) (defmacro lif-not [test not-branch &optional yes-branch] "Like `if-not`, but anything that is not None is considered true." `(if* (is ~test None) ~not-branch ~yes-branch)) (defmacro when [test &rest body] "Execute `body` when `test` is true" `(if ~test (do ~@body))) (defmacro unless [test &rest body] "Execute `body` when `test` is false" `(if-not ~test (do ~@body))) (defmacro with-gensyms [args &rest body] (setv syms []) (for* [arg args] (.extend syms `[~arg (gensym '~arg)])) `(let ~syms ~@body)) (defmacro defmacro/g! [name args &rest body] (let [syms (list (distinct (filter (fn [x] (and (hasattr x "startswith") (.startswith x "g!"))) (flatten body)))) gensyms []] (for* [sym syms] (.extend gensyms `[~sym (gensym (cut '~sym 2))])) `(defmacro ~name [~@args] (let ~gensyms ~@body)))) (defmacro defmacro! [name args &rest body] "Like defmacro/g! plus automatic once-only evaluation for o! parameters, which are available as the equivalent g! symbol." (setv os (list-comp s [s args] (.startswith s "o!")) gs (list-comp (HySymbol (+ "g!" (cut s 2))) [s os])) `(defmacro/g! ~name ~args `(do (setv ~@(interleave ~gs ~os)) ~@~body))) (if-python2 (defmacro/g! yield-from [expr] `(do (import types) (setv ~g!iter (iter ~expr)) (setv ~g!return None) (setv ~g!message None) (while True (try (if (isinstance ~g!iter types.GeneratorType) (setv ~g!message (yield (.send ~g!iter ~g!message))) (setv ~g!message (yield (next ~g!iter)))) (except [~g!e StopIteration] (do (setv ~g!return (if (hasattr ~g!e "value") (. ~g!e value) None)) (break))))) ~g!return)) None) (defmacro defmain [args &rest body] "Write a function named \"main\" and do the if __main__ dance" (let [retval (gensym) mainfn `(fn [~@args] ~@body)] `(when (= --name-- "__main__") (import sys) (setv ~retval (apply ~mainfn sys.argv)) (if (integer? ~retval) (sys.exit ~retval))))) (defreader @ [expr] (let [decorators (cut expr None -1) fndef (get expr -1)] `(with-decorator ~@decorators ~fndef))) hy-0.12.1/hy/core/reserved.hy000066400000000000000000000033341304171765200157550ustar00rootroot00000000000000;;; Get a frozenset of Hy reserved words ;; ;; Copyright (c) 2016 Paul Tagliamonte ;; ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. (import hy sys keyword) (setv _cache None) (defn names [] "Return a frozenset of reserved symbol names. The result of the first call is cached." (global _cache) (if (is _cache None) (do (setv unmangle (. sys.modules ["hy.lex.parser"] hy_symbol_unmangle)) (setv _cache (frozenset (map unmangle (+ hy.core.language.*exports* hy.core.shadow.*exports* (list (.keys (get hy.macros._hy_macros None))) keyword.kwlist (list-comp k [k (.keys hy.compiler.-compile-table)] (isinstance k hy._compat.string-types)))))))) _cache) hy-0.12.1/hy/core/shadow.hy000066400000000000000000000066421304171765200154300ustar00rootroot00000000000000;; Copyright (c) 2014 Paul Tagliamonte ;; Copyright (c) 2014 James King ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. ;;;; Hy shadow functions (import operator) (defn + [&rest args] "Shadow + operator for when we need to import / map it against something" (let [count (len args)] (if (zero? count) (raise (TypeError "Need at least 1 argument to add/concatenate")) (if (= count 1) (operator.pos (get args 0)) (reduce operator.add args))))) (defn - [&rest args] "Shadow - operator for when we need to import / map it against something" (let [count (len args)] (if (= count 0) (raise (TypeError "Need at least 1 argument to subtract")) (if (= count 1) (- (get args 0)) (reduce operator.sub args))))) (defn * [&rest args] "Shadow * operator for when we need to import / map it against something" (if (= (len args) 0) 1 ; identity (reduce operator.mul args))) (defn / [&rest args] "Shadow / operator for when we need to import / map it against something" (let [count (len args)] (if (= count 0) (raise (TypeError "Need at least 1 argument to divide")) (if (= count 1) (operator.truediv 1 (get args 0)) (reduce operator.truediv args))))) (defn comp-op [op args] "Helper for shadow comparison operators" (if (< (len args) 2) (raise (TypeError "Need at least 2 arguments to compare")) (reduce operator.and_ (list-comp (op x y) [(, x y) (zip args (cut args 1))])))) (defn < [&rest args] "Shadow < operator for when we need to import / map it against something" (comp-op operator.lt args)) (defn <= [&rest args] "Shadow <= operator for when we need to import / map it against something" (comp-op operator.le args)) (defn = [&rest args] "Shadow = operator for when we need to import / map it against something" (comp-op operator.eq args)) (defn != [&rest args] "Shadow != operator for when we need to import / map it against something" (comp-op operator.ne args)) (defn >= [&rest args] "Shadow >= operator for when we need to import / map it against something" (comp-op operator.ge args)) (defn > [&rest args] "Shadow > operator for when we need to import / map it against something" (comp-op operator.gt args)) ; TODO figure out a way to shadow "is", "is_not", "and", "or" (setv *exports* ['+ '- '* '/ '< '<= '= '!= '>= '>]) hy-0.12.1/hy/errors.py000066400000000000000000000101231304171765200145240ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # # Copyright (c) 2013 Paul Tagliamonte # Copyright (c) 2013 Bob Tolbert # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. import traceback from clint.textui import colored class HyError(Exception): """ Generic Hy error. All internal Exceptions will be subclassed from this Exception. """ pass class HyCompileError(HyError): def __init__(self, exception, traceback=None): self.exception = exception self.traceback = traceback def __str__(self): if isinstance(self.exception, HyTypeError): return str(self.exception) if self.traceback: tb = "".join(traceback.format_tb(self.traceback)).strip() else: tb = "No traceback available. 😟" return("Internal Compiler Bug 😱\n⤷ %s: %s\nCompilation traceback:\n%s" % (self.exception.__class__.__name__, self.exception, tb)) class HyTypeError(TypeError): def __init__(self, expression, message): super(HyTypeError, self).__init__(message) self.expression = expression self.message = message self.source = None self.filename = None def __str__(self): line = self.expression.start_line start = self.expression.start_column end = self.expression.end_column source = [] if self.source is not None: source = self.source.split("\n")[line-1:self.expression.end_line] if line == self.expression.end_line: length = end - start else: length = len(source[0]) - start result = "" result += ' File "%s", line %d, column %d\n\n' % (self.filename, line, start) if len(source) == 1: result += ' %s\n' % colored.red(source[0]) result += ' %s%s\n' % (' '*(start-1), colored.green('^' + '-'*(length-1) + '^')) if len(source) > 1: result += ' %s\n' % colored.red(source[0]) result += ' %s%s\n' % (' '*(start-1), colored.green('^' + '-'*length)) if len(source) > 2: # write the middle lines for line in source[1:-1]: result += ' %s\n' % colored.red("".join(line)) result += ' %s\n' % colored.green("-"*len(line)) # write the last line result += ' %s\n' % colored.red("".join(source[-1])) result += ' %s\n' % colored.green('-'*(end-1) + '^') result += colored.yellow("%s: %s\n\n" % (self.__class__.__name__, self.message.encode('utf-8'))) return result class HyMacroExpansionError(HyTypeError): pass class HyIOError(HyError, IOError): """ Trivial subclass of IOError and HyError, to distinguish between IOErrors raised by Hy itself as opposed to Hy programs. """ pass hy-0.12.1/hy/extra/000077500000000000000000000000001304171765200137645ustar00rootroot00000000000000hy-0.12.1/hy/extra/__init__.py000066400000000000000000000000001304171765200160630ustar00rootroot00000000000000hy-0.12.1/hy/extra/anaphoric.hy000066400000000000000000000121661304171765200163000ustar00rootroot00000000000000;;; Hy anaphoric macros ;; ;; Copyright (c) 2013 James King ;; 2013 Paul R. Tagliamonte ;; 2013 Abhishek L ;; ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. ;; ;;; These macros make writing functional programs more concise (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] "Evaluate the body form for each element in the list." `(for [it ~lst] ~@body)) (defmacro ap-each-while [lst form &rest body] "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] (if (p it) ~@body (break))))) (defmacro ap-map [form lst] "Yield elements evaluated in the form for each element in the list." (let [v (gensym 'v) f (gensym 'f)] `(let [~f (lambda [it] ~form)] (for [~v ~lst] (yield (~f ~v)))))) (defmacro ap-map-when [predfn rep lst] "Yield elements evaluated for each element in the list when the predicate function returns True." `(let [f (lambda [it] ~rep)] (for [it ~lst] (if (~predfn it) (yield (f it)) (yield it))))) (defmacro ap-filter [form lst] "Yield elements returned when the predicate form evaluates to True." `(let [pred (lambda [it] ~form)] (for [val ~lst] (if (pred val) (yield val))))) (defmacro ap-reject [form lst] "Yield elements returned when the predicate form evaluates to False" `(ap-filter (not ~form) ~lst)) (defmacro ap-dotimes [n &rest body] "Execute body for side effects `n' times, with it bound from 0 to n-1" (unless (numeric? n) (raise (TypeError (.format "{0!r} is not a number" n)))) `(ap-each (range ~n) ~@body)) (defmacro ap-first [predfn lst] "Yield the first element that passes `predfn`" (with-gensyms [n] `(let [~n None] (ap-each ~lst (when ~predfn (setv ~n it) (break))) ~n))) (defmacro ap-last [predfn lst] "Yield the last element that passes `predfn`" (with-gensyms [n] `(let [~n None] (ap-each ~lst (none? ~n) (when ~predfn (setv ~n it))) ~n))) (defmacro ap-reduce [form lst &optional [initial-value None]] "Anaphoric form of reduce, `acc' and `it' can be used for a form" (if (none? initial-value) `(let [acc (car ~lst)] (ap-each (cdr ~lst) (setv acc ~form)) acc) `(let [acc ~initial-value] (ap-each ~lst (setv acc ~form)) acc))) (defmacro ap-pipe [var &rest forms] "Pushes a value through several forms. (Anaphoric version of -> and ->>)" (if (empty? forms) var `(ap-pipe (let [it ~var] ~(first forms)) ~@(rest forms)))) (defmacro ap-compose [&rest forms] "Returns a function which is the composition of several forms." `(fn [var] (ap-pipe var ~@forms))) (defmacro xi [&rest body] "Returns a function with parameters implicitly determined by the presence in the body of xi parameters. An xi symbol designates the ith parameter (1-based, e.g. x1, x2, x3, etc.), or all remaining parameters for xi itself. This is not a replacement for lambda. The xi forms cannot be nested. " (setv flatbody (flatten body)) `(lambda [;; generate all xi symbols up to the maximum found in body ~@(genexpr (HySymbol (+ "x" (str i))) [i (range 1 ;; find the maximum xi (inc (max (+ (list-comp (int (cdr a)) [a flatbody] (and (symbol? a) (.startswith a 'x) (.isdigit (cdr a)))) [0]))))]) ;; generate the &rest parameter only if 'xi is present in body ~@(if (in 'xi flatbody) '(&rest xi) '())] (~@body))) hy-0.12.1/hy/importer.py000066400000000000000000000160201304171765200150530ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # Copyright (c) 2013, 2014 Bob Tolbert # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.compiler import hy_compile, HyTypeError from hy.models import HyObject, replace_hy_obj from hy.lex import tokenize, LexException from hy.errors import HyIOError from io import open import marshal import imp import sys import ast import os import __future__ from hy._compat import PY3, PY33, MAGIC, builtins, long_type, wr_long from hy._compat import string_types def ast_compile(ast, filename, mode): """Compile AST. Like Python's compile, but with some special flags.""" flags = (__future__.CO_FUTURE_DIVISION | __future__.CO_FUTURE_PRINT_FUNCTION) return compile(ast, filename, mode, flags) def import_buffer_to_hst(buf): """Import content from buf and return a Hy AST.""" return tokenize(buf + "\n") def import_file_to_hst(fpath): """Import content from fpath and return a Hy AST.""" try: with open(fpath, 'r', encoding='utf-8') as f: return import_buffer_to_hst(f.read()) except IOError as e: raise HyIOError(e.errno, e.strerror, e.filename) def import_buffer_to_ast(buf, module_name): """ Import content from buf and return a Python AST.""" return hy_compile(import_buffer_to_hst(buf), module_name) def import_file_to_ast(fpath, module_name): """Import content from fpath and return a Python AST.""" return hy_compile(import_file_to_hst(fpath), module_name) def import_file_to_module(module_name, fpath): """Import content from fpath and puts it into a Python module. Returns the module.""" try: _ast = import_file_to_ast(fpath, module_name) mod = imp.new_module(module_name) mod.__file__ = fpath eval(ast_compile(_ast, fpath, "exec"), mod.__dict__) except (HyTypeError, LexException) as e: if e.source is None: with open(fpath, 'rt') as fp: e.source = fp.read() e.filename = fpath raise except Exception: sys.modules.pop(module_name, None) raise return mod def import_file_to_globals(env, module_name, fpath): """ Import content from fpath and puts it into the dict provided (e.g., for use in a REPL) """ mod = import_file_to_module(module_name, fpath) for k, v in mod.__dict__.items(): env[k] = v def import_buffer_to_module(module_name, buf): try: _ast = import_buffer_to_ast(buf, module_name) mod = imp.new_module(module_name) eval(ast_compile(_ast, "", "exec"), mod.__dict__) except (HyTypeError, LexException) as e: if e.source is None: e.source = buf e.filename = '' raise return mod def hy_eval(hytree, namespace, module_name): foo = HyObject() foo.start_line = 0 foo.end_line = 0 foo.start_column = 0 foo.end_column = 0 replace_hy_obj(hytree, foo) if not isinstance(module_name, string_types): raise HyTypeError(foo, "Module name must be a string") _ast, expr = hy_compile(hytree, module_name, get_expr=True) # Spoof the positions in the generated ast... for node in ast.walk(_ast): node.lineno = 1 node.col_offset = 1 for node in ast.walk(expr): node.lineno = 1 node.col_offset = 1 if not isinstance(namespace, dict): raise HyTypeError(foo, "Globals must be a dictionary") # Two-step eval: eval() the body of the exec call eval(ast_compile(_ast, "", "exec"), namespace) # Then eval the expression context and return that return eval(ast_compile(expr, "", "eval"), namespace) def write_hy_as_pyc(fname): with open(fname, 'U') as f: try: st = os.fstat(f.fileno()) except AttributeError: st = os.stat(fname) timestamp = long_type(st.st_mtime) _ast = import_file_to_ast(fname, os.path.basename(os.path.splitext(fname)[0])) code = ast_compile(_ast, fname, "exec") cfile = "%s.pyc" % fname[:-len(".hy")] open_ = builtins.open with open_(cfile, 'wb') as fc: if PY3: fc.write(b'\0\0\0\0') else: fc.write('\0\0\0\0') wr_long(fc, timestamp) if PY33: wr_long(fc, st.st_size) marshal.dump(code, fc) fc.flush() fc.seek(0, 0) fc.write(MAGIC) class MetaLoader(object): def __init__(self, path): self.path = path def is_package(self, fullname): dirpath = "/".join(fullname.split(".")) for pth in sys.path: pth = os.path.abspath(pth) composed_path = "%s/%s/__init__.hy" % (pth, dirpath) if os.path.exists(composed_path): return True return False def load_module(self, fullname): if fullname in sys.modules: return sys.modules[fullname] if not self.path: return sys.modules[fullname] = None mod = import_file_to_module(fullname, self.path) ispkg = self.is_package(fullname) mod.__file__ = self.path mod.__loader__ = self mod.__name__ = fullname if ispkg: mod.__path__ = [] mod.__package__ = fullname else: mod.__package__ = fullname.rpartition('.')[0] sys.modules[fullname] = mod return mod class MetaImporter(object): def find_on_path(self, fullname): fls = ["%s/__init__.hy", "%s.hy"] dirpath = "/".join(fullname.split(".")) for pth in sys.path: pth = os.path.abspath(pth) for fp in fls: composed_path = fp % ("%s/%s" % (pth, dirpath)) if os.path.exists(composed_path): return composed_path def find_module(self, fullname, path=None): path = self.find_on_path(fullname) if path: return MetaLoader(path) sys.meta_path.insert(0, MetaImporter()) sys.path.insert(0, "") hy-0.12.1/hy/lex/000077500000000000000000000000001304171765200134315ustar00rootroot00000000000000hy-0.12.1/hy/lex/__init__.py000066400000000000000000000032741304171765200155500ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from rply.errors import LexingError from hy.lex.exceptions import LexException, PrematureEndOfInput # NOQA from hy.lex.lexer import lexer from hy.lex.parser import parser def tokenize(buf): """ Tokenize a Lisp file or string buffer into internal Hy objects. """ try: return parser.parse(lexer.lex(buf)) except LexingError as e: pos = e.getsourcepos() raise LexException("Could not identify the next token.", pos.lineno, pos.colno) except LexException as e: if e.source is None: e.source = buf raise hy-0.12.1/hy/lex/exceptions.py000066400000000000000000000047361304171765200161760ustar00rootroot00000000000000# Copyright (c) 2013 Nicolas Dandrimont # Copyright (c) 2013 Bob Tolbert # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.errors import HyError class LexException(HyError): """Error during the Lexing of a Hython expression.""" def __init__(self, message, lineno, colno): super(LexException, self).__init__(message) self.message = message self.lineno = lineno self.colno = colno self.source = None self.filename = '' def __str__(self): from hy.errors import colored line = self.lineno start = self.colno result = "" source = self.source.split("\n") if line > 0 and start > 0: result += ' File "%s", line %d, column %d\n\n' % (self.filename, line, start) if len(self.source) > 0: source_line = source[line-1] else: source_line = "" result += ' %s\n' % colored.red(source_line) result += ' %s%s\n' % (' '*(start-1), colored.green('^')) result += colored.yellow("LexException: %s\n\n" % self.message) return result class PrematureEndOfInput(LexException): """We got a premature end of input""" def __init__(self, message): super(PrematureEndOfInput, self).__init__(message, -1, -1) hy-0.12.1/hy/lex/lexer.py000066400000000000000000000045771304171765200151370ustar00rootroot00000000000000# Copyright (c) 2013 Nicolas Dandrimont # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from rply import LexerGenerator lg = LexerGenerator() # A regexp for something that should end a quoting/unquoting operator # i.e. a space or a closing brace/paren/curly end_quote = r'(?![\s\)\]\}])' lg.add('LPAREN', r'\(') lg.add('RPAREN', r'\)') lg.add('LBRACKET', r'\[') lg.add('RBRACKET', r'\]') lg.add('LCURLY', r'\{') lg.add('RCURLY', r'\}') lg.add('HLCURLY', r'#\{') lg.add('QUOTE', r'\'%s' % end_quote) lg.add('QUASIQUOTE', r'`%s' % end_quote) lg.add('UNQUOTESPLICE', r'~@%s' % end_quote) lg.add('UNQUOTE', r'~%s' % end_quote) lg.add('HASHBANG', r'#!.*[^\r\n]') lg.add('HASHREADER', r'#[^{]') # A regexp which matches incomplete strings, used to support # multi-line strings in the interpreter partial_string = r'''(?x) (?:u|r|ur|ru)? # prefix " # start string (?: | [^"\\] # non-quote or backslash | \\(.|\n) # or escaped single character or newline | \\x[0-9a-fA-F]{2} # or escaped raw character | \\u[0-9a-fA-F]{4} # or unicode escape | \\U[0-9a-fA-F]{8} # or long unicode escape )* # one or more times ''' lg.add('STRING', r'%s"' % partial_string) lg.add('PARTIAL_STRING', partial_string) lg.add('IDENTIFIER', r'[^()\[\]{}\'"\s;]+') lg.ignore(r';.*(?=\r|\n|$)') lg.ignore(r'\s+') lexer = lg.build() hy-0.12.1/hy/lex/parser.py000066400000000000000000000211231304171765200152760ustar00rootroot00000000000000# Copyright (c) 2013 Nicolas Dandrimont # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. import sys from functools import wraps from rply import ParserGenerator from hy.models.complex import HyComplex from hy.models.cons import HyCons from hy.models.dict import HyDict from hy.models.expression import HyExpression from hy.models.float import HyFloat from hy.models.integer import HyInteger from hy.models.keyword import HyKeyword from hy.models.list import HyList from hy.models.set import HySet from hy.models.string import HyString from hy.models.symbol import HySymbol from .lexer import lexer from .exceptions import LexException, PrematureEndOfInput pg = ParserGenerator( [rule.name for rule in lexer.rules] + ['$end'], cache_id="hy_parser" ) def hy_symbol_mangle(p): if p.startswith("*") and p.endswith("*") and p not in ("*", "**"): p = p[1:-1].upper() if "-" in p and p != "-": p = p.replace("-", "_") if p.endswith("?") and p != "?": p = "is_%s" % (p[:-1]) if p.endswith("!") and p != "!": p = "%s_bang" % (p[:-1]) return p def hy_symbol_unmangle(p): # hy_symbol_mangle is one-way, so this can't be perfect. # But it can be useful till we have a way to get the original # symbol (https://github.com/hylang/hy/issues/360). from hy._compat import str_type p = str_type(p) if p.endswith("_bang") and p != "_bang": p = p[:-len("_bang")] + "!" if p.startswith("is_") and p != "is_": p = p[len("is_"):] + "?" if "_" in p and p != "_": p = p.replace("_", "-") if (all([c.isalpha() and c.isupper() or c == '_' for c in p]) and any([c.isalpha() for c in p])): p = '*' + p.lower() + '*' return p def set_boundaries(fun): @wraps(fun) def wrapped(p): start = p[0].source_pos end = p[-1].source_pos ret = fun(p) ret.start_line = start.lineno ret.start_column = start.colno if start is not end: ret.end_line = end.lineno ret.end_column = end.colno else: ret.end_line = start.lineno ret.end_column = start.colno + len(p[0].value) return ret return wrapped def set_quote_boundaries(fun): @wraps(fun) def wrapped(p): start = p[0].source_pos ret = fun(p) ret.start_line = start.lineno ret.start_column = start.colno ret.end_line = p[-1].end_line ret.end_column = p[-1].end_column return ret return wrapped @pg.production("main : HASHBANG real_main") def main_hashbang(p): return p[1] @pg.production("main : real_main") def main(p): return p[0] @pg.production("real_main : list_contents") def real_main(p): return p[0] @pg.production("real_main : $end") def real_main_empty(p): return [] def reject_spurious_dots(*items): "Reject the spurious dots from items" for list in items: for tok in list: if tok == "." and type(tok) == HySymbol: raise LexException("Malformed dotted list", tok.start_line, tok.start_column) @pg.production("paren : LPAREN list_contents RPAREN") @set_boundaries def paren(p): cont = p[1] # Dotted lists are expressions of the form # (a b c . d) # that evaluate to nested cons cells of the form # (a . (b . (c . d))) if len(cont) >= 3 and isinstance(cont[-2], HySymbol) and cont[-2] == ".": reject_spurious_dots(cont[:-2], cont[-1:]) if len(cont) == 3: # Two-item dotted list: return the cons cell directly return HyCons(cont[0], cont[2]) else: # Return a nested cons cell return HyCons(cont[0], paren([p[0], cont[1:], p[2]])) # Warn preemptively on a malformed dotted list. # Only check for dots after the first item to allow for a potential # attribute accessor shorthand reject_spurious_dots(cont[1:]) return HyExpression(p[1]) @pg.production("paren : LPAREN RPAREN") @set_boundaries def empty_paren(p): return HyExpression([]) @pg.production("list_contents : term list_contents") def list_contents(p): return [p[0]] + p[1] @pg.production("list_contents : term") def list_contents_single(p): return [p[0]] @pg.production("term : identifier") @pg.production("term : paren") @pg.production("term : dict") @pg.production("term : list") @pg.production("term : set") @pg.production("term : string") def term(p): return p[0] @pg.production("term : QUOTE term") @set_quote_boundaries def term_quote(p): return HyExpression([HySymbol("quote"), p[1]]) @pg.production("term : QUASIQUOTE term") @set_quote_boundaries def term_quasiquote(p): return HyExpression([HySymbol("quasiquote"), p[1]]) @pg.production("term : UNQUOTE term") @set_quote_boundaries def term_unquote(p): return HyExpression([HySymbol("unquote"), p[1]]) @pg.production("term : UNQUOTESPLICE term") @set_quote_boundaries def term_unquote_splice(p): return HyExpression([HySymbol("unquote_splice"), p[1]]) @pg.production("term : HASHREADER term") @set_quote_boundaries def hash_reader(p): st = p[0].getstr()[1] str_object = HyString(st) expr = p[1] return HyExpression([HySymbol("dispatch_reader_macro"), str_object, expr]) @pg.production("set : HLCURLY list_contents RCURLY") @set_boundaries def t_set(p): return HySet(p[1]) @pg.production("set : HLCURLY RCURLY") @set_boundaries def empty_set(p): return HySet([]) @pg.production("dict : LCURLY list_contents RCURLY") @set_boundaries def t_dict(p): return HyDict(p[1]) @pg.production("dict : LCURLY RCURLY") @set_boundaries def empty_dict(p): return HyDict([]) @pg.production("list : LBRACKET list_contents RBRACKET") @set_boundaries def t_list(p): return HyList(p[1]) @pg.production("list : LBRACKET RBRACKET") @set_boundaries def t_empty_list(p): return HyList([]) if sys.version_info[0] >= 3: def uni_hystring(s): return HyString(eval(s)) else: def uni_hystring(s): return HyString(eval('u'+s)) @pg.production("string : STRING") @set_boundaries def t_string(p): # remove trailing quote s = p[0].value[:-1] # get the header header, s = s.split('"', 1) # remove unicode marker header = header.replace("u", "") # build python string s = header + '"""' + s + '"""' return uni_hystring(s) @pg.production("string : PARTIAL_STRING") def t_partial_string(p): # Any unterminated string requires more input raise PrematureEndOfInput("Premature end of input") @pg.production("identifier : IDENTIFIER") @set_boundaries def t_identifier(p): obj = p[0].value try: return HyInteger(obj) except ValueError: pass if '/' in obj: try: lhs, rhs = obj.split('/') return HyExpression([HySymbol('fraction'), HyInteger(lhs), HyInteger(rhs)]) except ValueError: pass try: return HyFloat(obj) except ValueError: pass if obj != 'j': try: return HyComplex(obj) except ValueError: pass if obj.startswith(":"): return HyKeyword(obj) obj = ".".join([hy_symbol_mangle(part) for part in obj.split(".")]) return HySymbol(obj) @pg.error def error_handler(token): tokentype = token.gettokentype() if tokentype == '$end': raise PrematureEndOfInput("Premature end of input") else: raise LexException( "Ran into a %s where it wasn't expected." % tokentype, token.source_pos.lineno, token.source_pos.colno) parser = pg.build() hy-0.12.1/hy/macros.py000066400000000000000000000173301304171765200145030ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from inspect import getargspec, formatargspec from hy.models import replace_hy_obj, wrap_value from hy.models.expression import HyExpression from hy.models.string import HyString from hy.errors import HyTypeError, HyMacroExpansionError from collections import defaultdict CORE_MACROS = [ "hy.core.bootstrap", ] EXTRA_MACROS = [ "hy.core.macros", ] _hy_macros = defaultdict(dict) _hy_reader = defaultdict(dict) def macro(name): """Decorator to define a macro called `name`. This stores the macro `name` in the namespace for the module where it is defined. If the module where it is defined is in `hy.core`, then the macro is stored in the default `None` namespace. This function is called from the `defmacro` special form in the compiler. """ def _(fn): try: argspec = getargspec(fn) fn._hy_macro_pass_compiler = argspec.keywords is not None except Exception: # An exception might be raised if fn has arguments with # names that are invalid in Python. fn._hy_macro_pass_compiler = False module_name = fn.__module__ if module_name.startswith("hy.core"): module_name = None _hy_macros[module_name][name] = fn return fn return _ def reader(name): """Decorator to define a reader macro called `name`. This stores the macro `name` in the namespace for the module where it is defined. If the module where it is defined is in `hy.core`, then the macro is stored in the default `None` namespace. This function is called from the `defreader` special form in the compiler. """ def _(fn): module_name = fn.__module__ if module_name.startswith("hy.core"): module_name = None _hy_reader[module_name][name] = fn return fn return _ def require(source_module, target_module, all_macros=False, assignments={}, prefix=""): """Load macros from `source_module` in the namespace of `target_module`. `assignments` maps old names to new names, but is ignored if `all_macros` is true. If `prefix` is nonempty, it is prepended to the name of each imported macro. (This means you get macros named things like "mymacromodule.mymacro", which looks like an attribute of a module, although it's actually just a symbol with a period in its name.) This function is called from the `require` special form in the compiler. """ seen_names = set() if prefix: prefix += "." for d in _hy_macros, _hy_reader: for name, macro in d[source_module].items(): seen_names.add(name) if all_macros: d[target_module][prefix + name] = macro elif name in assignments: d[target_module][prefix + assignments[name]] = macro if not all_macros: unseen = frozenset(assignments.keys()).difference(seen_names) if unseen: raise ImportError("cannot require names: " + repr(list(unseen))) def load_macros(module_name): """Load the hy builtin macros for module `module_name`. Modules from `hy.core` can only use the macros from CORE_MACROS. Other modules get the macros from CORE_MACROS and EXTRA_MACROS. """ def _import(module, module_name=module_name): "__import__ a module, avoiding recursions" if module != module_name: __import__(module) for module in CORE_MACROS: _import(module) if module_name.startswith("hy.core"): return for module in EXTRA_MACROS: _import(module) def make_empty_fn_copy(fn): try: # This might fail if fn has parameters with funny names, like o!n. In # such a case, we return a generic function that ensures the program # can continue running. Unfortunately, the error message that might get # raised later on while expanding a macro might not make sense at all. argspec = getargspec(fn) formatted_args = formatargspec(*argspec) fn_str = 'lambda {}: None'.format( formatted_args.lstrip('(').rstrip(')')) empty_fn = eval(fn_str) except Exception: def empty_fn(*args, **kwargs): None return empty_fn 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(compiler.module_name) old = None while old != tree: old = tree tree = macroexpand_1(tree, compiler) return tree def macroexpand_1(tree, compiler): """Expand the toplevel macro from `tree` once, in the context of `module_name`.""" if isinstance(tree, HyExpression): if tree == []: return tree fn = tree[0] if fn in ("quote", "quasiquote"): return tree ntree = HyExpression(tree[:]) ntree.replace(tree) opts = {} if isinstance(fn, HyString): 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_empty_fn_copy(m) m_copy(*ntree[1:], **opts) except TypeError as e: msg = "expanding `" + str(tree[0]) + "': " msg += str(e).replace("()", "", 1).strip() raise HyMacroExpansionError(tree, msg) try: obj = wrap_value(m(*ntree[1:], **opts)) except HyTypeError as e: if e.expression is None: e.expression = tree raise except Exception as e: msg = "expanding `" + str(tree[0]) + "': " + repr(e) raise HyMacroExpansionError(tree, msg) replace_hy_obj(obj, tree) return obj return ntree return tree def reader_macroexpand(char, tree, compiler): """Expand the reader macro "char" with argument `tree`.""" load_macros(compiler.module_name) reader_macro = _hy_reader[compiler.module_name].get(char) if reader_macro is None: try: reader_macro = _hy_reader[None][char] except KeyError: raise HyTypeError( char, "`{0}' is not a defined reader macro.".format(char) ) expr = reader_macro(tree) return replace_hy_obj(wrap_value(expr), tree) hy-0.12.1/hy/models/000077500000000000000000000000001304171765200141245ustar00rootroot00000000000000hy-0.12.1/hy/models/__init__.py000066400000000000000000000045321304171765200162410ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. class HyObject(object): """ Generic Hy Object model. This is helpful to inject things into all the Hy lexing Objects at once. """ def replace(self, other): if isinstance(other, HyObject): for attr in ["start_line", "end_line", "start_column", "end_column"]: if not hasattr(self, attr) and hasattr(other, attr): setattr(self, attr, getattr(other, attr)) else: raise TypeError("Can't replace a non Hy object with a Hy object") return self _wrappers = {} def wrap_value(x): """Wrap `x` into the corresponding Hy type. This allows replace_hy_obj to convert a non Hy object to a Hy object. This also allows a macro to return an unquoted expression transparently. """ wrapper = _wrappers.get(type(x)) if wrapper is None: return x else: return wrapper(x) def replace_hy_obj(obj, other): if isinstance(obj, HyObject): return obj.replace(other) wrapped_obj = wrap_value(obj) if isinstance(wrapped_obj, HyObject): return wrapped_obj.replace(other) else: raise TypeError("Don't know how to wrap a %s object to a HyObject" % type(obj)) hy-0.12.1/hy/models/complex.py000066400000000000000000000027461304171765200161560ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import HyObject, _wrappers class HyComplex(HyObject, complex): """ Internal representation of a Hy Complex. May raise a ValueError as if complex(foo) was called, given HyComplex(foo). """ def __new__(cls, number, *args, **kwargs): number = complex(number) return super(HyComplex, cls).__new__(cls, number) _wrappers[complex] = HyComplex hy-0.12.1/hy/models/cons.py000066400000000000000000000067701304171765200154520ustar00rootroot00000000000000# Copyright (c) 2013 Nicolas Dandrimont # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import HyObject, replace_hy_obj, wrap_value from hy.models.expression import HyExpression from hy.models.symbol import HySymbol class HyCons(HyObject): """ HyCons: a cons object. Building a HyCons of something and a HyList really builds a HyList """ __slots__ = ["car", "cdr"] def __new__(cls, car, cdr): if isinstance(cdr, list): # Keep unquotes in the cdr of conses if type(cdr) == HyExpression: if len(cdr) > 0 and type(cdr[0]) == HySymbol: if cdr[0] in ("unquote", "unquote_splice"): return super(HyCons, cls).__new__(cls) return cdr.__class__([wrap_value(car)] + cdr) elif cdr is None: return HyExpression([wrap_value(car)]) else: return super(HyCons, cls).__new__(cls) def __init__(self, car, cdr): self.car = wrap_value(car) self.cdr = wrap_value(cdr) def __getitem__(self, n): if n == 0: return self.car if n == slice(1, None): return self.cdr raise IndexError( "Can only get the car ([0]) or the cdr ([1:]) of a HyCons") def __setitem__(self, n, new): if n == 0: self.car = new return if n == slice(1, None): self.cdr = new return raise IndexError( "Can only set the car ([0]) or the cdr ([1:]) of a HyCons") def __iter__(self): yield self.car try: iterator = (i for i in self.cdr) except TypeError: if self.cdr is not None: yield self.cdr raise TypeError("Iteration on malformed cons") else: for i in iterator: yield i def replace(self, other): if self.car is not None: replace_hy_obj(self.car, other) if self.cdr is not None: replace_hy_obj(self.cdr, other) HyObject.replace(self, other) def __repr__(self): if isinstance(self.cdr, self.__class__): return "(%s %s)" % (repr(self.car), repr(self.cdr)[1:-1]) else: return "(%s . %s)" % (repr(self.car), repr(self.cdr)) def __eq__(self, other): return ( isinstance(other, self.__class__) and self.car == other.car and self.cdr == other.cdr ) hy-0.12.1/hy/models/dict.py000066400000000000000000000031201304171765200154150ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import _wrappers, wrap_value from hy.models.list import HyList class HyDict(HyList): """ HyDict (just a representation of a dict) """ def __repr__(self): return "{%s}" % (" ".join([repr(x) for x in self])) def keys(self): return self[0::2] def values(self): return self[1::2] def items(self): return list(zip(self.keys(), self.values())) _wrappers[dict] = lambda d: HyDict(wrap_value(x) for x in sum(d.items(), ())) hy-0.12.1/hy/models/expression.py000066400000000000000000000026471304171765200167060ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import _wrappers, wrap_value from hy.models.list import HyList class HyExpression(HyList): """ Hy S-Expression. Basically just a list. """ def __repr__(self): return "(%s)" % (" ".join([repr(x) for x in self])) _wrappers[HyExpression] = lambda e: HyExpression(wrap_value(x) for x in e) hy-0.12.1/hy/models/float.py000066400000000000000000000027241304171765200156100ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import HyObject, _wrappers class HyFloat(HyObject, float): """ Internal representation of a Hy Float. May raise a ValueError as if float(foo) was called, given HyFloat(foo). """ def __new__(cls, number, *args, **kwargs): number = float(number) return super(HyFloat, cls).__new__(cls, number) _wrappers[float] = HyFloat hy-0.12.1/hy/models/integer.py000066400000000000000000000043031304171765200161330ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import HyObject, _wrappers from hy._compat import long_type, str_type import sys class HyInteger(HyObject, long_type): """ Internal representation of a Hy Integer. May raise a ValueError as if int(foo) was called, given HyInteger(foo). On python 2.x long will be used instead """ def __new__(cls, number, *args, **kwargs): if isinstance(number, str_type): bases = {"0x": 16, "0o": 8, "0b": 2} for leader, base in bases.items(): if number.startswith(leader): # We've got a string, known leader, set base. number = long_type(number, base=base) break else: # We've got a string, no known leader; base 10. number = long_type(number, base=10) else: # We've got a non-string; convert straight. number = long_type(number) return super(HyInteger, cls).__new__(cls, number) _wrappers[int] = HyInteger if sys.version_info[0] < 3: # do not add long on python3 _wrappers[long_type] = HyInteger hy-0.12.1/hy/models/keyword.py000066400000000000000000000030771304171765200161710ustar00rootroot00000000000000# Copyright (c) 2013 Gergely Nagy # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from __future__ import unicode_literals from hy.models import HyObject from hy._compat import str_type KEYWORD_PREFIX = "\uFDD0" class HyKeyword(HyObject, str_type): """Generic Hy Keyword object. It's either a ``str`` or a ``unicode``, depending on the Python version. """ def __new__(cls, value): if not value.startswith(KEYWORD_PREFIX): value = KEYWORD_PREFIX + value obj = str_type.__new__(cls, value) return obj hy-0.12.1/hy/models/list.py000066400000000000000000000037531304171765200154610ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import HyObject, replace_hy_obj, _wrappers, wrap_value class HyList(HyObject, list): """ Hy List. Basically just a list. """ def replace(self, other): for x in self: replace_hy_obj(x, other) HyObject.replace(self, other) return self def __add__(self, other): return self.__class__(super(HyList, self).__add__(other)) def __getslice__(self, start, end): return self.__class__(super(HyList, self).__getslice__(start, end)) def __getitem__(self, item): ret = super(HyList, self).__getitem__(item) if isinstance(item, slice): return self.__class__(ret) return ret def __repr__(self): return "[%s]" % (" ".join([repr(x) for x in self])) _wrappers[list] = lambda l: HyList(wrap_value(x) for x in l) _wrappers[tuple] = lambda t: HyList(wrap_value(x) for x in t) hy-0.12.1/hy/models/set.py000066400000000000000000000026211304171765200152720ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import _wrappers, wrap_value from hy.models.list import HyList class HySet(HyList): """ Hy set (just a representation of a set) """ def __repr__(self): return "#{%s}" % (" ".join([repr(x) for x in self])) _wrappers[set] = lambda s: HySet(wrap_value(x) for x in s) hy-0.12.1/hy/models/string.py000066400000000000000000000026501304171765200160070ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import HyObject, _wrappers from hy._compat import str_type class HyString(HyObject, str_type): """ Generic Hy String object. Helpful to store string literals from Hy scripts. It's either a ``str`` or a ``unicode``, depending on the Python version. """ pass _wrappers[str_type] = HyString hy-0.12.1/hy/models/symbol.py000066400000000000000000000026521304171765200160100ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models import _wrappers from hy.models.string import HyString class HySymbol(HyString): """ Hy Symbol. Basically a String. """ def __init__(self, string): self += string _wrappers[bool] = lambda x: HySymbol("True") if x else HySymbol("False") _wrappers[type(None)] = lambda foo: HySymbol("None") hy-0.12.1/make.bat000066400000000000000000000037171304171765200136360ustar00rootroot00000000000000@ECHO OFF REM Make batch file for Hy development if "%1" == "" goto help if "%1" == "help" ( :help echo. No default step. Use setup.py echo. echo. Other targets: echo. echo. - docs echo. - full echo. echo. - dev "test & flake" echo. - flake echo. - test echo. - diff echo. - tox echo. - d echo. - r echo. - clean echo. goto :EOF ) if "%1" == "docs" ( :docs cd docs make.bat html cd .. goto :EOF ) if "%1" == "upload" ( :upload python setup.py sdist upload goto :EOF ) if "%1" == "clear" ( :clear cls goto :EOF ) if "%1" == "d" ( :d call :clear call :dev goto :EOF ) if "%1" == "test" ( :test call :venv nosetests -sv goto :EOF ) if "%1" == "venv" ( :venv echo.%VIRTUAL_ENV% | findstr /C:"hy" 1>nul if errorlevel 1 ( echo.You're not in a Hy virtualenv. FOR SHAME ) ELSE ( echo.We're properly in a virtualenv. Going ahead. ) goto :EOF ) if "%1" == "flake" ( :flake echo.flake8 hy tests flake8 hy tests goto :EOF ) if "%1" == "dev" ( :dev call :test call :flake goto :EOF ) if "%1" == "tox" ( :tox call :venv tox -e "py26,py27,py33,py34,flake8" goto :EOF ) if "%1" == "d" ( :d call :clear call :dev goto :EOF ) if "%i" == "diff" ( :diff git diff --color goto :EOF ) if "%1" == "r" ( :r call :d call :tox call :diff goto :EOF ) if "%1" == "full" ( call :docs call :d call :tox goto :EOF ) if "%1" == "clean" ( :clean if EXIST hy\*.pyc cmd /C del /S /Q hy\*.pyc if EXIST tests\*pyc cmd /C del /S /Q tests\*pyc for /r %%R in (__pycache__) do if EXIST %%R (rmdir /S /Q %%R) if EXIST .tox\NUL cmd /C rmdir /S /Q .tox if EXIST dist\NUL cmd /C rmdir /S /Q dist if EXIST hy.egg-info\NUL cmd /C rmdir /S /Q hy.egg-info if EXIST docs\_build\NUL cmd /C rmdir /S /Q docs\_build goto :EOF ) echo.Error: '%1' - unknown target echo. goto :help hy-0.12.1/requirements-dev.txt000066400000000000000000000001501304171765200162550ustar00rootroot00000000000000-r requirements-travis.txt # test tools nose tox # documentation Pygments>=1.6 Sphinx sphinx_rtd_theme hy-0.12.1/requirements-travis.txt000066400000000000000000000000371304171765200170130ustar00rootroot00000000000000# code quality flake8 coverage hy-0.12.1/scripts/000077500000000000000000000000001304171765200137105ustar00rootroot00000000000000hy-0.12.1/scripts/reformat-changelog000077500000000000000000000035721304171765200174110ustar00rootroot00000000000000#!/usr/bin/env hy (import re) (import pdb) (import codecs) (setv *maintainer-line* " -- Alexander Artemenko Thu, 30 Sep 2014 13:06:09 +0400") (defn read-lines-from-file [filename] (let [f (codecs.open filename "r" "utf-8")] (fn [] (let [line (.readline f) ] line)))) (defn get-version-number [line] (let [match (re.search r"Changes from.*(\d+\.\d+\.\d+)$" line)] (if match (let [version (.group match (int 1)) numbered (list (map int (.split version "."))) explicit-mapping {"0.9.12" "0.10.0" "0.8.2" "0.9.0"}] (assoc numbered 2 (+ (get numbered 2) 1)) (.get explicit-mapping version (.join "." (map str numbered))))))) (defn read-version-content [reader] (setv line (reader)) (setv content []) (while (and line (not (get-version-number line))) (.append content (.strip line)) (setv line (reader))) [content line]) (defn read-versions-from-file [filename] (let [reader (read-lines-from-file filename)] (read-versions-rec (reader) reader))) (defn read-versions-rec [line reader] (if line (let [version (get-version-number line) [content next-line] (read-version-content reader)] (+ [{"from" version "content" content}] (read-versions-rec next-line reader))) [])) (defn format-deb-version [version] (setv result [(.format "hy ({}) unstable; urgency=low" (get version "from"))]) (for [line (get version "content")] (.append result (+ " " line))) (.append result *maintainer-line*) (.append result "") (.join "\n" result)) (defmain [&rest args] (let [versions (read-versions-from-file "NEWS")] (for [version versions] (print (.encode (format-deb-version version) "utf-8"))))) hy-0.12.1/scripts/update-coreteam.hy000066400000000000000000000024321304171765200173320ustar00rootroot00000000000000;; You need to install the requests package first (import os.path) (import requests) (setv *api-url* "https://api.github.com/{}") (setv *rst-format* "* `{} <{}>`_") (setv *missing-names* {"khinsen" "Konrad Hinsen"}) ;; We have three concealed members on the hylang organization ;; and GitHub only shows public members if the requester is not ;; an owner of the organization. (setv *concealed-members* [(, "aldeka" "Karen Rustad") (, "tuturto" "Tuukka Turto") (, "cndreisbach" "Clinton N. Dreisbach")]) (defn get-dev-name [login] (setv name (get (.json (requests.get (.format *api-url* (+ "users/" login)))) "name")) (if-not name (.get *missing-names* login) name)) (setv coredevs (requests.get (.format *api-url* "orgs/hylang/members"))) (setv result (set)) (for [dev (.json coredevs)] (result.add (.format *rst-format* (get-dev-name (get dev "login")) (get dev "html_url")))) (for [(, login name) *concealed-members*] (result.add (.format *rst-format* name (+ "https://github.com/" login)))) (setv filename (os.path.abspath (os.path.join os.path.pardir "docs" "coreteam.rst"))) (with [fobj (open filename "w+")] (fobj.write (+ (.join "\n" result) "\n"))) hy-0.12.1/setup.cfg000066400000000000000000000001421304171765200140370ustar00rootroot00000000000000[nosetests] detailed-errors=1 with-coverage=1 cover-package=hy nocapture=1 [wheel] universal = 1 hy-0.12.1/setup.py000077500000000000000000000075601304171765200137460ustar00rootroot00000000000000#!/usr/bin/env python # Copyright (c) 2012, 2013 Paul Tagliamonte # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. import os import re import sys import runpy import subprocess from setuptools import find_packages, setup os.chdir(os.path.split(os.path.abspath(__file__))[0]) PKG = "hy" VERSIONFILE = os.path.join(PKG, "version.py") try: __version__ = (subprocess.check_output (["git", "describe", "--tags", "--dirty"]) .decode('ASCII').strip() .replace('-', '+', 1).replace('-', '.')) with open(VERSIONFILE, "wt") as o: o.write("__version__ = {!r}\n".format(__version__)) except (subprocess.CalledProcessError, OSError): if os.path.exists(VERSIONFILE): __version__ = runpy.run_path(VERSIONFILE)['__version__'] else: __version__ = "unknown" long_description = """Hy is a Python <--> Lisp layer. It helps make things work nicer, and lets Python and the Hy lisp variant play nice together. """ install_requires = ['rply>=0.7.0', 'astor>=0.5', 'clint>=0.4'] 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.1') ver = sys.version_info[0] setup( name=PKG, version=__version__, install_requires=install_requires, entry_points={ 'console_scripts': [ 'hy = hy.cmdline:hy_main', 'hy%d = hy.cmdline:hy_main' % ver, 'hyc = hy.cmdline:hyc_main', 'hyc%d = hy.cmdline:hyc_main' % ver, 'hy2py = hy.cmdline:hy2py_main', 'hy2py%d = hy.cmdline:hy2py_main' % ver, ] }, packages=find_packages(exclude=['tests*']), package_data={ 'hy.contrib': ['*.hy'], 'hy.core': ['*.hy'], 'hy.extra': ['*.hy'], }, author="Paul Tagliamonte", author_email="tag@pault.ag", long_description=long_description, description='Lisp and Python love each other.', license="Expat", url="http://hylang.org/", platforms=['any'], classifiers=[ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: DFSG approved", "License :: OSI Approved :: MIT License", # Really "Expat". Ugh. "Operating System :: OS Independent", "Programming Language :: Lisp", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "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", ] ) hy-0.12.1/tests/000077500000000000000000000000001304171765200133635ustar00rootroot00000000000000hy-0.12.1/tests/__init__.py000066400000000000000000000016661304171765200155050ustar00rootroot00000000000000 import hy # noqa from hy._compat import PY3 from .native_tests.cons import * # noqa from .native_tests.defclass import * # noqa from .native_tests.mathematics import * # noqa from .native_tests.native_macros import * # noqa from .native_tests.quote import * # noqa from .native_tests.language import * # noqa from .native_tests.unless import * # noqa from .native_tests.when import * # noqa from .native_tests.with_decorator import * # noqa from .native_tests.core import * # noqa from .native_tests.reader_macros import * # noqa from .native_tests.shadow import * # noqa from .native_tests.with_test import * # noqa from .native_tests.extra.anaphoric import * # noqa from .native_tests.contrib.loop import * # noqa from .native_tests.contrib.walk import * # noqa from .native_tests.contrib.multi import * # noqa from .native_tests.contrib.sequences import * # noqa if PY3: from .native_tests.py3_only_tests import * # noqa hy-0.12.1/tests/compilers/000077500000000000000000000000001304171765200153605ustar00rootroot00000000000000hy-0.12.1/tests/compilers/__init__.py000066400000000000000000000000001304171765200174570ustar00rootroot00000000000000hy-0.12.1/tests/compilers/native/000077500000000000000000000000001304171765200166465ustar00rootroot00000000000000hy-0.12.1/tests/compilers/native/__init__.hy000066400000000000000000000000001304171765200207350ustar00rootroot00000000000000hy-0.12.1/tests/compilers/native/quoting.hy000066400000000000000000000003471304171765200207020ustar00rootroot00000000000000;;; ;;; (import [hy [HyExpression HySymbol HyString]]) (defn test-basic-quoting [] (assert (= (type (quote (foo bar))) HyExpression)) (assert (= (type (quote foo)) HySymbol)) (assert (= (type (quote "string")) HyString))) hy-0.12.1/tests/compilers/test_ast.py000066400000000000000000000420001304171765200175540ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # Copyright (c) 2013 Julien Danjou # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from __future__ import unicode_literals from hy import HyString from hy.models import HyObject from hy.compiler import hy_compile from hy.errors import HyCompileError, HyTypeError from hy.lex.exceptions import LexException from hy.lex import tokenize from hy._compat import PY3 import ast def _ast_spotcheck(arg, root, secondary): if "." in arg: local, full = arg.split(".", 1) return _ast_spotcheck(full, getattr(root, local), getattr(secondary, local)) assert getattr(root, arg) == getattr(secondary, arg) def can_compile(expr): return hy_compile(tokenize(expr), "__main__") def cant_compile(expr): try: hy_compile(tokenize(expr), "__main__") assert False except HyTypeError as e: # Anything that can't be compiled should raise a user friendly # error, otherwise it's a compiler bug. assert isinstance(e.expression, HyObject) assert e.message return e except HyCompileError as e: # Anything that can't be compiled should raise a user friendly # error, otherwise it's a compiler bug. assert isinstance(e.exception, HyTypeError) assert e.traceback return e def test_ast_bad_type(): "Make sure AST breakage can happen" try: hy_compile("foo", "__main__") assert True is False except HyCompileError: pass def test_ast_bad_if(): "Make sure AST can't compile invalid if*" cant_compile("(if*)") cant_compile("(if* foobar)") cant_compile("(if* 1 2 3 4 5)") def test_ast_valid_if(): "Make sure AST can compile valid if*" can_compile("(if* foo bar)") def test_ast_valid_unary_op(): "Make sure AST can compile valid unary operator" can_compile("(not 2)") can_compile("(~ 1)") def test_ast_invalid_unary_op(): "Make sure AST can't compile invalid unary operator" cant_compile("(not 2 3 4)") cant_compile("(not)") cant_compile("(not 2 3 4)") cant_compile("(~ 2 2 3 4)") cant_compile("(~)") def test_ast_bad_while(): "Make sure AST can't compile invalid while" cant_compile("(while)") cant_compile("(while (True))") def test_ast_good_do(): "Make sure AST can compile valid do" can_compile("(do)") can_compile("(do 1)") def test_ast_good_raise(): "Make sure AST can compile valid raise" can_compile("(raise)") can_compile("(raise Exception)") can_compile("(raise e)") if PY3: def test_ast_raise_from(): can_compile("(raise Exception :from NameError)") def test_ast_bad_raise(): "Make sure AST can't compile invalid raise" cant_compile("(raise Exception Exception)") def test_ast_good_try(): "Make sure AST can compile valid try" can_compile("(try)") can_compile("(try 1)") can_compile("(try 1 (except) (else 1))") can_compile("(try 1 (else 1) (except))") can_compile("(try 1 (finally 1) (except))") can_compile("(try 1 (finally 1))") can_compile("(try 1 (except) (finally 1))") can_compile("(try 1 (except) (finally 1) (else 1))") can_compile("(try 1 (except) (else 1) (finally 1))") def test_ast_bad_try(): "Make sure AST can't compile invalid try" cant_compile("(try 1 bla)") cant_compile("(try 1 bla bla)") cant_compile("(try (do) (else 1) (else 2))") cant_compile("(try 1 (else 1))") def test_ast_good_except(): "Make sure AST can compile valid except" can_compile("(try 1 (except))") can_compile("(try 1 (except []))") can_compile("(try 1 (except [Foobar]))") can_compile("(try 1 (except [[]]))") can_compile("(try 1 (except [x FooBar]))") can_compile("(try 1 (except [x [FooBar BarFoo]]))") can_compile("(try 1 (except [x [FooBar BarFoo]]))") def test_ast_bad_except(): "Make sure AST can't compile invalid except" cant_compile("(except 1)") cant_compile("(try 1 (except 1))") cant_compile("(try 1 (except [1 3]))") cant_compile("(try 1 (except [x [FooBar] BarBar]))") def test_ast_good_assert(): """Make sure AST can compile valid asserts. Asserts may or may not include a label.""" can_compile("(assert 1)") can_compile("(assert 1 \"Assert label\")") can_compile("(assert 1 (+ \"spam \" \"eggs\"))") can_compile("(assert 1 12345)") can_compile("(assert 1 None)") can_compile("(assert 1 (+ 2 \"incoming eggsception\"))") def test_ast_bad_assert(): "Make sure AST can't compile invalid assert" cant_compile("(assert)") cant_compile("(assert 1 2 3)") cant_compile("(assert 1 [1 2] 3)") def test_ast_good_global(): "Make sure AST can compile valid global" can_compile("(global a)") can_compile("(global foo bar)") def test_ast_bad_global(): "Make sure AST can't compile invalid global" cant_compile("(global)") cant_compile("(global (foo))") if PY3: def test_ast_good_nonlocal(): "Make sure AST can compile valid nonlocal" can_compile("(nonlocal a)") can_compile("(nonlocal foo bar)") def test_ast_bad_nonlocal(): "Make sure AST can't compile invalid nonlocal" cant_compile("(nonlocal)") cant_compile("(nonlocal (foo))") def test_ast_good_defclass(): "Make sure AST can compile valid defclass" can_compile("(defclass a)") can_compile("(defclass a [])") def test_ast_bad_defclass(): "Make sure AST can't compile invalid defclass" cant_compile("(defclass)") cant_compile("(defclass a None)") cant_compile("(defclass a None None)") def test_ast_good_lambda(): "Make sure AST can compile valid lambda" can_compile("(lambda [])") can_compile("(lambda [] 1)") def test_ast_bad_lambda(): "Make sure AST can't compile invalid lambda" cant_compile("(lambda)") def test_ast_good_yield(): "Make sure AST can compile valid yield" can_compile("(yield 1)") def test_ast_bad_yield(): "Make sure AST can't compile invalid yield" cant_compile("(yield 1 2)") def test_ast_good_import_from(): "Make sure AST can compile valid selective import" can_compile("(import [x [y]])") def test_ast_require(): "Make sure AST respects (require) syntax" can_compile("(require tests.resources.tlib)") can_compile("(require [tests.resources.tlib [qplah parald]])") can_compile("(require [tests.resources.tlib [*]])") can_compile("(require [tests.resources.tlib :as foobar])") can_compile("(require [tests.resources.tlib [qplah :as quiz]])") can_compile("(require [tests.resources.tlib [qplah :as quiz parald]])") cant_compile("(require [tests.resources.tlib])") cant_compile("(require [tests.resources.tlib [* qplah]])") cant_compile("(require [tests.resources.tlib [qplah *]])") cant_compile("(require [tests.resources.tlib [* *]])") def test_ast_good_get(): "Make sure AST can compile valid get" can_compile("(get x y)") def test_ast_bad_get(): "Make sure AST can't compile invalid get" cant_compile("(get)") cant_compile("(get 1)") def test_ast_good_cut(): "Make sure AST can compile valid cut" can_compile("(cut x)") can_compile("(cut x y)") can_compile("(cut x y z)") can_compile("(cut x y z t)") def test_ast_bad_cut(): "Make sure AST can't compile invalid cut" cant_compile("(cut)") cant_compile("(cut 1 2 3 4 5)") def test_ast_good_take(): "Make sure AST can compile valid 'take'" can_compile("(take 1 [2 3])") def test_ast_good_drop(): "Make sure AST can compile valid 'drop'" can_compile("(drop 1 [2 3])") def test_ast_good_assoc(): "Make sure AST can compile valid assoc" can_compile("(assoc x y z)") def test_ast_bad_assoc(): "Make sure AST can't compile invalid assoc" cant_compile("(assoc)") cant_compile("(assoc 1)") cant_compile("(assoc 1 2)") cant_compile("(assoc 1 2 3 4)") def test_ast_bad_with(): "Make sure AST can't compile invalid with" cant_compile("(with*)") cant_compile("(with* [])") cant_compile("(with* [] (pass))") def test_ast_valid_while(): "Make sure AST can't compile invalid while" can_compile("(while foo bar)") def test_ast_valid_for(): "Make sure AST can compile valid for" can_compile("(for [a 2] (print a))") def test_ast_invalid_for(): "Make sure AST can't compile invalid for" cant_compile("(for* [a 1] (else 1 2))") def test_ast_valid_let(): "Make sure AST can compile valid let" can_compile("(let [a b])") can_compile("(let [a 1])") can_compile("(let [a 1 b None])") def test_ast_invalid_let(): "Make sure AST can't compile invalid let" cant_compile("(let 1)") cant_compile("(let [1])") cant_compile("(let [a 1 2])") cant_compile("(let [a])") cant_compile("(let [1])") def test_ast_expression_basics(): """ Ensure basic AST expression conversion works. """ code = can_compile("(foo bar)").body[0] tree = ast.Expr(value=ast.Call( func=ast.Name( id="foo", ctx=ast.Load(), ), args=[ ast.Name(id="bar", ctx=ast.Load()) ], keywords=[], starargs=None, kwargs=None, )) _ast_spotcheck("value.func.id", code, tree) def test_ast_anon_fns_basics(): """ Ensure anon fns work. """ code = can_compile("(fn (x) (* x x))").body[0] assert type(code) == ast.FunctionDef code = can_compile("(fn (x))").body[0] cant_compile("(fn)") def test_ast_non_decoratable(): """ Ensure decorating garbage breaks """ cant_compile("(with-decorator (foo) (* x x))") def test_ast_lambda_lists(): """Ensure the compiler chokes on invalid 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(): code = can_compile("(print \"foo\")").body[0] assert type(code.value) == ast.Call def test_ast_tuple(): """ Ensure tuples work. """ code = can_compile("(, 1 2 3)").body[0].value assert type(code) == ast.Tuple def test_argument_destructuring(): """ Ensure argument destructuring compilers. """ can_compile("(fn [[a b]] (print a b))") cant_compile("(fn [[]] 0)") def test_lambda_list_keywords_rest(): """ Ensure we can compile functions with lambda list keywords.""" can_compile("(fn (x &rest xs) (print xs))") cant_compile("(fn (x &rest xs &rest ys) (print xs))") can_compile("(fn (&optional a &rest xs) (print xs))") 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(): """ Ensure we can compile functions with &kwargs.""" can_compile("(fn (x &kwargs kw) (list x kw))") cant_compile("(fn (x &kwargs xs &kwargs ys) (list x xs ys))") can_compile("(fn (&optional x &kwargs kw) (list x kw))") def test_lambda_list_keywords_kwonly(): """Ensure we can compile functions with &kwonly if we're on Python 3, or fail with an informative message on Python 2.""" kwonly_demo = "(fn [&kwonly a [b 2]] (print a b))" if PY3: code = can_compile(kwonly_demo) for i, kwonlyarg_name in enumerate(('a', 'b')): assert kwonlyarg_name == code.body[0].args.kwonlyargs[i].arg assert code.body[0].args.kw_defaults[0] is None assert code.body[0].args.kw_defaults[1].n == 2 else: exception = cant_compile(kwonly_demo) assert isinstance(exception, HyTypeError) message, = exception.args assert message == ("keyword-only arguments are only " "available under Python 3") def test_lambda_list_keywords_mixed(): """ Ensure we can mix them up.""" can_compile("(fn (x &rest xs &kwargs kw) (list x xs kw))") cant_compile("(fn (x &rest xs &fasfkey {bar \"baz\"}))") if PY3: can_compile("(fn [x &rest xs &kwargs kwxs &kwonly kwoxs]" " (list x xs kwxs kwoxs))") def test_missing_keyword_argument_value(): """Ensure the compiler chokes on missing keyword argument values.""" try: can_compile("((fn [x] x) :x)") except HyTypeError as e: assert(e.message == "Keyword argument :x needs a value.") else: assert(False) def test_ast_unicode_strings(): """Ensure we handle unicode strings correctly""" def _compile_string(s): hy_s = HyString(s) hy_s.start_line = hy_s.end_line = 0 hy_s.start_column = hy_s.end_column = 0 code = hy_compile([hy_s], "__main__") # code == ast.Module(body=[ast.Expr(value=ast.Str(s=xxx))]) return code.body[0].value.s assert _compile_string("test") == "test" assert _compile_string("\u03b1\u03b2") == "\u03b1\u03b2" assert _compile_string("\xc3\xa9") == "\xc3\xa9" def test_compile_error(): """Ensure we get compile error in tricky cases""" try: can_compile("(fn [] (in [1 2 3]))") except HyTypeError as e: assert(e.message == "`in' needs at least 2 arguments, got 1.") else: assert(False) def test_for_compile_error(): """Ensure we get compile error in tricky 'for' cases""" try: can_compile("(fn [] (for)") except LexException as e: assert(e.message == "Premature end of input") else: assert(False) try: can_compile("(fn [] (for)))") except LexException as e: assert(e.message == "Ran into a RPAREN where it wasn't expected.") else: assert(False) try: can_compile("(fn [] (for [x] x))") except HyTypeError as e: assert(e.message == "`for' requires an even number of args.") else: assert(False) try: can_compile("(fn [] (for [x xx]))") except HyTypeError as e: assert(e.message == "`for' requires a body to evaluate") else: assert(False) try: can_compile("(fn [] (for [x xx] (else 1)))") except HyTypeError as e: assert(e.message == "`for' requires a body to evaluate") else: assert(False) def test_attribute_access(): """Ensure attribute access compiles correctly""" can_compile("(. foo bar baz)") can_compile("(. foo [bar] baz)") can_compile("(. foo bar [baz] [0] quux [frob])") can_compile("(. foo bar [(+ 1 2 3 4)] quux [frob])") cant_compile("(. foo bar :baz [0] quux [frob])") cant_compile("(. foo bar baz (0) quux [frob])") cant_compile("(. foo bar baz [0] quux {frob})") def test_attribute_empty(): """Ensure using dot notation with a non-expression is an error""" cant_compile(".") cant_compile("foo.") cant_compile(".foo") cant_compile('"bar".foo') cant_compile('[2].foo') def test_cons_correct(): """Ensure cons gets compiled correctly""" can_compile("(cons a b)") def test_invalid_list_comprehension(): """Ensure that invalid list comprehensions do not break the compiler""" cant_compile("(genexpr x [])") cant_compile("(genexpr [x [1 2 3 4]] x)") cant_compile("(list-comp None [])") cant_compile("(list-comp [x [1 2 3]] x)") def test_bad_setv(): """Ensure setv handles error cases""" cant_compile("(setv if* 1)") cant_compile("(setv (a b) [1 2])") def test_defn(): """Ensure that defn works correctly in various corner cases""" cant_compile("(defn if* [] 1)") cant_compile("(defn \"hy\" [] 1)") cant_compile("(defn :hy [] 1)") can_compile("(defn &hy [] 1)") def test_setv_builtins(): """Ensure that assigning to a builtin fails, unless in a class""" cant_compile("(setv None 42)") cant_compile("(defn get [&rest args] 42)") can_compile("(defclass A [] (defn get [self] 42))") can_compile(""" (defclass A [] (defn get [self] 42) (defclass B [] (defn get [self] 42)) (defn if* [self] 0)) """) hy-0.12.1/tests/compilers/test_compiler.py000066400000000000000000000126131304171765200206060ustar00rootroot00000000000000# Copyright (c) 2013 Julien Danjou # Copyright (c) 2013 Nicolas Dandrimont # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. import ast import sys 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 else: import unittest class CompilerTest(unittest.TestCase): def test_builds_with_dash(self): self.assert_(callable(compiler.builds("foobar"))) self.assert_(callable(compiler.builds("foo_bar"))) self.assert_(callable(compiler.builds("-"))) self.assertRaisesRegexp(TypeError, r"\*post\* translated strings", compiler.builds, "foobar-with-dash-") class HyASTCompilerTest(unittest.TestCase): @staticmethod def _make_expression(*args): h = HyExpression(args) h.start_line = 1 h.end_line = 1 h.start_column = 1 h.end_column = 1 return h.replace(h) def setUp(self): self.c = compiler.HyASTCompiler('test') def test_fn_compiler_empty_function(self): ret = self.c.compile_function_def( self._make_expression(HySymbol("fn"), HyList())) self.assertEqual(ret.imports, {}) self.assertEqual(len(ret.stmts), 1) stmt = ret.stmts[0] self.assertIsInstance(stmt, ast.FunctionDef) self.assertIsInstance(stmt.args, ast.arguments) self.assertEqual(stmt.args.vararg, None) self.assertEqual(stmt.args.kwarg, None) self.assertEqual(stmt.args.defaults, []) self.assertEqual(stmt.decorator_list, []) self.assertEqual(len(stmt.body), 1) self.assertIsInstance(stmt.body[0], ast.Pass) self.assertIsInstance(ret.expr, ast.Name) def test_compiler_bare_names(self): """ Check that the compiler doesn't drop bare names from code branches """ ret = self.c.compile(self._make_expression(HySymbol("do"), HySymbol("a"), HySymbol("b"), HySymbol("c"))) # We expect two statements and a final expr. self.assertEqual(len(ret.stmts), 2) stmt = ret.stmts[0] self.assertIsInstance(stmt, ast.Expr) self.assertIsInstance(stmt.value, ast.Name) self.assertEqual(stmt.value.id, "a") stmt = ret.stmts[1] self.assertIsInstance(stmt, ast.Expr) self.assertIsInstance(stmt.value, ast.Name) self.assertEqual(stmt.value.id, "b") 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) hy-0.12.1/tests/compilers/test_quoting.py000066400000000000000000000000461304171765200204570ustar00rootroot00000000000000from .native.quoting import * # NOQA hy-0.12.1/tests/importer/000077500000000000000000000000001304171765200152245ustar00rootroot00000000000000hy-0.12.1/tests/importer/__init__.py000066400000000000000000000000001304171765200173230ustar00rootroot00000000000000hy-0.12.1/tests/importer/test_importer.py000066400000000000000000000022411304171765200204750ustar00rootroot00000000000000from hy.importer import import_file_to_module, import_buffer_to_ast, MetaLoader from hy.errors import HyTypeError import os import ast def test_basics(): "Make sure the basics of the importer work" import_file_to_module("basic", "tests/resources/importer/basic.hy") def test_stringer(): "Make sure the basics of the importer work" _ast = import_buffer_to_ast("(defn square [x] (* x x))", '') assert type(_ast.body[0]) == ast.FunctionDef def test_imports(): path = os.getcwd() + "/tests/resources/importer/a.hy" testLoader = MetaLoader(path) def _import_test(): try: return testLoader.load_module("tests.resources.importer.a") except: return "Error" assert _import_test() == "Error" assert _import_test() is not None def test_import_error_reporting(): "Make sure that (import) reports errors correctly." def _import_error_test(): try: import_buffer_to_ast("(import \"sys\")", '') except HyTypeError: return "Error reported" assert _import_error_test() == "Error reported" assert _import_error_test() is not None hy-0.12.1/tests/importer/test_pyc.py000066400000000000000000000006711304171765200174340ustar00rootroot00000000000000import os import imp import tempfile from hy.importer import write_hy_as_pyc def test_pyc(): """Test pyc compilation.""" f = tempfile.NamedTemporaryFile(suffix='.hy', delete=False) f.write(b'(defn pyctest [s] s)') f.close() write_hy_as_pyc(f.name) os.unlink(f.name) cfile = "%s.pyc" % f.name[:-len(".hy")] mod = imp.load_compiled('pyc', cfile) os.unlink(cfile) assert mod.pyctest('Foo') == 'Foo' hy-0.12.1/tests/lex/000077500000000000000000000000001304171765200141535ustar00rootroot00000000000000hy-0.12.1/tests/lex/__init__.py000066400000000000000000000000001304171765200162520ustar00rootroot00000000000000hy-0.12.1/tests/lex/test_lex.py000066400000000000000000000301571304171765200163620ustar00rootroot00000000000000# Copyright (c) 2013 Paul Tagliamonte # Copyright (c) 2014 Nicolas Dandrimont # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models.expression import HyExpression from hy.models.integer import HyInteger from hy.models.float import HyFloat from hy.models.complex import HyComplex from hy.models.symbol import HySymbol from hy.models.string import HyString from hy.models.dict import HyDict from hy.models.list import HyList from hy.models.set import HySet from hy.models.cons import HyCons from hy.lex import LexException, PrematureEndOfInput, tokenize def test_lex_exception(): """ Ensure tokenize throws a fit on a partial input """ try: tokenize("(foo") assert True is False except PrematureEndOfInput: pass try: tokenize("{foo bar") assert True is False except PrematureEndOfInput: pass try: tokenize("(defn foo [bar]") assert True is False except PrematureEndOfInput: pass try: tokenize("(foo \"bar") assert True is False except PrematureEndOfInput: pass def test_unbalanced_exception(): """Ensure the tokenization fails on unbalanced expressions""" try: tokenize("(bar))") assert True is False except LexException: pass try: tokenize("(baz [quux]])") assert True is False except LexException: pass def test_lex_expression_symbols(): """ Make sure that expressions produce symbols """ objs = tokenize("(foo bar)") assert objs == [HyExpression([HySymbol("foo"), HySymbol("bar")])] def test_lex_expression_strings(): """ Test that expressions can produce strings """ objs = tokenize("(foo \"bar\")") assert objs == [HyExpression([HySymbol("foo"), HyString("bar")])] def test_lex_expression_integer(): """ Make sure expressions can produce integers """ objs = tokenize("(foo 2)") assert objs == [HyExpression([HySymbol("foo"), HyInteger(2)])] def test_lex_symbols(): """ Make sure that symbols are valid expressions""" objs = tokenize("foo ") assert objs == [HySymbol("foo")] def test_lex_strings(): """ Make sure that strings are valid expressions""" objs = tokenize('"foo"') assert objs == [HyString("foo")] # Make sure backslash-escaped newlines work (see issue #831) objs = tokenize(r""" "a\ bc" """) assert objs == [HyString("abc")] def test_lex_integers(): """ Make sure that integers are valid expressions""" objs = tokenize("42 ") assert objs == [HyInteger(42)] def test_lex_fractions(): """ Make sure that fractions are valid expressions""" objs = tokenize("1/2") assert objs == [HyExpression([HySymbol("fraction"), HyInteger(1), HyInteger(2)])] def test_lex_expression_float(): """ Make sure expressions can produce floats """ objs = tokenize("(foo 2.)") assert objs == [HyExpression([HySymbol("foo"), HyFloat(2.)])] objs = tokenize("(foo -0.5)") assert objs == [HyExpression([HySymbol("foo"), HyFloat(-0.5)])] objs = tokenize("(foo 1.e7)") assert objs == [HyExpression([HySymbol("foo"), HyFloat(1.e7)])] def test_lex_expression_complex(): """ Make sure expressions can produce complex """ objs = tokenize("(foo 2.j)") assert objs == [HyExpression([HySymbol("foo"), HyComplex(2.j)])] objs = tokenize("(foo -0.5j)") assert objs == [HyExpression([HySymbol("foo"), HyComplex(-0.5j)])] objs = tokenize("(foo 1.e7j)") assert objs == [HyExpression([HySymbol("foo"), HyComplex(1.e7j)])] objs = tokenize("(foo j)") assert objs == [HyExpression([HySymbol("foo"), HySymbol("j")])] def test_lex_line_counting(): """ Make sure we can count lines / columns """ entry = tokenize("(foo (one two))")[0] assert entry.start_line == 1 assert entry.start_column == 1 assert entry.end_line == 1 assert entry.end_column == 15 entry = entry[1] assert entry.start_line == 1 assert entry.start_column == 6 assert entry.end_line == 1 assert entry.end_column == 14 def test_lex_line_counting_multi(): """ Make sure we can do multi-line tokenization """ entries = tokenize(""" (foo (one two)) (foo bar) """) entry = entries[0] assert entry.start_line == 2 assert entry.start_column == 1 assert entry.end_line == 2 assert entry.end_column == 15 entry = entries[1] assert entry.start_line == 3 assert entry.start_column == 1 assert entry.end_line == 3 assert entry.end_column == 9 def test_lex_line_counting_multi_inner(): """ Make sure we can do multi-line tokenization (inner) """ entry = tokenize("""(foo bar)""")[0] inner = entry[0] assert inner.start_line == 1 assert inner.start_column == 2 inner = entry[1] assert inner.start_line == 2 assert inner.start_column == 5 def test_dicts(): """ Ensure that we can tokenize a dict. """ objs = tokenize("{foo bar bar baz}") assert objs == [HyDict(["foo", "bar", "bar", "baz"])] objs = tokenize("(bar {foo bar bar baz})") assert objs == [HyExpression([HySymbol("bar"), HyDict(["foo", "bar", "bar", "baz"])])] objs = tokenize("{(foo bar) (baz quux)}") assert objs == [HyDict([ HyExpression([HySymbol("foo"), HySymbol("bar")]), HyExpression([HySymbol("baz"), HySymbol("quux")]) ])] def test_sets(): """ Ensure that we can tokenize a set. """ objs = tokenize("#{1 2}") assert objs == [HySet([HyInteger(1), HyInteger(2)])] objs = tokenize("(bar #{foo bar baz})") assert objs == [HyExpression([HySymbol("bar"), HySet(["foo", "bar", "baz"])])] objs = tokenize("#{(foo bar) (baz quux)}") assert objs == [HySet([ HyExpression([HySymbol("foo"), HySymbol("bar")]), HyExpression([HySymbol("baz"), HySymbol("quux")]) ])] # Duplicate items in a literal set should be okay (and should # be preserved). objs = tokenize("#{1 2 1 1 2 1}") assert objs == [HySet([HyInteger(n) for n in [1, 2, 1, 1, 2, 1]])] assert len(objs[0]) == 6 # https://github.com/hylang/hy/issues/1120 objs = tokenize("#{a 1}") assert objs == [HySet([HySymbol("a"), HyInteger(1)])] def test_nospace(): """ Ensure we can tokenize without spaces if we have to """ entry = tokenize("(foo(one two))")[0] assert entry.start_line == 1 assert entry.start_column == 1 assert entry.end_line == 1 assert entry.end_column == 14 entry = entry[1] assert entry.start_line == 1 assert entry.start_column == 5 assert entry.end_line == 1 assert entry.end_column == 13 def test_escapes(): """ Ensure we can escape things """ entry = tokenize("(foo \"foo\\n\")")[0] assert entry[1] == "foo\n" entry = tokenize("(foo \"foo\\s\")")[0] assert entry[1] == "foo\\s" def test_unicode_escapes(): """Ensure unicode escapes are handled correctly""" s = r'"a\xac\u1234\u20ac\U00008000"' assert len(s) == 29 entry = tokenize(s)[0] assert len(entry) == 5 assert [ord(x) for x in entry] == [97, 172, 4660, 8364, 32768] def test_hashbang(): """ Ensure we can escape things """ entry = tokenize("#!this is a comment\n") assert entry == [] def test_complex(): """Ensure we tokenize complex numbers properly""" # This is a regression test for #143 entry = tokenize("(1j)")[0][0] assert entry == HyComplex("1.0j") entry = tokenize("(j)")[0][0] assert entry == HySymbol("j") def test_reader_macro(): """Ensure reader macros are handles properly""" entry = tokenize("#^()") assert entry[0][0] == HySymbol("dispatch_reader_macro") assert entry[0][1] == HyString("^") assert len(entry[0]) == 3 def test_lex_comment_382(): """Ensure that we can tokenize sources with a comment at the end""" entry = tokenize("foo ;bar\n;baz") assert entry == [HySymbol("foo")] def test_lex_mangling_star(): """Ensure that mangling starred identifiers works according to plan""" entry = tokenize("*foo*") assert entry == [HySymbol("FOO")] entry = tokenize("*") assert entry == [HySymbol("*")] entry = tokenize("*foo") assert entry == [HySymbol("*foo")] def test_lex_mangling_hyphen(): """Ensure that hyphens get translated to underscores during mangling""" entry = tokenize("foo-bar") assert entry == [HySymbol("foo_bar")] entry = tokenize("-") assert entry == [HySymbol("-")] def test_lex_mangling_qmark(): """Ensure that identifiers ending with a question mark get mangled ok""" entry = tokenize("foo?") assert entry == [HySymbol("is_foo")] entry = tokenize("?") assert entry == [HySymbol("?")] entry = tokenize("im?foo") assert entry == [HySymbol("im?foo")] entry = tokenize(".foo?") assert entry == [HySymbol(".is_foo")] entry = tokenize("foo.bar?") assert entry == [HySymbol("foo.is_bar")] entry = tokenize("foo?.bar") assert entry == [HySymbol("is_foo.bar")] entry = tokenize(".foo?.bar.baz?") assert entry == [HySymbol(".is_foo.bar.is_baz")] def test_lex_mangling_bang(): """Ensure that identifiers ending with a bang get mangled ok""" entry = tokenize("foo!") assert entry == [HySymbol("foo_bang")] entry = tokenize("!") assert entry == [HySymbol("!")] entry = tokenize("im!foo") assert entry == [HySymbol("im!foo")] entry = tokenize(".foo!") assert entry == [HySymbol(".foo_bang")] entry = tokenize("foo.bar!") assert entry == [HySymbol("foo.bar_bang")] entry = tokenize("foo!.bar") assert entry == [HySymbol("foo_bang.bar")] entry = tokenize(".foo!.bar.baz!") assert entry == [HySymbol(".foo_bang.bar.baz_bang")] def test_unmangle(): import sys f = sys.modules["hy.lex.parser"].hy_symbol_unmangle assert f("FOO") == "*foo*" assert f("<") == "<" assert f("FOOa") == "FOOa" assert f("foo_bar") == "foo-bar" assert f("_") == "_" assert f("is_foo") == "foo?" assert f("is_") == "is-" assert f("foo_bang") == "foo!" assert f("_bang") == "-bang" def test_simple_cons(): """Check that cons gets tokenized correctly""" entry = tokenize("(a . b)")[0] assert entry == HyCons(HySymbol("a"), HySymbol("b")) def test_dotted_list(): """Check that dotted lists get tokenized correctly""" entry = tokenize("(a b c . (d . e))")[0] assert entry == HyCons(HySymbol("a"), HyCons(HySymbol("b"), HyCons(HySymbol("c"), HyCons(HySymbol("d"), HySymbol("e"))))) def test_cons_list(): """Check that cons of something and a list gets tokenized as a list""" entry = tokenize("(a . [])")[0] assert entry == HyList([HySymbol("a")]) assert type(entry) == HyList entry = tokenize("(a . ())")[0] assert entry == HyExpression([HySymbol("a")]) assert type(entry) == HyExpression entry = tokenize("(a b . {})")[0] assert entry == HyDict([HySymbol("a"), HySymbol("b")]) assert type(entry) == HyDict hy-0.12.1/tests/macros/000077500000000000000000000000001304171765200146475ustar00rootroot00000000000000hy-0.12.1/tests/macros/__init__.py000066400000000000000000000000001304171765200167460ustar00rootroot00000000000000hy-0.12.1/tests/macros/test_macro_processor.py000066400000000000000000000030521304171765200214600ustar00rootroot00000000000000 from hy.macros import macro, macroexpand from hy.lex import tokenize from hy.models.string import HyString from hy.models.list import HyList from hy.models.symbol import HySymbol from hy.models.expression import HyExpression from hy.errors import HyMacroExpansionError from hy.compiler import HyASTCompiler @macro("test") def tmac(*tree): """ Turn an expression into a list """ return HyList(tree) def test_preprocessor_simple(): """ Test basic macro expansion """ 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], HyASTCompiler(__name__)) assert type(obj) == HyList assert type(obj[0]) == HyExpression assert obj[0] == HyExpression([HySymbol("test"), HyString("one"), HyString("two")]) obj = HyList([HyString("one"), HyString("two")]) obj = tokenize('(shill ["one" "two"])')[0][1] assert obj == macroexpand(obj, HyASTCompiler("")) def test_preprocessor_exceptions(): """ Test that macro expansion raises appropriate exceptions""" try: macroexpand(tokenize('(defn)')[0], HyASTCompiler(__name__)) assert False except HyMacroExpansionError as e: assert "_hy_anon_fn_" not in str(e) assert "TypeError" not in str(e) hy-0.12.1/tests/macros/test_reader_macros.py000066400000000000000000000006401304171765200210660ustar00rootroot00000000000000from hy.macros import macroexpand from hy.compiler import HyTypeError, HyASTCompiler from hy.lex import tokenize def test_reader_macro_error(): """Check if we get correct error with wrong dispatch character""" try: macroexpand(tokenize("(dispatch_reader_macro '- '())")[0], HyASTCompiler(__name__)) except HyTypeError as e: assert "with the character `-`" in str(e) hy-0.12.1/tests/models/000077500000000000000000000000001304171765200146465ustar00rootroot00000000000000hy-0.12.1/tests/models/__init__.py000066400000000000000000000000001304171765200167450ustar00rootroot00000000000000hy-0.12.1/tests/models/test_cons.py000066400000000000000000000034771304171765200172340ustar00rootroot00000000000000# Copyright (c) 2013 Nicolas Dandrimont # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. from hy.models.cons import HyCons def test_cons_slicing(): """Check that cons slicing works as expected""" cons = HyCons("car", "cdr") assert cons[0] == "car" assert cons[1:] == "cdr" try: cons[:] assert True is False except IndexError: pass try: cons[1] assert True is False except IndexError: pass def test_cons_replacing(): """Check that assigning to a cons works as expected""" cons = HyCons("foo", "bar") cons[0] = "car" assert cons == HyCons("car", "bar") cons[1:] = "cdr" assert cons == HyCons("car", "cdr") try: cons[:] = "foo" assert True is False except IndexError: pass hy-0.12.1/tests/models/test_dict.py000066400000000000000000000004511304171765200172020ustar00rootroot00000000000000from hy.models.dict import HyDict hydict = HyDict(["a", 1, "b", 2, "c", 3]) def test_dict_items(): assert hydict.items() == [("a", 1), ("b", 2), ("c", 3)] def test_dict_keys(): assert hydict.keys() == ["a", "b", "c"] def test_dict_values(): assert hydict.values() == [1, 2, 3] hy-0.12.1/tests/models/test_list.py000066400000000000000000000010101304171765200172220ustar00rootroot00000000000000from hy.models.list import HyList def test_list_add(): """Check that adding two HyLists generates a HyList""" a = HyList([1, 2, 3]) b = HyList([3, 4, 5]) c = a + b assert c == [1, 2, 3, 3, 4, 5] assert c.__class__ == HyList def test_list_slice(): """Check that slicing a HyList produces a HyList""" a = HyList([1, 2, 3, 4]) sl1 = a[1:] sl5 = a[5:] assert type(sl1) == HyList assert sl1 == HyList([2, 3, 4]) assert type(sl5) == HyList assert sl5 == HyList([]) hy-0.12.1/tests/models/test_replace_hy_obj.py000066400000000000000000000014151304171765200212250ustar00rootroot00000000000000from hy._compat import long_type, str_type from hy.models.string import HyString from hy.models.integer import HyInteger from hy.models.list import HyList from hy.models import replace_hy_obj def test_replace_long_type(): """ Test replacing integers.""" replaced = replace_hy_obj(long_type(0), HyInteger(13)) assert replaced == HyInteger(0) def test_replace_string_type(): """Test replacing python string""" replaced = replace_hy_obj(str_type("foo"), HyString("bar")) assert replaced == HyString("foo") def test_replace_tuple(): """ Test replacing tuples.""" replaced = replace_hy_obj((long_type(0), ), HyInteger(13)) assert type(replaced) == HyList assert type(replaced[0]) == HyInteger assert replaced == HyList([HyInteger(0)]) hy-0.12.1/tests/models/test_set.py000066400000000000000000000001611304171765200170500ustar00rootroot00000000000000from hy.models.set import HySet hyset = HySet([3, 1, 2, 2]) def test_set(): assert hyset == [3, 1, 2, 2] hy-0.12.1/tests/models/test_wrap_value.py000066400000000000000000000015231304171765200204250ustar00rootroot00000000000000from hy._compat import long_type from hy.models.integer import HyInteger from hy.models.list import HyList from hy.models.expression import HyExpression from hy.models import wrap_value def test_wrap_long_type(): """ Test conversion of integers.""" wrapped = wrap_value(long_type(0)) assert type(wrapped) == HyInteger def test_wrap_tuple(): """ Test conversion of tuples.""" wrapped = wrap_value((HyInteger(0),)) assert type(wrapped) == HyList assert type(wrapped[0]) == HyInteger assert wrapped == HyList([HyInteger(0)]) def test_wrap_nested_expr(): """ Test conversion of HyExpressions with embedded non-HyObjects.""" wrapped = wrap_value(HyExpression([long_type(0)])) assert type(wrapped) == HyExpression assert type(wrapped[0]) == HyInteger assert wrapped == HyExpression([HyInteger(0)]) hy-0.12.1/tests/native_tests/000077500000000000000000000000001304171765200160735ustar00rootroot00000000000000hy-0.12.1/tests/native_tests/__init__.hy000066400000000000000000000000001304171765200201620ustar00rootroot00000000000000hy-0.12.1/tests/native_tests/cons.hy000066400000000000000000000034211304171765200173770ustar00rootroot00000000000000(defn test-cons-mutability [] "Test the mutability of conses" (setv tree (cons (cons 1 2) (cons 2 3))) (setv (car tree) "foo") (assert (= tree (cons "foo" (cons 2 3)))) (setv (cdr tree) "bar") (assert (= tree (cons "foo" "bar")))) (defn test-cons-quoting [] "Test quoting of conses" (assert (= (cons 1 2) (quote (1 . 2)))) (assert (= (quote foo) (car (quote (foo . bar))))) (assert (= (quote bar) (cdr (quote (foo . bar)))))) (defn test-cons-behavior [] "NATIVE: test the behavior of cons is consistent" (defn t= [a b] (and (= a b) (= (type a) (type b)))) (assert (t= (cons 1 2) '(1 . 2))) (assert (t= (cons 1 None) '(1))) (assert (t= (cons None 2) '(None . 2))) (assert (t= (cons 1 []) [1])) (setv tree (cons (cons 1 2) (cons 2 3))) (assert (t= (car tree) (cons 1 2))) (assert (t= (cdr tree) (cons 2 3)))) (defn test-cons-iteration [] "NATIVE: test the iteration behavior of cons" (setv x '(0 1 2 3 4 . 5)) (setv it (iter x)) (for* [i (range 6)] (assert (= i (next it)))) (assert (= 'success (try (do (next it) 'failurenext) (except [e TypeError] (if (= e.args (, "Iteration on malformed cons")) 'success 'failureexc)) (except [e Exception] 'failureexc2))))) (defn test-cons? [] "NATIVE: test behavior of cons?" (assert (cons? (cons 1 2))) (assert (cons? '(1 . 2))) (assert (cons? '(1 2 3 . 4))) (assert (cons? (list* 1 2 3))) (assert (not (cons? (cons 1 [2])))) (assert (not (cons? (list* 1 None))))) (defn test-list* [] "NATIVE: test behavior of list*" (assert (= 1 (list* 1))) (assert (= (cons 1 2) (list* 1 2))) (assert (= (cons 1 (cons 2 3)) (list* 1 2 3))) (assert (= '(1 2 3 4 . 5) (list* 1 2 3 4 5)))) hy-0.12.1/tests/native_tests/contrib/000077500000000000000000000000001304171765200175335ustar00rootroot00000000000000hy-0.12.1/tests/native_tests/contrib/__init__.hy000066400000000000000000000000001304171765200216220ustar00rootroot00000000000000hy-0.12.1/tests/native_tests/contrib/loop.hy000066400000000000000000000016261304171765200210530ustar00rootroot00000000000000(require [hy.contrib.loop [loop]]) (import sys) (defn tco-sum [x y] (loop [[x x] [y y]] (cond [(> y 0) (recur (inc x) (dec y))] [(< y 0) (recur (dec x) (inc y))] [True x]))) (defn non-tco-sum [x y] (cond [(> y 0) (inc (non-tco-sum x (dec y)))] [(< y 0) (dec (non-tco-sum x (inc y)))] [True x])) (defn test-loop [] ;; non-tco-sum should fail (try (setv n (non-tco-sum 100 10000)) (except [e RuntimeError] (assert True)) (else (assert False))) ;; tco-sum should not fail (try (setv n (tco-sum 100 10000)) (except [e RuntimeError] (assert False)) (else (assert (= n 10100))))) (defn test-recur-in-wrong-loc [] (defn bad-recur [n] (loop [[i n]] (if (= i 0) 0 (inc (recur (dec i)))))) (try (bad-recur 3) (except [e TypeError] (assert True)) (else (assert False)))) hy-0.12.1/tests/native_tests/contrib/multi.hy000066400000000000000000000070531304171765200212340ustar00rootroot00000000000000;; Copyright (c) 2014 Morten Linderud ;; Copyright (c) 2016 Tuukka Turto ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. (require [hy.contrib.multi [defmulti defmethod default-method defn]]) (defn test-different-signatures [] "NATIVE: Test multimethods with different signatures" (defmulti fun [&rest args] (len args)) (defmethod fun 0 [] "Hello!") (defmethod fun 1 [a] a) (defmethod fun 2 [a b] "a b") (defmethod fun 3 [a b c] "a b c") (assert (= (fun) "Hello!")) (assert (= (fun "a") "a")) (assert (= (fun "a" "b") "a b")) (assert (= (fun "a" "b" "c") "a b c"))) (defn test-basic-dispatch [] "NATIVE: Test basic dispatch" (defmulti area [shape] (:type shape)) (defmethod area "square" [square] (* (:width square) (:height square))) (defmethod area "circle" [circle] (* (** (:radius circle) 2) 3.14)) (default-method area [shape] 0) (assert (< 0.784 (area {:type "circle" :radius 0.5}) 0.786)) (assert (= (area {:type "square" :width 2 :height 2})) 4) (assert (= (area {:type "non-euclid rhomboid"}) 0))) (defn test-docs [] "NATIVE: Test if docs are properly handled" (defmulti fun [a b] "docs" a) (defmethod fun "foo" [a b] "foo was called") (defmethod fun "bar" [a b] "bar was called") (assert (= fun.--doc-- "docs"))) (defn test-kwargs-handling [] "NATIVE: Test handling of kwargs with multimethods" (defmulti fun [&kwargs kwargs] (get kwargs "type")) (defmethod fun "foo" [&kwargs kwargs] "foo was called") (defmethod fun "bar" [&kwargs kwargs] "bar was called") (assert (= (fun :type "foo" :extra "extra") "foo was called"))) (defn test-basic-multi [] "NATIVE: Test a basic arity overloaded defn" (defn fun ([] "Hello!") ([a] a) ([a b] "a b") ([a b c] "a b c")) (assert (= (fun) "Hello!")) (assert (= (fun "a") "a")) (assert (= (fun "a" "b") "a b")) (assert (= (fun "a" "b" "c") "a b c"))) (defn test-kw-args [] "NATIVE: Test if kwargs are handled correctly for arity overloading" (defn fun ([a] a) ([&optional [a "nop"] [b "p"]] (+ a b))) (assert (= (fun 1) 1)) (assert (= (apply fun [] {"a" "t"}) "t")) (assert (= (apply fun ["hello "] {"b" "world"}) "hello world")) (assert (= (apply fun [] {"a" "hello " "b" "world"}) "hello world"))) (defn test-docs [] "NATIVE: Test if docs are properly handled for arity overloading" (defn fun "docs" ([a] (print a)) ([a b] (print b))) (assert (= fun.--doc-- "docs"))) hy-0.12.1/tests/native_tests/contrib/sequences.hy000066400000000000000000000100211304171765200220620ustar00rootroot00000000000000;; Copyright (c) 2016 Tuukka Turto ;; ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. ;; (require [hy.contrib.sequences [seq defseq]]) (import [hy.contrib.sequences [Sequence end-sequence]]) (defn test-infinite-sequence [] "NATIVE: test creating infinite sequence" (assert (= (list (take 5 (seq [n] n))) [0 1 2 3 4]))) (defn test-indexing-sequence [] "NATIVE: test indexing sequence" (defseq shorty [n] (cond [(< n 10) n] [True (end-sequence)])) (setv 0-to-9 (list (range 10))) (assert (= (get shorty 0) (get 0-to-9 0)) "getting first element failed") (assert (= (get shorty 5) (get 0-to-9 5)) "getting 5th element failed") (assert (= (get shorty -1) (get 0-to-9 -1)) "getting element -1 failed")) (defn test-slicing-sequence [] "NATIVE: test slicing sequence" (defseq shorty [n] (cond [(< n 10) n] [True (end-sequence)])) (setv 0-to-9 (list (range 10))) (assert (= (first shorty) (first 0-to-9)) "getting first failed") (assert (= (list (rest shorty)) (list (rest 0-to-9))) "getting rest failed") (assert (= (list (cut shorty 2 6)) (list (cut 0-to-9 2 6))) "cutting 2-6 failed") (assert (= (list (cut shorty 2 8 2)) (list (cut 0-to-9 2 8 2))) "cutting 2-8-2 failed") (assert (= (list (cut shorty 8 2 -2)) (list (cut 0-to-9 8 2 -2))) "negative cut failed")) (defn test-recursive-sequence [] "NATIVE: test defining a recursive sequence" (defseq fibonacci [n] (cond [(= n 0) 0] [(= n 1) 1] [True (+ (get fibonacci (- n 1)) (get fibonacci (- n 2)))])) (assert (= (first fibonacci) 0) "first element of fibonacci didn't match") (assert (= (second fibonacci) 1) "second element of fibonacci didn't match") (assert (= (get fibonacci 40) 102334155) "40th element of fibonacci didn't match") (assert (= (list (take 9 fibonacci)) [0 1 1 2 3 5 8 13 21]) "taking 8 elements of fibonacci didn't match")) (defn test-nested-functions [] "NATIVE: test that defining nested functions is possible" (defseq primes [n] "infinite sequence of prime numbers" (defn divisible? [n prevs] "is n divisible by any item in prevs?" (any (map (fn [x] (not (% n x))) prevs))) (defn previous-primes [n] "previous prime numbers" (take (dec n) primes)) (defn next-possible-prime [n] "next possible prime after nth prime" (inc (get primes (dec n)))) (cond [(= n 0) 2] [True (do (setv guess (next-possible-prime n)) (while (divisible? guess (previous-primes n)) (setv guess (inc guess))) guess)])) (assert (= (list (take 10 primes)) [2 3 5 7 11 13 17 19 23 29]) "prime sequence didn't match")) hy-0.12.1/tests/native_tests/contrib/walk.hy000066400000000000000000000020611304171765200210320ustar00rootroot00000000000000(import [hy.contrib.walk [*]]) (def walk-form '(print {"foo" "bar" "array" [1 2 3 [4]] "something" (+ 1 2 3 4) "cons!" (cons 1 2) "quoted?" '(foo)})) (defn collector [acc x] (.append acc x) None) (defn test-walk-identity [] (assert (= (walk identity identity walk-form) walk-form))) (defn test-walk [] (let [acc '()] (assert (= (walk (partial collector acc) identity walk-form) [None None])) (assert (= acc walk-form))) (let [acc []] (assert (= (walk identity (partial collector acc) walk-form) None)) (assert (= acc [walk-form])))) (defn test-walk-iterators [] (let [acc []] (assert (= (walk (fn [x] (* 2 x)) (fn [x] x) (drop 1 [1 [2 [3 [4]]]])) [[2 [3 [4]] 2 [3 [4]]]])))) (defn test-macroexpand-all [] (assert (= (macroexpand-all '(with [a 1 b 2 c 3] (for [d c] foo))) '(with* [a 1] (with* [b 2] (with* [c 3] (do (for* [d c] (do foo))))))))) hy-0.12.1/tests/native_tests/core.hy000066400000000000000000000521641304171765200173750ustar00rootroot00000000000000;; Copyright (c) 2013 Paul Tagliamonte ;; Copyright (c) 2013, 2014 Bob Tolbert ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. (import [hy._compat [PY3]]) ;;;; some simple helpers (defn assert-true [x] (assert (= True x))) (defn assert-false [x] (assert (= False x))) (defn assert-equal [x y] (assert (= x y))) (defn assert-none [x] (assert (is x None))) (defn assert-requires-num [f] (for [x ["foo" [] None]] (try (f x) (except [TypeError] True) (else (assert False))))) (defn test-coll? [] "NATIVE: testing coll?" (assert-true (coll? [1 2 3])) (assert-true (coll? {"a" 1 "b" 2})) (assert-true (coll? (range 10))) (assert-false (coll? "abc")) (assert-false (coll? 1))) (defn test-butlast [] "NATIVE: testing butlast function" (assert-equal (list (butlast (range 10))) [0 1 2 3 4 5 6 7 8]) (assert-equal (list (butlast [1])) []) (assert-equal (list (butlast [])) []) ; with an infinite sequence (import itertools) (assert-equal (list (take 5 (butlast (itertools.count 10)))) [10 11 12 13 14])) (defn test-cycle [] "NATIVE: testing cycle" (assert-equal (list (cycle [])) []) (assert-equal (list (take 7 (cycle [1 2 3]))) [1 2 3 1 2 3 1]) (assert-equal (list (take 2 (cycle [1 2 3]))) [1 2]) (assert-equal (list (take 4 (cycle [1 None 3]))) [1 None 3 1])) (defn test-dec [] "NATIVE: testing the dec function" (assert-equal 0 (dec 1)) (assert-equal -1 (dec 0)) (assert-equal 0 (dec (dec 2))) (assert-requires-num dec)) (defn test-setv [] "NATIVE: testing setv mutation" (setv x 1) (setv y 1) (assert-equal x y) (setv x (setv y 12)) (assert-equal x 12) (assert-equal y 12) (setv x (setv y (fn [x] 9))) (assert-equal (x y) 9) (assert-equal (y x) 9) (try (do (setv a.b 1) (assert False)) (except [e [NameError]] (assert (in "name 'a' is not defined" (str e))))) (try (do (setv b.a (fn [x] x)) (assert False)) (except [e [NameError]] (assert (in "name 'b' is not defined" (str e))))) (import itertools) (setv foopermutations (fn [x] (itertools.permutations x))) (setv p (set [(, 1 3 2) (, 3 2 1) (, 2 1 3) (, 3 1 2) (, 1 2 3) (, 2 3 1)])) (assert-equal (set (itertools.permutations [1 2 3])) p) (assert-equal (set (foopermutations [3 1 2])) p) (setv permutations- itertools.permutations) (setv itertools.permutations (fn [x] 9)) (assert-equal (itertools.permutations p) 9) (assert-equal (foopermutations foopermutations) 9) (setv itertools.permutations permutations-) (assert-equal (set (itertools.permutations [2 1 3])) p) (assert-equal (set (foopermutations [2 3 1])) p)) (defn test-distinct [] "NATIVE: testing the distinct function" (setv res (list (distinct [ 1 2 3 4 3 5 2 ]))) (assert-equal res [1 2 3 4 5]) ;; distinct of an empty list should be [] (setv res (list (distinct []))) (assert-equal res []) ;; now with an iter (setv test_iter (iter [1 2 3 4 3 5 2])) (setv res (list (distinct test_iter))) (assert-equal res [1 2 3 4 5]) ; make sure we can handle None in the list (setv res (list (distinct [1 2 3 2 5 None 3 4 None]))) (assert-equal res [1 2 3 5 None 4])) (defn test-drop [] "NATIVE: testing drop function" (setv res (list (drop 2 [1 2 3 4 5]))) (assert-equal res [3 4 5]) (setv res (list (drop 3 (iter [1 2 3 4 5])))) (assert-equal res [4 5]) (setv res (list (drop 3 (iter [1 2 3 None 4 5])))) (assert-equal res [None 4 5]) (setv res (list (drop 0 [1 2 3 4 5]))) (assert-equal res [1 2 3 4 5]) (try (do (list (drop -1 [1 2 3 4 5])) (assert False)) (except [e [ValueError]] None)) (setv res (list (drop 6 (iter [1 2 3 4 5])))) (assert-equal res []) (setv res (list (take 5 (drop 2 (iterate inc 0))))) (assert-equal res [2 3 4 5 6])) (defn test-drop-last [] "NATIVE: testing drop-last function" (assert-equal (list (drop-last 5 (range 10 20))) [10 11 12 13 14]) (assert-equal (list (drop-last 0 (range 5))) [0 1 2 3 4]) (assert-equal (list (drop-last 100 (range 100))) []) ; with an infinite sequence (import itertools) (assert-equal (list (take 5 (drop-last 100 (itertools.count 10)))) [10 11 12 13 14])) (defn test-drop-while [] "NATIVE: testing drop-while function" (setv res (list (drop-while even? [2 4 7 8 9]))) (assert (= res [7 8 9])) (setv res (list (drop-while pos? [2 4 7 8 9]))) (assert (= res [])) (setv res (list (drop-while numeric? [1 2 3 None "a"]))) (assert (= res [None "a"]))) (defn test-empty? [] "NATIVE: testing the empty? function" (assert-true (empty? "")) (assert-false (empty? "None")) (assert-true (empty? (,))) (assert-false (empty? (, None))) (assert-true (empty? [])) (assert-false (empty? [None])) (assert-true (empty? {})) (assert-false (empty? {"a" None})) (assert-true (empty? (set))) (assert-false (empty? (set [None])))) (defn test-even [] "NATIVE: testing the even? function" (assert-true (even? -2)) (assert-false (even? 1)) (assert-true (even? 0)) (assert-requires-num even?)) (defn test-every? [] "NATIVE: testing the every? function" (assert-true (every? even? [2 4 6])) (assert-false (every? even? [1 3 5])) (assert-false (every? even? [2 4 5])) (assert-true (every? even? []))) (defn test-filter [] "NATIVE: testing the filter function" (setv res (list (filter pos? [ 1 2 3 -4 5]))) (assert-equal res [ 1 2 3 5 ]) ;; test with iter (setv res (list (filter pos? (iter [ 1 2 3 -4 5 -6])))) (assert-equal res [ 1 2 3 5]) (setv res (list (filter neg? [ -1 -4 5 3 4]))) (assert-false (= res [1 2])) ;; test with empty list (setv res (list (filter neg? []))) (assert-equal res []) ;; test with None in the list (setv res (list (filter even? (filter numeric? [1 2 None 3 4 None 4 6])))) (assert-equal res [2 4 4 6]) (setv res (list (filter none? [1 2 None 3 4 None 4 6]))) (assert-equal res [None None])) (defn test-flatten [] "NATIVE: testing the flatten function" (setv res (flatten [1 2 [3 4] 5])) (assert-equal res [1 2 3 4 5]) (setv res (flatten ["foo" (, 1 2) [1 [2 3] 4] "bar"])) (assert-equal res ["foo" 1 2 1 2 3 4 "bar"]) (setv res (flatten [1])) (assert-equal res [1]) (setv res (flatten [])) (assert-equal res []) (setv res (flatten (, 1))) (assert-equal res [1]) ;; test with None (setv res (flatten (, 1 (, None 3)))) (assert-equal res [1 None 3]) (try (flatten "foo") (except [e [TypeError]] (assert (in "not a collection" (str e))))) (try (flatten 12.34) (except [e [TypeError]] (assert (in "not a collection" (str e)))))) (defn test-float? [] "NATIVE: testing the float? function" (assert-true (float? 4.2)) (assert-false (float? 0)) (assert-false (float? -3)) (assert-true (float? -3.2)) (assert-false (float? "foo"))) (defn test-symbol? [] "NATIVE: testing the symbol? function" (assert-false (symbol? "hello")) (assert-false (symbol? [1 2 3])) (assert-false (symbol? '[a b c])) (assert-true (symbol? 'im-symbol)) (assert-false (symbol? (name 'im-symbol)))) (defn test-gensym [] "NATIVE: testing the gensym function" (import [hy.models.symbol [HySymbol]]) (setv s1 (gensym)) (assert (isinstance s1 HySymbol)) (assert (= 0 (.find s1 ":G_"))) (setv s2 (gensym "xx")) (setv s3 (gensym "xx")) (assert (= 0 (.find s2 ":xx_"))) (assert (not (= s2 s3))) (assert (not (= (str s2) (str s3))))) (defn test-identity [] "NATIVE: testing the identity function" (assert (= 4 (identity 4))) (assert (= "hy" (identity "hy"))) (assert (= [1 2] (identity [1 2])))) (defn test-inc [] "NATIVE: testing the inc function" (assert-equal 3 (inc 2)) (assert-equal 0 (inc -1)) (assert-requires-num inc) (defclass X [object] [__add__ (fn [self other] (.format "__add__ got {}" other))]) (assert-equal (inc (X)) "__add__ got 1")) (defn test-instance [] "NATIVE: testing instance? function" (defclass Foo [object]) (defclass Foo2 [object]) (defclass Foo3 [Foo]) (setv foo (Foo)) (setv foo3 (Foo3)) (assert-true (instance? Foo foo)) (assert-false (instance? Foo2 foo)) (assert-true (instance? Foo foo3)) (assert-true (instance? float 1.0)) (assert-true (instance? int (int 3))) (assert-true (instance? str (str "hello")))) (defn test-integer? [] "NATIVE: testing the integer? function" (assert-true (integer? 0)) (assert-true (integer? 3)) (assert-true (integer? -3)) (assert-true (integer? (integer "-3"))) (assert-true (integer? (integer 3))) (assert-false (integer? 4.2)) (assert-false (integer? None)) (assert-false (integer? "foo"))) (defn test-integer-char? [] "NATIVE: testing the integer-char? function" (assert-true (integer-char? "1")) (assert-true (integer-char? "-1")) (assert-true (integer-char? (str (integer 300)))) (assert-false (integer-char? "foo")) (assert-false (integer-char? None))) (defn test-interleave [] "NATIVE: testing the interleave function" ;; with more than 2 sequences (assert-equal (list (take 9 (interleave (range 10) (range 10 20) (range 20 30)))) [0 10 20 1 11 21 2 12 22]) ;; with sequences of different length (assert-equal (list (interleave (range 1000000) (range 0 -3 -1))) [0 0 1 -1 2 -2]) ;; with infinite sequences (import itertools) (assert-equal (list (take 10 (interleave (itertools.count) (itertools.count 100)))) [0 100 1 101 2 102 3 103 4 104])) (defn test-interpose [] "NATIVE: testing the interpose function" ;; with a list (assert-equal (list (interpose "!" ["a" "b" "c"])) ["a" "!" "b" "!" "c"]) ;; with an infinite sequence (import itertools) (assert-equal (list (take 7 (interpose -1 (itertools.count)))) [0 -1 1 -1 2 -1 3])) (defn test-iterable [] "NATIVE: testing iterable? function" ;; should work for a string (setv s (str "abcde")) (assert-true (iterable? s)) ;; should work for unicode (setv u "hello") (assert-true (iterable? u)) (assert-true (iterable? (iter u))) ;; should work for a list (setv l [1 2 3 4]) (assert-true (iterable? l)) (assert-true (iterable? (iter l))) ;; should work for a dict (setv d {:a 1 :b 2 :c 3}) (assert-true (iterable? d)) ;; should work for a tuple? (setv t (, 1 2 3 4)) (assert-true (iterable? t)) ;; should work for a generator (assert-true (iterable? (repeat 3))) ;; shouldn't work for an int (assert-false (iterable? 5))) (defn test-iterate [] "NATIVE: testing the iterate function" (setv res (list (take 5 (iterate inc 5)))) (assert-equal res [5 6 7 8 9]) (setv res (list (take 3 (iterate (fn [x] (* x x)) 5)))) (assert-equal res [5 25 625]) (setv f (take 4 (iterate inc 5))) (assert-equal (list f) [5 6 7 8])) (defn test-iterator [] "NATIVE: testing iterator? function" ;; should not work for a list (setv l [1 2 3 4]) (assert-false (iterator? l)) ;; should work for an iter over a list (setv i (iter [1 2 3 4])) (assert-true (iterator? i)) ;; should not work for a dict (setv d {:a 1 :b 2 :c 3}) (assert-false (iterator? d)) ;; should not work for a tuple? (setv t (, 1 2 3 4)) (assert-false (iterator? t)) ;; should work for a generator (assert-true (iterator? (repeat 3))) ;; should not work for an int (assert-false (iterator? 5))) (defn test-last [] "NATIVE: testing the last function" (assert-equal (last [1 2 3 4]) 4) (assert-equal (last [5]) 5)) (import itertools) (assert-equal (last (take 5 (itertools.count 10))) 14) (defn test-neg [] "NATIVE: testing the neg? function" (assert-true (neg? -2)) (assert-false (neg? 1)) (assert-false (neg? 0)) (when PY3 (assert-requires-num neg?))) (defn test-zero [] "NATIVE: testing the zero? function" (assert-false (zero? -2)) (assert-false (zero? 1)) (assert-true (zero? 0))) (defn test-none [] "NATIVE: testing for `is None`" (assert-true (none? None)) (setv f None) (assert-true (none? f)) (assert-false (none? 0)) (assert-false (none? ""))) (defn test-nth [] "NATIVE: testing the nth function" (assert-equal 2 (nth [1 2 4 7] 1)) (assert-equal 7 (nth [1 2 4 7] 3)) (assert-none (nth [1 2 4 7] 5)) (assert-equal (nth [1 2 4 7] 5 "some default value") "some default value") ; with default specified (try (do (nth [1 2 4 7] -1) (assert False)) (except [e [ValueError]] None)) ;; now for iterators (assert-equal 2 (nth (iter [1 2 4 7]) 1)) (assert-equal 7 (nth (iter [1 2 4 7]) 3)) (assert-none (nth (iter [1 2 4 7]) 5)) (assert-equal (nth (iter [1 2 4 7]) 5 "some default value") "some default value") ; with default specified (try (do (nth (iter [1 2 4 7]) -1) (assert False)) (except [e [ValueError]] None)) (assert-equal 5 (nth (take 3 (drop 2 [1 2 3 4 5 6])) 2))) (defn test-numeric? [] "NATIVE: testing the numeric? function" (assert-true (numeric? 1)) (assert-true (numeric? 3.4)) (assert-true (numeric? 0.0)) (assert-true (numeric? -1.45)) (assert-false (numeric? "Foo")) (assert-false (numeric? None))) (defn test-odd [] "NATIVE: testing the odd? function" (assert-true (odd? -3)) (assert-true (odd? 1)) (assert-false (odd? 0)) (assert-requires-num odd?)) (defn test-partition [] "NATIVE: testing the partition function" (setv ten (range 10)) ;; no remainder (assert-equal (list (partition ten 3)) [(, 0 1 2) (, 3 4 5) (, 6 7 8)]) ;; pair by default (assert-equal (list (partition ten)) [(, 0 1) (, 2 3) (, 4 5) (, 6 7) (, 8 9)]) ;; length 1 is valid (assert-equal (list (partition ten 1)) [(, 0) (, 1) (, 2) (, 3) (, 4) (, 5) (, 6) (, 7) (, 8) (, 9)]) ;; tuples of length < 1 don't crash (assert-equal (list (partition ten 0)) []) (assert-equal (list (partition ten -1)) []) ;; keep remainder with a fillvalue (assert-equal (list (partition ten 3 :fillvalue "x")) [(, 0 1 2) (, 3 4 5) (, 6 7 8) (, 9 "x" "x")]) ;; skip elements with step > n (assert-equal (list (partition ten 2 3)) [(, 0 1) (, 3 4) (, 6 7)]) ;; overlap with step < n (assert-equal (list (partition (range 5) 2 1)) [(, 0 1) (, 1 2) (, 2 3) (, 3 4)])) (defn test-pos [] "NATIVE: testing the pos? function" (assert-true (pos? 2)) (assert-false (pos? -1)) (assert-false (pos? 0)) (when PY3 (assert-requires-num pos?))) (defn test-remove [] "NATIVE: testing the remove function" (setv r (list (remove odd? [1 2 3 4 5 6 7]))) (assert-equal r [2 4 6]) (assert-equal (list (remove even? [1 2 3 4 5])) [1 3 5]) (assert-equal (list (remove neg? [1 2 3 4 5])) [1 2 3 4 5]) (assert-equal (list (remove pos? [1 2 3 4 5])) []) ;; deal with embedded None (assert-equal (list (remove (fn [x] (not (numeric? x))) [1 2 None 3 None 4])) [1 2 3 4])) (defn test-repeat [] "NATIVE: testing repeat" (setv r (repeat 10)) (assert-equal (list (take 5 r)) [10 10 10 10 10]) (assert-equal (list (take 4 r)) [10 10 10 10]) (setv r (repeat 10 3)) (assert-equal (list r) [10 10 10])) (defn test-repeatedly [] "NATIVE: testing repeatedly" (setv r (repeatedly (fn [] (inc 4)))) (assert-equal (list (take 5 r)) [5 5 5 5 5]) (assert-equal (list (take 4 r)) [5 5 5 5]) (assert-equal (list (take 6 r)) [5 5 5 5 5 5])) (defn test-second [] "NATIVE: testing second" (assert-equal 2 (second [1 2])) (assert-equal 3 (second [2 3 4]))) (defn test-some [] "NATIVE: testing the some function" (assert-true (some even? [2 4 6])) (assert-none (some even? [1 3 5])) (assert-true (some even? [1 2 3])) (assert-none (some even? [])) ; 0, "" (empty string) and [] (empty list) are all logical false (assert-none (some identity [0 "" []])) ; non-empty string is logical true (assert-equal (some identity [0 "this string is non-empty" []]) "this string is non-empty") ; None if collection is empty (assert-none (some even? []))) (defn test-string? [] "NATIVE: testing string?" (assert-true (string? "foo")) (assert-true (string? "")) (assert-false (string? 5.3)) (assert-true (string? (str 5.3))) (assert-false (string? None))) (defn test-take [] "NATIVE: testing the take function" (setv res (list (take 3 [1 2 3 4 5]))) (assert-equal res [1 2 3]) (setv res (list (take 4 (repeat "s")))) (assert-equal res ["s" "s" "s" "s"]) (setv res (list (take 0 (repeat "s")))) (assert-equal res []) (try (do (list (take -1 (repeat "s"))) (assert False)) (except [e [ValueError]] None)) (setv res (list (take 6 [1 2 None 4]))) (assert-equal res [1 2 None 4])) (defn test-take-nth [] "NATIVE: testing the take-nth function" (setv res (list (take-nth 2 [1 2 3 4 5 6 7]))) (assert-equal res [1 3 5 7]) (setv res (list (take-nth 3 [1 2 3 4 5 6 7]))) (assert-equal res [1 4 7]) (setv res (list (take-nth 4 [1 2 3 4 5 6 7]))) (assert-equal res [1 5]) (setv res (list (take-nth 5 [1 2 3 4 5 6 7]))) (assert-equal res [1 6]) (setv res (list (take-nth 6 [1 2 3 4 5 6 7]))) (assert-equal res [1 7]) (setv res (list (take-nth 7 [1 2 3 4 5 6 7]))) (assert-equal res [1]) ;; what if there are None's in list (setv res (list (take-nth 2 [1 2 3 None 5 6]))) (assert-equal res [1 3 5]) (setv res (list (take-nth 3 [1 2 3 None 5 6]))) (assert-equal res [1 None]) ;; using 0 should raise ValueError (let [passed False] (try (setv res (list (take-nth 0 [1 2 3 4 5 6 7]))) (except [ValueError] (setv passed True))) (assert passed))) (defn test-take-while [] "NATIVE: testing the take-while function" (setv res (list (take-while pos? [ 1 2 3 -4 5]))) (assert-equal res [1 2 3]) (setv res (list (take-while neg? [ -1 -4 5 3 4]))) (assert-false (= res [1 2])) (setv res (list (take-while none? [None None 1 2 3]))) (assert-equal res [None None]) (setv res (list (take-while (fn [x] (not (none? x))) [1 2 3 4 None 5 6 None 7]))) (assert-equal res [1 2 3 4])) (defn test-doto [] "NATIVE: testing doto macro" (setv collection []) (doto collection (.append 1) (.append 2) (.append 3)) (assert-equal collection [1 2 3]) (setv res (doto (set) (.add 2) (.add 1))) (assert-equal res (set [1 2])) (setv res (doto [] (.append 1) (.append 2) .reverse)) (assert-equal res [2 1])) (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? None)))) (defn test-import-init-hy [] "NATIVE: testing import of __init__.hy" (import tests.resources.bin) (assert (in "_null_fn_for_import_test" (dir tests.resources.bin)))) (defn test-accumulate [] "NATIVE: testing the accumulate function" (assert-equal (list (accumulate ["a" "b" "c"])) ["a" "ab" "abc"]) (assert-equal (list (accumulate [1 2 3 4 5])) [1 3 6 10 15]) (assert-equal (list (accumulate [1 -2 -3 -4 -5] -)) [1 3 6 10 15])) (defn test-reserved [] (import [hy.core.reserved [names]]) (assert (is (type (names)) frozenset)) (assert (in "and" (names))) (when PY3 (assert (in "False" (names)))) (assert (in "pass" (names))) (assert (in "class" (names))) (assert (in "defclass" (names))) (assert (in "->" (names))) (assert (in "keyword?" (names))) (assert (not-in "foo" (names))) (assert (not-in "hy" (names)))) (defn test-complement [] "NATIVE: test complement" (def helper (complement identity)) (assert-true (helper False)) (assert-false (helper True))) (defn test-constantly [] "NATIVE: test constantly" (def helper (constantly 42)) (assert-true (= (helper) 42)) (assert-true (= (helper 1 2 3) 42)) (assert-true (= (helper 1 2 :foo 3) 42))) (defn test-comp [] "NATIVE: test comp" (assert-true ((comp odd? inc second) [1 2 3 4 5])) (assert-true (= 1 ((comp first) [1 2 3]))) (assert-true ((comp even? inc +) 1 2 3 4 5)) (assert-true (= 5 ((comp) 5))) (assert (is (comp) identity))) (defn test-juxt [] "NATIVE: test juxt" (assert-equal ((juxt min max sum) [1 2 3 4 5 6]) [1 6 21]) (assert-equal ((juxt identity) 42) [42])) hy-0.12.1/tests/native_tests/defclass.hy000066400000000000000000000055011304171765200202220ustar00rootroot00000000000000(defn test-defclass [] "NATIVE: test defclass simple mechanism" (defclass A) (assert (isinstance (A) A))) (defn test-defclass-inheritance [] "NATIVE: test defclass inheritance" (defclass A []) (assert (isinstance (A) object)) (defclass A [object]) (assert (isinstance (A) object)) (defclass B [A]) (assert (isinstance (B) A)) (defclass C [object]) (defclass D [B C]) (assert (isinstance (D) A)) (assert (isinstance (D) B)) (assert (isinstance (D) C)) (assert (not (isinstance (A) D)))) (defn test-defclass-attrs [] "NATIVE: test defclass attributes" (defclass A [] [x 42]) (assert (= A.x 42)) (assert (= (getattr (A) "x") 42))) (defn test-defclass-attrs-fn [] "NATIVE: test defclass attributes with fn" (defclass B [] [x 42 y (fn [self value] (+ self.x value))]) (assert (= B.x 42)) (assert (= (.y (B) 5) 47)) (let [b (B)] (setv B.x 0) (assert (= (.y b 1) 1)))) (defn test-defclass-dynamic-inheritance [] "NATIVE: test defclass with dynamic inheritance" (defclass A [((fn [] (if True list dict)))] [x 42]) (assert (isinstance (A) list)) (defclass A [((fn [] (if False list dict)))] [x 42]) (assert (isinstance (A) dict))) (defn test-defclass-no-fn-leak [] "NATIVE: test defclass attributes with fn" (defclass A [] [x (fn [] 1)]) (try (do (x) (assert False)) (except [NameError]))) (defn test-defclass-docstring [] "NATIVE: test defclass docstring" (defclass A [] [--doc-- "doc string" x 1]) (setv a (A)) (assert (= a.__doc__ "doc string")) (defclass B [] "doc string" [x 1]) (setv b (B)) (assert (= b.x 1)) (assert (= b.__doc__ "doc string")) (defclass MultiLine [] "begin a very long multi-line string to make sure that it comes out the way we hope and can span 3 lines end." [x 1]) (setv mL (MultiLine)) (assert (= mL.x 1)) (assert (in "begin" mL.__doc__)) (assert (in "end" mL.__doc__))) (defn test-defclass-macroexpand [] "NATIVE: test defclass with macro expand" (defmacro M [] `(defn x [self x] (setv self._x x))) (defclass A [] (M)) (setv a (A)) (a.x 1) (assert (= a._x 1))) (defn test-defclass-syntax [] "NATIVE: test defclass syntax with properties and methods and side-effects" (setv foo 1) (defclass A [] [x 1 y 2] (global foo) (setv foo 2) (defn greet [self] "Greet the caller" "hello!")) (setv a (A)) (assert (= a.x 1)) (assert (= a.y 2)) (assert foo 2) (assert (.greet a) "hello")) (defn test-defclass-implicit-none-for-init [] "NATIVE: test that defclass adds an implicit None to --init--" (defclass A [] [--init-- (fn [self] (setv self.x 1) 42)]) (defclass B [] (defn --init-- [self] (setv self.x 2) 42)) (setv a (A)) (setv b (B)) (assert (= a.x 1)) (assert (= b.x 2))) hy-0.12.1/tests/native_tests/extra/000077500000000000000000000000001304171765200172165ustar00rootroot00000000000000hy-0.12.1/tests/native_tests/extra/__init__.hy000066400000000000000000000000001304171765200213050ustar00rootroot00000000000000hy-0.12.1/tests/native_tests/extra/anaphoric.hy000066400000000000000000000120371304171765200215270ustar00rootroot00000000000000;; Copyright (c) 2013 James King ;; Permission is hereby granted, free of charge, to any person obtaining a ;; copy of this software and associated documentation files (the "Software"), ;; to deal in the Software without restriction, including without limitation ;; the rights to use, copy, modify, merge, publish, distribute, sublicense, ;; and/or sell copies of the Software, and to permit persons to whom the ;; Software is furnished to do so, subject to the following conditions: ;; The above copyright notice and this permission notice shall be included in ;; all copies or substantial portions of the Software. ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ;; DEALINGS IN THE SOFTWARE. (import [hy.errors [HyMacroExpansionError]]) (require [hy.extra.anaphoric [*]]) ;;;; some simple helpers (defn assert-true [x] (assert (= True x))) (defn assert-false [x] (assert (= False x))) (defn assert-equal [x y] (assert (= x y))) (defn test-ap-if [] "NATIVE: testing anaphoric if" (ap-if True (assert-true 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" (setv res []) (ap-each [1 2 3 4] (.append res it)) (assert-equal res [1 2 3 4])) (defn test-ap-each-while [] "NATIVE: testing anaphoric each-while" (setv res []) (ap-each-while [2 2 4 3 4 5 6] (even? it) (.append res it)) (assert-equal res [2 2 4])) (defn test-ap-map [] "NATIVE: testing anaphoric map" (assert-equal (list (ap-map (* it 3) [1 2 3])) [3 6 9]) (assert-equal (list (ap-map (* it 3) [])) []) (assert-equal (let [v 1 f 1] (list (ap-map (it v f) [(fn [a b] (+ a b))]))) [2])) (defn test-ap-map-when [] "NATIVE: testing anaphoric map-when" (assert-equal (list (ap-map-when even? (* it 2) [1 2 3 4])) [1 4 3 8])) (defn test-ap-filter [] "NATIVE: testing anaphoric filter" (assert-equal (list (ap-filter (> it 2) [1 2 3 4])) [3 4]) (assert-equal (list (ap-filter (even? it) [1 2 3 4])) [2 4])) (defn test-ap-reject [] "NATIVE: testing anaphoric filter" (assert-equal (list (ap-reject (> it 2) [1 2 3 4])) [1 2]) (assert-equal (list (ap-reject (even? it) [1 2 3 4])) [1 3])) (defn test-ap-dotimes [] "NATIVE: testing anaphoric dotimes" (assert-equal (let [n []] (ap-dotimes 3 (.append n 3)) n) [3 3 3]) (assert-equal (let [n []] (ap-dotimes 3 (.append n it)) n) [0 1 2])) (defn test-ap-first [] "NATIVE: testing anaphoric first" (assert-equal (ap-first (> it 5) (range 10)) 6) (assert-equal (ap-first (even? it) [1 2 3 4]) 2) (assert-equal (ap-first (> it 10) (range 10)) None)) (defn test-ap-last [] "NATIVE: testing anaphoric last" (assert-equal (ap-last (> it 5) (range 10)) 9) (assert-equal (ap-last (even? it) [1 2 3 4]) 4) (assert-equal (ap-last (> it 10) (range 10)) None)) (defn test-ap-reduce [] "NATIVE: testing anaphoric reduce" (assert-equal (ap-reduce (* acc it) [1 2 3]) 6) (assert-equal (ap-reduce (* acc it) [1 2 3] 6) 36) (assert-equal (ap-reduce (+ acc " on " it) ["Hy" "meth"]) "Hy on meth") (assert-equal (ap-reduce (+ acc it) [] 1) 1)) (defn test-ap-pipe [] "NATIVE: testing anaphoric pipe" (assert-equal (ap-pipe 2 (+ it 1) (* it 3)) 9) (assert-equal (ap-pipe [4 5 6 7] (list (rest it)) (len it)) 3)) (defn test-ap-compose [] "NATIVE: testing anaphoric compose" (assert-equal ((ap-compose (+ it 1) (* it 3)) 2) 9) (assert-equal ((ap-compose (list (rest it)) (len it)) [4 5 6 7]) 3)) (defn test-xi [] "NATIVE: testing xi forms" ;; test ordering (assert-equal ((xi / x1 x2) 2 4) 0.5) (assert-equal ((xi / x2 x1) 2 4) 2) (assert-equal ((xi identity (, x5 x4 x3 x2 x1)) 1 2 3 4 5) (, 5 4 3 2 1)) (assert-equal ((xi identity (, x1 x2 x3 x4 x5)) 1 2 3 4 5) (, 1 2 3 4 5)) (assert-equal ((xi identity (, x1 x5 x2 x3 x4)) 1 2 3 4 5) (, 1 5 2 3 4)) ;; test &rest (assert-equal ((xi sum xi) 1 2 3) 6) (assert-equal ((xi identity (, x1 xi)) 10 1 2 3) (, 10 (, 1 2 3))) ;; no parameters (assert-equal ((xi list)) []) (assert-equal ((xi identity "Hy!")) "Hy!") (assert-equal ((xi identity "xi")) "xi") (assert-equal ((xi + "Hy " "world!")) "Hy world!") ;; test skipped parameters (assert-equal ((xi identity [x3 x1]) 1 2 3) [3 1]) ;; test nesting (assert-equal ((xi identity [x1 (, x2 [x3] "Hy" [xi])]) 1 2 3 4 5) [1 (, 2 [3] "Hy" [(, 4 5)])]) ;; test arg as function (assert-equal ((xi x1 2 4) +) 6) (assert-equal ((xi x1 2 4) -) -2) (assert-equal ((xi x1 2 4) /) 0.5)) hy-0.12.1/tests/native_tests/language.hy000066400000000000000000001166111304171765200202260ustar00rootroot00000000000000(import [tests.resources [kwtest function-with-a-dash]] [os.path [exists isdir isfile]] [sys :as systest] [operator [or_]] [hy.errors [HyTypeError]]) (import sys) (import [hy._compat [PY33 PY34 PY35]]) (defn test-sys-argv [] "NATIVE: test sys.argv" ;; BTW, this also tests inline comments. Which suck to implement. (assert (isinstance sys.argv list))) (defn test-hex [] "NATIVE: test hex" (assert (= 0x80 128))) (defn test-octal [] "NATIVE: test octal" (assert (= 0o1232 666))) (defn test-binary [] "NATIVE: test binary" (assert (= 0b1011101 93))) (defn test-fractions [] "NATIVE: test fractions" (assert (= 1/2 (fraction 1 2)))) (defn test-lists [] "NATIVE: test lists work right" (assert (= [1 2 3 4] (+ [1 2] [3 4])))) (defn test-dicts [] "NATIVE: test dicts work right" (assert (= {1 2 3 4} {3 4 1 2})) (assert (= {1 2 3 4} {1 (+ 1 1) 3 (+ 2 2)}))) (defn test-sets [] "NATIVE: test sets work right" (assert (= #{1 2 3 4} (| #{1 2} #{3 4}))) (assert (= (type #{1 2 3 4}) set)) (assert (= #{} (set)))) (defn test-setv-empty [] "NATIVE: test setv works with no arguments" (assert (is (setv) None))) (defn test-setv-get [] "NATIVE: test setv works on a get expression" (setv foo [0 1 2]) (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)) (except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) (try (eval '(setv True 0)) (except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) (try (eval '(setv None 1)) (except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) (try (eval '(defn defclass [] (print "hello"))) (except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) (try (eval '(defn get [] (print "hello"))) (except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e))))) (try (eval '(defn lambda [] (print "hello"))) (except [e [TypeError]] (assert (in "Can't assign to a builtin" (str e)))))) (defn test-setv-pairs [] "NATIVE: test that setv works on pairs of arguments" (assert (= (setv a 1 b 2) (, 1 2))) (assert (= a 1)) (assert (= b 2)) (setv y 0 x 1 y x) (assert y) (try (eval '(setv a 1 b)) (except [e [TypeError]] (assert (in "`setv' needs an even number of arguments" (str e)))))) (defn test-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")) (except [e [Exception]] (assert (in "to `fn' must be a list" (str e))))) (try (eval '(defn foo "foo")) (except [e [Exception]] (assert (in "takes a parameter list as second" (str e)))))) (defn test-alias-names-in-errors [] "NATIVE: tests that native aliases show the correct names in errors" (try (eval '(lambda)) (except [e [Exception]] (assert (in "lambda" (str e))))) (try (eval '(fn)) (except [e [Exception]] (assert (in "fn" (str e))))) (try (eval '(setv 1 2 3)) (except [e [Exception]] (assert (in "setv" (str e))))) (try (eval '(def 1 2 3)) (except [e [Exception]] (assert (in "def" (str e)))))) (defn test-for-loop [] "NATIVE: test for loops" (setv count1 0 count2 0) (for [x [1 2 3 4 5]] (setv count1 (+ count1 x)) (setv count2 (+ count2 x))) (assert (= count1 15)) (assert (= count2 15)) (setv count 0) (for [x [1 2 3 4 5] y [1 2 3 4 5]] (setv count (+ count x y)) (else (+= count 1))) (assert (= count 151)) (assert (= (list ((fn [] (for [x [[1] [2 3]] y x] (yield y))))) (list-comp y [x [[1] [2 3]] y x]))) (assert (= (list ((fn [] (for [x [[1] [2 3]] y x z (range 5)] (yield z))))) (list-comp z [x [[1] [2 3]] y x z (range 5)])))) (defn test-nasty-for-nesting [] "NATIVE: test nesting for loops harder" ;; This test and feature is dedicated to @nedbat. ;; let's ensure empty iterating is an implicit do (setv t 0) (for [] (setv t 1)) (assert (= t 1)) ;; OK. This first test will ensure that the else is hooked up to the ;; for when we break out of it. (for [x (range 2) y (range 2)] (break) (else (raise Exception))) ;; OK. This next test will ensure that the else is hooked up to the ;; "inner" iteration (for [x (range 2) y (range 2)] (if (= y 1) (break)) (else (raise Exception))) ;; OK. This next test will ensure that the else is hooked up to the ;; "outer" iteration (for [x (range 2) y (range 2)] (if (= x 1) (break)) (else (raise Exception))) ;; OK. This next test will ensure that we call the else branch exactly ;; once. (setv flag 0) (for [x (range 2) y (range 2)] (+ 1 1) (else (setv flag (+ flag 2)))) (assert (= flag 2))) (defn test-while-loop [] "NATIVE: test while loops?" (setv count 5) (setv fact 1) (while (> count 0) (setv fact (* fact count)) (setv count (- count 1))) (assert (= count 0)) (assert (= fact 120))) (defn test-not [] "NATIVE: test not" (assert (not (= 1 2))) (assert (= True (not False))) (assert (= False (not 42))) ) (defn test-inv [] "NATIVE: test inv" (assert (= (~ 1) -2)) (assert (= (~ -2) 1))) (defn test-in [] "NATIVE: test in" (assert (in "a" ["a" "b" "c" "d"])) (assert (not-in "f" ["a" "b" "c" "d"]))) (defn test-noteq [] "NATIVE: not eq" (assert (!= 2 3)) (assert (not (!= 1)))) (defn test-eq [] "NATIVE: eq" (assert (= 1 1)) (assert (= 1))) (defn test-numops [] "NATIVE: test numpos" (assert (> 5 4 3 2 1)) (assert (> 1)) (assert (< 1 2 3 4 5)) (assert (< 1)) (assert (<= 5 5 5 5 )) (assert (<= 1)) (assert (>= 5 5 5 5 )) (assert (>= 1))) (defn test-is [] "NATIVE: test is can deal with None" (setv a None) (assert (is a None)) (assert (is-not a "b")) (assert (none? a))) (defn test-branching [] "NATIVE: test if branching" (if True (assert (= 1 1)) (assert (= 2 1)))) (defn test-branching-with-do [] "NATIVE: test if branching (multiline)" (if False (assert (= 2 1)) (do (assert (= 1 1)) (assert (= 1 1)) (assert (= 1 1))))) (defn test-branching-expr-count-with-do [] "NATIVE: make sure we execute the right number of expressions in the branch" (setv counter 0) (if False (assert (= 2 1)) (do (setv counter (+ counter 1)) (setv counter (+ counter 1)) (setv counter (+ counter 1)))) (assert (= counter 3))) (defn test-cond [] "NATIVE: test if cond sorta works." (cond [(= 1 2) (assert (is True False))] [(is None None) (setv x True) (assert x)]) (assert (= (cond) None))) (defn test-if [] "NATIVE: test if if works." ;; with an odd number of args, the last argument is the default case (assert (= 1 (if 1))) (assert (= 1 (if 0 -1 1))) ;; with an even number of args, the default is None (assert (is None (if))) (assert (is None (if 0 1))) ;; test deeper nesting (assert (= 42 (if 0 0 None 1 "" 2 1 42 1 43))) ;; test shortcutting (setv x None) (if 0 (setv x 0) "" (setv x "") 42 (setv x 42) 43 (setv x 43) (setv x "default")) (assert (= x 42))) (defn test-index [] "NATIVE: Test that dict access works" (assert (= (get {"one" "two"} "one") "two")) (assert (= (get [1 2 3 4 5] 1) 2)) (assert (= (get {"first" {"second" {"third" "level"}}} "first" "second" "third") "level")) (assert (= (get ((fn [] {"first" {"second" {"third" "level"}}})) "first" "second" "third") "level")) (assert (= (get {"first" {"second" {"third" "level"}}} ((fn [] "first")) "second" "third") "level"))) (defn test-lambda [] "NATIVE: test lambda operator" (setv square (lambda [x] (* x x))) (assert (= 4 (square 2))) (setv lambda_list (lambda [test &rest args] (, test args))) (assert (= (, 1 (, 2 3)) (lambda_list 1 2 3)))) (defn test-imported-bits [] "NATIVE: test the imports work" (assert (is (exists ".") True)) (assert (is (isdir ".") True)) (assert (is (isfile ".") False))) (defn test-kwargs [] "NATIVE: test kwargs things." (assert (= (apply kwtest [] {"one" "two"}) {"one" "two"})) (setv mydict {"one" "three"}) (assert (= (apply kwtest [] mydict) mydict)) (assert (= (apply kwtest [] ((fn [] {"one" "two"}))) {"one" "two"}))) (defn test-apply [] "NATIVE: test working with args and functions" (defn sumit [a b c] (+ a b c)) (assert (= (apply sumit [1] {"b" 2 "c" 3}) 6)) (assert (= (apply sumit [1 2 2]) 5)) (assert (= (apply sumit [] {"a" 1 "b" 1 "c" 2}) 4)) (assert (= (apply sumit ((fn [] [1 1])) {"c" 1}) 3)) (defn noargs [] [1 2 3]) (assert (= (apply noargs) [1 2 3])) (defn sumit-mangle [an-a a-b a-c a-d] (+ an-a a-b a-c a-d)) (def Z "a_d") (assert (= (apply sumit-mangle [] {"an-a" 1 :a-b 2 'a-c 3 Z 4}) 10))) (defn test-apply-with-methods [] "NATIVE: test apply to call a method" (setv str "foo {bar}") (assert (= (apply .format [str] {"bar" "baz"}) (apply .format ["foo {0}" "baz"]) "foo baz")) (setv lst ["a {0} {1} {foo} {bar}" "b" "c"]) (assert (= (apply .format lst {"foo" "d" "bar" "e"}) "a b c d e"))) (defn test-dotted [] "NATIVE: test dotted invocation" (assert (= (.join " " ["one" "two"]) "one two")) (defclass X [object] []) (defclass M [object] [meth (fn [self &rest args &kwargs kwargs] (.join " " (+ (, "meth") args (tuple (map (fn [k] (get kwargs k)) (sorted (.keys kwargs)))))))]) (setv x (X)) (setv m (M)) (assert (= (.meth m) "meth")) (assert (= (.meth m "foo" "bar") "meth foo bar")) (assert (= (.meth :b "1" :a "2" m "foo" "bar") "meth foo bar 2 1")) (assert (= (apply .meth [m "foo" "bar"]) "meth foo bar")) (setv x.p m) (assert (= (.p.meth x) "meth")) (assert (= (.p.meth x "foo" "bar") "meth foo bar")) (assert (= (.p.meth :b "1" :a "2" x "foo" "bar") "meth foo bar 2 1")) (assert (= (apply .p.meth [x "foo" "bar"]) "meth foo bar")) (setv x.a (X)) (setv x.a.b m) (assert (= (.a.b.meth x) "meth")) (assert (= (.a.b.meth x "foo" "bar") "meth foo bar")) (assert (= (.a.b.meth :b "1" :a "2" x "foo" "bar") "meth foo bar 2 1")) (assert (= (apply .a.b.meth [x "foo" "bar"]) "meth foo bar")) (assert (is (.isdigit :foo) False))) (defn test-do [] "NATIVE: test do" (do)) (defn test-bare-try [] (try (try (raise ValueError)) (except [ValueError]) (else (assert False)))) (defn test-exceptions [] "NATIVE: test Exceptions" (try) (try (do)) (try (do)) (try (do) (except)) (try (do) (except [IOError]) (except)) ;; Test correct (raise) (let [passed False] (try (try (raise IndexError) (except [IndexError] (raise))) (except [IndexError] (setv passed True))) (assert passed)) ;; Test incorrect (raise) (let [passed False] (try (raise) ;; Python 2 raises TypeError ;; Python 3 raises RuntimeError (except [[TypeError RuntimeError]] (setv passed True))) (assert passed)) ;; Test (finally) (let [passed False] (try (do) (finally (setv passed True))) (assert passed)) ;; Test (finally) + (raise) (let [passed False] (try (raise Exception) (except) (finally (setv passed True))) (assert passed)) ;; Test (finally) + (raise) + (else) (let [passed False not-elsed True] (try (raise Exception) (except) (else (setv not-elsed False)) (finally (setv passed True))) (assert passed) (assert not-elsed)) (try (raise (KeyError)) (except [[IOError]] (assert False)) (except [e [KeyError]] (assert e))) (try (raise (KeyError)) (except [[IOError]] (assert False)) (except [e [KeyError]] (assert e))) (try (get [1] 3) (except [IndexError] (assert True)) (except [IndexError] (do))) (try (print foobar42ofthebaz) (except [IndexError] (assert False)) (except [NameError] (do))) (try (get [1] 3) (except [e IndexError] (assert (isinstance e IndexError)))) (try (get [1] 3) (except [e [IndexError NameError]] (assert (isinstance e IndexError)))) (try (print foobar42ofthebaz) (except [e [IndexError NameError]] (assert (isinstance e NameError)))) (try (print foobar42) (except [[IndexError NameError]] (do))) (try (get [1] 3) (except [[IndexError NameError]] (do))) (try (print foobar42ofthebaz) (except)) (try (print foobar42ofthebaz) (except [])) (try (print foobar42ofthebaz) (except [] (do))) (try (print foobar42ofthebaz) (except [] (setv foobar42ofthebaz 42) (assert (= foobar42ofthebaz 42)))) (let [passed False] (try (try (do) (except) (else (bla))) (except [NameError] (setv passed True))) (assert passed)) (let [x 0] (try (raise IOError) (except [IOError] (setv x 45)) (else (setv x 44))) (assert (= x 45))) (let [x 0] (try (raise KeyError) (except [] (setv x 45)) (else (setv x 44))) (assert (= x 45))) (let [x 0] (try (try (raise KeyError) (except [IOError] (setv x 45)) (else (setv x 44))) (except)) (assert (= x 0)))) (defn test-earmuffs [] "NATIVE: Test earmuffs" (setv *foo* "2") (setv foo "3") (assert (= *foo* FOO)) (assert (!= *foo* foo))) (defn test-threading [] "NATIVE: test threading macro" (assert (= (-> (.upper "a b c d") (.replace "A" "X") (.split)) ["X" "B" "C" "D"]))) (defn test-tail-threading [] "NATIVE: test tail threading macro" (assert (= (.join ", " (* 10 ["foo"])) (->> ["foo"] (* 10) (.join ", "))))) (defn test-threading-two [] "NATIVE: test threading macro" (assert (= (-> "a b c d" .upper (.replace "A" "X") .split) ["X" "B" "C" "D"]))) (defn test-as-threading [] "NATIVE: test as threading macro" (setv data [{:name "hooded cuttlefish" :classification {:subgenus "Acanthosepion" :species "Sepia prashadi"} :discovered {:year 1936 :name "Ronald Winckworth"}} {:name "slender cuttlefish" :classification {:subgenus "Doratosepion" :species "Sepia braggi"} :discovered {:year 1907 :name "Sir Joseph Cooke Verco"}}]) (assert (= (as-> (first data) x (:name x)) "hooded cuttlefish")) (assert (= (as-> (filter (fn [entry] (= (:name entry) "slender cuttlefish")) data) x (first x) (:discovered x) (:name x)) "Sir Joseph Cooke Verco"))) (defn test-assoc [] "NATIVE: test assoc" (setv vals {"one" "two"}) (assoc vals "two" "three") (assert (= (get vals "two") "three"))) (defn test-multiassoc [] "NATIVE: test assoc multiple values" (setv vals {"one" "two"}) (assoc vals "two" "three" "four" "five") (assert (and (= (get vals "two") "three") (= (get vals "four") "five") (= (get vals "one") "two")))) (defn test-pass [] "NATIVE: Test pass worksish" (if True (do) (do)) (assert (= 1 1))) (defn test-yield [] "NATIVE: test yielding" (defn gen [] (for [x [1 2 3 4]] (yield x))) (setv ret 0) (for [y (gen)] (setv ret (+ ret y))) (assert (= ret 10))) (defn test-yield-with-return [] "NATIVE: test yield with return" (defn gen [] (yield 3) "goodbye") (if PY33 (do (setv gg (gen)) (assert (= 3 (next gg))) (try (next gg) (except [e StopIteration] (assert (hasattr e "value")) (assert (= (getattr e "value") "goodbye"))))) (do (setv gg (gen)) (assert (= 3 (next gg))) (try (next gg) (except [e StopIteration] (assert (not (hasattr e "value")))))))) (defn test-yield-in-try [] "NATIVE: test yield in try" (defn gen [] (let [x 1] (try (yield x) (finally (print x))))) (setv output (list (gen))) (assert (= [1] output))) (defn test-first [] "NATIVE: test firsty things" (assert (= (first [1 2 3 4 5]) 1)) (assert (is (first []) None)) (assert (= (car [1 2 3 4 5]) 1))) (defn test-cut [] "NATIVE: test cut" (assert (= (cut [1 2 3 4 5] 1) [2 3 4 5])) (assert (= (cut [1 2 3 4 5] 1 3) [2 3])) (assert (= (cut [1 2 3 4 5]) [1 2 3 4 5]))) (defn test-take [] "NATIVE: test take" (assert (= (take 0 [2 3]) [])) (assert (= (take 1 [2 3]) [2])) (assert (= (take 2 [2 3]) [2 3]))) (defn test-drop [] "NATIVE: test drop" (assert (= (list (drop 0 [2 3])) [2 3])) (assert (= (list (drop 1 [2 3])) [3])) (assert (= (list (drop 2 [2 3])) []))) (defn test-rest [] "NATIVE: test rest" (assert (= (list (rest [1 2 3 4 5])) [2 3 4 5]))) (defn test-importas [] "NATIVE: test import as" (assert (!= (len systest.path) 0))) (defn test-context [] "NATIVE: test with" (with [fd (open "README.md" "r")] (assert fd)) (with [(open "README.md" "r")] (do))) (defn test-with-return [] "NATIVE: test that with returns stuff" (defn read-file [filename] (with [fd (open filename "r")] (.read fd))) (assert (!= 0 (len (read-file "README.md"))))) (defn test-for-doodle [] "NATIVE: test for-do" (do (do (do (do (do (do (do (do (do (setv (, x y) (, 0 0))))))))))) (for [- [1 2]] (do (setv x (+ x 1)) (setv y (+ y 1)))) (assert (= y x 2))) (defn test-for-else [] "NATIVE: test for else" (let [x 0] (for* [a [1 2]] (setv x (+ x a)) (else (setv x (+ x 50)))) (assert (= x 53))) (let [x 0] (for* [a [1 2]] (setv x (+ x a)) (else)) (assert (= x 3)))) (defn test-list-comprehensions [] "NATIVE: test list comprehensions" (assert (= (list-comp (* x 2) (x (range 2))) [0 2])) (assert (= (list-comp (* x 2) (x (range 4)) (% x 2)) [2 6])) (assert (= (sorted (list-comp (* y 2) ((, x y) (.items {"1" 1 "2" 2})))) [2 4])) (assert (= (list-comp (, x y) (x (range 2) y (range 2))) [(, 0 0) (, 0 1) (, 1 0) (, 1 1)])) (assert (= (list-comp j (j [1 2])) [1 2]))) (defn test-set-comprehensions [] "NATIVE: test set comprehensions" (assert (instance? set (set-comp x [x (range 2)]))) (assert (= (set-comp (* x 2) (x (range 2))) (set [0 2]))) (assert (= (set-comp (* x 2) (x (range 4)) (% x 2)) (set [2 6]))) (assert (= (set-comp (* y 2) ((, x y) (.items {"1" 1 "2" 2}))) (set [2 4]))) (assert (= (set-comp (, x y) (x (range 2) y (range 2))) (set [(, 0 0) (, 0 1) (, 1 0) (, 1 1)]))) (assert (= (set-comp j (j [1 2])) (set [1 2])))) (defn test-dict-comprehensions [] "NATIVE: test dict comprehensions" (assert (instance? dict (dict-comp x x [x (range 2)]))) (assert (= (dict-comp x (* x 2) (x (range 2))) {1 2 0 0})) (assert (= (dict-comp x (* x 2) (x (range 4)) (% x 2)) {3 6 1 2})) (assert (= (dict-comp x (* y 2) ((, x y) (.items {"1" 1 "2" 2}))) {"2" 4 "1" 2})) (assert (= (dict-comp (, x y) (+ x y) (x (range 2) y (range 2))) {(, 0 0) 0 (, 1 0) 1 (, 0 1) 1 (, 1 1) 2}))) (defn test-generator-expressions [] "NATIVE: test generator expressions" (assert (not (instance? list (genexpr x [x (range 2)])))) (assert (= (list (genexpr (* x 2) (x (range 2)))) [0 2])) (assert (= (list (genexpr (* x 2) (x (range 4)) (% x 2))) [2 6])) (assert (= (list (sorted (genexpr (* y 2) ((, x y) (.items {"1" 1 "2" 2}))))) [2 4])) (assert (= (list (genexpr (, x y) (x (range 2) y (range 2)))) [(, 0 0) (, 0 1) (, 1 0) (, 1 1)])) (assert (= (list (genexpr j (j [1 2]))) [1 2]))) (defn test-defn-order [] "NATIVE: test defn evaluation order" (setv acc []) (defn my-fun [] (.append acc "Foo") (.append acc "Bar") (.append acc "Baz")) (my-fun) (assert (= acc ["Foo" "Bar" "Baz"]))) (defn test-defn-return [] "NATIVE: test defn return" (defn my-fun [x] (+ x 1)) (assert (= 43 (my-fun 42)))) (defn test-defn-lambdakey [] "NATIVE: test defn with a &symbol function name" (defn &hy [] 1) (assert (= (&hy) 1))) (defn test-defn-do [] "NATIVE: test defn evaluation order with do" (setv acc []) (defn my-fun [] (do (.append acc "Foo") (.append acc "Bar") (.append acc "Baz"))) (my-fun) (assert (= acc ["Foo" "Bar" "Baz"]))) (defn test-defn-do-return [] "NATIVE: test defn return with do" (defn my-fun [x] (do (+ x 42) ; noop (+ x 1))) (assert (= 43 (my-fun 42)))) (defn test-mangles [] "NATIVE: test mangles" (assert (= 2 ((fn [] (+ 1 1)))))) (defn test-fn-return [] "NATIVE: test function return" (setv fn-test ((fn [] (fn [] (+ 1 1))))) (assert (= (fn-test) 2)) (setv fn-test (fn [])) (assert (= (fn-test) None))) (defn test-let [] "NATIVE: test let works rightish" ;; TODO: test sad paths for let (assert (= (let [x 1 y 2 z 3] (+ x y z)) 6)) (assert (= (let [x 1 a None y 2 b None] (if a 1 2)) 2)) (assert (= (let [x None] x) None)) (assert (= (let [x "x not bound"] (setv x "x bound by setv") x) "x bound by setv")) (assert (= (let [x "let nests scope correctly"] (let [y None] x)) "let nests scope correctly")) (assert (= (let [x 999999] (let [x "x being rebound"] x)) "x being rebound")) (assert (= (let [x "x not being rebound"] (let [x 2] None) x) "x not being rebound")) (assert (= (let [x (set [3 2 1 3 2]) y x z y] z) (set [1 2 3]))) (import math) (let [cos math.cos foo-cos (fn [x] (cos x))] (assert (= (cos math.pi) -1.0)) (assert (= (foo-cos (- math.pi)) -1.0)) (let [cos (fn [_] "cos has been locally rebound")] (assert (= (cos cos) "cos has been locally rebound")) (assert (= (-> math.pi (/ 3) foo-cos (round 2)) 0.5))) (setv cos (fn [_] "cos has been rebound by setv")) (assert (= (foo-cos foo-cos) "cos has been rebound by setv")))) (defn test-if-mangler [] "NATIVE: test that we return ifs" (assert (= True (if True True True)))) (defn test-nested-mangles [] "NATIVE: test that we can use macros in mangled code" (assert (= ((fn [] (-> 2 (+ 1 1) (* 1 2)))) 8))) (defn test-let-scope [] "NATIVE: test let works rightish" (setv y 123) (assert (= (let [x 1 y 2 z 3] (+ x y z)) 6)) (try (assert (= x 42)) ; This ain't true (except [e [NameError]] (assert e))) (assert (= y 123))) (defn test-symbol-utf-8 [] "NATIVE: test symbol encoded" (let [♥ "love" ⚘ "flower"] (assert (= (+ ⚘ ♥) "flowerlove")))) (defn test-symbol-dash [] "NATIVE: test symbol encoded" (let [♥-♥ "doublelove" -_- "what?"] (assert (= ♥-♥ "doublelove")) (assert (= -_- "what?")))) (defn test-symbol-question-mark [] "NATIVE: test foo? -> is_foo behavior" (let [foo? "nachos"] (assert (= is_foo "nachos")))) (defn test-and [] "NATIVE: test the and function" (let [and123 (and 1 2 3) and-false (and 1 False 3) and-true (and) and-single (and 1)] (assert (= and123 3)) (assert (= and-false False)) (assert (= and-true True)) (assert (= and-single 1))) ; short circuiting (setv a 1) (and 0 (setv a 2)) (assert (= a 1))) (defn test-and-#1151-do [] (setv a (and 0 (do 2 3))) (assert (= a 0)) (setv a (and 1 (do 2 3))) (assert (= a 3))) (defn test-and-#1151-for [] (setv l []) (setv x (and 0 (for [n [1 2]] (.append l n)))) (assert (= x 0)) (assert (= l [])) (setv x (and 15 (for [n [1 2]] (.append l n)))) (assert (= l [1 2]))) (defn test-and-#1151-del [] (setv l ["a" "b"]) (setv x (and 0 (del (get l 1)))) (assert (= x 0)) (assert (= l ["a" "b"])) (setv x (and 15 (del (get l 1)))) (assert (= l ["a"]))) (defn test-or [] "NATIVE: test the or function" (let [or-all-true (or 1 2 3 True "string") or-some-true (or False "hello") or-none-true (or False False) or-false (or) or-single (or 1)] (assert (= or-all-true 1)) (assert (= or-some-true "hello")) (assert (= or-none-true False)) (assert (= or-false None)) (assert (= or-single 1))) ; short circuiting (setv a 1) (or 1 (setv a 2)) (assert (= a 1))) (defn test-or-#1151-do [] (setv a (or 1 (do 2 3))) (assert (= a 1)) (setv a (or 0 (do 2 3))) (assert (= a 3))) (defn test-or-#1151-for [] (setv l []) (setv x (or 15 (for [n [1 2]] (.append l n)))) (assert (= x 15)) (assert (= l [])) (setv x (or 0 (for [n [1 2]] (.append l n)))) (assert (= l [1 2]))) (defn test-or-#1151-del [] (setv l ["a" "b"]) (setv x (or 15 (del (get l 1)))) (assert (= x 15)) (assert (= l ["a" "b"])) (setv x (or 0 (del (get l 1)))) (assert (= l ["a"]))) (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 (assert (= 1 (let [x 1 y 2] (if True 2) 1))) (assert (= 1 (let [x 1 y 2] (do) (do) ((fn [] 1)))))) (defn test-keyword [] "NATIVE: test if keywords are recognised" (assert (= :foo :foo)) (assert (= (get {:foo "bar"} :foo) "bar")) (assert (= (get {:bar "quux"} (get {:foo :bar} :foo)) "quux"))) (defn test-keyword-clash [] "NATIVE: test that keywords do not clash with normal strings" (assert (= (get {:foo "bar" ":foo" "quux"} :foo) "bar")) (assert (= (get {:foo "bar" ":foo" "quux"} ":foo") "quux"))) (defn test-empty-keyword [] "NATIVE: test that the empty keyword is recognized" (assert (= : :)) (assert (keyword? :)) (assert (!= : ":")) (assert (= (name :) "")) (defn f [&kwargs kwargs] (list (.items kwargs))) (assert (= (f : 3) [(, "" 3)]))) (defn test-nested-if [] "NATIVE: test nested if" (for [x (range 10)] (if (in "foo" "foobar") (do (if True True True)) (do (if False False False))))) (defn test-eval [] "NATIVE: test eval" (assert (= 2 (eval (quote (+ 1 1))))) (setv x 2) (assert (= 4 (eval (quote (+ x 2))))) (setv test-payload (quote (+ x 2))) (setv x 4) (assert (= 6 (eval test-payload))) (assert (= 9 ((eval (quote (fn [x] (+ 3 3 x)))) 3))) (assert (= 1 (eval (quote 1)))) (assert (= "foobar" (eval (quote "foobar")))) (setv x (quote 42)) (assert (= x (eval x))) (assert (= 27 (eval (+ (quote (*)) (* [(quote 3)] 3))))) (assert (= None (eval (quote (print "")))))) (defn test-eval-globals [] "NATIVE: test eval with explicit global dict" (assert (= 'bar (eval (quote foo) {'foo 'bar}))) (assert (= 1 (let [d {}] (eval '(setv x 1) d) (eval (quote x) d)))) (let [d1 {} d2 {}] (eval '(setv x 1) d1) (try (do ; this should fail with a name error (eval (quote x) d2) (assert False "We shouldn't have arrived here")) (except [e Exception] (assert (isinstance e NameError)))))) (defn test-eval-failure [] "NATIVE: test eval failure modes" ; yo dawg (try (eval '(eval)) (except [e HyTypeError]) (else (assert False))) (try (eval '(eval "snafu")) (except [e HyTypeError]) (else (assert False))) (try (eval 'False []) (except [e HyTypeError]) (else (assert False))) (try (eval 'False {} 1) (except [e HyTypeError]) (else (assert False)))) (defn test-import-syntax [] "NATIVE: test the import syntax." ;; Simple import (import sys os) ;; from os.path import basename (import [os.path [basename]]) (assert (= (basename "/some/path") "path")) ;; import os.path as p (import [os.path :as p]) (assert (= p.basename basename)) ;; from os.path import basename as bn (import [os.path [basename :as bn]]) (assert (= bn basename)) (import [sys]) ;; Multiple stuff to import (import sys [os.path [dirname]] [os.path :as op] [os.path [dirname :as dn]]) (assert (= (dirname "/some/path") "/some")) (assert (= op.dirname dirname)) (assert (= dn dirname))) (defn test-lambda-keyword-lists [] "NATIVE: test lambda keyword lists" (defn foo (x &rest xs &kwargs kw) [x xs kw]) (assert (= (foo 10 20 30) [10 (, 20 30) {}]))) (defn test-key-arguments [] "NATIVE: test &key function arguments" (defn foo [&key {"a" None "b" 1}] [a b]) (assert (= (foo) [None 1])) (assert (= (apply foo [] {"a" 2}) [2 1])) (assert (= (apply foo [] {"b" 42}) [None 42]))) (defn test-optional-arguments [] "NATIVE: test &optional function arguments" (defn foo [a b &optional c [d 42]] [a b c d]) (assert (= (foo 1 2) [1 2 None 42])) (assert (= (foo 1 2 3) [1 2 3 42])) (assert (= (foo 1 2 3 4) [1 2 3 4]))) (defn test-undefined-name [] "NATIVE: test that undefined names raise errors" (try (do xxx (assert False)) (except [NameError]))) (defn test-if-let-mixing [] "NATIVE: test that we can now mix if and let" (assert (= 0 (if True (let [x 0] x) 42)))) (defn test-if-in-if [] "NATIVE: test that we can use if in if" (assert (= 42 (if (if 1 True False) 42 43))) (assert (= 43 (if (if 0 True False) 42 43)))) (defn test-try-except-return [] "NATIVE: test we can return from in a try except" (assert (= ((fn [] (try xxx (except [NameError] (+ 1 1))))) 2)) (setv foo (try xxx (except [NameError] (+ 1 1)))) (assert (= foo 2)) (setv foo (try (+ 2 2) (except [NameError] (+ 1 1)))) (assert (= foo 4))) (defn test-require [] "NATIVE: test requiring macros from python code" (try (qplah 1 2 3 4) (except [NameError] True) (else (assert False))) (try (parald 1 2 3 4) (except [NameError] True) (else (assert False))) (require [tests.resources.tlib [qplah]]) (assert (= (qplah 1 2 3) [8 1 2 3])) (try (parald 1 2 3 4) (except [NameError] True) (else (assert False))) (require tests.resources.tlib) (assert (= (tests.resources.tlib.parald 1 2 3) [9 1 2 3])) (try (parald 1 2 3 4) (except [NameError] True) (else (assert False))) (require [tests.resources.tlib :as T]) (assert (= (T.parald 1 2 3) [9 1 2 3])) (try (parald 1 2 3 4) (except [NameError] True) (else (assert False))) (require [tests.resources.tlib [parald :as p]]) (assert (= (p 1 2 3) [9 1 2 3])) (try (parald 1 2 3 4) (except [NameError] True) (else (assert False))) (require [tests.resources.tlib [*]]) (assert (= (parald 1 2 3) [9 1 2 3]))) (defn test-require-native [] "NATIVE: test requiring macros from native code" (assert (= "failure" (try (do (setv x []) (rev (.append x 1) (.append x 2) (.append x 3)) (assert (= x [3 2 1])) "success") (except [NameError] "failure")))) (import tests.native_tests.native_macros) (assert (= "failure" (try (do (setv x []) (rev (.append x 1) (.append x 2) (.append x 3)) (assert (= x [3 2 1])) "success") (except [NameError] "failure")))) (require [tests.native_tests.native_macros [rev]]) (assert (= "success" (try (do (setv x []) (rev (.append x 1) (.append x 2) (.append x 3)) (assert (= x [3 2 1])) "success") (except [NameError] "failure"))))) (defn test-encoding-nightmares [] "NATIVE: test unicode encoding escaping crazybits" (assert (= (len "ℵℵℵ♥♥♥\t♥♥\r\n") 11))) (defn test-keyword-dict-access [] "NATIVE: test keyword dict access" (assert (= "test" (:foo {:foo "test"})))) (defn test-take [] "NATIVE: test the take operator" (assert (= [1 2 3] (list (take 3 [1 2 3])))) (assert (= [1 2 3] (list (take 4 [1 2 3])))) (assert (= [1 2] (list (take 2 [1 2 4]))))) (defn test-break-breaking [] "NATIVE: test checking if break actually breaks" (defn holy-grail [] (for [x (range 10)] (if (= x 5) (break))) x) (assert (= (holy-grail) 5))) (defn test-continue-continuation [] "NATIVE: test checking if continue actually continues" (setv y []) (for [x (range 10)] (if (!= x 5) (continue)) (.append y x)) (assert (= y [5]))) (defn test-empty-list [] "Evaluate an empty list to a []" (assert (= () []))) (defn test-string [] (assert (string? (string "a"))) (assert (string? (string 1))) (assert (= u"unicode" (string "unicode")))) (defn test-del [] "NATIVE: Test the behavior of del" (setv foo 42) (assert (= foo 42)) (del foo) (assert (= 'good (try (do foo 'bad) (except [NameError] 'good)))) (setv test (list (range 5))) (del (get test 4)) (assert (= test [0 1 2 3])) (del (get test 2)) (assert (= test [0 1 3])) (assert (= (del) None))) (defn test-macroexpand [] "Test macroexpand on ->" (assert (= (macroexpand '(-> (a b) (x y))) '(x (a b) y))) (assert (= (macroexpand '(-> (a b) (-> (c d) (e f)))) '(e (c (a b) d) f)))) (defn test-macroexpand-1 [] "Test macroexpand-1 on ->" (assert (= (macroexpand-1 '(-> (a b) (-> (c d) (e f)))) '(-> (a b) (c d) (e f))))) (defn test-merge-with [] "NATIVE: test merge-with" (assert (= (merge-with + {} {}) None)) (assert (= (merge-with + {"a" 10 "b" 20} {}) {"a" 10 "b" 20})) (assert (= (merge-with + {} {"a" 10 "b" 20}) {"a" 10 "b" 20})) (assert (= (merge-with + {"a" 10 "b" 20} {"a" 1 "c" 30}) {"a" 11 "b" 20 "c" 30})) (assert (= (merge-with + {:a 1 :b 2} {:a 9 :b 98 :c 0} {:a 10 :b 100 :c 10} {:a 5} {:c 5 :d 42}) {:d 42 :c 15 :a 25 :b 200})) (assert (= (merge-with or_ {"a" (set [1 2 3]) "b" (set [4 5 6])} {"a" (set [2 3 7 8]) "c" (set [1 2 3])}) {"a" (set [1 2 3 7 8]) "c" (set [1 2 3]) "b" (set [4 5 6])}))) (defn test-calling-module-name [] "NATIVE: Test the calling-module-name function" (assert (= (calling-module-name -1) "hy.core.language")) (assert (= (calling-module-name 0) "tests.native_tests.language"))) (defn test-disassemble [] "NATIVE: Test the disassemble function" (if PY35 (assert (= (disassemble '(do (leaky) (leaky) (macros))) "Module(\n body=[Expr(value=Call(func=Name(id='leaky'), args=[], keywords=[])),\n Expr(value=Call(func=Name(id='leaky'), args=[], keywords=[])),\n Expr(value=Call(func=Name(id='macros'), args=[], keywords=[]))])")) (assert (= (disassemble '(do (leaky) (leaky) (macros))) "Module(\n body=[\n Expr(value=Call(func=Name(id='leaky'), args=[], keywords=[], starargs=None, kwargs=None)),\n Expr(value=Call(func=Name(id='leaky'), args=[], keywords=[], starargs=None, kwargs=None)),\n Expr(value=Call(func=Name(id='macros'), args=[], keywords=[], starargs=None, kwargs=None))])"))) (assert (= (disassemble '(do (leaky) (leaky) (macros)) True) "leaky()\nleaky()\nmacros()"))) (defn test-attribute-access [] "NATIVE: Test the attribute access DSL" (defclass mycls [object]) (setv foo [(mycls) (mycls) (mycls)]) (assert (is (. foo) foo)) (assert (is (. foo [0]) (get foo 0))) (assert (is (. foo [0] --class--) mycls)) (assert (is (. foo [1] --class--) mycls)) (assert (is (. foo [(+ 1 1)] --class--) mycls)) (assert (= (. foo [(+ 1 1)] --class-- --name-- [0]) "m")) (assert (= (. foo [(+ 1 1)] --class-- --name-- [1]) "y")) (setv bar (mycls)) (setv (. foo [1]) bar) (assert (is bar (get foo 1))) (setv (. foo [1] test) "hello") (assert (= (getattr (. foo [1]) "test") "hello"))) (defn test-keyword-quoting [] "NATIVE: test keyword quoting magic" (assert (= :foo "\ufdd0:foo")) (assert (= `:foo "\ufdd0:foo"))) (defn test-only-parse-lambda-list-in-defn [] "NATIVE: test lambda lists are only parsed in defn" (try (foo [&rest spam] 1) (except [NameError] True) (else (raise AssertionError)))) (defn test-read [] "NATIVE: test that read takes something for stdin and reads" (if-python2 (import [StringIO [StringIO]]) (import [io [StringIO]])) (import [hy.models.expression [HyExpression]]) (def stdin-buffer (StringIO "(+ 2 2)\n(- 2 2)")) (assert (= (eval (read stdin-buffer)) 4)) (assert (isinstance (read stdin-buffer) HyExpression)) "Multiline test" (def stdin-buffer (StringIO "(\n+\n41\n1\n)\n(-\n2\n1\n)")) (assert (= (eval (read stdin-buffer)) 42)) (assert (= (eval (read stdin-buffer)) 1)) "EOF test" (def stdin-buffer (StringIO "(+ 2 2)")) (read stdin-buffer) (try (read stdin-buffer) (except [e Exception] (assert (isinstance e EOFError))))) (defn test-read-str [] "NATIVE: test read-str" (assert (= (read-str "(print 1)") '(print 1)))) (defn test-keyword-creation [] "NATIVE: Test keyword creation" (assert (= (keyword "foo") :foo)) (assert (= (keyword "foo_bar") :foo-bar)) (assert (= (keyword `foo) :foo)) (assert (= (keyword `foo-bar) :foo-bar)) (assert (= (keyword 'foo) :foo)) (assert (= (keyword 'foo-bar) :foo-bar)) (assert (= (keyword 1) :1)) (assert (= (keyword 1.0) :1.0)) (assert (= (keyword :foo_bar) :foo-bar))) (defn test-name-conversion [] "NATIVE: Test name conversion" (assert (= (name "foo") "foo")) (assert (= (name "foo_bar") "foo-bar")) (assert (= (name `foo) "foo")) (assert (= (name `foo_bar) "foo-bar")) (assert (= (name 'foo) "foo")) (assert (= (name 'foo_bar) "foo-bar")) (assert (= (name 1) "1")) (assert (= (name 1.0) "1.0")) (assert (= (name :foo) "foo")) (assert (= (name :foo_bar) "foo-bar")) (assert (= (name test-name-conversion) "test-name-conversion"))) (defn test-keywords [] "Check keyword use in function calls" (assert (= (kwtest) {})) (assert (= (kwtest :key "value") {"key" "value"})) (assert (= (kwtest :key-with-dashes "value") {"key_with_dashes" "value"})) (assert (= (kwtest :result (+ 1 1)) {"result" 2})) (assert (= (kwtest :key (kwtest :key2 "value")) {"key" {"key2" "value"}})) (assert (= ((get (kwtest :key (fn [x] (* x 2))) "key") 3) 6))) (defmacro identify-keywords [&rest elts] `(list (map (lambda (x) (if (is-keyword x) "keyword" "other")) ~elts))) (defn test-keywords-and-macros [] "Macros should still be able to handle keywords as they best see fit." (assert (= (identify-keywords 1 "bloo" :foo) ["other" "other" "keyword"]))) (defn test-argument-destr [] "Make sure argument destructuring works" (defn f [[a b] [c]] (, a b c)) (assert (= (f [1 2] [3]) (, 1 2 3)))) hy-0.12.1/tests/native_tests/mathematics.hy000066400000000000000000000121131304171765200207320ustar00rootroot00000000000000(import [hy._compat [PY35]]) (setv square (fn [x] (* x x))) (setv test_basic_math (fn [] "NATIVE: Test basic math." (assert (= (+ 2 2) 4)))) (setv test_mult (fn [] "NATIVE: Test multiplication." (assert (= 4 (square 2))) (assert (= 8 (* 8))) (assert (= 1 (*))))) (setv test_sub (fn [] "NATIVE: Test subtraction" (assert (= 4 (- 8 4))) (assert (= -8 (- 8))))) (setv test_add (fn [] "NATIVE: Test addition" (assert (= 4 (+ 1 1 1 1))) (assert (= 8 (+ 8))) (assert (= 0 (+))))) (defn test-add-unary [] "NATIVE: test that unary + calls __pos__" (defclass X [object] [__pos__ (fn [self] "called __pos__")]) (assert (= (+ (X)) "called __pos__")) ; Make sure the shadowed version works, too. (setv f +) (assert (= (f (X)) "called __pos__"))) (setv test_div (fn [] "NATIVE: Test division" (assert (= 25 (/ 100 2 2))) ; Commented out until float constants get implemented ; (assert (= 0.5 (/ 1 2))) (assert (= 1 (* 2 (/ 1 2)))))) (setv test_int_div (fn [] "NATIVE: Test integer division" (assert (= 25 (// 101 2 2))))) (defn test-modulo [] "NATIVE: test mod" (assert (= (% 10 2) 0))) (defn test-pow [] "NATIVE: test pow" (assert (= (** 10 2) 100))) (defn test-lshift [] "NATIVE: test lshift" (assert (= (<< 1 2) 4))) (defn test-rshift [] "NATIVE: test lshift" (assert (= (>> 8 1) 4))) (defn test-bitor [] "NATIVE: test lshift" (assert (= (| 1 2) 3))) (defn test-bitxor [] "NATIVE: test xor" (assert (= (^ 1 2) 3))) (defn test-bitand [] "NATIVE: test lshift" (assert (= (& 1 2) 0))) (defn test-augassign-add [] "NATIVE: test augassign add" (let [x 1] (+= x 41) (assert (= x 42)))) (defn test-augassign-sub [] "NATIVE: test augassign sub" (let [x 1] (-= x 41) (assert (= x -40)))) (defn test-augassign-mult [] "NATIVE: test augassign mult" (let [x 1] (*= x 41) (assert (= x 41)))) (defn test-augassign-div [] "NATIVE: test augassign div" (let [x 42] (/= x 2) (assert (= x 21)))) (defn test-augassign-floordiv [] "NATIVE: test augassign floordiv" (let [x 42] (//= x 2) (assert (= x 21)))) (defn test-augassign-mod [] "NATIVE: test augassign mod" (let [x 42] (%= x 2) (assert (= x 0)))) (defn test-augassign-pow [] "NATIVE: test augassign pow" (let [x 2] (**= x 3) (assert (= x 8)))) (defn test-augassign-lshift [] "NATIVE: test augassign lshift" (let [x 2] (<<= x 2) (assert (= x 8)))) (defn test-augassign-rshift [] "NATIVE: test augassign rshift" (let [x 8] (>>= x 1) (assert (= x 4)))) (defn test-augassign-bitand [] "NATIVE: test augassign bitand" (let [x 8] (&= x 1) (assert (= x 0)))) (defn test-augassign-bitor [] "NATIVE: test augassign bitand" (let [x 0] (|= x 2) (assert (= x 2)))) (defn test-augassign-bitxor [] "NATIVE: test augassign bitand" (let [x 1] (^= x 1) (assert (= x 0)))) (defn overflow-int-to-long [] "NATIVE: test if int does not raise an overflow exception" (assert (integer? (+ 1 1000000000000000000000000)))) (defclass HyTestMatrix [list] [--matmul-- (fn [self other] (let [n (len self) m (len (. other [0])) result []] (for [i (range m)] (let [result-row []] (for [j (range n)] (let [dot-product 0] (for [k (range (len (. self [0])))] (+= dot-product (* (. self [i] [k]) (. other [k] [j])))) (.append result-row dot-product))) (.append result result-row))) result))]) (def first-test-matrix (HyTestMatrix [[1 2 3] [4 5 6] [7 8 9]])) (def second-test-matrix (HyTestMatrix [[2 0 0] [0 2 0] [0 0 2]])) (def product-of-test-matrices (HyTestMatrix [[ 2 4 6] [ 8 10 12] [14 16 18]])) (defn test-matmul [] "NATIVE: test matrix multiplication" (if PY35 (assert (= (@ first-test-matrix second-test-matrix) product-of-test-matrices)) ;; Python <= 3.4 (let [matmul-attempt (try (@ first-test-matrix second-test-matrix) (except [e [Exception]] e))] (assert (isinstance matmul-attempt NameError))))) (defn test-augassign-matmul [] "NATIVE: test augmented-assignment matrix multiplication" (let [matrix first-test-matrix matmul-attempt (try (@= matrix second-test-matrix) (except [e [Exception]] e))] (if PY35 (assert (= product-of-test-matrices matrix)) (assert (isinstance matmul-attempt NameError))))) hy-0.12.1/tests/native_tests/native_macros.hy000066400000000000000000000217311304171765200212730ustar00rootroot00000000000000(import [hy.errors [HyTypeError]]) (defmacro rev [&rest body] "Execute the `body` statements in reverse" (quasiquote (do (unquote-splice (list (reversed body)))))) (defn test-rev-macro [] "NATIVE: test stararged native macros" (setv x []) (rev (.append x 1) (.append x 2) (.append x 3)) (assert (= x [3 2 1]))) ; Macros returning constants (defmacro an-int [] 42) (assert (= (an-int) 42)) (defmacro a-true [] True) (assert (= (a-true) True)) (defmacro a-false [] False) (assert (= (a-false) False)) (defmacro a-float [] 42.) (assert (= (a-float) 42.)) (defmacro a-complex [] 42j) (assert (= (a-complex) 42j)) (defmacro a-string [] "foo") (assert (= (a-string) "foo")) (defmacro a-list [] [1 2]) (assert (= (a-list) [1 2])) (defmacro a-tuple [&rest b] b) (assert (= (a-tuple 1 2) [1 2])) (defmacro a-dict [] {1 2}) (assert (= (a-dict) {1 2})) (defmacro a-set [] #{1 2}) (assert (= (a-set) #{1 2})) (defmacro a-none []) (assert (= (a-none) None)) ; A macro calling a previously defined function (eval-when-compile (defn foo [x y] (quasiquote (+ (unquote x) (unquote y))))) (defmacro bar [x y] (foo x y)) (defn test-macro-kw [] "NATIVE: test that an error is raised when &kwonly, &kwargs, or &key is used in a macro" (try (eval '(defmacro f [&kwonly a b])) (except [e HyTypeError] (assert (= e.message "macros cannot use &kwonly"))) (else (assert False))) (try (eval '(defmacro f [&kwargs kw])) (except [e HyTypeError] (assert (= e.message "macros cannot use &kwargs"))) (else (assert False))) (try (eval '(defmacro f [&key {"kw" "xyz"}])) (except [e HyTypeError] (assert (= e.message "macros cannot use &key"))) (else (assert False)))) (defn test-fn-calling-macro [] "NATIVE: test macro calling a plain function" (assert (= 3 (bar 1 2)))) (defn test-midtree-yield [] "NATIVE: test yielding with a returnable" (defn kruft [] (yield) (+ 1 1))) (defn test-midtree-yield-in-for [] "NATIVE: test yielding in a for with a return" (defn kruft-in-for [] (for* [i (range 5)] (yield i)) (+ 1 2))) (defn test-midtree-yield-in-while [] "NATIVE: test yielding in a while with a return" (defn kruft-in-while [] (setv i 0) (while (< i 5) (yield i) (setv i (+ i 1))) (+ 2 3))) (defn test-multi-yield [] "NATIVE: testing multiple yields" (defn multi-yield [] (for* [i (range 3)] (yield i)) (yield "a") (yield "end")) (assert (= (list (multi-yield)) [0 1 2 "a" "end"]))) ; Macro that checks a variable defined at compile or load time (setv phase "load") (eval-when-compile (setv phase "compile")) (defmacro phase-when-compiling [] phase) (assert (= phase "load")) (assert (= (phase-when-compiling) "compile")) (setv initialized False) (eval-and-compile (setv initialized True)) (defmacro test-initialized [] initialized) (assert initialized) (assert (test-initialized)) (defn test-if-python2 [] (import sys) (assert (= (get sys.version_info 0) (if-python2 2 3)))) (defn test-gensym-in-macros [] (import ast) (import [astor.codegen [to_source]]) (import [hy.importer [import_buffer_to_ast]]) (setv macro1 "(defmacro nif [expr pos zero neg] (let [g (gensym)] `(let [~g ~expr] (cond [(pos? ~g) ~pos] [(zero? ~g) ~zero] [(neg? ~g) ~neg])))) (print (nif (inc -1) 1 0 -1)) ") ;; expand the macro twice, should use a different ;; gensym each time (setv _ast1 (import_buffer_to_ast macro1 "foo")) (setv _ast2 (import_buffer_to_ast macro1 "foo")) (setv s1 (to_source _ast1)) (setv s2 (to_source _ast2)) ;; and make sure there is something new that starts with :G_ (assert (in ":G_" s1)) (assert (in ":G_" s2)) ;; but make sure the two don't match each other (assert (not (= s1 s2)))) (defn test-with-gensym [] (import ast) (import [astor.codegen [to_source]]) (import [hy.importer [import_buffer_to_ast]]) (setv macro1 "(defmacro nif [expr pos zero neg] (with-gensyms [a] `(let [~a ~expr] (cond [(pos? ~a) ~pos] [(zero? ~a) ~zero] [(neg? ~a) ~neg])))) (print (nif (inc -1) 1 0 -1)) ") ;; expand the macro twice, should use a different ;; gensym each time (setv _ast1 (import_buffer_to_ast macro1 "foo")) (setv _ast2 (import_buffer_to_ast macro1 "foo")) (setv s1 (to_source _ast1)) (setv s2 (to_source _ast2)) (assert (in ":a_" s1)) (assert (in ":a_" s2)) (assert (not (= s1 s2)))) (defn test-defmacro-g! [] (import ast) (import [astor.codegen [to_source]]) (import [hy.importer [import_buffer_to_ast]]) (setv macro1 "(defmacro/g! nif [expr pos zero neg] `(let [~g!res ~expr] (cond [(pos? ~g!res) ~pos] [(zero? ~g!res) ~zero] [(neg? ~g!res) ~neg]))) (print (nif (inc -1) 1 0 -1)) ") ;; expand the macro twice, should use a different ;; gensym each time (setv _ast1 (import_buffer_to_ast macro1 "foo")) (setv _ast2 (import_buffer_to_ast macro1 "foo")) (setv s1 (to_source _ast1)) (setv s2 (to_source _ast2)) (assert (in ":res_" s1)) (assert (in ":res_" s2)) (assert (not (= s1 s2))) ;; defmacro/g! didn't like numbers initially because they ;; don't have a startswith method and blew up during expansion (setv macro2 "(defmacro/g! two-point-zero [] `(+ (float 1) 1.0))") (assert (import_buffer_to_ast macro2 "foo"))) (defn test-defmacro! [] ;; defmacro! must do everything defmacro/g! can (import ast) (import [astor.codegen [to_source]]) (import [hy.importer [import_buffer_to_ast]]) (setv macro1 "(defmacro! nif [expr pos zero neg] `(let [~g!res ~expr] (cond [(pos? ~g!res) ~pos] [(zero? ~g!res) ~zero] [(neg? ~g!res) ~neg]))) (print (nif (inc -1) 1 0 -1)) ") ;; expand the macro twice, should use a different ;; gensym each time (setv _ast1 (import_buffer_to_ast macro1 "foo")) (setv _ast2 (import_buffer_to_ast macro1 "foo")) (setv s1 (to_source _ast1)) (setv s2 (to_source _ast2)) (assert (in ":res_" s1)) (assert (in ":res_" s2)) (assert (not (= s1 s2))) ;; defmacro/g! didn't like numbers initially because they ;; don't have a startswith method and blew up during expansion (setv macro2 "(defmacro! two-point-zero [] `(+ (float 1) 1.0))") (assert (import_buffer_to_ast macro2 "foo")) (defmacro! foo! [o!foo] `(do ~g!foo ~g!foo)) ;; test that o! becomes g! (assert (= "Hy" (foo! "Hy"))) ;; test that o! is evaluated once only (setv foo 40) (foo! (+= foo 1)) (assert (= 41 foo))) (defn test-if-not [] (assert (= (if-not True :yes :no) :no)) (assert (= (if-not False :yes :no) :yes)) (assert (none? (if-not True :yes))) (assert (= (if-not False :yes) :yes))) (defn test-lif [] "test that lif works as expected" ;; None is false (assert (= (lif None "true" "false") "false")) ;; But everything else is True! Even falsey things. (assert (= (lif True "true" "false") "true")) (assert (= (lif False "true" "false") "true")) (assert (= (lif 0 "true" "false") "true")) (assert (= (lif "some-string" "true" "false") "true")) (assert (= (lif "" "true" "false") "true")) (assert (= (lif (+ 1 2 3) "true" "false") "true")) (assert (= (lif None "true" "false") "false")) (assert (= (lif 0 "true" "false") "true")) ;; Test ellif [sic] (assert (= (lif None 0 None 1 0 2 3) 2))) (defn test-lif-not [] "test that lif-not works as expected" ; None is false (assert (= (lif-not None "false" "true") "false")) ; But everything else is True! Even falsey things. (assert (= (lif-not True "false" "true") "true")) (assert (= (lif-not False "false" "true") "true")) (assert (= (lif-not 0 "false" "true") "true")) (assert (= (lif-not "some-string" "false" "true") "true")) (assert (= (lif-not "" "false" "true") "true")) (assert (= (lif-not (+ 1 2 3) "false" "true") "true")) (assert (= (lif-not None "false" "true") "false")) (assert (= (lif-not 0 "false" "true") "true"))) (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]))) (defn test-yield-from-exception-handling [] "NATIVE: Ensure exception handling in yield from works right" (defn yield-from-subgenerator-test [] (yield 1) (yield 2) (yield 3) (assert 0)) (defn yield-from-test [] (for* [i (range 3)] (yield i)) (try (yield-from (yield-from-subgenerator-test)) (except [e AssertionError] (yield 4)))) (assert (= (list (yield-from-test)) [0 1 2 1 2 3 4]))) (defn test-defmain [] "NATIVE: make sure defmain is clean" (global --name--) (setv oldname --name--) (setv --name-- "__main__") (defn main [] (print 'Hy) 42) (try (defmain [&rest args] (main)) (except [e SystemExit] (assert (= (str e) "42")))) (setv --name-- oldname)) hy-0.12.1/tests/native_tests/py3_only_tests.hy000066400000000000000000000027661304171765200214460ustar00rootroot00000000000000;; Tests where the emitted code relies on Python 3. ;; Conditionally included in nosetests runs. (import [hy._compat [PY33]]) (import [hy.errors [HyCompileError]]) (defn test-exception-cause [] (try (raise ValueError :from NameError) (except [e [ValueError]] (assert (= (type (. e __cause__)) NameError))))) (defn test-kwonly [] "NATIVE: test keyword-only arguments" ;; keyword-only with default works (let [kwonly-foo-default-false (fn [&kwonly [foo False]] foo)] (assert (= (apply kwonly-foo-default-false) False)) (assert (= (apply kwonly-foo-default-false [] {"foo" True}) True))) ;; keyword-only without default ... (let [kwonly-foo-no-default (fn [&kwonly foo] foo) attempt-to-omit-default (try (kwonly-foo-no-default) (except [e [Exception]] e))] ;; works (assert (= (apply kwonly-foo-no-default [] {"foo" "quux"}) "quux")) ;; raises TypeError with appropriate message if not supplied (assert (isinstance attempt-to-omit-default TypeError)) (assert (in "missing 1 required keyword-only argument: 'foo'" (. attempt-to-omit-default args [0])))) ;; keyword-only with other arg types works (let [function-of-various-args (fn [a b &rest args &kwonly foo &kwargs kwargs] (, a b args foo kwargs))] (assert (= (apply function-of-various-args [1 2 3 4] {"foo" 5 "bar" 6 "quux" 7}) (, 1 2 (, 3 4) 5 {"bar" 6 "quux" 7}))))) hy-0.12.1/tests/native_tests/quote.hy000066400000000000000000000045111304171765200175730ustar00rootroot00000000000000(import hy) (defn test-quote [] "NATIVE: test for quoting functionality" (setv q (quote (a b c))) (assert (= (len q) 3)) (assert (= q [(quote a) (quote b) (quote c)]))) (defn test-quoted-hoistable [] "NATIVE: check whether quote works on hoisted things" (setv f (quote (if True True True))) (assert (= (car f) (quote if))) (assert (= (cdr f) (quote (True True True))))) (defn test-quoted-macroexpand [] "NATIVE: check that we don't expand macros in quoted expressions" (setv q1 (quote (-> a b c))) (setv q2 (quasiquote (-> a b c))) (assert (= q1 q2)) (assert (= (car q1) (quote ->))) (assert (= (cdr q1) (quote (a b c))))) (defn test-quote-dicts [] "NATIVE: test quoting dicts" (setv q (quote {foo bar baz quux})) (assert (= (len q) 4)) (assert (= (get q 0) (quote foo))) (assert (= (get q 1) (quote bar))) (assert (= (get q 2) (quote baz))) (assert (= (get q 3) (quote quux))) (assert (= (type q) hy.HyDict))) (defn test-quote-expr-in-dict [] "NATIVE: test quoting nested exprs in dict" (setv q (quote {(foo bar) 0})) (assert (= (len q) 2)) (setv qq (get q 0)) (assert (= qq (quote (foo bar))))) (defn test-quasiquote [] "NATIVE: test that quasiquote and quote are equivalent for simple cases" (setv q (quote (a b c))) (setv qq (quasiquote (a b c))) (assert (= q qq))) (defn test-unquote [] "NATIVE: test that unquote works as expected" (setv q (quote (unquote foo))) (assert (= (len q) 2)) (assert (= (get q 1) (quote foo))) (setv qq (quasiquote (a b c (unquote (+ 1 2))))) (assert (= (len qq) 4)) (assert (= qq (quote (a b c 3))))) (defn test-unquote-splice [] "NATIVE: test splicing unquotes" (setv q (quote (c d e))) (setv qq (quasiquote (a b (unquote-splice q) f (unquote-splice q)))) (assert (= (len qq) 9)) (assert (= qq (quote (a b c d e f c d e))))) (defn test-nested-quasiquote [] "NATIVE: test nested quasiquotes" (setv qq (quasiquote (1 (quasiquote (unquote (+ 1 (unquote (+ 2 3))))) 4))) (setv q (quote (1 (quasiquote (unquote (+ 1 5))) 4))) (assert (= (len q) 3)) (assert (= (get qq 1) (quote (quasiquote (unquote (+ 1 5)))))) (assert (= q qq))) (defmacro doodle [&rest body] `(do ~@body)) (defn test-unquote-splice [] "NATIVE: test unquote-splice does what's intended" (assert (= (doodle [1 2 3] [4 5 6]) [4 5 6]))) hy-0.12.1/tests/native_tests/reader_macros.hy000066400000000000000000000034471304171765200212530ustar00rootroot00000000000000(import [functools [wraps]]) (defn test-reader-macro [] "Test a basic reader macro" (defreader ^ [expr] expr) (assert (= #^"works" "works"))) (defn test-reader-macro-expr [] "Test basic exprs like lists and arrays" (defreader n [expr] (get expr 1)) (assert (= #n[1 2] 2)) (assert (= #n(1 2) 2))) (defn test-reader-macro-override [] "Test if we can override function symbols" (defreader + [n] (+ n 1)) (assert (= #+2 3))) (defn test-reader-macros-macros [] "Test if defreader is actually a macro" (defreader t [expr] `(, ~@expr)) (def a #t[1 2 3]) (assert (= (type a) tuple)) (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." #@((wraps func) (defn wrapper [&rest args &kwargs kwargs] (apply func (map inc args) (dict-comp k (inc v) [[k v] (.items kwargs)]))))) #@(increment-arguments (defn foo [&rest args &kwargs kwargs] "Bar." (, args kwargs))) ;; The decorator did what it was supposed to (assert (= (, (, 2 3 4) {"quux" 5 "baz" 6}) (foo 1 2 3 :quux 4 :baz 5))) ;; @wraps preserved the docstring and __name__ (assert (= "foo" (. foo --name--))) (assert (= "Bar." (. foo --doc--))) ;; We can use the #@ reader macro to apply more than one decorator #@(increment-arguments increment-arguments (defn double-foo [&rest args &kwargs kwargs] "Bar." (, args kwargs))) (assert (= (, (, 3 4 5) {"quux" 6 "baz" 7}) (double-foo 1 2 3 :quux 4 :baz 5)))) hy-0.12.1/tests/native_tests/shadow.hy000066400000000000000000000044221304171765200177240ustar00rootroot00000000000000(defn test-shadow-addition [] "NATIVE: test shadow addition" (let [x +] (assert (try (x) (except [TypeError] True) (else (raise AssertionError)))) (assert (= (x 1 2 3 4) 10)) (assert (= (x 1 2 3 4 5) 15)) ; with strings (assert (= (x "a" "b" "c") "abc")) ; with lists (assert (= (x ["a"] ["b"] ["c"]) ["a" "b" "c"])))) (defn test-shadow-subtraction [] "NATIVE: test shadow subtraction" (let [x -] (assert (try (x) (except [TypeError] True) (else (raise AssertionError)))) (assert (= (x 1) -1)) (assert (= (x 2 1) 1)) (assert (= (x 2 1 1) 0)))) (defn test-shadow-multiplication [] "NATIVE: test shadow multiplication" (let [x *] (assert (= (x) 1)) (assert (= (x 3) 3)) (assert (= (x 3 3) 9)))) (defn test-shadow-division [] "NATIVE: test shadow division" (let [x /] (assert (try (x) (except [TypeError] True) (else (raise AssertionError)))) (assert (= (x 1) 1)) (assert (= (x 8 2) 4)) (assert (= (x 8 2 2) 2)) (assert (= (x 8 2 2 2) 1)))) (defn test-shadow-compare [] "NATIVE: test shadow compare" (for [x [< <= = != >= >]] (assert (try (x) (except [TypeError] True) (else (raise AssertionError)))) (assert (try (x 1) (except [TypeError] True) (else (raise AssertionError))))) (for [(, x y) [[< >=] [<= >] [= !=]]] (for [args [[1 2] [2 1] [1 1] [2 2]]] (assert (= (apply x args) (not (apply y args)))))) (let [s-lt < s-gt > s-le <= s-ge >= s-eq = s-ne !=] (assert (apply s-lt [1 2 3])) (assert (not (apply s-lt [3 2 1]))) (assert (apply s-gt [3 2 1])) (assert (not (apply s-gt [1 2 3]))) (assert (apply s-le [1 1 2 2 3 3])) (assert (not (apply s-le [1 1 2 2 1 1]))) (assert (apply s-ge [3 3 2 2 1 1])) (assert (not (apply s-ge [3 3 2 2 3 3]))) (assert (apply s-eq [1 1 1 1 1])) (assert (not (apply s-eq [1 1 2 1 1]))) (assert (apply s-ne [1 2 3 4 5])) (assert (not (apply s-ne [1 1 2 3 4]))))) hy-0.12.1/tests/native_tests/unless.hy000066400000000000000000000004141304171765200177450ustar00rootroot00000000000000(defn test-unless [] "NATIVE: test unless" (assert (= (unless False 1) 1)) (assert (= (unless False 1 2) 2)) (assert (= (unless False 1 3) 3)) (assert (= (unless True 2) None)) (assert (= (unless (!= 1 2) 42) None)) (assert (= (unless (!= 2 2) 42) 42))) hy-0.12.1/tests/native_tests/when.hy000066400000000000000000000003701304171765200173760ustar00rootroot00000000000000(defn test-when [] "NATIVE: test when" (assert (= (when True 1) 1)) (assert (= (when True 1 2) 2)) (assert (= (when True 1 3) 3)) (assert (= (when False 2) None)) (assert (= (when (= 1 2) 42) None)) (assert (= (when (= 2 2) 42) 42))) hy-0.12.1/tests/native_tests/with_decorator.hy000066400000000000000000000011411304171765200214470ustar00rootroot00000000000000(defn foodec [func] (lambda [] (+ 1 1))) (with-decorator foodec (defn tfunction [] (* 2 2))) (defn bardec [cls] (setv cls.my_attr 123) cls) (with-decorator bardec (defclass cls [] [my_attr 456])) (defn test-decorator-clobbing [] "NATIVE: Tests whether nested decorators work" (do (defn dec1 [f] (defn k [] (+ (f) 1))) (defn dec2 [f] (defn k [] (+ (f) 2))) (with-decorator dec1 (with-decorator dec2 (defn f [] 1))) (assert (= (f) 4)))) (defn test-decorators [] "NATIVE: test decorators." (assert (= (tfunction) 2)) (assert (= cls.my_attr 123))) hy-0.12.1/tests/native_tests/with_test.hy000066400000000000000000000016701304171765200204530ustar00rootroot00000000000000(defclass WithTest [object] (defn --init-- [self val] (setv self.val val) None) (defn --enter-- [self] self.val) (defn --exit-- [self type value traceback] (setv self.val None))) (defn test-single-with [] "NATIVE: test a single with" (with [t (WithTest 1)] (assert (= t 1)))) (defn test-two-with [] "NATIVE: test two withs" (with [t1 (WithTest 1) t2 (WithTest 2)] (assert (= t1 1)) (assert (= t2 2)))) (defn test-thrice-with [] "NATIVE: test three withs" (with [t1 (WithTest 1) t2 (WithTest 2) t3 (WithTest 3)] (assert (= t1 1)) (assert (= t2 2)) (assert (= t3 3)))) (defn test-quince-with [] "NATIVE: test four withs, one with no args" (with [t1 (WithTest 1) t2 (WithTest 2) t3 (WithTest 3) _ (WithTest 4)] (assert (= t1 1)) (assert (= t2 2)) (assert (= t3 3)))) hy-0.12.1/tests/resources/000077500000000000000000000000001304171765200153755ustar00rootroot00000000000000hy-0.12.1/tests/resources/__init__.py000066400000000000000000000001301304171765200175000ustar00rootroot00000000000000 def kwtest(*args, **kwargs): return kwargs def function_with_a_dash(): pass hy-0.12.1/tests/resources/argparse_ex.hy000077500000000000000000000005051304171765200202420ustar00rootroot00000000000000#!/usr/bin/env hy (import sys) (import argparse) (setv parser (argparse.ArgumentParser)) (.add_argument parser "-i") (.add_argument parser "-c") (setv args (.parse_args parser)) ;; using (cond) allows -i to take precedence over -c (cond [args.i (print (str args.i))] [args.c (print (str "got c"))]) hy-0.12.1/tests/resources/bin/000077500000000000000000000000001304171765200161455ustar00rootroot00000000000000hy-0.12.1/tests/resources/bin/__init__.hy000066400000000000000000000000521304171765200202430ustar00rootroot00000000000000(defn -null-fn-for-import-test [] pass) hy-0.12.1/tests/resources/bin/main.hy000066400000000000000000000001351304171765200174320ustar00rootroot00000000000000(defmain [&rest args] (print args) (print "Hello World") (if (in "exit1" args) 1)) hy-0.12.1/tests/resources/bin/nomain.hy000066400000000000000000000001251304171765200177660ustar00rootroot00000000000000(print "This Should Still Works") (defn main [] (print "This Should Not Work")) hy-0.12.1/tests/resources/importer/000077500000000000000000000000001304171765200172365ustar00rootroot00000000000000hy-0.12.1/tests/resources/importer/a.hy000066400000000000000000000000241304171765200200140ustar00rootroot00000000000000(thisshouldnotwork) hy-0.12.1/tests/resources/importer/basic.hy000066400000000000000000000001501304171765200206550ustar00rootroot00000000000000;; This is a comment. It shall be ignored by the parser. (setv square (fn [x] (* x x))) hy-0.12.1/tests/resources/tlib.py000066400000000000000000000003331304171765200167000ustar00rootroot00000000000000from hy.macros import macro from hy import HyList, HyInteger @macro("qplah") def tmac(*tree): return HyList((HyInteger(8), ) + tree) @macro("parald") def tmac2(*tree): return HyList((HyInteger(9), ) + tree) hy-0.12.1/tests/test_bin.py000066400000000000000000000135311304171765200155470ustar00rootroot00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Copyright (c) 2013 Julien Danjou # Copyright (c) 2013 Will Kahn-Greene # Copyright (c) 2014 Bob Tolbert # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. import os import subprocess from hy._compat import PY3 hy_dir = os.environ.get('HY_DIR', '') def run_cmd(cmd, stdin_data=None): p = subprocess.Popen(os.path.join(hy_dir, cmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) stdout = "" stderr = "" if stdin_data is not None: p.stdin.write(stdin_data.encode('ASCII')) p.stdin.flush() p.stdin.close() # Read stdout and stderr otherwise if the PIPE buffer is full, we might # wait for ever… while p.poll() is None: stdout += p.stdout.read().decode('utf-8') stderr += p.stderr.read().decode('utf-8') return p.returncode, stdout, stderr def test_bin_hy(): ret = run_cmd("hy", "") assert ret[0] == 0 def test_bin_hy_stdin(): ret = run_cmd("hy", '(koan)') assert ret[0] == 0 assert "monk" in ret[1] def test_bin_hy_cmd(): ret = run_cmd("hy -c \"(koan)\"") assert ret[0] == 0 assert "monk" in ret[1] ret = run_cmd("hy -c \"(koan\"") assert ret[0] == 1 assert "Premature end of input" in ret[2] def test_bin_hy_icmd(): ret = run_cmd("hy -i \"(koan)\"", "(ideas)") assert ret[0] == 0 output = ret[1] assert "monk" in output assert "figlet" in output def test_bin_hy_icmd_file(): ret = run_cmd("hy -i test_files/icmd_test_file.hy", "(ideas)") assert ret[0] == 0 output = ret[1] assert "Hy!" in output def test_bin_hy_icmd_and_spy(): ret = run_cmd("hy -i \"(+ [] [])\" --spy", "(+ 1 1)") assert ret[0] == 0 output = ret[1] assert "([] + [])" in output def test_bin_hy_missing_file(): ret = run_cmd("hy foobarbaz") assert ret[0] == 2 assert "No such file" in ret[2] def test_bin_hy_file_with_args(): ret = run_cmd("hy tests/resources/argparse_ex.hy -h") assert ret[0] == 0 assert "usage" in ret[1] ret = run_cmd("hy tests/resources/argparse_ex.hy -c bar") assert ret[0] == 0 assert "got c" in ret[1] ret = run_cmd("hy tests/resources/argparse_ex.hy -i foo") assert ret[0] == 0 assert "foo" in ret[1] ret = run_cmd("hy tests/resources/argparse_ex.hy -i foo -c bar") assert ret[0] == 0 assert "foo" in ret[1] def test_bin_hyc(): ret = run_cmd("hyc") assert ret[0] == 2 assert "usage" in ret[2] ret = run_cmd("hyc -h") assert ret[0] == 0 assert "usage" in ret[1] ret = run_cmd("hyc tests/resources/argparse_ex.hy") assert ret[0] == 0 assert "Compiling" in ret[1] assert os.path.exists("tests/resources/argparse_ex.pyc") def test_bin_hyc_missing_file(): ret = run_cmd("hyc foobarbaz") assert ret[0] == 2 assert "[Errno 2]" in ret[2] def test_hy2py(): i = 0 for dirpath, dirnames, filenames in os.walk("tests/native_tests"): for f in filenames: if f.endswith(".hy"): if f == "py3_only_tests.hy" and not PY3: continue else: i += 1 ret = run_cmd("hy2py -s -a " + os.path.join(dirpath, f)) assert ret[0] == 0, f assert len(ret[1]) > 1, f assert len(ret[2]) == 0, f assert i def test_bin_hy_builtins(): import hy.cmdline # NOQA assert str(exit) == "Use (exit) or Ctrl-D (i.e. EOF) to exit" assert str(quit) == "Use (quit) or Ctrl-D (i.e. EOF) to exit" def test_bin_hy_main(): ret = run_cmd("hy tests/resources/bin/main.hy") assert ret[0] == 0 assert "Hello World" in ret[1] def test_bin_hy_main_args(): ret = run_cmd("hy tests/resources/bin/main.hy test 123") assert ret[0] == 0 assert "test" in ret[1] assert "123" in ret[1] def test_bin_hy_main_exitvalue(): ret = run_cmd("hy tests/resources/bin/main.hy exit1") assert ret[0] == 1 def test_bin_hy_no_main(): ret = run_cmd("hy tests/resources/bin/nomain.hy") assert ret[0] == 0 assert "This Should Still Work" in ret[1] def test_bin_hy_module_main(): ret = run_cmd("hy -m tests.resources.bin.main") assert ret[0] == 0 assert "Hello World" in ret[1] def test_bin_hy_module_main_args(): ret = run_cmd("hy -m tests.resources.bin.main test 123") assert ret[0] == 0 assert "test" in ret[1] assert "123" in ret[1] def test_bin_hy_module_main_exitvalue(): ret = run_cmd("hy -m tests.resources.bin.main exit1") assert ret[0] == 1 def test_bin_hy_module_no_main(): ret = run_cmd("hy -m tests.resources.bin.nomain") assert ret[0] == 0 assert "This Should Still Work" in ret[1] hy-0.12.1/tests/test_files/000077500000000000000000000000001304171765200155245ustar00rootroot00000000000000hy-0.12.1/tests/test_files/icmd_test_file.hy000066400000000000000000000000161304171765200210350ustar00rootroot00000000000000(print "Hy!") hy-0.12.1/tox.ini000066400000000000000000000004361304171765200135370ustar00rootroot00000000000000[tox] envlist = py27,pypy,py33,py34,py35,py36,flake8 skipsdist = True [testenv] commands = pip install --allow-all-external -e . nosetests passenv = TERM deps = -rrequirements-dev.txt [testenv:flake8] commands = flake8 hy bin tests --ignore=E121,E123,E126,E226,E24,E704,W503,E305