pax_global_header00006660000000000000000000000064136155463200014517gustar00rootroot0000000000000052 comment=6cc4c233b439f9e15f2d80cdebce8711bf50cb54 hy-0.18.0/000077500000000000000000000000001361554632000122255ustar00rootroot00000000000000hy-0.18.0/.dockerignore000066400000000000000000000000051361554632000146740ustar00rootroot00000000000000.git hy-0.18.0/.gitignore000066400000000000000000000001621361554632000142140ustar00rootroot00000000000000/hy/version.py *.pyc .*.sw? *hy*egg* *pyreadline*egg* .tox *pycache* dist .coverage build/ /.cache /.pytest_cache hy-0.18.0/.mailmap000066400000000000000000000014611361554632000136500ustar00rootroot00000000000000Paul 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.18.0/.travis.yml000066400000000000000000000006761361554632000143470ustar00rootroot00000000000000sudo: false dist: xenial language: python python: - "3.5" - "3.6" - "3.7" - "3.8" - pypy3.5-6.0 install: - pip install -r requirements-travis.txt - pip install -e . script: pytest 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.18.0/AUTHORS000066400000000000000000000075301361554632000133020ustar00rootroot00000000000000* 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 * Charles de Lacombe * John Patterson * Kai Lüke * Neil Lindquist * David Schaefer * Jordan Danford * Andrew Silva * Zaheer Soebhan * Rob Day * Eric Kaschalk * Yoan Tournade * Simon Gomizelj * Yigong Wang * Oskar Kvist * Brandon T. Willard * Andrew R. M. * Tristan de Cacqueray * Sören Tempel * Noah Snelson * Adam Porter * Gábor Lipták hy-0.18.0/CONTRIBUTING.rst000066400000000000000000000167501361554632000146770ustar00rootroot00000000000000Contributor Guidelines ====================== Contributions are welcome and greatly appreciated. Every little bit helps in making Hy better. Potential contributions include: - Reporting and fixing bugs. - Requesting features. - Adding features. - Writing tests for outstanding bugs or untested features. - You can mark tests that Hy can't pass yet as xfail_. - Cleaning up the code. - Improving the documentation. - Answering questions on `the IRC channel`_, `the mailing list`_, or `Stack Overflow`_. - Evangelizing for Hy in your organization, user group, conference, or bus stop. Issues ~~~~~~ In order to report bugs or request features, search the `issue tracker`_ to check for a duplicate. (If you're reporting a bug, make sure you can reproduce it with the very latest, bleeding-edge version of Hy from the ``master`` branch on GitHub. Bugs in stable versions of Hy are fixed on ``master`` before the fix makes it into a new stable release.) If there aren't any duplicates, then you can make a new issue. It's totally acceptable to create an issue when you're unsure whether something is a bug or not. We'll help you figure it out. Use the same issue tracker to report problems with the documentation. Pull requests ~~~~~~~~~~~~~ Submit proposed changes to the code or documentation as pull requests (PRs) on GitHub_. Git can be intimidating and confusing to the uninitiated. `This getting-started guide`_ may be helpful. However, if you're overwhelmed by Git, GitHub, or the rules below, don't sweat it. We want to keep the barrier to contribution low, so we're happy to help you with these finicky things or do them for you if necessary. Deciding what to do ------------------- Issues tagged good-first-bug_ are expected to be relatively easy to fix, so they may be good targets for your first PR for Hy. If you're proposing a major change to the Hy language, or you're unsure of the proposed change, create an issue to discuss it before you write any code. This will allow others to give feedback on your idea, and it can avoid wasted work. File headers ------------ Every Python or Hy file in the source tree that is potentially copyrightable should have the following header (but with ``;;`` in place of ``#`` for Hy files):: # Copyright [current year] the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. As a rule of thumb, a file can be considered potentially copyrightable if it includes at least 10 lines that contain something other than comments or whitespace. If in doubt, include the header. Commit formatting ----------------- Many PRs are small enough that only one commit is necessary, but bigger ones should be organized into logical units as separate commits. PRs should be free of merge commits and commits that fix or revert other commits in the same PR (``git rebase`` is your friend). Avoid committing spurious whitespace changes. The first line of a commit message should describe the overall change in 50 characters or less. If you wish to add more information, separate it from the first line with a blank line. Testing ------- New features and bug fixes should be tested. If you've caused an xfail_ test to start passing, remove the xfail mark. If you're testing a bug that has a GitHub issue, include a comment with the URL of the issue. No PR may be merged if it causes any tests to fail. You can run the test suite and check the style of your code with ``make d``. The byte-compiled versions of the test files can be purged using ``git clean -dfx tests/``. If you want to run the tests while skipping the slow ones in ``test_bin.py``, use ``pytest --ignore=tests/test_bin.py``. NEWS and AUTHORS ---------------- If you're making user-visible changes to the code, add one or more items describing it to the NEWS file. Finally, add yourself to the AUTHORS file (as a separate commit): you deserve it. :) The PR itself ------------- PRs should ask to merge a new branch that you created for the PR into hylang/hy's ``master`` branch, and they should have as their origin the most recent commit possible. If the PR fulfills one or more issues, then the body text of the PR (or the commit message for any of its commits) should say "Fixes #123" or "Closes #123" for each affected issue number. Use this exact (case-insensitive) wording, because when a PR containing such text is merged, GitHub automatically closes the mentioned issues, which is handy. Conversely, avoid this exact language if you want to mention an issue without closing it (because e.g. you've partly but not entirely fixed a bug). There are two situations in which a PR is allowed to be merged: 1. When it is approved by **two** members of Hy's core team other than the PR's author. Changes to the documentation, or trivial changes to code, need only **one** approving member. 2. When the PR is at least **two weeks** old and **no** member of the Hy core team has expressed disapproval of the PR in its current state. (Exception: a PR to create a new release is not eligible to be merged under this criterion, only the first one.) Anybody on the Hy core team may perform the merge. Merging should create a merge commit (don't squash unnecessarily, because that would remove separation between logically separate commits, and don't fast-forward, because that would throw away the history of the commits as a separate branch), which should include the PR number in the commit message. 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 .. _GitHub: https://github.com/hylang/hy .. _This getting-started guide: http://rogerdudler.github.io/git-guide/ .. _good-first-bug: https://github.com/hylang/hy/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-bug .. _the IRC channel: irc://freenode.net/hy .. _the mailing list: https://groups.google.com/forum/#!forum/hylang-discuss .. _Stack Overflow: https://stackoverflow.com/questions/tagged/hy .. _xfail: https://docs.pytest.org/en/latest/skipping.html#mark-a-test-function-as-expected-to-fail hy-0.18.0/Dockerfile000066400000000000000000000002561361554632000142220ustar00rootroot00000000000000# 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.18.0/LICENSE000066400000000000000000000021461361554632000132350ustar00rootroot00000000000000Copyright 2020 the authors. Portions of setup.py, copyright 2016 Jason R Coombs . 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-0.18.0/MANIFEST.in000066400000000000000000000001361361554632000137630ustar00rootroot00000000000000include AUTHORS include LICENSE include NEWS.rst include README.md include fastentrypoints.py hy-0.18.0/Makefile000066400000000000000000000025131361554632000136660ustar00rootroot00000000000000pip_url=https://bootstrap.pypa.io/get-pip.py python=python pip=pip coveralls=coveralls 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 pytest tox: venv tox flake: flake8 hy tests --ignore=E121,E123,E126,E226,E24,E704,W503,E302,E305,E701 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 -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.18.0/NEWS.rst000066400000000000000000001070421361554632000135370ustar00rootroot00000000000000.. default-role:: code 0.18.0 ============================== Removals ------------------------------ * Python 2 is no longer supported. * Support for attribute lists in `defclass` has been removed. Use `setv` and `defn` instead. * Literal keywords are no longer parsed differently in calls to functions with certain names. * `hy.contrib.multi` has been removed. Use `cond` or the PyPI package `multipledispatch` instead. Other Breaking Changes ------------------------------ * `HySequence` is now a subclass of `tuple` instead of `list`. Thus, a `HyList` will never be equal to a `list`, and you can't use `.append`, `.pop`, etc. on a `HyExpression` or `HyList`. New Features ------------------------------ * Added special forms `py` to `pys` that allow Hy programs to include inline Python code. * Added a special form `cmp` for chained comparisons. * All augmented assignment operators (except `%=` and `^=`) now allow more than two arguments. * Added support for function annotations (PEP 3107) and variable annotations (PEP 526). * Added a function `parse-args` as a wrapper for Python's `argparse`. Bug Fixes ------------------------------ * Statements in the second argument of `assert` are now executed. * Fixed a bug that caused the condition of a `while` to be compiled twice. * `in` and `not-in` now allow more than two arguments, as in Python. * `hy2py` can now handle format strings. * Fixed crashes from inaccessible history files. * Removed an accidental import from the internal Python module `test`. * Fixed a swarm of bugs in `hy.extra.anaphoric`. Misc. Improvements ------------------------------ * Replaced the dependency `clint` with `colorama`. 0.17.0 ============================== **Warning**: Hy 0.17.x will be the last Hy versions to support Python 2, and we expect 0.17.0 to be the only release in this line. By the time 0.18.0 is released (in 2020, after CPython 2 has ceased being developed), Hy will only support Python 3. Removals ------------------------------ * Python 3.4 is no longer supported. New Features ------------------------------ * Python 3.8 is now supported. * Format strings with embedded Hy code (e.g., `f"The sum is {(+ x y)}"`) are now supported, even on Pythons earlier than 3.6. * Added a special form `setx` to create Python 3.8 assignment expressions. * Added new core functions `list?` and `tuple`. * Gensyms now have a simpler format that's more concise when mangled (e.g., `_hyx_XsemicolonXfooXvertical_lineX1235` is now `_hyx_fooXUffffX1`). Bug Fixes ------------------------------ * Fixed a crash caused by errors creating temporary files during bytecode compilation. 0.16.0 ============================== Removals ------------------------------ * Empty expressions (`()`) are no longer legal at the top level. New Features ------------------------------ * `eval` / `hy_eval` and `hy_compile` now accept an optional `compiler` argument that enables the use of an existing `HyASTCompiler` instance. * Keyword objects (not just literal keywords) can be called, as shorthand for `(get obj :key)`, and they accept a default value as a second argument. * Minimal macro expansion namespacing has been implemented. As a result, external macros no longer have to `require` their own macro dependencies. * Macros and tags now reside in module-level `__macros__` and `__tags__` attributes. Bug Fixes ------------------------------ * Cleaned up syntax and compiler errors. * You can now call `defmain` with an empty lambda list. * `require` now compiles to Python AST. * Fixed circular `require`\s. * Fixed module reloading. * Fixed circular imports. * Fixed errors from `from __future__ import ...` statements and missing Hy module docstrings caused by automatic importing of Hy builtins. * Fixed `__main__` file execution. * Fixed bugs in the handling of unpacking forms in method calls and attribute access. * Fixed crashes on Windows when calling `hy-repr` on date and time objects. * Fixed a crash in `mangle` for some pathological inputs. * Fixed incorrect mangling of some characters at low code points. * Fixed a crash on certain versions of Python 2 due to changes in the standard module `tokenize`. 0.15.0 ============================== Removals ------------------------------ * Dotted lists, `HyCons`, `cons`, `cons?`, and `list*` have been removed. These were redundant with Python's built-in data structures and Hy's most common model types (`HyExpression`, `HyList`, etc.). * `&key` is no longer special in lambda lists. Use `&optional` instead. * Lambda lists can no longer unpack tuples. * `ap-pipe` and `ap-compose` have been removed. Use threading macros and `comp` instead. * `for/a` has been removed. Use `(for [:async ...] ...)` instead. * `(except)` is no longer allowed. Use `(except [])` instead. * `(import [foo])` is no longer allowed. Use `(import foo)` instead. Other Breaking Changes ------------------------------ * `HyExpression`, `HyDict`, and `HySet` no longer inherit from `HyList`. This means you can no longer use alternative punctuation in place of square brackets in special forms (e.g. `(fn (x) ...)` instead of the standard `(fn [x] ...)`). * Mangling rules have been overhauled; now, mangled names are always legal Python identifiers. * `_` and `-` are now equivalent, even as single-character names. * The REPL history variable `_` is now `*1`. * Non-shadow unary `=`, `is`, `<`, etc. now evaluate their argument instead of ignoring it. * `list-comp`, `set-comp`, `dict-comp`, and `genexpr` have been replaced by `lfor`, `sfor`, `dfor`, and `gfor`, respectively, which use a new syntax and have additional features. All Python comprehensions can now be written in Hy. * `&`-parameters in lambda lists must now appear in the same order that Python expects. * Literal keywords now evaluate to themselves, and `HyKeyword` no longer inherits from a Python string type * `HySymbol` no longer inherits from `HyString`. New Features ------------------------------ * Python 3.7 is now supported. * `while` and `for` are allowed to have empty bodies. * `for` supports the various new clause types offered by `lfor`. * `defclass` in Python 3 supports specifying metaclasses and other keyword arguments. * Added `mangle` and `unmangle` as core functions. * Added more REPL history variables: `*2` and `*3`. * Added a REPL variable holding the last exception: `*e`. * Added a command-line option `-E` per CPython. * Added a new module `hy.model_patterns`. Bug Fixes ------------------------------ * `hy2py` should now output legal Python code equivalent to the input Hy code in all cases. * Fixed `(return)` so it can exit a Python 2 generator. * Fixed a case where `->` and `->>` duplicated an argument. * Fixed bugs that caused `defclass` to drop statements or crash. * Fixed a REPL crash caused by illegal backslash escapes. * `NaN` can no longer create an infinite loop during macro-expansion. * Fixed a bug that caused `try` to drop expressions. * The compiler now properly recognizes `unquote-splice`. * Trying to import a dotted name is now a syntax error, as in Python. * `defmacro!` now allows optional arguments. * Fixed handling of variables that are bound multiple times in a single `let`. Misc. Improvements ---------------------------- * `hy-repr` uses registered functions instead of methods. * `hy-repr` supports more standard types. * `macroexpand-all` will now expand macros introduced by a `require` in the body of a macro. 0.14.0 ============================== Removals ------------------------------ * Python 3.3 is no longer supported * `def` is gone; use `setv` instead * `apply` is gone; use the new `#*` and `#**` syntax instead * `yield-from` is no longer supported under Python 2 * Periods are no longer allowed in keywords * Numeric literals can no longer begin with a comma or underscore * Literal `Inf`\s and `NaN`\s must now be capitalized like that Other Breaking Changes ------------------------------ * Single-character "sharp macros" are now "tag macros", which can have longer names * `xi` from `hy.extra.anaphoric` is now a tag macro `#%` * `eval` is now a function instead of a special form New Features ------------------------------ * The compiler now automatically promotes values to Hy model objects as necessary, so you can write ``(eval `(+ 1 ~n))`` instead of ``(eval `(+ 1 ~(HyInteger n)))`` * `return` has been implemented as a special form * Added a form of string literal called "bracket strings" delimited by `#[FOO[` and `]FOO]`, where `FOO` is customizable * Added support for PEP 492 (`async` and `await`) with `fn/a`, `defn/a`, `with/a`, and `for/a` * Added Python-style unpacking operators `#*` and `#**` (e.g., `(f #* args #** kwargs)`) * Added a macro `comment` * Added EDN `#_` syntax to discard the next term * `while` loops may now contain an `else` clause, like `for` loops * `#%` works on any expression and has a new `&kwargs` parameter `%**` * Added a macro `doc` and a tag macro `#doc` * `get` is available as a function * `~@` (`unquote-splice`) form now accepts any false value as empty Bug Fixes ------------------------------ * Relative imports (PEP 328) are now allowed * Numeric literals are no longer parsed as symbols when followed by a dot and a symbol * Hy now respects the environment variable `PYTHONDONTWRITEBYTECODE` * String literals should no longer be interpreted as special forms or macros * Tag macros (née sharp macros) whose names begin with `!` are no longer mistaken for shebang lines * Fixed a bug where REPL history wasn't saved if you quit the REPL with `(quit)` or `(exit)` * `exec` now works under Python 2 * No TypeError from multi-arity `defn` returning values evaluating to `None` * `try` forms are now possible in `defmacro` and `deftag` * Multiple expressions are now allowed in `try` * Fixed a crash when `macroexpand`\ing a macro with a named import * Fixed a crash when `with` suppresses an exception. `with` now returns `None` in this case. * Fixed a crash when `--repl-output-fn` raises an exception * Fixed a crash when `HyTypeError` was raised with objects that had no source position * `assoc` now evaluates its arguments only once each * Multiple expressions are now allowed in the `else` clause of a `for` loop * `else` clauses in `for` and `while` are recognized more reliably * Statements in the condition of a `while` loop are repeated properly * Argument destructuring no longer interferes with function docstrings * Nullary `yield-from` is now a syntax error * `break` and `continue` now raise an error when given arguments instead of silently ignoring them Misc. Improvements ------------------------------ * `read`, `read_str`, and `eval` are exposed and documented as top-level functions in the `hy` module * An experimental `let` macro has been added to `hy.contrib.walk` 0.13.1 ============================== Bug Fixes ------------------------------ * Changed setup.py to require astor 0.5, since 0.6 isn't backwards-compatible. 0.13.0 ============================== Language Changes ------------------------------ * Pythons 2.6, 3.0, 3.1, and 3.2 are no longer supported * `let` has been removed. Python's scoping rules do not make a proper implementation of it possible. Use `setv` instead. * `lambda` has been removed, but `fn` now does exactly what `lambda` did * `defreader` has been renamed to `defsharp`; what were previously called "reader macros", which were never true reader macros, are now called "sharp macros" * `try` now enforces the usual Python order for its elements (`else` must follow all `except`\s, and `finally` must come last). This is only a syntactic change; the elements were already run in Python order even when defined out of order. * `try` now requires an `except` or `finally` clause, as in Python * Importing or executing a Hy file automatically byte-compiles it, or loads a byte-compiled version if it exists and is up to date. This brings big speed boosts, even for one-liners, because Hy no longer needs to recompile its standard library for every startup. * Added bytestring literals, which create `bytes` objects under Python 3 and `str` objects under Python 2 * Commas and underscores are allowed in numeric literals * Many more operators (e.g., `**`, `//`, `not`, `in`) can be used as first-class functions * The semantics of binary operators when applied to fewer or more than two arguments have been made more logical * `(** a b c d)` is now equivalent to `(** a (** b (** c d)))`, not `(** (** (** a b) c) d)` * `setv` always returns `None` * When a `try` form executes an `else` clause, the return value for the `try` form is taken from `else` instead of the `try` body. For example, `(try 1 (except [ValueError] 2) (else 3))` returns `3`. * `xor`: If exactly one argument is true, return it * `hy.core.reserved` is now `hy.extra.reserved` * `cond` now supports single argument branches Bug Fixes ------------------------------ * All shadowed operators have the same arities as real operators * Shadowed comparison operators now use `and` instead of `&` for chained comparisons * `partition` no longer prematurely exhausts input iterators * `read` and `read-str` no longer raise an error when the input parses to a false value (e.g., the empty string) * A `yield` inside of a `with` statement will properly suppress implicit returns * `setv` no longer unnecessarily tries to get attributes * `loop` no longer replaces string literals equal to "recur" * The REPL now prints the correct value of `do` and `try` forms * Fixed a crash when tokenizing a single quote followed by whitespace Misc. Improvements ------------------------------ * New contrib module `hy-repr` * Added a command-line option `--repl-output-fn` 0.12.1 ============================== Bug Fixes ------------------------------ * Allow installation without Git 0.12.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 redundant 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) 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. Language Changes ------------------------------ * (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.18.0/README.md000066400000000000000000000035241361554632000135100ustar00rootroot00000000000000Hy == [![Version](https://img.shields.io/pypi/v/hy.svg)](https://pypi.python.org/pypi/hy) XKCD #224 Lisp and Python should love each other. Let's make it happen. Hy is a Lisp dialect that's embedded in Python. Since Hy transforms its Lisp code into Python abstract syntax tree (AST) objects, you have the whole beautiful world of Python at your fingertips, in Lisp form. To install the latest stable release of Hy, just use the command `pip3 install --user hy`. Then you can start an interactive read-eval-print loop (REPL) with the command `hy`, or run a Hy program with `hy myprogram.hy`. * [Why Hy?](http://docs.hylang.org/en/master/whyhy.html) * [Tutorial](http://docs.hylang.org/en/master/tutorial.html) Project ------- * Code: https://github.com/hylang/hy * Documentation: * stable, for use with the latest stable release: http://hylang.org/ * master, for use with the latest revision on GitHub: http://docs.hylang.org/en/master * Bug reports: We have no bugs! Your bugs are your own! (https://github.com/hylang/hy/issues) * License: MIT (Expat) * [Hacking on Hy](http://docs.hylang.org/en/master/hacking.html) * [Contributor Guidelines](http://docs.hylang.org/en/master/hacking.html#contributor-guidelines) * [Code of Conduct](http://docs.hylang.org/en/master/hacking.html#contributor-code-of-conduct) * IRC: Join #hy on [freenode](https://webchat.freenode.net/) * [Stack Overflow: The [hy] tag](https://stackoverflow.com/questions/tagged/hy) ![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)) hy-0.18.0/bin/000077500000000000000000000000001361554632000127755ustar00rootroot00000000000000hy-0.18.0/bin/py2ast000077500000000000000000000001511361554632000141420ustar00rootroot00000000000000#!/usr/bin/env python import sys import ast print(ast.dump(ast.parse(open(sys.argv[1], 'r').read()))) hy-0.18.0/conftest.py000066400000000000000000000024361361554632000144310ustar00rootroot00000000000000import os import importlib import py import pytest import hy from hy._compat import PY36, PY38 NATIVE_TESTS = os.path.join("", "tests", "native_tests", "") _fspath_pyimport = py.path.local.pyimport def pytest_ignore_collect(path, config): return (("py36_only" in path.basename and not PY36) or ("py38_only" in path.basename and not PY38) or None) def pyimport_patch_mismatch(self, **kwargs): """Lame fix for https://github.com/pytest-dev/py/issues/195""" try: return _fspath_pyimport(self, **kwargs) except py.path.local.ImportMismatchError: pkgpath = self.pypkgpath() if pkgpath is None: pkgroot = self.dirpath() modname = self.purebasename else: pkgroot = pkgpath.dirpath() names = self.new(ext="").relto(pkgroot).split(self.sep) if names[-1] == "__init__": names.pop() modname = ".".join(names) res = importlib.import_module(modname) return res py.path.local.pyimport = pyimport_patch_mismatch def pytest_collect_file(parent, path): if (path.ext == ".hy" and NATIVE_TESTS in path.dirname + os.sep and path.basename != "__init__.hy"): pytest_mod = pytest.Module(path, parent) return pytest_mod hy-0.18.0/docs/000077500000000000000000000000001361554632000131555ustar00rootroot00000000000000hy-0.18.0/docs/.gitignore000066400000000000000000000000071361554632000151420ustar00rootroot00000000000000_build hy-0.18.0/docs/Makefile000066400000000000000000000126541361554632000146250ustar00rootroot00000000000000# 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.18.0/docs/_static/000077500000000000000000000000001361554632000146035ustar00rootroot00000000000000hy-0.18.0/docs/_static/.keepme000066400000000000000000000000001361554632000160400ustar00rootroot00000000000000hy-0.18.0/docs/_static/CC0_1.0.txt000066400000000000000000000156101361554632000162720ustar00rootroot00000000000000Creative 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.18.0/docs/_static/cuddles-transparent-small.png000066400000000000000000001123261361554632000224060ustar00rootroot00000000000000PNG  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.18.0/docs/_static/cuddles.png000066400000000000000000001321621361554632000167410ustar00rootroot00000000000000PNG  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.18.0/docs/_static/hy-logo-full.png000066400000000000000000001323621361554632000176360ustar00rootroot00000000000000PNG  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.18.0/docs/_static/hy-logo-small.png000066400000000000000000000454251361554632000200070ustar00rootroot00000000000000PNG  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.18.0/docs/_static/hy-logo.svg000066400000000000000000000330551361554632000167100ustar00rootroot00000000000000 image/svg+xml hy-0.18.0/docs/_static/hy_logo-about.txt000066400000000000000000000015141361554632000201150ustar00rootroot00000000000000Hy 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.18.0/docs/_static/hy_logo-paths.svg000066400000000000000000000142401361554632000201020ustar00rootroot00000000000000 image/svg+xml hy-0.18.0/docs/_static/hy_logo-smaller.png000066400000000000000000000074211361554632000204120ustar00rootroot00000000000000PNG  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.18.0/docs/_static/hy_logo.png000066400000000000000000000353361361554632000167630ustar00rootroot00000000000000PNG  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.18.0/docs/_static/hy_logo.svg000066400000000000000000000117651361554632000167760ustar00rootroot00000000000000 image/svg+xml λ λ ( ) hy-0.18.0/docs/_templates/000077500000000000000000000000001361554632000153125ustar00rootroot00000000000000hy-0.18.0/docs/_templates/breadcrumbs.html000066400000000000000000000002531361554632000204710ustar00rootroot00000000000000{% extends "!breadcrumbs.html" %} {% block breadcrumbs_aside %}
  • Hy version {{ hy_descriptive_version }}
  • {{ super() }} {% endblock %} hy-0.18.0/docs/conf.py000066400000000000000000000032531361554632000144570ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # This file is execfile()d with the current directory set to its containing dir. import re, os, sys, time, html sys.path.append(os.path.abspath("..")) extensions = ['sphinx.ext.intersphinx'] from get_version import __version__ as hy_version # Read the Docs might dirty its checkout, so strip the dirty flag. hy_version = re.sub(r'[+.]dirty\Z', '', hy_version) templates_path = ['_templates'] source_suffix = '.rst' master_doc = 'index' # General information about the project. project = u'hy' copyright = u'%s the authors' % 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 hy_descriptive_version = html.escape(hy_version) if "+" in hy_version: hy_descriptive_version += " (unstable)" exclude_patterns = ['_build', 'coreteam.rst'] pygments_style = 'sphinx' import sphinx_rtd_theme html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # 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'] html_use_smartypants = False html_show_sphinx = False html_context = dict( hy_descriptive_version = hy_descriptive_version) intersphinx_mapping = dict( py = ('https://docs.python.org/3/', None)) hy-0.18.0/docs/contrib/000077500000000000000000000000001361554632000146155ustar00rootroot00000000000000hy-0.18.0/docs/contrib/hy_repr.rst000066400000000000000000000041621361554632000170220ustar00rootroot00000000000000================== Hy representations ================== .. versionadded:: 0.13.0 ``hy.contrib.hy-repr`` is a module containing two functions. To import them, say:: (import [hy.contrib.hy-repr [hy-repr hy-repr-register]]) To make the Hy REPL use it for output, invoke Hy like so:: $ hy --repl-output-fn=hy.contrib.hy-repr.hy-repr .. _hy-repr-fn: hy-repr ------- Usage: ``(hy-repr x)`` This function is Hy's equivalent of Python's built-in ``repr``. It returns a string representing the input object in Hy syntax. .. code-block:: hy => (hy-repr [1 2 3]) '[1 2 3]' => (repr [1 2 3]) '[1, 2, 3]' Like ``repr`` in Python, ``hy-repr`` can round-trip many kinds of values. Round-tripping implies that given an object ``x``, ``(eval (read-str (hy-repr x)))`` returns ``x``, or at least a value that's equal to ``x``. .. _hy-repr-register-fn: hy-repr-register ---------------- Usage: ``(hy-repr-register the-type fun)`` ``hy-repr-register`` lets you set the function that ``hy-repr`` calls to represent a type. .. code-block:: hy => (defclass C) => (hy-repr-register C (fn [x] "cuddles")) => (hy-repr [1 (C) 2]) '[1 cuddles 2]' If the type of an object passed to ``hy-repr`` doesn't have a registered function, ``hy-repr`` will search the type's method resolution order (its ``__mro__`` attribute) for the first type that does. If ``hy-repr`` doesn't find a candidate, it falls back on ``repr``. Registered functions often call ``hy-repr`` themselves. ``hy-repr`` will automatically detect self-references, even deeply nested ones, and output ``"..."`` for them instead of calling the usual registered function. To use a placeholder other than ``"..."``, pass a string of your choice to the keyword argument ``:placeholder`` of ``hy-repr-register``. .. code-block:: hy (defclass Container [object] (defn __init__ (fn [self value] (setv self.value value)))) (hy-repr-register Container :placeholder "HY THERE" (fn [x] (+ "(Container " (hy-repr x.value) ")"))) (setv container (Container 5)) (setv container.value container) (print (hy-repr container)) ; Prints "(Container HY THERE)" hy-0.18.0/docs/contrib/index.rst000066400000000000000000000004671361554632000164650ustar00rootroot00000000000000========================= 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 profile sequences walk hy_repr hy-0.18.0/docs/contrib/loop.rst000066400000000000000000000034451361554632000163260ustar00rootroot00000000000000========== 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.18.0/docs/contrib/profile.rst000066400000000000000000000021411361554632000170050ustar00rootroot00000000000000========== 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.18.0/docs/contrib/sequences.rst000066400000000000000000000043341361554632000173460ustar00rootroot00000000000000============== 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.18.0/docs/contrib/walk.rst000066400000000000000000000123721361554632000163120ustar00rootroot00000000000000==== 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) HyExpression([ 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]]) => (setv trail '([1 2 3] [4 [5 6 [7]]])) => (defn walking [x] ... (print "Walking:" x :sep "\n") ... x) => (postwalk walking trail) Walking: 1 Walking: 2 Walking: 3 Walking: HyExpression([ HyInteger(1), HyInteger(2), HyInteger(3)]) Walking: 4 Walking: 5 Walking: 6 Walking: 7 Walking: HyExpression([ HyInteger(7)]) Walking: HyExpression([ HyInteger(5), HyInteger(6), HyList([ HyInteger(7)])]) Walking: HyExpression([ HyInteger(4), HyList([ HyInteger(5), HyInteger(6), HyList([ HyInteger(7)])])]) Walking: HyExpression([ HyList([ HyInteger(1), HyInteger(2), HyInteger(3)]), HyList([ HyInteger(4), HyList([ HyInteger(5), HyInteger(6), HyList([ HyInteger(7)])])])]) HyExpression([ HyList([ HyInteger(1), HyInteger(2), HyInteger(3)]), HyList([ HyInteger(4), HyList([ HyInteger(5), HyInteger(6), HyList([ HyInteger(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]]) => (setv trail '([1 2 3] [4 [5 6 [7]]])) => (defn walking [x] ... (print "Walking:" x :sep "\n") ... x) => (prewalk walking trail) Walking: HyExpression([ HyList([ HyInteger(1), HyInteger(2), HyInteger(3)]), HyList([ HyInteger(4), HyList([ HyInteger(5), HyInteger(6), HyList([ HyInteger(7)])])])]) Walking: HyList([ HyInteger(1), HyInteger(2), HyInteger(3)]) Walking: 1 Walking: 2 Walking: 3 Walking: HyList([ HyInteger(4), HyList([ HyInteger(5), HyInteger(6), HyList([ HyInteger(7)])])]) Walking: 4 Walking: HyList([ HyInteger(5), HyInteger(6), HyList([ HyInteger(7)])]) Walking: 5 Walking: 6 Walking: HyList([ HyInteger(7)]) Walking: 7 HyExpression([ HyList([ HyInteger(1), HyInteger(2), HyInteger(3)]), HyList([ HyInteger(4), HyList([ HyInteger(5), HyInteger(6), HyList([ HyInteger(7)])])])]) macroexpand-all --------------- Usage: `(macroexpand-all form &optional module-name)` Recursively performs all possible macroexpansions in form, using the ``require`` context of ``module-name``. `macroexpand-all` assumes the calling module's context if unspecified. Macros ====== .. _let: let --- ``let`` creates lexically-scoped names for local variables. A let-bound name ceases to refer to that local outside the ``let`` form. Arguments in nested functions and bindings in nested ``let`` forms can shadow these names. .. code-block:: hy => (let [x 5] ; creates a new local bound to name 'x ... (print x) ... (let [x 6] ; new local and name binding that shadows 'x ... (print x)) ... (print x)) ; 'x refers to the first local again 5 6 5 Basic assignments (e.g. ``setv``, ``+=``) will update the local variable named by a let binding, when they assign to a let-bound name. But assignments via ``import`` are always hoisted to normal Python scope, and likewise, ``defclass`` will assign the class to the Python scope, even if it shares the name of a let binding. Use ``importlib.import_module`` and ``type`` (or whatever metaclass) instead, if you must avoid this hoisting. The ``let`` macro takes two parameters: a list defining *variables* and the *body* which gets executed. *variables* is a vector of variable and value pairs. Like the ``let*`` of many other Lisps, ``let`` executes the variable assignments one-by-one, in the order written:: .. code-block:: hy => (let [x 5 ... y (+ x 1)] ... (print x y)) 5 6 Unlike them, however, each ``(let …)`` form uses only one namespace for all its assignments. Thus, ``(let [x 1 x (fn [] x)] (x))`` returns a function object, not 1 as you might expect. It is an error to use a let-bound name in a ``global`` or ``nonlocal`` form. hy-0.18.0/docs/coreteam.rst000066400000000000000000000010441361554632000155050ustar00rootroot00000000000000* `Kodi B. Arfer `_ * `Nicolas Dandrimont `_ * `Julien Danjou `_ * `Rob Day `_ * `Simon Gomizelj `_ * `Ryan Gonzalez `_ * `Abhishek Lekshmanan `_ * `Morten Linderud `_ * `Matthew Odendahl `_ * `Paul Tagliamonte `_ * `Brandon T. Willard `_ hy-0.18.0/docs/extra/000077500000000000000000000000001361554632000143005ustar00rootroot00000000000000hy-0.18.0/docs/extra/anaphoric.rst000066400000000000000000000122471361554632000170040ustar00rootroot00000000000000================ 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 [*]])`` These macros are implemented by replacing any use of the designated anaphoric symbols (``it``, in most cases) with a gensym. Consequently, it's unwise to nest these macros, or to use an affected symbol as something other than a variable name, as in ``(print "My favorite Stephen King book is" 'it)``. .. _ap-if: ap-if ===== Usage: ``(ap-if test-form then-form else-form)`` As :ref:`if `, but the result of the test form is named ``it`` in the subsequent forms. As with ``if``, the else-clause is optional. .. code-block:: hy => (import os) => (ap-if (.get os.environ "PYTHONPATH") ... (print "Your PYTHONPATH is" it)) .. _ap-each: ap-each ======= Usage: ``(ap-each xs body…)`` Evaluate the body forms for each element ``it`` of ``xs`` and return ``None``. .. code-block:: hy => (ap-each [1 2 3] (print it)) 1 2 3 .. _ap-each-while: ap-each-while ============= Usage: ``(ap-each-while xs pred body…)`` As ``ap-each``, but the form ``pred`` is run before the body forms on each iteration, and the loop ends if ``pred`` is false. .. 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 xs)`` Create a generator like :py:func:`map` that yields each result of ``form`` evaluated with ``it`` bound to successive elements of ``xs``. .. 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 xs)`` As ``ap-map``, but the predicate function ``predfn`` (yes, that's a function, not an anaphoric form) is applied to each ``it``, and the anaphoric mapping form ``rep`` is only applied if the predicate is true. Otherwise, ``it`` is yielded unchanged. .. 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 xs)`` The :py:func:`filter` equivalent of ``ap-map``. .. code-block:: hy => (list (ap-filter (> (* it 2) 6) [1 2 3 4 5])) [4, 5] .. _ap-reject: ap-reject ========= Usage: ``(ap-reject form xs)`` Equivalent to ``(ap-filter (not form) xs)``. .. 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…)`` Equivalent to ``(ap-each (range n) body…)``. .. code-block:: hy => (setv n []) => (ap-dotimes 3 (.append n it)) => n [0, 1, 2] .. _ap-first: ap-first ======== Usage: ``(ap-first form xs)`` Evaluate the predicate ``form`` for each element ``it`` of ``xs``. When the predicate is true, stop and return ``it``. If the predicate is never true, return ``None``. .. code-block:: hy => (ap-first (> it 5) (range 10)) 6 .. _ap-last: ap-last ======== Usage: ``(ap-last form list)`` Evaluate the predicate ``form`` for every element ``it`` of ``xs``. Return the last element for which the predicate is true, or ``None`` if there is no such element. .. code-block:: hy => (ap-last (> it 5) (range 10)) 9 .. _ap-reduce: ap-reduce ========= Usage: ``(ap-reduce form xs &optional initial-value)`` This macro is an anaphoric version of :py:func:`reduce`. It works as follows: - Bind ``acc`` to the first element of ``xs``, bind ``it`` to the second, and evaluate ``form``. - Bind ``acc`` to the result, bind ``it`` to the third value of ``xs``, and evaluate ``form`` again. - Bind ``acc`` to the result, and continue until ``xs`` is exhausted. If ``initial-value`` is supplied, the process instead begins with ``acc`` set to ``initial-value`` and ``it`` set to the first element of ``xs``. .. code-block:: hy => (ap-reduce (+ it acc) (range 10)) 45 .. _#% #% == Usage: ``#% expr`` Makes an expression into a function with an implicit ``%`` parameter list. A ``%i`` symbol designates the (1-based) *i* th parameter (such as ``%3``). Only the maximum ``%i`` determines the number of ``%i`` parameters--the others need not appear in the expression. ``%*`` and ``%**`` name the ``&rest`` and ``&kwargs`` parameters, respectively. .. code-block:: hy => (#%[%1 %6 42 [%2 %3] %* %4] 1 2 3 4 555 6 7 8) [1, 6, 42, [2, 3], (7, 8), 4] => (#% %** :foo 2) {"foo": 2} When used on an s-expression, ``#%`` is similar to Clojure's anonymous function literals--``#()``. .. code-block:: hy => (setv add-10 #%(+ 10 %1)) => (add-10 6) 16 ``#%`` determines the parameter list by the presence of a ``%*`` or ``%**`` symbol and by the maximum ``%i`` symbol found *anywhere* in the expression, so nesting of ``#%`` forms is not recommended. hy-0.18.0/docs/extra/index.rst000066400000000000000000000004341361554632000161420ustar00rootroot00000000000000=================== 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 reserved hy-0.18.0/docs/extra/reserved.rst000066400000000000000000000007041361554632000166520ustar00rootroot00000000000000============== Reserved Names ============== names ===== Usage: ``(names)`` This function 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., ``not-in`` rather than ``not_in``). .. code-block:: hy => (import hy.extra.reserved) => (in "defclass" (hy.extra.reserved.names)) True hy-0.18.0/docs/hacking.rst000066400000000000000000000034101361554632000153110ustar00rootroot00000000000000.. _hacking: =============== 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 `pytest `_. To run the tests:: $ pytest 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! .. include:: ../CONTRIBUTING.rst Core Team ========= The core development team of Hy consists of following developers: .. include:: coreteam.rst hy-0.18.0/docs/index.rst000066400000000000000000000016451361554632000150240ustar00rootroot00000000000000The Hy Manual ============= .. image:: _static/hy-logo-small.png :alt: Hy :align: left :PyPI: https://pypi.python.org/pypi/hy :Source: https://github.com/hylang/hy :List: `hylang-discuss `_ :IRC: irc://chat.freenode.net/hy :Stack Overflow: `The [hy] tag `_ Hy is a Lisp dialect that's embedded in Python. Since Hy transforms its Lisp code into Python abstract syntax tree (AST) objects, you have the whole beautiful world of Python at your fingertips, in Lisp form. To install the latest stable release of Hy, just use the command ``pip3 install --user hy``. Then you can start an interactive read-eval-print loop (REPL) with the command ``hy``, or run a Hy program with ``hy myprogram.hy``. .. toctree:: :maxdepth: 3 whyhy tutorial style-guide language/index extra/index contrib/index hacking hy-0.18.0/docs/language/000077500000000000000000000000001361554632000147405ustar00rootroot00000000000000hy-0.18.0/docs/language/api.rst000066400000000000000000001670361361554632000162600ustar00rootroot00000000000000.. _special-forms: ================= 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. ^ - The ``^`` symbol is used to denote annotations in three different contexts: - Standalone variable annotations. - Variable annotations in a setv call. - Function argument annotations. They implement `PEP 526 `_ and `PEP 3107 `_. Here is some example syntax of all three usages: .. code-block:: clj ; Annotate the variable x as an int (equivalent to `x: int`). (^int x) ; Can annotate with expressions if needed (equivalent to `y: f(x)`). (^(f x) y) ; Annotations with an assignment: each annotation (int, str) covers the term that ; immediately follows. ; Equivalent to: x: int = 1; y = 2; z: str = 3 (setv ^int x 1 y 2 ^str z 3) ; Annotate a as an int, c as an int, and b as a str. ; Equivalent to: def func(a: int, b: str = None, c: int = 1): ... (defn func [^int a &optional ^str b ^int [c 1]] ...) The rules are: - The value to annotate with is the value that immediately follows the caret. - There must be no space between the caret and the value to annotate, otherwise it will be interpreted as a bitwise XOR like the Python operator. - The annotation always comes (and is evaluated) *before* the value being annotated. This is unlike Python, where it comes and is evaluated *after* the value being annotated. Note that variable annotations are only supported on Python 3.6+. For annotating items with generic types, the of_ macro will likely be of use. . - .. 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 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 =>(do ... (setv collection {}) ... (assoc collection "Dog" "Bark") ... (print collection)) {u'Dog': u'Bark'} =>(do ... (setv collection {}) ... (assoc collection "Dog" "Bark" "Cat" "Meow") ... (print collection)) {u'Cat': u'Meow', u'Dog': u'Bark'} =>(do ... (setv 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``. await ----- ``await`` creates an :ref:`await expression `. It takes exactly one argument: the object to wait for. :: => (import asyncio) => (defn/a main [] ... (print "hello") ... (await (asyncio.sleep 1)) ... (print "world")) => (asyncio.run (main)) hello world 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" (input "? ")) (break) (print "Try again"))) cmp --- ``cmp`` creates a :ref:`comparison expression `. It isn't required for unchained comparisons, which have only one comparison operator, nor for chains of the same operator. For those cases, you can use the comparison operators directly with Hy's usual prefix syntax, as in ``(= x 1)`` or ``(< 1 2 3)``. The use of ``cmp`` is to construct chains of heterogeneous operators, such as ``x <= y < z``. It uses an infix syntax with the general form :: (cmp ARG OP ARG OP ARG…) Hence, ``(cmp x <= y < z)`` is equivalent to ``(and (<= x y) (< y z))``, including short-circuiting, except that ``y`` is only evaluated once. Each ``ARG`` is an arbitrary form, which does not itself use infix syntax. Use :ref:`py-specialform` if you want fully Python-style operator syntax. You can also nest ``cmp`` forms, although this is rarely useful. Each ``OP`` is a literal comparison operator; other forms that resolve to a comparison operator are not allowed. At least two ``ARG``\ s and one ``OP`` are required, and every ``OP`` must be followed by an ``ARG``. As elsewhere in Hy, the equality operator is spelled ``=``, not ``==`` as in Python. comment ------- The ``comment`` macro ignores its body and always expands to ``None``. Unlike linewise comments, the body of the ``comment`` macro must be grammatically valid Hy, so the compiler can tell where the comment ends. Besides the semicolon linewise comments, Hy also has the ``#_`` discard prefix syntax to discard the next form. This is completely discarded and doesn't expand to anything, not even ``None``. .. code-block:: clj => (print (comment

    Surprise!

    ...

    You'd be surprised what's grammatically valid in Hy.

    ...

    (Keep delimiters in balance, and you're mostly good to go.)

    ) ... "Hy") None Hy => (print #_(comment

    Surprise!

    ...

    You'd be surprised what's grammatically valid in Hy.

    ...

    (Keep delimiters in balance, and you're mostly good to go.)

    )) ... "Hy") Hy .. _cond: 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)) If only the condition is given in a branch, then the condition is also used as the result. The expansion of this single argument version is demonstrated below: .. code-block:: clj (cond [condition-1] [condition-2]) (if condition-1 condition-1 (if condition-2 condition-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)) .. _do: do ---------- ``do`` (called ``progn`` in some Lisps) takes any number of forms, evaluates them, and returns the value of the last one, or ``None`` if no forms were provided. :: => (+ 1 (do (setv x (+ 1 1)) x)) 3 doc / #doc ---------- Documentation macro and tag macro. Gets help for macros or tag macros, respectively. .. code-block:: clj => (doc doc) Help on function (doc) in module hy.core.macros: (doc)(symbol) macro documentation Gets help for a macro function available in this module. Use ``require`` to make other macros available. Use ``#doc foo`` instead for help with tag macro ``#foo``. Use ``(help foo)`` instead for help with runtime objects. => (doc comment) Help on function (comment) in module hy.core.macros: (comment)(*body) Ignores body and always expands to None => #doc doc Help on function #doc in module hy.core.macros: #doc(symbol) tag macro documentation Gets help for a tag macro function available in this module. dfor ---- ``dfor`` creates a :ref:`dictionary comprehension `. Its syntax is the same as that of `lfor`_ except that the final value form must be a literal list of two elements, the first of which becomes each key and the second of which becomes each value. .. code-block:: hy => (dfor x (range 5) [x (* x 10)]) {0: 0, 1: 10, 2: 20, 3: 30, 4: 40} .. _setv: setv ---- ``setv`` is used to bind a value, object, or function to a symbol. For example: .. code-block:: clj => (setv 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 You can provide more than one target–value pair, and the assignments will be made in order:: (setv x 1 y x x 2) (print x y) ; => 2 1 You can perform parallel assignments or unpack the source value with square brackets and :ref:`unpack-iterable`:: (setv duo ["tim" "eric"]) (setv [guy1 guy2] duo) (print guy1 guy2) ; => tim eric (setv [letter1 letter2 #* others] "abcdefg") (print letter1 letter2 others) ; => a b ['c', 'd', 'e', 'f', 'g'] setx ----- Whereas ``setv`` creates an assignment statement, ``setx`` creates an assignment expression (see :pep:`572`). It requires Python 3.8 or later. Only one target–value pair is allowed, and the target must be a bare symbol, but the ``setx`` form returns the assigned value instead of ``None``. :: => (when (> (setx x (+ 1 2)) 0) ... (print x "is greater than 0")) 3 is greater than 0 .. _defclass: defclass -------- New classes are declared with ``defclass``. It can take optional parameters in the following order: a list defining (a) possible super class(es) and a string (:term:`py:docstring`). .. code-block:: clj (defclass class-name [super-class-1 super-class-2] "docstring" (setv attribute1 value1) (setv attribute2 value2) (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 [] ... (setv age None) ... (setv colour "white") ... ... (defn speak [self] (print "Meow"))) => (setv spot (Cat)) => (setv spot.colour "Black") 'Black' => (.speak spot) Meow .. _defn: defn ---- ``defn`` is used to define functions. It requires two arguments: a name (given as a symbol) and a list of parameters (also given as symbols). Any remaining arguments constitute the body of the function. .. code-block:: clj (defn name [params] bodyform1 bodyform2...) If there at least two body forms, and the first of them is a string literal, this string becomes the :term:`py:docstring` of the function. Parameters may be prefixed with the following special symbols. If you use more than one, they can only appear in the given order (so all `&optional` parameters must precede any `&rest` parameter, `&rest` must precede `&kwonly`, and `&kwonly` must precede `&kwargs`). This is the same order that Python requires. &optional All following parameters are optional. They may be given as two-argument lists, where the first element is the parameter name and the second is the default value. The parameter can also be given as a single item, in which case the default value is ``None``. The following example defines a function with one required positional argument as well as three optional arguments. The first optional argument defaults to ``None`` and the latter two default to ``"("`` and ``")"``, respectively. .. code-block:: clj => (defn format-pair [left-val &optional right-val [open-text "("] [close-text ")"]] ... (+ open-text (str left-val) ", " (str right-val) close-text)) => (format-pair 3) '(3, None)' => (format-pair "A" "B") '(A, B)' => (format-pair "A" "B" "<" ">") '' => (format-pair "A" :open-text "<" :close-text ">") '' &rest The following parameter will contain a list of 0 or more positional arguments. No other positional parameters 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] (setv odd-numbers (lfor x numbers :if (odd? x) x) even-numbers (lfor x numbers :if (even? x) 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 All following parmaeters can only be supplied as keywords. Like ``&optional``, the parameter may be marked as optional by declaring it as a two-element list containing the parameter name following by the default value. .. code-block:: clj => (defn compare [a b &kwonly keyfn [reverse False]] ... (setv result (keyfn a b)) ... (if (not reverse) ... result ... (- result))) => (compare "lisp" "python" ... :keyfn (fn [x y] ... (reduce - (map (fn [s] (ord (first s))) [x y])))) -4 => (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' &kwargs Like ``&rest``, but for keyword arugments. The following 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 unpacking: => (print-parameters #** {"parameter-1" 1 "parameter-2" 2}) parameter-1 1 parameter-2 2 The following example uses all of ``&optional``, ``&rest``, ``&kwonly``, and ``&kwargs`` in order to show their interactions with each other. The function renders an HTML tag. It requires an argument ``tag-name``, a string which is the tag name. It has one optional argument, ``delim``, which defaults to ``""`` and is placed between each child. The rest of the arguments, ``children``, are the tag's children or content. A single keyword-only argument, ``empty``, is included and defaults to ``False``. ``empty`` changes how the tag is rendered if it has no children. Normally, a tag with no children is rendered like ``
    ``. If ``empty`` is ``True``, then it will render like ``
    ``. The rest of the keyword arguments, ``props``, render as HTML attributes. .. code-block:: clj => (defn render-html-tag [tag-name &optional [delim ""] &rest children &kwonly [empty False] &kwargs attrs] ... (setv rendered-attrs (.join " " (lfor (, key val) (.items attrs) (+ (unmangle (str key)) "=\"" (str val) "\"")))) ... (if rendered-attrs ; If we have attributes, prefix them with a space after the tag name ... (setv rendered-attrs (+ " " rendered-attrs))) ... (setv rendered-children (.join delim children)) ... (if (and (not children) empty) ... (+ "<" tag-name rendered-attrs " />") ... (+ "<" tag-name rendered-attrs ">" rendered-children ""))) => (render-html-tag "div") '
    => (render-html-tag "img" :empty True) '' => (render-html-tag "img" :id "china" :class "big-image" :empty True) '' => (render-html-tag "p" " --- " (render-html-tag "span" "" :class "fancy" "I'm fancy!") "I'm to the right of fancy" "I'm alone :(") '

    I\'m fancy! --- I\'m to right right of fancy --- I\'m alone :(

    ' defn/a ------ ``defn/a`` macro is a variant of ``defn`` that instead defines coroutines. 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/a name [params] body) 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 deftag -------- .. versionadded:: 0.13.0 ``deftag`` defines a tag macro. A tag macro is a unary macro that has the same semantics as an ordinary macro defined with ``defmacro``. It is called with the syntax ``#tag FORM``, where ``tag`` is the name of the macro, and ``FORM`` is any form. The ``tag`` is often only one character, but it can be any symbol. .. code-block:: clj => (deftag ♣ [expr] `[~expr ~expr]) at 0x7f76d0271158> => #♣ 5 [5, 5] => (setv x 0) => #♣(+= x 1) [None, None] => x 2 In this example, if you used ``(defmacro ♣ ...)`` instead of ``(deftag ♣ ...)``, you would call the macro as ``(♣ 5)`` or ``(♣ (+= x 1))``. The syntax for calling tag macros is similar to that of reader macros a la Common Lisp's ``SET-MACRO-CHARACTER``. In fact, before Hy 0.13.0, tag macros were called "reader macros", and defined with ``defreader`` rather than ``deftag``. True reader macros are not (yet) implemented in Hy. 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-and-compile ---------------- ``eval-and-compile`` is a special form that takes any number of forms. The input forms are evaluated as soon as the ``eval-and-compile`` form is compiled, instead of being deferred until run-time. The input forms are also left in the program so they can be executed at run-time as usual. So, if you compile and immediately execute a program (as calling ``hy foo.hy`` does when ``foo.hy`` doesn't have an up-to-date byte-compiled version), ``eval-and-compile`` forms will be evaluated twice. One possible use of ``eval-and-compile`` is to make a function available both at compile-time (so a macro can call it while expanding) and run-time (so it can be called like any other function):: (eval-and-compile (defn add [x y] (+ x y))) (defmacro m [x] (add x 2)) (print (m 3)) ; prints 5 (print (add 3 6)) ; prints 9 Had the ``defn`` not been wrapped in ``eval-and-compile``, ``m`` wouldn't be able to call ``add``, because when the compiler was expanding ``(m 3)``, ``add`` wouldn't exist yet. eval-when-compile ----------------- ``eval-when-compile`` is like ``eval-and-compile``, but the code isn't executed at run-time. Hence, ``eval-when-compile`` doesn't directly contribute any code to the final program, although it can still change Hy's state while compiling (e.g., by defining a function). .. code-block:: clj (eval-when-compile (defn add [x y] (+ x y))) (defmacro m [x] (add x 2)) (print (m 3)) ; prints 5 (print (add 3 6)) ; raises NameError: name 'add' is not defined first ----- ``first`` is a function for accessing the first element of a collection. .. code-block:: clj => (first (range 10)) 0 It is implemented as ``(next (iter coll) None)``, so it works with any iterable, and if given an empty iterable, it will return ``None`` instead of raising an exception. .. code-block:: clj => (first (repeat 10)) 10 => (first []) None .. _for: for --- ``for`` is used to evaluate some forms for each element in an iterable object, such as a list. The return values of the forms are discarded and the ``for`` form returns ``None``. :: => (for [x [1 2 3]] ... (print "iterating") ... (print x)) iterating 1 iterating 2 iterating 3 In its square-bracketed first argument, ``for`` allows the same types of clauses as lfor_. :: => (for [x [1 2 3] :if (!= x 2) y [7 8]] ... (print x y)) 1 7 1 8 3 7 3 8 Furthermore, the last argument of ``for`` can be an ``(else …)`` form. This form is executed after the last iteration of the ``for``\'s outermost iteration clause, but only if that outermost loop terminates normally. If it's jumped out of with e.g. ``break``, the ``else`` is ignored. .. 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 .. _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) HySymbol('_G\uffff1') => (gensym "x") HySymbol('_x\uffff2') .. seealso:: Section :ref:`using-gensym` .. _get: get --- ``get`` is used to access single elements in collections. ``get`` takes at least two parameters: the *data structure* and the *index* or *key* of the item. It will then return the corresponding value from the collection. If multiple *index* or *key* values are provided, they are used to access successive elements in a nested structure. Example usage: .. code-block:: clj => (do ... (setv animals {"dog" "bark" "cat" "meow"} ... numbers (, "zero" "one" "two" "three") ... nested [0 1 ["a" "b" "c"] 3 4]) ... (print (get animals "dog")) ... (print (get numbers 2)) ... (print (get nested 2 1))) bark two b .. 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. .. _gfor: gfor ---- ``gfor`` creates a :ref:`generator expression `. Its syntax is the same as that of `lfor`_. The difference is that ``gfor`` returns an iterator, which evaluates and yields values one at a time. :: => (setv accum []) => (list (take-while ... (fn [x] (< x 5)) ... (gfor x (count) :do (.append accum x) x))) [0, 1, 2, 3, 4] => accum [0, 1, 2, 3, 4, 5] 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* / 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 can override 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 ------ ``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 [*]]) .. _fn: fn ----------- ``fn``, like Python's ``lambda``, can be used to define an anonymous function. Unlike Python's ``lambda``, the body of the function can comprise several statements. The parameters are similar to ``defn``: the first parameter is vector of parameters and the rest is the body of the function. ``fn`` returns a new function. In the following example, an anonymous function is defined and passed to another function for filtering output. .. code-block:: clj => (setv 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) fn/a ---- ``fn/a`` is a variant of ``fn`` than defines an anonymous coroutine. The parameters are similar to ``defn/a``: the first parameter is vector of parameters and the rest is the body of the function. ``fn/a`` returns a new coroutine. 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 .. _lfor: lfor ---- The comprehension forms ``lfor``, `sfor`_, `dfor`_, `gfor`_, and `for`_ are used to produce various kinds of loops, including Python-style :ref:`comprehensions `. ``lfor`` in particular creates a list comprehension. A simple use of ``lfor`` is:: => (lfor x (range 5) (* 2 x)) [0, 2, 4, 6, 8] ``x`` is the name of a new variable, which is bound to each element of ``(range 5)``. Each such element in turn is used to evaluate the value form ``(* 2 x)``, and the results are accumulated into a list. Here's a more complex example:: => (lfor ... x (range 3) ... y (range 3) ... :if (!= x y) ... :setv total (+ x y) ... [x y total]) [[0, 1, 1], [0, 2, 2], [1, 0, 1], [1, 2, 3], [2, 0, 2], [2, 1, 3]] When there are several iteration clauses (here, the pairs of forms ``x (range 3)`` and ``y (range 3)``), the result works like a nested loop or Cartesian product: all combinations are considered in lexicographic order. The general form of ``lfor`` is:: (lfor CLAUSES VALUE) where the ``VALUE`` is an arbitrary form that is evaluated to produce each element of the result list, and ``CLAUSES`` is any number of clauses. There are several types of clauses: - Iteration clauses, which look like ``LVALUE ITERABLE``. The ``LVALUE`` is usually just a symbol, but could be something more complicated, like ``[x y]``. - ``:async LVALUE ITERABLE``, which is an :ref:`asynchronous ` form of iteration clause. - ``:do FORM``, which simply evaluates the ``FORM``. If you use ``(continue)`` or ``(break)`` here, they will apply to the innermost iteration clause before the ``:do``. - ``:setv LVALUE RVALUE``, which is equivalent to ``:do (setv LVALUE RVALUE)``. - ``:if CONDITION``, which is equivalent to ``:do (unless CONDITION (continue))``. For ``lfor``, ``sfor``, ``gfor``, and ``dfor``, variables are scoped as if the comprehension form were its own function, so variables defined by an iteration clause or ``:setv`` are not visible outside the form. In fact, these forms are implemented as generator functions whenever they contain Python statements, with the attendant consequences for calling ``return``. By contrast, ``for`` shares the caller's scope. nonlocal -------- .. versionadded:: 0.11.1 ``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 ``fn`` scopes: .. code-block:: clj (defn some-function [] (setv x 0) (register-some-callback (fn [stuff] (nonlocal x) (setv x stuff)))) 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 of -- ``of`` is an alias for get, but with special semantics designed for handling PEP 484's generic types. ``of`` has three forms: - ``(of T)`` will simply become ``T``. - ``(of T x)`` will become ``(get T x)``. - ``(of T x y ...)`` (where the ``...`` represents zero or more arguments) will become ``(get T (, x y ...))``. For instance: .. code-block:: clj (of str) ; => str (of List int) ; => List[int] (of Set int) ; => Set[int] (of Dict str str) ; => Dict[str, str] (of Tuple str int) ; => Tuple[str, int] (of Callable [int str] str) ; => Callable[[int, str], str] .. _py-specialform: py -- ``py`` parses the given Python code at compile-time and inserts the result into the generated abstract syntax tree. Thus, you can mix Python code into a Hy program. Only a Python expression is allowed, not statements; use :ref:`pys-specialform` if you want to use Python statements. The value of the expression is returned from the ``py`` form. :: (print "A result from Python:" (py "'hello' + 'world'")) The code must be given as a single string literal, but you can still use macros, :ref:`eval-fn`, and related tools to construct the ``py`` form. If having to backslash-escape internal double quotes is getting you down, try a :ref:`bracket string `. If you want to evaluate some Python code that's only defined at run-time, try the standard Python function :func:`eval`. Python code need not syntactically round-trip if you use ``hy2py`` on a Hy program that uses ``py`` or ``pys``. For example, comments will be removed. .. _pys-specialform: pys --- As :ref:`py-specialform`, but the code can consist of zero or more statements, including compound statements such as ``for`` and ``def``. ``pys`` always returns ``None``. Also, the code string is dedented with :func:`textwrap.dedent` before parsing, which allows you to intend the code to match the surrounding Hy code, but significant leading whitespace in embedded string literals will be removed. :: (pys "myvar = 5") (print "myvar is" myvar) .. _quasiquote: 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 ----- ``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")) => x ; variable x is set to unevaluated expression HyExpression([ HySymbol('print'), HyString('Hello World')]) => (eval x) Hello World .. _require: 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 (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 ---- ``rest`` takes the given collection and returns an iterable of all but the first element. .. code-block:: clj => (list (rest (range 10))) [1, 2, 3, 4, 5, 6, 7, 8, 9] Given an empty collection, it returns an empty iterable. .. code-block:: clj => (list (rest [])) [] return ------- ``return`` compiles to a :py:keyword:`return` statement. It exits the current function, returning its argument if provided with one or ``None`` if not. .. code-block:: hy => (defn f [x] (for [n (range 10)] (when (> n x) (return n)))) => (f 3.9) 4 Note that in Hy, ``return`` is necessary much less often than in Python, since the last form of a function is returned automatically. Hence, an explicit ``return`` is only necessary to exit a function early. .. code-block:: hy => (defn f [x] (setv y 10) (+ x y)) => (f 4) 14 To get Python's behavior of returning ``None`` when execution reaches the end of a function, put ``None`` there yourself. .. code-block:: hy => (defn f [x] (setv y 10) (+ x y) None) => (print (f 4)) None sfor ---- ``sfor`` creates a set comprehension. ``(sfor CLAUSES VALUE)`` is equivalent to ``(set (lfor CLAUSES VALUE))``. See `lfor`_. .. _cut: 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 => (setv 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 catch exceptions (``except``) and run cleanup actions (``finally``). .. code-block:: clj (try (error-prone-function) (another-error-prone-function) (except [ZeroDivisionError] (print "Division by zero")) (except [[IndexError KeyboardInterrupt]] (print "Index error or Ctrl-C")) (except [e ValueError] (print "ValueError:" (repr e))) (except [e [TabError PermissionError ReferenceError]] (print "Some sort of error:" (repr e))) (else (print "No errors")) (finally (print "All done"))) The first argument of ``try`` is its body, which can contain one or more forms. Then comes any number of ``except`` clauses, then optionally an ``else`` clause, then optionally a ``finally`` clause. If an exception is raised with a matching ``except`` clause during the execution of the body, that ``except`` clause will be executed. If no exceptions are raised, the ``else`` clause is executed. The ``finally`` clause will be executed last regardless of whether an exception was raised. The return value of ``try`` is the last form of the ``except`` clause that was run, or the last form of ``else`` if no exception was raised, or the ``try`` body if there is no ``else`` clause. 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)) .. _unpack-iterable: unpack-iterable, unpack-mapping ------------------------------- (Also known as the splat operator, star operator, argument expansion, argument explosion, argument gathering, and varargs, among others...) ``unpack-iterable`` and ``unpack-mapping`` allow an iterable or mapping object (respectively) to provide positional or keywords arguments (respectively) to a function. .. code-block:: clj => (defn f [a b c d] [a b c d]) => (f (unpack-iterable [1 2]) (unpack-mapping {"c" 3 "d" 4})) [1, 2, 3, 4] ``unpack-iterable`` is usually written with the shorthand ``#*``, and ``unpack-mapping`` with ``#**``. .. code-block:: clj => (f #* [1 2] #** {"c" 3 "d" 4}) [1, 2, 3, 4] Unpacking is allowed in a variety of contexts, and you can unpack more than once in one expression (:pep:`3132`, :pep:`448`). .. code-block:: clj => (setv [a #* b c] [1 2 3 4 5]) => [a b c] [1, [2, 3, 4], 5] => [#* [1 2] #* [3 4]] [1, 2, 3, 4] => {#** {1 2} #** {3 4}} {1: 2, 3: 4} => (f #* [1] #* [2] #** {"c" 3} #** {"d" 4}) [1, 2, 3, 4] .. _unquote: unquote ------- Within a quasiquoted form, ``unquote`` forces evaluation of a symbol. ``unquote`` is aliased to the tilde (``~``) symbol. .. code-block:: clj => (setv nickname "Cuddles") => (quasiquote (= nickname (unquote nickname))) HyExpression([ HySymbol('='), HySymbol('nickname'), 'Cuddles']) => `(= nickname ~nickname) HyExpression([ HySymbol('='), HySymbol('nickname'), 'Cuddles']) unquote-splice -------------- ``unquote-splice`` forces the evaluation of a symbol within a quasiquoted form, much like ``unquote``. ``unquote-splice`` can be used when the symbol being unquoted contains an iterable value, as it "splices" that iterable into the quasiquoted form. ``unquote-splice`` can also be used when the value evaluates to a false value such as ``None``, ``False``, or ``0``, in which case the value is treated as an empty list and thus does not splice anything into the form. ``unquote-splice`` is aliased to the ``~@`` syntax. .. code-block:: clj => (setv nums [1 2 3 4]) => (quasiquote (+ (unquote-splice nums))) HyExpression([ HySymbol('+'), 1, 2, 3, 4]) => `(+ ~@nums) HyExpression([ HySymbol('+'), 1, 2, 3, 4]) => `[1 2 ~@(if (neg? (first nums)) nums)] HyList([ HyInteger(1), HyInteger(2)]) Here, the last example evaluates to ``('+' 1 2)``, since the condition ``(< (nth nums 0) 0)`` is ``False``, which makes this ``if`` expression evaluate to ``None``, because the ``if`` expression here does not have an else clause. ``unquote-splice`` then evaluates this as an empty value, leaving no effects on the list it is enclosed in, therefore resulting in ``('+' 1 2)``. 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 ----- ``while`` compiles to a :py:keyword:`while` statement. It is used to execute a set of forms as long as a condition is met. The first argument to ``while`` is the condition, and any remaining forms constitute the body. The following example will output "Hello world!" to the screen indefinitely: .. code-block:: clj (while True (print "Hello world!")) The last form of a ``while`` loop can be an ``else`` clause, which is executed after the loop terminates, unless it exited abnormally (e.g., with ``break``). So, .. code-block:: clj (setv x 2) (while x (print "In body") (-= x 1) (else (print "In else"))) prints :: In body In body In else If you put a ``break`` or ``continue`` form in the condition of a ``while`` loop, it will apply to the very same loop rather than an outer loop, even if execution is yet to ever reach the loop body. (Hy compiles a ``while`` loop with statements in its condition by rewriting it so that the condition is actually in the body.) So, .. code-block:: clj (for [x [1]] (print "In outer loop") (while (do (print "In condition") (break) (print "This won't print.") True) (print "This won't print, either.")) (print "At end of outer loop")) prints :: In outer loop In condition At end of outer loop .. _with: 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`` returns the value of its last form, unless it suppresses an exception (because the context manager's ``__exit__`` method returned true), in which case it returns ``None``. So, the previous example could also be written .. code-block:: clj (print (with [f (open "NEWS")] (.read f))) with/a ------ ``with/a`` behaves like ``with``, but is used to wrap the execution of a block within an asynchronous context manager. The context manager can then set up the local system and tear it down in a controlled manner asynchronously. .. code-block:: clj (with/a [arg (expr)] block) (with/a [(expr)] block) (with/a [arg (expr) (expr)] block) ``with/a`` returns the value of its last form, unless it suppresses an exception (because the context manager's ``__aexit__`` method returned true), in which case it returns ``None``. 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 tag 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 (do (setv a (gensym) b (gensym) c (gensym)) ...) .. seealso:: Section :ref:`using-gensym` xor --- .. versionadded:: 0.12.0 ``xor`` performs the logical operation of exclusive OR. It takes two arguments. If exactly one argument is true, that argument is returned. If neither is true, the second argument is returned (which will necessarily be false). Otherwise, when both arguments are true, the value ``False`` is returned. .. code-block:: clj => [(xor 0 0) (xor 0 1) (xor 1 0) (xor 1 1)] [0, 1, 1, False] 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 (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 (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 ``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.18.0/docs/language/cli.rst000066400000000000000000000037011361554632000162420ustar00rootroot00000000000000====================== 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:: --repl-output-fn Format REPL output using specific function (e.g., hy.contrib.hy-repr.hy-repr) .. versionadded:: 0.13.0 .. 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.18.0/docs/language/core.rst000066400000000000000000000564401361554632000164330ustar00rootroot00000000000000======= 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 => (setv example (comp str +)) => (example 1 2 3) "6" => (setv 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 => (setv inverse (complement identity)) => (inverse True) False => (inverse 1) False => (inverse False) True .. _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 => (setv 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 .. _eval-fn: 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. An optional fourth keyword parameter, ``compiler``, allows one to re-use an existing ``HyASTCompiler`` object for the compilation step. .. 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 .. _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 (``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") HyKeyword('foo') => (keyword 1) HyKeyword('foo') .. _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 .. _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))) HyExpression([ HySymbol('x'), HyExpression([ HySymbol('a'), HySymbol('b')]), HySymbol('y')]) => (macroexpand '(-> (a b) (-> (c d) (e f)))) HyExpression([ HySymbol('e'), HyExpression([ HySymbol('c'), HyExpression([ HySymbol('a'), HySymbol('b')]), HySymbol('d')]), HySymbol('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)))) HyExpression([ HySymbol('_>'), HyExpression([ HySymbol('a'), HySymbol('b')]), HyExpression([ HySymbol('c'), HySymbol('d')]), HyExpression([ HySymbol('e'), HySymbol('f')])]) .. _mangle-fn: mangle ------ Usage: ``(mangle x)`` Stringify the input and translate it according to :ref:`Hy's mangling rules `. .. code-block:: hylang => (mangle "foo-bar") 'foo_bar' .. _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 + {"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 => (setv 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 .. _parse-args: parse-args ---------- Usage: ``(parse-args spec &optional args &kwargs parser-args)`` Return arguments namespace parsed from *args* or ``sys.argv`` with :py:meth:`argparse.ArgumentParser.parse_args` according to *spec*. *spec* should be a list of arguments which will be passed to repeated calls to :py:meth:`argparse.ArgumentParser.add_argument`. *parser-args* may be a list of keyword arguments to pass to the :py:class:`argparse.ArgumentParser` constructor. .. code-block:: hy => (parse-args [["strings" :nargs "+" :help "Strings"] ["-n" "--numbers" :action "append" :type 'int :help "Numbers"]] ["a" "b" "-n" "1" "-n" "2"] :description "Parse strings and numbers from args") Namespace(numbers=[1, 2], strings=['a', 'b']) .. _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 .. _list?-fn: list? ----- Usage: ``(list? x)`` Returns ``True`` if *x* is a list. .. code-block:: hy => (list? '(inc 41)) True => (list? '42) False .. _string?-fn: string? ------- Usage: ``(string? x)`` Returns ``True`` if *x* is a string (``str``). .. 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 .. _tuple?-fn: tuple? ------ Usage: ``(tuple? x)`` Returns ``True`` if *x* is a tuple. .. code-block:: hy => (tuple? (, 42 44)) True => (tuple? [42 44]) 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) HyExpression([ HySymbol('+'), HyInteger(2), HyInteger(2)]) => (eval (read)) (+ 2 2) 4 => (import io) => (setv buffer (io.StringIO "(+ 2 2)\n(- 2 1)")) => (eval (read :from-file buffer)) 4 => (eval (read :from-file buffer)) 1 => (with [f (open "example.hy" "w")] ... (.write f "(print 'hello)\n(print \"hyfriends!\")")) 35 => (with [f (open "example.hy")] ... (try (while True ... (setv exp (read f)) ... (print "OHY" exp) ... (eval exp)) ... (except [e EOFError] ... (print "EOF!")))) OHY HyExpression([ HySymbol('print'), HyExpression([ HySymbol('quote'), HySymbol('hello')])]) hello OHY HyExpression([ HySymbol('print'), HyString('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)") HyExpression([ HySymbol('print'), HyInteger(1)]) => (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])) [] .. _unmangle-fn: unmangle -------- Usage: ``(unmangle x)`` Stringify the input and return a string that would :ref:`mangle ` to it. Note that this isn't a one-to-one operation, and nor is ``mangle``, so ``mangle`` and ``unmangle`` don't always round-trip. .. code-block:: hylang => (unmangle "foo_bar") 'foo-bar' 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.18.0/docs/language/index.rst000066400000000000000000000002351361554632000166010ustar00rootroot00000000000000 Documentation Index =================== Contents: .. toctree:: :maxdepth: 3 cli interop syntax api core model_patterns internals hy-0.18.0/docs/language/internals.rst000066400000000000000000000337321361554632000175010ustar00rootroot00000000000000========================= 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. Hy uses pretty-printing reprs for its compound models by default. If this is causing issues, it can be turned off globally by setting ``hy.models.PRETTY`` to ``False``, or temporarily by using the ``hy.models.pretty`` context manager. Hy also attempts to color pretty reprs and errors using ``colorama``. These can be turned off globally by setting ``hy.models.COLORED`` and ``hy.errors.COLORED``, respectively, to ``False``. .. _hysequence: HySequence ~~~~~~~~~~ ``hy.models.HySequence`` is the abstract base class of "iterable" Hy models, such as HyExpression and HyList. Adding a HySequence 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. HySequences are (mostly) immutable: you can't add, modify, or remove elements. You can still append to a variable containing a HySequence with ``+=`` and otherwise construct new HySequences out of old ones. .. _hylist: HyList ~~~~~~ ``hy.models.HyList`` is a :ref:`HySequence` for bracketed ``[]`` lists, which, when used as a top-level expression, translate to Python list literals in the compilation phase. .. _hyexpression: HyExpression ~~~~~~~~~~~~ ``hy.models.HyExpression`` inherits :ref:`HySequence` 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.HyDict`` inherits :ref:`HySequence` for curly-bracketed ``{}`` expressions, which compile down to a Python dictionary literal. 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.HyString`` represents string literals (including bracket strings), which compile down to unicode string literals (``str``) in Python. ``HyString``\s 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. ``HyString``\s have an attribute ``brackets`` that stores the custom delimiter used for a bracket string (e.g., ``"=="`` for ``#[==[hello world]==]`` and the empty string for ``#[[hello world]]``). ``HyString``\s that are not produced by bracket strings have their ``brackets`` set to ``None``. HyBytes ~~~~~~~ ``hy.models.HyBytes`` is like ``HyString``, but for sequences of bytes. It inherits from ``bytes``. .. _hy_numeric_models: Numeric Models ~~~~~~~~~~~~~~ ``hy.models.HyInteger`` represents integer literals, using the ``int`` type. ``hy.models.HyFloat`` represents floating-point literals. ``hy.models.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.HySymbol`` is the model used to represent symbols in the Hy language. Like ``HyString``, it inherits from ``str`` (or ``unicode`` on Python 2). Symbols are :ref:`mangled ` when they are compiled to Python variable names. .. _hykeyword: HyKeyword ~~~~~~~~~ ``hy.models.HyKeyword`` represents keywords in Hy. Keywords are symbols starting with a ``:``. See :ref:`syntax-keywords`. 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 reconfigure 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: _temp_name_here = True else: _temp_name_here = False print(_temp_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] `(do (setv 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] (setv g (gensym)) `(do (setv ~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 ``setv`` form: .. code-block:: hy (with-gensyms [a b c] ...) expands to: .. code-block:: hy (do (setv 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] `(do (setv ~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] `(do (setv ~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.18.0/docs/language/interop.rst000066400000000000000000000073101361554632000171530ustar00rootroot00000000000000.. _interop: ===================== Hy <-> Python interop ===================== Despite being a Lisp, Hy aims to be fully compatible with Python. That means every Python module or package can be imported in Hy code, and vice versa. :ref:`Mangling ` allows variable names to be spelled differently in Hy and Python. For example, Python's ``str.format_map`` can be written ``str.format-map`` in Hy, and a Hy function named ``valid?`` would be called ``is_valid`` in Python. In Python, you can import Hy's core functions ``mangle`` and ``unmangle`` directly from the ``hy`` package. Using Python from Hy ==================== You can embed Python code directly into a Hy program with the special operators :ref:`py-specialform` and :ref:`pys-specialform`. Using a Python module from Hy is nice and easy: you just have to :ref:`import` it. If you have the following in ``greetings.py`` in Python:: def greet(name): print("hello," name) You can use it in Hy: .. code-block:: clj (import greetings) (.greet greetings "foo") ; prints "hello, foo" You can also import ``.pyc`` bytecode files, of course. Using Hy from Python ==================== Suppose you have written some useful utilities in Hy, and you want to use them in regular Python, or to share them with others as a package. Or suppose you work with somebody else, who doesn't like Hy (!), and only uses Python. In any case, you need to know how to use Hy from Python. Fear not, for it is easy. If you save the following in ``greetings.hy``: .. code-block:: clj (setv this-will-have-underscores "See?") (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") # prints "Hello from Hy, Foo" print(greetings.this_will_have_underscores) # prints "See?" If you create a package with Hy code, and you do the ``import hy`` in ``__init__.py``, you can then directly include the package. Of course, Hy still has to be installed. Compiled files -------------- You can also compile a module with ``hyc``, which gives you a ``.pyc`` file. You can import that file. Hy does not *really* need to be installed ; however, if in your code, you use any symbol from :doc:`core`, a corresponding ``import`` statement will be generated, and Hy will have to be installed. Even if you do not use a Hy builtin, but just another function or variable with the name of a Hy builtin, the ``import`` will be generated. For example, the previous code causes the import of ``name`` from ``hy.core.language``. **Bottom line: in most cases, Hy has to be installed.** Launching a Hy REPL from Python ------------------------------- You can use the function ``run_repl()`` to launch the Hy REPL from Python:: >>> import hy.cmdline >>> hy.cmdline.run_repl() hy 0.12.1 using CPython(default) 3.6.0 on Linux => (defn foo [] (print "bar")) => (test) bar If you want to print the Python code Hy generates for you, use the ``spy`` argument:: >>> import hy.cmdline >>> hy.cmdline.run_repl(spy=True) hy 0.12.1 using CPython(default) 3.6.0 on Linux => (defn test [] (print "bar")) def test(): return print('bar') => (test) test() bar Evaluating strings of Hy code from Python ----------------------------------------- Evaluating a string (or ``file`` object) containing a Hy expression requires two separate steps. First, use the ``read_str`` function (or ``read`` for a ``file`` object) to turn the expression into a Hy model:: >>> import hy >>> expr = hy.read_str("(- (/ (+ 1 3 88) 2) 8)") Then, use the ``eval`` function to evaluate it:: >>> hy.eval(expr) 38.0 hy-0.18.0/docs/language/model_patterns.rst000066400000000000000000000067761361554632000205320ustar00rootroot00000000000000============== Model Patterns ============== The module ``hy.model-patterns`` provides a library of parser combinators for parsing complex trees of Hy models. Model patterns exist mostly to help implement the compiler, but they can also be useful for writing macros. A motivating example -------------------- The kind of problem that model patterns are suited for is the following. Suppose you want to validate and extract the components of a form like: .. code-block:: clj (setv form '(try (foo1) (foo2) (except [EType1] (foo3)) (except [e EType2] (foo4) (foo5)) (except [] (foo6)) (finally (foo7) (foo8)))) You could do this with loops and indexing, but it would take a lot of code and be error-prone. Model patterns concisely express the general form of an expression to be matched, like what a regular expression does for text. Here's a pattern for a ``try`` form of the above kind: .. code-block:: clj (import [funcparserlib.parser [maybe many]]) (import [hy.model-patterns [*]]) (setv parser (whole [ (sym "try") (many (notpexpr "except" "else" "finally")) (many (pexpr (sym "except") (| (brackets) (brackets FORM) (brackets SYM FORM)) (many FORM))) (maybe (dolike "else")) (maybe (dolike "finally"))])) You can run the parser with ``(.parse parser form)``. The result is: .. code-block:: clj (, ['(foo1) '(foo2)] [ '([EType1] [(foo3)]) '([e EType2] [(foo4) (foo5)]) '([] [(foo6)])] None '((foo7) (foo8))) which is conveniently utilized with an assignment such as ``(setv [body except-clauses else-part finally-part] result)``. Notice that ``else-part`` will be set to ``None`` because there is no ``else`` clause in the original form. Usage ----- Model patterns are implemented as funcparserlib_ parser combinators. We won't reproduce funcparserlib's own documentation, but here are some important built-in parsers: - ``(+ ...)`` matches its arguments in sequence. - ``(| ...)`` matches any one of its arguments. - ``(>> parser function)`` matches ``parser``, then feeds the result through ``function`` to change the value that's produced on a successful parse. - ``(skip parser)`` matches ``parser``, but doesn't add it to the produced value. - ``(maybe parser)`` matches ``parser`` if possible. Otherwise, it produces the value ``None``. - ``(some function)`` takes a predicate ``function`` and matches a form if it satisfies the predicate. The best reference for Hy's parsers is the docstrings (use ``(help hy.model-patterns)``), but again, here are some of the more important ones: - ``FORM`` matches anything. - ``SYM`` matches any symbol. - ``(sym "foo")`` or ``(sym ":foo")`` matches and discards (per ``skip``) the named symbol or keyword. - ``(brackets ...)`` matches the arguments in square brackets. - ``(pexpr ...)`` matches the arguments in parentheses. Here's how you could write a simple macro using model patterns: .. code-block:: clj (defmacro pairs [&rest args] (import [funcparserlib.parser [many]]) (import [hy.model-patterns [whole SYM FORM]]) (setv [args] (->> args (.parse (whole [ (many (+ SYM FORM))])))) `[~@(->> args (map (fn [x] (, (name (get x 0)) (get x 1)))))]) (print (pairs a 1 b 2 c 3)) ; => [["a" 1] ["b" 2] ["c" 3]] A failed parse will raise ``funcparserlib.parser.NoParseError``. .. _funcparserlib: https://github.com/vlasovskikh/funcparserlib hy-0.18.0/docs/language/syntax.rst000066400000000000000000000176421361554632000170320ustar00rootroot00000000000000.. _syntax: ============== Syntax ============== identifiers ----------- An identifier consists of a nonempty sequence of Unicode characters that are not whitespace nor any of the following: ``( ) [ ] { } ' "``. Hy first tries to parse each identifier into a numeric literal, then into a keyword if that fails, and finally into a symbol if that fails. numeric literals ---------------- In addition to regular numbers, standard notation from Python for non-base 10 integers is used. ``0x`` for Hex, ``0o`` for Octal, ``0b`` for Binary. .. code-block:: clj (print 0x80 0b11101 0o102 30) Underscores and commas can appear anywhere in a numeric literal except the very beginning. They have no effect on the value of the literal, but they're useful for visually separating digits. .. code-block:: clj (print 10,000,000,000 10_000_000_000) Unlike Python, Hy provides literal forms for NaN and infinity: ``NaN``, ``Inf``, and ``-Inf``. string literals --------------- Hy allows double-quoted strings (e.g., ``"hello"``), but not single-quoted strings like Python. The single-quote character ``'`` is reserved for preventing the evaluation of a form (e.g., ``'(+ 1 1)``), as in most Lisps. .. _syntax-bracket-strings: Python's so-called triple-quoted strings (e.g., ``'''hello'''`` and ``"""hello"""``) aren't supported. However, in Hy, unlike Python, any string literal can contain newlines. Furthermore, Hy supports an alternative form of string literal called a "bracket string" similar to Lua's long brackets. Bracket strings have customizable delimiters, like the here-documents of other languages. A bracket string begins with ``#[FOO[`` and ends with ``]FOO]``, where ``FOO`` is any string not containing ``[`` or ``]``, including the empty string. (If ``FOO`` is exactly ``f`` or begins with ``f-``, the bracket string is interpreted as a :ref:`format string `.) For example:: => (print #[["That's very kind of yuo [sic]" Tom wrote back.]]) "That's very kind of yuo [sic]" Tom wrote back. => (print #[==[1 + 1 = 2]==]) 1 + 1 = 2 A bracket string can contain newlines, but if it begins with one, the newline is removed, so you can begin the content of a bracket string on the line following the opening delimiter with no effect on the content. Any leading newlines past the first are preserved. Plain string literals support :ref:`a variety of backslash escapes `. To create a "raw string" that interprets all backslashes literally, prefix the string with ``r``, as in ``r"slash\not"``. Bracket strings are always raw strings and don't allow the ``r`` prefix. Like Python, Hy treats all string literals as sequences of Unicode characters by default. You may prefix a plain string literal (but not a bracket string) with ``b`` to treat it as a sequence of bytes. Unlike Python, Hy only recognizes string prefixes (``r``, etc.) in lowercase. .. _syntax-fstrings: format strings -------------- A format string (or "f-string", or "formatted string literal") is a string literal with embedded code, possibly accompanied by formatting commands. Hy f-strings work much like :ref:`Python f-strings ` except that the embedded code is in Hy rather than Python, and they're supported on all versions of Python. :: => (print f"The sum is {(+ 1 1)}.") The sum is 2. Since ``!`` and ``:`` are identifier characters in Hy, Hy decides where the code in a replacement field ends, and any conversion or format specifier begins, by parsing exactly one form. You can use ``do`` to combine several forms into one, as usual. Whitespace may be necessary to terminate the form:: => (setv foo "a") => (print f"{foo:x<5}") … NameError: name 'hyx_fooXcolonXxXlessHthan_signX5' is not defined => (print f"{foo :x<5}") axxxx Unlike Python, whitespace is allowed between a conversion and a format specifier. Also unlike Python, comments and backslashes are allowed in replacement fields. Hy's lexer will still process the whole format string normally, like any other string, before any replacement fields are considered, so you may need to backslash your backslashes, and you can't comment out a closing brace or the string delimiter. .. _syntax-keywords: keywords -------- An identifier headed by a colon, such as ``:foo``, is a keyword. If a literal keyword appears in a function call, it's used to indicate a keyword argument rather than passed in as a value. For example, ``(f :foo 3)`` calls the function ``f`` with the keyword argument named ``foo`` set to ``3``. Hence, trying to call a function on a literal keyword may fail: ``(f :foo)`` yields the error ``Keyword argument :foo needs a value``. To avoid this, you can quote the keyword, as in ``(f ':foo)``, or use it as the value of another keyword argument, as in ``(f :arg :foo)``. Keywords can be called like functions as shorthand for ``get``. ``(:foo obj)`` is equivalent to ``(get obj :foo)``. An optional ``default`` argument is also allowed: ``(:foo obj 2)`` or ``(:foo obj :default 2)`` returns ``2`` if ``(get obj :foo)`` raises a ``KeyError``. .. _mangling: symbols ------- Symbols are identifiers that are neither legal numeric literals nor legal keywords. In most contexts, symbols are compiled to Python variable names. Some example symbols are ``hello``, ``+++``, ``3fiddy``, ``$40``, ``just✈wrong``, and ``🦑``. Since the rules for Hy symbols are much more permissive than the rules for Python identifiers, Hy uses a mangling algorithm to convert its own names to Python-legal names. The rules are: - Convert all hyphens (``-``) to underscores (``_``). Thus, ``foo-bar`` becomes ``foo_bar``. - If the name ends with ``?``, remove it and prepend ``is_``. Thus, ``tasty?`` becomes ``is_tasty``. - If the name still isn't Python-legal, make the following changes. A name could be Python-illegal because it contains a character that's never legal in a Python name, it contains a character that's illegal in that position, or it's equal to a Python reserved word. - Prepend ``hyx_`` to the name. - Replace each illegal character with ``XfooX``, where ``foo`` is the Unicode character name in lowercase, with spaces replaced by underscores and hyphens replaced by ``H``. Replace ``X`` itself the same way. If the character doesn't have a name, use ``U`` followed by its code point in lowercase hexadecimal. Thus, ``green☘`` becomes ``hyx_greenXshamrockX`` and ``if`` becomes ``hyx_if``. - Finally, any added ``hyx_`` or ``is_`` is added after any leading underscores, because leading underscores have special significance to Python. Thus, ``_tasty?`` becomes ``_is_tasty`` instead of ``is__tasty``. Mangling isn't something you should have to think about often, but you may see mangled names in error messages, the output of ``hy2py``, etc. A catch to be aware of is that mangling, as well as the inverse "unmangling" operation offered by the ``unmangle`` function, isn't one-to-one. Two different symbols can mangle to the same string and hence compile to the same Python variable. The chief practical consequence of this is that ``-`` and ``_`` are interchangeable in all symbol names, so you shouldn't assign to the one-character name ``_`` , or else you'll interfere with certain uses of subtraction. discard prefix -------------- Hy supports the Extensible Data Notation discard prefix, like Clojure. Any form prefixed with ``#_`` is discarded instead of compiled. This completely removes the form so it doesn't evaluate to anything, not even None. It's often more useful than linewise comments for commenting out a form, because it respects code structure even when part of another form is on the same line. For example: .. code-block:: clj => (print "Hy" "cruel" "World!") Hy cruel World! => (print "Hy" #_"cruel" "World!") Hy World! => (+ 1 1 (print "Math is hard!")) Math is hard! Traceback (most recent call last): ... TypeError: unsupported operand type(s) for +: 'int' and 'NoneType' => (+ 1 1 #_(print "Math is hard!")) 2 hy-0.18.0/docs/make.bat000066400000000000000000000144631361554632000145720ustar00rootroot00000000000000@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.18.0/docs/style-guide.rst000066400000000000000000000627621361554632000161570ustar00rootroot00000000000000============== Hy Style Guide ============== The Hy style guide intends to be a set of ground rules for the Hyve (yes, the Hy community prides itself in appending Hy to everything) to write idiomatic Hy code. Hy derives a lot from Clojure & Common Lisp, while always maintaining Python interoperability. Layout & Indentation ==================== The #1 complaint about Lisp? *It's too weird looking with all those parentheses! How do you even* **read** *that?* And, they're right! Lisp was originally much too hard to read. Then they figured out layout and indentation. And it was glorious. The Three Laws -------------- Here's the secret: *Real Lispers don't count the brackets.* They fade into the background. When reading Lisp, disregard the trailing closing brackets---those are for the computer, not the human. As in Python, read the code structure by indentation. Lisp code is made of trees---Abstract Syntax Trees---not strings. S-expressions are very direct textual representation of AST. That's the level of *homoiconicity*---the level Lisp macros operate on. It's not like the C-preprocessor or Python's interpolated eval-string tricks that see code as just letters. That's not how to think of Lisp code; think tree structure, not delimiters. 1. Closing brackets must NEVER be left alone, sad and lonesome on their own line. .. code-block:: clj ;; PREFERRED (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) ; Lots of Irritating Superfluous Parentheses ; L.I.S.P. ;)) ;; How the experienced Lisper sees it. Indented trees. Like Python. (defn fib [n (if (<= n 2 n (+ (fib (- n 1 (fib (- n 2 ;; BAD ;; We're trying to ignore them and you want to give them their own line? ;; Hysterically ridiculous. (defn fib [ n ] ; My eyes! (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))) ) ) ; GAH, BURN IT WITH FIRE! 2. New lines must ALWAYS be indented past their parent opening bracket. .. code-block:: clj ;; PREFERRED (foo (, arg1 arg2)) ;; BAD. And evil. ;; Same bracket structure as above, but not enough indent. (foo (, arg1 arg2)) ;; PREFERRED. Same indent as above, but now it matches the brackets. (fn [arg] arg) ;; Remember, when reading Lisp, you ignore the trailing brackets. ;; Look at what happens if we remove them. ;; Can you tell where they should go by the indentation? (foo (, arg1 arg2 (foo (, arg1 arg2 (fn [arg arg ;; See how the structure of those last two became indistinguishable? ;; Reconstruction of the bad example by indent. ;; Not what we started with, is it? (foo (, arg1) arg2) ;; Beware of brackets with reader syntax. ;; You still have to indent past them. ;; BAD `#{(foo) ~@[(bar) 1 2]} ;; Above, no trail. `#{(foo ~@[(bar 1 2 ;; Reconstruction. Is. Wrong. `#{(foo)} ~@[(bar)] 1 2 ;; PREFERRED `#{(foo) ~@[(bar) 1 2]} ;; OK ;; A string is an atom, not a HySequence. (foo "abc xyz") ;; Still readable without trailing brackets. (foo "abc xyz" ; Double-quote isn't a closing bracket. Don't ignore it. 3. New lines must NEVER be indented past the previous element's opening bracket. .. code-block:: clj ;; BAD ((get-fn q) x y) ;; The above with trailing brackets removed. See the problem? ((get-fn q x y ;; By indentation, this is where the brackets should go. ((get-fn q x y)) ;; OK ((get-fn q) x y) ;; The above without trailing brackets. Still OK (for humans). ((get-fn q) x ; The ) on this line isn't trailing! y ;; PREFERRED, since the ) should end the line. ((get-fn q) x y) Limits ------ Follow PEP 8 rules for line limits, viz. + 72 columns max for text (docstrings and comments). + 79 columns max for other code, OR + 99 for other code if primarily maintained by a team that can agree to 99. Whitespace ---------- AVOID trailing spaces. They suck! AVOID tabs in code. Indent with spaces only. PREFER the ``\t`` escape sequence to literal tab characters in one-line string literals. + Literal tabs are OK inside multiline strings if you also add a warning comment. + But ``\t`` is still PREFERRED in multiline strings. + The comment should PREFERABLY appear just before the string. + But a blanket warning at the top of a function, class, or file is OK. Alignment --------- Line up arguments to function calls when splitting over multiple lines. + The first argument PREFERABLY stays on the first line with the function name, + but may instead start on the next line indented one space past its parent bracket. .. code-block:: clj ;; PREFERRED. All args aligned with first arg. (foofunction arg1 (barfunction bararg1 bararg2 bararg3) ; Aligned with bararg1. arg3) ;; BAD (foofunction arg1 (barfunction bararg1 bararg2 ; Wrong. Looks like a macro body. bararg3) ; Why?! arg3) ;; PREFERRED. Args can all go on one line if it fits. (foofunction arg1 (barfunction bararg1 bararg2 bararg3) arg3) ;; OK. Args not on first line, but still aligned. (foofunction arg1 ; Indented one column past parent ( (barfunction bararg1 ; Indent again. bararg2 ; Aligned with bararg1. bararg3) arg3) ; Aligned with arg1. Hold it Open ------------ If you need to separate a bracket trail use a ``#_ /`` comment to hold it open. This avoids violating law #1. .. code-block:: clj ;; PREFERRED [(foo) (bar) (baz)] ;; OK, especially if the list is long. (Not that three is long.) ;; This is better for version control line diffs. [ ; Opening brackets can't be "trailing closing brackets" btw. (foo) (bar) (baz) #_ /] ; Nothing to see here. Move along. ;; Examples of commenting out items at the end of a list follow. ;; As with typing things in the REPL, these cases are less important ;; if you're the only one that sees them. But even so, maintaining ;; good style can help prevent errors. ;; BAD and a syntax error. Lost a bracket. [(foo) ;; (bar) ;; (baz)] ;; BAD. Broke law #1. [(foo) ;; (bar) ;; (baz) ] ;; PREFERRED ;; The discard syntax respects code structure, ;; so it's less likely to cause errors. [(foo) #_(bar) #_(baz)] ;; OK. Adding a final discarded element makes line comments safer. [(foo) ;; (bar) ;; (baz) #_ /] Snuggle ------- Brackets like to snuggle, don't leave them out in the cold! .. code-block:: clj ;; PREFERRED [1 2 3] (foo (bar 2)) ;; BAD [ 1 2 3 ] ( foo ( bar 2 ) ) ;; BAD. And ugly. [ 1 2 3] (foo( bar 2) ) Grouping -------- Use whitespace to show implicit groups, but be consistent within a form. .. code-block:: clj ;; Older Lisps would typically wrap such groups in even more parentheses. ;; (The Common Lisp LOOP macro was a notable exception.) ;; But Hy takes after Clojure, which has a lighter touch. ;; BAD. Can't tell key from value without counting {1 9 2 8 3 7 4 6 5 5} ;; PREFERRED. This can fit on one line. Clojure would have used commas ;; here, but those aren't whitespace in Hy. Use extra spaces instead. {1 9 2 8 3 7 4 6 5 5} ;; OK. And preferred if it couldn't fit on one line. {1 9 2 8 3 7 4 6 5 5} ; Newlines show key-value pairs in dict. ;; BAD ;; This grouping makes no sense. #{1 2 3 4} ; It's a set, so why are there pairs? ;; BAD ;; This grouping also makes no sense. But, it could be OK in a macro or ;; something if this grouping was somehow meaningful there. [1 1 2 1 2 3] ; wHy do you like random patterns? [sic pun, sorry] ;; Be consistent. Separate all groups the same way in a form. ;; BAD {1 9 2 8 3 7 4 6 5 5} ; Pick one or the other! ;; BAD {1 9 2 8 3 7 4 6 5 5} ; You forgot something. ;; Groups of one must also be consistent. ;; PREFERRED (foo 1 2 3) ; No need for extra spaces here. ;; OK, but you could have fit this on one line. (foo 1 2 3) ;; OK, but you still could have fit this on one line. [1 2] ;; BAD (foo 1 2 ; This isn't a pair? 3) ; Lines or spaces--pick one or the other! ;; PREFERRRED (foofunction (make-arg) (get-arg) #tag(do-stuff) ; Tags belong with what they tag. #* args ; #* goes with what it unpacks. :foo spam :bar eggs ; Keyword args are also pairs. Group them. #** kwargs) ;; PREFERRED. Spaces divide groups on one line. (quux :foo spam :bar eggs #* with-spam) {:foo spam :bar eggs} ;; OK. The colon is still enough to indicate groups. (quux :foo spam :bar eggs #* with-spam) {:foo spam :bar eggs} ;; OK. ("foo" spam "bar" eggs} ;; BAD. Can't tell key from value. (quux :foo :spam :bar :eggs :baz :bacon) {:foo :spam :bar :eggs :baz :bacon} {"foo" "spam" "bar" "eggs" "baz" "bacon"} ;; PREFERRED (quux :foo :spam :bar :eggs :baz :bacon) {:foo :spam :bar :eggs :baz :bacon} {"foo" "spam" "bar" "eggs" "baz" "bacon"} ;; OK. Yep, those are pairs too. (setv x 1 y 2) ;; PREFERRED. This fits on one line. (setv x 1 y 2) ;; BAD. Doesn't separate groups. (print (if (< n 0.0) "negative" (= n 0.0) "zero" (> n 0.0) "positive" "not a number")) ;; BAD. And evil. Broke law #3. Shows groups but args aren't aligned. (print (if (< n 0.0) "negative" (= n 0.0) "zero" (> n 0.0) "positive" "not a number")) ;; BAD. Shows groups but args aren't aligned. ;; If the then-parts weren't atoms, this would break law #3. (print (if (< n 0.0) "negative" (= n 0.0) "zero" (> n 0.0) "positive" "not a number")) ;; OK. Redundant (do) forms allow extra indent to show groups ;; without violating law #3. (print (if (< n 0.0) (do "negative") (= n 0.0) (do "zero") (> n 0.0) (do "positive") "not a number")) Separate toplevel forms (including toplevel comments not about a particular form) with a single blank line, rather than two as in Python. + This can be omitted for tightly associated forms. Methods within a defclass need not be separated by blank line. Special Arguments ----------------- Macros and special forms are normally indented one space past the parent bracket, but can also have "special" arguments that are indented like function arguments. + Macros with an ``&rest body`` argument contain an implicit ``do``. + The body is never special, but the arguments before it are. .. code-block:: clj ;; PREFERRED (assoc foo ; foo is special "x" 1 ; remaining args are not special. Indent 2 spaces. "y" 2) ;; PREFERRED ;; The do form has no special args. Indent like a function call. (do (foo) (bar) (baz)) ;; OK ;; No special args to distinguish. This is also valid function indent. (do (foo) (bar) (baz)) ;; PREFERRED (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) ;; OK (defn fib [n] ; name and argslist are special. Indent like function args. ;; The defn body is not special. Indent 1 space past parent bracket. (if (<= n 2) n (+ (fib (- n 1)) ; Emacs-style else indent. (fib (- n 2))))) Removing Whitespace ------------------- Removing whitespace can also make groups clearer. .. code-block:: clj ;; lookups ;; OK (. foo ["bar"]) ;; PREFERRED (. foo["bar"]) ;; BAD. Doesn't show groups clearly. (import foo foo [spam :as sp eggs :as eg] bar bar [bacon]) ;; OK. Extra spaces show groups. (import foo foo [spam :as sp eggs :as eg] bar bar [bacon]) ;; PREFERRED. Removing spaces is even clearer. (import foo foo[spam :as sp eggs :as eg] bar bar[bacon]) ;; OK. Newlines show groups. (import foo foo [spam :as sp eggs :as eg] bar bar [bacon]) ;; PREFERRED, It's more consistent with the preferred one-line version. (import foo foo[spam :as sp eggs :as eg] bar bar[bacon]) ;; Avoid whitespace after tags. ;; Note which shows groups better. ;; BAD (foofunction #tag "foo" #tag (foo) #* (get-args)) ;; OK (foofunction #tag "foo" #tag (foo) #* (get-args)) ;; PREFERRED (foofunction #tag"foo" #tag(foo) #*(get-args)) ;; PREFERRED ;; Can't group these by removing whitespace. Use extra spaces instead. (foofunction #x foo #x bar #* args) ;; OK ;; Same idea, but this could have fit on one line. (foofunction #x foo #x bar #* args) ;; OK, but you don't need to separate function name from first arg. (foofunction #x foo #x bar #* args) ;; OK. But same idea. ;; No need to separate the first group from the function name. (foofunction #x foo #x bar #* args) ;; PREFERRED. It's still clear what this is tagging. ;; And you don't have to re-indent. #_ (def foo [] stuff) ;; OK, but more work. #_(def foo [] stuff) ;; BAD, you messed up the indent and broke law #2. #_(def foo [] stuff) ;; BAD, keep the tag grouped with its argument. #_ (def foo [] stuff) Close Bracket, Close Line ------------------------- A *single* closing bracket SHOULD end the line, unless it's in the middle of an implicit group. + If the forms are small and simple you can maybe leave them on one line. A *train* of closing brackets MUST end the line. .. code-block:: clj ;; One-liners are overrated. ;; Maybe OK if you're just typing into the REPL. ;; But even then, maintaining good style can help prevent errors. ;; BAD. One-liner is too hard to read. (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) ;; BAD. Getting better, but the first line is still too complex. (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) (fib (- n 2))))) ;; OK. Barely. (defn fib [n] (if (<= n 2) n (+ (fib (- n 1)) ; This line is pushing it. (fib (- n 2))))) ;; OK (defn fib [n] ; Saw a "]", newline. (if (<= n 2) ; OK to break here, since there's only one pair. n (+ (fib (- n 1)) ; Whitespace separation (Emacs else-indent). (fib (- n 2))))) ;; OK (defn fib [n] ; Saw a "]", end line. (Margin comments don't count.) (if (<= n 2) n ; Saw a ")", but it's in a pair starting in this line. (+ (fib (- n 1)) ; Saw a "))" MUST end line. (fib (- n 2))))) ;; OK. Pairs. (print (if (< n 0.0) "negative" ; Single ) inside group. No break. (= n 0.0) "zero" (> n 0.0) "positive" :else "not a number")) ; :else is not magic; True works too. ;; OK. Avoided line breaks at single ) to show pairs. (print (if (< n 0.0) "negative" (= n 0.0) "zero" (> n 0.0) (do (do-foo) ; Single ) inside group. No break. (do-bar) "positive") "not a number")) ; Implicit else is PREFERRED. ;; BAD (print (if (< n 0.0) "negative" (= n 0.0) "zero" (and (even? n) (> n 0.0)) "even-positive" ; Bad. "))" must break. (> n 0.0) "positive" "not a number")) ;; BAD (print (if (< n 0.0) "negative" (= n 0.0) "zero" (and (even? n) (> n 0.0)) (do (do-foo) ; Y U no break? (do-bar) "even-positive") (> n 0.0) "positive" "not a number")) ;; OK. Blank line separates multiline groups. (print (if (< n 0.0) "negative" (= n 0.0) "zero" (and (even? n) (> n 0.0)) (do (do-foo) (do-bar) "even-positive") (> n 0.0) "positive" "not a number")) ;; BAD. Groups are not separated consistently. (print (if (< n 0.0) "negative" (= n 0.0) "zero" (> n 0.0) (do (do-foo) "positive") "not a number")) ;; OK. Single )'s and forms are simple enough. (with [f (open "names.txt")] (-> (.read f) .strip (.replace "\"" "") (.split ",") sorted))) ;; PREFERRED. Even so, this version is much clearer. (with [f (open "names.txt")] (-> (.read f) .strip (.replace "\"" "") (.split ",") sorted))) Comments -------- Prefer docstrings to comments where applicable---in ``fn``, ``defclass``, at the top of the module, and in any other macros derived from these that can take a docstring (e.g. ``defmacro/g!``, ``deftag``, ``defn``). Docstrings contents follow the same conventions as Python. The ``(comment)`` macro is still subject to the three laws. If you're tempted to violate them, consider discarding a string instead with ``#_``. Semicolon comments always have one space between the semicolon and the start of the comment. Also, try to not comment the obvious. Comments with more than a single word should start with a capital letter and use punctuation. Separate sentences with a single space. .. code-block:: clj ;; This commentary is not about a particular form. ;; These can span multiple lines. Limit them to column 72, per PEP 8. ;; Separate them from the next form or form comment with a blank line. ;; PREFERRED. (setv ind (dec x)) ; Indexing starts from 0, ; margin comment continues on new line. ;; OK ;; 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 ;; Comment about the whole foofunction call. ;; These can also span mulitple lines. (foofunction ;; Form comment about (get-arg1). Not a margin comment! (get-arg1) ;; Form comment about arg2. The indent matches. arg2) Indent form comments at the same level as the form they're commenting about; they must always start with exactly two semicolons ``;;``. Form comments appear directly above what they're commenting on, never below. General toplevel commentary is not indented; these must always start with exactly two semicolons ``;;`` and be separated from the next form with a blank line. For long commentary, consider using a ``#_`` applied to a string for this purpose instead. Margin comments start two spaces from the end of the code; they must always start with a single semicolon ``;``. Margin comments may be continued on the next line. When commenting out entire forms, prefer the ``#_`` syntax. But if you do need line comments, use the more general double-colon form. Coding Style ============ Pythonic Names -------------- Use Python's naming conventions where still applicable to Hy. + The first parameter of a method is ``self``, + of a classmethod is ``cls``. Threading Macros ---------------- PREFER 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 ;; BAD. Not wrong, but could be much clearer with a threading macro. (setv NAMES (with [f (open "names.txt")] (sorted (.split (.replace (.strip (.read f)) "\"" "") ",")))) ;; PREFERRED. This compiles exactly the same way as the above. (setv NAMES (with [f (open "names.txt")] (-> (.read f) .strip (.replace "\"" "") (.split ",") sorted))) ;; BAD. Probably. The macro makes it less clear in this case. (defn square? [x] (->> 2 (pow (int (sqrt x))) (= x))) ;; OK. Much clearer that the previous example above. (defn square? [x] (-> x sqrt int (pow 2) (= x)) ;; PREFERRED. Judicious use. ;; You don't have to thread everything if it improves clarity. (defn square? [x] (= x (-> x sqrt int (pow 2)))) ;; OK. Still clear enough with no threading macro this time. (defn square? [x] (= x (pow (int (sqrt x)) ; saw a "))", break. 2)) ; aligned with first arg to pow Method Calls ------------ 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 ;; PREFERRED (with [fd (open "/etc/passwd")] (print (.readlines fd))) ;; OK (with [fd (open "/etc/passwd")] (print (fd.readlines))) Use More Arguments ------------------ PREFER using multiple arguments to multiple forms. But judicious use of redundant forms can clarify intent. AVOID the separating blank line for toplevel forms in this case. .. code-block:: clj ;; BAD (setv x 1) (setv y 2) (setv z 3) (setv foo 9) (setv bar 10) ;; OK (setv x 1 y 2 z 3 foo 9 bar 10) ;; PREFERRED (setv x 1 y 2 z 3) (setv foo 9 bar 10) Imports ------- As in Python, group imports. + Standard library imports (including Hy's) first. + Then third-party modules, + and finally internal modules. PREFER one import form for each group. PREFER alphabetical order within groups. Require macros before any imports and group them the same way. But sometimes imports are conditional or must be ordered a certain way for programmatic reasons, which is OK. .. code-block:: clj ;; PREFERRED (require hy.extra.anaphoric [%]) (require thirdparty [some-macro]) (require mymacros [my-macro]) (import json re) (import numpy :as np pandas :as pd) (import mymodule1) Underscores ----------- Prefer hyphens when separating words. + PREFERRED ``foo-bar`` + BAD ``foo_bar`` Don't use leading hyphens, except for "operators" or symbols meant to be read as including one, e.g. ``-Inf``, ``->foo``. Prefix private names with an underscore, not a dash. to avoid confusion with negated literals like ``-Inf``, ``-42`` or ``-4/2``. + PREFERRED ``_x`` + BAD ``-x`` Write Python's magic "dunder" names the same as in Python. Like ``__init__``, not ``--init--`` or otherwise, to be consistent with the private names rule above. Private names should still separate words using dashes instead of underscores, to be consistent with non-private parameter names and such that need the same name sans prefix, like ``foo-bar``, not ``foo_bar``. + PREFERRED ``_foo-bar`` + BAD ``_foo_bar`` .. code-block:: clj ;; BAD ;; What are you doing? (_= spam 2) ; Throwing it away? (_ 100 7) ; i18n? ;; PREFERRED ;; Clearly subtraction. (-= spam 2) (- 100 7) ;; BAD ;; This looks weird. (_>> foo bar baz) ;; PREFERRED ;; OH, it's an arrow! (->> foo bar baz) ;; Negative x? (setv -x 100) ; BAD. Unless you really meant that? ;; PREFERRED ;; Oh, it's just a module private. (setv _x 100) ;; BAD (class Foo [] (defn __init-- [self] ...)) ;; OK (class Foo [] ;; Less weird? (defn --init-- [self] ...)) ;; PREFERRED (class Foo [] (defn __init__ [self] ...)) ;; OK, but would be module private. (No import *) (def ->dict [&rest pairs] (dict (partition pairs))) Thanks ====== + This guide is heavily inspired from `@paultag`_ 's blog post `Hy Survival Guide`_ + The `Clojure Style Guide`_ + `Parinfer`_ and `Parlinter`_ (the three laws) + The Community Scheme Wiki `scheme-style`_ (ending bracket ends the line) + `Riastradh's Lisp Style Rules`_ (Lisp programmers do not ... Azathoth forbid, count brackets) .. _`Hy Survival Guide`: https://notes.pault.ag/hy-survival-guide/ .. _`Clojure Style Guide`: https://github.com/bbatsov/clojure-style-guide .. _`@paultag`: https://github.com/paultag .. _`Parinfer`: https://shaunlebron.github.io/parinfer/ .. _`Parlinter`: https://github.com/shaunlebron/parlinter .. _`scheme-style`: http://community.schemewiki.org/?scheme-style .. _`Comment-Tips`: https://www.gnu.org/software/emacs/manual/html_node/elisp/Comment-Tips.html .. _`Riastradh's Lisp Style Rules`: http://mumble.net/~campbell/scheme/style.txt hy-0.18.0/docs/tutorial.rst000066400000000000000000000273531361554632000155640ustar00rootroot00000000000000======== Tutorial ======== .. image:: _static/cuddles-transparent-small.png :alt: Karen Rustard's Cuddles This chapter provides a quick introduction to Hy. It assumes a basic background in programming, but no specific prior knowledge of Python or Lisp. Lisp-stick on a Python ====================== Let's start with the classic:: (print "Hy, world!") This program calls the :func:`print` function, which, like all of Python's :ref:`built-in functions `, is available in Hy. All of Python's :ref:`binary and unary operators ` are available, too, although ``==`` is spelled ``=`` in deference to Lisp tradition. Here's how we'd use the addition operator ``+``:: (+ 1 3) This code returns ``4``. It's equivalent to ``1 + 3`` in Python and many other languages. Languages in the `Lisp `_ family, including Hy, use a prefix syntax: ``+``, just like ``print`` or ``sqrt``, appears before all of its arguments. The call is delimited by parentheses, but the opening parenthesis appears before the operator being called instead of after it, so instead of ``sqrt(2)``, we write ``(sqrt 2)``. Multiple arguments, such as the two integers in ``(+ 1 3)``, are separated by whitespace. Many operators, including ``+``, allow more than two arguments: ``(+ 1 2 3)`` is equivalent to ``1 + 2 + 3``. Here's a more complex example:: (- (* (+ 1 3 88) 2) 8) This code returns ``176``. Why? We can see the infix equivalent with the command ``echo "(- (* (+ 1 3 88) 2) 8)" | hy2py``, which returns the Python code corresponding to the given Hy code, or by passing the ``--spy`` option to Hy when starting the REPL, which shows the Python equivalent of each input line before the result. The infix equivalent in this case is: .. code-block:: python ((1 + 3 + 88) * 2) - 8 To evaluate this infix expression, you'd of course evaluate the innermost parenthesized expression first and work your way outwards. The same goes for Lisp. Here's what we'd get by evaluating the above Hy code one step at a time:: (- (* (+ 1 3 88) 2) 8) (- (* 92 2) 8) (- 184 8) 176 The basic unit of Lisp syntax, which is similar to a C or Python expression, is the **form**. ``92``, ``*``, and ``(* 92 2)`` are all forms. A Lisp program consists of a sequence of forms nested within forms. Forms are typically separated from each other by whitespace, but some forms, such as string literals (``"Hy, world!"``), can contain whitespace themselves. An **expression** is a form enclosed in parentheses; its first child form, called the **head**, determines what the expression does, and should generally be a function, macro, or special operator. Functions are the most ordinary sort of head, whereas macros (described in more detail below) are functions executed at compile-time instead and return code to be executed at run-time. Special operators are one of :ref:`a fixed set of names ` that are hard-coded into the compiler, and used to implement everything else. Comments start with a ``;`` character and continue till the end of the line. A comment is functionally equivalent to whitespace. :: (print (** 2 64)) ; Max 64-bit unsigned integer value Although ``#`` isn't a comment character in Hy, a Hy program can begin with a `shebang line `_, which Hy itself will ignore:: #!/usr/bin/env hy (print "Make me executable, and run me!") Literals ======== Hy has :ref:`literal syntax ` for all of the same data types that Python does. Here's an example of Hy code for each type and the Python equivalent. ============== ================ ================= Hy Python Type ============== ================ ================= ``1`` ``1`` :class:`int` ``1.2`` ``1.2`` :class:`float` ``4j`` ``4j`` :class:`complex` ``True`` ``True`` :class:`bool` ``None`` ``None`` :class:`NoneType` ``"hy"`` ``'hy'`` :class:`str` ``b"hy"`` ``b'hy'`` :class:`bytes` ``(, 1 2 3)`` ``(1, 2, 3)`` :class:`tuple` ``[1 2 3]`` ``[1, 2, 3]`` :class:`list` ``#{1 2 3}`` ``{1, 2, 3}`` :class:`set` ``{1 2 3 4}`` ``{1: 2, 3: 4}`` :class:`dict` ============== ================ ================= In addition, Hy has a Clojure-style literal syntax for :class:`fractions.Fraction`: ``1/3`` is equivalent to ``fractions.Fraction(1, 3)``. The Hy REPL prints output in Python syntax by default:: => [1 2 3] [1, 2, 3] But if you start Hy like this (a shell alias might be helpful):: $ hy --repl-output-fn=hy.contrib.hy-repr.hy-repr the interactive mode will use :ref:`hy-repr-fn` instead of Python's native ``repr`` function to print out values, so you'll see values in Hy syntax:: => [1 2 3] [1 2 3] Basic operations ================ Set variables with :ref:`setv`:: (setv zone-plane 8) Access the elements of a list, dictionary, or other data structure with :ref:`get`:: (setv fruit ["apple" "banana" "cantaloupe"]) (print (get fruit 0)) ; => apple (setv (get fruit 1) "durian") (print (get fruit 1)) ; => durian Access a range of elements in an ordered structure with :ref:`cut`:: (print (cut "abcdef" 1 4)) ; => bcd Conditional logic can be built with :ref:`if`:: (if (= 1 1) (print "Math works. The universe is safe.") (print "Math has failed. The universe is doomed.")) As in this example, ``if`` is called like ``(if CONDITION THEN ELSE)``. It executes and returns the form ``THEN`` if ``CONDITION`` is true (according to :class:`bool`) and ``ELSE`` otherwise. If ``ELSE`` is omitted, ``None`` is used in its place. What if you want to use more than form in place of the ``THEN`` or ``ELSE`` clauses, or in place of ``CONDITION``, for that matter? Use the special operator :ref:`do` (known more traditionally in Lisp as ``progn``), which combines several forms into one, returning the last:: (if (do (print "Let's check.") (= 1 1)) (do (print "Math works.") (print "The universe is safe.")) (do (print "Math has failed.") (print "The universe is doomed."))) For branching on more than one case, try :ref:`cond`:: (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!")]) The macro ``(when CONDITION THEN-1 THEN-2 …)`` is shorthand for ``(if CONDITION (do THEN-1 THEN-2 …))``. ``unless`` works the same as ``when``, but inverts the condition with ``not``. Hy's basic loops are :ref:`while` and :ref:`for`:: (setv x 3) (while (> x 0) (print x) (setv x (- x 1))) ; => 3 2 1 (for [x [1 2 3]] (print x)) ; => 1 2 3 A more functional way to iterate is provided by the comprehension forms such as :ref:`lfor`. Whereas ``for`` always returns ``None``, ``lfor`` returns a list with one element per iteration. :: (print (lfor x [1 2 3] (* x 2))) ; => [2, 4, 6] Functions, classes, and modules =============================== Define named functions with :ref:`defn`:: (defn fib [n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (print (fib 8)) ; => 21 Define anonymous functions with :ref:`fn`:: (print (list (filter (fn [x] (% x 2)) (range 10)))) ; => [1, 3, 5, 7, 9] Special symbols in the parameter list of ``defn`` or ``fn`` allow you to indicate optional arguments, provide default values, and collect unlisted arguments:: (defn test [a b &optional c [d "x"] &rest e] [a b c d e]) (print (test 1 2)) ; => [1, 2, None, 'x', ()] (print (test 1 2 3 4 5 6 7)) ; => [1, 2, 3, 4, (5, 6, 7)] Set a function parameter by name with a ``:keyword``:: (test 1 2 :d "y") ; => [1, 2, None, 'y', ()] Define classes with :ref:`defclass`:: (defclass FooBar [] (defn __init__ [self x] (setv self.x x)) (defn get-x [self] self.x)) Here we create a new instance ``fb`` of ``FooBar`` and access its attributes by various means:: (setv fb (FooBar 15)) (print fb.x) ; => 15 (print (. fb x)) ; => 15 (print (.get-x fb)) ; => 15 (print (fb.get-x)) ; => 15 Note that syntax like ``fb.x`` and ``fb.get-x`` only works when the object being invoked (``fb``, in this case) is a simple variable name. To get an attribute or call a method of an arbitrary form ``FORM``, you must use the syntax ``(. FORM x)`` or ``(.get-x FORM)``. Access an external module, whether written in Python or Hy, with :ref:`import`:: (import math) (print (math.sqrt 2)) ; => 1.4142135623730951 Python can import a Hy module like any other module so long as Hy itself has been imported first, which, of course, must have already happened if you're running a Hy program. Macros ====== Macros are the basic metaprogramming tool of Lisp. A macro is a function that is called at compile time (i.e., when a Hy program is being translated to Python :mod:`ast` objects) and returns code, which becomes part of the final program. Here's a simple example:: (print "Executing") (defmacro m [] (print "Now for a slow computation") (setv x (% (** 10 10 7) 3)) (print "Done computing") x) (print "Value:" (m)) (print "Done executing") If you run this program twice in a row, you'll see this:: $ hy example.hy Now for a slow computation Done computing Executing Value: 1 Done executing $ hy example.hy Executing Value: 1 Done executing The slow computation is performed while compiling the program on its first invocation. Only after the whole program is compiled does normal execution begin from the top, printing "Executing". When the program is called a second time, it is run from the previously compiled bytecode, which is equivalent to simply:: (print "Executing") (print "Value:" 1) (print "Done executing") Our macro ``m`` has an especially simple return value, an integer, which at compile-time is converted to an integer literal. In general, macros can return arbitrary Hy forms to be executed as code. There are several special operators and macros that make it easy to construct forms programmatically, such as :ref:`quote` (``'``), :ref:`quasiquote` (`````), :ref:`unquote` (``~``), and :ref:`defmacro!`. The previous chapter has :ref:`a simple example ` of using ````` and ``~`` to define a new control construct ``do-while``. Sometimes it's nice to be able to call a one-parameter macro without parentheses. Tag macros allow this. The name of a tag macro is often just one character long, but since Hy allows most Unicode characters in the name of a macro (or ordinary variable), you won't out of characters soon. :: => (deftag ↻ [code] ... (setv op (last code) params (list (butlast code))) ... `(~op ~@params)) => #↻(1 2 3 +) 6 What if you want to use a macro that's defined in a different module? ``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 translation from Hy to Python. Instead, use :ref:`require`, which imports the module and makes macros available at compile-time. ``require`` uses the same syntax as ``import``. :: => (require tutorial.macros) => (tutorial.macros.rev (1 2 3 +)) 6 Next steps ========== You now know enough to be dangerous with Hy. You may now smile villainously and sneak off to your Hydeaway to do unspeakable things. Refer to Python's documention for the details of Python semantics, and the rest of this manual for Hy-specific features. Like Hy itself, the manual is incomplete, but :ref:`contributions ` are always welcome. hy-0.18.0/docs/whyhy.rst000066400000000000000000000142011361554632000150550ustar00rootroot00000000000000======= Why Hy? ======= Hy is a multi-paradigm general-purpose programming language in the `Lisp family `_. It's implemented as a kind of alternative syntax for Python. Compared to Python, Hy offers a variety of extra features, generalizations, and syntactic simplifications, as would be expected of a Lisp. Compared to other Lisps, Hy provides direct access to Python's built-ins and third-party Python libraries, while allowing you to freely mix imperative, functional, and object-oriented styles of programming. Hy versus Python ---------------- The first thing a Python programmer will notice about Hy is that it has Lisp's traditional parenthesis-heavy prefix syntax in place of Python's C-like infix syntax. For example, ``print("The answer is", 2 + object.method(arg))`` could be written ``(print "The answer is" (+ 2 (.method object arg)))`` in Hy. Consequently, Hy is free-form: structure is indicated by parentheses rather than whitespace, making it convenient for command-line use. As in other Lisps, the value of a simplistic syntax is that it facilitates Lisp's signature feature: `metaprogramming `_ through macros, which are functions that manipulate code objects at compile time to produce new code objects, which are then executed as if they had been part of the original code. In fact, Hy allows arbitrary computation at compile-time. For example, here's a simple macro that implements a C-style do-while loop, which executes its body for as long as the condition is true, but at least once. .. _do-while: :: (defmacro do-while [condition &rest body] `(do ~body (while ~condition ~body))) (setv x 0) (do-while x (print "This line is executed once.")) Hy also removes Python's restrictions on mixing expressions and statements, allowing for more direct and functional code. For example, Python doesn't allow :ref:`with ` blocks, which close a resource once you're done using it, to return values. They can only execute a set of statements: .. code-block:: python with open("foo") as o: f1 = o.read() with open("bar") as o: f2 = o.read() print(len(f1) + len(f2)) In Hy, :ref:`with` returns the value of its last body form, so you can use it like an ordinary function call:: (print (+ (len (with [o (open "foo")] (.read o)) (len (with [o (open "bar")] (.read o)))))) To be even more concise, you can put a ``with`` form in a :ref:`generator expression `:: (print (sum (gfor filename ["foo" "bar"] (len (with [o (open filename)] (.read o)))))) Finally, Hy offers several generalizations to Python's binary operators. Operators can be given more than two arguments (e.g., ``(+ 1 2 3)``), including augmented assignment operators (e.g., ``(+= x 1 2 3)``). They are also provided as ordinary first-class functions of the same name, allowing them to be passed to higher-order functions: ``(sum xs)`` could be written ``(reduce + xs)``. The Hy compiler works by reading Hy source code into Hy model objects and compiling the Hy model objects into Python abstract syntax tree (:py:mod:`ast`) objects. Python AST objects can then be compiled and run by Python itself, byte-compiled for faster execution later, or rendered into Python source code. You can even :ref:`mix Python and Hy code in the same project, or even the same file,` which can be a good way to get your feet wet in Hy. Hy versus other Lisps --------------------- At run-time, Hy is essentially Python code. Thus, while Hy's design owes a lot to `Clojure `_, it is more tightly coupled to Python than Clojure is to Java; a better analogy is `CoffeeScript's `_ relationship to JavaScript. Python's built-in :ref:`functions ` and :ref:`data structures ` are directly available:: (print (int "deadbeef" :base 16)) ; 3735928559 (print (len [1 10 100])) ; 3 The same goes for third-party Python libraries from `PyPI `_ and elsewhere. Here's a tiny `CherryPy `_ web application in Hy:: (import cherrypy) (defclass HelloWorld [] (#@ cherrypy.expose (defn index [self] "Hello World!"))) (cherrypy.quickstart (HelloWorld)) You can even run Hy on `PyPy `_ for a particularly speedy Lisp. Like all Lisps, Hy is `homoiconic `_. Its syntax is represented not with cons cells or with Python's basic data structures, but with simple subclasses of Python's basic data structures called :ref:`models `. Using models in place of plain ``list``\s, ``set``\s, and so on has two purposes: models can keep track of their line and column numbers for the benefit of error messages, and models can represent syntactic features that the corresponding primitive type can't, such as the order in which elements appear in a set literal. However, models can be concatenated and indexed just like plain lists, and you can return ordinary Python types from a macro or give them to ``eval`` and Hy will automatically promote them to models. Hy takes much of its semantics from Python. For example, Hy is a Lisp-1 because Python functions use the same namespace as objects that aren't functions. In general, any Python code should be possible to literally translate to Hy. At the same time, Hy goes to some lengths to allow you to do typical Lisp things that aren't straightforward in Python. For example, Hy provides the aforementioned mixing of statements and expressions, :ref:`name mangling ` that transparently converts symbols with names like ``valid?`` to Python-legal identifiers, and a :ref:`let` macro to provide block-level scoping in place of Python's usual function-level scoping. Overall, Hy, like Common Lisp, is intended to be an unopinionated big-tent language that lets you do what you want. If you're interested in a more small-and-beautiful approach to Lisp, in the style of Scheme, check out `Hissp `_, another Lisp embedded in Python that was created by a Hy developer. hy-0.18.0/fastentrypoints.py000066400000000000000000000077121361554632000160620ustar00rootroot00000000000000# noqa: D300,D400 # Copyright (c) 2016, Aaron Christianson # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ''' Monkey patch setuptools to write faster console_scripts with this format: import sys from mymodule import entry_function sys.exit(entry_function()) This is better. (c) 2016, Aaron Christianson http://github.com/ninjaaron/fast-entry_points ''' from setuptools.command import easy_install import re TEMPLATE = '''\ # -*- coding: utf-8 -*- # EASY-INSTALL-ENTRY-SCRIPT: '{3}','{4}','{5}' __requires__ = '{3}' import re import sys from {0} import {1} if __name__ == '__main__': sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) sys.exit({2}())''' @classmethod def get_args(cls, dist, header=None): # noqa: D205,D400 """ Yield write_script() argument tuples for a distribution's console_scripts and gui_scripts entry points. """ if header is None: # pylint: disable=E1101 header = cls.get_header() spec = str(dist.as_requirement()) for type_ in 'console', 'gui': group = type_ + '_scripts' for name, ep in dist.get_entry_map(group).items(): # ensure_safe_name if re.search(r'[\\/]', name): raise ValueError("Path separators not allowed in script names") script_text = TEMPLATE.format( ep.module_name, ep.attrs[0], '.'.join(ep.attrs), spec, group, name) # pylint: disable=E1101 args = cls._get_script_args(type_, name, header, script_text) for res in args: yield res # pylint: disable=E1101 easy_install.ScriptWriter.get_args = get_args def main(): import os import re import shutil import sys dests = sys.argv[1:] or ['.'] filename = re.sub('\.pyc$', '.py', __file__) for dst in dests: shutil.copy(filename, dst) manifest_path = os.path.join(dst, 'MANIFEST.in') setup_path = os.path.join(dst, 'setup.py') # Insert the include statement to MANIFEST.in if not present with open(manifest_path, 'a+') as manifest: manifest.seek(0) manifest_content = manifest.read() if 'include fastentrypoints.py' not in manifest_content: manifest.write(('\n' if manifest_content else '') + 'include fastentrypoints.py') # Insert the import statement to setup.py if not present with open(setup_path, 'a+') as setup: setup.seek(0) setup_content = setup.read() if 'import fastentrypoints' not in setup_content: setup.seek(0) setup.truncate() setup.write('import fastentrypoints\n' + setup_content) hy-0.18.0/get_version.py000066400000000000000000000014441361554632000151260ustar00rootroot00000000000000import os, subprocess, runpy # Try to get and update the version. os.chdir(os.path.split(os.path.abspath(__file__))[0]) VERSIONFILE = os.path.join("hy", "version.py") if "HY_VERSION" in os.environ: __version__ = os.environ["HY_VERSION"] else: 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" hy-0.18.0/hy/000077500000000000000000000000001361554632000126455ustar00rootroot00000000000000hy-0.18.0/hy/__init__.py000066400000000000000000000012451361554632000147600ustar00rootroot00000000000000__appname__ = 'hy' try: from hy.version import __version__ except ImportError: __version__ = 'unknown' def _initialize_env_var(env_var, default_val): import os, distutils.util try: res = bool(distutils.util.strtobool( os.environ.get(env_var, str(default_val)))) except ValueError as e: res = default_val return res from hy.models import HyExpression, HyInteger, HyKeyword, HyComplex, HyString, HyBytes, HySymbol, HyFloat, HyDict, HyList, HySet # NOQA import hy.importer # NOQA # we import for side-effects. from hy.lex import read, read_str, mangle, unmangle # NOQA from hy.compiler import hy_eval as eval # NOQA hy-0.18.0/hy/__main__.py000066400000000000000000000005551361554632000147440ustar00rootroot00000000000000import 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) hy.importer._import_from_path('__main__', sys.argv[0]) sys.exit(0) # right? hy-0.18.0/hy/_compat.py000066400000000000000000000006051361554632000146420ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import sys PY36 = sys.version_info >= (3, 6) PY37 = sys.version_info >= (3, 7) PY38 = sys.version_info >= (3, 8) def reraise(exc_type, value, traceback=None): try: raise value.with_traceback(traceback) finally: traceback = None hy-0.18.0/hy/cmdline.py000066400000000000000000000604641361554632000146440ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. from __future__ import print_function import colorama colorama.init() import argparse import code import ast import sys import os import io import importlib import py_compile import traceback import runpy import types import time import linecache import hashlib import codeop import builtins import astor.code_gen import hy from hy.lex import hy_parse, mangle from contextlib import contextmanager from hy.lex.exceptions import PrematureEndOfInput from hy.compiler import (HyASTCompiler, hy_eval, hy_compile, hy_ast_compile_flags) from hy.errors import (HyLanguageError, HyRequireError, HyMacroExpansionError, filtered_hy_exceptions, hy_exc_handler) from hy.importer import runhy from hy.completer import completion, Completer from hy.macros import macro, require from hy.models import HyExpression, HyString, HySymbol sys.last_type = None sys.last_value = None sys.last_traceback = None 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) class HyHelper(object): def __repr__(self): return ("Use (help) for interactive help, or (help object) for help " "about object.") def __call__(self, *args, **kwds): import pydoc return pydoc.help(*args, **kwds) builtins.quit = HyQuitter('quit') builtins.exit = HyQuitter('exit') builtins.help = HyHelper() @contextmanager def extend_linecache(add_cmdline_cache): _linecache_checkcache = linecache.checkcache def _cmdline_checkcache(*args): _linecache_checkcache(*args) linecache.cache.update(add_cmdline_cache) linecache.checkcache = _cmdline_checkcache yield linecache.checkcache = _linecache_checkcache _codeop_maybe_compile = codeop._maybe_compile def _hy_maybe_compile(compiler, source, filename, symbol): """The `codeop` version of this will compile the same source multiple times, and, since we have macros and things like `eval-and-compile`, we can't allow that. """ if not isinstance(compiler, HyCompile): return _codeop_maybe_compile(compiler, source, filename, symbol) for line in source.split("\n"): line = line.strip() if line and line[0] != ';': # Leave it alone (could do more with Hy syntax) break else: if symbol != "eval": # Replace it with a 'pass' statement (i.e. tell the compiler to do # nothing) source = "pass" return compiler(source, filename, symbol) codeop._maybe_compile = _hy_maybe_compile class HyCompile(codeop.Compile, object): """This compiler uses `linecache` like `IPython.core.compilerop.CachingCompiler`. """ def __init__(self, module, locals, ast_callback=None, hy_compiler=None, cmdline_cache={}): self.module = module self.locals = locals self.ast_callback = ast_callback self.hy_compiler = hy_compiler super(HyCompile, self).__init__() self.flags |= hy_ast_compile_flags self.cmdline_cache = cmdline_cache def _cache(self, source, name): entry = (len(source), time.time(), [line + '\n' for line in source.splitlines()], name) linecache.cache[name] = entry self.cmdline_cache[name] = entry def _update_exc_info(self): self.locals['_hy_last_type'] = sys.last_type self.locals['_hy_last_value'] = sys.last_value # Skip our frame. sys.last_traceback = getattr(sys.last_traceback, 'tb_next', sys.last_traceback) self.locals['_hy_last_traceback'] = sys.last_traceback def __call__(self, source, filename="", symbol="single"): if source == 'pass': # We need to return a no-op to signal that no more input is needed. return (compile(source, filename, symbol),) * 2 hash_digest = hashlib.sha1(source.encode("utf-8").strip()).hexdigest() name = '{}-{}'.format(filename.strip('<>'), hash_digest) try: hy_ast = hy_parse(source, filename=name) except Exception: # Capture a traceback without the compiler/REPL frames. sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() self._update_exc_info() raise self._cache(source, name) try: hy_ast = hy_parse(source, filename=filename) root_ast = ast.Interactive if symbol == 'single' else ast.Module # Our compiler doesn't correspond to a real, fixed source file, so # we need to [re]set these. self.hy_compiler.filename = filename self.hy_compiler.source = source exec_ast, eval_ast = hy_compile(hy_ast, self.module, root=root_ast, get_expr=True, compiler=self.hy_compiler, filename=filename, source=source) if self.ast_callback: self.ast_callback(exec_ast, eval_ast) exec_code = super(HyCompile, self).__call__(exec_ast, name, symbol) eval_code = super(HyCompile, self).__call__(eval_ast, name, 'eval') except HyLanguageError: # Hy will raise exceptions during compile-time that Python would # raise during run-time (e.g. import errors for `require`). In # order to work gracefully with the Python world, we convert such # Hy errors to code that purposefully reraises those exceptions in # the places where Python code expects them. sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() self._update_exc_info() exec_code = super(HyCompile, self).__call__( 'import hy._compat; hy._compat.reraise(' '_hy_last_type, _hy_last_value, _hy_last_traceback)', name, symbol) eval_code = super(HyCompile, self).__call__('None', name, 'eval') return exec_code, eval_code class HyCommandCompiler(codeop.CommandCompiler, object): def __init__(self, *args, **kwargs): self.compiler = HyCompile(*args, **kwargs) def __call__(self, *args, **kwargs): try: return super(HyCommandCompiler, self).__call__(*args, **kwargs) except PrematureEndOfInput: # We have to do this here, because `codeop._maybe_compile` won't # take `None` for a return value (at least not in Python 2.7) and # this exception type is also a `SyntaxError`, so it will be caught # by `code.InteractiveConsole` base methods before it reaches our # `runsource`. return None class HyREPL(code.InteractiveConsole, object): def __init__(self, spy=False, output_fn=None, locals=None, filename=""): # Create a proper module for this REPL so that we can obtain it easily # (e.g. using `importlib.import_module`). # We let `InteractiveConsole` initialize `self.locals` when it's # `None`. super(HyREPL, self).__init__(locals=locals, filename=filename) module_name = self.locals.get('__name__', '__console__') # Make sure our newly created module is properly introduced to # `sys.modules`, and consistently use its namespace as `self.locals` # from here on. self.module = sys.modules.setdefault(module_name, types.ModuleType(module_name)) self.module.__dict__.update(self.locals) self.locals = self.module.__dict__ # Load cmdline-specific macros. require('hy.cmdline', self.module, assignments='ALL') self.hy_compiler = HyASTCompiler(self.module) self.cmdline_cache = {} self.compile = HyCommandCompiler(self.module, self.locals, ast_callback=self.ast_callback, hy_compiler=self.hy_compiler, cmdline_cache=self.cmdline_cache) self.spy = spy self.last_value = None self.print_last_value = True if output_fn is None: self.output_fn = repr elif callable(output_fn): self.output_fn = output_fn else: if "." in output_fn: parts = [mangle(x) for x in output_fn.split(".")] module, f = '.'.join(parts[:-1]), parts[-1] self.output_fn = getattr(importlib.import_module(module), f) else: self.output_fn = getattr(builtins, mangle(output_fn)) # Pre-mangle symbols for repl recent results: *1, *2, *3 self._repl_results_symbols = [mangle("*{}".format(i + 1)) for i in range(3)] self.locals.update({sym: None for sym in self._repl_results_symbols}) # Allow access to the running REPL instance self.locals['_hy_repl'] = self def ast_callback(self, exec_ast, eval_ast): if self.spy: try: # Mush the two AST chunks into a single module for # conversion into Python. new_ast = ast.Module( exec_ast.body + [ast.Expr(eval_ast.body)], type_ignores=[]) print(astor.to_source(new_ast)) except Exception: msg = 'Exception in AST callback:\n{}\n'.format( traceback.format_exc()) self.write(msg) def _error_wrap(self, error_fn, exc_info_override=False, *args, **kwargs): sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() if exc_info_override: # Use a traceback that doesn't have the REPL frames. sys.last_type = self.locals.get('_hy_last_type', sys.last_type) sys.last_value = self.locals.get('_hy_last_value', sys.last_value) sys.last_traceback = self.locals.get('_hy_last_traceback', sys.last_traceback) # Sadly, this method in Python 2.7 ignores an overridden `sys.excepthook`. if sys.excepthook is sys.__excepthook__: error_fn(*args, **kwargs) else: sys.excepthook(sys.last_type, sys.last_value, sys.last_traceback) self.locals[mangle("*e")] = sys.last_value def showsyntaxerror(self, filename=None): if filename is None: filename = self.filename self._error_wrap(super(HyREPL, self).showsyntaxerror, exc_info_override=True, filename=filename) def showtraceback(self): self._error_wrap(super(HyREPL, self).showtraceback) def runcode(self, code): try: eval(code[0], self.locals) self.last_value = eval(code[1], self.locals) # Don't print `None` values. self.print_last_value = self.last_value is not None except SystemExit: raise except Exception as e: # Set this to avoid a print-out of the last value on errors. self.print_last_value = False self.showtraceback() def runsource(self, source, filename='', symbol='exec'): try: res = super(HyREPL, self).runsource(source, filename, symbol) except (HyMacroExpansionError, HyRequireError): # We need to handle these exceptions ourselves, because the base # method only handles `OverflowError`, `SyntaxError` and # `ValueError`. self.showsyntaxerror(filename) return False except (HyLanguageError): # Our compiler will also raise `TypeError`s self.showtraceback() return False # Shift exisitng REPL results if not res: next_result = self.last_value for sym in self._repl_results_symbols: self.locals[sym], next_result = next_result, self.locals[sym] # Print the value. if self.print_last_value: try: output = self.output_fn(self.last_value) except Exception: self.showtraceback() return False print(output) return res @macro("koan") def koan_macro(ETname): 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(ETname): 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 (fn [x] (= (% x 2) 0)) (range 0 10)) ;;; swaggin' functional bits (Python rulez) (max (map (fn [x] (len x)) ["hi" "my" "name" "is" "paul"])) """)]) def run_command(source, filename=None): __main__ = importlib.import_module('__main__') require("hy.cmdline", __main__, assignments="ALL") try: tree = hy_parse(source, filename=filename) except HyLanguageError: hy_exc_handler(*sys.exc_info()) return 1 with filtered_hy_exceptions(): hy_eval(tree, None, __main__, filename=filename, source=source) return 0 def run_repl(hr=None, **kwargs): import platform sys.ps1 = "=> " sys.ps2 = "... " if not hr: hr = HyREPL(**kwargs) namespace = hr.locals with filtered_hy_exceptions(), \ extend_linecache(hr.cmdline_cache), \ completion(Completer(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, **kwargs): if os.path.exists(source): # Emulate Python cmdline behavior by setting `sys.path` relative # to the executed file's location. if sys.path[0] == '': sys.path[0] = os.path.realpath(os.path.split(source)[0]) else: sys.path.insert(0, os.path.split(source)[0]) with io.open(source, "r", encoding='utf-8') as f: source = f.read() filename = source else: filename = '' hr = HyREPL(**kwargs) with filtered_hy_exceptions(): res = hr.runsource(source, filename=filename) # If the command was prematurely ended, show an error (just like Python # does). if res: hy_exc_handler(sys.last_type, sys.last_value, sys.last_traceback) 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("-E", action='store_true', help="ignore PYTHON* environment variables") parser.add_argument("-B", action='store_true', help="don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x") 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("--repl-output-fn", help="function for printing REPL output " "(e.g., hy.contrib.hy-repr.hy-repr)") parser.add_argument("-v", "--version", action="version", version=VERSION) # this will contain the script/program name and any arguments for it. parser.add_argument('args', nargs=argparse.REMAINDER, help=argparse.SUPPRESS) # Get the path of the Hy cmdline executable and swap it with # `sys.executable` (saving the original, just in case). # XXX: The `__main__` module will also have `__file__` set to the # entry-point script. Currently, I don't see an immediate problem, but # that's not how the Python cmdline works. hy.executable = argv[0] hy.sys_executable = sys.executable sys.executable = hy.executable # 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.E: # User did "hy -E ..." _remove_python_envs() if options.B: sys.dont_write_bytecode = True if options.command: # User did "hy -c ..." return run_command(options.command, filename='') if options.mod: # User did "hy -m ..." sys.argv = [sys.argv[0]] + options.args + module_args runpy.run_module(options.mod, run_name='__main__', alter_sys=True) return 0 if options.icommand: # User did "hy -i ..." return run_icommand(options.icommand, spy=options.spy, output_fn=options.repl_output_fn) if options.args: if options.args[0] == "-": # Read the program from stdin return run_command(sys.stdin.read(), filename='') else: # User did "hy " filename = options.args[0] # Emulate Python cmdline behavior by setting `sys.path` relative # to the executed file's location. if sys.path[0] == '': sys.path[0] = os.path.realpath(os.path.split(filename)[0]) else: sys.path.insert(0, os.path.split(filename)[0]) try: sys.argv = options.args with filtered_hy_exceptions(): runhy.run_path(filename, run_name='__main__') return 0 except FileNotFoundError as e: print("hy: Can't open file '{0}': [Errno {1}] {2}".format( e.filename, e.errno, e.strerror), file=sys.stderr) sys.exit(e.errno) except HyLanguageError: hy_exc_handler(*sys.exc_info()) sys.exit(1) # User did NOTHING! return run_repl(spy=options.spy, output_fn=options.repl_output_fn) # entry point for cmd line script "hy" def hy_main(): sys.path.insert(0, "") sys.exit(cmdline_handler("hy", sys.argv)) def hyc_main(): parser = argparse.ArgumentParser(prog="hyc") parser.add_argument("files", metavar="FILE", nargs='*', help=('File(s) to compile (use STDIN if only' ' "-" or nothing is provided)')) parser.add_argument("-v", action="version", version=VERSION) options = parser.parse_args(sys.argv[1:]) rv = 0 if len(options.files) == 0 or ( len(options.files) == 1 and options.files[0] == '-'): while True: filename = sys.stdin.readline() if not filename: break filename = filename.rstrip('\n') try: py_compile.compile(filename, doraise=True) except py_compile.PyCompileError as error: rv = 1 sys.stderr.write("%s\n" % error.msg) except OSError as error: rv = 1 sys.stderr.write("%s\n" % error) else: for filename in options.files: try: print("Compiling %s" % filename) py_compile.compile(filename, doraise=True) except py_compile.PyCompileError as error: # return value to indicate at least one failure rv = 1 sys.stderr.write("%s\n" % error.msg) return rv # entry point for cmd line script "hy2py" def hy2py_main(): import platform 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:]) if options.FILE is None or options.FILE == '-': filename = '' source = sys.stdin.read() else: filename = options.FILE with io.open(options.FILE, 'r', encoding='utf-8') as source_file: source = source_file.read() with filtered_hy_exceptions(): hst = hy_parse(source, filename=filename) if options.with_source: # need special printing on Windows in case the # codepage doesn't support utf-8 characters if platform.system() == "Windows": for h in hst: try: print(h) except: print(str(h).encode('utf-8')) else: print(hst) print() print() with filtered_hy_exceptions(): _ast = hy_compile(hst, '__main__', filename=filename, source=source) if options.with_ast: if platform.system() == "Windows": _print_for_windows(astor.dump_tree(_ast)) else: print(astor.dump_tree(_ast)) print() print() if not options.without_python: if platform.system() == "Windows": _print_for_windows(astor.code_gen.to_source(_ast)) else: print(astor.code_gen.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')) # remove PYTHON* environment variables, # such as "PYTHONPATH" def _remove_python_envs(): for key in list(os.environ.keys()): if key.startswith("PYTHON"): os.environ.pop(key) hy-0.18.0/hy/compiler.py000077500000000000000000002434421361554632000150450ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. from hy.models import (HyObject, HyExpression, HyKeyword, HyInteger, HyComplex, HyString, HyBytes, HySymbol, HyFloat, HyList, HySet, HyDict, HySequence, wrap_value) from hy.model_patterns import (FORM, SYM, KEYWORD, STR, sym, brackets, whole, notpexpr, dolike, pexpr, times, Tag, tag, unpack) from funcparserlib.parser import some, many, oneplus, maybe, NoParseError from hy.errors import (HyCompileError, HyTypeError, HyLanguageError, HySyntaxError, HyEvalError, HyInternalError) from hy.lex import mangle, unmangle, hy_parse, parse_one_thing, LexException from hy._compat import (PY36, PY38, reraise) from hy.macros import require, load_macros, macroexpand, tag_macroexpand import hy.core import re import textwrap import pkgutil import traceback import itertools import importlib import inspect import types import ast import sys import copy import builtins import __future__ from collections import defaultdict from functools import reduce Inf = float('inf') hy_ast_compile_flags = (__future__.CO_FUTURE_DIVISION | __future__.CO_FUTURE_PRINT_FUNCTION) def ast_compile(ast, filename, mode): """Compile AST. Parameters ---------- ast : instance of `ast.AST` filename : str Filename used for run-time error messages mode: str `compile` mode parameter Returns ------- out : instance of `types.CodeType` """ return compile(ast, filename, mode, hy_ast_compile_flags) def calling_module(n=1): """Get the module calling, if available. As a fallback, this will import a module using the calling frame's globals value of `__name__`. Parameters ---------- n: int, optional The number of levels up the stack from this function call. The default is one level up. Returns ------- out: types.ModuleType The module at stack level `n + 1` or `None`. """ frame_up = inspect.stack(0)[n + 1][0] module = inspect.getmodule(frame_up) if module is None: # This works for modules like `__main__` module_name = frame_up.f_globals.get('__name__', None) if module_name: try: module = importlib.import_module(module_name) except ImportError: pass return module def ast_str(x, piecewise=False): if piecewise: return ".".join(ast_str(s) if s else "" for s in x.split(".")) return mangle(x) _special_form_compilers = {} _model_compilers = {} _decoratables = (ast.FunctionDef, ast.ClassDef, ast.AsyncFunctionDef) # _bad_roots are fake special operators, which are used internally # by other special forms (e.g., `except` in `try`) but can't be # used to construct special forms themselves. _bad_roots = tuple(ast_str(x) for x in ( "unquote", "unquote-splice", "unpack-mapping", "except")) def special(names, pattern): """Declare special operators. The decorated method and the given pattern is assigned to _special_form_compilers for each of the listed names.""" pattern = whole(pattern) def dec(fn): for name in names if isinstance(names, list) else [names]: if isinstance(name, tuple): condition, name = name if not condition: continue _special_form_compilers[ast_str(name)] = (fn, pattern) return fn return dec def builds_model(*model_types): "Assign the decorated method to _model_compilers for the given types." def _dec(fn): for t in model_types: _model_compilers[t] = fn return fn return _dec # Provide asty.Foo(x, ...) as shorthand for # ast.Foo(..., lineno=x.start_line, col_offset=x.start_column) or # ast.Foo(..., lineno=x.lineno, col_offset=x.col_offset) class Asty(object): def __getattr__(self, name): setattr(Asty, name, staticmethod(lambda x, **kwargs: getattr(ast, name)( lineno=getattr( x, 'start_line', getattr(x, 'lineno', None)), col_offset=getattr( x, 'start_column', getattr(x, 'col_offset', None)), **kwargs))) return getattr(Asty, name) asty = Asty() 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") 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.__used_expr = False # XXX: Make sure we only have AST where we should. for kwarg in kwargs: if kwarg not in ["imports", "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 @property def lineno(self): if self._expr is not None: return self._expr.lineno if self.stmts: return self.stmts[-1].lineno return None @property def col_offset(self): if self._expr is not None: return self._expr.col_offset if self.stmts: return self.stmts[-1].col_offset return None 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 return ast.Name( id=ast_str("None"), ctx=ast.Load(), lineno=self.stmts[-1].lineno if self.stmts else 0, col_offset=self.stmts[-1].col_offset if self.stmts else 0) 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() + asty.Expr(self.expr, 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, ast.AsyncFunctionDef)): 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 return result def __str__(self): return ( "Result(imports=[%s], stmts=[%s], expr=%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 )) def is_unpack(kind, x): return (isinstance(x, HyExpression) and len(x) > 0 and isinstance(x[0], HySymbol) and x[0] == "unpack-" + kind) def make_hy_model(outer, x, rest): return outer( [HySymbol(a) if type(a) is str else a[0] if type(a) is list else a for a in x] + (rest or [])) def mkexpr(*items, **kwargs): return make_hy_model(HyExpression, items, kwargs.get('rest')) def mklist(*items, **kwargs): return make_hy_model(HyList, items, kwargs.get('rest')) # Parse an annotation setting. OPTIONAL_ANNOTATION = maybe(pexpr(sym("annotate*") + FORM) >> (lambda x: x[0])) def is_annotate_expression(model): return (isinstance(model, HyExpression) and model and isinstance(model[0], HySymbol) and model[0] == HySymbol("annotate*")) class HyASTCompiler(object): """A Hy-to-Python AST compiler""" def __init__(self, module, filename=None, source=None): """ Parameters ---------- module: str or types.ModuleType Module name or object in which the Hy tree is evaluated. filename: str, optional The name of the file for the source to be compiled. This is optional information for informative error messages and debugging. source: str, optional The source for the file, if any, being compiled. This is optional information for informative error messages and debugging. """ self.anon_var_count = 0 self.imports = defaultdict(set) self.temp_if = None if not inspect.ismodule(module): self.module = importlib.import_module(module) else: self.module = module self.module_name = self.module.__name__ self.filename = filename self.source = source # Hy expects these to be present, so we prep the module for Hy # compilation. self.module.__dict__.setdefault('__macros__', {}) self.module.__dict__.setdefault('__tags__', {}) self.can_use_stdlib = not self.module_name.startswith("hy.core") self._stdlib = {} # Everything in core needs to be explicit (except for # the core macros, which are built with the core functions). if self.can_use_stdlib: # Load stdlib macros into the module namespace. load_macros(self.module) # Populate _stdlib. for stdlib_module in hy.core.STDLIB: mod = importlib.import_module(stdlib_module) for e in map(ast_str, getattr(mod, 'EXPORTS', [])): self._stdlib[e] = stdlib_module def get_anon_var(self): self.anon_var_count += 1 return "_hy_anon_var_%s" % self.anon_var_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(mkexpr('import', module).replace(expr)) names = sorted(name for name in names if name) if names: ret += self.compile(mkexpr('import', mklist(module, mklist(*names)))) self.imports = defaultdict(set) return ret.stmts def compile_atom(self, atom): # Compilation methods may mutate the atom, so copy it first. atom = copy.copy(atom) return Result() + _model_compilers[type(atom)](self, atom) def compile(self, tree): if tree is None: return Result() try: ret = self.compile_atom(tree) 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 HyLanguageError as e: # These are expected errors that should be passed to the user. reraise(type(e), e, sys.exc_info()[2]) except Exception as e: # These are unexpected errors that will--hopefully--never be seen # by the user. f_exc = traceback.format_exc() exc_msg = "Internal Compiler Bug 😱\n⤷ {}".format(f_exc) reraise(HyCompileError, HyCompileError(exc_msg), sys.exc_info()[2]) def _syntax_error(self, expr, message): return HySyntaxError(message, expr, self.filename, self.source) def _compile_collect(self, exprs, with_kwargs=False, dict_display=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 is_unpack("mapping", expr): ret += self.compile(expr[1]) if dict_display: compiled_exprs.append(None) compiled_exprs.append(ret.force_expr) elif with_kwargs: keywords.append(asty.keyword( expr, arg=None, value=ret.force_expr)) elif with_kwargs and isinstance(expr, HyKeyword): try: value = next(exprs_iter) except StopIteration: raise self._syntax_error(expr, "Keyword argument {kw} needs a value.".format(kw=expr)) if not expr: raise self._syntax_error(expr, "Can't call a function with the empty keyword") compiled_value = self.compile(value) ret += compiled_value arg = str(expr)[1:] keywords.append(asty.keyword( expr, arg=ast_str(arg), value=compiled_value.force_expr)) else: ret += self.compile(expr) compiled_exprs.append(ret.force_expr) return compiled_exprs, ret, keywords def _compile_branch(self, exprs): """Make a branch out of an iterable 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 """ ret = Result() for x in map(self.compile, exprs[:-1]): ret += x ret += x.expr_as_stmt() if exprs: ret += self.compile(exprs[-1]) return ret 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 self._syntax_error(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) 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) elif isinstance(name, ast.Starred): new_name = ast.Starred( value=self._storeize(expr, name.value, func)) else: raise self._syntax_error(expr, "Can't assign or delete a %s" % type(expr).__name__) new_name.ctx = func() ast.copy_location(new_name, name) return new_name 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. """ op = None if isinstance(form, HyExpression) and form and ( isinstance(form[0], HySymbol)): op = unmangle(ast_str(form[0])) if level == 0 and op in ("unquote", "unquote-splice"): if len(form) != 2: raise HyTypeError("`%s' needs 1 argument, got %s" % op, len(form) - 1, self.filename, form, self.source) return set(), form[1], op == "unquote-splice" elif op == "quasiquote": level += 1 elif op in ("unquote", "unquote-splice"): level -= 1 name = form.__class__.__name__ imports = set([name]) body = [form] if isinstance(form, HySequence): contents = [] for x in form: f_imps, f_contents, splice = self._render_quoted_form(x, level) imports.update(f_imps) if splice: contents.append(HyExpression([ HySymbol("list"), HyExpression([HySymbol("or"), f_contents, HyList()])])) else: contents.append(HyList([f_contents])) if form: # If there are arguments, they can be spliced # so we build a sum... body = [HyExpression([HySymbol("+"), HyList()] + contents)] else: body = [HyList()] elif isinstance(form, HySymbol): body = [HyString(form)] elif isinstance(form, HyKeyword): body = [HyString(form.name)] elif isinstance(form, HyString): if form.is_format: body.extend([HyKeyword("is_format"), form.is_format]) if form.brackets is not None: body.extend([HyKeyword("brackets"), form.brackets]) ret = HyExpression([HySymbol(name)] + body).replace(form) return imports, ret, False @special(["quote", "quasiquote"], [FORM]) def compile_quote(self, expr, root, arg): level = Inf if root == "quote" else 0 # Only quasiquotes can unquote imports, stmts, _ = self._render_quoted_form(arg, level) ret = self.compile(stmts) ret.add_imports("hy", imports) return ret @special("unpack-iterable", [FORM]) def compile_unpack_iterable(self, expr, root, arg): ret = self.compile(arg) ret += asty.Starred(expr, value=ret.force_expr, ctx=ast.Load()) return ret @special("do", [many(FORM)]) def compile_do(self, expr, root, body): return self._compile_branch(body) @special("raise", [maybe(FORM), maybe(sym(":from") + FORM)]) def compile_raise_expression(self, expr, root, exc, cause): ret = Result() if exc is not None: exc = self.compile(exc) ret += exc exc = exc.force_expr if cause is not None: cause = self.compile(cause) ret += cause cause = cause.force_expr return ret + asty.Raise( expr, type=ret.expr, exc=exc, inst=None, tback=None, cause=cause) @special("try", [many(notpexpr("except", "else", "finally")), many(pexpr(sym("except"), brackets() | brackets(FORM) | brackets(SYM, FORM), many(FORM))), maybe(dolike("else")), maybe(dolike("finally"))]) def compile_try_expression(self, expr, root, body, catchers, orelse, finalbody): body = self._compile_branch(body) return_var = asty.Name( expr, id=ast_str(self.get_anon_var()), ctx=ast.Store()) handler_results = Result() handlers = [] for catcher in catchers: handler_results += self._compile_catch_expression( catcher, return_var, *catcher) handlers.append(handler_results.stmts.pop()) if orelse is None: orelse = [] else: orelse = self._compile_branch(orelse) orelse += asty.Assign(expr, targets=[return_var], value=orelse.force_expr) orelse += orelse.expr_as_stmt() orelse = orelse.stmts if finalbody is None: finalbody = [] else: finalbody = self._compile_branch(finalbody) finalbody += finalbody.expr_as_stmt() finalbody = finalbody.stmts # Using (else) without (except) is verboten! if orelse and not handlers: raise self._syntax_error(expr, "`try' cannot have `else' without `except'") # Likewise a bare (try) or (try BODY). if not (handlers or finalbody): raise self._syntax_error(expr, "`try' must have an `except' or `finally' clause") returnable = Result( expr=asty.Name(expr, id=return_var.id, ctx=ast.Load()), temp_variables=[return_var]) body += body.expr_as_stmt() if orelse else asty.Assign( expr, targets=[return_var], value=body.force_expr) body = body.stmts or [asty.Pass(expr)] x = asty.Try( expr, body=body, handlers=handlers, orelse=orelse, finalbody=finalbody) return handler_results + x + returnable def _compile_catch_expression(self, expr, var, exceptions, body): # exceptions catch should be either: # [[list of exceptions]] # or # [variable [list of exceptions]] # or # [variable exception] # or # [exception] # or # [] name = None if len(exceptions) == 2: name = ast_str(exceptions[0]) exceptions_list = exceptions[-1] if exceptions else HyList() if isinstance(exceptions_list, HyList): if len(exceptions_list): # [FooBar BarFoo] → catch Foobar and BarFoo exceptions elts, types, _ = self._compile_collect(exceptions_list) types += asty.Tuple(exceptions_list, elts=elts, ctx=ast.Load()) else: # [] → all exceptions caught types = Result() else: types = self.compile(exceptions_list) body = self._compile_branch(body) body += asty.Assign(expr, targets=[var], value=body.force_expr) body += body.expr_as_stmt() return types + asty.ExceptHandler( expr, type=types.expr, name=name, body=body.stmts or [asty.Pass(expr)]) @special("if*", [FORM, FORM, maybe(FORM)]) def compile_if(self, expr, _, cond, body, orel_expr): cond = self.compile(cond) body = self.compile(body) nested = root = False orel = Result() if orel_expr is not None: 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 = asty.Name(expr, id=ast_str(self.temp_if), ctx=ast.Store()) branch += asty.Assign(expr, targets=[name], value=body.force_expr) 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 = asty.Name(expr, id=ast_str(var), ctx=ast.Store()) # Store the result of the body body += asty.Assign(expr, targets=[name], value=body.force_expr) # and of the else clause if not nested or not orel.stmts or (not root and var != self.temp_if): orel += asty.Assign(expr, targets=[name], value=orel.force_expr) # Then build the if ret += asty.If(expr, test=ret.force_expr, body=body.stmts, orelse=orel.stmts) # And make our expression context our temp variable expr_name = asty.Name(expr, id=ast_str(var), ctx=ast.Load()) ret += Result(expr=expr_name, temp_variables=[expr_name, name]) else: # Just make that an if expression ret += asty.IfExp(expr, test=ret.force_expr, body=body.force_expr, orelse=orel.force_expr) if root: self.temp_if = None return ret @special(["break", "continue"], []) def compile_break_or_continue_expression(self, expr, root): return (asty.Break if root == "break" else asty.Continue)(expr) @special("assert", [FORM, maybe(FORM)]) def compile_assert_expression(self, expr, root, test, msg): if msg is None or type(msg) is HySymbol: ret = self.compile(test) return ret + asty.Assert( expr, test=ret.force_expr, msg=(None if msg is None else self.compile(msg).force_expr)) # The `msg` part may involve statements, which we only # want to be executed if the assertion fails. Rewrite the # form to set `msg` to a variable. msg_var = self.get_anon_var() return self.compile(mkexpr( 'if*', mkexpr('and', '__debug__', mkexpr('not', [test])), mkexpr('do', mkexpr('setv', msg_var, [msg]), mkexpr('assert', 'False', msg_var))).replace(expr)) @special(["global", "nonlocal"], [oneplus(SYM)]) def compile_global_or_nonlocal(self, expr, root, syms): node = asty.Global if root == "global" else asty.Nonlocal return node(expr, names=list(map(ast_str, syms))) @special("yield", [maybe(FORM)]) def compile_yield_expression(self, expr, root, arg): ret = Result() if arg is not None: ret += self.compile(arg) return ret + asty.Yield(expr, value=ret.force_expr) @special(["yield-from", "await"], [FORM]) def compile_yield_from_or_await_expression(self, expr, root, arg): ret = Result() + self.compile(arg) node = asty.YieldFrom if root == "yield-from" else asty.Await return ret + node(expr, value=ret.force_expr) @special("get", [FORM, oneplus(FORM)]) def compile_index_expression(self, expr, name, obj, indices): indices, ret, _ = self._compile_collect(indices) ret += self.compile(obj) for ix in indices: ret += asty.Subscript( expr, value=ret.force_expr, slice=ast.Index(value=ix), ctx=ast.Load()) return ret @special(".", [FORM, many(SYM | brackets(FORM))]) def compile_attribute_access(self, expr, name, invocant, keys): ret = self.compile(invocant) for attr in keys: if isinstance(attr, HySymbol): ret += asty.Attribute(attr, value=ret.force_expr, attr=ast_str(attr), ctx=ast.Load()) else: # attr is a HyList compiled_attr = self.compile(attr[0]) ret = compiled_attr + ret + asty.Subscript( attr, value=ret.force_expr, slice=ast.Index(value=compiled_attr.force_expr), ctx=ast.Load()) return ret @special("del", [many(FORM)]) def compile_del_expression(self, expr, name, args): if not args: return asty.Pass(expr) del_targets = [] ret = Result() for target in args: compiled_target = self.compile(target) ret += compiled_target del_targets.append(self._storeize(target, compiled_target, ast.Del)) return ret + asty.Delete(expr, targets=del_targets) @special("cut", [FORM, maybe(FORM), maybe(FORM), maybe(FORM)]) def compile_cut_expression(self, expr, name, obj, lower, upper, step): ret = [Result()] def c(e): ret[0] += self.compile(e) return ret[0].force_expr s = asty.Subscript( expr, value=c(obj), slice=ast.Slice(lower=c(lower), upper=c(upper), step=c(step)), ctx=ast.Load()) return ret[0] + s @special("with-decorator", [oneplus(FORM)]) def compile_decorate_expression(self, expr, name, args): decs, fn = args[:-1], self.compile(args[-1]) if not fn.stmts or not isinstance(fn.stmts[-1], _decoratables): raise self._syntax_error(args[-1], "Decorated a non-function") decs, ret, _ = self._compile_collect(decs) fn.stmts[-1].decorator_list = decs + fn.stmts[-1].decorator_list return ret + fn @special(["with*", "with/a*"], [brackets(FORM, maybe(FORM)), many(FORM)]) def compile_with_expression(self, expr, root, args, body): thing, ctx = (None, args[0]) if args[1] is None else args if thing is not None: thing = self._storeize(thing, self.compile(thing)) ctx = self.compile(ctx) body = self._compile_branch(body) # Store the result of the body in a tempvar var = self.get_anon_var() name = asty.Name(expr, id=ast_str(var), ctx=ast.Store()) body += asty.Assign(expr, targets=[name], value=body.force_expr) # Initialize the tempvar to None in case the `with` exits # early with an exception. initial_assign = asty.Assign( expr, targets=[name], value=asty.Name( expr, id=ast_str("None"), ctx=ast.Load())) node = asty.With if root == "with*" else asty.AsyncWith the_with = node(expr, context_expr=ctx.force_expr, optional_vars=thing, body=body.stmts, items=[ast.withitem(context_expr=ctx.force_expr, optional_vars=thing)]) ret = Result(stmts=[initial_assign]) + ctx + the_with # And make our expression context our temp variable expr_name = asty.Name(expr, id=ast_str(var), ctx=ast.Load()) ret += Result(expr=expr_name) # We don't give the Result any temp_vars because we don't want # Result.rename to touch `name`. Otherwise, initial_assign will # clobber any preexisting value of the renamed-to variable. return ret @special(",", [many(FORM)]) def compile_tuple(self, expr, root, args): elts, ret, _ = self._compile_collect(args) return ret + asty.Tuple(expr, elts=elts, ctx=ast.Load()) _loopers = many( tag('setv', sym(":setv") + FORM + FORM) | tag('if', sym(":if") + FORM) | tag('do', sym(":do") + FORM) | tag('afor', sym(":async") + FORM + FORM) | tag('for', FORM + FORM)) @special(["for"], [brackets(_loopers), many(notpexpr("else")) + maybe(dolike("else"))]) @special(["lfor", "sfor", "gfor"], [_loopers, FORM]) @special(["dfor"], [_loopers, brackets(FORM, FORM)]) def compile_comprehension(self, expr, root, parts, final): node_class = { "for": asty.For, "lfor": asty.ListComp, "dfor": asty.DictComp, "sfor": asty.SetComp, "gfor": asty.GeneratorExp}[root] is_for = root == "for" orel = [] if is_for: # Get the `else`. body, else_expr = final if else_expr is not None: orel.append(self._compile_branch(else_expr)) orel[0] += orel[0].expr_as_stmt() else: # Get the final value (and for dictionary # comprehensions, the final key). if node_class is asty.DictComp: key, elt = map(self.compile, final) else: key = None elt = self.compile(final) # Compile the parts. if is_for: parts = parts[0] if not parts: return Result(expr=ast.parse({ asty.For: "None", asty.ListComp: "[]", asty.DictComp: "{}", asty.SetComp: "{1}.__class__()", asty.GeneratorExp: "(_ for _ in [])"}[node_class]).body[0].value) parts = [ Tag(p.tag, self.compile(p.value) if p.tag in ["if", "do"] else [ self._storeize(p.value[0], self.compile(p.value[0])), self.compile(p.value[1])]) for p in parts] # Produce a result. if (is_for or elt.stmts or (key is not None and key.stmts) or any(p.tag == 'do' or (p.value[1].stmts if p.tag in ("for", "afor", "setv") else p.value.stmts) for p in parts)): # The desired comprehension can't be expressed as a # real Python comprehension. We'll write it as a nested # loop in a function instead. def f(parts): # This function is called recursively to construct # the nested loop. if not parts: if is_for: if body: bd = self._compile_branch(body) return bd + bd.expr_as_stmt() return Result(stmts=[asty.Pass(expr)]) if node_class is asty.DictComp: ret = key + elt val = asty.Tuple( key, ctx=ast.Load(), elts=[key.force_expr, elt.force_expr]) else: ret = elt val = elt.force_expr return ret + asty.Expr( elt, value=asty.Yield(elt, value=val)) (tagname, v), parts = parts[0], parts[1:] if tagname in ("for", "afor"): orelse = orel and orel.pop().stmts node = asty.AsyncFor if tagname == "afor" else asty.For return v[1] + node( v[1], target=v[0], iter=v[1].force_expr, body=f(parts).stmts, orelse=orelse) elif tagname == "setv": return v[1] + asty.Assign( v[1], targets=[v[0]], value=v[1].force_expr) + f(parts) elif tagname == "if": return v + asty.If( v, test=v.force_expr, body=f(parts).stmts, orelse=[]) elif tagname == "do": return v + v.expr_as_stmt() + f(parts) else: raise ValueError("can't happen") if is_for: return f(parts) fname = self.get_anon_var() # Define the generator function. ret = Result() + asty.FunctionDef( expr, name=fname, args=ast.arguments( args=[], vararg=None, kwarg=None, posonlyargs=[], kwonlyargs=[], kw_defaults=[], defaults=[]), body=f(parts).stmts, decorator_list=[]) # Immediately call the new function. Unless the user asked # for a generator, wrap the call in `[].__class__(...)` or # `{}.__class__(...)` or `{1}.__class__(...)` to get the # right type. We don't want to just use e.g. `list(...)` # because the name `list` might be rebound. return ret + Result(expr=ast.parse( "{}({}())".format( {asty.ListComp: "[].__class__", asty.DictComp: "{}.__class__", asty.SetComp: "{1}.__class__", asty.GeneratorExp: ""}[node_class], fname)).body[0].value) # We can produce a real comprehension. generators = [] for tagname, v in parts: if tagname in ("for", "afor"): generators.append(ast.comprehension( target=v[0], iter=v[1].expr, ifs=[], is_async=int(tagname == "afor"))) elif tagname == "setv": generators.append(ast.comprehension( target=v[0], iter=asty.Tuple(v[1], elts=[v[1].expr], ctx=ast.Load()), ifs=[], is_async=0)) elif tagname == "if": generators[-1].ifs.append(v.expr) else: raise ValueError("can't happen") if node_class is asty.DictComp: return asty.DictComp(expr, key=key.expr, value=elt.expr, generators=generators) return node_class(expr, elt=elt.expr, generators=generators) @special(["not", "~"], [FORM]) def compile_unary_operator(self, expr, root, arg): ops = {"not": ast.Not, "~": ast.Invert} operand = self.compile(arg) return operand + asty.UnaryOp( expr, op=ops[root](), operand=operand.force_expr) _symn = some(lambda x: isinstance(x, HySymbol) and "." not in x) @special(["import", "require"], [many( SYM | brackets(SYM, sym(":as"), _symn) | brackets(SYM, brackets(many(_symn + maybe(sym(":as") + _symn)))))]) def compile_import_or_require(self, expr, root, entries): ret = Result() for entry in entries: assignments = "ALL" prefix = "" if isinstance(entry, HySymbol): # e.g., (import foo) module, prefix = entry, entry elif isinstance(entry, HyList) and isinstance(entry[1], HySymbol): # e.g., (import [foo :as bar]) module, prefix = entry else: # e.g., (import [foo [bar baz :as MyBaz bing]]) # or (import [foo [*]]) module, kids = entry kids = kids[0] if (HySymbol('*'), None) in kids: if len(kids) != 1: star = kids[kids.index((HySymbol('*'), None))][0] raise self._syntax_error(star, "* in an import name list must be on its own") else: assignments = [(k, v or k) for k, v in kids] ast_module = ast_str(module, piecewise=True) if root == "import": module = ast_module.lstrip(".") level = len(ast_module) - len(module) if assignments == "ALL" and prefix == "": node = asty.ImportFrom names = [ast.alias(name="*", asname=None)] elif assignments == "ALL": node = asty.Import prefix = ast_str(prefix, piecewise=True) names = [ast.alias( name=ast_module, asname=prefix if prefix != module else None)] else: node = asty.ImportFrom names = [ ast.alias( name=ast_str(k), asname=None if v == k else ast_str(v)) for k, v in assignments] ret += node( expr, module=module or None, names=names, level=level) elif require(ast_module, self.module, assignments=assignments, prefix=prefix): # Actually calling `require` is necessary for macro expansions # occurring during compilation. self.imports['hy.macros'].update([None]) # The `require` we're creating in AST is the same as above, but used at # run-time (e.g. when modules are loaded via bytecode). ret += self.compile(HyExpression([ HySymbol('hy.macros.require'), HyString(ast_module), HySymbol('None'), HyKeyword('assignments'), (HyString("ALL") if assignments == "ALL" else [[HyString(k), HyString(v)] for k, v in assignments]), HyKeyword('prefix'), HyString(prefix)]).replace(expr)) return ret @special(["and", "or"], [many(FORM)]) def compile_logical_or_and_and_operator(self, expr, operator, args): ops = {"and": (ast.And, "True"), "or": (ast.Or, "None")} opnode, default = ops[operator] osym = expr[0] if len(args) == 0: return asty.Name(osym, id=default, ctx=ast.Load()) elif len(args) == 1: return self.compile(args[0]) ret = Result() values = list(map(self.compile, args)) if any(value.stmts for value in values): # Compile it to an if...else sequence var = self.get_anon_var() name = asty.Name(osym, id=var, ctx=ast.Store()) expr_name = asty.Name(osym, id=var, ctx=ast.Load()) temp_variables = [name, expr_name] def make_assign(value, node=None): positioned_name = asty.Name( node or osym, id=var, ctx=ast.Store()) temp_variables.append(positioned_name) return asty.Assign( node or osym, targets=[positioned_name], value=value) 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 = asty.UnaryOp(node, op=ast.Not(), operand=expr_name) current.append(asty.If(node, test=cond, body=[], orelse=[])) current = current[-1].body ret = sum(root, ret) ret += Result(expr=expr_name, temp_variables=temp_variables) else: ret += asty.BoolOp(osym, op=opnode(), values=[value.force_expr for value in values]) return ret _c_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} _c_ops = {ast_str(k): v for k, v in _c_ops.items()} def _get_c_op(self, sym): k = ast_str(sym) if k not in self._c_ops: raise self._syntax_error(sym, "Illegal comparison operator: " + str(sym)) return self._c_ops[k]() @special(["=", "is", "<", "<=", ">", ">="], [oneplus(FORM)]) @special(["!=", "is-not", "in", "not-in"], [times(2, Inf, FORM)]) def compile_compare_op_expression(self, expr, root, args): if len(args) == 1: return (self.compile(args[0]) + asty.Name(expr, id="True", ctx=ast.Load())) ops = [self._get_c_op(root) for _ in args[1:]] exprs, ret, _ = self._compile_collect(args) return ret + asty.Compare( expr, left=exprs[0], ops=ops, comparators=exprs[1:]) @special("cmp", [FORM, many(SYM + FORM)]) def compile_chained_comparison(self, expr, root, arg1, args): ret = self.compile(arg1) arg1 = ret.force_expr ops = [self._get_c_op(op) for op, _ in args] args, ret2, _ = self._compile_collect( [x for _, x in args]) return ret + ret2 + asty.Compare(expr, left=arg1, ops=ops, comparators=args) # The second element of each tuple below is an aggregation operator # that's used for augmented assignment with three or more arguments. m_ops = {"+": (ast.Add, "+"), "/": (ast.Div, "*"), "//": (ast.FloorDiv, "*"), "*": (ast.Mult, "*"), "-": (ast.Sub, "+"), "%": (ast.Mod, None), "**": (ast.Pow, "**"), "<<": (ast.LShift, "+"), ">>": (ast.RShift, "+"), "|": (ast.BitOr, "|"), "^": (ast.BitXor, None), "&": (ast.BitAnd, "&"), "@": (ast.MatMult, "@")} @special(["+", "*", "|"], [many(FORM)]) @special(["-", "/", "&", "@"], [oneplus(FORM)]) @special(["**", "//", "<<", ">>"], [times(2, Inf, FORM)]) @special(["%", "^"], [times(2, 2, FORM)]) def compile_maths_expression(self, expr, root, args): if len(args) == 0: # Return the identity element for this operator. return asty.Num(expr, n=( {"+": 0, "|": 0, "*": 1}[root])) if len(args) == 1: if root == "/": # Compute the reciprocal of the argument. args = [HyInteger(1).replace(expr), args[0]] elif root in ("+", "-"): # Apply unary plus or unary minus to the argument. op = {"+": ast.UAdd, "-": ast.USub}[root]() ret = self.compile(args[0]) return ret + asty.UnaryOp(expr, op=op, operand=ret.force_expr) else: # Return the argument unchanged. return self.compile(args[0]) op = self.m_ops[root][0] right_associative = root == "**" ret = self.compile(args[-1 if right_associative else 0]) for child in args[-2 if right_associative else 1 :: -1 if right_associative else 1]: left_expr = ret.force_expr ret += self.compile(child) right_expr = ret.force_expr if right_associative: left_expr, right_expr = right_expr, left_expr ret += asty.BinOp(expr, left=left_expr, op=op(), right=right_expr) return ret a_ops = {x + "=": v for x, v in m_ops.items()} @special([x for x, (_, v) in a_ops.items() if v is not None], [FORM, oneplus(FORM)]) @special([x for x, (_, v) in a_ops.items() if v is None], [FORM, times(1, 1, FORM)]) def compile_augassign_expression(self, expr, root, target, values): if len(values) > 1: return self.compile(mkexpr(root, [target], mkexpr(self.a_ops[root][1], rest=values)).replace(expr)) op = self.a_ops[root][0] target = self._storeize(target, self.compile(target)) ret = self.compile(values[0]) return ret + asty.AugAssign( expr, target=target, value=ret.force_expr, op=op()) @special("setv", [many(OPTIONAL_ANNOTATION + FORM + FORM)]) @special((PY38, "setx"), [times(1, 1, SYM + FORM)]) def compile_def_expression(self, expr, root, decls): if not decls: return asty.Name(expr, id='None', ctx=ast.Load()) result = Result() is_assignment_expr = root == HySymbol("setx") for decl in decls: if is_assignment_expr: ann = None name, value = decl else: ann, name, value = decl result += self._compile_assign(ann, name, value, is_assignment_expr=is_assignment_expr) return result @special(["annotate*"], [FORM, FORM]) def compile_basic_annotation(self, expr, root, ann, target): return self._compile_assign(ann, target, None) def _compile_assign(self, ann, name, value, *, is_assignment_expr = False): # Ensure that assignment expressions have a result and no annotation. assert not is_assignment_expr or (value is not None and ann is None) ld_name = self.compile(name) annotate_only = value is None if annotate_only: result = Result() else: result = self.compile(value) invalid_name = False if ann is not None: # An annotation / annotated assignment is more strict with the target expression. invalid_name = not isinstance(ld_name.expr, (ast.Name, ast.Attribute, ast.Subscript)) else: invalid_name = (str(name) in ("None", "True", "False") or isinstance(ld_name.expr, ast.Call)) if invalid_name: raise self._syntax_error(name, "illegal target for {}".format( "annotation" if annotate_only else "assignment")) if (result.temp_variables and isinstance(name, HySymbol) and '.' not in name): result.rename(name) if not is_assignment_expr: # Throw away .expr to ensure that (setv ...) returns None. result.expr = None else: st_name = self._storeize(name, ld_name) if ann is not None: ann_result = self.compile(ann) result = ann_result + result if is_assignment_expr: node = asty.NamedExpr elif ann is not None: if not PY36: raise self._syntax_error(name, "Variable annotations are not supported on " "Python <=3.6") node = lambda x, **kw: asty.AnnAssign(x, annotation=ann_result.force_expr, simple=int(isinstance(name, HySymbol)), **kw) else: node = asty.Assign result += node( name if hasattr(name, "start_line") else result, value=result.force_expr if not annotate_only else None, target=st_name, targets=[st_name]) return result @special(["while"], [FORM, many(notpexpr("else")), maybe(dolike("else"))]) def compile_while_expression(self, expr, root, cond, body, else_expr): cond_compiled = self.compile(cond) body = self._compile_branch(body) body += body.expr_as_stmt() body_stmts = body.stmts or [asty.Pass(expr)] if cond_compiled.stmts: # We need to ensure the statements for the condition are # executed on every iteration. Rewrite the loop to use a # single anonymous variable as the condition, i.e.: # anon_var = True # while anon_var: # condition stmts... # anon_var = condition expr # if anon_var: # while loop body cond_var = asty.Name(cond, id=self.get_anon_var(), ctx=ast.Load()) def make_not(operand): return asty.UnaryOp(cond, op=ast.Not(), operand=operand) body_stmts = cond_compiled.stmts + [ asty.Assign(cond, targets=[self._storeize(cond, cond_var)], # Cast the condition to a bool in case it's mutable and # changes its truth value, but use (not (not ...)) instead of # `bool` in case `bool` has been redefined. value=make_not(make_not(cond_compiled.force_expr))), asty.If(cond, test=cond_var, body=body_stmts, orelse=[]), ] cond_compiled = (Result() + asty.Assign(cond, targets=[self._storeize(cond, cond_var)], value=asty.Name(cond, id="True", ctx=ast.Load())) + cond_var) orel = Result() if else_expr is not None: orel = self._compile_branch(else_expr) orel += orel.expr_as_stmt() ret = cond_compiled + asty.While( expr, test=cond_compiled.force_expr, body=body_stmts, orelse=orel.stmts) return ret NASYM = some(lambda x: isinstance(x, HySymbol) and x not in ( "&optional", "&rest", "&kwonly", "&kwargs")) @special(["fn", "fn*", "fn/a"], [ # The starred version is for internal use (particularly, in the # definition of `defn`). It ensures that a FunctionDef is # produced rather than a Lambda. OPTIONAL_ANNOTATION, brackets( many(OPTIONAL_ANNOTATION + NASYM), maybe(sym("&optional") + many(OPTIONAL_ANNOTATION + (NASYM | brackets(SYM, FORM)))), maybe(sym("&rest") + OPTIONAL_ANNOTATION + NASYM), maybe(sym("&kwonly") + many(OPTIONAL_ANNOTATION + (NASYM | brackets(SYM, FORM)))), maybe(sym("&kwargs") + OPTIONAL_ANNOTATION + NASYM)), many(FORM)]) def compile_function_def(self, expr, root, returns, params, body): force_functiondef = root in ("fn*", "fn/a") node = asty.AsyncFunctionDef if root == "fn/a" else asty.FunctionDef ret = Result() # NOTE: Our evaluation order of return type annotations is # different from Python: Python evalautes them after the argument # annotations / defaults (as that's where they are in the source), # but Hy evaluates them *first*, since here they come before the # # argument list. Therefore, it would be more confusing for # readability to evaluate them after like Python. ret = Result() returns_ann = None if returns is not None: returns_result = self.compile(returns) ret += returns_result mandatory, optional, rest, kwonly, kwargs = params optional = optional or [] kwonly = kwonly or [] mandatory_ast, _, ret = self._compile_arguments_set(mandatory, False, ret) optional_ast, optional_defaults, ret = self._compile_arguments_set(optional, True, ret) kwonly_ast, kwonly_defaults, ret = self._compile_arguments_set(kwonly, False, ret) rest_ast = kwargs_ast = None if rest is not None: [rest_ast], _, ret = self._compile_arguments_set([rest], False, ret) if kwargs is not None: [kwargs_ast], _, ret = self._compile_arguments_set([kwargs], False, ret) args = ast.arguments( args=mandatory_ast + optional_ast, defaults=optional_defaults, vararg=rest_ast, posonlyargs=[], kwonlyargs=kwonly_ast, kw_defaults=kwonly_defaults, kwarg=kwargs_ast) body = self._compile_branch(body) if not force_functiondef and not body.stmts and returns is None: return ret + asty.Lambda(expr, args=args, body=body.force_expr) if body.expr: body += asty.Return(body.expr, value=body.expr) name = self.get_anon_var() ret += node(expr, name=name, args=args, body=body.stmts or [asty.Pass(expr)], decorator_list=[], returns=returns_result.force_expr if returns is not None else None) ast_name = asty.Name(expr, id=name, ctx=ast.Load()) ret += Result(expr=ast_name, temp_variables=[ast_name, ret.stmts[-1]]) return ret def _compile_arguments_set(self, decls, implicit_default_none, ret): args_ast = [] args_defaults = [] for ann, decl in decls: default = None # funcparserlib will check to make sure that the only times we # ever have a HyList here are due to a default value. if isinstance(decl, HyList): sym, default = decl else: sym = decl if implicit_default_none: default = HySymbol('None').replace(sym) if ann is not None: ret += self.compile(ann) ann_ast = ret.force_expr else: ann_ast = None if default is not None: ret += self.compile(default) args_defaults.append(ret.force_expr) else: # Note that the only time any None should ever appear here # is in kwargs, since the order of those with defaults vs # those without isn't significant in the same way as # positional args. args_defaults.append(None) args_ast.append(asty.arg(sym, arg=ast_str(sym), annotation=ann_ast)) return args_ast, args_defaults, ret @special("return", [maybe(FORM)]) def compile_return(self, expr, root, arg): ret = Result() if arg is None: return asty.Return(expr, value=None) ret += self.compile(arg) return ret + asty.Return(expr, value=ret.force_expr) @special("defclass", [ SYM, maybe(brackets(many(FORM)) + maybe(STR) + many(FORM))]) def compile_class_expression(self, expr, root, name, rest): base_list, docstring, body = rest or ([[]], None, []) bases_expr, bases, keywords = ( self._compile_collect(base_list[0], with_kwargs=True)) bodyr = Result() if docstring is not None: bodyr += self.compile(docstring).expr_as_stmt() for e in body: e = self.compile(self._rewire_init( macroexpand(e, self.module, self))) bodyr += e + e.expr_as_stmt() return bases + asty.ClassDef( expr, decorator_list=[], name=ast_str(name), keywords=keywords, starargs=None, kwargs=None, bases=bases_expr, body=bodyr.stmts or [asty.Pass(expr)]) def _rewire_init(self, expr): "Given a (setv …) form, append None to definitions of __init__." if not (isinstance(expr, HyExpression) and len(expr) > 1 and isinstance(expr[0], HySymbol) and expr[0] == HySymbol("setv")): return expr new_args = [] decls = list(expr[1:]) while decls: if is_annotate_expression(decls[0]): # Handle annotations. ann = decls.pop(0) else: ann = None k, v = (decls.pop(0), decls.pop(0)) if ast_str(k) == "__init__" and isinstance(v, HyExpression): v += HyExpression([HySymbol("None")]) if ann is not None: new_args.append(ann) new_args.extend((k, v)) return HyExpression([HySymbol("setv")] + new_args).replace(expr) @special("dispatch-tag-macro", [STR, FORM]) def compile_dispatch_tag_macro(self, expr, root, tag, arg): return self.compile(tag_macroexpand( HyString(mangle(tag)).replace(tag), arg, self.module)) @special(["eval-and-compile", "eval-when-compile"], [many(FORM)]) def compile_eval_and_compile(self, expr, root, body): new_expr = HyExpression([HySymbol("do").replace(expr[0])]).replace(expr) try: hy_eval(new_expr + body, self.module.__dict__, self.module, filename=self.filename, source=self.source) except HyInternalError: # Unexpected "meta" compilation errors need to be treated # like normal (unexpected) compilation errors at this level # (or the compilation level preceding this one). raise except Exception as e: # These could be expected Hy language errors (e.g. syntax errors) # or regular Python runtime errors that do not signify errors in # the compilation *process* (although compilation did technically # fail). # We wrap these exceptions and pass them through. reraise(HyEvalError, HyEvalError(str(e), self.filename, body, self.source), sys.exc_info()[2]) return (self._compile_branch(body) if ast_str(root) == "eval_and_compile" else Result()) @special(["py", "pys"], [STR]) def compile_inline_python(self, expr, root, code): exec_mode = root == HySymbol("pys") try: o = ast.parse( textwrap.dedent(code) if exec_mode else code, self.filename, 'exec' if exec_mode else 'eval').body except (SyntaxError, ValueError if PY36 else TypeError) as e: raise self._syntax_error( expr, "Python parse error in '{}': {}".format(root, e)) return Result(stmts=o) if exec_mode else o @builds_model(HyExpression) def compile_expression(self, expr, *, allow_annotation_expression=False): # Perform macro expansions expr = macroexpand(expr, self.module, self) if not isinstance(expr, HyExpression): # Go through compile again if the type changed. return self.compile(expr) if not expr: raise self._syntax_error(expr, "empty expressions are not allowed at top level") args = list(expr) root = args.pop(0) func = None if isinstance(root, HySymbol): # First check if `root` is a special operator, unless it has an # `unpack-iterable` in it, since Python's operators (`+`, # etc.) can't unpack. An exception to this exception is that # tuple literals (`,`) can unpack. Finally, we allow unpacking in # `.` forms here so the user gets a better error message. sroot = ast_str(root) bad_root = sroot in _bad_roots or (sroot == ast_str("annotate*") and not allow_annotation_expression) if (sroot in _special_form_compilers or bad_root) and ( sroot in (mangle(","), mangle(".")) or not any(is_unpack("iterable", x) for x in args)): if bad_root: raise self._syntax_error(expr, "The special form '{}' is not allowed here".format(root)) # `sroot` is a special operator. Get the build method and # pattern-match the arguments. build_method, pattern = _special_form_compilers[sroot] try: parse_tree = pattern.parse(args) except NoParseError as e: raise self._syntax_error( expr[min(e.state.pos + 1, len(expr) - 1)], "parse error for special form '{}': {}".format( root, e.msg.replace("", "end of form"))) return Result() + build_method( self, expr, unmangle(sroot), *parse_tree) if root.startswith("."): # (.split "test test") -> "test test".split() # (.a.b.c x v1 v2) -> (.c (. x a b) v1 v2) -> x.a.b.c(v1, v2) # Get the method name (the last named attribute # in the chain of attributes) attrs = [HySymbol(a).replace(root) for a in root.split(".")[1:]] root = attrs.pop() # Get the object we're calling the method on # (extracted with the attribute access DSL) # Skip past keywords and their arguments. try: kws, obj, rest = ( many(KEYWORD + FORM | unpack("mapping")) + FORM + many(FORM)).parse(args) except NoParseError: raise self._syntax_error(expr, "attribute access requires object") # Reconstruct `args` to exclude `obj`. args = [x for p in kws for x in p] + list(rest) if is_unpack("iterable", obj): raise self._syntax_error(obj, "can't call a method on an unpacking form") func = self.compile(HyExpression( [HySymbol(".").replace(root), obj] + attrs)) # And get the method func += asty.Attribute(root, value=func.force_expr, attr=ast_str(root), ctx=ast.Load()) elif is_annotate_expression(root): # Flatten and compile the annotation expression. ann_expr = HyExpression(root + args).replace(root) return self.compile_expression(ann_expr, allow_annotation_expression=True) if not func: func = self.compile(root) args, ret, keywords = self._compile_collect(args, with_kwargs=True) return func + ret + asty.Call( expr, func=func.expr, args=args, keywords=keywords) @builds_model(HyInteger, HyFloat, HyComplex) def compile_numeric_literal(self, x): f = {HyInteger: int, HyFloat: float, HyComplex: complex}[type(x)] return asty.Num(x, n=f(x)) @builds_model(HySymbol) def compile_symbol(self, symbol): if "." in symbol: glob, local = symbol.rsplit(".", 1) if not glob: raise self._syntax_error(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 self._syntax_error(symbol, 'cannot access empty attribute') glob = HySymbol(glob).replace(symbol) ret = self.compile_symbol(glob) return asty.Attribute( symbol, value=ret, attr=ast_str(local), ctx=ast.Load()) if self.can_use_stdlib and ast_str(symbol) in self._stdlib: self.imports[self._stdlib[ast_str(symbol)]].add(ast_str(symbol)) return asty.Name(symbol, id=ast_str(symbol), ctx=ast.Load()) @builds_model(HyKeyword) def compile_keyword(self, obj): ret = Result() ret += asty.Call( obj, func=asty.Name(obj, id="HyKeyword", ctx=ast.Load()), args=[asty.Str(obj, s=obj.name)], keywords=[]) ret.add_imports("hy", {"HyKeyword"}) return ret @builds_model(HyString, HyBytes) def compile_string(self, string): if type(string) is HyString and string.is_format: # This is a format string (a.k.a. an f-string). return self._format_string(string, str(string)) node = asty.Bytes if type(string) is HyBytes else asty.Str f = bytes if type(string) is HyBytes else str return node(string, s=f(string)) def _format_string(self, string, rest, allow_recursion=True): values = [] ret = Result() while True: # Look for the next replacement field, and get the # plain text before it. match = re.search(r'\{\{?|\}\}?', rest) if match: literal_chars = rest[: match.start()] if match.group() == '}': raise self._syntax_error(string, "f-string: single '}' is not allowed") if match.group() in ('{{', '}}'): # Doubled braces just add a single brace to the text. literal_chars += match.group()[0] rest = rest[match.end() :] else: literal_chars = rest rest = "" if literal_chars: values.append(asty.Str(string, s = literal_chars)) if not rest: break if match.group() != '{': continue # Look for the end of the replacement field, allowing # one more level of matched braces, but no deeper, and only # if we can recurse. match = re.match( r'(?: \{ [^{}]* \} | [^{}]+ )* \}' if allow_recursion else r'[^{}]* \}', rest, re.VERBOSE) if not match: raise self._syntax_error(string, 'f-string: mismatched braces') item = rest[: match.end() - 1] rest = rest[match.end() :] # Parse the first form. try: model, item = parse_one_thing(item) except (ValueError, LexException) as e: raise self._syntax_error(string, "f-string: " + str(e)) # Look for a conversion character. item = item.lstrip() conversion = None if item.startswith('!'): conversion = item[1] item = item[2:].lstrip() # Look for a format specifier. format_spec = None if item.startswith(':'): if allow_recursion: ret += self._format_string(string, item[1:], allow_recursion=False) format_spec = ret.force_expr else: format_spec = asty.Str(string, s=item[1:]) if PY36: format_spec = asty.JoinedStr(string, values=[format_spec]) elif item: raise self._syntax_error(string, "f-string: trailing junk in field") # Now, having finished compiling any recursively included # forms, we can compile the first form that we parsed. ret += self.compile(model) if PY36: values.append(asty.FormattedValue( string, conversion = -1 if conversion is None else ord(conversion), format_spec = format_spec, value = ret.force_expr)) else: # Make an expression like: # "{!r:{}}".format(value, format_spec) values.append(asty.Call(string, func = asty.Attribute( string, value = asty.Str(string, s = '{' + ('!' + conversion if conversion else '') + ':{}}'), attr = 'format', ctx = ast.Load()), args = [ ret.force_expr, format_spec or asty.Str(string, s = "")], keywords = [], starargs = None, kwargs = None)) return ret + ( asty.JoinedStr(string, values = values) if PY36 else reduce( lambda x, y: asty.BinOp(string, left = x, op = ast.Add(), right = y), values)) @builds_model(HyList, HySet) def compile_list(self, expression): elts, ret, _ = self._compile_collect(expression) node = {HyList: asty.List, HySet: asty.Set}[type(expression)] return ret + node(expression, elts=elts, ctx=ast.Load()) @builds_model(HyDict) def compile_dict(self, m): keyvalues, ret, _ = self._compile_collect(m, dict_display=True) return ret + asty.Dict(m, keys=keyvalues[::2], values=keyvalues[1::2]) def get_compiler_module(module=None, compiler=None, calling_frame=False): """Get a module object from a compiler, given module object, string name of a module, and (optionally) the calling frame; otherwise, raise an error.""" module = getattr(compiler, 'module', None) or module if isinstance(module, str): if module.startswith('<') and module.endswith('>'): module = types.ModuleType(module) else: module = importlib.import_module(ast_str(module, piecewise=True)) if calling_frame and not module: module = calling_module(n=2) if not inspect.ismodule(module): raise TypeError('Invalid module type: {}'.format(type(module))) return module def hy_eval(hytree, locals=None, module=None, ast_callback=None, compiler=None, filename=None, source=None): """Evaluates a quoted expression and returns the value. If you're evaluating hand-crafted AST trees, make sure the line numbers are set properly. Try `fix_missing_locations` and related functions in the Python `ast` library. Examples -------- => (eval '(print "Hello World")) "Hello World" If you want to evaluate a string, use ``read-str`` to convert it to a form first: => (eval (read-str "(+ 1 1)")) 2 Parameters ---------- hytree: HyObject The Hy AST object to evaluate. locals: dict, optional Local environment in which to evaluate the Hy tree. Defaults to the calling frame. module: str or types.ModuleType, optional Module, or name of the module, to which the Hy tree is assigned and the global values are taken. The module associated with `compiler` takes priority over this value. When neither `module` nor `compiler` is specified, the calling frame's module is used. ast_callback: callable, optional A callback that is passed the Hy compiled tree and resulting expression object, in that order, after compilation but before evaluation. compiler: HyASTCompiler, optional An existing Hy compiler to use for compilation. Also serves as the `module` value when given. filename: str, optional The filename corresponding to the source for `tree`. This will be overridden by the `filename` field of `tree`, if any; otherwise, it defaults to "". When `compiler` is given, its `filename` field value is always used. source: str, optional A string containing the source code for `tree`. This will be overridden by the `source` field of `tree`, if any; otherwise, if `None`, an attempt will be made to obtain it from the module given by `module`. When `compiler` is given, its `source` field value is always used. Returns ------- out : Result of evaluating the Hy compiled tree. """ module = get_compiler_module(module, compiler, True) if locals is None: frame = inspect.stack()[1][0] locals = inspect.getargvalues(frame).locals if not isinstance(locals, dict): raise TypeError("Locals must be a dictionary") # Does the Hy AST object come with its own information? filename = getattr(hytree, 'filename', filename) or '' source = getattr(hytree, 'source', source) _ast, expr = hy_compile(hytree, module, get_expr=True, compiler=compiler, filename=filename, source=source) if ast_callback: ast_callback(_ast, expr) # Two-step eval: eval() the body of the exec call eval(ast_compile(_ast, filename, "exec"), module.__dict__, locals) # Then eval the expression context and return that return eval(ast_compile(expr, filename, "eval"), module.__dict__, locals) def _module_file_source(module_name, filename, source): """Try to obtain missing filename and source information from a module name without actually loading the module. """ if filename is None or source is None: mod_loader = pkgutil.get_loader(module_name) if mod_loader: if filename is None: filename = mod_loader.get_filename(module_name) if source is None: source = mod_loader.get_source(module_name) # We need a non-None filename. filename = filename or '' return filename, source def hy_compile(tree, module, root=ast.Module, get_expr=False, compiler=None, filename=None, source=None): """Compile a HyObject tree into a Python AST Module. Parameters ---------- tree: HyObject The Hy AST object to compile. module: str or types.ModuleType, optional Module, or name of the module, in which the Hy tree is evaluated. The module associated with `compiler` takes priority over this value. root: ast object, optional (ast.Module) Root object for the Python AST tree. get_expr: bool, optional (False) If true, return a tuple with `(root_obj, last_expression)`. compiler: HyASTCompiler, optional An existing Hy compiler to use for compilation. Also serves as the `module` value when given. filename: str, optional The filename corresponding to the source for `tree`. This will be overridden by the `filename` field of `tree`, if any; otherwise, it defaults to "". When `compiler` is given, its `filename` field value is always used. source: str, optional A string containing the source code for `tree`. This will be overridden by the `source` field of `tree`, if any; otherwise, if `None`, an attempt will be made to obtain it from the module given by `module`. When `compiler` is given, its `source` field value is always used. Returns ------- out : A Python AST tree """ module = get_compiler_module(module, compiler, False) if isinstance(module, str): if module.startswith('<') and module.endswith('>'): module = types.ModuleType(module) else: module = importlib.import_module(ast_str(module, piecewise=True)) if not inspect.ismodule(module): raise TypeError('Invalid module type: {}'.format(type(module))) filename = getattr(tree, 'filename', filename) source = getattr(tree, 'source', source) tree = wrap_value(tree) if not isinstance(tree, HyObject): raise TypeError("`tree` must be a HyObject or capable of " "being promoted to one") compiler = compiler or HyASTCompiler(module, filename=filename, source=source) result = compiler.compile(tree) expr = result.force_expr if not get_expr: result += result.expr_as_stmt() body = [] # Pull out a single docstring and prepend to the resulting body. if (len(result.stmts) > 0 and issubclass(root, ast.Module) and isinstance(result.stmts[0], ast.Expr) and isinstance(result.stmts[0].value, ast.Str)): body += [result.stmts.pop(0)] body += sorted(compiler.imports_as_stmts(tree) + result.stmts, key=lambda a: not (isinstance(a, ast.ImportFrom) and a.module == '__future__')) ret = root(body=body, type_ignores=[]) if get_expr: expr = ast.Expression(body=expr) ret = (ret, expr) return ret hy-0.18.0/hy/completer.py000066400000000000000000000067401361554632000152200ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import contextlib import os import re import sys import builtins import hy.macros import hy.compiler docomplete = True try: import readline except ImportError: try: import pyreadline.rlmain import pyreadline.unicode_helper # NOQA import readline except ImportError: docomplete = False if docomplete: 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._special_form_compilers, builtins.__dict__, namespace] self.tag_path = [] namespace.setdefault('__macros__', {}) namespace.setdefault('__tags__', {}) self.path.append(namespace['__macros__']) self.tag_path.append(namespace['__tags__']) 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, str): k = k.replace("_", "-") if k.startswith(text): matches.append(k) return matches def tag_matches(self, text): text = text[1:] matches = [] for p in self.tag_path: for k in p.keys(): if isinstance(k, str): if k.startswith(text): matches.append("#{}".format(k)) return matches def complete(self, text, state): if text.startswith("#"): matches = self.tag_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: pass readline.parse_and_bind(readline_bind) try: yield finally: if docomplete: try: readline.write_history_file(history) except IOError: pass hy-0.18.0/hy/contrib/000077500000000000000000000000001361554632000143055ustar00rootroot00000000000000hy-0.18.0/hy/contrib/__init__.py000066400000000000000000000000001361554632000164040ustar00rootroot00000000000000hy-0.18.0/hy/contrib/botsbuildbots.hy000066400000000000000000000010211361554632000175200ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (defn Botsbuildbots [] (Botsbuildbots)) (defmacro Botsbuildbots [] "Build bots, repeatedly.^W^W^WPrint the AUTHORS, forever." `(try (do (import [requests]) (setv 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.18.0/hy/contrib/hy_repr.hy000066400000000000000000000123571361554632000163270ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (import [math [isnan]] re datetime collections [hy._compat [PY36]] [hy.models [HyObject HyExpression HySymbol HyKeyword HyInteger HyFloat HyComplex HyList HyDict HySet HyString HyBytes]]) (try (import [_collections_abc [dict-keys dict-values dict-items]]) (except [ImportError] (defclass C) (setv [dict-keys dict-values dict-items] [C C C]))) (setv -registry {}) (defn hy-repr-register [types f &optional placeholder] (for [typ (if (list? types) types [types])] (setv (get -registry typ) (, f placeholder)))) (setv -quoting False) (setv -seen (set)) (defn hy-repr [obj] (setv [f placeholder] (next (gfor t (. (type obj) __mro__) :if (in t -registry) (get -registry t)) [-base-repr None])) (global -quoting) (setv started-quoting False) (when (and (not -quoting) (instance? HyObject obj) (not (instance? HyKeyword obj))) (setv -quoting True) (setv started-quoting True)) (setv oid (id obj)) (when (in oid -seen) (return (if (none? placeholder) "..." placeholder))) (.add -seen oid) (try (+ (if started-quoting "'" "") (f obj)) (finally (.discard -seen oid) (when started-quoting (setv -quoting False))))) (hy-repr-register tuple (fn [x] (if (hasattr x "_fields") ; It's a named tuple. (We can't use `instance?` or so because ; generated named-tuple classes don't actually inherit from ; collections.namedtuple.) (.format "({} {})" (. (type x) __name__) (.join " " (gfor [k v] (zip x._fields x) (+ ":" k " " (hy-repr v))))) ; Otherwise, print it as a regular tuple. (+ "(," (if x " " "") (-cat x) ")")))) (hy-repr-register dict :placeholder "{...}" (fn [x] (setv text (.join " " (gfor [k v] (.items x) (+ (hy-repr k) " " (hy-repr v))))) (+ "{" text "}"))) (hy-repr-register HyDict :placeholder "{...}" (fn [x] (setv text (.join " " (gfor [k v] (partition x) (+ (hy-repr k) " " (hy-repr v))))) (if (% (len x) 2) (+= text (+ " " (hy-repr (get x -1))))) (+ "{" text "}"))) (hy-repr-register HyExpression (fn [x] (setv syntax { 'quote "'" 'quasiquote "`" 'unquote "~" 'unquote-splice "~@" 'unpack-iterable "#* " 'unpack-mapping "#** "}) (if (and x (symbol? (first x)) (in (first x) syntax)) (+ (get syntax (first x)) (hy-repr (second x))) (+ "(" (-cat x) ")")))) (hy-repr-register [HySymbol HyKeyword] str) (hy-repr-register [str bytes] (fn [x] (setv r (.lstrip (-base-repr x) "ub")) (+ (if (instance? bytes x) "b" "") (if (.startswith "\"" r) ; If Python's built-in repr produced a double-quoted string, use ; that. r ; Otherwise, we have a single-quoted string, which isn't valid Hy, so ; convert it. (+ "\"" (.replace (cut r 1 -1) "\"" "\\\"") "\""))))) (hy-repr-register bool str) (hy-repr-register float (fn [x] (if (isnan x) "NaN" (= x Inf) "Inf" (= x -Inf) "-Inf" (-base-repr x)))) (hy-repr-register complex (fn [x] (.replace (.replace (.strip (-base-repr x) "()") "inf" "Inf") "nan" "NaN"))) (hy-repr-register fraction (fn [x] (.format "{}/{}" (hy-repr x.numerator) (hy-repr x.denominator)))) (setv -matchobject-type (type (re.match "" ""))) (hy-repr-register -matchobject-type (fn [x] (.format "<{}.{} object; :span {} :match {}>" -matchobject-type.__module__ -matchobject-type.__name__ (hy-repr (.span x)) (hy-repr (.group x 0))))) (hy-repr-register datetime.datetime (fn [x] (.format "(datetime.datetime {}{})" (-strftime-0 x "%Y %m %d %H %M %S") (-repr-time-innards x)))) (hy-repr-register datetime.date (fn [x] (-strftime-0 x "(datetime.date %Y %m %d)"))) (hy-repr-register datetime.time (fn [x] (.format "(datetime.time {}{})" (-strftime-0 x "%H %M %S") (-repr-time-innards x)))) (defn -repr-time-innards [x] (.rstrip (+ " " (.join " " (filter identity [ (if x.microsecond (str x.microsecond)) (if (not (none? x.tzinfo)) (+ ":tzinfo " (hy-repr x.tzinfo))) (if (and PY36 (!= x.fold 0)) (+ ":fold " (hy-repr x.fold)))]))))) (defn -strftime-0 [x fmt] ; Remove leading 0s in `strftime`. This is a substitute for the `-` ; flag for when Python isn't built with glibc. (re.sub r"(\A| )0([0-9])" r"\1\2" (.strftime x fmt))) (hy-repr-register collections.Counter (fn [x] (.format "(Counter {})" (hy-repr (dict x))))) (hy-repr-register collections.defaultdict (fn [x] (.format "(defaultdict {} {})" (hy-repr x.default-factory) (hy-repr (dict x))))) (for [[types fmt] (partition [ [list HyList] "[...]" [set HySet] "#{...}" frozenset "(frozenset #{...})" dict-keys "(dict-keys [...])" dict-values "(dict-values [...])" dict-items "(dict-items [...])"])] (defn mkrepr [fmt] (fn [x] (.replace fmt "..." (-cat x) 1))) (hy-repr-register types :placeholder fmt (mkrepr fmt))) (defn -cat [obj] (.join " " (map hy-repr obj))) (defn -base-repr [x] (unless (instance? HyObject x) (return (repr x))) ; Call (.repr x) using the first class of x that doesn't inherit from ; HyObject. (.__repr__ (next (gfor t (. (type x) __mro__) :if (not (issubclass t HyObject)) t)) x)) hy-0.18.0/hy/contrib/loop.hy000066400000000000000000000044431361554632000156250ustar00rootroot00000000000000;;; Hy tail-call optimization ;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;;; The loop/recur macro allows you to construct functions that use tail-call ;;; optimization to allow arbitrary levels of recursion. (import [hy.contrib.walk [prewalk]]) (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 (f #* (.pop accumulated)))) (assoc active 0 False) result))) (defmacro/g! fnr [signature &rest body] (setv new-body (prewalk (fn [x] (if (and (symbol? x) (= x "recur")) g!recur-fn x)) body)) `(do (import [hy.contrib.loop [--trampoline--]]) (with-decorator --trampoline-- (defn ~g!recur-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. (setv 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.18.0/hy/contrib/profile.hy000066400000000000000000000015371361554632000163150ustar00rootroot00000000000000;;; Hy profiling macros ;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;;; These macros make debugging where bottlenecks exist easier. (defmacro profile/calls [&rest body] `(do (import [pycallgraph [PyCallGraph]] [pycallgraph.output [GraphvizOutput]]) (with* [(PyCallGraph :output (GraphvizOutput))] ~@body))) (defmacro/g! profile/cpu [&rest body] " Profile a bit of code " `(do (import cProfile pstats) (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 (pstats.Stats ~g!hy-pr :stream ~g!hy-s))) (.print-stats ~g!hy-ps) (print (.getvalue ~g!hy-s)))) hy-0.18.0/hy/contrib/sequences.hy000066400000000000000000000042101361554632000166370ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (defclass Sequence [] (defn --init-- [self func] "initialize a new sequence with a function to compute values" (setv (. self func) func) (setv (. self cache) []) (setv (. self high-water) -1)) (defn --getitem-- [self n] "get nth item of sequence" (if (hasattr n "start") (gfor x (range n.start n.stop (or n.step 1)) (get self x)) (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)))))) (defn --iter-- [self] "create iterator for this sequence" (setv index 0) (try (while True (yield (get self index)) (setv index (inc index))) (except [IndexError] (return)))) (defn --len-- [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))))) (setv max-items-in-repr 10) (defn --str-- [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)))) (defn --repr-- [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] `(setv ~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.18.0/hy/contrib/walk.hy000066400000000000000000000266161361554632000156200ustar00rootroot00000000000000;;; Hy AST walker ;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (import [hy [HyExpression HyDict]] [hy.models [HySequence]] [functools [partial]] [importlib [import-module]] [collections [OrderedDict]] [hy.macros [macroexpand :as mexpand]] [hy.compiler [HyASTCompiler]]) (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)))] [(or (instance? HySequence form) (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))) ;; TODO: move to hy.core? (defn call? [form] "Checks whether form is a non-empty HyExpression" (and (instance? HyExpression form) form)) (defn macroexpand-all [form &optional module-name] "Recursively performs all possible macroexpansions in form." (setv module (or (and module-name (import-module module-name)) (calling-module)) quote-level 0 ast-compiler (HyASTCompiler module)) ; TODO: make nonlocal after dropping Python2 (defn traverse [form] (walk expand identity form)) (defn expand [form] (nonlocal quote-level) ;; manages quote levels (defn +quote [&optional [x 1]] (nonlocal quote-level) (setv head (first form)) (+= quote-level x) (when (neg? quote-level) (raise (TypeError "unquote outside of quasiquote"))) (setv res (traverse (cut form 1))) (-= quote-level x) `(~head ~@res)) (if (call? form) (cond [quote-level (cond [(in (first form) '[unquote unquote-splice]) (+quote -1)] [(= (first form) 'quasiquote) (+quote)] [True (traverse form)])] [(= (first form) 'quote) form] [(= (first form) 'quasiquote) (+quote)] [(= (first form) (HySymbol "require")) (ast-compiler.compile form) (return)] [True (traverse (mexpand form module ast-compiler))]) (if (coll? form) (traverse form) form))) (expand form)) ;; TODO: move to hy.extra.reserved? (import hy) (setv special-forms (list (.keys hy.compiler._special-form-compilers))) (defn lambda-list [form] " splits a fn argument list into sections based on &-headers. returns an OrderedDict mapping headers to sublists. Arguments without a header are under None. " (setv headers ['&optional '&rest '&kwonly '&kwargs] sections (OrderedDict [(, None [])]) header None) (for [arg form] (if (in arg headers) (do (setv header arg) (assoc sections header []) ;; Don't use a header more than once. It's the compiler's problem. (.remove headers header)) (.append (get sections header) arg))) sections) (defn symbolexpand [form expander &optional [protected (frozenset)] [quote-level 0]] (.expand (SymbolExpander form expander protected quote-level))) (defclass SymbolExpander[] (defn __init__ [self form expander protected quote-level] (setv self.form form self.expander expander self.protected protected self.quote-level quote-level)) (defn expand-symbols [self form &optional protected quote-level] (if (none? protected) (setv protected self.protected)) (if (none? quote-level) (setv quote-level self.quote-level)) (symbolexpand form self.expander protected quote-level)) (defn traverse [self form &optional protected quote-level] (if (none? protected) (setv protected self.protected)) (if (none? quote-level) (setv quote-level self.quote-level)) (walk (partial symbolexpand :expander self.expander :protected protected :quote-level quote-level) identity form)) ;; manages quote levels (defn +quote [self &optional [x 1]] `(~(self.head) ~@(self.traverse (self.tail) :quote-level (+ self.quote-level x)))) (defn handle-dot [self] `(. ~(self.expand-symbols (first (self.tail))) ~@(walk (fn [form] (if (symbol? form) form ; don't expand attrs (self.expand-symbols form))) identity (cut (self.tail) 1)))) (defn head [self] (first self.form)) (defn tail [self] (cut self.form 1)) (defn handle-except [self] (setv tail (self.tail)) ;; protect the "as" name binding the exception `(~(self.head) ~@(self.traverse tail (| self.protected (if (and tail (-> tail first len (= 2))) #{(first (first tail))} #{}))))) (defn handle-args-list [self] (setv protected #{} argslist []) (for [[header section] (-> self (.tail) first lambda-list .items)] (if header (.append argslist header)) (cond [(in header [None '&rest '&kwargs]) (.update protected section) (.extend argslist section)] [(in header '[&optional &kwonly]) (for [pair section] (cond [(coll? pair) (.add protected (first pair)) (.append argslist `[~(first pair) ~(self.expand-symbols (second pair))])] [True (.add protected pair) (.append argslist pair)]))])) (, protected argslist)) (defn handle-fn [self] (setv [protected argslist] (self.handle-args-list)) `(~(self.head) ~argslist ~@(self.traverse (cut (self.tail) 1)(| protected self.protected)))) ;; don't expand symbols in quotations (defn handle-quoted [self] (if (call? self.form) (if (in (self.head) '[unquote unquote-splice]) (self.+quote -1) (= (self.head) 'quasiquote) (self.+quote) (self.handle-coll)) (if (coll? self.form) (self.handle-coll) (self.handle-base)))) ;; convert dotted names to the standard special form (defn convert-dotted-symbol [self] (self.expand-symbols `(. ~@(map HySymbol (.split self.form '.))))) (defn expand-symbol [self] (if (not-in self.form self.protected) (self.expander self.form) (self.handle-base))) (defn handle-symbol [self] (if (and self.form (not (.startswith self.form '.)) (in '. self.form)) (self.convert-dotted-symbol) (self.expand-symbol))) (defn handle-global [self] (.update self.protected (set (self.tail))) (self.handle-base)) (defn handle-defclass [self] ;; don't expand the name of the class `(~(self.head) ~(first (self.tail)) ~@(self.traverse (cut (self.tail) 1)))) (defn handle-special-form [self] ;; don't expand other special form symbols in head position `(~(self.head) ~@(self.traverse (self.tail)))) (defn handle-base [self] self.form) (defn handle-coll [self] ;; recursion (self.traverse self.form)) ;; We have to treat special forms differently. ;; Quotation should suppress symbol expansion, ;; and local bindings should shadow those made by let. (defn handle-call [self] (setv head (first self.form)) (if (in head '[fn fn*]) (self.handle-fn) (in head '[import require quote eval-and-compile eval-when-compile]) (self.handle-base) (= head 'except) (self.handle-except) (= head ".") (self.handle-dot) (= head 'defclass) (self.handle-defclass) (= head 'quasiquote) (self.+quote) ;; must be checked last! (in (mangle head) special-forms) (self.handle-special-form) ;; Not a special form. Traverse it like a coll (self.handle-coll))) (defn expand [self] "the main entry point. Call this to do the expansion" (setv form self.form) (if self.quote-level (self.handle-quoted) (symbol? form) (self.handle-symbol) (call? form) (self.handle-call) (coll? form) (self.handle-coll) ;; recursive base case--it's an atom. Put it back. (self.handle-base)))) (defmacro smacrolet [bindings &optional module-name &rest body] " symbol macro let. Replaces symbols in body, but only where it would be a valid let binding. The bindings pairs the target symbol and the expansion form for that symbol. " (if (odd? (len bindings)) (macro-error bindings "bindings must be paired")) (for [k (cut bindings None None 2)] (if-not (symbol? k) (macro-error k "bind targets must be symbols") (if (in '. k) (macro-error k "binding target may not contain a dot")))) (setv bindings (dict (partition bindings)) body (macroexpand-all body (or module-name (calling-module-name)))) (symbolexpand `(do ~@body) (fn [symbol] (.get bindings symbol symbol)))) (defmacro let [bindings &rest body] " sets up lexical bindings in its body Bindings are processed sequentially, so you can use the result of an earlier binding in a later one. Basic assignments (e.g. setv, +=) will update the let binding, if they use the name of a let binding. But assignments via `import` are always hoisted to normal Python scope, and likewise, `defclass` will assign the class to the Python scope, even if it shares the name of a let binding. Use `import_module` and `type` (or whatever metaclass) instead, if you must avoid this hoisting. Function arguments can shadow let bindings in their body, as can nested let forms. " (if (odd? (len bindings)) (macro-error bindings "let bindings must be paired")) (setv g!let (gensym 'let) replacements (OrderedDict) keys [] values []) (defn expander [symbol] (.get replacements symbol symbol)) (for [[k v] (partition bindings)] (if-not (symbol? k) (macro-error k "bind targets must be symbols") (if (in '. k) (macro-error k "binding target may not contain a dot"))) (.append values (symbolexpand (macroexpand-all v &name) expander)) (.append keys `(get ~g!let ~(name k))) (assoc replacements k (last keys))) `(do (setv ~g!let {} ~@(interleave keys values)) ~@(symbolexpand (macroexpand-all body &name) expander))) ;; (defmacro macrolet []) hy-0.18.0/hy/core/000077500000000000000000000000001361554632000135755ustar00rootroot00000000000000hy-0.18.0/hy/core/__init__.py000066400000000000000000000000721361554632000157050ustar00rootroot00000000000000STDLIB = [ "hy.core.language", "hy.core.shadow" ] hy-0.18.0/hy/core/bootstrap.hy000066400000000000000000000056211361554632000161600ustar00rootroot00000000000000;;; Hy bootstrap macros ;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;;; These macros are the essential hy macros. ;;; They are automatically required everywhere, even inside hy.core modules. (eval-and-compile (import hy) ((hy.macros.macro "defmacro") (fn [&name macro-name lambda-list &rest body] "the defmacro macro" (if* (not (isinstance macro-name hy.models.HySymbol)) (raise (hy.errors.HyTypeError (% "received a `%s' instead of a symbol for macro name" (. (type name) __name__)) None --file-- None))) (for [kw '[&kwonly &kwargs]] (if* (in kw lambda-list) (raise (hy.errors.HyTypeError (% "macros cannot use %s" kw) macro-name --file-- None)))) ;; this looks familiar... `(eval-and-compile (import hy) ((hy.macros.macro ~(str macro-name)) (fn ~(+ `[&name] lambda-list) ~@body)))))) (defmacro if [&rest args] "Conditionally evaluate alternating test and then expressions." (setv n (len args)) (if* n (if* (= n 1) (get args 0) `(if* ~(get args 0) ~(get args 1) (if ~@(cut args 2)))))) (defmacro deftag [tag-name lambda-list &rest body] (import hy.models) (if (and (not (isinstance tag-name hy.models.HySymbol)) (not (isinstance tag-name hy.models.HyString))) (raise (hy.errors.HyTypeError (% "received a `%s' instead of a symbol for tag macro name" (. (type tag-name) --name--)) tag-name --file-- None))) (if (or (= tag-name ":") (= tag-name "&")) (raise (hy.errors.HyNameError (% "%s can't be used as a tag macro name" tag-name)))) (setv tag-name (.replace (hy.models.HyString tag-name) tag-name)) `(eval-and-compile (import hy) ((hy.macros.tag ~tag-name) (fn ~lambda-list ~@body)))) (defmacro macro-error [expression reason &optional [filename '--name--]] `(raise (hy.errors.HyMacroExpansionError ~reason ~filename ~expression None))) (defmacro defn [name &rest args] "Define `name` as a function with `args` as the signature, annotations, and body." (import hy) (if (not (= (type name) hy.HySymbol)) (macro-error name "defn takes a name as first argument")) `(setv ~name (fn* ~@args))) (defmacro defn/a [name lambda-list &rest body] "Define `name` as a function with `lambda-list` signature and body `body`." (import hy) (if (not (= (type name) hy.HySymbol)) (macro-error name "defn/a takes a name as first argument")) (if (not (isinstance lambda-list hy.HyList)) (macro-error name "defn/a takes a parameter list as second argument")) `(setv ~name (fn/a ~lambda-list ~@body))) hy-0.18.0/hy/core/language.hy000066400000000000000000000267221361554632000157330ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;;;; This contains some of the core Hy functions used ;;;; to make functional programming slightly easier. ;;;; (import itertools) (import functools) (import [fractions [Fraction :as fraction]]) (import operator) ; shadow not available yet (import sys) (import [collections.abc :as cabc]) (import [hy.models [HySymbol HyKeyword]]) (import [hy.lex [tokenize mangle unmangle read read-str]]) (import [hy.lex.exceptions [LexException PrematureEndOfInput]]) (import [hy.compiler [HyASTCompiler calling-module hy-eval :as eval]]) (import [hy.core.shadow [*]]) (require [hy.core.bootstrap [*]]) (defn butlast [coll] "Return an iterator of all but the last item in `coll`." (drop-last 1 coll)) (defn coll? [coll] "Check if `coll` is iterable and not a string." (and (iterable? coll) (not (string? coll)))) (defn comp [&rest fs] "Return the function from composing the given functions `fs`." (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 (first-f #* args #** kwargs)) (for [f fs] (setv res (f res))) res)))) (defn complement [f] "Returns a new function that returns the logically inverted result of `f`." (fn [&rest args &kwargs kwargs] (not (f #* args #** kwargs)))) (defn constantly [value] "Create a new function that always returns `value` regardless of its input." (fn [&rest args &kwargs kwargs] value)) (defn keyword? [k] "Check whether `k` is a keyword." (instance? HyKeyword k)) (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 `codegen` is true, generate python code instead." (import astor) (import hy.compiler) (setv compiled (hy.compiler.hy-compile tree (calling-module-name))) ((if codegen astor.code-gen.to-source astor.dump-tree) compiled)) (defn distinct [coll] "Return a generator from the original collection `coll` with no duplicates." (setv seen (set) citer (iter coll)) (for [val citer] (if (not-in val seen) (do (yield val) (.add seen val))))) (setv remove itertools.filterfalse zip-longest itertools.zip_longest ;; was builtin in Python2 reduce functools.reduce accumulate itertools.accumulate) ;; infinite iterators (setv count itertools.count cycle itertools.cycle repeat itertools.repeat) ;; shortest-terminating iterators (setv *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 (setv combinations itertools.combinations multicombinations itertools.combinations_with_replacement permutations itertools.permutations product itertools.product) (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`." (setv iters (tee coll)) (map first (zip #* [(get iters 0) (drop n (get iters 1))]))) (defn empty? [coll] "Check if `coll` is empty." (= 0 (len coll))) (defn even? [n] "Check if `n` is an even number." (= (% n 2) 0)) (defn every? [pred coll] "Check if `pred` is true applied to every x in `coll`." (all (map pred coll))) (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] "Check if x is float." (isinstance x float)) (defn list? [x] (isinstance x list)) (defn tuple? [x] (isinstance x tuple)) (defn symbol? [s] "Check if `s` is a symbol." (instance? HySymbol s)) (import [threading [Lock]]) (setv _gensym_counter 0) (setv _gensym_lock (Lock)) (defn gensym [&optional [g "G"]] "Generate a unique symbol for use in macros without accidental name clashes." (setv 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 "_{}\uffff{}" 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] "Return `x`." x) (defn inc [n] "Increment `n` by 1." (+ n 1)) (defn instance? [klass x] "Perform `isinstance` with reversed arguments." (isinstance x klass)) (defn integer? [x] "Check if `x` is an integer." (isinstance x int)) (defn integer-char? [x] "Check 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 (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] "Check if `x` is an iterable." (isinstance x cabc.Iterable)) (defn iterate [f x] "Returns an iterator repeatedly applying `f` to seed `x`.. x, f(x), f(f(x))..." (setv val x) (while True (yield val) (setv val (f val)))) (defn iterator? [x] "Check if `x` is an iterator." (isinstance x cabc.Iterator)) (defn juxt [f &rest fs] "Return a function applying each `fs` to args, collecting results in a list." (setv fs (+ (, f) fs)) (fn [&rest args &kwargs kwargs] (lfor f fs (f #* args #** kwargs)))) (defn last [coll] "Return last item from `coll`." (get (tuple coll) -1)) (defn macroexpand [form] "Return the full macro expansion of `form`." (import hy.macros) (setv module (calling-module)) (hy.macros.macroexpand form module (HyASTCompiler module))) (defn macroexpand-1 [form] "Return the single step macro expansion of `form`." (import hy.macros) (setv module (calling-module)) (hy.macros.macroexpand-1 form module (HyASTCompiler module))) (defn merge-with [f &rest maps] "Return the map of `maps` joined onto the first via the function `f`. 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) (do (defn merge-entry [m e] (setv k (get e 0) v (get e 1)) (setv (get m k) (if (in k m) (f (get m k) v) v)) m) (defn merge2 [m1 m2] (reduce merge-entry (.items m2) (or m1 {}))) (reduce merge2 maps)))) (defn neg? [n] "Check if `n` is < 0." (< n 0)) (defn none? [x] "Check if `x` is None" (is x None)) (defn numeric? [x] "Check if `x` is an instance of numbers.Number." (import numbers) (instance? numbers.Number x)) (defn nth [coll n &optional [default None]] "Return `n`th item in `coll` or None (specify `default`) if out of bounds." (next (drop n coll) default)) (defn odd? [n] "Check if `n` is an odd number." (= (% n 2) 1)) (setv -sentinel (object)) (defn partition [coll &optional [n 2] step [fillvalue -sentinel]] "Chunk `coll` into `n`-tuples (pairs by default). The remainder, if any, is not included unless `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) coll-clones (tee coll n) slices (gfor start (range n) (islice (get coll-clones start) start None step))) (if (is fillvalue -sentinel) (zip #* slices) (zip-longest #* slices :fillvalue fillvalue))) (defn pos? [n] "Check if `n` is > 0." (> n 0)) (defn rest [coll] "Get all the elements of `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 applying `pred` in `coll`, else None." (first (filter None (map pred coll)))) (defn string? [x] "Check if `x` is a string." (isinstance x str)) (defn take [count coll] "Take `count` elements from `coll`." (islice coll None count)) (defn take-nth [n coll] "Return every `n`th member of `coll`. Raises ValueError for (not (pos? n))." (if (not (pos? n)) (raise (ValueError "n must be positive"))) (setv citer (iter coll) skip (dec n)) (for [val citer] (yield val) (for [_ (range skip)] (try (next citer) (except [StopIteration] (return)))))) (defn zero? [n] "Check if `n` equals 0." (= n 0)) (defn keyword [value] "Create a keyword from `value`. Strings numbers and even objects with the __name__ magic will work." (if (keyword? value) (HyKeyword (unmangle value.name)) (if (string? value) (HyKeyword (unmangle value)) (try (unmangle (.__name__ value)) (except [] (HyKeyword (str value))))))) (defn name [value] "Convert `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 (keyword? value) (unmangle (cut (str value) 1)) (if (string? value) (unmangle value) (try (unmangle (. value __name__)) (except [] (str value)))))) (defn xor [a b] "Perform exclusive or between `a` and `b`." (if (and a b) False (or a b))) (defn parse-args [spec &optional args &kwargs parser-args] "Return arguments namespace parsed from `args` or `sys.argv` with `argparse.ArgumentParser.parse-args` according to `spec`. `spec` should be a list of arguments to pass to repeated calls to `argparse.ArgumentParser.add-argument`. `parser-args` may be a list of keyword arguments to pass to the `argparse.ArgumentParser` constructor." (import argparse) (setv parser (argparse.ArgumentParser #** parser-args)) (for [arg spec] (eval `(.add-argument parser ~@arg))) (.parse-args parser args)) (setv EXPORTS '[*map accumulate butlast calling-module calling-module-name chain coll? combinations comp complement compress constantly count cycle dec distinct disassemble drop drop-last drop-while empty? eval even? every? first flatten float? fraction gensym group-by identity inc instance? integer? integer-char? interleave interpose islice iterable? iterate iterator? juxt keyword keyword? last list? macroexpand macroexpand-1 mangle merge-with multicombinations name neg? none? nth numeric? odd? parse-args partition permutations pos? product read read-str remove repeat repeatedly rest reduce second some string? symbol? take take-nth take-while tuple? unmangle xor tee zero? zip-longest]) hy-0.18.0/hy/core/macros.hy000066400000000000000000000176241361554632000154350ustar00rootroot00000000000000;;; Hy core macros ;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;;; These macros form the hy language ;;; They are automatically required in every module, except inside hy.core (import [hy.models [HyList HySymbol]]) (eval-and-compile (import [hy.core.language [*]])) (require [hy.core.bootstrap [*]]) (defmacro as-> [head name &rest rest] "Beginning with `head`, expand a sequence of assignments `rest` to `name`. Each assignment is passed to the subsequent form. Returns the final assignment, leaving the name bound to it in the local scope. This behaves similarly to other threading macros, but requires specifying the threading point per-form via the name, rather than fixing to the first or last argument." `(do (setv ~name ~head ~@(interleave (repeat name) rest)) ~name)) (defmacro assoc [coll k1 v1 &rest other-kvs] "Associate key/index value pair(s) to a collection `coll` like a dict or list. If more than three parameters are given, the remaining args are k/v pairs to be associated in pairs." (if (odd? (len other-kvs)) (macro-error (last other-kvs) "`assoc` takes an odd number of arguments")) (setv c (if other-kvs (gensym "c") coll)) `(setv ~@(+ (if other-kvs [c coll] []) #* (gfor [k v] (partition (+ (, k1 v1) other-kvs)) [`(get ~c ~k) v])))) (defn _with [node args body] (if (not args) `(do ~@body) (<= (len args) 2) `(~node [~@args] ~@body) True (do (setv [p1 p2 #* args] args) `(~node [~p1 ~p2] ~(_with node args body))))) (defmacro with [args &rest body] "Wrap execution of `body` within a context manager given as bracket `args`. Shorthand for nested with* loops: (with [x foo y bar] baz) -> (with* [x foo] (with* [y bar] baz))." (_with 'with* args body)) (defmacro with/a [args &rest body] "Wrap execution of `body` with/ain a context manager given as bracket `args`. Shorthand for nested with/a* loops: (with/a [x foo y bar] baz) -> (with/a* [x foo] (with/a* [y bar] baz))." (_with 'with/a* args body)) (defmacro cond [&rest branches] "Build a nested if clause with each `branch` a [cond result] bracket pair. The result in the bracket may be omitted, in which case the condition is also used as the result." (or branches (return)) `(if ~@(reduce + (gfor branch branches (if (not (and (is (type branch) hy.HyList) branch)) (macro-error branch "each cond branch needs to be a nonempty list") (= (len branch) 1) (do (setv g (gensym)) [`(do (setv ~g ~(first branch)) ~g) g]) True [(first branch) `(do ~@(cut branch 1))]))))) (defmacro -> [head &rest args] "Thread `head` first through the `rest` of the forms. The result of the first threaded form is inserted into the first position of the second form, the second result is inserted into the third form, and so on." (setv ret head) (for [node args] (setv ret (if (isinstance node HyExpression) `(~(first node) ~ret ~@(rest node)) `(~node ~ret)))) ret) (defmacro doto [form &rest expressions] "Perform possibly mutating `expressions` on `form`, returning resulting obj." (setv f (gensym)) (defn build-form [expression] (if (isinstance expression HyExpression) `(~(first expression) ~f ~@(rest expression)) `(~expression ~f))) `(do (setv ~f ~form) ~@(map build-form expressions) ~f)) (defmacro ->> [head &rest args] "Thread `head` last through the `rest` of the forms. The result of the first threaded form is inserted into the last position of the second form, the second result is inserted into the third form, and so on." (setv ret head) (for [node args] (setv ret (if (isinstance node HyExpression) `(~@node ~ret) `(~node ~ret)))) ret) (defmacro of [base &rest args] "Shorthand for indexing for type annotations. If only one arguments are given, this expands to just that argument. If two arguments are given, it expands to indexing the first argument via the second. Otherwise, the first argument is indexed using a tuple of the rest. E.g. `(of List int)` -> `List[int]`, `(of Dict str str)` -> `Dict[str, str]`." (if (empty? args) base (= (len args) 1) `(get ~base ~@args) `(get ~base (, ~@args)))) (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] "Execute `body` with `args` as bracket of names to gensym for use in macros." (setv syms []) (for [arg args] (.extend syms [arg `(gensym '~arg)])) `(do (setv ~@syms) ~@body)) (defmacro defmacro/g! [name args &rest body] "Like `defmacro`, but symbols prefixed with 'g!' are gensymed." (setv 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] (setv ~@gensyms) ~@body)) (defmacro defmacro! [name args &rest body] "Like `defmacro/g!`, with automatic once-only evaluation for 'o!' params. Such 'o!' params are available within `body` as the equivalent 'g!' symbol." (defn extract-o!-sym [arg] (cond [(and (symbol? arg) (.startswith arg "o!")) arg] [(and (instance? HyList arg) (.startswith (first arg) "o!")) (first arg)])) (setv os (list (filter identity (map extract-o!-sym args))) gs (lfor s os (HySymbol (+ "g!" (cut s 2))))) `(defmacro/g! ~name ~args `(do (setv ~@(interleave ~gs ~os)) ~@~body))) (defmacro defmain [args &rest body] "Write a function named \"main\" and do the 'if __main__' dance. The symbols in `args` are bound to the elements in `sys.argv`, which means that the first symbol in `args` will always take the value of the script/executable name (i.e. `sys.argv[0]`). " (setv retval (gensym) restval (gensym)) `(when (= --name-- "__main__") (import sys) (setv ~retval ((fn [~@(or args `[&rest ~restval])] ~@body) #* sys.argv)) (if (integer? ~retval) (sys.exit ~retval)))) (deftag @ [expr] "with-decorator tag macro" (if (empty? expr) (macro-error expr "missing function argument")) (setv decorators (cut expr None -1) fndef (get expr -1)) `(with-decorator ~@decorators ~fndef)) (defmacro comment [&rest body] "Ignores body and always expands to None" None) (defmacro doc [symbol] "macro documentation Gets help for a macro function available in this module. Use ``require`` to make other macros available. Use ``#doc foo`` instead for help with tag macro ``#foo``. Use ``(help foo)`` instead for help with runtime objects." `(help (.get __macros__ '~symbol None))) (deftag doc [symbol] "tag macro documentation Gets help for a tag macro function available in this module." `(help (.get __tags__ '~symbol None))) hy-0.18.0/hy/core/shadow.hy000066400000000000000000000114011361554632000154210ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;;;; Hy shadow functions (import operator) (require [hy.core.bootstrap [*]]) (import [functools [reduce]]) (defn + [&rest args] "Shadowed `+` operator adds `args`." (if (= (len args) 0) 0 (= (len args) 1) (+ (get args 0)) ; else (reduce operator.add args))) (defn - [a1 &rest a-rest] "Shadowed `-` operator subtracts each `a-rest` from `a1`." (if a-rest (reduce operator.sub a-rest a1) (- a1))) (defn * [&rest args] "Shadowed `*` operator multiplies `args`." (if (= (len args) 0) 1 (= (len args) 1) (get args 0) ; else (reduce operator.mul args))) (defn ** [a1 a2 &rest a-rest] "Shadowed `**` operator takes `a1` to the power of `a2`, ..., `a-rest`." ; We use `-foldr` instead of `reduce` because exponentiation ; is right-associative. (-foldr operator.pow (+ (, a1 a2) a-rest))) (defn -foldr [f xs] (reduce (fn [x y] (f y x)) (cut xs None None -1))) (defn / [a1 &rest a-rest] "Shadowed `/` operator divides `a1` by each `a-rest`." (if a-rest (reduce operator.truediv a-rest a1) (/ 1 a1))) (defn // [a1 a2 &rest a-rest] "Shadowed `//` operator floor divides `a1` by `a2`, ..., `a-rest`." (reduce operator.floordiv (+ (, a2) a-rest) a1)) (defn % [x y] "Shadowed `%` operator takes `x` modulo `y`." (% x y)) (defn @ [a1 &rest a-rest] "Shadowed `@` operator matrix multiples `a1` by each `a-rest`." (reduce operator.matmul a-rest a1)) (defn << [a1 a2 &rest a-rest] "Shadowed `<<` operator performs left-shift on `a1` by `a2`, ..., `a-rest`." (reduce operator.lshift (+ (, a2) a-rest) a1)) (defn >> [a1 a2 &rest a-rest] "Shadowed `>>` operator performs right-shift on `a1` by `a2`, ..., `a-rest`." (reduce operator.rshift (+ (, a2) a-rest) a1)) (defn & [a1 &rest a-rest] "Shadowed `&` operator performs bitwise-and on `a1` by each `a-rest`." (if a-rest (reduce operator.and_ a-rest a1) a1)) (defn | [&rest args] "Shadowed `|` operator performs bitwise-or on `a1` by each `a-rest`." (if (= (len args) 0) 0 (= (len args) 1) (get args 0) ; else (reduce operator.or_ args))) (defn ^ [x y] "Shadowed `^` operator performs bitwise-xor on `x` and `y`." (^ x y)) (defn ~ [x] "Shadowed `~` operator performs bitwise-negation on `x`." (~ x)) (defn comp-op [op a1 a-rest] "Helper for shadow comparison operators" (if a-rest (and #* (gfor (, x y) (zip (+ (, a1) a-rest) a-rest) (op x y))) True)) (defn < [a1 &rest a-rest] "Shadowed `<` operator perform lt comparison on `a1` by each `a-rest`." (comp-op operator.lt a1 a-rest)) (defn <= [a1 &rest a-rest] "Shadowed `<=` operator perform le comparison on `a1` by each `a-rest`." (comp-op operator.le a1 a-rest)) (defn = [a1 &rest a-rest] "Shadowed `=` operator perform eq comparison on `a1` by each `a-rest`." (comp-op operator.eq a1 a-rest)) (defn is [a1 &rest a-rest] "Shadowed `is` keyword perform is on `a1` by each `a-rest`." (comp-op operator.is_ a1 a-rest)) (defn != [a1 a2 &rest a-rest] "Shadowed `!=` operator perform neq comparison on `a1` by `a2`, ..., `a-rest`." (comp-op operator.ne a1 (+ (, a2) a-rest))) (defn is-not [a1 a2 &rest a-rest] "Shadowed `is-not` keyword perform is-not on `a1` by `a2`, ..., `a-rest`." (comp-op operator.is-not a1 (+ (, a2) a-rest))) (defn in [a1 a2 &rest a-rest] "Shadowed `in` keyword perform `a1` in `a2` in …." (comp-op (fn [x y] (in x y)) a1 (+ (, a2) a-rest))) (defn not-in [a1 a2 &rest a-rest] "Shadowed `not in` keyword perform `a1` not in `a2` not in…." (comp-op (fn [x y] (not-in x y)) a1 (+ (, a2) a-rest))) (defn >= [a1 &rest a-rest] "Shadowed `>=` operator perform ge comparison on `a1` by each `a-rest`." (comp-op operator.ge a1 a-rest)) (defn > [a1 &rest a-rest] "Shadowed `>` operator perform gt comparison on `a1` by each `a-rest`." (comp-op operator.gt a1 a-rest)) (defn and [&rest args] "Shadowed `and` keyword perform and on `args`." (if (= (len args) 0) True (= (len args) 1) (get args 0) ; else (reduce (fn [x y] (and x y)) args))) (defn or [&rest args] "Shadowed `or` keyword perform or on `args`." (if (= (len args) 0) None (= (len args) 1) (get args 0) ; else (reduce (fn [x y] (or x y)) args))) (defn not [x] "Shadowed `not` keyword perform not on `x`." (not x)) (defn get [coll key1 &rest keys] "Access item in `coll` indexed by `key1`, with optional `keys` nested-access." (setv coll (get coll key1)) (for [k keys] (setv coll (get coll k))) coll) (setv EXPORTS [ '+ '- '* '** '/ '// '% '@ '<< '>> '& '| '^ '~ '< '> '<= '>= '= '!= 'and 'or 'not 'is 'is-not 'in 'not-in 'get]) hy-0.18.0/hy/errors.py000066400000000000000000000250221361554632000145340ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import os import re import sys import traceback import pkgutil from functools import reduce from colorama import Fore from contextlib import contextmanager from hy import _initialize_env_var _hy_filter_internal_errors = _initialize_env_var('HY_FILTER_INTERNAL_ERRORS', True) COLORED = _initialize_env_var('HY_COLORED_ERRORS', False) class HyError(Exception): pass class HyInternalError(HyError): """Unexpected errors occurring during compilation or parsing of Hy code. Errors sub-classing this are not intended to be user-facing, and will, hopefully, never be seen by users! """ class HyLanguageError(HyError): """Errors caused by invalid use of the Hy language. This, and any errors inheriting from this, are user-facing. """ def __init__(self, message, expression=None, filename=None, source=None, lineno=1, colno=1): """ Parameters ---------- message: str The message to display for this error. expression: HyObject, optional The Hy expression generating this error. filename: str, optional The filename for the source code generating this error. Expression-provided information will take precedence of this value. source: str, optional The actual source code generating this error. Expression-provided information will take precedence of this value. lineno: int, optional The line number of the error. Expression-provided information will take precedence of this value. colno: int, optional The column number of the error. Expression-provided information will take precedence of this value. """ self.msg = message self.compute_lineinfo(expression, filename, source, lineno, colno) if isinstance(self, SyntaxError): syntax_error_args = (self.filename, self.lineno, self.offset, self.text) super(HyLanguageError, self).__init__(message, syntax_error_args) else: super(HyLanguageError, self).__init__(message) def compute_lineinfo(self, expression, filename, source, lineno, colno): # NOTE: We use `SyntaxError`'s field names (i.e. `text`, `offset`, # `msg`) for compatibility and print-outs. self.text = getattr(expression, 'source', source) self.filename = getattr(expression, 'filename', filename) if self.text: lines = self.text.splitlines() self.lineno = getattr(expression, 'start_line', lineno) self.offset = getattr(expression, 'start_column', colno) end_column = getattr(expression, 'end_column', len(lines[self.lineno-1])) end_line = getattr(expression, 'end_line', self.lineno) # Trim the source down to the essentials. self.text = '\n'.join(lines[self.lineno-1:end_line]) if end_column: if self.lineno == end_line: self.arrow_offset = end_column else: self.arrow_offset = len(self.text[0]) self.arrow_offset -= self.offset else: self.arrow_offset = None else: # We could attempt to extract the source given a filename, but we # don't. self.lineno = lineno self.offset = colno self.arrow_offset = None def __str__(self): """Provide an exception message that includes SyntaxError-like source line information when available. """ # Syntax errors are special and annotate the traceback (instead of what # we would do in the message that follows the traceback). if isinstance(self, SyntaxError): return super(HyLanguageError, self).__str__() # When there isn't extra source information, use the normal message. elif not self.text: return super(HyLanguageError, self).__str__() # Re-purpose Python's builtin syntax error formatting. output = traceback.format_exception_only( SyntaxError, SyntaxError(self.msg, (self.filename, self.lineno, self.offset, self.text))) arrow_idx, _ = next(((i, x) for i, x in enumerate(output) if x.strip() == '^'), (None, None)) if arrow_idx: msg_idx = arrow_idx + 1 else: msg_idx, _ = next((i, x) for i, x in enumerate(output) if x.startswith('SyntaxError: ')) # Get rid of erroneous error-type label. output[msg_idx] = re.sub('^SyntaxError: ', '', output[msg_idx]) # Extend the text arrow, when given enough source info. if arrow_idx and self.arrow_offset: output[arrow_idx] = '{}{}^\n'.format(output[arrow_idx].rstrip('\n'), '-' * (self.arrow_offset - 1)) if COLORED: output[msg_idx:] = [Fore.YELLOW + o + Fore.RESET for o in output[msg_idx:]] if arrow_idx: output[arrow_idx] = Fore.GREEN + output[arrow_idx] + Fore.RESET for idx, line in enumerate(output[::msg_idx]): if line.strip().startswith( 'File "{}", line'.format(self.filename)): output[idx] = Fore.RED + line + Fore.RESET # This resulting string will come after a ":" prompt, so # put it down a line. output.insert(0, '\n') # Avoid "...expected str instance, ColoredString found" return reduce(lambda x, y: x + y, output) class HyCompileError(HyInternalError): """Unexpected errors occurring within the compiler.""" class HyTypeError(HyLanguageError, TypeError): """TypeError occurring during the normal use of Hy.""" class HyNameError(HyLanguageError, NameError): """NameError occurring during the normal use of Hy.""" class HyRequireError(HyLanguageError): """Errors arising during the use of `require` This, and any errors inheriting from this, are user-facing. """ class HyMacroExpansionError(HyLanguageError): """Errors caused by invalid use of Hy macros. This, and any errors inheriting from this, are user-facing. """ class HyEvalError(HyLanguageError): """Errors occurring during code evaluation at compile-time. These errors distinguish unexpected errors within the compilation process (i.e. `HyInternalError`s) from unrelated errors in user code evaluated by the compiler (e.g. in `eval-and-compile`). This, and any errors inheriting from this, are user-facing. """ class HyIOError(HyInternalError, IOError): """ Subclass used to distinguish between IOErrors raised by Hy itself as opposed to Hy programs. """ class HySyntaxError(HyLanguageError, SyntaxError): """Error during the Lexing of a Hython expression.""" class HyWrapperError(HyError, TypeError): """Errors caused by language model object wrapping. These can be caused by improper user-level use of a macro, so they're not really "internal". If they arise due to anything else, they're an internal/compiler problem, though. """ def _module_filter_name(module_name): try: compiler_loader = pkgutil.get_loader(module_name) if not compiler_loader: return None filename = compiler_loader.get_filename(module_name) if not filename: return None if compiler_loader.is_package(module_name): # Use the package directory (e.g. instead of `.../__init__.py`) so # that we can filter all modules in a package. return os.path.dirname(filename) else: # Normalize filename endings, because tracebacks will use `pyc` when # the loader says `py`. return filename.replace('.pyc', '.py') except Exception: return None _tb_hidden_modules = {m for m in map(_module_filter_name, ['hy.compiler', 'hy.lex', 'hy.cmdline', 'hy.lex.parser', 'hy.importer', 'hy._compat', 'hy.macros', 'hy.models', 'rply']) if m is not None} def hy_exc_filter(exc_type, exc_value, exc_traceback): """Produce exceptions print-outs with all frames originating from the modules in `_tb_hidden_modules` filtered out. The frames are actually filtered by each module's filename and only when a subclass of `HyLanguageError` is emitted. This does not remove the frames from the actual tracebacks, so debugging will show everything. """ # frame = (filename, line number, function name*, text) new_tb = [] for frame in traceback.extract_tb(exc_traceback): if not (frame[0].replace('.pyc', '.py') in _tb_hidden_modules or os.path.dirname(frame[0]) in _tb_hidden_modules): new_tb += [frame] lines = traceback.format_list(new_tb) lines.insert(0, "Traceback (most recent call last):\n") lines.extend(traceback.format_exception_only(exc_type, exc_value)) output = ''.join(lines) return output def hy_exc_handler(exc_type, exc_value, exc_traceback): """A `sys.excepthook` handler that uses `hy_exc_filter` to remove internal Hy frames from a traceback print-out. """ if os.environ.get('HY_DEBUG', False): return sys.__excepthook__(exc_type, exc_value, exc_traceback) try: output = hy_exc_filter(exc_type, exc_value, exc_traceback) sys.stderr.write(output) sys.stderr.flush() except Exception: sys.__excepthook__(exc_type, exc_value, exc_traceback) @contextmanager def filtered_hy_exceptions(): """Temporarily apply a `sys.excepthook` that filters Hy internal frames from tracebacks. Filtering can be controlled by the variable `hy.errors._hy_filter_internal_errors` and environment variable `HY_FILTER_INTERNAL_ERRORS`. """ global _hy_filter_internal_errors if _hy_filter_internal_errors: current_hook = sys.excepthook sys.excepthook = hy_exc_handler yield sys.excepthook = current_hook else: yield hy-0.18.0/hy/extra/000077500000000000000000000000001361554632000137705ustar00rootroot00000000000000hy-0.18.0/hy/extra/__init__.py000066400000000000000000000000001361554632000160670ustar00rootroot00000000000000hy-0.18.0/hy/extra/anaphoric.hy000066400000000000000000000053241361554632000163020ustar00rootroot00000000000000;;; Hy anaphoric macros ;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;;; These macros make writing functional programs more concise (defmacro ap-if [test-form then-form &optional else-form] (rit `(do (setv it ~test-form) (if it ~then-form ~else-form)))) (defmacro ap-each [xs &rest body] (rit `(for [it ~xs] ~@body))) (defmacro ap-each-while [xs form &rest body] (rit `(for [it ~xs] (unless ~form (break)) ~@body))) (defmacro ap-map [form xs] (rit `(gfor it ~xs ~form))) (defmacro ap-map-when [predfn rep xs] (rit `(gfor it ~xs (if (~predfn it) ~rep it)))) (defmacro ap-filter [form xs] (rit `(gfor it ~xs :if ~form it))) (defmacro ap-reject [form xs] (rit `(gfor it ~xs :if (not ~form) it))) (defmacro ap-dotimes [n &rest body] (rit `(for [it (range ~n)] ~@body))) (defmacro ap-first [form xs] (rit `(next (gfor it ~xs :if ~form it) None))) (defmacro ap-last [form xs] (setv x (gensym)) (rit `(do (setv ~x None) (for [it ~xs :if ~form] (setv ~x it)) ~x))) (defmacro! ap-reduce [form o!xs &optional [initial-value None]] (recur-sym-replace {'it (gensym) 'acc (gensym)} `(do (setv acc ~(if (none? initial-value) `(do (setv ~g!xs (iter ~g!xs)) (next ~g!xs)) initial-value)) (for [it ~g!xs] (setv acc ~form)) acc))) (deftag % [expr] (setv %symbols (sfor a (flatten [expr]) :if (and (symbol? a) (.startswith a '%)) a)) `(fn [;; generate all %i symbols up to the maximum found in expr ~@(gfor i (range 1 (-> (lfor a %symbols :if (.isdigit (cut a 1)) (int (cut a 1))) (or (, 0)) max inc)) (HySymbol (+ "%" (str i)))) ;; generate the &rest parameter only if '%* is present in expr ~@(if (in '%* %symbols) '(&rest %*)) ;; similarly for &kwargs and %** ~@(if (in '%** %symbols) '(&kwargs %**))] ~expr)) ;;; -------------------------------------------------- ;;; Subroutines ;;; -------------------------------------------------- (defn recur-sym-replace [d form] "Recursive symbol replacement." (cond [(instance? HySymbol form) (.get d form form)] [(coll? form) ((type form) (gfor x form (recur-sym-replace d x)))] [True form])) (defn rit [form] "Replace `it` with a gensym throughout `form`." (recur-sym-replace {'it (gensym)} form)) hy-0.18.0/hy/extra/reserved.hy000066400000000000000000000012211361554632000161450ustar00rootroot00000000000000;;; Get a frozenset of Hy reserved words ;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (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 _cache (frozenset (map unmangle (+ hy.core.language.EXPORTS hy.core.shadow.EXPORTS (list (.keys hy.core.macros.__macros__)) keyword.kwlist (list (.keys hy.compiler._special_form_compilers)) (list hy.compiler._bad_roots))))))) _cache) hy-0.18.0/hy/importer.py000066400000000000000000000126351361554632000150670ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. from __future__ import absolute_import import sys import os import inspect import pkgutil import re import io import types import tempfile import importlib from functools import partial from contextlib import contextmanager from hy.compiler import hy_compile, hy_ast_compile_flags from hy.lex import hy_parse @contextmanager def loader_module_obj(loader): """Use the module object associated with a loader. This is intended to be used by a loader object itself, and primarily as a work-around for attempts to get module and/or file code from a loader without actually creating a module object. Since Hy currently needs the module object for macro importing, expansion, and whatnot, using this will reconcile Hy with such attempts. For example, if we're first compiling a Hy script starting from `runpy.run_path`, the Hy compiler will need a valid module object in which to run, but, given the way `runpy.run_path` works, there might not be one yet (e.g. `__main__` for a .hy file). We compensate by properly loading the module here. The function `inspect.getmodule` has a hidden-ish feature that returns modules using their associated filenames (via `inspect.modulesbyfile`), and, since the Loaders (and their delegate Loaders) carry a filename/path associated with the parent package, we use it as a more robust attempt to obtain an existing module object. When no module object is found, a temporary, minimally sufficient module object is created for the duration of the `with` body. """ tmp_mod = False try: module = inspect.getmodule(None, _filename=loader.path) except KeyError: module = None if module is None: tmp_mod = True module = sys.modules.setdefault(loader.name, types.ModuleType(loader.name)) module.__file__ = loader.path module.__name__ = loader.name try: yield module finally: if tmp_mod: del sys.modules[loader.name] def _hy_code_from_file(filename, loader_type=None): """Use PEP-302 loader to produce code for a given Hy source file.""" full_fname = os.path.abspath(filename) fname_path, fname_file = os.path.split(full_fname) modname = os.path.splitext(fname_file)[0] sys.path.insert(0, fname_path) try: if loader_type is None: loader = pkgutil.get_loader(modname) else: loader = loader_type(modname, full_fname) code = loader.get_code(modname) finally: sys.path.pop(0) return code def _get_code_from_file(run_name, fname=None, hy_src_check=lambda x: x.endswith('.hy')): """A patch of `runpy._get_code_from_file` that will also run and cache Hy code. """ if fname is None and run_name is not None: fname = run_name # Check for bytecode first. (This is what the `runpy` version does!) with open(fname, "rb") as f: code = pkgutil.read_code(f) if code is None: if hy_src_check(fname): code = _hy_code_from_file(fname, loader_type=HyLoader) else: # Try normal source with open(fname, "rb") as f: # This code differs from `runpy`'s only in that we # force decoding into UTF-8. source = f.read().decode('utf-8') code = compile(source, fname, 'exec') return (code, fname) importlib.machinery.SOURCE_SUFFIXES.insert(0, '.hy') _py_source_to_code = importlib.machinery.SourceFileLoader.source_to_code def _could_be_hy_src(filename): return (os.path.isfile(filename) and (filename.endswith('.hy') or not any(filename.endswith(ext) for ext in importlib.machinery.SOURCE_SUFFIXES[1:]))) def _hy_source_to_code(self, data, path, _optimize=-1): if _could_be_hy_src(path): source = data.decode("utf-8") hy_tree = hy_parse(source, filename=path) with loader_module_obj(self) as module: data = hy_compile(hy_tree, module) return _py_source_to_code(self, data, path, _optimize=_optimize) importlib.machinery.SourceFileLoader.source_to_code = _hy_source_to_code # This is actually needed; otherwise, pre-created finders assigned to the # current dir (i.e. `''`) in `sys.path` will not catch absolute imports of # directory-local modules! sys.path_importer_cache.clear() # Do this one just in case? importlib.invalidate_caches() # XXX: These aren't truly cross-compliant. # They're useful for testing, though. HyImporter = importlib.machinery.FileFinder HyLoader = importlib.machinery.SourceFileLoader # We create a separate version of runpy, "runhy", that prefers Hy source over # Python. runhy = importlib.import_module('runpy') runhy._get_code_from_file = partial(_get_code_from_file, hy_src_check=_could_be_hy_src) del sys.modules['runpy'] runpy = importlib.import_module('runpy') _runpy_get_code_from_file = runpy._get_code_from_file runpy._get_code_from_file = _get_code_from_file def _import_from_path(name, path): """A helper function that imports a module from the given path.""" spec = importlib.util.spec_from_file_location(name, path) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod hy-0.18.0/hy/lex/000077500000000000000000000000001361554632000134355ustar00rootroot00000000000000hy-0.18.0/hy/lex/__init__.py000066400000000000000000000131131361554632000155450ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. from __future__ import unicode_literals import keyword import re import sys import unicodedata from hy.lex.exceptions import PrematureEndOfInput, LexException # NOQA from hy.models import HyExpression, HySymbol try: from io import StringIO except ImportError: from StringIO import StringIO def hy_parse(source, filename=''): """Parse a Hy source string. Parameters ---------- source: string Source code to parse. filename: string, optional File name corresponding to source. Defaults to "". Returns ------- out : HyExpression """ _source = re.sub(r'\A#!.*', '', source) res = HyExpression([HySymbol("do")] + tokenize(_source + "\n", filename=filename)) res.source = source res.filename = filename return res class ParserState(object): def __init__(self, source, filename): self.source = source self.filename = filename def tokenize(source, filename=None): """ Tokenize a Lisp file or string buffer into internal Hy objects. Parameters ---------- source: str The source to tokenize. filename: str, optional The filename corresponding to `source`. """ from hy.lex.lexer import lexer from hy.lex.parser import parser from rply.errors import LexingError try: return parser.parse(lexer.lex(source), state=ParserState(source, filename)) except LexingError as e: pos = e.getsourcepos() raise LexException("Could not identify the next token.", None, filename, source, max(pos.lineno, 1), max(pos.colno, 1)) except LexException as e: raise e def parse_one_thing(src_string): """Parse the first form from the string. Return it and the remainder of the string.""" import re from hy.lex.lexer import lexer from hy.lex.parser import parser from rply.errors import LexingError tokens = [] err = None for token in lexer.lex(src_string): tokens.append(token) try: model, = parser.parse( iter(tokens), state=ParserState(src_string, filename=None)) except (LexingError, LexException) as e: err = e else: return model, src_string[re.match( r'.+\n' * (model.end_line - 1) + '.' * model.end_column, src_string).end():] if err: raise err raise ValueError("No form found") mangle_delim = 'X' def mangle(s): """Stringify the argument and convert it to a valid Python identifier according to Hy's mangling rules.""" def unicode_char_to_hex(uchr): # Covert a unicode char to hex string, without prefix if len(uchr) == 1 and ord(uchr) < 128: return format(ord(uchr), 'x') return (uchr.encode('unicode-escape').decode('utf-8') .lstrip('\\U').lstrip('\\u').lstrip('\\x').lstrip('0')) assert s s = str(s) s = s.replace("-", "_") s2 = s.lstrip('_') leading_underscores = '_' * (len(s) - len(s2)) s = s2 if s.endswith("?"): s = 'is_' + s[:-1] if not isidentifier(leading_underscores + s): # Replace illegal characters with their Unicode character # names, or hexadecimal if they don't have one. s = 'hyx_' + ''.join( c if c != mangle_delim and isidentifier('S' + c) # We prepend the "S" because some characters aren't # allowed at the start of an identifier. else '{0}{1}{0}'.format(mangle_delim, unicodedata.name(c, '').lower().replace('-', 'H').replace(' ', '_') or 'U{}'.format(unicode_char_to_hex(c))) for c in s) s = leading_underscores + s assert isidentifier(s) return s def unmangle(s): """Stringify the argument and try to convert it to a pretty unmangled form. This may not round-trip, because different Hy symbol names can mangle to the same Python identifier.""" s = str(s) s2 = s.lstrip('_') leading_underscores = len(s) - len(s2) s = s2 if s.startswith('hyx_'): s = re.sub('{0}(U)?([_a-z0-9H]+?){0}'.format(mangle_delim), lambda mo: chr(int(mo.group(2), base=16)) if mo.group(1) else unicodedata.lookup( mo.group(2).replace('_', ' ').replace('H', '-').upper()), s[len('hyx_'):]) if s.startswith('is_'): s = s[len("is_"):] + "?" s = s.replace('_', '-') return '-' * leading_underscores + s def read(from_file=sys.stdin, eof=""): """Read from input and returns a tokenized string. Can take a given input buffer to read from, and a single byte as EOF (defaults to an empty string). """ buff = "" while True: inn = str(from_file.readline()) if inn == eof: raise EOFError("Reached end of file") buff += inn try: parsed = next(iter(tokenize(buff)), None) except (PrematureEndOfInput, IndexError): pass else: break return parsed def read_str(input): return read(StringIO(str(input))) def isidentifier(x): if x in ('True', 'False', 'None'): return True if keyword.iskeyword(x): return False return x.isidentifier() hy-0.18.0/hy/lex/exceptions.py000066400000000000000000000022061361554632000161700ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. from hy.errors import HySyntaxError class LexException(HySyntaxError): @classmethod def from_lexer(cls, message, state, token): lineno = None colno = None source = state.source source_pos = token.getsourcepos() if source_pos: lineno = source_pos.lineno colno = source_pos.colno elif source: # Use the end of the last line of source for `PrematureEndOfInput`. # We get rid of empty lines and spaces so that the error matches # with the last piece of visible code. lines = source.rstrip().splitlines() lineno = lineno or len(lines) colno = colno or len(lines[lineno - 1]) else: lineno = lineno or 1 colno = colno or 1 return cls(message, None, state.filename, source, lineno, colno) class PrematureEndOfInput(LexException): pass hy-0.18.0/hy/lex/lexer.py000077500000000000000000000035041361554632000151330ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. 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_set = r'\s\)\]\}' end_quote = r'(?![%s])' % end_quote_set identifier = 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('ANNOTATION', r'\^(?![=%s])' % end_quote_set) lg.add('DISCARD', r'#_') lg.add('HASHSTARS', r'#\*+') lg.add('BRACKETSTRING', r'''(?x) \# \[ ( [^\[\]]* ) \[ # Opening delimiter \n? # A single leading newline will be ignored ((?:\n|.)*?) # Content of the string \] \1 \] # Closing delimiter ''') lg.add('HASHOTHER', r'#%s' % identifier) # A regexp which matches incomplete strings, used to support # multi-line strings in the interpreter partial_string = r'''(?x) (?:u|r|ur|ru|b|br|rb|f|fr|rf)? # 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', identifier) lg.ignore(r';.*(?=\r|\n|$)') lg.ignore(r'\s+') lexer = lg.build() hy-0.18.0/hy/lex/parser.py000077500000000000000000000172431361554632000153150ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. from __future__ import unicode_literals from functools import wraps from rply import ParserGenerator from hy.models import (HyBytes, HyComplex, HyDict, HyExpression, HyFloat, HyInteger, HyKeyword, HyList, HySet, HyString, HySymbol) from .lexer import lexer from .exceptions import LexException, PrematureEndOfInput pg = ParserGenerator([rule.name for rule in lexer.rules] + ['$end']) def set_boundaries(fun): @wraps(fun) def wrapped(state, p): start = p[0].source_pos end = p[-1].source_pos ret = fun(state, 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: v = p[0].value ret.end_line = start.lineno + v.count('\n') ret.end_column = (len(v) - v.rindex('\n') - 1 if '\n' in v else start.colno + len(v) - 1) return ret return wrapped def set_quote_boundaries(fun): @wraps(fun) def wrapped(state, p): start = p[0].source_pos ret = fun(state, 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 : list_contents") def main(state, p): return p[0] @pg.production("main : $end") def main_empty(state, p): return [] @pg.production("paren : LPAREN list_contents RPAREN") @set_boundaries def paren(state, p): return HyExpression(p[1]) @pg.production("paren : LPAREN RPAREN") @set_boundaries def empty_paren(state, p): return HyExpression([]) @pg.production("list_contents : term list_contents") def list_contents(state, p): return [p[0]] + p[1] @pg.production("list_contents : term") def list_contents_single(state, p): return [p[0]] @pg.production("list_contents : DISCARD term discarded_list_contents") def list_contents_empty(state, p): return [] @pg.production("discarded_list_contents : DISCARD term discarded_list_contents") @pg.production("discarded_list_contents :") def discarded_list_contents(state, p): pass @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(state, p): return p[0] @pg.production("term : DISCARD term term") def term_discard(state, p): return p[2] @pg.production("term : QUOTE term") @set_quote_boundaries def term_quote(state, p): return HyExpression([HySymbol("quote"), p[1]]) @pg.production("term : QUASIQUOTE term") @set_quote_boundaries def term_quasiquote(state, p): return HyExpression([HySymbol("quasiquote"), p[1]]) @pg.production("term : UNQUOTE term") @set_quote_boundaries def term_unquote(state, p): return HyExpression([HySymbol("unquote"), p[1]]) @pg.production("term : UNQUOTESPLICE term") @set_quote_boundaries def term_unquote_splice(state, p): return HyExpression([HySymbol("unquote-splice"), p[1]]) @pg.production("term : ANNOTATION term") @set_quote_boundaries def term_annotation(state, p): return HyExpression([HySymbol("annotate*"), p[1]]) @pg.production("term : HASHSTARS term") @set_quote_boundaries def term_hashstars(state, p): n_stars = len(p[0].getstr()[1:]) if n_stars == 1: sym = "unpack-iterable" elif n_stars == 2: sym = "unpack-mapping" else: raise LexException.from_lexer( "Too many stars in `#*` construct (if you want to unpack a symbol " "beginning with a star, separate it with whitespace)", state, p[0]) return HyExpression([HySymbol(sym), p[1]]) @pg.production("term : HASHOTHER term") @set_quote_boundaries def hash_other(state, p): # p == [(Token('HASHOTHER', '#foo'), bar)] st = p[0].getstr()[1:] str_object = HyString(st) expr = p[1] return HyExpression([HySymbol("dispatch-tag-macro"), str_object, expr]) @pg.production("set : HLCURLY list_contents RCURLY") @set_boundaries def t_set(state, p): return HySet(p[1]) @pg.production("set : HLCURLY RCURLY") @set_boundaries def empty_set(state, p): return HySet([]) @pg.production("dict : LCURLY list_contents RCURLY") @set_boundaries def t_dict(state, p): return HyDict(p[1]) @pg.production("dict : LCURLY RCURLY") @set_boundaries def empty_dict(state, p): return HyDict([]) @pg.production("list : LBRACKET list_contents RBRACKET") @set_boundaries def t_list(state, p): return HyList(p[1]) @pg.production("list : LBRACKET RBRACKET") @set_boundaries def t_empty_list(state, p): return HyList([]) @pg.production("string : STRING") @set_boundaries def t_string(state, p): s = p[0].value # Detect and remove any "f" prefix. is_format = False if s.startswith('f') or s.startswith('rf'): is_format = True s = s.replace('f', '', 1) # Replace the single double quotes with triple double quotes to allow # embedded newlines. try: s = eval(s.replace('"', '"""', 1)[:-1] + '"""') except SyntaxError: raise LexException.from_lexer("Can't convert {} to a HyString".format(p[0].value), state, p[0]) return (HyString(s, is_format = is_format) if isinstance(s, str) else HyBytes(s)) @pg.production("string : PARTIAL_STRING") def t_partial_string(state, p): # Any unterminated string requires more input raise PrematureEndOfInput.from_lexer("Partial string literal", state, p[0]) bracket_string_re = next(r.re for r in lexer.rules if r.name == 'BRACKETSTRING') @pg.production("string : BRACKETSTRING") @set_boundaries def t_bracket_string(state, p): m = bracket_string_re.match(p[0].value) delim, content = m.groups() return HyString( content, is_format = delim == 'f' or delim.startswith('f-'), brackets = delim) @pg.production("identifier : IDENTIFIER") @set_boundaries def t_identifier(state, p): obj = p[0].value val = symbol_like(obj) if val is not None: return val if "." in obj and symbol_like(obj.split(".", 1)[0]) is not None: # E.g., `5.attr` or `:foo.attr` raise LexException.from_lexer( 'Cannot access attribute on anything other than a name (in ' 'order to get attributes of expressions, use ' '`(. )` or `(. )`)', state, p[0]) return HySymbol(obj) def symbol_like(obj): "Try to interpret `obj` as a number or keyword." 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(":") and "." not in obj: return HyKeyword(obj[1:]) @pg.error def error_handler(state, token): tokentype = token.gettokentype() if tokentype == '$end': raise PrematureEndOfInput.from_lexer("Premature end of input", state, token) else: raise LexException.from_lexer( "Ran into a %s where it wasn't expected." % tokentype, state, token) parser = pg.build() hy-0.18.0/hy/macros.py000066400000000000000000000311441361554632000145060ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import sys import importlib import inspect import pkgutil import traceback from contextlib import contextmanager from hy._compat import reraise, PY38 from hy.models import replace_hy_obj, HyExpression, HySymbol, wrap_value from hy.lex import mangle from hy.errors import (HyLanguageError, HyMacroExpansionError, HyTypeError, HyRequireError) try: # Check if we have the newer inspect.signature available. # Otherwise fallback to the legacy getargspec. inspect.signature # noqa except AttributeError: def has_kwargs(fn): argspec = inspect.getargspec(fn) return argspec.keywords is not None def format_args(fn): argspec = inspect.getargspec(fn) return inspect.formatargspec(*argspec) else: def has_kwargs(fn): parameters = inspect.signature(fn).parameters return any(param.kind == param.VAR_KEYWORD for param in parameters.values()) def format_args(fn): return str(inspect.signature(fn)) CORE_MACROS = [ "hy.core.bootstrap", ] EXTRA_MACROS = [ "hy.core.macros", ] def macro(name): """Decorator to define a macro called `name`. """ name = mangle(name) def _(fn): fn = rename_function(fn, name) try: fn._hy_macro_pass_compiler = has_kwargs(fn) 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 = inspect.getmodule(fn) module_macros = module.__dict__.setdefault('__macros__', {}) module_macros[name] = fn return fn return _ def tag(name): """Decorator to define a tag macro called `name`. """ def _(fn): _name = mangle('#{}'.format(name)) fn = rename_function(fn, _name) module = inspect.getmodule(fn) module_name = module.__name__ if module_name.startswith("hy.core"): module_name = None module_tags = module.__dict__.setdefault('__tags__', {}) module_tags[mangle(name)] = fn return fn return _ def _same_modules(source_module, target_module): """Compare the filenames associated with the given modules names. This tries to not actually load the modules. """ if not (source_module or target_module): return False if target_module == source_module: return True def _get_filename(module): filename = None try: if not inspect.ismodule(module): loader = pkgutil.get_loader(module) if loader: filename = loader.get_filename() else: filename = inspect.getfile(module) except (TypeError, ImportError): pass return filename source_filename = _get_filename(source_module) target_filename = _get_filename(target_module) return (source_filename and target_filename and source_filename == target_filename) def require(source_module, target_module, assignments, prefix=""): """Load macros from one module into the namespace of another. This function is called from the `require` special form in the compiler. Parameters ---------- source_module: str or types.ModuleType The module from which macros are to be imported. target_module: str, types.ModuleType or None The module into which the macros will be loaded. If `None`, then the caller's namespace. The latter is useful during evaluation of generated AST/bytecode. assignments: str or list of tuples of strs The string "ALL" or a list of macro name and alias pairs. prefix: str, optional ("") If nonempty, its value is prepended to the name of each imported macro. This allows one to emulate namespaced macros, like "mymacromodule.mymacro", which looks like an attribute of a module. Returns ------- out: boolean Whether or not macros and tags were actually transferred. """ if target_module is None: parent_frame = inspect.stack()[1][0] target_namespace = parent_frame.f_globals target_module = target_namespace.get('__name__', None) elif isinstance(target_module, str): target_module = importlib.import_module(target_module) target_namespace = target_module.__dict__ elif inspect.ismodule(target_module): target_namespace = target_module.__dict__ else: raise HyTypeError('`target_module` is not a recognized type: {}'.format( type(target_module))) # Let's do a quick check to make sure the source module isn't actually # the module being compiled (e.g. when `runpy` executes a module's code # in `__main__`). # We use the module's underlying filename for this (when they exist), since # it's the most "fixed" attribute. if _same_modules(source_module, target_module): return False if not inspect.ismodule(source_module): try: source_module = importlib.import_module(source_module) except ImportError as e: reraise(HyRequireError, HyRequireError(e.args[0]), None) source_macros = source_module.__dict__.setdefault('__macros__', {}) source_tags = source_module.__dict__.setdefault('__tags__', {}) if len(source_module.__macros__) + len(source_module.__tags__) == 0: if assignments != "ALL": raise HyRequireError('The module {} has no macros or tags'.format( source_module)) else: return False target_macros = target_namespace.setdefault('__macros__', {}) target_tags = target_namespace.setdefault('__tags__', {}) if prefix: prefix += "." if assignments == "ALL": name_assigns = [(k, k) for k in tuple(source_macros.keys()) + tuple(source_tags.keys())] else: name_assigns = assignments for name, alias in name_assigns: _name = mangle(name) alias = mangle(prefix + alias) if _name in source_module.__macros__: target_macros[alias] = source_macros[_name] elif _name in source_module.__tags__: target_tags[alias] = source_tags[_name] else: raise HyRequireError('Could not require name {} from {}'.format( _name, source_module)) return True def load_macros(module): """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. """ builtin_macros = CORE_MACROS if not module.__name__.startswith("hy.core"): builtin_macros += EXTRA_MACROS module_macros = module.__dict__.setdefault('__macros__', {}) module_tags = module.__dict__.setdefault('__tags__', {}) for builtin_mod_name in builtin_macros: builtin_mod = importlib.import_module(builtin_mod_name) # Make sure we don't overwrite macros in the module. if hasattr(builtin_mod, '__macros__'): module_macros.update({k: v for k, v in builtin_mod.__macros__.items() if k not in module_macros}) if hasattr(builtin_mod, '__tags__'): module_tags.update({k: v for k, v in builtin_mod.__tags__.items() if k not in module_tags}) @contextmanager def macro_exceptions(module, macro_tree, compiler=None): try: yield except HyLanguageError as e: # These are user-level Hy errors occurring in the macro. # We want to pass them up to the user. reraise(type(e), e, sys.exc_info()[2]) except Exception as e: if compiler: filename = compiler.filename source = compiler.source else: filename = None source = None exc_msg = ' '.join(traceback.format_exception_only( sys.exc_info()[0], sys.exc_info()[1])) msg = "expanding macro {}\n ".format(str(macro_tree[0])) msg += exc_msg reraise(HyMacroExpansionError, HyMacroExpansionError( msg, macro_tree, filename, source), sys.exc_info()[2]) def macroexpand(tree, module, compiler=None, once=False): """Expand the toplevel macros for the given Hy AST tree. Load the macros from the given `module`, then expand the (top-level) macros in `tree` until we no longer can. `HyExpression` resulting from macro expansions are assigned the module in which the macro function is defined (determined using `inspect.getmodule`). If the resulting `HyExpression` is itself macro expanded, then the namespace of the assigned module is checked first for a macro corresponding to the expression's head/car symbol. If the head/car symbol of such a `HyExpression` is not found among the macros of its assigned module's namespace, the outer-most namespace--e.g. the one given by the `module` parameter--is used as a fallback. Parameters ---------- tree: HyObject or list Hy AST tree. module: str or types.ModuleType Module used to determine the local namespace for macros. compiler: HyASTCompiler, optional The compiler object passed to expanded macros. once: boolean, optional Only expand the first macro in `tree`. Returns ------ out: HyObject Returns a mutated tree with macros expanded. """ if not inspect.ismodule(module): module = importlib.import_module(module) assert not compiler or compiler.module == module while True: if not isinstance(tree, HyExpression) or tree == []: break fn = tree[0] if fn in ("quote", "quasiquote") or not isinstance(fn, HySymbol): break fn = mangle(fn) expr_modules = (([] if not hasattr(tree, 'module') else [tree.module]) + [module]) # Choose the first namespace with the macro. m = next((mod.__macros__[fn] for mod in expr_modules if fn in mod.__macros__), None) if not m: break opts = {} if m._hy_macro_pass_compiler: if compiler is None: from hy.compiler import HyASTCompiler compiler = HyASTCompiler(module) opts['compiler'] = compiler with macro_exceptions(module, tree, compiler): obj = m(module.__name__, *tree[1:], **opts) if isinstance(obj, HyExpression): obj.module = inspect.getmodule(m) tree = replace_hy_obj(obj, tree) if once: break tree = wrap_value(tree) return tree def macroexpand_1(tree, module, compiler=None): """Expand the toplevel macro from `tree` once, in the context of `compiler`.""" return macroexpand(tree, module, compiler, once=True) def tag_macroexpand(tag, tree, module): """Expand the tag macro `tag` with argument `tree`.""" if not inspect.ismodule(module): module = importlib.import_module(module) expr_modules = (([] if not hasattr(tree, 'module') else [tree.module]) + [module]) # Choose the first namespace with the macro. tag_macro = next((mod.__tags__[tag] for mod in expr_modules if tag in mod.__tags__), None) if tag_macro is None: raise HyTypeError("`{0}' is not a defined tag macro.".format(tag), None, tag, None) expr = tag_macro(tree) if isinstance(expr, HyExpression): expr.module = inspect.getmodule(tag_macro) return replace_hy_obj(expr, tree) def rename_function(func, new_name): """Creates a copy of a function and [re]sets the name at the code-object level. """ c = func.__code__ new_code = type(c)(*[getattr(c, 'co_{}'.format(a)) if a != 'name' else str(new_name) for a in code_obj_args]) _fn = type(func)(new_code, func.__globals__, str(new_name), func.__defaults__, func.__closure__) _fn.__dict__.update(func.__dict__) return _fn code_obj_args = ['argcount', 'posonlyargcount', 'kwonlyargcount', 'nlocals', 'stacksize', 'flags', 'code', 'consts', 'names', 'varnames', 'filename', 'name', 'firstlineno', 'lnotab', 'freevars', 'cellvars'] if not PY38: code_obj_args.remove("posonlyargcount") hy-0.18.0/hy/model_patterns.py000066400000000000000000000061771361554632000162520ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. "Parser combinators for pattern-matching Hy model trees." from hy.models import HyExpression, HySymbol, HyKeyword, HyString, HyList from funcparserlib.parser import ( some, skip, many, finished, a, Parser, NoParseError, State) from functools import reduce from itertools import repeat from collections import namedtuple from operator import add from math import isinf FORM = some(lambda _: True) SYM = some(lambda x: isinstance(x, HySymbol)) KEYWORD = some(lambda x: isinstance(x, HyKeyword)) STR = some(lambda x: isinstance(x, HyString)) def sym(wanted): "Parse and skip the given symbol or keyword." if wanted.startswith(":"): return skip(a(HyKeyword(wanted[1:]))) return skip(some(lambda x: isinstance(x, HySymbol) and x == wanted)) def whole(parsers): """Parse the parsers in the given list one after another, then expect the end of the input.""" if len(parsers) == 0: return finished >> (lambda x: []) if len(parsers) == 1: return parsers[0] + finished >> (lambda x: x[:-1]) return reduce(add, parsers) + skip(finished) def _grouped(group_type, parsers): return ( some(lambda x: isinstance(x, group_type)) >> (lambda x: group_type(whole(parsers).parse(x)).replace(x, recursive=False))) def brackets(*parsers): "Parse the given parsers inside square brackets." return _grouped(HyList, parsers) def pexpr(*parsers): "Parse the given parsers inside a parenthesized expression." return _grouped(HyExpression, parsers) def dolike(head): "Parse a `do`-like form." return pexpr(sym(head), many(FORM)) def notpexpr(*disallowed_heads): """Parse any object other than a HyExpression beginning with a HySymbol equal to one of the disallowed_heads.""" return some(lambda x: not ( isinstance(x, HyExpression) and x and isinstance(x[0], HySymbol) and x[0] in disallowed_heads)) def unpack(kind): "Parse an unpacking form, returning it unchanged." return some(lambda x: isinstance(x, HyExpression) and len(x) > 0 and isinstance(x[0], HySymbol) and x[0] == "unpack-" + kind) def times(lo, hi, parser): """Parse `parser` several times (`lo` to `hi`) in a row. `hi` can be float('inf'). The result is a list no matter the number of instances.""" @Parser def f(tokens, s): result = [] for _ in range(lo): (v, s) = parser.run(tokens, s) result.append(v) end = s.max try: for _ in (repeat(1) if isinf(hi) else range(hi - lo)): (v, s) = parser.run(tokens, s) result.append(v) except NoParseError as e: end = e.state.max return result, State(s.pos, end) return f Tag = namedtuple('Tag', ['tag', 'value']) def tag(tag_name, parser): """Matches the given parser and produces a named tuple `(Tag tag value)` with `tag` set to the given tag name and `value` set to the parser's value.""" return parser >> (lambda x: Tag(tag_name, x)) hy-0.18.0/hy/models.py000066400000000000000000000250071361554632000145060ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. from __future__ import unicode_literals from contextlib import contextmanager from math import isnan, isinf from hy import _initialize_env_var from hy.errors import HyWrapperError from fractions import Fraction from colorama import Fore PRETTY = True COLORED = _initialize_env_var('HY_COLORED_AST_OBJECTS', False) @contextmanager def pretty(pretty=True): """ Context manager to temporarily enable or disable pretty-printing of Hy model reprs. """ global PRETTY old, PRETTY = PRETTY, pretty try: yield finally: PRETTY = old class _ColoredModel: """ Mixin that provides a helper function for models that have color. """ def _colored(self, text): if COLORED: return self.color + text + Fore.RESET else: return text class HyObject(object): """ Generic Hy Object model. This is helpful to inject things into all the Hy lexing Objects at once. The position properties (`start_line`, `end_line`, `start_column`, `end_column`) are each 1-based and inclusive. For example, a symbol `abc` starting at the first column would have `start_column` 1 and `end_column` 3. """ __properties__ = ["module", "start_line", "end_line", "start_column", "end_column"] def replace(self, other, recursive=False): if isinstance(other, HyObject): for attr in self.__properties__: 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 '{}'".format(repr(other), repr(self))) return self def __repr__(self): return "%s(%s)" % (self.__class__.__name__, super(HyObject, self).__repr__()) _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. """ new = _wrappers.get(type(x), lambda y: y)(x) if not isinstance(new, HyObject): raise HyWrapperError("Don't know how to wrap {!r}: {!r}".format(type(x), x)) if isinstance(x, HyObject): new = new.replace(x, recursive=False) if not hasattr(new, "start_column"): new.start_column = 0 if not hasattr(new, "start_line"): new.start_line = 0 return new def replace_hy_obj(obj, other): return wrap_value(obj).replace(other) def repr_indent(obj): return repr(obj).replace("\n", "\n ") class HyString(HyObject, str): """ 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. """ def __new__(cls, s=None, is_format=False, brackets=None): value = super(HyString, cls).__new__(cls, s) value.is_format = bool(is_format) value.brackets = brackets return value _wrappers[str] = HyString class HyBytes(HyObject, bytes): """ Generic Hy Bytes object. It's either a ``bytes`` or a ``str``, depending on the Python version. """ pass _wrappers[bytes] = HyBytes class HySymbol(HyObject, str): """ Hy Symbol. Basically a string. """ def __new__(cls, s=None): return super(HySymbol, cls).__new__(cls, s) _wrappers[bool] = lambda x: HySymbol("True") if x else HySymbol("False") _wrappers[type(None)] = lambda foo: HySymbol("None") class HyKeyword(HyObject): """Generic Hy Keyword object.""" __slots__ = ['name'] def __init__(self, value): self.name = value def __repr__(self): return "%s(%r)" % (self.__class__.__name__, self.name) def __str__(self): return ":%s" % self.name def __hash__(self): return hash(self.name) def __eq__(self, other): if not isinstance(other, HyKeyword): return NotImplemented return self.name == other.name def __ne__(self, other): if not isinstance(other, HyKeyword): return NotImplemented return self.name != other.name def __bool__(self): return bool(self.name) _sentinel = object() def __call__(self, data, default=_sentinel): try: return data[self] except KeyError: if default is HyKeyword._sentinel: raise return default def strip_digit_separators(number): # Don't strip a _ or , if it's the first character, as _42 and # ,42 aren't valid numbers return (number[0] + number[1:].replace("_", "").replace(",", "") if isinstance(number, str) and len(number) > 1 else number) class HyInteger(HyObject, int): """ Internal representation of a Hy Integer. May raise a ValueError as if int(foo) was called, given HyInteger(foo). """ def __new__(cls, number, *args, **kwargs): if isinstance(number, str): number = strip_digit_separators(number) 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 = int(number, base=base) break else: # We've got a string, no known leader; base 10. number = int(number, base=10) else: # We've got a non-string; convert straight. number = int(number) return super(HyInteger, cls).__new__(cls, number) _wrappers[int] = HyInteger def check_inf_nan_cap(arg, value): if isinstance(arg, str): if isinf(value) and "i" in arg.lower() and "Inf" not in arg: raise ValueError('Inf must be capitalized as "Inf"') if isnan(value) and "NaN" not in arg: raise ValueError('NaN must be capitalized as "NaN"') 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, num, *args, **kwargs): value = super(HyFloat, cls).__new__(cls, strip_digit_separators(num)) check_inf_nan_cap(num, value) return value _wrappers[float] = HyFloat 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, real, imag=0, *args, **kwargs): if isinstance(real, str): value = super(HyComplex, cls).__new__( cls, strip_digit_separators(real) ) p1, _, p2 = real.lstrip("+-").replace("-", "+").partition("+") check_inf_nan_cap(p1, value.imag if "j" in p1 else value.real) if p2: check_inf_nan_cap(p2, value.imag) return value return super(HyComplex, cls).__new__(cls, real, imag) _wrappers[complex] = HyComplex class HySequence(HyObject, tuple, _ColoredModel): """ An abstract type for sequence-like models to inherit from. """ def replace(self, other, recursive=True): if recursive: for x in self: replace_hy_obj(x, other) HyObject.replace(self, other) return self def __add__(self, other): return self.__class__(super(HySequence, self).__add__( tuple(other) if isinstance(other, list) else other)) def __getslice__(self, start, end): return self.__class__(super(HySequence, self).__getslice__(start, end)) def __getitem__(self, item): ret = super(HySequence, self).__getitem__(item) if isinstance(item, slice): return self.__class__(ret) return ret color = None def __repr__(self): return str(self) if PRETTY else super(HySequence, self).__repr__() def __str__(self): with pretty(): if self: return self._colored("{}{}\n {}{}".format( self._colored(self.__class__.__name__), self._colored("(["), self._colored(",\n ").join(map(repr_indent, self)), self._colored("])"), )) return self._colored("{}([\n {}])".format( self.__class__.__name__, ','.join(repr_indent(e) for e in self), )) else: return self._colored(self.__class__.__name__ + "()") class HyList(HySequence): color = Fore.CYAN def recwrap(f): return lambda l: f(wrap_value(x) for x in l) _wrappers[HyList] = recwrap(HyList) _wrappers[list] = recwrap(HyList) _wrappers[tuple] = recwrap(HyList) class HyDict(HySequence, _ColoredModel): """ HyDict (just a representation of a dict) """ color = Fore.GREEN def __str__(self): with pretty(): if self: pairs = [] for k, v in zip(self[::2],self[1::2]): k, v = repr_indent(k), repr_indent(v) pairs.append( ("{0}{c}\n {1}\n " if '\n' in k+v else "{0}{c} {1}").format(k, v, c=self._colored(','))) if len(self) % 2 == 1: pairs.append("{} {}\n".format( repr_indent(self[-1]), self._colored("# odd"))) return "{}\n {}{}".format( self._colored("HyDict(["), "{c}\n ".format(c=self._colored(',')).join(pairs), self._colored("])")) else: return self._colored("HyDict()") def keys(self): return list(self[0::2]) def values(self): return list(self[1::2]) def items(self): return list(zip(self.keys(), self.values())) _wrappers[HyDict] = recwrap(HyDict) _wrappers[dict] = lambda d: HyDict(wrap_value(x) for x in sum(d.items(), ())) class HyExpression(HySequence): """ Hy S-Expression. Basically just a list. """ color = Fore.YELLOW _wrappers[HyExpression] = recwrap(HyExpression) _wrappers[Fraction] = lambda e: HyExpression( [HySymbol("fraction"), wrap_value(e.numerator), wrap_value(e.denominator)]) class HySet(HySequence): """ Hy set (just a representation of a set) """ color = Fore.RED _wrappers[HySet] = recwrap(HySet) _wrappers[set] = recwrap(HySet) hy-0.18.0/issue_template.md000066400000000000000000000007411361554632000155740ustar00rootroot00000000000000Hy's issue list is for bugs, complaints, and feature requests. For help with Hy, ask on our IRC channel (may take up to a day), Stack Overflow with the `[hy]` tag, or on our mailing list. If you're reporting a bug, make sure you can reproduce it with the very latest, bleeding-edge version of Hy from the `master` branch on GitHub. Bugs in stable versions of Hy are fixed on `master` before the fix makes it into a new stable release. You can delete this text after reading it. hy-0.18.0/make.bat000066400000000000000000000037141361554632000136370ustar00rootroot00000000000000@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 pytest -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.18.0/requirements-dev.txt000066400000000000000000000001461361554632000162660ustar00rootroot00000000000000-r requirements-travis.txt # test tools tox # documentation Pygments >= 1.6 Sphinx sphinx_rtd_theme hy-0.18.0/requirements-travis.txt000066400000000000000000000000601361554632000170130ustar00rootroot00000000000000pytest >= 3.2.1 # code quality flake8 coverage hy-0.18.0/setup.cfg000066400000000000000000000011071361554632000140450ustar00rootroot00000000000000[wheel] universal = 1 [coverage:run] omit = */python?.?/* */lib-python/?.?/*.py */lib_pypy/_*.py */pypy/* [coverage:report] exclude_lines = # Have to re-enable the standard pragma pragma: no cover # We want ignore_errors so we don't get NoSource warnings for loading # byte-compiled Hy modules. ignore_errors = True [tool:pytest] # Be sure to include Hy test functions with mangled names. python_functions=test_* is_test_* hyx_test_* hyx_is_test_* filterwarnings = once::DeprecationWarning once::PendingDeprecationWarning ignore::SyntaxWarning hy-0.18.0/setup.py000077500000000000000000000076351361554632000137550ustar00rootroot00000000000000#!/usr/bin/env python # Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import glob import importlib import inspect import os import sys from setuptools import find_packages, setup from setuptools.command.install import install import fastentrypoints # Monkey-patches setuptools. from get_version import __version__ os.chdir(os.path.split(os.path.abspath(__file__))[0]) PKG = "hy" 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. """ class Install(install): def __compile_hy_bytecode(self): for path in sorted(glob.iglob('hy/**.hy', recursive=True)): importlib.util.cache_from_source(path, optimize=self.optimize) def run(self): # Don't bother messing around with deps if they wouldn't be installed anyway. # Code is based on setuptools's install.py. if not (self.old_and_unmanageable or self.single_version_externally_managed or not self._called_from_setup(inspect.currentframe())): easy_install = self.distribution.get_command_class('easy_install') cmd = easy_install( self.distribution, args="x", root=self.root, record=self.record, ) cmd.ensure_finalized() cmd.always_copy_from = '.' cmd.package_index.scan(glob.glob('*.egg')) cmd.args = self.distribution.install_requires # Avoid deprecation warnings on new setuptools versions. if 'show_deprecation' in inspect.signature(cmd.run).parameters: cmd.run(show_deprecation=False) else: cmd.run() # Make sure any new packages get picked up. import site importlib.reload(site) importlib.invalidate_caches() self.__compile_hy_bytecode() # The deps won't be reinstalled because of: # https://github.com/pypa/setuptools/issues/456 return install.run(self) install_requires = [ 'rply>=0.7.7', 'astor>=0.8', 'funcparserlib>=0.3.6', 'colorama'] if os.name == 'nt': install_requires.append('pyreadline>=2.1') setup( name=PKG, version=__version__, install_requires=install_requires, cmdclass=dict(install=Install), entry_points={ 'console_scripts': [ 'hy = hy.cmdline:hy_main', 'hy3 = hy.cmdline:hy_main', 'hyc = hy.cmdline:hyc_main', 'hyc3 = hy.cmdline:hyc_main', 'hy2py = hy.cmdline:hy2py_main', 'hy2py3 = hy.cmdline:hy2py_main', ] }, packages=find_packages(exclude=['tests*']), package_data={ 'hy.contrib': ['*.hy', '__pycache__/*'], 'hy.core': ['*.hy', '__pycache__/*'], 'hy.extra': ['*.hy', '__pycache__/*'], }, data_files=[ ('get_version', ['get_version.py']) ], 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 :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Topic :: Software Development :: Code Generators", "Topic :: Software Development :: Compilers", "Topic :: Software Development :: Libraries", ] ) hy-0.18.0/tests/000077500000000000000000000000001361554632000133675ustar00rootroot00000000000000hy-0.18.0/tests/__init__.py000066400000000000000000000000001361554632000154660ustar00rootroot00000000000000hy-0.18.0/tests/compilers/000077500000000000000000000000001361554632000153645ustar00rootroot00000000000000hy-0.18.0/tests/compilers/__init__.py000066400000000000000000000000001361554632000174630ustar00rootroot00000000000000hy-0.18.0/tests/compilers/test_ast.py000066400000000000000000000454251361554632000175760ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. from __future__ import unicode_literals from hy import HyString from hy.compiler import hy_compile, hy_eval from hy.errors import HyCompileError, HyLanguageError, HyError from hy.lex import hy_parse from hy.lex.exceptions import LexException, PrematureEndOfInput from hy._compat import PY36 import ast import pytest 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(hy_parse(expr), __name__) def can_eval(expr): return hy_eval(hy_parse(expr)) def cant_compile(expr): with pytest.raises(HyError) as excinfo: hy_compile(hy_parse(expr), __name__) if issubclass(excinfo.type, HyLanguageError): assert excinfo.value.msg return excinfo.value elif issubclass(excinfo.type, HyCompileError): # Anything that can't be compiled should raise a user friendly # error, otherwise it's a compiler bug. return excinfo.value def s(x): return can_compile('"module docstring" ' + x).body[-1].value.s def test_ast_bad_type(): "Make sure AST breakage can happen" class C: pass with pytest.raises(TypeError): hy_compile(C(), __name__, filename='', source='') def test_empty_expr(): "Empty expressions should be illegal at the top level." cant_compile("(print ())") can_compile("(print '())") def test_dot_unpacking(): can_compile("(.meth obj #* args az)") cant_compile("(.meth #* args az)") cant_compile("(. foo #* bar baz)") can_compile("(.meth obj #** args az)") can_compile("(.meth #** args obj)") cant_compile("(. foo #** bar baz)") 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)") 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)") 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 1 (except []) (else 1))") can_compile("(try 1 (finally 1))") can_compile("(try 1 (except []) (finally 1))") can_compile("(try 1 (except [x]) (except [y]) (finally 1))") can_compile("(try 1 (except []) (else 1) (finally 1))") can_compile("(try 1 (except [x]) (except [y]) (else 1) (finally 1))") def test_ast_bad_try(): "Make sure AST can't compile invalid try" cant_compile("(try)") cant_compile("(try 1)") cant_compile("(try 1 bla)") cant_compile("(try 1 bla bla)") cant_compile("(try (do bla bla))") cant_compile("(try (do) (else 1) (else 2))") cant_compile("(try 1 (else 1))") cant_compile("(try 1 (else 1) (except []))") cant_compile("(try 1 (finally 1) (except []))") cant_compile("(try 1 (except []) (finally 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 [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))") cant_compile("(try 1 (except 1))") cant_compile("(try 1 (except [1 3]))") cant_compile("(try 1 (except [(f) [IOError ValueError]]))") 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))") 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 [])") can_compile("(defclass a [] None 42)") can_compile("(defclass a [] None \"test\")") can_compile("(defclass a [] None (print \"foo\"))") def test_ast_good_defclass_with_metaclass(): "Make sure AST can compile valid defclass with keywords" can_compile("(defclass a [:metaclass b])") can_compile("(defclass a [:b c])") 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("(fn [])") can_compile("(fn [] 1)") def test_ast_bad_lambda(): "Make sure AST can't compile invalid lambda" cant_compile("(fn)") cant_compile("(fn ())") cant_compile("(fn () 1)") cant_compile("(fn (x) 1)") cant_compile('(fn "foo")') 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_import_mangle_dotted(): """Mangling a module name with a period shouldn't create a spurious `asname`.""" code = can_compile("(import a-b.c)") assert code.body[0].names[0].name == "a_b.c" assert code.body[0].names[0].asname is None 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_import_require_dotted(): """As in Python, it should be a compile-time error to attempt to import a dotted name.""" cant_compile("(import [spam [foo.bar]])") cant_compile("(require [spam [foo.bar]])") 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)") can_compile("(while foo bar (else baz))") def test_ast_valid_for(): "Make sure AST can compile valid for" can_compile("(for [a 2] (print a))") def test_nullary_break_continue(): can_compile("(while 1 (break))") cant_compile("(while 1 (break 1))") can_compile("(while 1 (continue))") cant_compile("(while 1 (continue 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].value assert type(code) == ast.Lambda code = can_compile("(fn [x] (print \"multiform\") (* x x))").body[0] assert type(code) == ast.FunctionDef can_compile("(fn [x])") 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 [&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_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_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(): kwonly_demo = "(fn [&kwonly a [b 2]] (print 1) (print a b))" 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 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\"}])") can_compile("(fn [x &rest xs &kwonly kwoxs &kwargs kwxs]" " (list x xs kwxs kwoxs))") def test_missing_keyword_argument_value(): """Ensure the compiler chokes on missing keyword argument values.""" with pytest.raises(HyLanguageError) as excinfo: can_compile("((fn [x] x) :x)") assert excinfo.value.msg == "Keyword argument :x needs a value." def test_ast_unicode_strings(): """Ensure we handle unicode strings correctly""" def _compile_string(s): hy_s = HyString(s) code = hy_compile([hy_s], __name__, filename='', source=s) # We put hy_s in a list so it isn't interpreted as a docstring. # code == ast.Module(body=[ast.Expr(value=ast.List(elts=[ast.Str(s=xxx)]))]) return code.body[0].value.elts[0].s assert _compile_string("test") == "test" assert _compile_string("\u03b1\u03b2") == "\u03b1\u03b2" assert _compile_string("\xc3\xa9") == "\xc3\xa9" def test_ast_unicode_vs_bytes(): assert s('"hello"') == "hello" assert type(s('"hello"')) is str assert s('b"hello"') == b"hello" assert type(s('b"hello"')) is bytes assert s('b"\\xa0"') == bytes([160]) @pytest.mark.skipif(not PY36, reason='f-strings require Python 3.6+') def test_format_string(): assert can_compile('f"hello world"') assert can_compile('f"hello {(+ 1 1)} world"') assert can_compile('f"hello world {(+ 1 1)}"') assert cant_compile('f"hello {(+ 1 1) world"') assert cant_compile('f"hello (+ 1 1)} world"') assert cant_compile('f"hello {(+ 1 1} world"') assert can_compile(r'f"hello {\"n\"} world"') assert can_compile(r'f"hello {\"\\n\"} world"') def test_ast_bracket_string(): assert s(r'#[[empty delims]]') == 'empty delims' assert s(r'#[my delim[fizzle]my delim]') == 'fizzle' assert s(r'#[[]]') == '' assert s(r'#[my delim[]my delim]') == '' assert type(s('#[X[hello]X]')) is str assert s(r'#[X[raw\nstring]X]') == 'raw\\nstring' assert s(r'#[foozle[aa foozli bb ]foozle]') == 'aa foozli bb ' assert s(r'#[([unbalanced](]') == 'unbalanced' assert s(r'#[(1💯@)} {a![hello world](1💯@)} {a!]') == 'hello world' assert (s(r'''#[X[ Remove the leading newline, please. ]X]''') == 'Remove the leading newline, please.\n') assert (s(r'''#[X[ Only one leading newline should be removed. ]X]''') == '\n\nOnly one leading newline should be removed.\n') def test_compile_error(): """Ensure we get compile error in tricky cases""" with pytest.raises(HyLanguageError) as excinfo: can_compile("(fn [] (in [1 2 3]))") def test_for_compile_error(): """Ensure we get compile error in tricky 'for' cases""" with pytest.raises(PrematureEndOfInput) as excinfo: can_compile("(fn [] (for)") assert excinfo.value.msg == "Premature end of input" with pytest.raises(LexException) as excinfo: can_compile("(fn [] (for)))") assert excinfo.value.msg == "Ran into a RPAREN where it wasn't expected." cant_compile("(fn [] (for [x] x))") 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_bad_setv(): """Ensure setv handles error cases""" cant_compile("(setv (a b) [1 2])") def test_defn(): """Ensure that defn works correctly in various corner cases""" cant_compile("(defn \"hy\" [] 1)") cant_compile("(defn :hy [] 1)") can_compile("(defn &hy [] 1)") cant_compile('(defn hy "foo")') def test_setv_builtins(): """Ensure that assigning to a builtin fails, unless in a class""" cant_compile("(setv None 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)) """) def test_top_level_unquote(): with pytest.raises(HyLanguageError) as excinfo: can_compile("(unquote)") assert excinfo.value.msg == "The special form 'unquote' is not allowed here" with pytest.raises(HyLanguageError) as excinfo: can_compile("(unquote-splice)") assert excinfo.value.msg == "The special form 'unquote-splice' is not allowed here" def test_lots_of_comment_lines(): # https://github.com/hylang/hy/issues/1313 can_compile(1000 * ";\n") def test_compiler_macro_tag_try(): """Check that try forms within defmacro/deftag are compiled correctly""" # https://github.com/hylang/hy/issues/1350 can_compile("(defmacro foo [] (try None (except [] None)) `())") can_compile("(deftag foo [] (try None (except [] None)) `())") def test_ast_good_yield_from(): "Make sure AST can compile valid yield-from" can_compile("(yield-from [1 2])") def test_ast_bad_yield_from(): "Make sure AST can't compile invalid yield-from" cant_compile("(yield-from)") def test_eval_generator_with_return(): """Ensure generators with a return statement works.""" can_eval("(fn [] (yield 1) (yield 2) (return))") def test_futures_imports(): """Make sure __future__ imports go first, especially when builtins are automatically added (e.g. via use of a builtin name like `name`).""" hy_ast = can_compile(( '(import [__future__ [print_function]])\n' '(import sys)\n' '(setv name [1 2])' '(print (first name))')) assert hy_ast.body[0].module == '__future__' assert hy_ast.body[1].module == 'hy.core.language' hy_ast = can_compile(( '(import sys)\n' '(import [__future__ [print_function]])\n' '(setv name [1 2])' '(print (first name))')) assert hy_ast.body[0].module == '__future__' assert hy_ast.body[1].module == 'hy.core.language' def test_inline_python(): can_compile('(py "1 + 1")') cant_compile('(py "1 +")') can_compile('(pys "if 1:\n 2")') cant_compile('(pys "if 1\n 2")') hy-0.18.0/tests/compilers/test_compiler.py000066400000000000000000000042311361554632000206070ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import ast from hy import compiler from hy.models import HyExpression, HyList, HySymbol, HyInteger import types 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 test_compiler_bare_names(): """ Check that the compiler doesn't drop bare names from code branches """ e = make_expression(HySymbol("do"), HySymbol("a"), HySymbol("b"), HySymbol("c")) ret = compiler.HyASTCompiler(types.ModuleType('test')).compile(e) # We expect two statements and a final expr. assert len(ret.stmts) == 2 for stmt, symbol in zip(ret.stmts, "ab"): assert isinstance(stmt, ast.Expr) assert isinstance(stmt.value, ast.Name) assert stmt.value.id == symbol assert isinstance(ret.expr, ast.Name) assert ret.expr.id == "c" def test_compiler_yield_return(): """ 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. """ e = make_expression(HySymbol("fn"), HyList(), HyExpression([HySymbol("yield"), HyInteger(2)]), HyExpression([HySymbol("+"), HyInteger(1), HyInteger(1)])) ret = compiler.HyASTCompiler(types.ModuleType('test')).compile_atom(e) assert len(ret.stmts) == 1 stmt, = ret.stmts assert isinstance(stmt, ast.FunctionDef) body = stmt.body assert len(body) == 2 assert isinstance(body[0], ast.Expr) assert isinstance(body[0].value, ast.Yield) assert isinstance(body[1], ast.Return) assert isinstance(body[1].value, ast.BinOp) hy-0.18.0/tests/importer/000077500000000000000000000000001361554632000152305ustar00rootroot00000000000000hy-0.18.0/tests/importer/__init__.py000066400000000000000000000000001361554632000173270ustar00rootroot00000000000000hy-0.18.0/tests/importer/test_importer.py000066400000000000000000000205671361554632000205140ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import os import sys import ast import tempfile import runpy import importlib from fractions import Fraction from importlib import reload import pytest import hy from hy.lex import hy_parse from hy.errors import HyLanguageError from hy.lex.exceptions import PrematureEndOfInput from hy.compiler import hy_eval, hy_compile from hy.importer import HyLoader def test_basics(): "Make sure the basics of the importer work" assert os.path.isfile('tests/resources/__init__.py') resources_mod = importlib.import_module('tests.resources') assert hasattr(resources_mod, 'kwtest') assert os.path.isfile('tests/resources/bin/__init__.hy') bin_mod = importlib.import_module('tests.resources.bin') assert hasattr(bin_mod, '_null_fn_for_import_test') def test_runpy(): # XXX: `runpy` won't update cached bytecode! Don't know if that's # intentional or not. basic_ns = runpy.run_path('tests/resources/importer/basic.hy') assert 'square' in basic_ns main_ns = runpy.run_path('tests/resources/bin') assert main_ns['visited_main'] == 1 del main_ns main_ns = runpy.run_module('tests.resources.bin') assert main_ns['visited_main'] == 1 with pytest.raises(IOError): runpy.run_path('tests/resources/foobarbaz.py') def test_stringer(): _ast = hy_compile(hy_parse("(defn square [x] (* x x))"), __name__) assert type(_ast.body[0]) == ast.FunctionDef def test_imports(): path = os.getcwd() + "/tests/resources/importer/a.hy" testLoader = HyLoader("tests.resources.importer.a", path) def _import_test(): try: return testLoader.load_module() 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." with pytest.raises(HyLanguageError): hy_compile(hy_parse("(import \"sys\")"), __name__) def test_import_error_cleanup(): "Failed initial imports should not leave dead modules in `sys.modules`." with pytest.raises(hy.errors.HyMacroExpansionError): importlib.import_module('tests.resources.fails') assert 'tests.resources.fails' not in sys.modules @pytest.mark.skipif(sys.dont_write_bytecode, reason="Bytecode generation is suppressed") def test_import_autocompiles(): "Test that (import) byte-compiles the module." with tempfile.NamedTemporaryFile(suffix='.hy', delete=True) as f: f.write(b'(defn pyctest [s] (+ "X" s "Y"))') f.flush() pyc_path = importlib.util.cache_from_source(f.name) try: os.remove(pyc_path) except (IOError, OSError): pass test_loader = HyLoader("mymodule", f.name).load_module() assert hasattr(test_loader, 'pyctest') assert os.path.exists(pyc_path) os.remove(pyc_path) def test_eval(): def eval_str(s): return hy_eval(hy.read_str(s), filename='', source=s) assert eval_str('[1 2 3]') == [1, 2, 3] assert eval_str('{"dog" "bark" "cat" "meow"}') == { 'dog': 'bark', 'cat': 'meow'} assert eval_str('(, 1 2 3)') == (1, 2, 3) assert eval_str('#{3 1 2}') == {1, 2, 3} assert eval_str('1/2') == Fraction(1, 2) assert eval_str('(.strip " fooooo ")') == 'fooooo' assert eval_str( '(if True "this is if true" "this is if false")') == "this is if true" assert eval_str('(lfor num (range 100) :if (= (% num 2) 1) (pow num 2))') == [ pow(num, 2) for num in range(100) if num % 2 == 1] def test_reload(): """Generate a test module, confirm that it imports properly (and puts the module in `sys.modules`), then modify the module so that it produces an error when reloaded. Next, fix the error, reload, and check that the module is updated and working fine. Rinse, repeat. This test is adapted from CPython's `test_import.py`. """ def unlink(filename): os.unlink(source) bytecode = importlib.util.cache_from_source(source) if os.path.isfile(bytecode): os.unlink(bytecode) TESTFN = 'testfn' source = TESTFN + os.extsep + "hy" with open(source, "w") as f: f.write("(setv a 1)") f.write("(setv b 2)") sys.path.insert(0, os.curdir) try: mod = importlib.import_module(TESTFN) assert TESTFN in sys.modules assert mod.a == 1 assert mod.b == 2 # On WinXP, just replacing the .py file wasn't enough to # convince reload() to reparse it. Maybe the timestamp didn't # move enough. We force it to get reparsed by removing the # compiled file too. unlink(source) # Now damage the module. with open(source, "w") as f: f.write("(setv a 10)") f.write("(setv b (// 20 0))") with pytest.raises(ZeroDivisionError): reload(mod) # But we still expect the module to be in sys.modules. mod = sys.modules.get(TESTFN) assert mod is not None # We should have replaced a w/ 10, but the old b value should # stick. assert mod.a == 10 assert mod.b == 2 # Now fix the issue and reload the module. unlink(source) with open(source, "w") as f: f.write("(setv a 11)") f.write("(setv b (// 20 1))") reload(mod) mod = sys.modules.get(TESTFN) assert mod is not None assert mod.a == 11 assert mod.b == 20 # Now cause a syntax error unlink(source) with open(source, "w") as f: # Missing paren... f.write("(setv a 11") f.write("(setv b (// 20 1))") with pytest.raises(PrematureEndOfInput): reload(mod) mod = sys.modules.get(TESTFN) assert mod is not None assert mod.a == 11 assert mod.b == 20 # Fix it and retry unlink(source) with open(source, "w") as f: f.write("(setv a 12)") f.write("(setv b (// 10 1))") reload(mod) mod = sys.modules.get(TESTFN) assert mod is not None assert mod.a == 12 assert mod.b == 10 finally: del sys.path[0] if TESTFN in sys.modules: del sys.modules[TESTFN] unlink(source) def test_reload_reexecute(capsys): """A module is re-executed when it's reloaded, even if it's unchanged. https://github.com/hylang/hy/issues/712""" import tests.resources.hello_world assert capsys.readouterr().out == 'hello world\n' assert capsys.readouterr().out == '' reload(tests.resources.hello_world) assert capsys.readouterr().out == 'hello world\n' def test_circular(): """Test circular imports by creating a temporary file/module that calls a function that imports itself.""" sys.path.insert(0, os.path.abspath('tests/resources/importer')) try: mod = runpy.run_module('circular') assert mod['f']() == 1 finally: sys.path.pop(0) def test_shadowed_basename(): """Make sure Hy loads `.hy` files instead of their `.py` counterparts (.e.g `__init__.py` and `__init__.hy`). """ sys.path.insert(0, os.path.realpath('tests/resources/importer')) try: assert os.path.isfile('tests/resources/importer/foo/__init__.hy') assert os.path.isfile('tests/resources/importer/foo/__init__.py') assert os.path.isfile('tests/resources/importer/foo/some_mod.hy') assert os.path.isfile('tests/resources/importer/foo/some_mod.py') foo = importlib.import_module('foo') assert foo.__file__.endswith('foo/__init__.hy') assert foo.ext == 'hy' some_mod = importlib.import_module('foo.some_mod') assert some_mod.__file__.endswith('foo/some_mod.hy') assert some_mod.ext == 'hy' finally: sys.path.pop(0) def test_docstring(): """Make sure a module's docstring is loaded.""" sys.path.insert(0, os.path.realpath('tests/resources/importer')) try: mod = importlib.import_module('docstring') expected_doc = ("This module has a docstring.\n\n" "It covers multiple lines, too!\n") assert mod.__doc__ == expected_doc assert mod.a == 1 finally: sys.path.pop(0) hy-0.18.0/tests/importer/test_pyc.py000066400000000000000000000012071361554632000174340ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import os import importlib.util import py_compile import tempfile import hy.importer def test_pyc(): """Test pyc compilation.""" with tempfile.NamedTemporaryFile(suffix='.hy') as f: f.write(b'(defn pyctest [s] (+ "X" s "Y"))') f.flush() cfile = py_compile.compile(f.name) assert os.path.exists(cfile) try: mod = hy.importer._import_from_path('pyc', cfile) finally: os.remove(cfile) assert mod.pyctest('Foo') == 'XFooY' hy-0.18.0/tests/macros/000077500000000000000000000000001361554632000146535ustar00rootroot00000000000000hy-0.18.0/tests/macros/__init__.py000066400000000000000000000000001361554632000167520ustar00rootroot00000000000000hy-0.18.0/tests/macros/test_macro_processor.py000066400000000000000000000036061361554632000214710ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. from hy.macros import macro, macroexpand from hy.lex import tokenize from hy.models import HyString, HyList, HySymbol, HyExpression, HyFloat from hy.errors import HyMacroExpansionError from hy.compiler import HyASTCompiler import pytest @macro("test") def tmac(ETname, *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], __name__, HyASTCompiler(__name__)) assert obj == HyList(["one", "two"]) assert type(obj) == HyList def test_preprocessor_expression(): """ Test that macro expansion doesn't recurse""" obj = macroexpand(tokenize('(test (test "one" "two"))')[0], __name__, 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, __name__, HyASTCompiler(__name__)) def test_preprocessor_exceptions(): """ Test that macro expansion raises appropriate exceptions""" with pytest.raises(HyMacroExpansionError) as excinfo: macroexpand(tokenize('(defn)')[0], __name__, HyASTCompiler(__name__)) assert "_hy_anon_" not in excinfo.value.msg def test_macroexpand_nan(): # https://github.com/hylang/hy/issues/1574 import math NaN = float('nan') x = macroexpand(HyFloat(NaN), __name__, HyASTCompiler(__name__)) assert type(x) is HyFloat assert math.isnan(x) hy-0.18.0/tests/macros/test_tag_macros.py000066400000000000000000000010761361554632000204070ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. from hy.macros import macroexpand from hy.compiler import HyTypeError, HyASTCompiler from hy.lex import tokenize def test_tag_macro_error(): """Check if we get correct error with wrong dispatch character""" try: macroexpand(tokenize("(dispatch_tag_macro '- '())")[0], __name__, HyASTCompiler(__name__)) except HyTypeError as e: assert "with the character `-`" in str(e) hy-0.18.0/tests/native_tests/000077500000000000000000000000001361554632000160775ustar00rootroot00000000000000hy-0.18.0/tests/native_tests/__init__.py000066400000000000000000000002731361554632000202120ustar00rootroot00000000000000# Note that __init__.py is intentional so pytest (more specifically py.path) # will detect us as a Python package. There's logic there that involves looking # specifically for this file. hy-0.18.0/tests/native_tests/comprehensions.hy000066400000000000000000000135231361554632000215010ustar00rootroot00000000000000(import types pytest) (defn test-comprehension-types [] ; Forms that get compiled to real comprehensions (assert (is (type (lfor x "abc" x)) list)) (assert (is (type (sfor x "abc" x)) set)) (assert (is (type (dfor x "abc" [x x])) dict)) (assert (is (type (gfor x "abc" x)) types.GeneratorType)) ; Forms that get compiled to loops (assert (is (type (lfor x "abc" :do (setv y 1) x)) list)) (assert (is (type (sfor x "abc" :do (setv y 1) x)) set)) (assert (is (type (dfor x "abc" :do (setv y 1) [x x])) dict)) (assert (is (type (gfor x "abc" :do (setv y 1) x)) types.GeneratorType))) #@ ((pytest.mark.parametrize "specialop" ["for" "lfor" "sfor" "gfor" "dfor"]) (defn test-fors [specialop] (setv cases [ ['(f x [] x) []] ['(f j [1 2 3] j) [1 2 3]] ['(f x (range 3) (* x 2)) [0 2 4]] ['(f x (range 2) y (range 2) (, x y)) [(, 0 0) (, 0 1) (, 1 0) (, 1 1)]] ['(f (, x y) (.items {"1" 1 "2" 2}) (* y 2)) [2 4]] ['(f x (do (setv s "x") "ab") y (do (+= s "y") "def") (+ x y s)) ["adxy" "aexy" "afxy" "bdxyy" "bexyy" "bfxyy"]] ['(f x (range 4) :if (% x 2) (* x 2)) [2 6]] ['(f x "abc" :setv y (.upper x) (+ x y)) ["aA" "bB" "cC"]] ['(f x "abc" :do (setv y (.upper x)) (+ x y)) ["aA" "bB" "cC"]] ['(f x (range 3) y (range 3) :if (> y x) z [7 8 9] :setv s (+ x y z) :if (!= z 8) (, x y z s)) [(, 0 1 7 8) (, 0 1 9 10) (, 0 2 7 9) (, 0 2 9 11) (, 1 2 7 10) (, 1 2 9 12)]] ['(f x [0 1] :setv l [] y (range 4) :do (.append l (, x y)) :if (>= y 2) z [7 8 9] :if (!= z 8) (, x y (tuple l) z)) [(, 0 2 (, (, 0 0) (, 0 1) (, 0 2)) 7) (, 0 2 (, (, 0 0) (, 0 1) (, 0 2)) 9) (, 0 3 (, (, 0 0) (, 0 1) (, 0 2) (, 0 3)) 7) (, 0 3 (, (, 0 0) (, 0 1) (, 0 2) (, 0 3)) 9) (, 1 2 (, (, 1 0) (, 1 1) (, 1 2)) 7) (, 1 2 (, (, 1 0) (, 1 1) (, 1 2)) 9) (, 1 3 (, (, 1 0) (, 1 1) (, 1 2) (, 1 3)) 7) (, 1 3 (, (, 1 0) (, 1 1) (, 1 2) (, 1 3)) 9)]] ['(f x (range 4) :do (unless (% x 2) (continue)) (* x 2)) [2 6]] ['(f x (range 4) :setv p 9 :do (unless (% x 2) (continue)) (* x 2)) [2 6]] ['(f x (range 20) :do (when (= x 3) (break)) (* x 2)) [0 2 4]] ['(f x (range 20) :setv p 9 :do (when (= x 3) (break)) (* x 2)) [0 2 4]] ['(f x [4 5] y (range 20) :do (when (> y 1) (break)) z [8 9] (, x y z)) [(, 4 0 8) (, 4 0 9) (, 4 1 8) (, 4 1 9) (, 5 0 8) (, 5 0 9) (, 5 1 8) (, 5 1 9)]]]) (for [[expr answer] cases] ; Mutate the case as appropriate for the operator before ; evaluating it. (setv expr (+ (HyExpression [(HySymbol specialop)]) (cut expr 1))) (when (= specialop "dfor") (setv expr (+ (cut expr 0 -1) `([~(get expr -1) 1])))) (when (= specialop "for") (setv expr `(do (setv out []) (for [~@(cut expr 1 -1)] (.append out ~(get expr -1))) out))) (setv result (eval expr)) (when (= specialop "dfor") (setv result (.keys result))) (assert (= (sorted result) answer) (str expr))))) (defn test-fors-no-loopers [] (setv l []) (for [] (.append l 1)) (assert (= l [])) (assert (= (lfor 1) [])) (assert (= (sfor 1) #{})) (assert (= (list (gfor 1)) [])) (assert (= (dfor [1 2]) {}))) (defn test-raise-in-comp [] (defclass E [Exception] []) (setv l []) (import pytest) (with [(pytest.raises E)] (lfor x (range 10) :do (.append l x) :do (when (= x 5) (raise (E))) x)) (assert (= l [0 1 2 3 4 5]))) (defn test-scoping [] (setv x 0) (for [x [1 2 3]]) (assert (= x 3)) ; An `lfor` that gets compiled to a real comprehension (setv x 0) (assert (= (lfor x [1 2 3] (inc x)) [2 3 4])) (assert (= x 0)) ; An `lfor` that gets compiled to a loop (setv x 0 l []) (assert (= (lfor x [4 5 6] :do (.append l 1) (inc x)) [5 6 7])) (assert (= l [1 1 1])) (assert (= x 0)) ; An `sfor` that gets compiled to a real comprehension (setv x 0) (assert (= (sfor x [1 2 3] (inc x)) #{2 3 4})) (assert (= x 0))) (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)) (setv count 0) ; multiple statements in the else branch should work (for [x [1 2 3 4 5] y [1 2 3 4 5]] (setv count (+ count x y)) (else (+= count 1) (+= count 10))) (assert (= count 161)) ; don't be fooled by constructs that look like else (setv s "") (setv else True) (for [x "abcde"] (+= s x) [else (+= s "_")]) (assert (= s "a_b_c_d_e_")) (setv s "") (with [(pytest.raises TypeError)] (for [x "abcde"] (+= s x) ("else" (+= s "z")))) (assert (= s "az")) (assert (= (list ((fn [] (for [x [[1] [2 3]] y x] (yield y))))) (lfor x [[1] [2 3]] y x y))) (assert (= (list ((fn [] (for [x [[1] [2 3]] y x z (range 5)] (yield z))))) (lfor x [[1] [2 3]] y x z (range 5) z)))) (defn test-nasty-for-nesting [] "NATIVE: test nesting for loops harder" ;; This test and feature is dedicated to @nedbat. ;; 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-empty-for [] (setv l []) (defn f [] (for [x (range 3)] (.append l "a") (yield x))) (for [x (f)]) (assert (= l ["a" "a" "a"])) (setv l []) (for [x (f)] (else (.append l "z"))) (assert (= l ["a" "a" "a" "z"]))) hy-0.18.0/tests/native_tests/contrib/000077500000000000000000000000001361554632000175375ustar00rootroot00000000000000hy-0.18.0/tests/native_tests/contrib/__init__.hy000066400000000000000000000000001361554632000216260ustar00rootroot00000000000000hy-0.18.0/tests/native_tests/contrib/hy_repr.hy000066400000000000000000000131701361554632000215530ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (import [hy._compat [PY36 PY37]] [math [isnan]] [hy.contrib.hy-repr [hy-repr hy-repr-register]]) (defn test-hy-repr-roundtrip-from-value [] ; Test that a variety of values round-trip properly. (setv values [ None False True 5 5.1 '5 '5.1 Inf -Inf (int 5) 1/2 5j 5.1j 2+1j 1.2+3.4j Inf-Infj "" b"" '"" 'b"" "apple bloom" b"apple bloom" "⚘" '"apple bloom" 'b"apple bloom" '"⚘" "single ' quotes" b"single ' quotes" "\"double \" quotes\"" b"\"double \" quotes\"" 'mysymbol :mykeyword [] (,) #{} (frozenset #{}) '[] '(,) '#{} '(frozenset #{}) '['[]] '(+ 1 2) [1 2 3] (, 1 2 3) #{1 2 3} (frozenset #{1 2 3}) '[1 2 3] '(, 1 2 3) '#{1 2 3} '(frozenset #{1 2 3}) {"a" 1 "b" 2 "a" 3} '{"a" 1 "b" 2 "a" 3} [1 [2 3] (, 4 (, 'mysymbol :mykeyword)) {"a" b"hello"} '(f #* a #** b)] '[1 [2 3] (, 4 (, mysymbol :mykeyword)) {"a" b"hello"} (f #* a #** b)]]) (for [original-val values] (setv evaled (eval (read-str (hy-repr original-val)))) (assert (= evaled original-val)) (assert (is (type evaled) (type original-val)))) (assert (isnan (eval (read-str (hy-repr NaN)))))) (defn test-hy-repr-roundtrip-from-str [] (setv strs [ "'Inf" "'-Inf" "'NaN" "1+2j" "NaN+NaNj" "'NaN+NaNj" "[1 2 3]" "'[1 2 3]" "[1 'a 3]" "'[1 a 3]" "'[1 'a 3]" "[1 '[2 3] 4]" "'[1 [2 3] 4]" "'[1 '[2 3] 4]" "'[1 `[2 3] 4]" "'[1 `[~foo ~@bar] 4]" "'[1 `[~(+ 1 2) ~@(+ [1] [2])] 4]" "'[1 `[~(do (print x 'y) 1)] 4]" "{1 20}" "'{1 10 1 20}" "'asymbol" ":akeyword" "'(f #* args #** kwargs)"]) (for [original-str strs] (setv rep (hy-repr (eval (read-str original-str)))) (assert (= rep original-str)))) (defn test-hy-repr-no-roundtrip [] ; Test one of the corner cases in which hy-repr doesn't ; round-trip: when a HyObject contains a non-HyObject, we ; promote the constituent to a HyObject. (setv orig `[a ~5.0]) (setv reprd (hy-repr orig)) (assert (= reprd "'[a 5.0]")) (setv result (eval (read-str reprd))) (assert (is (type (get orig 1)) float)) (assert (is (type (get result 1)) HyFloat))) (defn test-dict-views [] (assert (= (hy-repr (.keys {1 2})) "(dict-keys [1])")) (assert (= (hy-repr (.values {1 2})) "(dict-values [2])")) (assert (= (hy-repr (.items {1 2})) "(dict-items [(, 1 2)])"))) (defn test-datetime [] (import [datetime :as D]) (assert (= (hy-repr (D.datetime 2009 1 15 15 27 5 0)) "(datetime.datetime 2009 1 15 15 27 5)")) (assert (= (hy-repr (D.datetime 2009 1 15 15 27 5 123)) "(datetime.datetime 2009 1 15 15 27 5 123)")) (assert (= (hy-repr (D.datetime 2009 1 15 15 27 5 123 :tzinfo D.timezone.utc)) "(datetime.datetime 2009 1 15 15 27 5 123 :tzinfo datetime.timezone.utc)")) (when PY36 (assert (= (hy-repr (D.datetime 2009 1 15 15 27 5 :fold 1)) "(datetime.datetime 2009 1 15 15 27 5 :fold 1)")) (assert (= (hy-repr (D.datetime 2009 1 15 15 27 5 :fold 1 :tzinfo D.timezone.utc)) "(datetime.datetime 2009 1 15 15 27 5 :tzinfo datetime.timezone.utc :fold 1)"))) (assert (= (hy-repr (D.date 2015 11 3)) "(datetime.date 2015 11 3)")) (assert (= (hy-repr (D.time 1 2 3)) "(datetime.time 1 2 3)")) (assert (= (hy-repr (D.time 1 2 3 4567)) "(datetime.time 1 2 3 4567)")) (when PY36 (assert (= (hy-repr (D.time 1 2 3 4567 :fold 1 :tzinfo D.timezone.utc)) "(datetime.time 1 2 3 4567 :tzinfo datetime.timezone.utc :fold 1)")))) (defn test-collections [] (import collections) (assert (= (hy-repr (collections.defaultdict :a 8)) "(defaultdict None {\"a\" 8})")) (assert (= (hy-repr (collections.defaultdict int :a 8)) "(defaultdict {\"a\" 8})")) (assert (= (hy-repr (collections.Counter [15 15 15 15])) "(Counter {15 4})")) (setv C (collections.namedtuple "Fooey" ["cd" "a_b"])) (assert (= (hy-repr (C 11 12)) "(Fooey :cd 11 :a_b 12)"))) (defn test-hy-model-constructors [] (import hy) (assert (= (hy-repr (hy.HyInteger 7)) "'7")) (assert (= (hy-repr (hy.HyString "hello")) "'\"hello\"")) (assert (= (hy-repr (hy.HyList [1 2 3])) "'[1 2 3]")) (assert (= (hy-repr (hy.HyDict [1 2 3])) "'{1 2 3}"))) (defn test-hy-repr-self-reference [] (setv x [1 2 3]) (setv (get x 1) x) (assert (= (hy-repr x) "[1 [...] 3]")) (setv x {1 2 3 [4 5] 6 7}) (setv (get x 3 1) x) (assert (in (hy-repr x) (lfor ; The ordering of a dictionary isn't guaranteed, so we need ; to check for all possible orderings. p (permutations ["1 2" "3 [4 {...}]" "6 7"]) (+ "{" (.join " " p) "}"))))) (defn test-matchobject [] (import re) (setv mo (re.search "b+" "aaaabbbccc")) (assert (= (hy-repr mo) (.format #[[<{} object; :span (, 4 7) :match "bbb">]] (if PY37 "re.Match" (+ (. (type mo) __module__) ".SRE_Match")))))) (defn test-hy-repr-custom [] (defclass C [object]) (hy-repr-register C (fn [x] "cuddles")) (assert (= (hy-repr (C)) "cuddles")) (defclass Container [object] (defn __init__ [self value] (setv self.value value))) (hy-repr-register Container :placeholder "(Container ...)" (fn [x] (+ "(Container " (hy-repr x.value) ")"))) (setv container (Container 5)) (setv container.value container) (assert (= (hy-repr container) "(Container (Container ...))")) (setv container.value [1 container 3]) (assert (= (hy-repr container) "(Container [1 (Container ...) 3])"))) (defn test-hy-repr-fallback [] (defclass D [object] (defn __repr__ [self] "cuddles")) (assert (= (hy-repr (D)) "cuddles"))) hy-0.18.0/tests/native_tests/contrib/loop.hy000066400000000000000000000022501361554632000210510ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (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)))) (defn test-recur-string [] "test that `loop` doesn't touch a string named `recur`" (assert (= (loop [] (+ "recur" "1")) "recur1"))) hy-0.18.0/tests/native_tests/contrib/sequences.hy000066400000000000000000000060431361554632000220770ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (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.18.0/tests/native_tests/contrib/walk.hy000066400000000000000000000205331361554632000210420ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (import [hy.contrib.walk [*]]) (require [hy.contrib.walk [*]]) (import pytest) (setv walk-form '(print {"foo" "bar" "array" [1 2 3 [4]] "something" (+ 1 2 3 4) "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 [] (setv acc []) (assert (= (list (walk (partial collector acc) identity walk-form)) [None None])) (assert (= acc (list walk-form))) (setv acc []) (assert (= (walk identity (partial collector acc) walk-form) None)) (assert (= acc [walk-form]))) (defn test-walk-iterators [] (assert (= (walk (fn [x] (* 2 x)) (fn [x] x) (drop 1 [1 [2 [3 [4]]]])) [[2 [3 [4]] 2 [3 [4]]]]))) (defmacro foo-walk [] 42) (defn test-macroexpand-all [] ;; make sure a macro from the current module works (assert (= (macroexpand-all '(foo-walk)) 42)) (assert (= (macroexpand-all '(with [a 1])) '(with* [a 1]))) (assert (= (macroexpand-all '(with [a 1 b 2 c 3] (for [d c] foo))) '(with* [a 1] (with* [b 2] (with* [c 3] (for [d c] foo)))))) (assert (= (macroexpand-all '(with [a 1] '(with [b 2]) `(with [c 3] ~(with [d 4]) ~@[(with [e 5])]))) '(with* [a 1] '(with [b 2]) `(with [c 3] ~(with* [d 4]) ~@[(with* [e 5])])))) (defmacro require-macro [] `(do (require [tests.resources.macros [test-macro :as my-test-macro]]) (my-test-macro))) (assert (= (last (macroexpand-all '(require-macro))) '(setv blah 1)))) (defn test-let-basic [] (assert (zero? (let [a 0] a))) (setv a "a" b "b") (let [a "x" b "y"] (assert (= (+ a b) "xy")) (let [a "z"] (assert (= (+ a b) "zy"))) ;; let-shadowed variable doesn't get clobbered. (assert (= (+ a b) "xy"))) (let [q "q"] (assert (= q "q"))) (assert (= a "a")) (assert (= b "b")) (assert (in "a" (.keys (vars)))) ;; scope of q is limited to let body (assert (not-in "q" (.keys (vars))))) (defn test-let-sequence [] ;; assignments happen in sequence, not parallel. (let [a "a" b "b" ab (+ a b)] (assert (= ab "ab")) (let [c "c" abc (+ ab c)] (assert (= abc "abc"))))) (defn test-let-early [] (setv a "a") (let [q (+ a "x") a 2 ; should not affect q b 3] (assert (= q "ax")) (let [q (* a b) a (+ a b) b (* a b)] (assert (= q 6)) (assert (= a 5)) (assert (= b 15)))) (assert (= a "a"))) (defn test-let-special [] ;; special forms in function position still work as normal (let [, 1] (assert (= (, , ,) (, 1 1))))) (defn test-let-quasiquote [] (setv a-symbol 'a) (let [a "x"] (assert (= a "x")) (assert (= 'a a-symbol)) (assert (= `a a-symbol)) (assert (= `(foo ~a) '(foo "x"))) (assert (= `(foo `(bar a ~a ~~a)) '(foo `(bar a ~a ~"x")))) (assert (= `(foo ~@[a]) '(foo "x"))) (assert (= `(foo `(bar [a] ~@[a] ~@~(HyList [a 'a `a]) ~~@[a])) '(foo `(bar [a] ~@[a] ~@["x" a a] ~"x")))))) (defn test-let-except [] (let [foo 42 bar 33] (assert (= foo 42)) (try (do 1/0 (assert False)) (except [foo Exception] ;; let bindings should work in except block (assert (= bar 33)) ;; but exception bindings can shadow let bindings (assert (instance? Exception foo)))) ;; let binding did not get clobbered. (assert (= foo 42)))) (defn test-let-mutation [] (setv foo 42) (setv error False) (let [foo 12 bar 13] (assert (= foo 12)) (setv foo 14) (assert (= foo 14)) (del foo) ;; deleting a let binding should not affect others (assert (= bar 13)) (try ;; foo=42 is still shadowed, but the let binding was deleted. (do foo (assert False)) (except [le LookupError] (setv error le))) (setv foo 16) (assert (= foo 16)) (setv [foo bar baz] [1 2 3]) (assert (= foo 1)) (assert (= bar 2)) (assert (= baz 3))) (assert error) (assert (= foo 42)) (assert (= baz 3))) (defn test-let-break [] (for [x (range 3)] (let [done (odd? x)] (if done (break)))) (assert (= x 1))) (defn test-let-continue [] (let [foo []] (for [x (range 10)] (let [odd (odd? x)] (if odd (continue)) (.append foo x))) (assert (= foo [0 2 4 6 8])))) (defn test-let-yield [] (defn grind [] (yield 0) (let [a 1 b 2] (yield a) (yield b))) (assert (= (tuple (grind)) (, 0 1 2)))) (defn test-let-return [] (defn get-answer [] (let [answer 42] (return answer))) (assert (= (get-answer) 42))) (defn test-let-import [] (let [types 6] ;; imports don't fail, even if using a let-bound name (import types) ;; let-bound name is not affected (assert (= types 6))) ;; import happened in Python scope. (assert (in "types" (vars))) (assert (instance? types.ModuleType types))) (defn test-let-defclass [] (let [Foo 42 quux object] ;; the name of the class is just a symbol, even if it's a let binding (defclass Foo [quux] ; let bindings apply in inheritance list ;; let bindings apply inside class body (setv x Foo) ;; quux is not local (setv quux "quux")) (assert (= quux "quux"))) ;; defclass always creates a python-scoped variable, even if it's a let binding name (assert (= Foo.x 42))) (defn test-let-dot [] (setv foo (fn []) foo.a 42) (let [a 1 b [] bar (fn [])] (setv bar.a 13) (assert (= bar.a 13)) (setv (. bar a) 14) (assert (= bar.a 14)) (assert (= a 1)) (assert (= b [])) ;; method syntax not affected (.append b 2) (assert (= b [2])) ;; attrs access is not affected (assert (= foo.a 42)) (assert (= (. foo a) 42)) ;; but indexing is (assert (= (. [1 2 3] [a]) 2)))) (defn test-let-positional [] (let [a 0 b 1 c 2] (defn foo [a b] (, a b c)) (assert (= (foo 100 200) (, 100 200 2))) (setv c 300) (assert (= (foo 1000 2000) (, 1000 2000 300))) (assert (= a 0)) (assert (= b 1)) (assert (= c 300)))) (defn test-let-rest [] (let [xs 6 a 88 c 64 &rest 12] (defn foo [a b &rest xs] (-= a 1) (setv xs (list xs)) (.append xs 42) (, &rest a b c xs)) (assert (= xs 6)) (assert (= a 88)) (assert (= (foo 1 2 3 4) (, 12 0 2 64 [3 4 42]))) (assert (= xs 6)) (assert (= c 64)) (assert (= a 88)))) (defn test-let-kwargs [] (let [kws 6 &kwargs 13] (defn foo [&kwargs kws] (, &kwargs kws)) (assert (= kws 6)) (assert (= (foo :a 1) (, 13 {"a" 1}))))) (defn test-let-optional [] (let [a 1 b 6 d 2] (defn foo [&optional [a a] b [c d]] (, a b c)) (assert (= (foo) (, 1 None 2))) (assert (= (foo 10 20 30) (, 10 20 30))))) (defn test-let-closure [] (let [count 0] (defn +count [&optional [x 1]] (+= count x) count)) ;; let bindings can still exist outside of a let body (assert (= 1 (+count))) (assert (= 2 (+count))) (assert (= 42 (+count 40)))) (defmacro triple [a] (setv g!a (gensym a)) `(do (setv ~g!a ~a) (+ ~g!a ~g!a ~g!a))) (defmacro ap-triple [] '(+ a a a)) (defn test-let-macros [] (let [a 1 b (triple a) c (ap-triple)] (assert (= (triple a) 3)) (assert (= (ap-triple) 3)) (assert (= b 3)) (assert (= c 3)))) (defn test-let-rebind [] (let [x "foo" y "bar" x (+ x y) y (+ y x) x (+ x x)] (assert (= x "foobarfoobar")) (assert (= y "barfoobar")))) hy-0.18.0/tests/native_tests/core.hy000066400000000000000000000552521361554632000174020ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;;;; 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 y 12) (setv x y) (assert-equal x 12) (assert-equal y 12) (setv y (fn [x] 9)) (setv x y) (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? []))) (setv globalvar 1) (defn test-exec [] (setv localvar 1) (setv code " result['localvar in locals'] = 'localvar' in locals() result['localvar in globals'] = 'localvar' in globals() result['globalvar in locals'] = 'globalvar' in locals() result['globalvar in globals'] = 'globalvar' in globals() result['x in locals'] = 'x' in locals() result['x in globals'] = 'x' in globals() result['y in locals'] = 'y' in locals() result['y in globals'] = 'y' in globals()") (setv result {}) (exec code) (assert-true (get result "localvar in locals")) (assert-false (get result "localvar in globals")) (assert-false (get result "globalvar in locals")) (assert-true (get result "globalvar in globals")) (assert-false (or (get result "x in locals") (get result "x in globals") (get result "y in locals") (get result "y in globals"))) (setv result {}) (exec code {"x" 1 "result" result}) (assert-false (or (get result "localvar in locals") (get result "localvar in globals") (get result "globalvar in locals") (get result "globalvar in globals"))) (assert-true (and (get result "x in locals") (get result "x in globals"))) (assert-false (or (get result "y in locals") (get result "y in globals"))) (setv result {}) (exec code {"x" 1 "result" result} {"y" 1}) (assert-false (or (get result "localvar in locals") (get result "localvar in globals") (get result "globalvar in locals") (get result "globalvar in globals"))) (assert-false (get result "x in locals")) (assert-true (get result "x in globals")) (assert-true (get result "y in locals")) (assert-false (get result "y in globals"))) (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-list? [] "NATIVE: testing the list? function" (assert-false (list? "hello")) (assert-true (list? [1 2 3]))) (defn test-tuple? [] "NATIVE: testing the tuple? function" (assert-false (tuple? [4 5])) (assert-true (tuple? (, 4 5)))) (defn test-gensym [] "NATIVE: testing the gensym function" (import [hy.models [HySymbol]]) (setv s1 (gensym)) (assert (isinstance s1 HySymbol)) (assert (= 0 (.find s1 "_G\uffff"))) (setv s2 (gensym "xx")) (setv s3 (gensym "xx")) (assert (= 0 (.find s2 "_xx\uffff"))) (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] (defn __add__ [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? (int "-3"))) (assert-true (integer? (int 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 (int 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)) (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-parse-args [] "NATIVE: testing the parse-args function" (setv parsed-args (parse-args [["strings" :nargs "+" :help "Strings"] ["-n" "--numbers" :action "append" :type 'int :help "Numbers"]] ["a" "b" "-n" "1" "-n" "2"] :description "Parse strings and numbers from args")) (assert-equal parsed-args.strings ["a" "b"]) (assert-equal parsed-args.numbers [1 2])) (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)]) ;; length 0 returns an empty sequence (assert-equal (list (partition ten 0)) []) ;; negative length raises ValueError (try (do (partition ten -1) (assert False)) (except [ValueError])) ;; 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)]) ;; tee the input as necessary ;; https://github.com/hylang/hy/issues/1237 (assert-equal (list (take 4 (partition (cycle [1 2 3]) 3))) [(, 1 2 3) (, 1 2 3) (, 1 2 3) (, 1 2 3)]) (assert-equal (list (partition (iter (range 10)))) [(, 0 1) (, 2 3) (, 4 5) (, 6 7) (, 8 9)])) (defn test-pos [] "NATIVE: testing the pos? function" (assert-true (pos? 2)) (assert-false (pos? -1)) (assert-false (pos? 0)) (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 (setv 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)) (setv x :bar) (assert (keyword? x)) (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-complement [] "NATIVE: test complement" (setv helper (complement identity)) (assert-true (helper False)) (assert-false (helper True))) (defn test-constantly [] "NATIVE: test constantly" (setv 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])) (defn test-comment [] (assert-none (comment

    This is merely a comment.

    Move along. (Nothing to see here.)

    ))) (defn test-doc [capsys] (doc doc) (setv out_err (.readouterr capsys)) (assert (.startswith (.strip (first out_err)) "Help on function doc in module hy.core.macros:")) (assert (empty? (second out_err)))) hy-0.18.0/tests/native_tests/defclass.hy000066400000000000000000000063711361554632000202340ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (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 [] (setv x 42)) (assert (= A.x 42)) (assert (= (getattr (A) "x") 42))) (defn test-defclass-attrs-fn [] "NATIVE: test defclass attributes with fn" (defclass B [] (setv x 42) (setv y (fn [self value] (+ self.x value)))) (assert (= B.x 42)) (assert (= (.y (B) 5) 47)) (setv 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)))] (setv x 42)) (assert (isinstance (A) list)) (defclass A [((fn [] (if False list dict)))] (setv x 42)) (assert (isinstance (A) dict))) (defn test-defclass-no-fn-leak [] "NATIVE: test defclass attributes with fn" (defclass A [] (setv x (fn [] 1))) (try (do (x) (assert False)) (except [NameError]))) (defn test-defclass-docstring [] "NATIVE: test defclass docstring" (defclass A [] (setv --doc-- "doc string") (setv x 1)) (setv a (A)) (assert (= a.__doc__ "doc string")) (defclass B [] "doc string" (setv 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." (setv 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 [] (setv x 1) (setv 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 [] (setv --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))) (defn test-class-sideeffects [] "NATIVE: test that defclass runs all expressions" (defn set-sentinel [] (setv set-sentinel.set True)) (setv set-sentinel.set False) (defclass A [] (set-sentinel)) (assert set-sentinel.set)) hy-0.18.0/tests/native_tests/extra/000077500000000000000000000000001361554632000172225ustar00rootroot00000000000000hy-0.18.0/tests/native_tests/extra/__init__.hy000066400000000000000000000000001361554632000213110ustar00rootroot00000000000000hy-0.18.0/tests/native_tests/extra/anaphoric.hy000066400000000000000000000100561361554632000215320ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (import [hy.errors [HyMacroExpansionError]]) (require [hy.extra.anaphoric [*]]) (defn test-ap-if [] (ap-if True (assert (is it True))) (ap-if False True (assert (is it False))) ; https://github.com/hylang/hy/issues/1847 (setv it "orig") (setv out (ap-if (+ 1 1) (+ it 1) (+ it 10))) (assert (= out 3)) (assert (= it "orig"))) (defn test-ap-each [] (setv res []) (assert (is (ap-each [1 2 3 4] (.append res it)) None)) (assert (= res [1 2 3 4]))) (defn test-ap-each-while [] (setv res []) (ap-each-while [2 2 4 3 4 5 6] (even? it) (.append res it)) (assert (= res [2 2 4]))) (defn test-ap-map [] (assert (= (list (ap-map (* it 3) [1 2 3])) [3 6 9])) (assert (= (list (ap-map (* it 3) [])) [])) (assert (= (do (setv v 1 f 1) (list (ap-map (it v f) [(fn [a b] (+ a b))]))) [2]))) (defn test-ap-map-when [] (assert (= (list (ap-map-when even? (* it 2) [1 2 3 4])) [1 4 3 8]))) (defn test-ap-filter [] (assert (= (list (ap-filter (> it 2) [1 2 3 4])) [3 4])) (assert (= (list (ap-filter (even? it) [1 2 3 4])) [2 4]))) (defn test-ap-reject [] (assert (= (list (ap-reject (> it 2) [1 2 3 4])) [1 2])) (assert (= (list (ap-reject (even? it) [1 2 3 4])) [1 3]))) (defn test-ap-dotimes [] (assert (= (do (setv n []) (ap-dotimes 3 (.append n 3)) n) [3 3 3])) (assert (= (do (setv n []) (ap-dotimes 3 (.append n it)) n) [0 1 2])) ; https://github.com/hylang/hy/issues/1853 (setv n 5) (setv x "") (ap-dotimes n (+= x ".")) (assert (= x "....."))) (defn test-ap-first [] (assert (= (ap-first (> it 5) (range 10)) 6)) (assert (= (ap-first (even? it) [1 2 3 4]) 2)) (assert (= (ap-first (> it 10) (range 10)) None))) (defn test-ap-last [] (assert (= (ap-last (> it 5) (range 10)) 9)) (assert (= (ap-last (even? it) [1 2 3 4]) 4)) (assert (= (ap-last (> it 10) (range 10)) None))) (defn test-ap-reduce [] (assert (= (ap-reduce (* acc it) [1 2 3]) 6)) (assert (= (ap-reduce (* acc it) [1 2 3] 6) 36)) (assert (= (ap-reduce (+ acc " on " it) ["Hy" "meth"]) "Hy on meth")) (assert (= (ap-reduce (+ acc it) [] 1) 1)) ; https://github.com/hylang/hy/issues/1848 (assert (= (ap-reduce (* acc it) (map inc [1 2 3])) 24)) (assert (= (ap-reduce (* acc it) (map inc [1 2 3]) 4) 96)) (setv expr-evaluated 0) (assert (= (ap-reduce (* acc it) (do (+= expr-evaluated 1) [4 5 6]))) 120) (assert (= expr-evaluated 1))) (defn test-tag-fn [] ;; test ordering (assert (= (#%(/ %1 %2) 2 4) 0.5)) (assert (= (#%(/ %2 %1) 2 4) 2)) (assert (= (#%(identity (, %5 %4 %3 %2 %1)) 1 2 3 4 5) (, 5 4 3 2 1))) (assert (= (#%(identity (, %1 %2 %3 %4 %5)) 1 2 3 4 5) (, 1 2 3 4 5))) (assert (= (#%(identity (, %1 %5 %2 %3 %4)) 1 2 3 4 5) (, 1 5 2 3 4))) ;; test &rest (assert (= (#%(sum %*) 1 2 3) 6)) (assert (= (#%(identity (, %1 %*)) 10 1 2 3) (, 10 (, 1 2 3)))) ;; no parameters (assert (= (#%(list)) [])) (assert (= (#%(identity "Hy!")) "Hy!")) (assert (= (#%(identity "%*")) "%*")) (assert (= (#%(+ "Hy " "world!")) "Hy world!")) ;; test skipped parameters (assert (= (#%(identity [%3 %1]) 1 2 3) [3 1])) ;; test nesting (assert (= (#%(identity [%1 (, %2 [%3] "Hy" [%*])]) 1 2 3 4 5) [1 (, 2 [3] "Hy" [(, 4 5)])])) ;; test arg as function (assert (= (#%(%1 2 4) +) 6)) (assert (= (#%(%1 2 4) -) -2)) (assert (= (#%(%1 2 4) /) 0.5)) ;; test &rest &kwargs (assert (= (#%(, %* %**) 1 2 :a 'b) (, (, 1 2) (dict :a 'b)))) ;; test other expression types (assert (= (#% %* 1 2 3) (, 1 2 3))) (assert (= (#% %** :foo 2) (dict :foo 2))) (assert (= (#%[%3 %2 %1] 1 2 3) [3 2 1])) (assert (= (#%{%1 %2} 10 100) {10 100})) (assert (= (#% #{%3 %2 %1} 1 3 2) #{3 1 2})) ; sets are not ordered. (assert (= (#% "%1") "%1"))) hy-0.18.0/tests/native_tests/extra/anaphoric_single.hy000066400000000000000000000006671361554632000231020ustar00rootroot00000000000000;; Copyright 2019 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (require [hy.extra.anaphoric [ap-last]]) (defn test-anaphoric-single-require [] ; https://github.com/hylang/hy/issues/1853#issuecomment-568192529 ; `ap-last` should work even if `require`d without anything else ; from the anaphoric module. (assert (= (ap-last (> it 0) [-1 1 0 3 2 0 -1]) 2))) hy-0.18.0/tests/native_tests/extra/reserved.hy000066400000000000000000000010231361554632000213770ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (import [hy.extra.reserved [names]]) (defn test-reserved [] (assert (is (type (names)) frozenset)) (assert (in "and" (names))) (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)))) hy-0.18.0/tests/native_tests/language.hy000066400000000000000000001422131361554632000202270ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (import [tests.resources [kwtest function-with-a-dash]] [os.path [exists isdir isfile]] [sys :as systest] re [operator [or_]] [hy.errors [HyLanguageError]] pytest) (import sys) (import [hy._compat [PY38]]) (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-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 names Python can't assign to and that we can't mangle" (try (eval '(setv None 1)) (except [e [SyntaxError]] (assert (in "illegal target for assignment" (str e))))) (try (eval '(defn None [] (print "hello"))) (except [e [SyntaxError]] (assert (in "illegal target for assignment" (str e))))) (try (eval '(setv False 1)) (except [e [SyntaxError]] (assert (in "illegal target for assignment" (str e))))) (try (eval '(setv True 0)) (except [e [SyntaxError]] (assert (in "illegal target for assignment" (str e))))) (try (eval '(defn True [] (print "hello"))) (except [e [SyntaxError]] (assert (in "illegal target for assignment" (str e)))))) (defn test-setv-pairs [] "NATIVE: test that setv works on pairs of arguments" (setv a 1 b 2) (assert (= a 1)) (assert (= b 2)) (setv y 0 x 1 y x) (assert (= y 1)) (with [(pytest.raises HyLanguageError)] (eval '(setv a 1 b)))) (defn test-setv-returns-none [] "NATIVE: test that setv always returns None" (assert (none? (setv))) (assert (none? (setv x 1))) (assert (= x 1)) (assert (none? (setv x 2))) (assert (= x 2)) (assert (none? (setv y 2 z 3))) (assert (= y 2)) (assert (= z 3)) (assert (none? (setv [y z] [7 8]))) (assert (= y 7)) (assert (= z 8)) (assert (none? (setv (, y z) [9 10]))) (assert (= y 9)) (assert (= z 10)) (setv p 11) (setv p (setv q 12)) (assert (= q 12)) (assert (none? p)) (assert (none? (setv x (defn phooey [] (setv p 1) (+ p 6))))) (assert (none? (setv x (defclass C)))) (assert (none? (setv x (for [i (range 3)] i (inc i))))) (assert (none? (setv x (assert True)))) (assert (none? (setv x (with [(open "README.md" "r")] 3)))) (assert (= x 3)) (assert (none? (setv x (try (/ 1 2) (except [ZeroDivisionError] "E1"))))) (assert (= x .5)) (assert (none? (setv x (try (/ 1 0) (except [ZeroDivisionError] "E2"))))) (assert (= x "E2")) ; https://github.com/hylang/hy/issues/1052 (assert (none? (setv (get {} "x") 42))) (setv l []) (defclass Foo [object] (defn __setattr__ [self attr val] (.append l [attr val]))) (setv x (Foo)) (assert (none? (setv x.eggs "ham"))) (assert (not (hasattr x "eggs"))) (assert (= l [["eggs" "ham"]]))) (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 HyLanguageError] (assert (= e.msg "Can't assign or delete a non-expression")))) (try (do (eval '(setv 1 1)) (assert False)) (except [e HyLanguageError] (assert (= e.msg "Can't assign or delete a HyInteger")))) (try (do (eval '(setv {1 2} 1)) (assert False)) (except [e HyLanguageError] (assert (= e.msg "Can't assign or delete a HyDict")))) (try (do (eval '(del 1 1)) (assert False)) (except [e HyLanguageError] (assert (= e.msg "Can't assign or delete a HyInteger"))))) (defn test-no-str-as-sym [] "Don't treat strings as symbols in the calling position" (with [(pytest.raises TypeError)] ("setv" True 3)) ; A special form (with [(pytest.raises TypeError)] ("abs" -2)) ; A function (with [(pytest.raises TypeError)] ("when" 1 2))) ; A macro (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)) (setv l []) (defn f [] (.append l 1) (len l)) (while (!= (f) 4)) (assert (= l [1 1 1 1])) (setv l []) (defn f [] (.append l 1) (len l)) (while (!= (f) 4) (do)) (assert (= l [1 1 1 1])) ; only compile the condition once ; https://github.com/hylang/hy/issues/1790 (global while-cond-var) (setv while-cond-var 10) (eval '(do (defmacro while-cond [] (global while-cond-var) (assert (= while-cond-var 10)) (+= while-cond-var 1) `(do (setv x 3) False)) (while (while-cond)) (assert (= x 3))))) (defn test-while-loop-else [] (setv count 5) (setv fact 1) (setv myvariable 18) (while (> count 0) (setv fact (* fact count)) (setv count (- count 1)) (else (setv myvariable 26))) (assert (= count 0)) (assert (= fact 120)) (assert (= myvariable 26)) ; multiple statements in a while loop should work (setv count 5) (setv fact 1) (setv myvariable 18) (setv myothervariable 15) (while (> count 0) (setv fact (* fact count)) (setv count (- count 1)) (else (setv myvariable 26) (setv myothervariable 24))) (assert (= count 0)) (assert (= fact 120)) (assert (= myvariable 26)) (assert (= myothervariable 24)) ; else clause shouldn't get run after a break (while True (break) (else (setv myvariable 53))) (assert (= myvariable 26)) ; don't be fooled by constructs that look like else clauses (setv x 2) (setv a []) (setv else True) (while x (.append a x) (-= x 1) [else (.append a "e")]) (assert (= a [2 "e" 1 "e"])) (setv x 2) (setv a []) (with [(pytest.raises TypeError)] (while x (.append a x) (-= x 1) ("else" (.append a "e")))) (assert (= a [2 "e"]))) (defn test-while-multistatement-condition [] ; The condition should be executed every iteration, before the body. ; `else` should be executed last. (setv s "") (setv x 2) (while (do (+= s "a") x) (+= s "b") (-= x 1) (else (+= s "z"))) (assert (= s "ababaz")) ; `else` should still be skipped after `break`. (setv s "") (setv x 2) (while (do (+= s "a") x) (+= s "b") (-= x 1) (when (= x 0) (break)) (else (+= s "z"))) (assert (= s "abab")) ; `continue` should jump to the condition. (setv s "") (setv x 2) (setv continued? False) (while (do (+= s "a") x) (+= s "b") (when (and (= x 1) (not continued?)) (+= s "c") (setv continued? True) (continue)) (-= x 1) (else (+= s "z"))) (assert (= s "ababcabaz")) ; `break` in a condition applies to the `while`, not an outer loop. (setv s "") (for [x "123"] (+= s x) (setv y 0) (while (do (when (and (= x "2") (= y 1)) (break)) (< y 3)) (+= s "y") (+= y 1))) (assert (= s "1yyy2y3yyy")) ; The condition is still tested appropriately if its last variable ; is set to a false value in the loop body. (setv out []) (setv x 0) (setv a [1 1]) (while (do (.append out 2) (setv x (and a (.pop a))) x) (setv x 0) (.append out x)) (assert (= out [2 0 2 0 2])) (assert (is x 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)) (assert (= (cond [False] [[]] [8])) 8) ;make sure test is only evaluated once (setv x 0) (cond [(do (+= x 1) True)]) (assert (= x 1))) (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-fn [] "NATIVE: test fn operator" (setv square (fn [x] (* x x))) (assert (= 4 (square 2))) (setv lambda_list (fn [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-star-unpacking [] ; Python 3-only forms of unpacking are in py3_only_tests.hy (setv l [1 2 3]) (setv d {"a" "x" "b" "y"}) (defn fun [&optional x1 x2 x3 x4 a b c] [x1 x2 x3 x4 a b c]) (assert (= (fun 5 #* l) [5 1 2 3 None None None])) (assert (= (+ #* l) 6)) (assert (= (fun 5 #** d) [5 None None None "x" "y" None])) (assert (= (fun 5 #* l #** d) [5 1 2 3 "x" "y" None]))) (defn test-kwargs [] "NATIVE: test kwargs things." (assert (= (kwtest :one "two") {"one" "two"})) (setv mydict {"one" "three"}) (assert (= (kwtest #** mydict) mydict)) (assert (= (kwtest #** ((fn [] {"one" "two"}))) {"one" "two"}))) (defn test-dotted [] "NATIVE: test dotted invocation" (assert (= (.join " " ["one" "two"]) "one two")) (defclass X [object] []) (defclass M [object] (defn meth [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 (= (.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 (= (.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 (= (.a.b.meth x #* ["foo" "bar"]) "meth foo bar")) (assert (= (.__str__ :foo) ":foo"))) (defn test-do [] "NATIVE: test do" (do)) (defn test-try [] (try (do) (except [])) (try (do) (except [IOError]) (except [])) ; test that multiple statements in a try get evaluated (setv value 0) (try (+= value 1) (+= value 2) (except [IOError]) (except [])) (assert (= value 3)) ; test that multiple expressions in a try get evaluated ; https://github.com/hylang/hy/issues/1584 (setv l []) (defn f [] (.append l 1)) (try (f) (f) (f) (except [IOError])) (assert (= l [1 1 1])) (setv l []) (try (f) (f) (f) (except [IOError]) (else (f))) (assert (= l [1 1 1 1])) ;; Test correct (raise) (setv passed False) (try (try (do) (raise IndexError) (except [IndexError] (raise))) (except [IndexError] (setv passed True))) (assert passed) ;; Test incorrect (raise) (setv passed False) (try (raise) (except [RuntimeError] (setv passed True))) (assert passed) ;; Test (finally) (setv passed False) (try (do) (finally (setv passed True))) (assert passed) ;; Test (finally) + (raise) (setv passed False) (try (raise Exception) (except []) (finally (setv passed True))) (assert passed) ;; Test (finally) + (raise) + (else) (setv 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 [] (do))) (try (print foobar42ofthebaz) (except [] (setv foobar42ofthebaz 42) (assert (= foobar42ofthebaz 42)))) (setv passed False) (try (try (do) (except []) (else (bla))) (except [NameError] (setv passed True))) (assert passed) (setv x 0) (try (raise IOError) (except [IOError] (setv x 45)) (else (setv x 44))) (assert (= x 45)) (setv x 0) (try (raise KeyError) (except [] (setv x 45)) (else (setv x 44))) (assert (= x 45)) (setv x 0) (try (try (raise KeyError) (except [IOError] (setv x 45)) (else (setv x 44))) (except [])) (assert (= x 0)) ; test that [except ...] and ("except" ...) aren't treated like (except ...), ; and that the code there is evaluated normally (setv x 0) (try (+= x 1) ("except" [IOError] (+= x 1)) (except [])) (assert (= x 2)) (setv x 0) (try (+= x 1) [except [IOError] (+= x 1)] (except [])) (assert (= x 2))) (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-in-macro [] ; https://github.com/hylang/hy/issues/1537 ; The macros need to be defined in another file or else the bug ; isn't visible in cb72a8c155ac4ef8e16afc63ffa80c1d5abb68a7 (require tests.resources.macros) (tests.resources.macros.thread-set-ab) (assert (= ab 2)) (tests.resources.macros.threadtail-set-cd) (assert (= cd 5))) (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-assoc-eval-lvalue-once [] ;; https://github.com/hylang/hy/issues/1068 "`assoc` only evaluates its lvalue once" (setv counter []) (setv d {}) (defn f [] (.append counter 1) d) (assoc (f) "a" 1 "b" 2 "c" 3) (assert (= d {"a" 1 "b" 2 "c" 3})) (assert (= counter [1]))) (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") (setv gg (gen)) (assert (= 3 (next gg))) (try (next gg) (except [e StopIteration] (assert (hasattr e "value")) (assert (= (getattr e "value") "goodbye"))))) (defn test-yield-in-try [] "NATIVE: test yield in try" (defn gen [] (setv x 1) (try (yield x) (finally (print x)))) (setv output (list (gen))) (assert (= [1] output))) (defn test-first [] "NATIVE: test first" (assert (= (first [1 2 3 4 5]) 1)) (assert (= (first (range 10)) 0)) (assert (= (first (repeat 10)) 10)) (assert (is (first []) None))) (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-rest [] "NATIVE: test rest" (assert (= (list (rest [1 2 3 4 5])) [2 3 4 5])) (assert (= (list (take 3 (rest (iterate inc 8)))) [9 10 11])) (assert (= (list (rest [])) []))) (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-context-yield [] "NATIVE: test yields inside of with statements don't try to return before Python 3.3" (defn f [] (with [(open "README.md")] (yield 123))) (assert (= (next (f)) 123))) (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" (setv x 0) (for [a [1 2]] (setv x (+ x a)) (else (setv x (+ x 50)))) (assert (= x 53)) (setv x 0) (for [a [1 2]] (setv x (+ x a)) (else)) (assert (= x 3))) (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-defn-dunder-name [] "NATIVE: test that defn preserves __name__" (defn phooey [x] (+ x 1)) (assert (= phooey.__name__ "phooey")) (defn mooey [x] (+= x 1) x) (assert (= mooey.__name__ "mooey"))) (defn test-defn-annotations [] "NATIVE: test that annotations in defn work" (defn f [^int p1 p2 ^str p3 &optional ^str o1 ^int [o2 0] &rest ^str rest &kwonly ^str k1 ^int [k2 0] &kwargs ^bool kwargs]) (assert (= (. f __annotations__ ["p1"]) int)) (assert (= (. f __annotations__ ["p3"]) str)) (assert (= (. f __annotations__ ["o1"]) str)) (assert (= (. f __annotations__ ["o2"]) int)) (assert (= (. f __annotations__ ["rest"]) str)) (assert (= (. f __annotations__ ["k1"]) str)) (assert (= (. f __annotations__ ["k2"]) int)) (assert (= (. f __annotations__ ["kwargs"]) bool))) (defn test-return [] ; `return` in main line (defn f [x] (return (+ x "a")) (+ x "b")) (assert (= (f "q") "qa")) ; Nullary `return` (defn f [x] (return) 5) (assert (none? (f "q"))) ; `return` in `when` (defn f [x] (when (< x 3) (return [x 1])) [x 2]) (assert (= (f 2) [2 1])) (assert (= (f 4) [4 2])) ; `return` in a loop (setv accum []) (defn f [x] (while True (when (zero? x) (return)) (.append accum x) (-= x 1)) (.append accum "this should never be appended") 1) (assert (none? (f 5))) (assert (= accum [5 4 3 2 1])) ; `return` of a `do` (setv accum []) (defn f [] (return (do (.append accum 1) 3)) 4) (assert (= (f) 3)) (assert (= accum [1])) ; `return` of an `if` that will need to be compiled to a statement (setv accum []) (defn f [x] (return (if (= x 1) (do (.append accum 1) "a") (do (.append accum 2) "b"))) "c") (assert (= (f 2) "b")) (assert (= accum [2]))) (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-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-and [] "NATIVE: test the and function" (setv 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" (setv 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" ; Test each cell of the truth table. (assert (is (xor False False) False)) (assert (is (xor False True) True)) (assert (is (xor True False) True)) (assert (is (xor True True) False)) ; Same thing, but with numbers. (assert (is (xor 0 0) 0)) (assert (is (xor 0 1) 1)) (assert (is (xor 1 0) 1)) (assert (is (xor 1 1) False)) ; Of two distinct false values, the second is returned. (assert (is (xor False 0) 0)) (assert (is (xor 0 False) False))) (defn test-if-return-branching [] "NATIVE: test the if return branching" ; thanks, kirbyfan64 (defn f [] (if True (setv x 1) 2) 1) (assert (= 1 (f)))) (defn test-keyword [] "NATIVE: test if keywords are recognised" (assert (= :foo :foo)) (assert (= :foo ':foo)) (setv x :foo) (assert (is (type x) (type ':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 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-false [] (assert (is (eval 'False) False)) (assert (is (eval 'None) None)) (assert (= (eval '0) 0)) (assert (= (eval '"") "")) (assert (= (eval 'b"") b"")) (assert (= (eval ':) :)) (assert (= (eval '[]) [])) (assert (= (eval '(,)) (,))) (assert (= (eval '{}) {})) (assert (= (eval '#{}) #{}))) (defn test-eval-globals [] "NATIVE: test eval with explicit global dict" (assert (= 'bar (eval (quote foo) {'foo 'bar}))) (assert (= 1 (do (setv d {}) (eval '(setv x 1) d) (eval (quote x) d)))) (setv 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 TypeError]) (else (assert False))) (defclass C) (try (eval (C)) (except [e TypeError]) (else (assert False))) (try (eval 'False []) (except [e TypeError]) (else (assert False))) (try (eval 'False {} 1) (except [e TypeError]) (else (assert False)))) (defn test-eval-quasiquote [] ; https://github.com/hylang/hy/issues/1174 (for [x [ None False True 5 5.1 1/2 5j 5.1j 2+1j 1.2+3.4j "" b"" "apple bloom" b"apple bloom" "⚘" b"\x00" [] #{} {} [1 2 3] #{1 2 3} {"a" 1 "b" 2}]] (assert (= (eval `(identity ~x)) x)) (assert (= (eval x) x))) (setv kw :mykeyword) (assert (= (get (eval `[~kw]) 0) kw)) (assert (= (eval kw) kw)) ; Tuples wrap to HyLists, not HyExpressions. (assert (= (eval (,)) [])) (assert (= (eval (, 1 2 3)) [1 2 3])) (assert (= (eval `(+ "a" ~(+ "b" "c"))) "abc")) (setv l ["a" "b"]) (setv n 1) (assert (= (eval `(get ~l ~n) "b"))) (setv d {"a" 1 "b" 2}) (setv k "b") (assert (= (eval `(get ~d ~k)) 2))) (defn test-quote-bracket-string-delim [] (assert (= (. '#[my delim[hello world]my delim] brackets) "my delim")) (assert (= (. '#[[squid]] brackets) "")) (assert (none? (. '"squid" brackets)))) (defn test-format-strings [] (assert (= f"hello world" "hello world")) (assert (= f"hello {(+ 1 1)} world" "hello 2 world")) (assert (= f"a{ (.upper (+ \"g\" \"k\")) }z" "aGKz")) ; Referring to a variable (setv p "xyzzy") (assert (= f"h{p}j" "hxyzzyj")) ; Including a statement and setting a variable (assert (= f"a{(do (setv floop 4) (* floop 2))}z" "a8z")) (assert (= floop 4)) ; Comments (assert (= f"a{(+ 1 2 ; This is a comment. 3)}z" "a6z")) ; Newlines in replacement fields (assert (= f"ey {\"bee cee\"} dee" "ey bee\ncee dee")) ; Conversion characters and format specifiers (setv p:9 "other") (setv !r "bar") (assert (= f"a{p !r}" "a'xyzzy'")) (assert (= f"a{p :9}" "axyzzy ")) (assert (= f"a{p:9}" "aother")) (assert (= f"a{p !r :9}" "a'xyzzy' ")) (assert (= f"a{p !r:9}" "a'xyzzy' ")) (assert (= f"a{p:9 :9}" "aother ")) (assert (= f"a{!r}" "abar")) (assert (= f"a{!r !r}" "a'bar'")) ; Fun with `r` (assert (= f"hello {r\"\\n\"}" r"hello \n")) (assert (= f"hello {r\"\n\"}" "hello \n")) ; The `r` applies too late to avoid interpreting a backslash. ; Braces escaped via doubling (assert (= f"ab{{cde" "ab{cde")) (assert (= f"ab{{cde}}}}fg{{{{{{" "ab{cde}}fg{{{")) (assert (= f"ab{{{(+ 1 1)}}}" "ab{2}")) ; Nested replacement fields (assert (= f"{2 :{(+ 2 2)}}" " 2")) (setv value 12.34 width 10 precision 4) (assert (= f"result: {value :{width}.{precision}}" "result: 12.34")) ; Nested replacement fields with ! and : (defclass C [object] (defn __format__ [self format-spec] (+ "C[" format-spec "]"))) (assert (= f"{(C) : {(str (+ 1 1)) !r :x<5}}" "C[ '2'xx]")) ; Format bracket strings (assert (= #[f[a{p !r :9}]f] "a'xyzzy' ")) (assert (= #[f-string[result: {value :{width}.{precision}}]f-string] "result: 12.34"))) (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)) ;; 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-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-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 that we can return from an `except` form" (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-try-else-return [] "NATIVE: test that we can return from the `else` clause of a `try`" ; https://github.com/hylang/hy/issues/798 (assert (= "ef" ((fn [] (try (+ "a" "b") (except [NameError] (+ "c" "d")) (else (+ "e" "f"))))))) (setv foo (try (+ "A" "B") (except [NameError] (+ "C" "D")) (else (+ "E" "F")))) (assert (= foo "EF")) ; Check that the lvalue isn't assigned in the main `try` body ; there's an `else`. (setv x 1) (setv y 0) (setv x (try (+ "G" "H") (except [NameError] (+ "I" "J")) (else (setv y 1) (assert (= x 1)) (+ "K" "L")))) (assert (= x "KL")) (assert (= y 1))) (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-get [] (assert (= (:foo {:foo "test"}) "test")) (setv f :foo) (assert (= (f {:foo "test"}) "test")) (with [(pytest.raises KeyError)] (:foo {:a 1 :b 2})) (assert (= (:foo {:a 1 :b 2} 3) 3)) (assert (= (:foo {:a 1 :b 2 :foo 5} 3) 5)) (with [(pytest.raises TypeError)] (:foo "Hello World")) (with [(pytest.raises TypeError)] (:foo (object))) ; The default argument should work regardless of the collection type. (defclass G [object] (defn __getitem__ [self k] (raise KeyError))) (assert (= (:foo (G) 15) 15))) (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-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-with-named-import [] ; https://github.com/hylang/hy/issues/1207 (defmacro m-with-named-import [] (import [math [pow]]) (pow 2 3)) (assert (= (macroexpand '(m-with-named-import)) (** 2 3)))) (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"))) (defn test-disassemble [] "NATIVE: Test the disassemble function" (assert (= (disassemble '(do (leaky) (leaky) (macros))) (.format "Module( body=[Expr(value=Call(func=Name(id='leaky'), args=[], keywords=[])), Expr(value=Call(func=Name(id='leaky'), args=[], keywords=[])), Expr(value=Call(func=Name(id='macros'), args=[], keywords=[]))]{})" (if PY38 ",\n type_ignores=[]" "")))) (assert (= (disassemble '(do (leaky) (leaky) (macros)) True) "leaky() leaky() macros() ")) (assert (= (re.sub r"[L() ]" "" (disassemble `(+ ~(+ 1 1) 40) True)) "2+40\n"))) (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-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" (import [io [StringIO]]) (import [hy.models [HyExpression]]) (setv stdin-buffer (StringIO "(+ 2 2)\n(- 2 2)")) (assert (= (eval (read stdin-buffer)) 4)) (assert (isinstance (read stdin-buffer) HyExpression)) "Multiline test" (setv 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" (setv 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))) (assert (is (type (read-str "(print 1)")) (type '(print 1)))) ; Watch out for false values: https://github.com/hylang/hy/issues/1243 (assert (= (read-str "\"\"") '"")) (assert (is (type (read-str "\"\"")) (type '""))) (assert (= (read-str "[]") '[])) (assert (is (type (read-str "[]")) (type '[]))) (assert (= (read-str "0") '0)) (assert (is (type (read-str "0")) (type '0)))) (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)) (setv x :foo_bar) (assert (= (keyword x) :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 (fn [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-assert-multistatements [] ; https://github.com/hylang/hy/issues/1390 (setv l []) (defn f [x] (.append l x) False) (with [(pytest.raises AssertionError)] (assert (do (f 1) (f 2)) (do (f 3) (f 4)))) (assert (= l [1 2 3 4]))) (defn test-underscore_variables [] ; https://github.com/hylang/hy/issues/1340 (defclass XYZ [] (setv _42 6)) (setv x (XYZ)) (assert (= (. x _42) 6))) (defn test-docstrings [] "Make sure docstrings in functions work and don't clash with return values" (defn f [] "docstring" 5) (assert (= (. f __doc__) "docstring")) ; a single string is the return value, not a docstring ; (https://github.com/hylang/hy/issues/1402) (defn f3 [] "not a docstring") (assert (none? (. f3 __doc__))) (assert (= (f3) "not a docstring"))) (defn test-module-docstring [] (import [tests.resources.module-docstring-example :as m]) (assert (= m.__doc__ "This is the module docstring.")) (assert (= m.foo 5))) (defn test-relative-import [] "Make sure relative imports work properly" (import [..resources [tlib]]) (assert (= tlib.SECRET-MESSAGE "Hello World"))) (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 (defn kwonly-foo-default-false [&kwonly [foo False]] foo) (assert (= (kwonly-foo-default-false) False)) (assert (= (kwonly-foo-default-false :foo True) True)) ;; keyword-only without default ... (defn kwonly-foo-no-default [&kwonly foo] foo) (setv attempt-to-omit-default (try (kwonly-foo-no-default) (except [e [Exception]] e))) ;; works (assert (= (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 (defn function-of-various-args [a b &rest args &kwonly foo &kwargs kwargs] (, a b args foo kwargs)) (assert (= (function-of-various-args 1 2 3 4 :foo 5 :bar 6 :quux 7) (, 1 2 (, 3 4) 5 {"bar" 6 "quux" 7})))) (defn test-extended-unpacking-1star-lvalues [] (setv [x #*y] [1 2 3 4]) (assert (= x 1)) (assert (= y [2 3 4])) (setv [a #*b c] "ghijklmno") (assert (= a "g")) (assert (= b (list "hijklmn"))) (assert (= c "o"))) (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]))) (require [hy.contrib.walk [let]]) (defn test-let-optional [] (let [a 1 b 6 d 2] (defn foo [&kwonly [a a] b [c d]] (, a b c)) (assert (= (foo :b "b") (, 1 "b" 2))) (assert (= (foo :b 20 :a 10 :c 30) (, 10 20 30))))) (defn test-pep-3115 [] (defclass member-table [dict] (defn --init-- [self] (setv self.member-names [])) (defn --setitem-- [self key value] (if (not-in key self) (.append self.member-names key)) (dict.--setitem-- self key value))) (defclass OrderedClass [type] (setv --prepare-- (classmethod (fn [metacls name bases] (member-table)))) (defn --new-- [cls name bases classdict] (setv result (type.--new-- cls name bases (dict classdict))) (setv result.member-names classdict.member-names) result)) (defclass MyClass [:metaclass OrderedClass] (defn method1 [self] (pass)) (defn method2 [self] (pass))) (assert (= (. (MyClass) member-names) ["__module__" "__qualname__" "method1" "method2"]))) (import [asyncio [get-event-loop sleep]]) (defn test-unpacking-pep448-1star [] (setv l [1 2 3]) (setv p [4 5]) (assert (= ["a" #*l "b" #*p #*l] ["a" 1 2 3 "b" 4 5 1 2 3])) (assert (= (, "a" #*l "b" #*p #*l) (, "a" 1 2 3 "b" 4 5 1 2 3))) (assert (= #{"a" #*l "b" #*p #*l} #{"a" "b" 1 2 3 4 5})) (defn f [&rest args] args) (assert (= (f "a" #*l "b" #*p #*l) (, "a" 1 2 3 "b" 4 5 1 2 3))) (assert (= (+ #*l #*p) 15)) (assert (= (and #*l) 3))) (defn test-unpacking-pep448-2star [] (setv d1 {"a" 1 "b" 2}) (setv d2 {"c" 3 "d" 4}) (assert (= {1 "x" #**d1 #**d2 2 "y"} {"a" 1 "b" 2 "c" 3 "d" 4 1 "x" 2 "y"})) (defn fun [&optional a b c d e f] [a b c d e f]) (assert (= (fun #**d1 :e "eee" #**d2) [1 2 3 4 "eee" None]))) (defn run-coroutine [coro] "Run a coroutine until its done in the default event loop.""" (.run_until_complete (get-event-loop) (coro))) (defn test-fn/a [] (assert (= (run-coroutine (fn/a [] (await (sleep 0)) [1 2 3])) [1 2 3]))) (defn test-defn/a [] (defn/a coro-test [] (await (sleep 0)) [1 2 3]) (assert (= (run-coroutine coro-test) [1 2 3]))) (defn test-decorated-defn/a [] (defn decorator [func] (fn/a [] (/ (await (func)) 2))) #@(decorator (defn/a coro-test [] (await (sleep 0)) 42)) (assert (= (run-coroutine coro-test) 21))) (defclass AsyncWithTest [] (defn --init-- [self val] (setv self.val val) None) (defn/a --aenter-- [self] self.val) (defn/a --aexit-- [self tyle value traceback] (setv self.val None))) (defn test-single-with/a [] (run-coroutine (fn/a [] (with/a [t (AsyncWithTest 1)] (assert (= t 1)))))) (defn test-two-with/a [] (run-coroutine (fn/a [] (with/a [t1 (AsyncWithTest 1) t2 (AsyncWithTest 2)] (assert (= t1 1)) (assert (= t2 2)))))) (defn test-thrice-with/a [] (run-coroutine (fn/a [] (with/a [t1 (AsyncWithTest 1) t2 (AsyncWithTest 2) t3 (AsyncWithTest 3)] (assert (= t1 1)) (assert (= t2 2)) (assert (= t3 3)))))) (defn test-quince-with/a [] (run-coroutine (fn/a [] (with/a [t1 (AsyncWithTest 1) t2 (AsyncWithTest 2) t3 (AsyncWithTest 3) _ (AsyncWithTest 4)] (assert (= t1 1)) (assert (= t2 2)) (assert (= t3 3)))))) hy-0.18.0/tests/native_tests/mangling.hy000066400000000000000000000107011361554632000202340ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (defn test-hyphen [] (setv a-b 1) (assert (= a-b 1)) (assert (= a_b 1)) (setv -a-_b- 2) (assert (= -a-_b- 2)) (assert (= -a--b- 2)) (assert (= -a__b- 2)) (setv -_- 3) (assert (= -_- 3)) (assert (= --- 3)) (assert (= ___ 3))) (defn test-underscore-number [] (setv _42 3) (assert (= _42 3)) (assert (!= _42 -42)) (assert (not (in "_hyx_42" (locals))))) (defn test-question-mark [] (setv foo? "nachos") (assert (= foo? "nachos")) (assert (= is_foo "nachos")) (setv ___ab_cd? "tacos") (assert (= ___ab_cd? "tacos")) (assert (= ___is_ab_cd "tacos"))) (defn test-py-forbidden-ascii [] (setv # "no comment") (assert (= # "no comment")) (assert (= hyx_Xnumber_signX "no comment")) (setv $ "dosh") (assert (= $ "dosh")) (assert (= hyx_Xdollar_signX "dosh"))) (defn test-basic-multilingual-plane [] (setv ♥ "love" ⚘ab "flower") (assert (= (+ ⚘ab ♥) "flowerlove")) (assert (= (+ hyx_XflowerXab hyx_Xblack_heart_suitX) "flowerlove")) (setv ⚘-⚘ "doubleflower") (assert (= ⚘-⚘ "doubleflower")) (assert (= hyx_XflowerX_XflowerX "doubleflower")) (setv ⚘? "mystery") (assert (= ⚘? "mystery")) (assert (= hyx_is_XflowerX "mystery"))) (defn test-higher-unicode [] (setv 😂 "emoji") (assert (= 😂 "emoji")) (assert (= hyx_Xface_with_tears_of_joyX "emoji"))) (defn test-nameless-unicode [] (setv  "private use") (assert (=  "private use")) (assert (= hyx_XUe000X "private use"))) (defn test-charname-with-hyphen [] (setv a> args (.parse (whole [(many (notpexpr "until")) (dolike "until")])))) (setv g (gensym)) `(do (setv ~g True) (while (or ~g (not (do ~@condition))) ~@body (setv ~g False)))) (defn test-do-until [] (setv n 0 s "") (do-until (+= s "x") (until (+= n 1) (>= n 3))) (assert (= s "xxx")) (do-until (+= s "x") (until (+= n 1) (>= n 3))) (assert (= s "xxxx"))) (defmacro loop [&rest args] (import [hy.model-patterns [whole FORM sym SYM]] [funcparserlib.parser [many]]) (setv [loopers body] (->> args (.parse (whole [ (many (| (>> (+ (sym "while") FORM) (fn [x] [x])) (+ (sym "for") SYM (sym "in") FORM) (+ (sym "for") SYM (sym "from") FORM (sym "to") FORM))) (sym "do") (many FORM)])))) (defn f [loopers] (setv [head tail] [(first loopers) (cut loopers 1)]) (print head) (cond [(none? head) `(do ~@body)] [(= (len head) 1) `(while ~@head ~(f tail))] [(= (len head) 2) `(for [~@head] ~(f tail))] [True ; (= (len head) 3) (setv [sym from to] head) `(for [~sym (range ~from (inc ~to))] ~(f tail))])) (f loopers)) (defn test-loop [] (setv l []) (loop for x in "abc" do (.append l x)) (assert (= l ["a" "b" "c"])) (setv l [] k 2) (loop while (> k 0) for n from 1 to 3 for p in [k n (* 10 n)] do (.append l p) (-= k 1)) (print l) (assert (= l [2 1 10 -1 2 20 -4 3 30]))) hy-0.18.0/tests/native_tests/native_macros.hy000066400000000000000000000374541361554632000213100ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (import pytest [hy.errors [HyTypeError HyMacroExpansionError]]) (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]))) (defn test-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-bytes [] b"foo") (assert (= (a-bytes) b"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 or &kwargs is used in a macro" (try (eval '(defmacro f [&kwonly a b])) (except [e HyTypeError] (assert (= e.msg "macros cannot use &kwonly"))) (else (assert False))) (try (eval '(defmacro f [&kwargs kw])) (except [e HyTypeError] (assert (= e.msg "macros cannot use &kwargs"))) (else (assert False)))) (defn test-fn-calling-macro [] "NATIVE: test macro calling a plain function" (assert (= 3 (bar 1 2)))) (defn test-optional-and-unpacking-in-macro [] ; https://github.com/hylang/hy/issues/1154 (defn f [&rest args] (+ "f:" (repr args))) (defmacro mac [&optional x] `(f #* [~x])) (assert (= (mac) "f:(None,)"))) (defn test-macro-autoboxing-docstring [] (defmacro m [] (setv mystring "hello world") `(fn [] ~mystring (+ 1 2))) (setv f (m)) (assert (= (f) 3)) (assert (= f.__doc__ "hello world"))) (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-gensym-in-macros [] (import ast) (import [astor.code-gen [to-source]]) (import [hy.compiler [hy-compile]]) (import [hy.lex [hy-parse]]) (setv macro1 "(defmacro nif [expr pos zero neg] (setv g (gensym)) `(do (setv ~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 (hy-compile (hy-parse macro1) __name__)) (setv _ast2 (hy-compile (hy-parse macro1) __name__)) (setv s1 (to_source _ast1)) (setv s2 (to_source _ast2)) ;; and make sure there is something new that starts with _G\uffff (assert (in (mangle "_G\uffff") s1)) (assert (in (mangle "_G\uffff") s2)) ;; but make sure the two don't match each other (assert (not (= s1 s2)))) (defn test-with-gensym [] (import ast) (import [astor.code-gen [to-source]]) (import [hy.compiler [hy-compile]]) (import [hy.lex [hy-parse]]) (setv macro1 "(defmacro nif [expr pos zero neg] (with-gensyms [a] `(do (setv ~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 (hy-compile (hy-parse macro1) __name__)) (setv _ast2 (hy-compile (hy-parse macro1) __name__)) (setv s1 (to_source _ast1)) (setv s2 (to_source _ast2)) (assert (in (mangle "_a\uffff") s1)) (assert (in (mangle "_a\uffff") s2)) (assert (not (= s1 s2)))) (defn test-defmacro/g! [] (import ast) (import [astor.code-gen [to-source]]) (import [hy.compiler [hy-compile]]) (import [hy.lex [hy-parse]]) (setv macro1 "(defmacro/g! nif [expr pos zero neg] `(do (setv ~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 (hy-compile (hy-parse macro1) __name__)) (setv _ast2 (hy-compile (hy-parse macro1) __name__)) (setv s1 (to_source _ast1)) (setv s2 (to_source _ast2)) (assert (in (mangle "_res\uffff") s1)) (assert (in (mangle "_res\uffff") 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 (hy-compile (hy-parse macro2) __name__))) (defn test-defmacro! [] ;; defmacro! must do everything defmacro/g! can (import ast) (import [astor.code-gen [to-source]]) (import [hy.compiler [hy-compile]]) (import [hy.lex [hy-parse]]) (setv macro1 "(defmacro! nif [expr pos zero neg] `(do (setv ~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 (hy-compile (hy-parse macro1) __name__)) (setv _ast2 (hy-compile (hy-parse macro1) __name__)) (setv s1 (to_source _ast1)) (setv s2 (to_source _ast2)) (assert (in (mangle "_res\uffff") s1)) (assert (in (mangle "_res\uffff") 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 (hy-compile (hy-parse macro2) __name__)) (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)) ;; test &optional args (defmacro! bar! [o!a &optional [o!b 1]] `(do ~g!a ~g!a ~g!b ~g!b)) ;; test that o!s are evaluated once only (bar! (+= foo 1) (+= foo 1)) (assert (= 43 foo)) ;; test that the optional arg works (assert (= (bar! 2) 1))) (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-defmain [] "NATIVE: make sure defmain is clean" (global --name--) (setv oldname --name--) (setv --name-- "__main__") (defn main [x] (print (integer? x)) x) (try (defmain [&rest args] (main 42)) (assert False) (except [e SystemExit] (assert (= (str e) "42")))) ;; Try a `defmain` without args (try (defmain [] (main 42)) (assert False) (except [e SystemExit] (assert (= (str e) "42")))) ;; Try a `defmain` with only one arg (import sys) (setv oldargv sys.argv) (try (setv sys.argv [1]) (defmain [x] (main x)) (assert False) (except [e SystemExit] (assert (= (str e) "1")))) (setv sys.argv oldargv) (setv --name-- oldname)) (defn test-macro-namespace-resolution [] "Confirm that local versions of macro-macro dependencies do not shadow the versions from the macro's own module, but do resolve unbound macro references in expansions." ;; `nonlocal-test-macro` is a macro used within ;; `tests.resources.macro-with-require.test-module-macro`. ;; Here, we introduce an equivalently named version in local scope that, when ;; used, will expand to a different output string. (defmacro nonlocal-test-macro [x] (print "this is the local version of `nonlocal-test-macro`!")) ;; Was the above macro created properly? (assert (in "nonlocal_test_macro" __macros__)) (setv nonlocal-test-macro (get __macros__ "nonlocal_test_macro")) (require [tests.resources.macro-with-require [*]]) (setv module-name-var "tests.native_tests.native_macros.test-macro-namespace-resolution") (assert (= (+ "This macro was created in tests.resources.macros, " "expanded in tests.native_tests.native_macros.test-macro-namespace-resolution " "and passed the value 2.") (test-module-macro 2))) (assert (= (+ "This macro was created in tests.resources.macros, " "expanded in tests.native_tests.native_macros.test-macro-namespace-resolution " "and passed the value 2.") #test-module-tag 2)) ;; Now, let's use a `require`d macro that depends on another macro defined only ;; in this scope. (defmacro local-test-macro [x] (.format "This is the local version of `nonlocal-test-macro` returning {}!" (int x))) (assert (= "This is the local version of `nonlocal-test-macro` returning 3!" (test-module-macro-2 3))) (assert (= "This is the local version of `nonlocal-test-macro` returning 3!" #test-module-tag-2 3))) (defn test-macro-from-module [] "Macros loaded from an external module, which itself `require`s macros, should work without having to `require` the module's macro dependencies (due to [minimal] macro namespace resolution). In doing so we also confirm that a module's `__macros__` attribute is correctly loaded and used. Additionally, we confirm that `require` statements are executed via loaded bytecode." (import os sys marshal types) (import importlib) (setv pyc-file (importlib.util.cache-from-source (os.path.realpath (os.path.join "tests" "resources" "macro_with_require.hy")))) ;; Remove any cached byte-code, so that this runs from source and ;; gets evaluated in this module. (when (os.path.isfile pyc-file) (os.unlink pyc-file) (.clear sys.path_importer_cache) (when (in "tests.resources.macro_with_require" sys.modules) (del (get sys.modules "tests.resources.macro_with_require")) (__macros__.clear) (__tags__.clear))) ;; Ensure that bytecode isn't present when we require this module. (assert (not (os.path.isfile pyc-file))) (defn test-requires-and-macros [] (require [tests.resources.macro-with-require [test-module-macro]]) ;; Make sure that `require` didn't add any of its `require`s (assert (not (in "nonlocal-test-macro" __macros__))) ;; and that it didn't add its tags. (assert (not (in "test_module_tag" __tags__))) ;; Now, require everything. (require [tests.resources.macro-with-require [*]]) ;; Again, make sure it didn't add its required macros and/or tags. (assert (not (in "nonlocal-test-macro" __macros__))) ;; Its tag(s) should be here now. (assert (in "test_module_tag" __tags__)) ;; The test macro expands to include this symbol. (setv module-name-var "tests.native_tests.native_macros") (assert (= (+ "This macro was created in tests.resources.macros, " "expanded in tests.native_tests.native_macros " "and passed the value 1.") (test-module-macro 1))) (assert (= (+ "This macro was created in tests.resources.macros, " "expanded in tests.native_tests.native_macros " "and passed the value 1.") #test-module-tag 1))) (test-requires-and-macros) ;; Now that bytecode is present, reload the module, clear the `require`d ;; macros and tags, and rerun the tests. (assert (os.path.isfile pyc-file)) ;; Reload the module and clear the local macro context. (.clear sys.path_importer_cache) (del (get sys.modules "tests.resources.macro_with_require")) (.clear __macros__) (.clear __tags__) ;; XXX: There doesn't seem to be a way--via standard import mechanisms--to ;; ensure that an imported module used the cached bytecode. We'll simply have ;; to trust that the .pyc loading convention was followed. (test-requires-and-macros)) (defn test-recursive-require-star [] "(require [foo [*]]) should pull in macros required by `foo`." (require [tests.resources.macro-with-require [*]]) (test-macro) (assert (= blah 1))) (defn test-macro-errors [] (import traceback [hy.importer [hy-parse]]) (setv test-expr (hy-parse "(defmacro blah [x] `(print ~@z)) (blah y)")) (with [excinfo (pytest.raises HyMacroExpansionError)] (eval test-expr)) (setv output (traceback.format_exception_only excinfo.type excinfo.value)) (setv output (cut (.splitlines (.strip (first output))) 1)) (setv expected [" File \"\", line 1" " (defmacro blah [x] `(print ~@z)) (blah y)" " ^------^" "expanding macro blah" " NameError: global name 'z' is not defined"]) (assert (= (cut expected 0 -1) (cut output 0 -1))) (assert (or (= (get expected -1) (get output -1)) ;; Handle PyPy's peculiarities (= (.replace (get expected -1) "global " "") (get output -1)))) ;; This should throw a `HyWrapperError` that gets turned into a ;; `HyMacroExpansionError`. (with [excinfo (pytest.raises HyMacroExpansionError)] (eval '(do (defmacro wrap-error-test [] (fn [])) (wrap-error-test)))) (assert (in "HyWrapperError" (str excinfo.value)))) hy-0.18.0/tests/native_tests/operators.hy000066400000000000000000000221651361554632000204650ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (defmacro op-and-shadow-test [op &rest body] ; Creates two tests with the given `body`, one where all occurrences ; of the symbol `f` are syntactically replaced with `op` (a test of ; the real operator), and one where the body is preceded by an ; assignment of `op` to `f` (a test of the shadow operator). ; ; `op` can also be a list of operators, in which case two tests are ; created for each operator. (import [hy [HySymbol HyString]] [hy.contrib.walk [prewalk]]) (setv defns []) (for [o (if (coll? op) op [op])] (.append defns `(defn ~(HySymbol (+ "test_operator_" o "_real")) [] (setv f-name ~(HyString o)) ~@(prewalk :form body :f (fn [x] (if (and (symbol? x) (= x "f")) o x))))) (.append defns `(defn ~(HySymbol (+ "test_operator_" o "_shadow")) [] (setv f-name ~(HyString o)) (setv f ~o) ~@body))) `(do ~@defns)) (defmacro forbid [expr] `(assert (try (eval '~expr) (except [[TypeError SyntaxError]] True) (else (raise AssertionError))))) (op-and-shadow-test + (assert (= (f) 0)) (defclass C [object] (defn __pos__ [self] "called __pos__")) (assert (= (f (C)) "called __pos__")) (assert (= (f 1 2) 3)) (assert (= (f 1 2 3 4) 10)) (assert (= (f 1 2 3 4 5) 15)) ; with strings (assert (= (f "a" "b" "c") "abc")) ; with lists (assert (= (f ["a"] ["b"] ["c"]) ["a" "b" "c"]))) (op-and-shadow-test - (forbid (f)) (assert (= (f 1) -1)) (assert (= (f 2 1) 1)) (assert (= (f 2 1 1) 0))) (op-and-shadow-test * (assert (= (f) 1)) (assert (= (f 3) 3)) (assert (= (f 3 3) 9)) (assert (= (f 2 3 4) 24)) (assert (= (f "ke" 4) "kekekeke")) (assert (= (f [1 2 3] 2) [1 2 3 1 2 3]))) (op-and-shadow-test ** (forbid (f)) (forbid (f 1)) (assert (= (f 3 2) 9)) (assert (= (f 5 4 3 2) (** 5 (** 4 (** 3 2)))))) ; Exponentiation is right-associative. (op-and-shadow-test / (forbid (f)) (assert (= (f 2) .5)) (assert (= (f 3 2) 1.5)) (assert (= (f 8 2) 4)) (assert (= (f 8 2 2) 2)) (assert (= (f 8 2 2 2) 1))) (op-and-shadow-test // (forbid (f)) (forbid (f 1)) (assert (= (f 16 5) 3)) (assert (= (f 8 2) 4)) (assert (= (f 8 2 2) 2))) (op-and-shadow-test % (forbid (f)) (forbid (f 1)) (assert (= (f 16 5) 1)) (assert (= (f 8 2) 0)) (assert (= (f "aa %s bb" 15) "aa 15 bb")) (assert (= (f "aa %s bb %s cc" (, "X" "Y")) "aa X bb Y cc")) (forbid (f 1 2 3))) (op-and-shadow-test @ (defclass C [object] (defn __init__ [self content] (setv self.content content)) (defn __matmul__ [self other] (C (+ self.content other.content)))) (forbid (f)) (assert (do (setv c (C "a")) (is (f c) c))) (assert (= (. (f (C "b") (C "c")) content) "bc")) (assert (= (. (f (C "d") (C "e") (C "f")) content) "def"))) (op-and-shadow-test << (forbid (f)) (forbid (f 1)) (assert (= (f 0b101 2) 0b10100)) (assert (= (f 0b101 2 3) 0b10100000))) (op-and-shadow-test >> (forbid (f)) (forbid (f 1)) (assert (= (f 0b101 2) 0b1)) (assert (= (f 0b101000010 2 3) 0b1010))) (op-and-shadow-test & (forbid (f)) ; Binary AND has no identity element for the set of all ; nonnegative integers, because we can't have a 1 in every bit ; when there are infinitely many bits. (assert (= (f 17) 17)) (assert (= (f 0b0011 0b0101) 0b0001)) (assert (= (f 0b111 0b110 0b100) 0b100))) (op-and-shadow-test | (assert (= (f) 0)) (assert (= (f 17) 17)) (assert (= (f 0b0011 0b0101) 0b0111)) (assert (= (f 0b11100 0b11000 0b10010) 0b11110))) (op-and-shadow-test ^ (forbid (f)) (forbid (f 17)) (assert (= (f 0b0011 0b0101) 0b0110)) (forbid (f 0b111 0b110 0b100))) ; `xor` with 3 arguments is kill (https://github.com/hylang/hy/pull/1102), ; so we don't allow `^` with 3 arguments, either. (op-and-shadow-test ~ (forbid (f)) (assert (= (& (f 0b00101111) 0xFF) 0b11010000)) (forbid (f 0b00101111 0b11010000))) (op-and-shadow-test < (forbid (f)) (assert (is (f "hello") True)) (assert (is (f 1 2) True)) (assert (is (f 2 1) False)) (assert (is (f 1 1) False)) (assert (is (f 1 2 3) True)) (assert (is (f 3 2 1) False)) (assert (is (f 1 3 2) False)) (assert (is (f 1 2 2) False)) ; Make sure chained comparisons use `and`, not `&`. ; https://github.com/hylang/hy/issues/1191 (defclass C [object] (defn __init__ [self x] (setv self.x x)) (defn __lt__ [self other] self.x)) (assert (= (f (C "a") (C "b") (C "c")) "b"))) (op-and-shadow-test > (forbid (f)) (assert (is (f "hello") True)) (assert (is (f 1 2) False)) (assert (is (f 2 1) True)) (assert (is (f 1 1) False)) (assert (is (f 1 2 3) False)) (assert (is (f 3 2 1) True)) (assert (is (f 1 3 2) False)) (assert (is (f 2 1 1) False))) (op-and-shadow-test <= (forbid (f)) (assert (is (f "hello") True)) (assert (is (f 1 2) True)) (assert (is (f 2 1) False)) (assert (is (f 1 1) True)) (assert (is (f 1 2 3) True)) (assert (is (f 3 2 1) False)) (assert (is (f 1 3 2) False)) (assert (is (f 1 2 2) True))) (op-and-shadow-test >= (forbid (f)) (assert (is (f "hello") True)) (assert (is (f 1 2) False)) (assert (is (f 2 1) True)) (assert (is (f 1 1) True)) (assert (is (f 1 2 3) False)) (assert (is (f 3 2 1) True)) (assert (is (f 1 3 2) False)) (assert (is (f 2 1 1) True))) (op-and-shadow-test [= is] (forbid (f)) (assert (is (f "hello") True)) ; Unary comparison operators, despite always returning True, ; should evaluate their argument. (setv p "a") (assert (is (f (do (setv p "b") "hello")) True)) (assert (= p "b")) (defclass C) (setv x (get {"is" (C) "=" 0} f-name)) (setv y (get {"is" (C) "=" 1} f-name)) (assert (is (f x x) True)) (assert (is (f y y) True)) (assert (is (f x y) False)) (assert (is (f y x) False)) (assert (is (f x x x x x) True)) (assert (is (f x x x y x) False)) (setv n None) (assert (is (f n None) True)) (assert (is (f n "b") False))) (op-and-shadow-test [!= is-not] (forbid (f)) (forbid (f "hello")) (defclass C) (setv x (get {"is-not" (C) "!=" 0} f-name)) (setv y (get {"is-not" (C) "!=" 1} f-name)) (setv z (get {"is-not" (C) "!=" 2} f-name)) (assert (is (f x x) False)) (assert (is (f y y) False)) (assert (is (f x y) True)) (assert (is (f y x) True)) (assert (is (f x y z) True)) (assert (is (f x x x) False)) (assert (is (f x y x) True)) (assert (is (f x x y) False))) (op-and-shadow-test and (assert (is (f) True)) (assert (= (f 17) 17)) (assert (= (f 1 2) 2)) (assert (= (f 1 0) 0)) (assert (= (f 0 2) 0)) (assert (= (f 0 0) 0)) (assert (= (f 1 2 3) 3)) (assert (= (f 1 0 3) 0)) (assert (= (f "a" 1 True [1]) [1]))) (op-and-shadow-test or (assert (is (f) None)) (assert (= (f 17) 17)) (assert (= (f 1 2) 1)) (assert (= (f 1 0) 1)) (assert (= (f 0 2) 2)) (assert (= (f 0 0) 0)) (assert (= (f 1 2 3) 1)) (assert (= (f 0 0 3) 3)) (assert (= (f "" None 0 False []) []))) (op-and-shadow-test not (forbid (f)) (assert (is (f "hello") False)) (assert (is (f 0) True)) (assert (is (f None) True))) (op-and-shadow-test [in not-in] (forbid (f)) (forbid (f 3)) (assert (is (f 3 [1 2]) (!= f-name "in"))) (assert (is (f 2 [1 2]) (= f-name "in"))) (assert (is (f 2 [1 2] [[1 2] 3]) (= f-name "in"))) (assert (is (f 3 [1 2] [[2 2] 3]) (!= f-name "in")))) (op-and-shadow-test [get] (forbid (f)) (forbid (f "hello")) (assert (= (f "hello" 1) "e")) (assert (= (f [[1 2 3] [4 5 6] [7 8 9]] 1 2) 6)) (assert (= (f {"x" {"y" {"z" 12}}} "x" "y" "z") 12))) (defn test-chained-comparison [] (assert (cmp 2 = (+ 1 1) = (- 3 1))) (assert (not (cmp 2 = (+ 1 1) = (+ 3 1)))) (assert (cmp 2 = 2 > 1)) (assert (cmp 2 = (+ 1 1) > 1)) (setv x 2) (assert (cmp 2 = x > 1)) (assert (cmp 2 = x > (> 4 3))) (assert (not (cmp (> 4 3) = x > 1))) (assert (cmp 1 in [1] in [[1] [2 3]] not-in [5])) (assert (not (cmp 1 in [1] not-in [[1] [2 3]] not-in [5])))) (defn test-augassign [] (setv b 2 c 3 d 4) (defmacro same-as [expr1 expr2 expected-value] `(do (setv a 4) ~expr1 (setv expr1-value a) (setv a 4) ~expr2 (assert (= expr1-value a ~expected-value)))) (same-as (+= a b c d) (+= a (+ b c d)) 13) (same-as (-= a b c d) (-= a (+ b c d)) -5) (same-as (*= a b c d) (*= a (* b c d)) 96) (same-as (**= a b c) (**= a (** b c)) 65,536) (same-as (/= a b c d) (/= a (* b c d)) (/ 1 6)) (same-as (//= a b c d) (//= a (* b c d)) 0) (same-as (<<= a b c d) (<<= a (+ b c d)) 0b10_00000_00000) (same-as (>>= a b c d) (>>= a (+ b c d)) 0) (same-as (&= a b c d) (&= a (& b c d)) 0) (same-as (|= a b c d) (|= a (| b c d)) 0b111) (defclass C [object] (defn __init__ [self content] (setv self.content content)) (defn __matmul__ [self other] (C (+ self.content other.content)))) (setv a (C "a") b (C "b") c (C "c") d (C "d")) (@= a b c d) (assert (= a.content "abcd")) (setv a (C "a")) (@= a (@ b c d)) (assert (= a.content "abcd")) (setv a 15) (%= a 9) (assert (= a 6)) (setv a 0b1100) (^= a 0b1010) (assert (= a 0b0110))) hy-0.18.0/tests/native_tests/py36_only_tests.hy000066400000000000000000000030671361554632000215330ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;; Tests where the emitted code relies on Python ≥3.6. ;; conftest.py skips this file when running on Python <3.6. (import [asyncio [get-event-loop sleep]]) (import [typing [get-type-hints List Dict]]) (defn run-coroutine [coro] "Run a coroutine until its done in the default event loop.""" (.run_until_complete (get-event-loop) (coro))) (defn test-for-async [] (defn/a numbers [] (for [i [1 2]] (yield i))) (run-coroutine (fn/a [] (setv x 0) (for [:async a (numbers)] (setv x (+ x a))) (assert (= x 3))))) (defn test-for-async-else [] (defn/a numbers [] (for [i [1 2]] (yield i))) (run-coroutine (fn/a [] (setv x 0) (for [:async a (numbers)] (setv x (+ x a)) (else (setv x (+ x 50)))) (assert (= x 53))))) (defn test-variable-annotations [] (defclass AnnotationContainer [] (setv ^int x 1 y 2) (^bool z)) (setv annotations (get-type-hints AnnotationContainer)) (assert (= (get annotations "x") int)) (assert (= (get annotations "z") bool))) (defn test-of [] (assert (= (of str) str)) (assert (= (of List int) (get List int))) (assert (= (of Dict str str) (get Dict (, str str))))) (defn test-pep-487 [] (defclass QuestBase [] (defn --init-subclass-- [cls swallow &kwargs kwargs] (setv cls.swallow swallow))) (defclass Quest [QuestBase :swallow "african"]) (assert (= (. (Quest) swallow) "african"))) hy-0.18.0/tests/native_tests/py38_only_tests.hy000066400000000000000000000013371361554632000215330ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;; Tests where the emitted code relies on Python ≥3.8. ;; conftest.py skips this file when running on Python <3.8. (import pytest) (defn test-setx [] (setx y (+ (setx x (+ "a" "b")) "c")) (assert (= x "ab")) (assert (= y "abc")) (setv l []) (for [x [1 2 3]] (when (>= (setx y (+ x 8)) 10) (.append l y))) (assert (= l [10 11])) (setv a ["apple" None "banana"]) (setv filtered (lfor i (range (len a)) :if (is-not (setx v (get a i)) None) v)) (assert (= filtered ["apple" "banana"])) (assert (= v "banana")) (with [(pytest.raises NameError)] i)) hy-0.18.0/tests/native_tests/quote.hy000066400000000000000000000052551361554632000176050ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (import [hy [HyExpression HySymbol HyString HyBytes HyDict]]) (defn test-quote [] "NATIVE: test for quoting functionality" (setv q (quote (a b c))) (assert (= (len q) 3)) (assert (= q (HyExpression [(quote a) (quote b) (quote c)])))) (defn test-basic-quoting [] (assert (= (type (quote (foo bar))) HyExpression)) (assert (= (type (quote foo)) HySymbol)) (assert (= (type (quote "string")) HyString)) (assert (= (type (quote b"string")) HyBytes))) (defn test-quoted-hoistable [] "NATIVE: check whether quote works on hoisted things" (setv f (quote (if True True True))) (assert (= (get f 0) (quote if))) (assert (= (cut f 1) (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 (= (get q1 0) (quote ->))) (assert (= (cut q1 1) (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) 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 `(a b ~@q f ~@q ~@0 ~@False ~@None g ~@(when False 1) h)) (assert (= (len qq) 11)) (assert (= qq (quote (a b c d e f c d e g h))))) (defn test-nested-quasiquote [] "NATIVE: test nested quasiquotes" (setv qq `(1 `~(+ 1 ~(+ 2 3) ~@None) 4)) (setv q (quote (1 `~(+ 1 5) 4))) (assert (= (len q) 3)) (assert (= (get qq 1) (quote `~(+ 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.18.0/tests/native_tests/tag_macros.hy000066400000000000000000000065721361554632000205720ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (import [functools [wraps]]) (defn test-tag-macro [] "Test a basic tag macro" (deftag ^ [expr] expr) (assert (= #^"works" "works"))) (defn test-long-tag-macro [] "Test a tag macro with a name longer than one character" (deftag foo [expr] `['foo ~expr]) (assert (= #foo'bar ['foo 'bar])) (assert (= #foo"baz" ['foo "baz"])) (assert (= #foo(- 44 2) ['foo 42])) (assert (= #foo(, 42) ['foo (, 42)])) (assert (= #foo[42] ['foo [42]])) (assert (= #foo{4 2} ['foo {4 2}]))) (defn test-hyphenated-tag-macro [] "Test if hyphens translate properly" (deftag foo-bar [x] `['foo ~x 'bar]) (assert (= #foo-bar 42) ['foo 42 'bar]) (assert (= #foo_bar 42) ['foo 42 'bar]) (deftag spam_eggs [x] `['spam ~x 'eggs]) (assert (= #spam-eggs 42 ['spam 42 'eggs])) (assert (= #spam_eggs 42 ['spam 42 'eggs]))) (defn test-bang-tag-macro [] "Test tag macros whose names start with `!`" ; https://github.com/hylang/hy/issues/1334 (deftag !a [x] `["foo" ~x]) (assert (= #!a 3 ["foo" 3])) (deftag ! [x] `["bar" ~x]) (assert (= #! 4 ["bar" 4]))) (defn test-tag-macro-whitespace [] "Test whitespace after a tag macro" (deftag foo [expr] `['foo ~expr]) (assert (= #foo 42) ['foo 42]) (assert (= #foo (- 44 2) ['foo 42])) (deftag b [x] `['bar ~x]) (assert (= #b 42) ['bar 42]) ; # is allowed in tags, so this must be separated (assert (= #b #{42} ['bar #{42}])) ; multiple tags must likewise be separated (assert (= #b #foo 42 ['bar ['foo 42]])) ; newlines are also whitespace (assert (= #foo 42 ['foo 42])) (assert (= #foo; a semicolon/comment should count as whitespace 42 ['foo 42]))) (defn test-tag-macro-expr [] "Test basic exprs like lists and arrays" (deftag n [expr] (get expr 1)) (assert (= #n[1 2] 2)) (assert (= #n(1 2) 2))) (defn test-tag-macro-override [] "Test if we can override function symbols" (deftag + [n] (+ n 1)) (assert (= #+ 2 3))) (defn test-tag-macros-macros [] "Test if deftag is actually a macro" (deftag t [expr] `(, ~@expr)) (setv a #t[1 2 3]) (assert (= (type a) tuple)) (assert (= (, 1 2 3) a))) (defn test-tag-macro-string-name [] "Test if deftag accepts a string as a macro name." (deftag "." [expr] expr) (assert (= #."works" "works"))) (defn test-builtin-decorator-tag [] (defn increment-arguments [func] "Increments each argument passed to the decorated function." ((wraps func) (fn [&rest args &kwargs kwargs] (func #* (map inc args) #** (dfor [k v] (.items kwargs) [k (inc v)]))))) #@(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 #@ tag 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.18.0/tests/native_tests/unless.hy000066400000000000000000000004141361554632000177510ustar00rootroot00000000000000(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.18.0/tests/native_tests/when.hy000066400000000000000000000003701361554632000174020ustar00rootroot00000000000000(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.18.0/tests/native_tests/with_decorator.hy000066400000000000000000000017761361554632000214710ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (defn test-decorated-1line-function [] (defn foodec [func] (fn [] (+ (func) 1))) (with-decorator foodec (defn tfunction [] (* 2 2))) (assert (= (tfunction) 5))) (defn test-decorated-multiline-function [] (defn bazdec [func] (fn [] (+ (func) "x"))) (with-decorator bazdec (defn f [] (setv intermediate "i") (+ intermediate "b"))) (assert (= (f) "ibx"))) (defn test-decorated-class [] (defn bardec [cls] (setv cls.attr2 456) cls) (with-decorator bardec (defclass cls [] (setv attr1 123))) (assert (= cls.attr1 123)) (assert (= cls.attr2 456))) (defn test-decorator-clobbing [] "NATIVE: Tests whether nested decorators work" (do (defn dec1 [f] (fn [] (+ (f) 1))) (defn dec2 [f] (fn [] (+ (f) 2))) (with-decorator dec1 (with-decorator dec2 (defn f [] 1))) (assert (= (f) 4)))) hy-0.18.0/tests/native_tests/with_test.hy000066400000000000000000000032701361554632000204550ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (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)))) (defclass SuppressZDE [object] (defn --enter-- [self]) (defn --exit-- [self exc-type exc-value traceback] (and (not (none? exc-type)) (issubclass exc-type ZeroDivisionError)))) (defn test-exception-suppressing-with [] ; https://github.com/hylang/hy/issues/1320 (setv x (with [(SuppressZDE)] 5)) (assert (= x 5)) (setv y (with [(SuppressZDE)] (/ 1 0))) (assert (none? y)) (setv z (with [(SuppressZDE)] (/ 1 0) 5)) (assert (none? z)) (defn f [] (with [(SuppressZDE)] (/ 1 0))) (assert (none? (f))) (setv w 7 l []) (setv w (with [(SuppressZDE)] (.append l w) (/ 1 0) 5)) (assert (none? w)) (assert (= l [7]))) hy-0.18.0/tests/resources/000077500000000000000000000000001361554632000154015ustar00rootroot00000000000000hy-0.18.0/tests/resources/__init__.py000066400000000000000000000001261361554632000175110ustar00rootroot00000000000000def kwtest(*args, **kwargs): return kwargs def function_with_a_dash(): pass hy-0.18.0/tests/resources/argparse_ex.hy000077500000000000000000000007151361554632000202510ustar00rootroot00000000000000#!/usr/bin/env hy ;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. (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.18.0/tests/resources/bin/000077500000000000000000000000001361554632000161515ustar00rootroot00000000000000hy-0.18.0/tests/resources/bin/__init__.hy000066400000000000000000000000521361554632000202470ustar00rootroot00000000000000(defn -null-fn-for-import-test [] pass) hy-0.18.0/tests/resources/bin/__main__.hy000066400000000000000000000000711361554632000202310ustar00rootroot00000000000000(print "This is a __main__.hy") (setv visited_main True) hy-0.18.0/tests/resources/bin/bytecompile.hy000066400000000000000000000001321361554632000210230ustar00rootroot00000000000000(defmacro m [] (print "Hello from macro") "boink") (print "The macro returned:" (m)) hy-0.18.0/tests/resources/bin/circular_macro_require.hy000066400000000000000000000002401361554632000232300ustar00rootroot00000000000000(defmacro bar [expr] `(print ~expr)) (defmacro foo [expr] `(do (require [tests.resources.bin.circular-macro-require [bar]]) (bar ~expr))) (foo 42) hy-0.18.0/tests/resources/bin/main.hy000066400000000000000000000001351361554632000174360ustar00rootroot00000000000000(defmain [&rest args] (print args) (print "Hello World") (if (in "exit1" args) 1)) hy-0.18.0/tests/resources/bin/nomain.hy000066400000000000000000000001251361554632000177720ustar00rootroot00000000000000(print "This Should Still Works") (defn main [] (print "This Should Not Work")) hy-0.18.0/tests/resources/bin/printenv.hy000066400000000000000000000000441361554632000203560ustar00rootroot00000000000000(import os) (print (. os environ)) hy-0.18.0/tests/resources/bin/require_and_eval.hy000066400000000000000000000001271361554632000220200ustar00rootroot00000000000000(require [hy.extra.anaphoric [ap-if]]) (print (eval '(ap-if (+ "a" "b") (+ it "c")))) hy-0.18.0/tests/resources/fails.hy000066400000000000000000000001511361554632000170360ustar00rootroot00000000000000"This module produces an error when imported." (defmacro a-macro [x] (+ x 1)) (print (a-macro 'blah)) hy-0.18.0/tests/resources/hello_world.hy000066400000000000000000000000261361554632000202530ustar00rootroot00000000000000(print "hello world") hy-0.18.0/tests/resources/icmd_test_file.hy000066400000000000000000000000161361554632000207120ustar00rootroot00000000000000(print "Hy!") hy-0.18.0/tests/resources/importer/000077500000000000000000000000001361554632000172425ustar00rootroot00000000000000hy-0.18.0/tests/resources/importer/a.hy000066400000000000000000000000241361554632000200200ustar00rootroot00000000000000(thisshouldnotwork) hy-0.18.0/tests/resources/importer/basic.hy000066400000000000000000000001501361554632000206610ustar00rootroot00000000000000;; This is a comment. It shall be ignored by the parser. (setv square (fn [x] (* x x))) hy-0.18.0/tests/resources/importer/circular.hy000066400000000000000000000001041361554632000214030ustar00rootroot00000000000000(setv a 1) (defn f [] (import circular) circular.a) (print (f)) hy-0.18.0/tests/resources/importer/docstring.hy000066400000000000000000000001131361554632000215730ustar00rootroot00000000000000"This module has a docstring. It covers multiple lines, too! " (setv a 1) hy-0.18.0/tests/resources/importer/foo/000077500000000000000000000000001361554632000200255ustar00rootroot00000000000000hy-0.18.0/tests/resources/importer/foo/__init__.hy000066400000000000000000000000561361554632000221270ustar00rootroot00000000000000(print "This is __init__.hy") (setv ext "hy") hy-0.18.0/tests/resources/importer/foo/__init__.py000066400000000000000000000000501361554632000221310ustar00rootroot00000000000000print('This is __init__.py') ext = 'py' hy-0.18.0/tests/resources/importer/foo/some_mod.hy000066400000000000000000000000561361554632000221720ustar00rootroot00000000000000(print "This is test_mod.hy") (setv ext "hy") hy-0.18.0/tests/resources/importer/foo/some_mod.py000066400000000000000000000000501361554632000221740ustar00rootroot00000000000000print('This is test_mod.py') ext = 'py' hy-0.18.0/tests/resources/macro_with_require.hy000066400000000000000000000017241361554632000216370ustar00rootroot00000000000000;; Require all the macros and make sure they don't pollute namespaces/modules ;; that require `*` from this. (require [tests.resources.macros [*]]) (defmacro test-module-macro [a] "The variable `macro-level-var' here should not bind to the same-named symbol in the expansion of `nonlocal-test-macro'." (setv macro-level-var "tests.resources.macros.macro-with-require") `(nonlocal-test-macro ~a)) (deftag test-module-tag [a] "The variable `macro-level-var' here should not bind to the same-named symbol in the expansion of `nonlocal-test-macro'." (setv macro-level-var "tests.resources.macros.macro-with-require") `(nonlocal-test-macro ~a)) (defmacro test-module-macro-2 [a] "The macro `local-test-macro` isn't in this module's namespace, so it better be in the expansion's!" `(local-test-macro ~a)) (deftag test-module-tag-2 [a] "The macro `local-test-macro` isn't in this module's namespace, so it better be in the expansion's!" `(local-test-macro ~a)) hy-0.18.0/tests/resources/macros.hy000066400000000000000000000014031361554632000172250ustar00rootroot00000000000000(setv module-name-var "tests.resources.macros") (defmacro thread-set-ab [] (defn f [&rest args] (.join "" (+ (, "a") args))) (setv variable (HySymbol (-> "b" (f)))) `(setv ~variable 2)) (defmacro threadtail-set-cd [] (defn f [&rest args] (.join "" (+ (, "c") args))) (setv variable (HySymbol (->> "d" (f)))) `(setv ~variable 5)) (defmacro test-macro [] '(setv blah 1)) (defmacro nonlocal-test-macro [x] "When called from `macro-with-require`'s macro(s), the first instance of `module-name-var` should resolve to the value in the module where this is defined, then the expansion namespace/module" `(.format (+ "This macro was created in {}, expanded in {} " "and passed the value {}.") ~module-name-var module-name-var ~x))hy-0.18.0/tests/resources/module_docstring_example.hy000066400000000000000000000000561361554632000230200ustar00rootroot00000000000000"This is the module docstring." (setv foo 5) hy-0.18.0/tests/resources/no_extension000066400000000000000000000000621361554632000200320ustar00rootroot00000000000000#!/usr/bin/env hy (print "This Should Still Work")hy-0.18.0/tests/resources/pydemo.hy000066400000000000000000000122041361554632000172370ustar00rootroot00000000000000;; Copyright 2020 the authors. ;; This file is part of Hy, which is free software licensed under the Expat ;; license. See the LICENSE. ;; This Hy module is intended to concisely demonstrate all of ;; Python's major syntactic features for the purpose of testing hy2py. "This is a module docstring." (setv mystring (* "foo" 3)) (setv long-string "This is a very long string literal, which would surely exceed any limitations on how long a line or a string literal can be. The string literal alone exceeds 256 characters. It also has a character outside the Basic Multilingual Plane: 😂. Here's a double quote: \". Here are some escaped newlines:\n\n\nHere is a literal newline: Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people’s hats off—then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me.") (setv identifier-that-has☝️💯☝️-to-be-mangled "ponies") (setv mynumber (+ 1 2)) (setv myhex 0x123) (setv mylong 1234567890987654321234567890987654321) (setv myfloat 3.34e15) (setv mynan NaN) (setv pinf Inf) (setv ninf -Inf) (setv mycomplex -Inf+5j) (setv mycomplex2 NaN-Infj) (setv num-expr (+ 3 (* 5 2) (- 6 (// 8 2)) (* (+ 1 2) (- 3 5)))) ; = 9 (setv mylist [1 2 3]) (setv mytuple (, "a" "b" "c")) (setv myset #{4 5 6}) (setv mydict {7 8 9 900 10 15}) (setv emptylist []) (setv emptytuple (,)) (setv emptyset #{}) (setv emptydict {}) (setv mylistcomp (lfor x (range 10) :if (% x 2) x)) (setv mysetcomp (sfor x (range 5) :if (not (% x 2)) x)) (setv mydictcomp (dfor k "abcde" :if (!= k "c") [k (.upper k)])) (setv mygenexpr (gfor x (cycle [1 2 3]) :if (!= x 2) x)) (setv attr-ref str.upper) (setv subscript (get "hello" 2)) (setv myslice (cut "hello" 1 None 2)) (setv call (len "hello")) (setv comparison (< "a" "b" "c")) (setv boolexpr (and (or True False) (not (and True False)))) (setv condexpr (if "" "x" "y")) (setv mylambda (fn [x] (+ x "z"))) (setv fstring1 f"hello {(+ 1 1)} world") (setv p "xyzzy") (setv fstring2 f"a{p !r :9}") (setv augassign 103) (//= augassign 4) (setv delstatement ["a" "b" "c" "d" "e"]) (del (get delstatement 1)) (import math) (import [math [sqrt]]) (import [math [sin :as sine]]) (import [datetime [*]]) (setv if-block "") (if 0 (do (+= if-block "a") (+= if-block "b")) (do (+= if-block "c") (+= if-block "d"))) (setv counter 4) (setv while-block "") (while counter (+= while-block "x") (-= counter 1) (else (+= while-block "e"))) (setv counter2 8) (setv cont-and-break "") (while counter2 (+= cont-and-break "x") (-= counter2 1) (when (= counter2 5) (continue)) (+= cont-and-break "y") (when (= counter2 3) (break)) (+= cont-and-break "z")) (setv for-block "") (for [x ["fo" "fi" "fu"]] (setv for-block (+ x for-block))) (try (assert (= 1 0)) (except [_ AssertionError] (setv caught-assertion True)) (finally (setv ran-finally True))) (try (raise (ValueError "payload")) (except [e ValueError] (setv myraise (str e)))) (try 1 (except [e ValueError] (raise)) (else (setv ran-try-else True))) (defn fun [a b &optional [c 9] [d 10] &rest args &kwargs kwargs] "function docstring" [a b c d args (sorted (.items kwargs))]) (setv funcall1 (fun 1 2 3 4 "a" "b" "c" :k1 "v1" :k2 "v2")) (setv funcall2 (fun 7 8 #* [9 10 11] #** {"x1" "y1" "x2" "y2"})) (defn returner [] (return 1) (raise (ValueError)) 2) (setv myret (returner)) (defn generator [] (for [x "abc"] (yield x))) (setv myyield (list (generator))) (with-decorator (fn [f] (setv f.newattr "hello") f) (defn mydecorated [])) (setv myglobal 102) (defn set-global [] (global myglobal) (+= myglobal 1)) (set-global) (defclass C1 []) ; Force the creation of a `pass` statement. (defclass C2 [C1] "class docstring" (setv attr1 5) (setv attr2 6)) (import [contextlib [closing]]) (setv closed []) (defclass Closeable [] (defn close [self] (.append closed self.x))) (with [c1 (closing (Closeable)) c2 (closing (Closeable))] (setv c1.x "v1") (setv c2.x "v2")) (setv closed1 (.copy closed)) (pys " closed = [] pys_accum = [] for i in range(5): with closing(Closeable()) as o: class C: pass o.x = C() pys_accum.append(i)") (setv py-accum (py "''.join(map(str, pys_accum))")) hy-0.18.0/tests/resources/relative_import.hy000066400000000000000000000000641361554632000211500ustar00rootroot00000000000000(import bin.printenv) (import sys) (print sys.path) hy-0.18.0/tests/resources/tlib.py000066400000000000000000000004141361554632000167040ustar00rootroot00000000000000from hy.macros import macro from hy import HyList, HyInteger SECRET_MESSAGE = "Hello World" @macro("qplah") def tmac(ETname, *tree): return HyList((HyInteger(8), ) + tree) @macro("parald") def tmac2(ETname, *tree): return HyList((HyInteger(9), ) + tree) hy-0.18.0/tests/test_bin.py000066400000000000000000000440631361554632000155570ustar00rootroot00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import os import re import shlex import subprocess import builtins from importlib.util import cache_from_source import pytest hy_dir = os.environ.get('HY_DIR', '') def hr(s=""): return "hy --repl-output-fn=hy.contrib.hy-repr.hy-repr " + s def run_cmd(cmd, stdin_data=None, expect=0, dontwritebytecode=False): env = dict(os.environ) if dontwritebytecode: env["PYTHONDONTWRITEBYTECODE"] = "1" else: env.pop("PYTHONDONTWRITEBYTECODE", None) cmd = shlex.split(cmd) cmd[0] = os.path.join(hy_dir, cmd[0]) p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=False, env=env) output = p.communicate(input=stdin_data) assert p.wait() == expect return output def rm(fpath): try: os.remove(fpath) except (IOError, OSError): try: os.rmdir(fpath) except (IOError, OSError): pass def test_bin_hy(): run_cmd("hy", "") def test_bin_hy_stdin(): output, _ = run_cmd("hy", '(koan)') assert "monk" in output output, _ = run_cmd("hy --spy", '(koan)') assert "monk" in output assert "\n Ummon" in output # --spy should work even when an exception is thrown output, _ = run_cmd("hy --spy", '(foof)') assert "foof()" in output def test_bin_hy_stdin_multiline(): output, _ = run_cmd("hy", '(+ "a" "b"\n"c" "d")') assert "'abcd'" in output def test_bin_hy_history(): output, _ = run_cmd("hy", '''(+ "a" "b") (+ "c" "d") (+ "e" "f") (.format "*1: {}, *2: {}, *3: {}," *1 *2 *3)''') assert "'*1: ef, *2: cd, *3: ab,'" in output output, _ = run_cmd("hy", '''(raise (Exception "TEST ERROR")) (+ "err: " (str *e))''') assert "'err: TEST ERROR'" in output def test_bin_hy_stdin_comments(): _, err_empty = run_cmd("hy", '') output, err = run_cmd("hy", '(+ "a" "b") ; "c"') assert "'ab'" in output assert err == err_empty _, err = run_cmd("hy", '; 1') assert err == err_empty def test_bin_hy_stdin_assignment(): # If the last form is an assignment, don't print the value. output, _ = run_cmd("hy", '(setv x (+ "A" "Z"))') assert "AZ" not in output output, _ = run_cmd("hy", '(setv x (+ "A" "Z")) (+ "B" "Y")') assert "AZ" not in output assert "BY" in output output, _ = run_cmd("hy", '(+ "B" "Y") (setv x (+ "A" "Z"))') assert "AZ" not in output assert "BY" not in output def test_bin_hy_stdin_as_arrow(): # https://github.com/hylang/hy/issues/1255 output, _ = run_cmd("hy", "(as-> 0 it (inc it) (inc it))") assert re.match(r"=>\s+2L?\s+=>", output) def test_bin_hy_stdin_error_underline_alignment(): _, err = run_cmd("hy", "(defmacro mabcdefghi [x] x)\n(mabcdefghi)") msg_idx = err.rindex(" (mabcdefghi)") assert msg_idx err_parts = err[msg_idx:].splitlines() assert err_parts[1].startswith(" ^----------^") assert err_parts[2].startswith("expanding macro mabcdefghi") assert (err_parts[3].startswith(" TypeError: mabcdefghi") or # PyPy can use a function's `__name__` instead of # `__code__.co_name`. err_parts[3].startswith(" TypeError: (mabcdefghi)")) def test_bin_hy_stdin_except_do(): # https://github.com/hylang/hy/issues/533 output, _ = run_cmd("hy", '(try (/ 1 0) (except [ZeroDivisionError] "hello"))') # noqa assert "hello" in output output, _ = run_cmd("hy", '(try (/ 1 0) (except [ZeroDivisionError] "aaa" "bbb" "ccc"))') # noqa assert "aaa" not in output assert "bbb" not in output assert "ccc" in output output, _ = run_cmd("hy", '(if True (do "xxx" "yyy" "zzz"))') assert "xxx" not in output assert "yyy" not in output assert "zzz" in output def test_bin_hy_stdin_unlocatable_hytypeerror(): # https://github.com/hylang/hy/issues/1412 # The chief test of interest here is the returncode assertion # inside run_cmd. _, err = run_cmd("hy", """ (import hy.errors) (raise (hy.errors.HyTypeError (+ "A" "Z") None '[] None))""") assert "AZ" in err def test_bin_hy_error_parts_length(): """Confirm that exception messages print arrows surrounding the affected expression.""" prg_str = """ (import hy.errors [hy.importer [hy-parse]]) (setv test-expr (hy-parse "(+ 1\n\n'a 2 3\n\n 1)")) (setv test-expr.start-line {}) (setv test-expr.start-column {}) (setv test-expr.end-column {}) (raise (hy.errors.HyLanguageError "this\nis\na\nmessage" test-expr None None)) """ # Up-arrows right next to each other. _, err = run_cmd("hy", prg_str.format(3, 1, 2)) msg_idx = err.rindex("HyLanguageError:") assert msg_idx err_parts = err[msg_idx:].splitlines()[1:] expected = [' File "", line 3', ' \'a 2 3', ' ^^', 'this', 'is', 'a', 'message'] for obs, exp in zip(err_parts, expected): assert obs.startswith(exp) # Make sure only one up-arrow is printed _, err = run_cmd("hy", prg_str.format(3, 1, 1)) msg_idx = err.rindex("HyLanguageError:") assert msg_idx err_parts = err[msg_idx:].splitlines()[1:] assert err_parts[2] == ' ^' # Make sure lines are printed in between arrows separated by more than one # character. _, err = run_cmd("hy", prg_str.format(3, 1, 6)) print(err) msg_idx = err.rindex("HyLanguageError:") assert msg_idx err_parts = err[msg_idx:].splitlines()[1:] assert err_parts[2] == ' ^----^' def test_bin_hy_stdin_bad_repr(): # https://github.com/hylang/hy/issues/1389 output, err = run_cmd("hy", """ (defclass BadRepr [] (defn __repr__ [self] (/ 0))) (BadRepr) (+ "A" "Z")""") assert "ZeroDivisionError" in err assert "AZ" in output def test_bin_hy_stdin_hy_repr(): output, _ = run_cmd("hy", '(+ [1] [2])') assert "[1, 2]" in output.replace('L', '') output, _ = run_cmd(hr(), '(+ [1] [2])') assert "[1 2]" in output output, _ = run_cmd(hr("--spy"), '(+ [1] [2])') assert "[1]+[2]" in output.replace('L', '').replace(' ', '') assert "[1 2]" in output # --spy should work even when an exception is thrown output, _ = run_cmd(hr("--spy"), '(+ [1] [2] (foof))') assert "[1]+[2]" in output.replace('L', '').replace(' ', '') def test_bin_hy_ignore_python_env(): os.environ.update({"PYTHONTEST": '0'}) output, _ = run_cmd("hy -c '(print (do (import os) (. os environ)))'") assert "PYTHONTEST" in output output, _ = run_cmd("hy -m tests.resources.bin.printenv") assert "PYTHONTEST" in output output, _ = run_cmd("hy tests/resources/bin/printenv.hy") assert "PYTHONTEST" in output output, _ = run_cmd("hy -E -c '(print (do (import os) (. os environ)))'") assert "PYTHONTEST" not in output os.environ.update({"PYTHONTEST": '0'}) output, _ = run_cmd("hy -E -m tests.resources.bin.printenv") assert "PYTHONTEST" not in output os.environ.update({"PYTHONTEST": '0'}) output, _ = run_cmd("hy -E tests/resources/bin/printenv.hy") assert "PYTHONTEST" not in output def test_bin_hy_cmd(): output, _ = run_cmd("hy -c \"(koan)\"") assert "monk" in output _, err = run_cmd("hy -c \"(koan\"", expect=1) assert "Premature end of input" in err def test_bin_hy_icmd(): output, _ = run_cmd("hy -i \"(koan)\"", "(ideas)") assert "monk" in output assert "figlet" in output def test_bin_hy_icmd_file(): output, _ = run_cmd("hy -i resources/icmd_test_file.hy", "(ideas)") assert "Hy!" in output file_relative_path = os.path.realpath(os.path.split('tests/resources/relative_import.hy')[0]) output, _ = run_cmd("hy -i tests/resources/relative_import.hy None") assert file_relative_path in output def test_bin_hy_icmd_and_spy(): output, _ = run_cmd("hy -i \"(+ [] [])\" --spy", "(+ 1 1)") assert "[] + []" in output def test_bin_hy_missing_file(): _, err = run_cmd("hy foobarbaz", expect=2) assert "No such file" in err def test_bin_hy_file_with_args(): assert "usage" in run_cmd("hy tests/resources/argparse_ex.hy -h")[0] assert "got c" in run_cmd("hy tests/resources/argparse_ex.hy -c bar")[0] assert "foo" in run_cmd("hy tests/resources/argparse_ex.hy -i foo")[0] assert "foo" in run_cmd("hy tests/resources/argparse_ex.hy -i foo -c bar")[0] # noqa def test_bin_hyc(): _, err = run_cmd("hyc", expect=0) assert err == '' _, err = run_cmd("hyc -", expect=0) assert err == '' output, _ = run_cmd("hyc -h") assert "usage" in output path = "tests/resources/argparse_ex.hy" output, _ = run_cmd("hyc " + path) assert "Compiling" in output assert os.path.exists(cache_from_source(path)) rm(cache_from_source(path)) def test_bin_hyc_missing_file(): _, err = run_cmd("hyc foobarbaz", expect=1) assert "[Errno 2]" in err def test_bin_hy_builtins(): # hy.cmdline replaces builtins.exit and builtins.quit # for use by hy's repl. import hy.cmdline # NOQA # this test will fail if run from IPython because IPython deletes # builtins.exit and builtins.quit assert str(builtins.exit) == "Use (exit) or Ctrl-D (i.e. EOF) to exit" assert type(builtins.exit) is hy.cmdline.HyQuitter assert str(builtins.quit) == "Use (quit) or Ctrl-D (i.e. EOF) to exit" assert type(builtins.quit) is hy.cmdline.HyQuitter def test_bin_hy_main(): output, _ = run_cmd("hy tests/resources/bin/main.hy") assert "Hello World" in output def test_bin_hy_main_args(): output, _ = run_cmd("hy tests/resources/bin/main.hy test 123") assert "test" in output assert "123" in output def test_bin_hy_main_exitvalue(): run_cmd("hy tests/resources/bin/main.hy exit1", expect=1) def test_bin_hy_no_main(): output, _ = run_cmd("hy tests/resources/bin/nomain.hy") assert "This Should Still Work" in output @pytest.mark.parametrize('scenario', ["normal", "prevent_by_force", "prevent_by_env", "prevent_by_option"]) @pytest.mark.parametrize('cmd_fmt', [['hy', '{fpath}'], ['hy', '-m', '{modname}'], ['hy', '-c', "'(import {modname})'"]]) def test_bin_hy_byte_compile(scenario, cmd_fmt): modname = "tests.resources.bin.bytecompile" fpath = modname.replace(".", "/") + ".hy" if scenario == 'prevent_by_option': cmd_fmt.insert(1, '-B') cmd = ' '.join(cmd_fmt).format(**locals()) rm(cache_from_source(fpath)) if scenario == "prevent_by_force": # Keep Hy from being able to byte-compile the module by # creating a directory at the target location. os.mkdir(cache_from_source(fpath)) # Whether or not we can byte-compile the module, we should be able # to run it. output, _ = run_cmd(cmd, dontwritebytecode=(scenario == "prevent_by_env")) assert "Hello from macro" in output assert "The macro returned: boink" in output if scenario == "normal": # That should've byte-compiled the module. assert os.path.exists(cache_from_source(fpath)) elif scenario == "prevent_by_env" or scenario == "prevent_by_option": # No byte-compiled version should've been created. assert not os.path.exists(cache_from_source(fpath)) # When we run the same command again, and we've byte-compiled the # module, the byte-compiled version should be run instead of the # source, in which case the macro shouldn't be run. output, _ = run_cmd(cmd) assert ("Hello from macro" in output) ^ (scenario == "normal") assert "The macro returned: boink" in output def test_bin_hy_module_main(): output, _ = run_cmd("hy -m tests.resources.bin.main") assert "Hello World" in output def test_bin_hy_module_main_file(): output, _ = run_cmd("hy -m tests.resources.bin") assert "This is a __main__.hy" in output output, _ = run_cmd("hy -m .tests.resources.bin", expect=1) def test_bin_hy_file_main_file(): output, _ = run_cmd("hy tests/resources/bin") assert "This is a __main__.hy" in output def test_bin_hy_file_sys_path(): """The test resource `relative_import.hy` will perform an absolute import of a module in its directory: a directory that is not on the `sys.path` of the script executing the module (i.e. `hy`). We want to make sure that Hy adopts the file's location in `sys.path`, instead of the runner's current dir (e.g. '' in `sys.path`). """ file_path, _ = os.path.split('tests/resources/relative_import.hy') file_relative_path = os.path.realpath(file_path) output, _ = run_cmd("hy tests/resources/relative_import.hy") assert file_relative_path in output def test_bin_hy_module_main_args(): output, _ = run_cmd("hy -m tests.resources.bin.main test 123") assert "test" in output assert "123" in output def test_bin_hy_module_main_exitvalue(): run_cmd("hy -m tests.resources.bin.main exit1", expect=1) def test_bin_hy_module_no_main(): output, _ = run_cmd("hy -m tests.resources.bin.nomain") assert "This Should Still Work" in output def test_bin_hy_sys_executable(): output, _ = run_cmd("hy -c '(do (import sys) (print sys.executable))'") assert output.strip().endswith('/hy') def test_bin_hy_file_no_extension(): """Confirm that a file with no extension is processed as Hy source""" output, _ = run_cmd("hy tests/resources/no_extension") assert "This Should Still Work" in output def test_bin_hy_circular_macro_require(): """Confirm that macros can require themselves during expansion and when run from the command line.""" # First, with no bytecode test_file = "tests/resources/bin/circular_macro_require.hy" rm(cache_from_source(test_file)) assert not os.path.exists(cache_from_source(test_file)) output, _ = run_cmd("hy {}".format(test_file)) assert "42" == output.strip() # Now, with bytecode assert os.path.exists(cache_from_source(test_file)) output, _ = run_cmd("hy {}".format(test_file)) assert "42" == output.strip() def test_bin_hy_macro_require(): """Confirm that a `require` will load macros into the non-module namespace (i.e. `exec(code, locals)`) used by `runpy.run_path`. In other words, this confirms that the AST generated for a `require` will load macros into the unnamed namespace its run in.""" # First, with no bytecode test_file = "tests/resources/bin/require_and_eval.hy" rm(cache_from_source(test_file)) assert not os.path.exists(cache_from_source(test_file)) output, _ = run_cmd("hy {}".format(test_file)) assert "abc" == output.strip() # Now, with bytecode assert os.path.exists(cache_from_source(test_file)) output, _ = run_cmd("hy {}".format(test_file)) assert "abc" == output.strip() def test_bin_hy_tracebacks(): """Make sure the printed tracebacks are correct.""" # We want the filtered tracebacks. os.environ['HY_DEBUG'] = '' def req_err(x): assert (x == 'hy.errors.HyRequireError: No module named ' "'not_a_real_module'") # Modeled after # > python -c 'import not_a_real_module' # Traceback (most recent call last): # File "", line 1, in # ImportError: No module named not_a_real_module _, error = run_cmd('hy', '(require not-a-real-module)') error_lines = error.splitlines() if error_lines[-1] == '': del error_lines[-1] assert len(error_lines) <= 10 # Rough check for the internal traceback filtering req_err(error_lines[4]) _, error = run_cmd('hy -c "(require not-a-real-module)"', expect=1) error_lines = error.splitlines() assert len(error_lines) <= 4 req_err(error_lines[-1]) output, error = run_cmd('hy -i "(require not-a-real-module)"') assert output.startswith('=> ') print(error.splitlines()) req_err(error.splitlines()[2]) # Modeled after # > python -c 'print("hi' # File "", line 1 # print("hi # ^ # SyntaxError: EOL while scanning string literal _, error = run_cmd(r'hy -c "(print \""', expect=1) peoi_re = ( r'Traceback \(most recent call last\):\n' r' File "(?:|string-[0-9a-f]+)", line 1\n' r' \(print "\n' r' \^\n' r'hy.lex.exceptions.PrematureEndOfInput: Partial string literal\n') assert re.search(peoi_re, error) # Modeled after # > python -i -c "print('" # File "", line 1 # print(' # ^ # SyntaxError: EOL while scanning string literal # >>> output, error = run_cmd(r'hy -i "(print \""') assert output.startswith('=> ') assert re.match(peoi_re, error) # Modeled after # > python -c 'print(a)' # Traceback (most recent call last): # File "", line 1, in # NameError: name 'a' is not defined output, error = run_cmd('hy -c "(print a)"', expect=1) error_lines = error.splitlines() assert error_lines[3] == ' File "", line 1, in ' # PyPy will add "global" to this error message, so we work around that. assert error_lines[-1].strip().replace(' global', '') == ( "NameError: name 'a' is not defined") # Modeled after # > python -c 'compile()' # Traceback (most recent call last): # File "", line 1, in # TypeError: Required argument 'source' (pos 1) not found output, error = run_cmd('hy -c "(compile)"', expect=1) error_lines = error.splitlines() assert error_lines[-2] == ' File "", line 1, in ' assert error_lines[-1].startswith('TypeError') hy-0.18.0/tests/test_hy2py.py000066400000000000000000000122341361554632000160550ustar00rootroot00000000000000# -*- encoding: utf-8 -*- # Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import math, itertools from hy import mangle from hy._compat import PY36 import hy.importer def test_direct_import(): import tests.resources.pydemo assert_stuff(tests.resources.pydemo) def test_hy2py_import(tmpdir): import subprocess python_code = subprocess.check_output( ["hy2py", "tests/resources/pydemo.hy"]).decode("UTF-8") path = tmpdir.join("pydemo.py") path.write(python_code) # Note: explicit "str" is needed for 3.5. assert_stuff(hy.importer._import_from_path("pydemo", str(path))) def assert_stuff(m): # This makes sure that automatically imported builtins go after docstrings. assert m.__doc__ == u'This is a module docstring.' assert m.mystring == "foofoofoo" assert m.long_string == u"This is a very long string literal, which would surely exceed any limitations on how long a line or a string literal can be. The string literal alone exceeds 256 characters. It also has a character outside the Basic Multilingual Plane: 😂. Here's a double quote: \". Here are some escaped newlines:\n\n\nHere is a literal newline:\nCall me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation. Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people’s hats off—then, I account it high time to get to sea as soon as I can. This is my substitute for pistol and ball. With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship. There is nothing surprising in this. If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me." assert getattr(m, mangle(u"identifier-that-has☝️💯☝️-to-be-mangled")) == "ponies" assert m.mynumber == 3 assert m.myhex == 0x123 assert m.mylong - 1234567890987654321234567890987654320 == 1 assert m.myfloat == 3.34e15 assert math.isnan(m.mynan) assert math.isinf(m.pinf) assert m.pinf > 0 assert math.isinf(m.ninf) assert m.ninf < 0 assert math.isinf(m.mycomplex.real) assert m.mycomplex.real < 0 assert m.mycomplex.imag == 5 assert math.isnan(m.mycomplex2.real) assert math.isinf(m.mycomplex2.imag) assert m.mycomplex2.imag < 0 assert m.num_expr == 9 assert m.mylist == [1, 2, 3] assert m.mytuple == ("a", "b", "c") assert m.myset == {4, 5, 6} assert m.mydict == {7: 8, 9: 900, 10: 15} assert m.emptylist == [] assert m.emptytuple == () assert m.emptyset == set() assert m.emptydict == {} assert m.mylistcomp == [1, 3, 5, 7, 9] assert m.mysetcomp == {0, 2, 4} assert m.mydictcomp == dict(a="A", b="B", d="D", e="E") assert type(m.mygenexpr) is type( (x for x in [1, 2, 3]) ) assert list(itertools.islice(m.mygenexpr, 5)) == [1, 3, 1, 3, 1] assert m.attr_ref is str.upper assert m.subscript == "l" assert m.myslice == "el" assert m.call == 5 assert m.comparison is True assert m.boolexpr is True assert m.condexpr == "y" assert type(m.mylambda) is type(lambda x: x + "z") assert m.mylambda("a") == "az" assert m.fstring1 == "hello 2 world" assert m.fstring2 == "a'xyzzy' " assert m.augassign == 25 assert m.delstatement == ["a", "c", "d", "e"] assert m.math is math assert m.sqrt is math.sqrt assert m.sine is math.sin import datetime assert m.timedelta is datetime.timedelta assert m.if_block == "cd" assert m.while_block == "xxxxe" assert m.cont_and_break == "xyzxyzxxyzxy" assert m.for_block == "fufifo" assert m.caught_assertion is True assert m.ran_finally is True assert m.myraise == "payload" assert m.ran_try_else is True assert type(m.fun) is type(lambda x: x) assert m.fun.__doc__ == "function docstring" assert m.funcall1 == [ 1, 2, 3, 4, ("a", "b", "c"), [("k1", "v1"), ("k2", "v2")]] assert m.funcall2 == [ 7, 8, 9, 10, (11,), [("x1", "y1"), ("x2", "y2")]] assert m.myret == 1 assert m.myyield == ["a", "b", "c"] assert m.mydecorated.newattr == "hello" assert m.myglobal == 103 class C: pass assert type(m.C1) is type(C) assert m.C2.__doc__ == "class docstring" assert issubclass(m.C2, m.C1) assert (m.C2.attr1, m.C2.attr2) == (5, 6) assert m.closed1 == ["v2", "v1"] assert len(m.closed) == 5 for a, b in itertools.combinations(m.closed, 2): assert type(a) is not type(b) assert m.pys_accum == [0, 1, 2, 3, 4] assert m.py_accum == "01234" hy-0.18.0/tests/test_lex.py000066400000000000000000000407511361554632000155770ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import sys import traceback import pytest from math import isnan from hy.models import (HyExpression, HyInteger, HyFloat, HyComplex, HySymbol, HyString, HyDict, HyList, HySet, HyKeyword) from hy.lex import tokenize from hy.lex.exceptions import LexException, PrematureEndOfInput from hy.errors import hy_exc_handler def peoi(): return pytest.raises(PrematureEndOfInput) def lexe(): return pytest.raises(LexException) def check_ex(execinfo, expected): output = traceback.format_exception_only(execinfo.type, execinfo.value) assert output[:-1] == expected[:-1] # Python 2.7 doesn't give the full exception name, so we compensate. assert output[-1].endswith(expected[-1]) def check_trace_output(capsys, execinfo, expected): sys.__excepthook__(execinfo.type, execinfo.value, execinfo.tb) captured_wo_filtering = capsys.readouterr()[-1].strip('\n') hy_exc_handler(execinfo.type, execinfo.value, execinfo.tb) captured_w_filtering = capsys.readouterr()[-1].strip('\n') output = captured_w_filtering.split('\n') # Make sure the filtered frames aren't the same as the unfiltered ones. assert output[:-1] != captured_wo_filtering.split('\n')[:-1] # Remove the origin frame lines. assert output[3:-1] == expected[:-1] # Python 2.7 doesn't give the full exception name, so we compensate. assert output[-1].endswith(expected[-1]) def test_lex_exception(): """ Ensure tokenize throws a fit on a partial input """ with peoi(): tokenize("(foo") with peoi(): tokenize("{foo bar") with peoi(): tokenize("(defn foo [bar]") with peoi(): tokenize("(foo \"bar") def test_unbalanced_exception(): """Ensure the tokenization fails on unbalanced expressions""" with lexe(): tokenize("(bar))") with lexe(): tokenize("(baz [quux]])") def test_lex_single_quote_err(): "Ensure tokenizing \"' \" throws a LexException that can be stringified" # https://github.com/hylang/hy/issues/1252 with lexe() as execinfo: tokenize("' ") check_ex(execinfo, [ ' File "", line 1\n', " '\n", ' ^\n', 'LexException: Could not identify the next token.\n']) 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_strings_exception(): """ Make sure tokenize throws when codec can't decode some bytes""" with lexe() as execinfo: tokenize('\"\\x8\"') check_ex(execinfo, [ ' File "", line 1\n', ' "\\x8"\n', ' ^\n', 'LexException: Can\'t convert "\\x8" to a HyString\n']) def test_lex_bracket_strings(): objs = tokenize("#[my delim[hello world]my delim]") assert objs == [HyString("hello world")] assert objs[0].brackets == "my delim" objs = tokenize("#[[squid]]") assert objs == [HyString("squid")] assert objs[0].brackets == "" 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_big_float(): # https://github.com/hylang/hy/issues/1448 assert tokenize("1e900") == [HyFloat(1e900)] assert tokenize("1e900-1e900j") == [HyComplex(1e900, -1e900)] def test_lex_nan_and_inf(): assert isnan(tokenize("NaN")[0]) assert tokenize("Nan") == [HySymbol("Nan")] assert tokenize("nan") == [HySymbol("nan")] assert tokenize("NAN") == [HySymbol("NAN")] assert tokenize("Inf") == [HyFloat(float("inf"))] assert tokenize("inf") == [HySymbol("inf")] assert tokenize("INF") == [HySymbol("INF")] assert tokenize("-Inf") == [HyFloat(float("-inf"))] assert tokenize("-inf") == [HySymbol("-inf")] assert tokenize("-INF") == [HySymbol("-INF")] def test_lex_expression_complex(): """ Make sure expressions can produce complex """ def t(x): return tokenize("(foo {})".format(x)) def f(x): return [HyExpression([HySymbol("foo"), x])] assert t("2.j") == f(HyComplex(2.j)) assert t("-0.5j") == f(HyComplex(-0.5j)) assert t("1.e7j") == f(HyComplex(1e7j)) assert t("j") == f(HySymbol("j")) assert isnan(t("NaNj")[0][1].imag) assert t("nanj") == f(HySymbol("nanj")) assert t("Inf+Infj") == f(HyComplex(complex(float("inf"), float("inf")))) assert t("Inf-Infj") == f(HyComplex(complex(float("inf"), float("-inf")))) assert t("Inf-INFj") == f(HySymbol("Inf-INFj")) def test_lex_digit_separators(): assert tokenize("1_000_000") == [HyInteger(1000000)] assert tokenize("1,000,000") == [HyInteger(1000000)] assert tokenize("1,000_000") == [HyInteger(1000000)] assert tokenize("1_000,000") == [HyInteger(1000000)] assert tokenize("0x_af") == [HyInteger(0xaf)] assert tokenize("0x,af") == [HyInteger(0xaf)] assert tokenize("0b_010") == [HyInteger(0b010)] assert tokenize("0b,010") == [HyInteger(0b010)] assert tokenize("0o_373") == [HyInteger(0o373)] assert tokenize("0o,373") == [HyInteger(0o373)] assert tokenize('1_2.3,4') == [HyFloat(12.34)] assert tokenize('1_2e3,4') == [HyFloat(12e34)] assert (tokenize("1,2/3_4") == [HyExpression([HySymbol("fraction"), HyInteger(12), HyInteger(34)])]) assert tokenize("1,0_00j") == [HyComplex(1000j)] assert tokenize("1,,,,___,____,,__,,2__,,,__") == [HyInteger(12)] assert (tokenize("_1,,,,___,____,,__,,2__,,,__") == [HySymbol("_1,,,,___,____,,__,,2__,,,__")]) assert (tokenize("1,,,,___,____,,__,,2__,q,__") == [HySymbol("1,,,,___,____,,__,,2__,q,__")]) def test_lex_bad_attrs(): with lexe() as execinfo: tokenize("1.foo") check_ex(execinfo, [ ' File "", line 1\n', ' 1.foo\n', ' ^\n', 'LexException: Cannot access attribute on anything other' ' than a name (in order to get attributes of expressions,' ' use `(. )` or `(. )`)\n']) with lexe(): tokenize("0.foo") with lexe(): tokenize("1.5.foo") with lexe(): tokenize("1e3.foo") with lexe(): tokenize("5j.foo") with lexe(): tokenize("3+5j.foo") with lexe(): tokenize("3.1+5.1j.foo") assert tokenize("j.foo") with lexe(): tokenize("3/4.foo") assert tokenize("a/1.foo") assert tokenize("1/a.foo") with lexe(): tokenize(":hello.foo") def test_lex_column_counting(): 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 symbol = entry[0] assert symbol.start_line == 1 assert symbol.start_column == 2 assert symbol.end_line == 1 assert symbol.end_column == 4 inner_expr = entry[1] assert inner_expr.start_line == 1 assert inner_expr.start_column == 6 assert inner_expr.end_line == 1 assert inner_expr.end_column == 14 def test_lex_column_counting_with_literal_newline(): string, symbol = tokenize('"apple\nblueberry" abc') assert string.start_line == 1 assert string.start_column == 1 assert string.end_line == 2 assert string.end_column == 10 assert symbol.start_line == 2 assert symbol.start_column == 12 assert symbol.end_line == 2 assert symbol.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(r"""(foo "foo\n")""")[0] assert entry[1] == "foo\n" entry = tokenize(r"""(foo r"foo\s")""")[0] assert entry[1] == r"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_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_tag_macro(): """Ensure tag macros are handled properly""" entry = tokenize("#^()") assert entry[0][0] == HySymbol("dispatch-tag-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_discard(): """Check that discarded terms are removed properly.""" # empty assert tokenize("") == [] # single assert tokenize("#_1") == [] # multiple assert tokenize("#_1 #_2") == [] assert tokenize("#_1 #_2 #_3") == [] # nested discard assert tokenize("#_ #_1 2") == [] assert tokenize("#_ #_ #_1 2 3") == [] # trailing assert tokenize("0") == [0] assert tokenize("0 #_1") == [0] assert tokenize("0 #_1 #_2") == [0] # leading assert tokenize("2") == [2] assert tokenize("#_1 2") == [2] assert tokenize("#_0 #_1 2") == [2] assert tokenize("#_ #_0 1 2") == [2] # both assert tokenize("#_1 2 #_3") == [2] assert tokenize("#_0 #_1 2 #_ #_3 4") == [2] # inside assert tokenize("0 #_1 2") == [0, 2] assert tokenize("0 #_1 #_2 3") == [0, 3] assert tokenize("0 #_ #_1 2 3") == [0, 3] # in HyList assert tokenize("[]") == [HyList([])] assert tokenize("[#_1]") == [HyList([])] assert tokenize("[#_1 #_2]") == [HyList([])] assert tokenize("[#_ #_1 2]") == [HyList([])] assert tokenize("[0]") == [HyList([HyInteger(0)])] assert tokenize("[0 #_1]") == [HyList([HyInteger(0)])] assert tokenize("[0 #_1 #_2]") == [HyList([HyInteger(0)])] assert tokenize("[2]") == [HyList([HyInteger(2)])] assert tokenize("[#_1 2]") == [HyList([HyInteger(2)])] assert tokenize("[#_0 #_1 2]") == [HyList([HyInteger(2)])] assert tokenize("[#_ #_0 1 2]") == [HyList([HyInteger(2)])] # in HySet assert tokenize("#{}") == [HySet()] assert tokenize("#{#_1}") == [HySet()] assert tokenize("#{0 #_1}") == [HySet([HyInteger(0)])] assert tokenize("#{#_1 0}") == [HySet([HyInteger(0)])] # in HyDict assert tokenize("{}") == [HyDict()] assert tokenize("{#_1}") == [HyDict()] assert tokenize("{#_0 1 2}") == [HyDict([HyInteger(1), HyInteger(2)])] assert tokenize("{1 #_0 2}") == [HyDict([HyInteger(1), HyInteger(2)])] assert tokenize("{1 2 #_0}") == [HyDict([HyInteger(1), HyInteger(2)])] # in HyExpression assert tokenize("()") == [HyExpression()] assert tokenize("(#_foo)") == [HyExpression()] assert tokenize("(#_foo bar)") == [HyExpression([HySymbol("bar")])] assert tokenize("(foo #_bar)") == [HyExpression([HySymbol("foo")])] assert tokenize("(foo :bar 1)") == [HyExpression([HySymbol("foo"), HyKeyword("bar"), HyInteger(1)])] assert tokenize("(foo #_:bar 1)") == [HyExpression([HySymbol("foo"), HyInteger(1)])] assert tokenize("(foo :bar #_1)") == [HyExpression([HySymbol("foo"), HyKeyword("bar")])] # discard term with nesting assert tokenize("[1 2 #_[a b c [d e [f g] h]] 3 4]") == [ HyList([HyInteger(1), HyInteger(2), HyInteger(3), HyInteger(4)]) ] # discard with other prefix syntax assert tokenize("a #_'b c") == [HySymbol("a"), HySymbol("c")] assert tokenize("a '#_b c") == [HySymbol("a"), HyExpression([HySymbol("quote"), HySymbol("c")])] assert tokenize("a '#_b #_c d") == [HySymbol("a"), HyExpression([HySymbol("quote"), HySymbol("d")])] assert tokenize("a '#_ #_b c d") == [HySymbol("a"), HyExpression([HySymbol("quote"), HySymbol("d")])] def test_lex_exception_filtering(capsys): """Confirm that the exception filtering works for lexer errors.""" # First, test for PrematureEndOfInput with peoi() as execinfo: tokenize(" \n (foo\n \n") check_trace_output(capsys, execinfo, [ ' File "", line 2', ' (foo', ' ^', 'PrematureEndOfInput: Premature end of input']) # Now, for a generic LexException with lexe() as execinfo: tokenize(" \n\n 1.foo ") check_trace_output(capsys, execinfo, [ ' File "", line 3', ' 1.foo', ' ^', 'LexException: Cannot access attribute on anything other' ' than a name (in order to get attributes of expressions,' ' use `(. )` or `(. )`)']) hy-0.18.0/tests/test_models.py000066400000000000000000000111641361554632000162660ustar00rootroot00000000000000# Copyright 2020 the authors. # This file is part of Hy, which is free software licensed under the Expat # license. See the LICENSE. import copy import hy from hy.models import (wrap_value, replace_hy_obj, HyString, HyInteger, HyList, HyDict, HySet, HyExpression, HyComplex, HyFloat, pretty) hy.models.COLORED = False def test_wrap_int(): """ Test conversion of integers.""" wrapped = wrap_value(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([0])) assert type(wrapped) == HyExpression assert type(wrapped[0]) == HyInteger assert wrapped == HyExpression([HyInteger(0)]) def test_replace_int(): """ Test replacing integers.""" replaced = replace_hy_obj(0, HyInteger(13)) assert replaced == HyInteger(0) def test_replace_string_type(): """Test replacing python string""" replaced = replace_hy_obj("foo", HyString("bar")) assert replaced == HyString("foo") def test_replace_tuple(): """ Test replacing tuples.""" replaced = replace_hy_obj((0, ), HyInteger(13)) assert type(replaced) == HyList assert type(replaced[0]) == HyInteger assert replaced == HyList([HyInteger(0)]) 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 == HyList([1, 2, 3, 3, 4, 5]) assert type(c) is 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([]) 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] hyset = HySet([3, 1, 2, 2]) def test_set(): assert list(hyset) == [3, 1, 2, 2] def test_number_model_copy(): i = HyInteger(42) assert (i == copy.copy(i)) assert (i == copy.deepcopy(i)) f = HyFloat(42.) assert (f == copy.copy(f)) assert (f == copy.deepcopy(f)) c = HyComplex(42j) assert (c == copy.copy(c)) assert (c == copy.deepcopy(c)) PRETTY_STRINGS = { k % ('[1.0] {1.0} (1.0) #{1.0}',): v.format(""" HyList([ HyFloat(1.0)]), HyDict([ HyFloat(1.0) # odd ]), HyExpression([ HyFloat(1.0)]), HySet([ HyFloat(1.0)])""") for k, v in {'[%s]': 'HyList([{}])', '#{%s}': 'HySet([{}])'}.items()} PRETTY_STRINGS.update({ '{[1.0] {1.0} (1.0) #{1.0}}': """HyDict([ HyList([ HyFloat(1.0)]), HyDict([ HyFloat(1.0) # odd ]) , HyExpression([ HyFloat(1.0)]), HySet([ HyFloat(1.0)]) ])""" , '[1.0 1j [] {} () #{}]': """HyList([ HyFloat(1.0), HyComplex(1j), HyList(), HyDict(), HyExpression(), HySet()])""" , '{{1j 2j} {1j 2j [][1j]} {[1j][] 1j 2j} {[1j][1j]}}': """HyDict([ HyDict([ HyComplex(1j), HyComplex(2j)]), HyDict([ HyComplex(1j), HyComplex(2j), HyList(), HyList([ HyComplex(1j)]) ]) , HyDict([ HyList([ HyComplex(1j)]), HyList() , HyComplex(1j), HyComplex(2j)]), HyDict([ HyList([ HyComplex(1j)]), HyList([ HyComplex(1j)]) ]) ])"""}) def test_compound_model_repr(): HY_LIST_MODELS = (HyExpression, HyDict, HySet, HyList) with pretty(False): for model in HY_LIST_MODELS: assert eval(repr(model())).__class__ is model assert eval(repr(model([1, 2]))) == model([1, 2]) assert eval(repr(model([1, 2, 3]))) == model([1, 2, 3]) for k, v in PRETTY_STRINGS.items(): # `str` should be pretty, even under `pretty(False)`. assert str(hy.read_str(k)) == v for k in PRETTY_STRINGS.keys(): assert eval(repr(hy.read_str(k))) == hy.read_str(k) with pretty(True): for model in HY_LIST_MODELS: assert eval(repr(model())).__class__ is model assert eval(repr(model([1, 2]))) == model([1, 2]) assert eval(repr(model([1, 2, 3]))) == model([1, 2, 3]) for k, v in PRETTY_STRINGS.items(): assert repr(hy.read_str(k)) == v hy-0.18.0/tox.ini000066400000000000000000000004211361554632000135350ustar00rootroot00000000000000[tox] envlist = py27,pypy,py34,py35,py36,pypy3,flake8 skipsdist = True [testenv] commands = pip install -e . pytest {posargs} passenv = TERM deps = -rrequirements-dev.txt [testenv:flake8] commands = flake8 hy bin tests --ignore=E121,E123,E126,E226,E24,E704,W503,E305