Merge branch 'develop' into feature/lambda-list-keyword
This commit is contained in:
commit
4d90123506
3
AUTHORS
3
AUTHORS
@ -4,3 +4,6 @@
|
|||||||
* Christopher Allan Webber <cwebber@dustycloud.org>
|
* Christopher Allan Webber <cwebber@dustycloud.org>
|
||||||
* Will Kahn-Greene <willg@bluesock.org>
|
* Will Kahn-Greene <willg@bluesock.org>
|
||||||
* James King <james@agentultra.com>
|
* James King <james@agentultra.com>
|
||||||
|
* Julien Danjou <julien@danjou.info>
|
||||||
|
* Nicolas Dandrimont <nicolas.dandrimont@crans.org>
|
||||||
|
* Gergely Nagy <algernon@madhouse-project.org>
|
||||||
|
33
ChangeLog
33
ChangeLog
@ -1,33 +0,0 @@
|
|||||||
2013-04-01 Paul Tagliamonte <paultag@debian.org>
|
|
||||||
|
|
||||||
* hy/compiler.py (compile_print_expression): Add routines for not creating
|
|
||||||
an ast.Print in Python 3.x, it's since become an ast.Call.
|
|
||||||
* Cleaned up the tests a bit, and added some coverage to some uncovered
|
|
||||||
modules
|
|
||||||
* hy/compiler.py (compile_do_expression): Add progn as an alias
|
|
||||||
(compile_def_expression): Add setf / setv as an alias for simple assignment
|
|
||||||
(compile_list_comrehension): Added list comprehensions.
|
|
||||||
|
|
||||||
2013-03-29 Paul Tagliamonte <paultag@debian.org>
|
|
||||||
|
|
||||||
* New release, 0.9.3.
|
|
||||||
|
|
||||||
2013-03-27 Paul Tagliamonte <paultag@debian.org>
|
|
||||||
|
|
||||||
* hy/compiler.py (compile_tuple): Add routines for tuples.
|
|
||||||
(compile_def_expression): add Tuple checking
|
|
||||||
(compile_for_expression): same
|
|
||||||
(compile_with_as_expression): same
|
|
||||||
|
|
||||||
2013-03-25 Paul Tagliamonte <paultag@debian.org>
|
|
||||||
|
|
||||||
* bin/hy (global): Added readline support to the hy REPL. History should
|
|
||||||
now be stored in ~/.hy-history
|
|
||||||
(global): added paren-matching bits, hacked in hard. Better solution?
|
|
||||||
|
|
||||||
2013-03-24 Paul Tagliamonte <paultag@debian.org>
|
|
||||||
|
|
||||||
* The release before this was version 0.9.2.
|
|
||||||
|
|
||||||
* Initial ChangeLog entry. There've been a lot of changes, but I won't bother
|
|
||||||
to fake history here.
|
|
17
LICENSE
Normal file
17
LICENSE
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
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.
|
3
Makefile
3
Makefile
@ -22,6 +22,9 @@ site:
|
|||||||
docs:
|
docs:
|
||||||
make -C docs html
|
make -C docs html
|
||||||
|
|
||||||
|
upload: r
|
||||||
|
python setup.py sdist upload
|
||||||
|
|
||||||
full: d tox site docs
|
full: d tox site docs
|
||||||
|
|
||||||
venv:
|
venv:
|
||||||
|
122
NEWS
Normal file
122
NEWS
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
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 then 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)
|
11
README.md
11
README.md
@ -7,6 +7,7 @@ Lisp and Python should love each other. Let's make it happen.
|
|||||||
|
|
||||||
[![Build Status](https://travis-ci.org/paultag/hy.png?branch=master)](https://travis-ci.org/paultag/hy)
|
[![Build Status](https://travis-ci.org/paultag/hy.png?branch=master)](https://travis-ci.org/paultag/hy)
|
||||||
|
|
||||||
|
|
||||||
Hylarious Hacks
|
Hylarious Hacks
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
@ -28,3 +29,13 @@ Well, I wrote Hy to help people realize one thing about Python:
|
|||||||
It's really goddamn awesome.
|
It's really goddamn awesome.
|
||||||
|
|
||||||
Oh, and lisps are neat.
|
Oh, and lisps are neat.
|
||||||
|
|
||||||
|
|
||||||
|
Project
|
||||||
|
-------
|
||||||
|
|
||||||
|
* Code: https://github.com/paultag/hy
|
||||||
|
* Docs: http://hy.rtfd.org/
|
||||||
|
* Quickstart: http://hy.rtfd.org/en/latest/quickstart.html
|
||||||
|
* Bug reports: We have no bugs! Your bugs are your own! (https://github.com/paultag/hy/issues)
|
||||||
|
* License: MIT (Expat)
|
||||||
|
5
TODO
5
TODO
@ -9,9 +9,6 @@
|
|||||||
|
|
||||||
+ Use (def) to imply global foo
|
+ Use (def) to imply global foo
|
||||||
|
|
||||||
- New Builtins:
|
|
||||||
+ While
|
|
||||||
|
|
||||||
- New macros:
|
- New macros:
|
||||||
+ loop
|
+ loop
|
||||||
|
|
||||||
@ -31,3 +28,5 @@
|
|||||||
|
|
||||||
- core tests (odd? even? true? false?) which
|
- core tests (odd? even? true? false?) which
|
||||||
build out to a lambda / function / expr
|
build out to a lambda / function / expr
|
||||||
|
|
||||||
|
- add -d flag (debug) for hy REPL based on @jd's try/catch
|
||||||
|
8
bin/hy
8
bin/hy
@ -51,8 +51,12 @@ class HyREPL(code.InteractiveConsole):
|
|||||||
tokens = process(_machine.nodes)
|
tokens = process(_machine.nodes)
|
||||||
|
|
||||||
_machine = Machine(Idle, 1, 0)
|
_machine = Machine(Idle, 1, 0)
|
||||||
_ast = hy_compile(tokens, root=ast.Interactive)
|
try:
|
||||||
code = compile(_ast, filename, symbol)
|
_ast = hy_compile(tokens, root=ast.Interactive)
|
||||||
|
code = compile(_ast, filename, symbol)
|
||||||
|
except Exception:
|
||||||
|
self.showtraceback()
|
||||||
|
return False
|
||||||
|
|
||||||
self.runcode(code)
|
self.runcode(code)
|
||||||
return False
|
return False
|
||||||
|
121
docs/_static/CC0_1.0.txt
vendored
Normal file
121
docs/_static/CC0_1.0.txt
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
Creative 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.
|
15
docs/_static/hy_logo-about.txt
vendored
Normal file
15
docs/_static/hy_logo-about.txt
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Hy 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
|
||||||
|
<http://creativecommons.org/publicdomain/zero/1.0/>.
|
111
docs/_static/hy_logo-paths.svg
vendored
Normal file
111
docs/_static/hy_logo-paths.svg
vendored
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="187.22501"
|
||||||
|
height="164.2733"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.3.1 r9886"
|
||||||
|
sodipodi:docname="hy_logo.svg"
|
||||||
|
inkscape:export-filename="/home/cwebber/devel/hy/docs/_static/hy_logo-paths.png"
|
||||||
|
inkscape:export-xdpi="200"
|
||||||
|
inkscape:export-ydpi="200">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="2.8"
|
||||||
|
inkscape:cx="124.29468"
|
||||||
|
inkscape:cy="108.77929"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:window-width="1440"
|
||||||
|
inkscape:window-height="874"
|
||||||
|
inkscape:window-x="1440"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-148.88306,-183.07397)">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum"
|
||||||
|
x="242.85715"
|
||||||
|
y="449.50504"
|
||||||
|
id="text2985"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2987"
|
||||||
|
x="242.85715"
|
||||||
|
y="449.50504"
|
||||||
|
style="font-size:100px" /></text>
|
||||||
|
<g
|
||||||
|
transform="scale(-1,1)"
|
||||||
|
style="font-size:100px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum Italic"
|
||||||
|
id="text2993">
|
||||||
|
<path
|
||||||
|
d="m -195.57143,292.36218 8.4,-48.9 c 0.3,-1.6 0.4,-3.1 0.4,-4.6 0,-11.59999 -10.20001,-17.2 -21.8,-17.2 -10.09999,0 -19.9,4.00001 -19.9,9.3 0,1.7 1.4,2.5 4.1,2.5 2.1,0 4.3,-1.1 6.4,-3.3 3,-3.19999 6.4,-4.8 10.2,-4.8 7.79999,0 11.9,5.40001 11.9,13.4 0,1.5 -0.2,3.2 -0.5,4.9 l -1.4,8.3 c -4.59999,-6.09999 -7.80001,-8.4 -15.3,-8.4 -11.19999,0 -15.8,6.70001 -17.4,15.9 l -5.6,24 c -1.9,8.99999 -7.1,12.1 -12.2,12.1 -1.9,0 -3.8,-0.5 -5.7,-1.5 l -1.7,2.3 c 4.5,3.5 8.8,5.2 12.9,5.2 5.99999,0 12.4,-4.50001 14.8,-13.1 l 7.8,-33.9 c 1.2,-3.39999 4.5,-6.3 8.7,-6.3 6.09999,0 8.6,2.10001 12.9,7.8 l -6.2,36.3 9.2,0"
|
||||||
|
style="font-style:italic;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum Italic"
|
||||||
|
id="path3256" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="scale(1,-1)"
|
||||||
|
style="font-size:100px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum Italic"
|
||||||
|
id="text2993-0">
|
||||||
|
<path
|
||||||
|
d="m 288.50714,-244.1122 8.4,-48.9 c 0.3,-1.6 0.4,-3.1 0.4,-4.6 0,-11.59999 -10.20001,-17.2 -21.8,-17.2 -10.09999,0 -19.9,4.00001 -19.9,9.3 0,1.7 1.4,2.5 4.1,2.5 2.1,0 4.3,-1.1 6.4,-3.3 3,-3.19999 6.4,-4.8 10.2,-4.8 7.79999,0 11.9,5.40001 11.9,13.4 0,1.5 -0.2,3.2 -0.5,4.9 l -1.4,8.3 c -4.6,-6.09999 -7.80001,-8.4 -15.3,-8.4 -11.19999,0 -15.8,6.70001 -17.4,15.9 l -5.6,24 c -1.9,8.99999 -7.10001,12.1 -12.2,12.1 -1.9,0 -3.8,-0.5 -5.7,-1.5 l -1.7,2.3 c 4.49999,3.5 8.8,5.2 12.9,5.2 5.99999,0 12.4,-4.50001 14.8,-13.1 l 7.8,-33.9 c 1.2,-3.39999 4.5,-6.3 8.7,-6.3 6.09999,0 8.6,2.10001 12.9,7.8 l -6.2,36.3 9.2,0"
|
||||||
|
style="font-style:italic;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum Italic"
|
||||||
|
id="path3253" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="matrix(0.76181009,-0.61556036,0.30983361,1.0623103,0,0)"
|
||||||
|
style="font-size:140.70762634px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum"
|
||||||
|
id="text3089">
|
||||||
|
<path
|
||||||
|
d="m 119.16228,379.55276 0,-5.34689 c -11.53801,-4.08052 -15.05571,-16.32212 -15.05571,-52.48394 l 0,-6.47256 c 0,-36.16182 3.5177,-48.40342 15.05571,-52.48394 l 0,-5.34689 c -4.64334,0.70354 -6.61326,1.26637 -9.14599,2.53274 -20.121173,9.56811 -19.276948,37.70966 -19.276948,58.53437 0,34.33263 3.236287,46.85565 14.352178,55.57951 4.22122,3.23627 7.3168,4.36194 14.07076,5.4876"
|
||||||
|
style=""
|
||||||
|
id="path3250" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="matrix(0.76181009,-0.61556036,0.30983361,1.0623103,0,0)"
|
||||||
|
style="font-size:140.70762634px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum"
|
||||||
|
id="text3089-6">
|
||||||
|
<path
|
||||||
|
d="m 260.12941,384.13592 c 0,-34.61404 -3.23629,-46.85565 -14.35218,-55.57951 -4.22122,-3.23628 -7.3168,-4.36194 -14.07076,-5.4876 l 0,5.34689 c 11.53801,4.08052 15.05571,16.32212 15.05571,52.48394 l 0,6.47255 c 0,36.16183 -3.5177,48.40343 -15.05571,52.48395 l 0,5.34689 c 4.64334,-0.70354 6.61326,-1.26637 9.14599,-2.53274 20.40259,-9.56811 19.27695,-38.69462 19.27695,-58.53437"
|
||||||
|
style=""
|
||||||
|
id="path3247" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.2 KiB |
BIN
docs/_static/hy_logo-smaller.png
vendored
Normal file
BIN
docs/_static/hy_logo-smaller.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
BIN
docs/_static/hy_logo.png
vendored
Normal file
BIN
docs/_static/hy_logo.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
125
docs/_static/hy_logo.svg
vendored
Normal file
125
docs/_static/hy_logo.svg
vendored
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="187.22501"
|
||||||
|
height="164.2733"
|
||||||
|
id="svg2"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.3.1 r9886"
|
||||||
|
sodipodi:docname="hy_logo2.svg"
|
||||||
|
inkscape:export-filename="/home/cwebber/devel/hy/docs/_static/hy_logo4.png"
|
||||||
|
inkscape:export-xdpi="200"
|
||||||
|
inkscape:export-ydpi="200">
|
||||||
|
<defs
|
||||||
|
id="defs4" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="2.8"
|
||||||
|
inkscape:cx="124.29468"
|
||||||
|
inkscape:cy="108.77929"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:window-width="1440"
|
||||||
|
inkscape:window-height="874"
|
||||||
|
inkscape:window-x="1440"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<metadata
|
||||||
|
id="metadata7">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(-148.88306,-183.07397)">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum"
|
||||||
|
x="242.85715"
|
||||||
|
y="449.50504"
|
||||||
|
id="text2985"
|
||||||
|
sodipodi:linespacing="125%"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2987"
|
||||||
|
x="242.85715"
|
||||||
|
y="449.50504"
|
||||||
|
style="font-size:100px" /></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:100px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum Italic"
|
||||||
|
x="-253.87143"
|
||||||
|
y="292.36218"
|
||||||
|
id="text2993"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="scale(-1,1)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2995"
|
||||||
|
x="-253.87143"
|
||||||
|
y="292.36218"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum Italic">λ</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:100px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum Italic"
|
||||||
|
x="230.20714"
|
||||||
|
y="-244.1122"
|
||||||
|
id="text2993-0"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="scale(1,-1)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan2995-6"
|
||||||
|
x="230.20714"
|
||||||
|
y="-244.1122"
|
||||||
|
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum Italic">λ</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:140.70762634px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum"
|
||||||
|
x="80.045563"
|
||||||
|
y="358.30591"
|
||||||
|
id="text3089"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(0.76181009,-0.61556036,0.30983361,1.0623103,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3091"
|
||||||
|
x="80.045563"
|
||||||
|
y="358.30591">(</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:140.70762634px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:TeXGyreBonum;-inkscape-font-specification:TeXGyreBonum"
|
||||||
|
x="229.31444"
|
||||||
|
y="423.95618"
|
||||||
|
id="text3089-6"
|
||||||
|
sodipodi:linespacing="125%"
|
||||||
|
transform="matrix(0.76181009,-0.61556036,0.30983361,1.0623103,0,0)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan3091-5"
|
||||||
|
x="229.31444"
|
||||||
|
y="423.95618">)</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.0 KiB |
68
docs/hacking.rst
Normal file
68
docs/hacking.rst
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
===============
|
||||||
|
Hacking on hy
|
||||||
|
===============
|
||||||
|
|
||||||
|
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 `Python virtual environment
|
||||||
|
<https://pypi.python.org/pypi/virtualenv>`_
|
||||||
|
2. (optional) go to https://github.com/paultag/hy and fork it
|
||||||
|
3. get the source code::
|
||||||
|
|
||||||
|
$ git clone git://github.com/paultag/hy.git
|
||||||
|
|
||||||
|
(or use your fork)
|
||||||
|
4. install for hacking::
|
||||||
|
|
||||||
|
$ python setup.py develop
|
||||||
|
|
||||||
|
5. install other develop-y requirements::
|
||||||
|
|
||||||
|
$ pip install -r requirements-dev.txt
|
||||||
|
|
||||||
|
6. do awesome things; make someone shriek in delight/disgust at what
|
||||||
|
you have wrought
|
||||||
|
|
||||||
|
|
||||||
|
Test!
|
||||||
|
=====
|
||||||
|
|
||||||
|
Tests are located in ``tests/``. We use `nose
|
||||||
|
<https://nose.readthedocs.org/en/latest/>`_.
|
||||||
|
|
||||||
|
To run the tests::
|
||||||
|
|
||||||
|
$ nosetests
|
||||||
|
|
||||||
|
Write tests---tests are good!
|
||||||
|
|
||||||
|
|
||||||
|
Document!
|
||||||
|
=========
|
||||||
|
|
||||||
|
Documentation is located in ``docs/``. We use `Sphinx
|
||||||
|
<http://sphinx-doc.org/>`_.
|
||||||
|
|
||||||
|
To build the docs in html::
|
||||||
|
|
||||||
|
$ cd docs
|
||||||
|
$ make html
|
||||||
|
|
||||||
|
Write docs---docs are good! Even this doc!
|
@ -1,6 +1,10 @@
|
|||||||
Welcome to Hy's documentation!
|
Welcome to Hy's documentation!
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
|
.. image:: _static/hy_logo-smaller.png
|
||||||
|
:alt: Hy logo
|
||||||
|
:align: left
|
||||||
|
|
||||||
Welcome to `Hy <https://github.com/paultag/hy>`_!
|
Welcome to `Hy <https://github.com/paultag/hy>`_!
|
||||||
Hy is a wonderful dialect of Lisp that's embedded in Python.
|
Hy is a wonderful dialect of Lisp that's embedded in Python.
|
||||||
Since Hy transforms its lisp code into the python Abstract Syntax
|
Since Hy transforms its lisp code into the python Abstract Syntax
|
||||||
@ -32,5 +36,7 @@ Contents:
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 3
|
:maxdepth: 3
|
||||||
|
|
||||||
|
quickstart
|
||||||
|
hacking
|
||||||
|
tutorial
|
||||||
language/index
|
language/index
|
||||||
.. library/index
|
|
||||||
|
101
docs/language/api.rst
Normal file
101
docs/language/api.rst
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
=================
|
||||||
|
Hy (the language)
|
||||||
|
=================
|
||||||
|
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
This is incomplete; please consider contributing to the documentation
|
||||||
|
effort.
|
||||||
|
|
||||||
|
|
||||||
|
Theory of Hy
|
||||||
|
============
|
||||||
|
|
||||||
|
Hy maintains, over everything else, 100% compatibility in both directions
|
||||||
|
with Python it's self. All Hy code follows a few simple rules. Memorize
|
||||||
|
this, it's going to come in handy.
|
||||||
|
|
||||||
|
These rules help make sure code is idiomatic and interface-able in both
|
||||||
|
languages.
|
||||||
|
|
||||||
|
|
||||||
|
* Symbols in earmufs will be translated to the uppercased version of that
|
||||||
|
string. For example, `*foo*` will become `FOO`.
|
||||||
|
|
||||||
|
* UTF-8 entities will be encoded using
|
||||||
|
`punycode <http://en.wikipedia.org/wiki/Punycode>`_ and prefixed with
|
||||||
|
`__hy_`. For instance, `⚘` will become `__hy_w7h`, and `♥` will become
|
||||||
|
`__hy_g6h`.
|
||||||
|
|
||||||
|
* Symbols that contain dashes will have them replaced with underscores. For
|
||||||
|
example, `render-template` will become `render_template`.
|
||||||
|
|
||||||
|
|
||||||
|
Builtins
|
||||||
|
========
|
||||||
|
|
||||||
|
Hy features a number 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.
|
||||||
|
|
||||||
|
do / progn
|
||||||
|
----------
|
||||||
|
|
||||||
|
the `do` or `progn` forms can be used in full code branches. What that means
|
||||||
|
is basically `(do)` and `(progn)` can only be used where a Python expression
|
||||||
|
can be used. These forms don't actually allow you to break Pythonic internals
|
||||||
|
such as `lambda` or `list-comp`, where you can only have one expression.
|
||||||
|
|
||||||
|
|
||||||
|
Some example usage
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(if true
|
||||||
|
(do (print "Side effects rock!")
|
||||||
|
(print "Yeah, really!")))
|
||||||
|
|
||||||
|
`do` can accept any number of arguments, from 1 to n.
|
||||||
|
|
||||||
|
|
||||||
|
throw / raise
|
||||||
|
-------------
|
||||||
|
|
||||||
|
the `throw` or `raise` forms can be used to raise an Exception at runtime.
|
||||||
|
|
||||||
|
|
||||||
|
Example usage
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(throw)
|
||||||
|
; re-rase the last exception
|
||||||
|
|
||||||
|
(throw IOError)
|
||||||
|
; Throw an IOError
|
||||||
|
|
||||||
|
(throw (IOError "foobar"))
|
||||||
|
; Throw an IOError("foobar")
|
||||||
|
|
||||||
|
|
||||||
|
`throw` can acccept a single argument (an `Exception` class or instance), or
|
||||||
|
no arguments to re-raise the last Exception.
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
---
|
||||||
|
|
||||||
|
.. TODO::
|
||||||
|
Document the else / finally syntax.
|
||||||
|
|
||||||
|
the `try` form is used to start a `try` / `catch` block. The form is used
|
||||||
|
as follows
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(try
|
||||||
|
(error-prone-function)
|
||||||
|
(catch [e SomeException] (err "It sucks!")))
|
||||||
|
|
||||||
|
`try` must contain at least one `catch` block, and may optionally have an
|
||||||
|
`else` or `finally` block.
|
@ -1,392 +1,11 @@
|
|||||||
Language Spec
|
|
||||||
=============
|
|
||||||
|
|
||||||
This bit covers a bit about Hy's lovable quirks and eccentricities.
|
Documentation Index
|
||||||
|
===================
|
||||||
|
|
||||||
In a nutshell, Hy is a lisp dialect, but one that converts its
|
Contents:
|
||||||
structure into Python... literally a conversion into Python's abstract
|
|
||||||
syntax tree! (Or to put it in more crude terms, Hy is lisp-stick on a
|
|
||||||
python!)
|
|
||||||
|
|
||||||
This is pretty cool because it means Hy is several things:
|
.. toctree::
|
||||||
|
:maxdepth: 3
|
||||||
|
|
||||||
- A lisp that feels very pythonic
|
api
|
||||||
- For lispers, a great way to use lisp's crazy powers but in the wide
|
internals
|
||||||
world of Python's libraries (why yes, you now can write a Django
|
|
||||||
application in lisp!)
|
|
||||||
- For pythonistas, a great way to start exploring lisp, from the
|
|
||||||
comfort of python!
|
|
||||||
- For everyone: a pleasant language that has a lot of neat ideas!
|
|
||||||
|
|
||||||
|
|
||||||
Basic intro to lisp for pythonistas
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
Okay, maybe you've never used lisp before, but you've used python!
|
|
||||||
|
|
||||||
A "hello world" in hy is actually super simple. Let's try it:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(print "hello world")
|
|
||||||
|
|
||||||
See? Easy! As you may have guessed, this is the same as the python
|
|
||||||
version of::
|
|
||||||
|
|
||||||
print "hello world"
|
|
||||||
|
|
||||||
To add up some super simple math, we could do:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(+ 1 3)
|
|
||||||
|
|
||||||
Which would return 4 and would be the equivalent of:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
1 + 3
|
|
||||||
|
|
||||||
What you'll notice is that the first item in the list is the function
|
|
||||||
being called and the rest of the arguments are the arguments being
|
|
||||||
passed in. In fact, in hy (as with most lisps) we can pass in
|
|
||||||
multiple arguments to the plus operator:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(+ 1 3 55)
|
|
||||||
|
|
||||||
Which would return 59.
|
|
||||||
|
|
||||||
Maybe you've heard of lisp before but don't know much about it. Lisp
|
|
||||||
isn't as hard as you might think, and hy inherits from python, so hy
|
|
||||||
is a great way to start learning lisp. The main thing that's obvious
|
|
||||||
about lisp is that there's a lot of parentheses. This might seem
|
|
||||||
confusing at first, but it isn't so hard. Let's look at some simple
|
|
||||||
math that's wrapped in a bunch of parentheses that we could enter into
|
|
||||||
the hy interpreter:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(setv result (- (/ (+ 1 3 88) 2) 8))
|
|
||||||
|
|
||||||
This would return 37. But why? Well, we could look at the equivalent
|
|
||||||
expression in python::
|
|
||||||
|
|
||||||
result = ((1 + 3 + 88) / 2) - 8
|
|
||||||
|
|
||||||
If you were to try to figure out how the above were to work in python,
|
|
||||||
you'd of course figure out the results by solving each inner
|
|
||||||
parenthesis. That's the same basic idea in hy. Let's try this
|
|
||||||
exercise first in python::
|
|
||||||
|
|
||||||
result = ((1 + 3 + 88) / 2) - 8
|
|
||||||
# simplified to...
|
|
||||||
result = (92 / 2) - 8
|
|
||||||
# simplified to...
|
|
||||||
result = 46 - 8
|
|
||||||
# simplified to...
|
|
||||||
result = 38
|
|
||||||
|
|
||||||
Now let's try the same thing in hy:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(setv result (- (/ (+ 1 3 88) 2) 8))
|
|
||||||
; simplified to...
|
|
||||||
(setv result (- (/ 92 2) 8))
|
|
||||||
; simplified to...
|
|
||||||
(setv result (- 46 8))
|
|
||||||
; simplified to...
|
|
||||||
(setv result 38)
|
|
||||||
|
|
||||||
As you probably guessed, this last expression with "setv" means to
|
|
||||||
assign the variable "result" to 38.
|
|
||||||
|
|
||||||
See? Not too hard!
|
|
||||||
|
|
||||||
This is the basic premise of lisp... lisp stands for "list
|
|
||||||
processing"... this means that the structure of the program is
|
|
||||||
actually lists of lists. (If you're familiar with python lists,
|
|
||||||
imagine the entire same structure as above but with square brackets
|
|
||||||
instead, any you'll be able to see the structure above as both a
|
|
||||||
program and a datastructure.) This is easier to understand with more
|
|
||||||
examples, so let's write a simple python program and test it and then
|
|
||||||
show the equivalent hy program::
|
|
||||||
|
|
||||||
def simple_conversation():
|
|
||||||
print "Hello! I'd like to get to know you. Tell me about yourself!"
|
|
||||||
name = raw_input("What is your name? ")
|
|
||||||
age = raw_input("What is your age? ")
|
|
||||||
print "Hello " + name + "! I see you are " + age + " years old."
|
|
||||||
|
|
||||||
simple_conversation()
|
|
||||||
|
|
||||||
If we ran this program, it might go like::
|
|
||||||
|
|
||||||
Hello! I'd like to get to know you. Tell me about yourself!
|
|
||||||
What is your name? Gary
|
|
||||||
What is your age? 38
|
|
||||||
Hello Gary! I see you are 38 years old.
|
|
||||||
|
|
||||||
Now let's look at the equivalent hy program:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(defn simple-conversation []
|
|
||||||
(print "Hello! I'd like to get to know you. Tell me about yourself!")
|
|
||||||
(setv name (raw_input "What is your name? "))
|
|
||||||
(setv age (raw_input "What is your age? "))
|
|
||||||
(print (+ "Hello " name "! I see you are "
|
|
||||||
age " years old.")))
|
|
||||||
|
|
||||||
(simple-conversation)
|
|
||||||
|
|
||||||
If you look at the above program, as long as you remember that the
|
|
||||||
first element in each list of the program is the function (or
|
|
||||||
macro... we'll get to those later) being called and that the rest are
|
|
||||||
the arguments, it's pretty easy to figure out what this all means.
|
|
||||||
(As you probably also guessed, defn is the hy method of defining
|
|
||||||
methods.)
|
|
||||||
|
|
||||||
Still, lots of people find this confusing at first because there's so
|
|
||||||
many parentheses, but there are plenty of things that can help make
|
|
||||||
this easier: keep indentation nice and use an editor with parenthesis
|
|
||||||
matching (this will help you figure out what each parenthesis pairs up
|
|
||||||
with) and things will start to feel comfortable.
|
|
||||||
|
|
||||||
There are some advantages to having a code structure that's actually a
|
|
||||||
very simple datastructure as the core of lisp is based on. For one
|
|
||||||
thing, it means that your programs are easy to parse and that the
|
|
||||||
entire actual structure of the program is very clearly exposed to you.
|
|
||||||
(There's an extra step in hy where the structure you see is converted
|
|
||||||
to python's own representations... in more "pure" lisps such as common
|
|
||||||
lisp or emacs lisp, the data structure you see for the code and the
|
|
||||||
data structure that is executed is much more literally close.)
|
|
||||||
|
|
||||||
Another implication of this is macros: if a program's structure is a
|
|
||||||
simple data structure, that means you can write code that can write
|
|
||||||
code very easily, meaning that implementing entirely new language
|
|
||||||
features can be very fast. Previous to hy, this wasn't very possible
|
|
||||||
for python programmers... now you too can make use of macros'
|
|
||||||
incredible power (just be careful to not aim them footward)!
|
|
||||||
|
|
||||||
|
|
||||||
Hy is python flavored lisp (or vice versa?)
|
|
||||||
-------------------------------------------
|
|
||||||
|
|
||||||
Hy converts to python's own abstract syntax tree, so you'll soon start
|
|
||||||
to find that all the familiar power of python is at your fingertips.
|
|
||||||
|
|
||||||
You have full access to python's data types and standard library in
|
|
||||||
hy. Let's experiment with this in the hy interpreter::
|
|
||||||
|
|
||||||
=> [1 2 3]
|
|
||||||
[1, 2, 3]
|
|
||||||
=> {"dog" "bark"
|
|
||||||
... "cat" "meow"}
|
|
||||||
...
|
|
||||||
{'dog': 'bark', 'cat': 'meow'}
|
|
||||||
|
|
||||||
(You may notice that at present, the common lisp method of quoting
|
|
||||||
things like so:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
'(1 2 3)
|
|
||||||
|
|
||||||
does not work. Instead, use square brackets as above.)
|
|
||||||
|
|
||||||
You also have access to all the builtin types' nice methods::
|
|
||||||
|
|
||||||
=> (.strip " fooooo ")
|
|
||||||
"fooooo"
|
|
||||||
|
|
||||||
What's this? Yes indeed, this is precisely the same as::
|
|
||||||
|
|
||||||
" fooooo ".strip()
|
|
||||||
|
|
||||||
That's right... lisp with dot notation! If we have this string
|
|
||||||
assigned as a variable, we can also do the following:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(setv this-string " fooooo ")
|
|
||||||
(this-string.strip)
|
|
||||||
|
|
||||||
What about conditionals?:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(if (try-some-thing)
|
|
||||||
(print "this is if true")
|
|
||||||
(print "this is if false"))
|
|
||||||
|
|
||||||
As you can tell above, the first argument to if is a truth test, the
|
|
||||||
second argument is a body if true, and the third argument (optional!)
|
|
||||||
is if false (ie, "else"!).
|
|
||||||
|
|
||||||
If you need to do more complex conditionals, you'll find that you
|
|
||||||
don't have elif available in hy. Instead, you should use something
|
|
||||||
called "cond". In python, you might do something like::
|
|
||||||
|
|
||||||
somevar = 33
|
|
||||||
if somevar > 50:
|
|
||||||
print "That variable is too big!"
|
|
||||||
elif somevar < 10:
|
|
||||||
print "That variable is too small!"
|
|
||||||
else:
|
|
||||||
print "That variable is jussssst right!"
|
|
||||||
|
|
||||||
In hy, you would do:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(cond
|
|
||||||
((> somevar 50)
|
|
||||||
(print "That variable is too big!"))
|
|
||||||
((< somevar 10)
|
|
||||||
(print "That variable is too small!"))
|
|
||||||
(true
|
|
||||||
(print "That variable is jussssst right!")))
|
|
||||||
|
|
||||||
What you'll notice is that cond switches off between a some statement
|
|
||||||
that is executed and checked conditionally for true or falseness, and
|
|
||||||
then a bit of code to execute if it turns out to be true. You'll also
|
|
||||||
notice that the "else" is implemented at the end simply by checking
|
|
||||||
for "true"... that's because true will always be true, so if we get
|
|
||||||
this far, we'll always run that one!
|
|
||||||
|
|
||||||
You might notice above that if you have code like:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(if some-condition
|
|
||||||
(body-if-true)
|
|
||||||
(body-if-false))
|
|
||||||
|
|
||||||
But wait! What if you want to execute more than one statment in the
|
|
||||||
body of one of these?
|
|
||||||
|
|
||||||
You can do the following:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(if (try-some-thing)
|
|
||||||
(do
|
|
||||||
(print "this is if true")
|
|
||||||
(print "and why not, let's keep talking about how true it is!))
|
|
||||||
(print "this one's still simply just false"))
|
|
||||||
|
|
||||||
You can see that we used "do" to wrap multiple statments. If you're
|
|
||||||
familiar with other lisps, this is the equivalent of "progn"
|
|
||||||
elsewhere.
|
|
||||||
|
|
||||||
Comments start with semicolons:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(print "this will run")
|
|
||||||
; (print "but this will not")
|
|
||||||
(+ 1 2 3) ; we'll execute the addition, but not this comment!
|
|
||||||
|
|
||||||
Looping is not hard but has a kind of special structure. In python,
|
|
||||||
we might do::
|
|
||||||
|
|
||||||
for i in range(10):
|
|
||||||
print "'i' is now at " + str(i)
|
|
||||||
|
|
||||||
The equivalent in hy would be:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(for (i (range 10))
|
|
||||||
(print (+ "'i' is now at " (str i))))
|
|
||||||
|
|
||||||
|
|
||||||
You can also import and make use of various python libraries. For
|
|
||||||
example:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(import os)
|
|
||||||
|
|
||||||
(if (os.path.isdir "/tmp/somedir")
|
|
||||||
(os.mkdir "/tmp/somedir/anotherdir")
|
|
||||||
(print "Hey, that path isn't there!"))
|
|
||||||
|
|
||||||
Comments start with semicolons:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(print "this will run")
|
|
||||||
; (print "but this will not")
|
|
||||||
(+ 1 2 3) ; we'll execute the addition, but not this comment!
|
|
||||||
|
|
||||||
And yes, we do have lisp comprehensions! In Python you might do::
|
|
||||||
|
|
||||||
odds_squared = [
|
|
||||||
pow(num, 2)
|
|
||||||
for num in range(100)
|
|
||||||
if num % 2 == 1]
|
|
||||||
|
|
||||||
In hy, you could do these like:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
; and a little more complex
|
|
||||||
(setv odds-squared
|
|
||||||
(list-comp
|
|
||||||
(pow num 2)
|
|
||||||
(num (range 100))
|
|
||||||
(= (% num 2) 1))
|
|
||||||
|
|
||||||
|
|
||||||
Protips!
|
|
||||||
--------
|
|
||||||
|
|
||||||
Hy also features something known as the "threading macro", a really neat
|
|
||||||
feature of Clojure's. The "threading macro" (written as "->"), is used
|
|
||||||
to avoid deep nesting of expressions.
|
|
||||||
|
|
||||||
The threading macro inserts each expression into the next expression's first
|
|
||||||
argument place.
|
|
||||||
|
|
||||||
Let's take the classic:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(loop (print (eval (read))))
|
|
||||||
|
|
||||||
Rather then write it like that, we can write it as follows:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(-> (read) (eval) (print) (loop))
|
|
||||||
|
|
||||||
Now, using `python-sh <http://amoffat.github.com/sh/>`_, we can show
|
|
||||||
how the threading macro (because of python-sh's setup) can be used like
|
|
||||||
a pipe:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
=> (import-from sh cat grep wc)
|
|
||||||
=> (-> (cat "/usr/share/dict/words") (grep "-E" "^hy") (wc "-l"))
|
|
||||||
210
|
|
||||||
|
|
||||||
Which, of course, expands out to:
|
|
||||||
|
|
||||||
.. code-block:: clj
|
|
||||||
|
|
||||||
(wc (grep (cat "/usr/share/dict/words") "-E" "^hy") "-l")
|
|
||||||
|
|
||||||
Much more readable, no! Use the threading macro!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TODO
|
|
||||||
----
|
|
||||||
|
|
||||||
- How do I define classes?
|
|
||||||
- Blow your mind with macros!
|
|
||||||
- Where's my banana???
|
|
||||||
|
27
docs/language/internals.rst
Normal file
27
docs/language/internals.rst
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
=========================
|
||||||
|
Internal Hy Documentation
|
||||||
|
=========================
|
||||||
|
|
||||||
|
.. info::
|
||||||
|
These bits are for folks who hack on Hy it's self, mostly!
|
||||||
|
|
||||||
|
|
||||||
|
Hy Models
|
||||||
|
=========
|
||||||
|
|
||||||
|
.. TODO::
|
||||||
|
Write this.
|
||||||
|
|
||||||
|
|
||||||
|
Hy Macros
|
||||||
|
=========
|
||||||
|
|
||||||
|
.. TODO::
|
||||||
|
Write this.
|
||||||
|
|
||||||
|
|
||||||
|
Hy Compiler Builtins
|
||||||
|
====================
|
||||||
|
|
||||||
|
.. TODO::
|
||||||
|
Write this.
|
38
docs/quickstart.rst
Normal file
38
docs/quickstart.rst
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
==========
|
||||||
|
Quickstart
|
||||||
|
==========
|
||||||
|
|
||||||
|
HOW TO GET HY REAL FAST:
|
||||||
|
|
||||||
|
1. create a `Python virtual environment
|
||||||
|
<https://pypi.python.org/pypi/virtualenv>`_
|
||||||
|
2. activate your Python virtual environment
|
||||||
|
3. ``pip install hy``
|
||||||
|
4. start a REPL with ``hy``
|
||||||
|
5. type stuff in the REPL::
|
||||||
|
|
||||||
|
=> (print "Hy!")
|
||||||
|
Hy!
|
||||||
|
=> (defn salutationsnm [name] (print (+ "Hy " name "!")))
|
||||||
|
=> (salutationsnm "YourName")
|
||||||
|
Hy YourName!
|
||||||
|
|
||||||
|
etc
|
||||||
|
|
||||||
|
6. hit CTRL-D when you're done
|
||||||
|
|
||||||
|
OMG! That's amazing! I want to write a hy program.
|
||||||
|
|
||||||
|
7. open up an elite programming editor
|
||||||
|
8. type::
|
||||||
|
|
||||||
|
(print "i was going to code in python syntax, but then i got hy")
|
||||||
|
|
||||||
|
9. save as ``test_program_of_awesome.hy``
|
||||||
|
10. run::
|
||||||
|
|
||||||
|
hy test_program_of_awesome.hy
|
||||||
|
|
||||||
|
11. take a deep breath so as to not hyperventilate
|
||||||
|
12. smile villainously and sneak off to your hydeaway and do
|
||||||
|
unspeakable things
|
414
docs/tutorial.rst
Normal file
414
docs/tutorial.rst
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
========
|
||||||
|
Tutorial
|
||||||
|
========
|
||||||
|
|
||||||
|
Welcome to the Hy tutorial!
|
||||||
|
|
||||||
|
In a nutshell, Hy is a lisp dialect, but one that converts its
|
||||||
|
structure into Python... literally a conversion into Python's abstract
|
||||||
|
syntax tree! (Or to put it in more crude terms, Hy is lisp-stick on a
|
||||||
|
python!)
|
||||||
|
|
||||||
|
This is pretty cool because it means Hy is several things:
|
||||||
|
|
||||||
|
- A lisp that feels very pythonic
|
||||||
|
- For lispers, a great way to use lisp's crazy powers but in the wide
|
||||||
|
world of Python's libraries (why yes, you now can write a Django
|
||||||
|
application in lisp!)
|
||||||
|
- For pythonistas, a great way to start exploring lisp, from the
|
||||||
|
comfort of python!
|
||||||
|
- For everyone: a pleasant language that has a lot of neat ideas!
|
||||||
|
|
||||||
|
|
||||||
|
Basic intro to lisp for pythonistas
|
||||||
|
===================================
|
||||||
|
|
||||||
|
Okay, maybe you've never used lisp before, but you've used python!
|
||||||
|
|
||||||
|
A "hello world" in hy is actually super simple. Let's try it:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(print "hello world")
|
||||||
|
|
||||||
|
See? Easy! As you may have guessed, this is the same as the python
|
||||||
|
version of::
|
||||||
|
|
||||||
|
print "hello world"
|
||||||
|
|
||||||
|
To add up some super simple math, we could do:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(+ 1 3)
|
||||||
|
|
||||||
|
Which would return 4 and would be the equivalent of:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
1 + 3
|
||||||
|
|
||||||
|
What you'll notice is that the first item in the list is the function
|
||||||
|
being called and the rest of the arguments are the arguments being
|
||||||
|
passed in. In fact, in hy (as with most lisps) we can pass in
|
||||||
|
multiple arguments to the plus operator:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(+ 1 3 55)
|
||||||
|
|
||||||
|
Which would return 59.
|
||||||
|
|
||||||
|
Maybe you've heard of lisp before but don't know much about it. Lisp
|
||||||
|
isn't as hard as you might think, and hy inherits from python, so hy
|
||||||
|
is a great way to start learning lisp. The main thing that's obvious
|
||||||
|
about lisp is that there's a lot of parentheses. This might seem
|
||||||
|
confusing at first, but it isn't so hard. Let's look at some simple
|
||||||
|
math that's wrapped in a bunch of parentheses that we could enter into
|
||||||
|
the hy interpreter:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(setv result (- (/ (+ 1 3 88) 2) 8))
|
||||||
|
|
||||||
|
This would return 37. But why? Well, we could look at the equivalent
|
||||||
|
expression in python::
|
||||||
|
|
||||||
|
result = ((1 + 3 + 88) / 2) - 8
|
||||||
|
|
||||||
|
If you were to try to figure out how the above were to work in python,
|
||||||
|
you'd of course figure out the results by solving each inner
|
||||||
|
parenthesis. That's the same basic idea in hy. Let's try this
|
||||||
|
exercise first in python::
|
||||||
|
|
||||||
|
result = ((1 + 3 + 88) / 2) - 8
|
||||||
|
# simplified to...
|
||||||
|
result = (92 / 2) - 8
|
||||||
|
# simplified to...
|
||||||
|
result = 46 - 8
|
||||||
|
# simplified to...
|
||||||
|
result = 38
|
||||||
|
|
||||||
|
Now let's try the same thing in hy:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(setv result (- (/ (+ 1 3 88) 2) 8))
|
||||||
|
; simplified to...
|
||||||
|
(setv result (- (/ 92 2) 8))
|
||||||
|
; simplified to...
|
||||||
|
(setv result (- 46 8))
|
||||||
|
; simplified to...
|
||||||
|
(setv result 38)
|
||||||
|
|
||||||
|
As you probably guessed, this last expression with "setv" means to
|
||||||
|
assign the variable "result" to 38.
|
||||||
|
|
||||||
|
See? Not too hard!
|
||||||
|
|
||||||
|
This is the basic premise of lisp... lisp stands for "list
|
||||||
|
processing"... this means that the structure of the program is
|
||||||
|
actually lists of lists. (If you're familiar with python lists,
|
||||||
|
imagine the entire same structure as above but with square brackets
|
||||||
|
instead, any you'll be able to see the structure above as both a
|
||||||
|
program and a datastructure.) This is easier to understand with more
|
||||||
|
examples, so let's write a simple python program and test it and then
|
||||||
|
show the equivalent hy program::
|
||||||
|
|
||||||
|
def simple_conversation():
|
||||||
|
print "Hello! I'd like to get to know you. Tell me about yourself!"
|
||||||
|
name = raw_input("What is your name? ")
|
||||||
|
age = raw_input("What is your age? ")
|
||||||
|
print "Hello " + name + "! I see you are " + age + " years old."
|
||||||
|
|
||||||
|
simple_conversation()
|
||||||
|
|
||||||
|
If we ran this program, it might go like::
|
||||||
|
|
||||||
|
Hello! I'd like to get to know you. Tell me about yourself!
|
||||||
|
What is your name? Gary
|
||||||
|
What is your age? 38
|
||||||
|
Hello Gary! I see you are 38 years old.
|
||||||
|
|
||||||
|
Now let's look at the equivalent hy program:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(defn simple-conversation []
|
||||||
|
(print "Hello! I'd like to get to know you. Tell me about yourself!")
|
||||||
|
(setv name (raw_input "What is your name? "))
|
||||||
|
(setv age (raw_input "What is your age? "))
|
||||||
|
(print (+ "Hello " name "! I see you are "
|
||||||
|
age " years old.")))
|
||||||
|
|
||||||
|
(simple-conversation)
|
||||||
|
|
||||||
|
If you look at the above program, as long as you remember that the
|
||||||
|
first element in each list of the program is the function (or
|
||||||
|
macro... we'll get to those later) being called and that the rest are
|
||||||
|
the arguments, it's pretty easy to figure out what this all means.
|
||||||
|
(As you probably also guessed, defn is the hy method of defining
|
||||||
|
methods.)
|
||||||
|
|
||||||
|
Still, lots of people find this confusing at first because there's so
|
||||||
|
many parentheses, but there are plenty of things that can help make
|
||||||
|
this easier: keep indentation nice and use an editor with parenthesis
|
||||||
|
matching (this will help you figure out what each parenthesis pairs up
|
||||||
|
with) and things will start to feel comfortable.
|
||||||
|
|
||||||
|
There are some advantages to having a code structure that's actually a
|
||||||
|
very simple datastructure as the core of lisp is based on. For one
|
||||||
|
thing, it means that your programs are easy to parse and that the
|
||||||
|
entire actual structure of the program is very clearly exposed to you.
|
||||||
|
(There's an extra step in hy where the structure you see is converted
|
||||||
|
to python's own representations... in more "pure" lisps such as common
|
||||||
|
lisp or emacs lisp, the data structure you see for the code and the
|
||||||
|
data structure that is executed is much more literally close.)
|
||||||
|
|
||||||
|
Another implication of this is macros: if a program's structure is a
|
||||||
|
simple data structure, that means you can write code that can write
|
||||||
|
code very easily, meaning that implementing entirely new language
|
||||||
|
features can be very fast. Previous to hy, this wasn't very possible
|
||||||
|
for python programmers... now you too can make use of macros'
|
||||||
|
incredible power (just be careful to not aim them footward)!
|
||||||
|
|
||||||
|
|
||||||
|
Hy is python flavored lisp (or vice versa?)
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
Hy converts to python's own abstract syntax tree, so you'll soon start
|
||||||
|
to find that all the familiar power of python is at your fingertips.
|
||||||
|
|
||||||
|
You have full access to python's data types and standard library in
|
||||||
|
hy. Let's experiment with this in the hy interpreter::
|
||||||
|
|
||||||
|
=> [1 2 3]
|
||||||
|
[1, 2, 3]
|
||||||
|
=> {"dog" "bark"
|
||||||
|
... "cat" "meow"}
|
||||||
|
...
|
||||||
|
{'dog': 'bark', 'cat': 'meow'}
|
||||||
|
|
||||||
|
(You may notice that at present, the common lisp method of quoting
|
||||||
|
things like so:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
'(1 2 3)
|
||||||
|
|
||||||
|
does not work. Instead, use square brackets as above.)
|
||||||
|
|
||||||
|
You also have access to all the builtin types' nice methods::
|
||||||
|
|
||||||
|
=> (.strip " fooooo ")
|
||||||
|
"fooooo"
|
||||||
|
|
||||||
|
What's this? Yes indeed, this is precisely the same as::
|
||||||
|
|
||||||
|
" fooooo ".strip()
|
||||||
|
|
||||||
|
That's right... lisp with dot notation! If we have this string
|
||||||
|
assigned as a variable, we can also do the following:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(setv this-string " fooooo ")
|
||||||
|
(this-string.strip)
|
||||||
|
|
||||||
|
What about conditionals?:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(if (try-some-thing)
|
||||||
|
(print "this is if true")
|
||||||
|
(print "this is if false"))
|
||||||
|
|
||||||
|
As you can tell above, the first argument to if is a truth test, the
|
||||||
|
second argument is a body if true, and the third argument (optional!)
|
||||||
|
is if false (ie, "else"!).
|
||||||
|
|
||||||
|
If you need to do more complex conditionals, you'll find that you
|
||||||
|
don't have elif available in hy. Instead, you should use something
|
||||||
|
called "cond". In python, you might do something like::
|
||||||
|
|
||||||
|
somevar = 33
|
||||||
|
if somevar > 50:
|
||||||
|
print "That variable is too big!"
|
||||||
|
elif somevar < 10:
|
||||||
|
print "That variable is too small!"
|
||||||
|
else:
|
||||||
|
print "That variable is jussssst right!"
|
||||||
|
|
||||||
|
In hy, you would do:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(cond
|
||||||
|
((> somevar 50)
|
||||||
|
(print "That variable is too big!"))
|
||||||
|
((< somevar 10)
|
||||||
|
(print "That variable is too small!"))
|
||||||
|
(true
|
||||||
|
(print "That variable is jussssst right!")))
|
||||||
|
|
||||||
|
What you'll notice is that cond switches off between a some statement
|
||||||
|
that is executed and checked conditionally for true or falseness, and
|
||||||
|
then a bit of code to execute if it turns out to be true. You'll also
|
||||||
|
notice that the "else" is implemented at the end simply by checking
|
||||||
|
for "true"... that's because true will always be true, so if we get
|
||||||
|
this far, we'll always run that one!
|
||||||
|
|
||||||
|
You might notice above that if you have code like:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(if some-condition
|
||||||
|
(body-if-true)
|
||||||
|
(body-if-false))
|
||||||
|
|
||||||
|
But wait! What if you want to execute more than one statment in the
|
||||||
|
body of one of these?
|
||||||
|
|
||||||
|
You can do the following:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(if (try-some-thing)
|
||||||
|
(do
|
||||||
|
(print "this is if true")
|
||||||
|
(print "and why not, let's keep talking about how true it is!))
|
||||||
|
(print "this one's still simply just false"))
|
||||||
|
|
||||||
|
You can see that we used "do" to wrap multiple statments. If you're
|
||||||
|
familiar with other lisps, this is the equivalent of "progn"
|
||||||
|
elsewhere.
|
||||||
|
|
||||||
|
Comments start with semicolons:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(print "this will run")
|
||||||
|
; (print "but this will not")
|
||||||
|
(+ 1 2 3) ; we'll execute the addition, but not this comment!
|
||||||
|
|
||||||
|
Looping is not hard but has a kind of special structure. In python,
|
||||||
|
we might do::
|
||||||
|
|
||||||
|
for i in range(10):
|
||||||
|
print "'i' is now at " + str(i)
|
||||||
|
|
||||||
|
The equivalent in hy would be:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(for (i (range 10))
|
||||||
|
(print (+ "'i' is now at " (str i))))
|
||||||
|
|
||||||
|
|
||||||
|
You can also import and make use of various python libraries. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(import os)
|
||||||
|
|
||||||
|
(if (os.path.isdir "/tmp/somedir")
|
||||||
|
(os.mkdir "/tmp/somedir/anotherdir")
|
||||||
|
(print "Hey, that path isn't there!"))
|
||||||
|
|
||||||
|
Comments start with semicolons:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(print "this will run")
|
||||||
|
; (print "but this will not")
|
||||||
|
(+ 1 2 3) ; we'll execute the addition, but not this comment!
|
||||||
|
|
||||||
|
And yes, we do have lisp comprehensions! In Python you might do::
|
||||||
|
|
||||||
|
odds_squared = [
|
||||||
|
pow(num, 2)
|
||||||
|
for num in range(100)
|
||||||
|
if num % 2 == 1]
|
||||||
|
|
||||||
|
In hy, you could do these like:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(setv odds-squared
|
||||||
|
(list-comp
|
||||||
|
(pow num 2)
|
||||||
|
(num (range 100))
|
||||||
|
(= (% num 2) 1)))
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
; And, an example stolen shamelessly from a Clojure page:
|
||||||
|
; Let's list all the blocks of a Chessboard:
|
||||||
|
|
||||||
|
(list-comp
|
||||||
|
(, x y)
|
||||||
|
(x (range 9)
|
||||||
|
y "ABCDEFGH"))
|
||||||
|
|
||||||
|
; [(0, 'A'), (0, 'B'), (0, 'C'), (0, 'D'), (0, 'E'), (0, 'F'), (0, 'G'), (0, 'H'),
|
||||||
|
; (1, 'A'), (1, 'B'), (1, 'C'), (1, 'D'), (1, 'E'), (1, 'F'), (1, 'G'), (1, 'H'),
|
||||||
|
; (2, 'A'), (2, 'B'), (2, 'C'), (2, 'D'), (2, 'E'), (2, 'F'), (2, 'G'), (2, 'H'),
|
||||||
|
; (3, 'A'), (3, 'B'), (3, 'C'), (3, 'D'), (3, 'E'), (3, 'F'), (3, 'G'), (3, 'H'),
|
||||||
|
; (4, 'A'), (4, 'B'), (4, 'C'), (4, 'D'), (4, 'E'), (4, 'F'), (4, 'G'), (4, 'H'),
|
||||||
|
; (5, 'A'), (5, 'B'), (5, 'C'), (5, 'D'), (5, 'E'), (5, 'F'), (5, 'G'), (5, 'H'),
|
||||||
|
; (6, 'A'), (6, 'B'), (6, 'C'), (6, 'D'), (6, 'E'), (6, 'F'), (6, 'G'), (6, 'H'),
|
||||||
|
; (7, 'A'), (7, 'B'), (7, 'C'), (7, 'D'), (7, 'E'), (7, 'F'), (7, 'G'), (7, 'H'),
|
||||||
|
; (8, 'A'), (8, 'B'), (8, 'C'), (8, 'D'), (8, 'E'), (8, 'F'), (8, 'G'), (8, 'H')]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Protips!
|
||||||
|
========
|
||||||
|
|
||||||
|
Hy also features something known as the "threading macro", a really neat
|
||||||
|
feature of Clojure's. The "threading macro" (written as "->"), is used
|
||||||
|
to avoid deep nesting of expressions.
|
||||||
|
|
||||||
|
The threading macro inserts each expression into the next expression's first
|
||||||
|
argument place.
|
||||||
|
|
||||||
|
Let's take the classic:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(loop (print (eval (read))))
|
||||||
|
|
||||||
|
Rather then write it like that, we can write it as follows:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(-> (read) (eval) (print) (loop))
|
||||||
|
|
||||||
|
Now, using `python-sh <http://amoffat.github.com/sh/>`_, we can show
|
||||||
|
how the threading macro (because of python-sh's setup) can be used like
|
||||||
|
a pipe:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
=> (import-from sh cat grep wc)
|
||||||
|
=> (-> (cat "/usr/share/dict/words") (grep "-E" "^hy") (wc "-l"))
|
||||||
|
210
|
||||||
|
|
||||||
|
Which, of course, expands out to:
|
||||||
|
|
||||||
|
.. code-block:: clj
|
||||||
|
|
||||||
|
(wc (grep (cat "/usr/share/dict/words") "-E" "^hy") "-l")
|
||||||
|
|
||||||
|
Much more readable, no! Use the threading macro!
|
||||||
|
|
||||||
|
|
||||||
|
TODO
|
||||||
|
====
|
||||||
|
|
||||||
|
- How do I define classes?
|
||||||
|
- Blow your mind with macros!
|
||||||
|
- Where's my banana???
|
||||||
|
- Mention that you can import .hy files in .py files and vice versa!
|
12
eg/python3/futures/hello-world.hy
Normal file
12
eg/python3/futures/hello-world.hy
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
(import-from concurrent.futures ThreadPoolExecutor as-completed)
|
||||||
|
(import-from random randint)
|
||||||
|
|
||||||
|
(import-from sh sleep)
|
||||||
|
|
||||||
|
(defn task-to-do [] (sleep (randint 1 5)))
|
||||||
|
|
||||||
|
|
||||||
|
(with-as (ThreadPoolExecutor 10) executor
|
||||||
|
(setf jobs (list-comp (.submit executor task-to-do) (x (range 0 10))))
|
||||||
|
(for (future (as-completed jobs))
|
||||||
|
(.result future)))
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
|
|
||||||
__appname__ = "hy"
|
__appname__ = "hy"
|
||||||
__version__ = "0.9.3"
|
__version__ = "0.9.5"
|
||||||
|
|
||||||
|
|
||||||
import hy.importer # NOQA
|
import hy.importer # NOQA
|
||||||
|
473
hy/compiler.py
473
hy/compiler.py
@ -1,4 +1,7 @@
|
|||||||
|
# -*- encoding: utf-8 -*-
|
||||||
|
#
|
||||||
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
|
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
|
||||||
|
# Copyright (c) 2013 Julien Danjou <julien@danjou.info>
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
# copy of this software and associated documentation files (the "Software"),
|
# copy of this software and associated documentation files (the "Software"),
|
||||||
@ -28,17 +31,48 @@ from hy.models.symbol import HySymbol
|
|||||||
from hy.models.list import HyList
|
from hy.models.list import HyList
|
||||||
from hy.models.dict import HyDict
|
from hy.models.dict import HyDict
|
||||||
|
|
||||||
|
from hy.util import flatten_literal_list
|
||||||
|
|
||||||
|
import codecs
|
||||||
import ast
|
import ast
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
||||||
class HyCompileError(HyError):
|
class HyCompileError(HyError):
|
||||||
pass
|
def __init__(self, exception,
|
||||||
|
start_line=0, start_column=0):
|
||||||
|
self.exception = exception
|
||||||
|
self.start_line = start_line
|
||||||
|
self.start_column = start_column
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.start_line == 0:
|
||||||
|
return("Internal Compiler Bug\n⤷ %s: %s"
|
||||||
|
% (self.exception.__class__.__name__,
|
||||||
|
self.exception))
|
||||||
|
return ("Compilation error at line %d, column %d\n%s: %s"
|
||||||
|
% (self.start_line, self.start_column,
|
||||||
|
self.exception.__class__.__name__,
|
||||||
|
self.exception))
|
||||||
|
|
||||||
|
|
||||||
_compile_table = {}
|
_compile_table = {}
|
||||||
|
|
||||||
|
|
||||||
|
def ast_str(foobar):
|
||||||
|
if sys.version_info[0] >= 3:
|
||||||
|
return str(foobar)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return str(foobar)
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
enc = codecs.getencoder('punycode')
|
||||||
|
foobar, _ = enc(foobar)
|
||||||
|
return "__hy_%s" % (str(foobar).replace("-", "_"))
|
||||||
|
|
||||||
|
|
||||||
def builds(_type):
|
def builds(_type):
|
||||||
def _dec(fn):
|
def _dec(fn):
|
||||||
_compile_table[_type] = fn
|
_compile_table[_type] = fn
|
||||||
@ -49,6 +83,38 @@ def builds(_type):
|
|||||||
return _dec
|
return _dec
|
||||||
|
|
||||||
|
|
||||||
|
def _raise_wrong_args_number(expression, error):
|
||||||
|
err = TypeError(error % (expression.pop(0),
|
||||||
|
len(expression)))
|
||||||
|
err.start_line = expression.start_line
|
||||||
|
err.start_column = expression.start_column
|
||||||
|
raise err
|
||||||
|
|
||||||
|
|
||||||
|
def checkargs(exact=None, min=None, max=None):
|
||||||
|
def _dec(fn):
|
||||||
|
def checker(self, expression):
|
||||||
|
if exact is not None and (len(expression) - 1) != exact:
|
||||||
|
_raise_wrong_args_number(expression,
|
||||||
|
"`%%s' needs %d arguments, got %%d" %
|
||||||
|
exact)
|
||||||
|
|
||||||
|
if min is not None and (len(expression) - 1) < min:
|
||||||
|
_raise_wrong_args_number(
|
||||||
|
expression,
|
||||||
|
"`%%s' needs at least %d arguments, got %%d" % (min))
|
||||||
|
|
||||||
|
if max is not None and (len(expression) - 1) > max:
|
||||||
|
_raise_wrong_args_number(
|
||||||
|
expression,
|
||||||
|
"`%%s' needs at most %d arguments, got %%d" % (max))
|
||||||
|
|
||||||
|
return fn(self, expression)
|
||||||
|
|
||||||
|
return checker
|
||||||
|
return _dec
|
||||||
|
|
||||||
|
|
||||||
class HyASTCompiler(object):
|
class HyASTCompiler(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -56,14 +122,30 @@ class HyASTCompiler(object):
|
|||||||
self.anon_fn_count = 0
|
self.anon_fn_count = 0
|
||||||
|
|
||||||
def compile(self, tree):
|
def compile(self, tree):
|
||||||
for _type in _compile_table:
|
try:
|
||||||
if type(tree) == _type:
|
for _type in _compile_table:
|
||||||
return _compile_table[_type](self, tree)
|
if type(tree) == _type:
|
||||||
|
return _compile_table[_type](self, tree)
|
||||||
|
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 Exception as e:
|
||||||
|
raise HyCompileError(exception=e,
|
||||||
|
start_line=getattr(e, "start_line", 0),
|
||||||
|
start_column=getattr(e, "start_column", 0))
|
||||||
|
|
||||||
raise HyCompileError("Unknown type - `%s'" % (str(type(tree))))
|
raise HyCompileError("Unknown type - `%s'" % (str(type(tree))))
|
||||||
|
|
||||||
def _mangle_branch(self, tree):
|
def _mangle_branch(self, tree, start_line, start_column):
|
||||||
|
# If tree is empty, just return a pass statement
|
||||||
|
if tree == []:
|
||||||
|
return [ast.Pass(lineno=start_line,
|
||||||
|
col_offset=start_column)]
|
||||||
|
|
||||||
ret = []
|
ret = []
|
||||||
|
tree = list(flatten_literal_list(tree))
|
||||||
tree.reverse()
|
tree.reverse()
|
||||||
|
|
||||||
if self.returnable and len(tree) > 0:
|
if self.returnable and len(tree) > 0:
|
||||||
@ -73,10 +155,21 @@ class HyASTCompiler(object):
|
|||||||
ret.append(ast.Return(value=el,
|
ret.append(ast.Return(value=el,
|
||||||
lineno=el.lineno,
|
lineno=el.lineno,
|
||||||
col_offset=el.col_offset))
|
col_offset=el.col_offset))
|
||||||
ret += [ast.Expr(value=el,
|
if isinstance(el, ast.FunctionDef):
|
||||||
lineno=el.lineno,
|
ret.append(ast.Return(
|
||||||
col_offset=el.col_offset)
|
value=ast.Name(
|
||||||
if not isinstance(el, ast.stmt) else el for el in tree] # NOQA
|
arg=el.name, id=el.name, ctx=ast.Load(),
|
||||||
|
lineno=el.lineno, col_offset=el.col_offset),
|
||||||
|
lineno=el.lineno, col_offset=el.col_offset))
|
||||||
|
|
||||||
|
for el in tree:
|
||||||
|
if isinstance(el, ast.stmt):
|
||||||
|
ret.append(el)
|
||||||
|
continue
|
||||||
|
|
||||||
|
ret.append(ast.Expr(value=el,
|
||||||
|
lineno=el.lineno,
|
||||||
|
col_offset=el.col_offset))
|
||||||
|
|
||||||
ret.reverse()
|
ret.reverse()
|
||||||
return ret
|
return ret
|
||||||
@ -95,9 +188,11 @@ class HyASTCompiler(object):
|
|||||||
return [self.compile(x) for x in expr[1:]]
|
return [self.compile(x) for x in expr[1:]]
|
||||||
|
|
||||||
@builds("throw")
|
@builds("throw")
|
||||||
|
@builds("raise")
|
||||||
|
@checkargs(max=1)
|
||||||
def compile_throw_expression(self, expr):
|
def compile_throw_expression(self, expr):
|
||||||
expr.pop(0)
|
expr.pop(0)
|
||||||
exc = self.compile(expr.pop(0))
|
exc = self.compile(expr.pop(0)) if expr else None
|
||||||
return ast.Raise(
|
return ast.Raise(
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
@ -116,52 +211,152 @@ class HyASTCompiler(object):
|
|||||||
else:
|
else:
|
||||||
Try = ast.TryExcept
|
Try = ast.TryExcept
|
||||||
|
|
||||||
|
try:
|
||||||
|
body = expr.pop(0)
|
||||||
|
except IndexError:
|
||||||
|
body = []
|
||||||
|
|
||||||
|
# (try something…)
|
||||||
|
body = self._code_branch(self.compile(body),
|
||||||
|
expr.start_line,
|
||||||
|
expr.start_column)
|
||||||
|
|
||||||
|
orelse = []
|
||||||
|
if len(expr) == 0:
|
||||||
|
# (try) or (try body)
|
||||||
|
handlers = [ast.ExceptHandler(
|
||||||
|
lineno=expr.start_line,
|
||||||
|
col_offset=expr.start_column,
|
||||||
|
type=None,
|
||||||
|
name=None,
|
||||||
|
body=[ast.Pass(lineno=expr.start_line,
|
||||||
|
col_offset=expr.start_column)])]
|
||||||
|
else:
|
||||||
|
handlers = []
|
||||||
|
for e in expr:
|
||||||
|
if not len(e):
|
||||||
|
raise TypeError("Empty list not allowed in `try'")
|
||||||
|
|
||||||
|
if e[0] in (HySymbol("except"), HySymbol("catch")):
|
||||||
|
handlers.append(self.compile(e))
|
||||||
|
elif e[0] == HySymbol("else"):
|
||||||
|
if orelse:
|
||||||
|
raise TypeError(
|
||||||
|
"`try' cannot have more than one `else'")
|
||||||
|
else:
|
||||||
|
orelse = self._code_branch(self.compile(e[1:]),
|
||||||
|
e.start_line,
|
||||||
|
e.start_column)
|
||||||
|
else:
|
||||||
|
raise TypeError("Unknown expression in `try'")
|
||||||
|
|
||||||
|
if handlers == []:
|
||||||
|
raise TypeError(
|
||||||
|
"`try' must have at least `except' or `finally'")
|
||||||
|
|
||||||
return Try(
|
return Try(
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
body=self._code_branch(self.compile(expr.pop(0))),
|
body=body,
|
||||||
handlers=[self.compile(s) for s in expr],
|
handlers=handlers,
|
||||||
finalbody=[],
|
finalbody=[],
|
||||||
orelse=[])
|
orelse=orelse)
|
||||||
|
|
||||||
@builds("catch")
|
@builds("catch")
|
||||||
|
@builds("except")
|
||||||
def compile_catch_expression(self, expr):
|
def compile_catch_expression(self, expr):
|
||||||
expr.pop(0) # catch
|
catch = expr.pop(0) # catch
|
||||||
_type = self.compile(expr.pop(0))
|
|
||||||
name = expr.pop(0)
|
|
||||||
|
|
||||||
if sys.version_info[0] >= 3:
|
try:
|
||||||
# Python3 features a change where the Exception handler
|
exceptions = expr.pop(0)
|
||||||
# moved the name from a Name() to a pure Python String type.
|
except IndexError:
|
||||||
#
|
exceptions = HyList()
|
||||||
# We'll just make sure it's a pure "string", and let it work
|
# exceptions catch should be either:
|
||||||
# it's magic.
|
# [[list of exceptions]]
|
||||||
name = str(name)
|
# or
|
||||||
|
# [variable [list of exceptions]]
|
||||||
|
# or
|
||||||
|
# [variable exception]
|
||||||
|
# or
|
||||||
|
# [exception]
|
||||||
|
# or
|
||||||
|
# []
|
||||||
|
if not isinstance(exceptions, HyList):
|
||||||
|
raise TypeError("`%s' exceptions list is not a list" % catch)
|
||||||
|
if len(exceptions) > 2:
|
||||||
|
raise TypeError("`%s' exceptions list is too long" % catch)
|
||||||
|
|
||||||
|
# [variable [list of exceptions]]
|
||||||
|
# let's pop variable and use it as name
|
||||||
|
if len(exceptions) == 2:
|
||||||
|
name = exceptions.pop(0)
|
||||||
|
if sys.version_info[0] >= 3:
|
||||||
|
# Python3 features a change where the Exception handler
|
||||||
|
# moved the name from a Name() to a pure Python String type.
|
||||||
|
#
|
||||||
|
# We'll just make sure it's a pure "string", and let it work
|
||||||
|
# it's magic.
|
||||||
|
name = ast_str(name)
|
||||||
|
else:
|
||||||
|
# Python2 requires an ast.Name, set to ctx Store.
|
||||||
|
name = self._storeize(self.compile(name))
|
||||||
else:
|
else:
|
||||||
# Python2 requires an ast.Name, set to ctx Store.
|
name = None
|
||||||
name = self.compile(name)
|
|
||||||
name.ctx = ast.Store()
|
try:
|
||||||
|
exceptions_list = exceptions.pop(0)
|
||||||
|
except IndexError:
|
||||||
|
exceptions_list = []
|
||||||
|
|
||||||
|
if isinstance(exceptions_list, list):
|
||||||
|
if len(exceptions_list):
|
||||||
|
# [FooBar BarFoo] → catch Foobar and BarFoo exceptions
|
||||||
|
_type = ast.Tuple(elts=[self.compile(x)
|
||||||
|
for x in exceptions_list],
|
||||||
|
lineno=expr.start_line,
|
||||||
|
col_offset=expr.start_column,
|
||||||
|
ctx=ast.Load())
|
||||||
|
else:
|
||||||
|
# [] → all exceptions catched
|
||||||
|
_type = None
|
||||||
|
elif isinstance(exceptions_list, HySymbol):
|
||||||
|
_type = self.compile(exceptions_list)
|
||||||
|
else:
|
||||||
|
raise TypeError("`%s' needs a valid exception list" % catch)
|
||||||
|
|
||||||
|
body = self._code_branch([self.compile(x) for x in expr],
|
||||||
|
expr.start_line,
|
||||||
|
expr.start_column)
|
||||||
|
|
||||||
return ast.ExceptHandler(
|
return ast.ExceptHandler(
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
type=_type,
|
type=_type,
|
||||||
name=name,
|
name=name,
|
||||||
body=self._code_branch([self.compile(x) for x in expr]))
|
body=body)
|
||||||
|
|
||||||
def _code_branch(self, branch):
|
def _code_branch(self, branch, start_line, start_column):
|
||||||
if isinstance(branch, list):
|
return self._mangle_branch((branch
|
||||||
return self._mangle_branch(branch)
|
if isinstance(branch, list)
|
||||||
return self._mangle_branch([branch])
|
else [branch]),
|
||||||
|
start_line,
|
||||||
|
start_column)
|
||||||
|
|
||||||
@builds("if")
|
@builds("if")
|
||||||
|
@checkargs(min=2, max=3)
|
||||||
def compile_if_expression(self, expr):
|
def compile_if_expression(self, expr):
|
||||||
expr.pop(0)
|
expr.pop(0) # if
|
||||||
test = self.compile(expr.pop(0))
|
test = self.compile(expr.pop(0))
|
||||||
body = self._code_branch(self.compile(expr.pop(0)))
|
body = self._code_branch(self.compile(expr.pop(0)),
|
||||||
orel = []
|
expr.start_line,
|
||||||
if len(expr) > 0:
|
expr.start_column)
|
||||||
orel = self._code_branch(self.compile(expr.pop(0)))
|
|
||||||
|
if len(expr) == 1:
|
||||||
|
orel = self._code_branch(self.compile(expr.pop(0)),
|
||||||
|
expr.start_line,
|
||||||
|
expr.start_column)
|
||||||
|
else:
|
||||||
|
orel = []
|
||||||
|
|
||||||
return ast.If(test=test,
|
return ast.If(test=test,
|
||||||
body=body,
|
body=body,
|
||||||
@ -190,6 +385,7 @@ class HyASTCompiler(object):
|
|||||||
nl=True)
|
nl=True)
|
||||||
|
|
||||||
@builds("assert")
|
@builds("assert")
|
||||||
|
@checkargs(1)
|
||||||
def compile_assert_expression(self, expr):
|
def compile_assert_expression(self, expr):
|
||||||
expr.pop(0) # assert
|
expr.pop(0) # assert
|
||||||
e = expr.pop(0)
|
e = expr.pop(0)
|
||||||
@ -199,6 +395,7 @@ class HyASTCompiler(object):
|
|||||||
col_offset=e.start_column)
|
col_offset=e.start_column)
|
||||||
|
|
||||||
@builds("lambda")
|
@builds("lambda")
|
||||||
|
@checkargs(min=2)
|
||||||
def compile_lambda_expression(self, expr):
|
def compile_lambda_expression(self, expr):
|
||||||
expr.pop(0)
|
expr.pop(0)
|
||||||
sig = expr.pop(0)
|
sig = expr.pop(0)
|
||||||
@ -208,7 +405,7 @@ class HyASTCompiler(object):
|
|||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
args=ast.arguments(args=[
|
args=ast.arguments(args=[
|
||||||
ast.Name(arg=str(x), id=str(x),
|
ast.Name(arg=ast_str(x), id=ast_str(x),
|
||||||
ctx=ast.Param(),
|
ctx=ast.Param(),
|
||||||
lineno=x.start_line,
|
lineno=x.start_line,
|
||||||
col_offset=x.start_column)
|
col_offset=x.start_column)
|
||||||
@ -221,10 +418,12 @@ class HyASTCompiler(object):
|
|||||||
body=self.compile(body))
|
body=self.compile(body))
|
||||||
|
|
||||||
@builds("pass")
|
@builds("pass")
|
||||||
|
@checkargs(0)
|
||||||
def compile_pass_expression(self, expr):
|
def compile_pass_expression(self, expr):
|
||||||
return ast.Pass(lineno=expr.start_line, col_offset=expr.start_column)
|
return ast.Pass(lineno=expr.start_line, col_offset=expr.start_column)
|
||||||
|
|
||||||
@builds("yield")
|
@builds("yield")
|
||||||
|
@checkargs(1)
|
||||||
def compile_yield_expression(self, expr):
|
def compile_yield_expression(self, expr):
|
||||||
expr.pop(0)
|
expr.pop(0)
|
||||||
return ast.Yield(
|
return ast.Yield(
|
||||||
@ -238,7 +437,7 @@ class HyASTCompiler(object):
|
|||||||
return ast.Import(
|
return ast.Import(
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
names=[ast.alias(name=str(x), asname=None) for x in expr])
|
names=[ast.alias(name=ast_str(x), asname=None) for x in expr])
|
||||||
|
|
||||||
@builds("import_as")
|
@builds("import_as")
|
||||||
def compile_import_as_expression(self, expr):
|
def compile_import_as_expression(self, expr):
|
||||||
@ -247,21 +446,23 @@ class HyASTCompiler(object):
|
|||||||
return ast.Import(
|
return ast.Import(
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
module=str(expr.pop(0)),
|
module=ast_str(expr.pop(0)),
|
||||||
names=[ast.alias(name=str(x[0]),
|
names=[ast.alias(name=ast_str(x[0]),
|
||||||
asname=str(x[1])) for x in modlist])
|
asname=ast_str(x[1])) for x in modlist])
|
||||||
|
|
||||||
@builds("import_from")
|
@builds("import_from")
|
||||||
|
@checkargs(min=1)
|
||||||
def compile_import_from_expression(self, expr):
|
def compile_import_from_expression(self, expr):
|
||||||
expr.pop(0) # index
|
expr.pop(0) # index
|
||||||
return ast.ImportFrom(
|
return ast.ImportFrom(
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
module=str(expr.pop(0)),
|
module=ast_str(expr.pop(0)),
|
||||||
names=[ast.alias(name=str(x), asname=None) for x in expr],
|
names=[ast.alias(name=ast_str(x), asname=None) for x in expr],
|
||||||
level=0)
|
level=0)
|
||||||
|
|
||||||
@builds("get")
|
@builds("get")
|
||||||
|
@checkargs(2)
|
||||||
def compile_index_expression(self, expr):
|
def compile_index_expression(self, expr):
|
||||||
expr.pop(0) # index
|
expr.pop(0) # index
|
||||||
val = self.compile(expr.pop(0)) # target
|
val = self.compile(expr.pop(0)) # target
|
||||||
@ -275,6 +476,7 @@ class HyASTCompiler(object):
|
|||||||
ctx=ast.Load())
|
ctx=ast.Load())
|
||||||
|
|
||||||
@builds("slice")
|
@builds("slice")
|
||||||
|
@checkargs(min=1, max=3)
|
||||||
def compile_slice_expression(self, expr):
|
def compile_slice_expression(self, expr):
|
||||||
expr.pop(0) # index
|
expr.pop(0) # index
|
||||||
val = self.compile(expr.pop(0)) # target
|
val = self.compile(expr.pop(0)) # target
|
||||||
@ -297,6 +499,7 @@ class HyASTCompiler(object):
|
|||||||
ctx=ast.Load())
|
ctx=ast.Load())
|
||||||
|
|
||||||
@builds("assoc")
|
@builds("assoc")
|
||||||
|
@checkargs(3)
|
||||||
def compile_assoc_expression(self, expr):
|
def compile_assoc_expression(self, expr):
|
||||||
expr.pop(0) # assoc
|
expr.pop(0) # assoc
|
||||||
# (assoc foo bar baz) => foo[bar] = baz
|
# (assoc foo bar baz) => foo[bar] = baz
|
||||||
@ -317,6 +520,7 @@ class HyASTCompiler(object):
|
|||||||
value=self.compile(val))
|
value=self.compile(val))
|
||||||
|
|
||||||
@builds("decorate_with")
|
@builds("decorate_with")
|
||||||
|
@checkargs(min=1)
|
||||||
def compile_decorate_expression(self, expr):
|
def compile_decorate_expression(self, expr):
|
||||||
expr.pop(0) # decorate-with
|
expr.pop(0) # decorate-with
|
||||||
fn = self.compile(expr.pop(-1))
|
fn = self.compile(expr.pop(-1))
|
||||||
@ -325,23 +529,30 @@ class HyASTCompiler(object):
|
|||||||
fn.decorator_list = [self.compile(x) for x in expr]
|
fn.decorator_list = [self.compile(x) for x in expr]
|
||||||
return fn
|
return fn
|
||||||
|
|
||||||
@builds("with_as")
|
@builds("with")
|
||||||
def compile_with_as_expression(self, expr):
|
@checkargs(min=2)
|
||||||
expr.pop(0) # with-as
|
def compile_with_expression(self, expr):
|
||||||
ctx = self.compile(expr.pop(0))
|
expr.pop(0) # with
|
||||||
thing = self.compile(expr.pop(0))
|
|
||||||
if isinstance(thing, ast.Tuple):
|
|
||||||
for x in thing.elts:
|
|
||||||
x.ctx = ast.Store()
|
|
||||||
|
|
||||||
thing.ctx = ast.Store()
|
args = expr.pop(0)
|
||||||
|
if len(args) > 2 or len(args) < 1:
|
||||||
|
raise TypeError("with needs [arg (expr)] or [(expr)]")
|
||||||
|
|
||||||
|
args.reverse()
|
||||||
|
ctx = self.compile(args.pop(0))
|
||||||
|
|
||||||
|
thing = None
|
||||||
|
if args != []:
|
||||||
|
thing = self._storeize(self.compile(args.pop(0)))
|
||||||
|
|
||||||
ret = ast.With(context_expr=ctx,
|
ret = ast.With(context_expr=ctx,
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
optional_vars=thing,
|
optional_vars=thing,
|
||||||
body=self._mangle_branch([
|
body=self._code_branch(
|
||||||
self.compile(x) for x in expr]))
|
[self.compile(x) for x in expr],
|
||||||
|
expr.start_line,
|
||||||
|
expr.start_column))
|
||||||
|
|
||||||
if sys.version_info[0] >= 3 and sys.version_info[1] >= 3:
|
if sys.version_info[0] >= 3 and sys.version_info[1] >= 3:
|
||||||
ret.items = [ast.withitem(context_expr=ctx, optional_vars=thing)]
|
ret.items = [ast.withitem(context_expr=ctx, optional_vars=thing)]
|
||||||
@ -357,32 +568,42 @@ class HyASTCompiler(object):
|
|||||||
ctx=ast.Load())
|
ctx=ast.Load())
|
||||||
|
|
||||||
@builds("list_comp")
|
@builds("list_comp")
|
||||||
|
@checkargs(min=2, max=3)
|
||||||
def compile_list_comprehension(self, expr):
|
def compile_list_comprehension(self, expr):
|
||||||
# (list-comp expr (target iter))
|
# (list-comp expr (target iter) cond?)
|
||||||
expr.pop(0)
|
expr.pop(0)
|
||||||
thing = self.compile(expr.pop(0))
|
expression = expr.pop(0)
|
||||||
ident, gen = expr.pop(0)
|
tar_it = iter(expr.pop(0))
|
||||||
|
targets = zip(tar_it, tar_it)
|
||||||
|
|
||||||
ident = self.compile(ident)
|
cond = self.compile(expr.pop(0)) if expr != [] else None
|
||||||
gen = self.compile(gen)
|
|
||||||
|
|
||||||
if isinstance(ident, ast.Tuple):
|
ret = ast.ListComp(
|
||||||
for x in ident.elts:
|
|
||||||
x.ctx = ast.Store()
|
|
||||||
ident.ctx = ast.Store()
|
|
||||||
|
|
||||||
return ast.ListComp(
|
|
||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
elt=thing,
|
elt=self.compile(expression),
|
||||||
generators=[
|
generators=[])
|
||||||
ast.comprehension(
|
|
||||||
target=ident,
|
for target, iterable in targets:
|
||||||
iter=gen,
|
ret.generators.append(ast.comprehension(
|
||||||
ifs=[self.compile(x) for x in expr])
|
target=self._storeize(self.compile(target)),
|
||||||
])
|
iter=self.compile(iterable),
|
||||||
|
ifs=[]))
|
||||||
|
|
||||||
|
if cond:
|
||||||
|
ret.generators[-1].ifs.append(cond)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def _storeize(self, name):
|
||||||
|
if isinstance(name, ast.Tuple):
|
||||||
|
for x in name.elts:
|
||||||
|
x.ctx = ast.Store()
|
||||||
|
name.ctx = ast.Store()
|
||||||
|
return name
|
||||||
|
|
||||||
@builds("kwapply")
|
@builds("kwapply")
|
||||||
|
@checkargs(2)
|
||||||
def compile_kwapply_expression(self, expr):
|
def compile_kwapply_expression(self, expr):
|
||||||
expr.pop(0) # kwapply
|
expr.pop(0) # kwapply
|
||||||
call = self.compile(expr.pop(0))
|
call = self.compile(expr.pop(0))
|
||||||
@ -391,11 +612,39 @@ class HyASTCompiler(object):
|
|||||||
if type(call) != ast.Call:
|
if type(call) != ast.Call:
|
||||||
raise TypeError("kwapplying a non-call")
|
raise TypeError("kwapplying a non-call")
|
||||||
|
|
||||||
call.keywords = [ast.keyword(arg=str(x),
|
call.keywords = [ast.keyword(arg=ast_str(x),
|
||||||
value=self.compile(kwargs[x])) for x in kwargs]
|
value=self.compile(kwargs[x])) for x in kwargs]
|
||||||
|
|
||||||
return call
|
return call
|
||||||
|
|
||||||
|
@builds("not")
|
||||||
|
@builds("~")
|
||||||
|
@checkargs(1)
|
||||||
|
def compile_unary_operator(self, expression):
|
||||||
|
ops = {"not": ast.Not,
|
||||||
|
"~": ast.Invert}
|
||||||
|
operator = expression.pop(0)
|
||||||
|
operand = expression.pop(0)
|
||||||
|
return ast.UnaryOp(op=ops[operator](),
|
||||||
|
operand=self.compile(operand),
|
||||||
|
lineno=operator.start_line,
|
||||||
|
col_offset=operator.start_column)
|
||||||
|
|
||||||
|
@builds("and")
|
||||||
|
@builds("or")
|
||||||
|
@checkargs(min=2)
|
||||||
|
def compile_logical_or_and_and_operator(self, expression):
|
||||||
|
ops = {"and": ast.And,
|
||||||
|
"or": ast.Or}
|
||||||
|
operator = expression.pop(0)
|
||||||
|
values = []
|
||||||
|
for child in expression:
|
||||||
|
values.append(self.compile(child))
|
||||||
|
return ast.BoolOp(op=ops[operator](),
|
||||||
|
lineno=operator.start_line,
|
||||||
|
col_offset=operator.start_column,
|
||||||
|
values=values)
|
||||||
|
|
||||||
@builds("=")
|
@builds("=")
|
||||||
@builds("!=")
|
@builds("!=")
|
||||||
@builds("<")
|
@builds("<")
|
||||||
@ -406,6 +655,7 @@ class HyASTCompiler(object):
|
|||||||
@builds("in")
|
@builds("in")
|
||||||
@builds("is_not")
|
@builds("is_not")
|
||||||
@builds("not_in")
|
@builds("not_in")
|
||||||
|
@checkargs(min=2)
|
||||||
def compile_compare_op_expression(self, expression):
|
def compile_compare_op_expression(self, expression):
|
||||||
ops = {"=": ast.Eq, "!=": ast.NotEq,
|
ops = {"=": ast.Eq, "!=": ast.NotEq,
|
||||||
"<": ast.Lt, "<=": ast.LtE,
|
"<": ast.Lt, "<=": ast.LtE,
|
||||||
@ -429,6 +679,7 @@ class HyASTCompiler(object):
|
|||||||
@builds("-")
|
@builds("-")
|
||||||
@builds("/")
|
@builds("/")
|
||||||
@builds("*")
|
@builds("*")
|
||||||
|
@checkargs(min=2)
|
||||||
def compile_maths_expression(self, expression):
|
def compile_maths_expression(self, expression):
|
||||||
# operator = Mod | Pow | LShift | RShift | BitOr |
|
# operator = Mod | Pow | LShift | RShift | BitOr |
|
||||||
# BitXor | BitAnd | FloorDiv
|
# BitXor | BitAnd | FloorDiv
|
||||||
@ -467,7 +718,7 @@ class HyASTCompiler(object):
|
|||||||
lineno=expr.start_line,
|
lineno=expr.start_line,
|
||||||
col_offset=expr.start_column,
|
col_offset=expr.start_column,
|
||||||
value=self.compile(obj),
|
value=self.compile(obj),
|
||||||
attr=str(fn),
|
attr=ast_str(fn),
|
||||||
ctx=ast.Load()),
|
ctx=ast.Load()),
|
||||||
args=[self.compile(x) for x in expr],
|
args=[self.compile(x) for x in expr],
|
||||||
keywords=[],
|
keywords=[],
|
||||||
@ -499,6 +750,7 @@ class HyASTCompiler(object):
|
|||||||
@builds("def")
|
@builds("def")
|
||||||
@builds("setf")
|
@builds("setf")
|
||||||
@builds("setv")
|
@builds("setv")
|
||||||
|
@checkargs(2)
|
||||||
def compile_def_expression(self, expression):
|
def compile_def_expression(self, expression):
|
||||||
expression.pop(0) # "def"
|
expression.pop(0) # "def"
|
||||||
name = expression.pop(0)
|
name = expression.pop(0)
|
||||||
@ -509,15 +761,10 @@ class HyASTCompiler(object):
|
|||||||
# We special case a FunctionDef, since we can define by setting
|
# We special case a FunctionDef, since we can define by setting
|
||||||
# FunctionDef's .name attribute, rather then foo == anon_fn. This
|
# FunctionDef's .name attribute, rather then foo == anon_fn. This
|
||||||
# helps keep things clean.
|
# helps keep things clean.
|
||||||
what.name = str(name)
|
what.name = ast_str(name)
|
||||||
return what
|
return what
|
||||||
|
|
||||||
name = self.compile(name)
|
name = self._storeize(self.compile(name))
|
||||||
if isinstance(name, ast.Tuple):
|
|
||||||
for x in name.elts:
|
|
||||||
x.ctx = ast.Store()
|
|
||||||
|
|
||||||
name.ctx = ast.Store()
|
|
||||||
|
|
||||||
return ast.Assign(
|
return ast.Assign(
|
||||||
lineno=expression.start_line,
|
lineno=expression.start_line,
|
||||||
@ -525,34 +772,43 @@ class HyASTCompiler(object):
|
|||||||
targets=[name], value=what)
|
targets=[name], value=what)
|
||||||
|
|
||||||
@builds("foreach")
|
@builds("foreach")
|
||||||
|
@checkargs(min=1)
|
||||||
def compile_for_expression(self, expression):
|
def compile_for_expression(self, expression):
|
||||||
ret_status = self.returnable
|
ret_status = self.returnable
|
||||||
self.returnable = False
|
self.returnable = False
|
||||||
|
|
||||||
expression.pop(0) # for
|
expression.pop(0) # for
|
||||||
name, iterable = expression.pop(0)
|
name, iterable = expression.pop(0)
|
||||||
target = self.compile_symbol(name)
|
target = self._storeize(self.compile_symbol(name))
|
||||||
|
|
||||||
if isinstance(target, ast.Tuple):
|
|
||||||
for x in target.elts:
|
|
||||||
x.ctx = ast.Store()
|
|
||||||
|
|
||||||
target.ctx = ast.Store()
|
|
||||||
# support stuff like:
|
|
||||||
# (for [x [1 2 3 4]
|
|
||||||
# y [a b c d]] ...)
|
|
||||||
|
|
||||||
ret = ast.For(lineno=expression.start_line,
|
ret = ast.For(lineno=expression.start_line,
|
||||||
col_offset=expression.start_column,
|
col_offset=expression.start_column,
|
||||||
target=target,
|
target=target,
|
||||||
iter=self.compile(iterable),
|
iter=self.compile(iterable),
|
||||||
body=self._mangle_branch([
|
body=self._code_branch(
|
||||||
self.compile(x) for x in expression]),
|
[self.compile(x) for x in expression],
|
||||||
|
expression.start_line,
|
||||||
|
expression.start_column),
|
||||||
orelse=[])
|
orelse=[])
|
||||||
|
|
||||||
self.returnable = ret_status
|
self.returnable = ret_status
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@builds("while")
|
||||||
|
@checkargs(min=2)
|
||||||
|
def compile_while_expression(self, expr):
|
||||||
|
expr.pop(0) # "while"
|
||||||
|
test = self.compile(expr.pop(0))
|
||||||
|
|
||||||
|
return ast.While(test=test,
|
||||||
|
body=self._code_branch(
|
||||||
|
[self.compile(x) for x in expr],
|
||||||
|
expr.start_line,
|
||||||
|
expr.start_column),
|
||||||
|
orelse=[],
|
||||||
|
lineno=expr.start_line,
|
||||||
|
col_offset=expr.start_column)
|
||||||
|
|
||||||
@builds(HyList)
|
@builds(HyList)
|
||||||
def compile_list(self, expr):
|
def compile_list(self, expr):
|
||||||
return ast.List(
|
return ast.List(
|
||||||
@ -562,16 +818,30 @@ class HyASTCompiler(object):
|
|||||||
col_offset=expr.start_column)
|
col_offset=expr.start_column)
|
||||||
|
|
||||||
@builds("fn")
|
@builds("fn")
|
||||||
|
@checkargs(min=2)
|
||||||
def compile_fn_expression(self, expression):
|
def compile_fn_expression(self, expression):
|
||||||
expression.pop(0) # fn
|
expression.pop(0) # fn
|
||||||
|
|
||||||
ret_status = self.returnable
|
ret_status = self.returnable
|
||||||
self.returnable = True
|
|
||||||
|
|
||||||
self.anon_fn_count += 1
|
self.anon_fn_count += 1
|
||||||
name = "_hy_anon_fn_%d" % (self.anon_fn_count)
|
name = "_hy_anon_fn_%d" % (self.anon_fn_count)
|
||||||
sig = expression.pop(0)
|
sig = expression.pop(0)
|
||||||
|
|
||||||
|
body = []
|
||||||
|
if expression != []:
|
||||||
|
self.returnable = True
|
||||||
|
tailop = self.compile(expression.pop(-1))
|
||||||
|
self.returnable = False
|
||||||
|
for el in expression:
|
||||||
|
body.append(self.compile(el))
|
||||||
|
body.append(tailop)
|
||||||
|
|
||||||
|
self.returnable = True
|
||||||
|
body = self._code_branch(body,
|
||||||
|
expression.start_line,
|
||||||
|
expression.start_column)
|
||||||
|
|
||||||
ret = ast.FunctionDef(
|
ret = ast.FunctionDef(
|
||||||
name=name,
|
name=name,
|
||||||
lineno=expression.start_line,
|
lineno=expression.start_line,
|
||||||
@ -579,7 +849,7 @@ class HyASTCompiler(object):
|
|||||||
args=ast.arguments(
|
args=ast.arguments(
|
||||||
args=[
|
args=[
|
||||||
ast.Name(
|
ast.Name(
|
||||||
arg=str(x), id=str(x),
|
arg=ast_str(x), id=ast_str(x),
|
||||||
ctx=ast.Param(),
|
ctx=ast.Param(),
|
||||||
lineno=x.start_line,
|
lineno=x.start_line,
|
||||||
col_offset=x.start_column)
|
col_offset=x.start_column)
|
||||||
@ -589,8 +859,7 @@ class HyASTCompiler(object):
|
|||||||
kwonlyargs=[],
|
kwonlyargs=[],
|
||||||
kw_defaults=[],
|
kw_defaults=[],
|
||||||
defaults=[]),
|
defaults=[]),
|
||||||
body=self._code_branch([
|
body=body,
|
||||||
self.compile(x) for x in expression]),
|
|
||||||
decorator_list=[])
|
decorator_list=[])
|
||||||
|
|
||||||
self.returnable = ret_status
|
self.returnable = ret_status
|
||||||
@ -613,19 +882,19 @@ class HyASTCompiler(object):
|
|||||||
lineno=symbol.start_line,
|
lineno=symbol.start_line,
|
||||||
col_offset=symbol.start_column,
|
col_offset=symbol.start_column,
|
||||||
value=self.compile_symbol(glob),
|
value=self.compile_symbol(glob),
|
||||||
attr=str(local),
|
attr=ast_str(local),
|
||||||
ctx=ast.Load()
|
ctx=ast.Load()
|
||||||
)
|
)
|
||||||
|
|
||||||
return ast.Name(id=str(symbol),
|
return ast.Name(id=ast_str(symbol),
|
||||||
arg=str(symbol),
|
arg=ast_str(symbol),
|
||||||
ctx=ast.Load(),
|
ctx=ast.Load(),
|
||||||
lineno=symbol.start_line,
|
lineno=symbol.start_line,
|
||||||
col_offset=symbol.start_column)
|
col_offset=symbol.start_column)
|
||||||
|
|
||||||
@builds(HyString)
|
@builds(HyString)
|
||||||
def compile_string(self, string):
|
def compile_string(self, string):
|
||||||
return ast.Str(s=str(string), lineno=string.start_line,
|
return ast.Str(s=ast_str(string), lineno=string.start_line,
|
||||||
col_offset=string.start_column)
|
col_offset=string.start_column)
|
||||||
|
|
||||||
@builds(HyDict)
|
@builds(HyDict)
|
||||||
@ -649,5 +918,5 @@ def hy_compile(tree, root=None):
|
|||||||
tlo = root
|
tlo = root
|
||||||
if root is None:
|
if root is None:
|
||||||
tlo = ast.Module
|
tlo = ast.Module
|
||||||
ret = tlo(body=compiler._mangle_branch(compiler.compile(tree)))
|
ret = tlo(body=compiler._mangle_branch(compiler.compile(tree), 0, 0))
|
||||||
return ret
|
return ret
|
||||||
|
@ -20,15 +20,24 @@
|
|||||||
|
|
||||||
from hy.macros import process as mprocess
|
from hy.macros import process as mprocess
|
||||||
|
|
||||||
|
import hy.mangle
|
||||||
|
|
||||||
|
|
||||||
MACROS = [
|
MACROS = [
|
||||||
"hy.core.bootstrap", # defn, cond
|
"hy.core.bootstrap",
|
||||||
|
"hy.core.mangles",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def process(tree):
|
def process(tree):
|
||||||
load_macros()
|
load_macros()
|
||||||
return mprocess(tree)
|
old = None
|
||||||
|
while old != tree:
|
||||||
|
old = tree
|
||||||
|
tree = mprocess(tree)
|
||||||
|
for m in hy.mangle.MANGLES:
|
||||||
|
m().mangle(tree)
|
||||||
|
return tree
|
||||||
|
|
||||||
|
|
||||||
def load_macros():
|
def load_macros():
|
||||||
|
@ -94,6 +94,20 @@ def threading_macro(tree):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
@macro("_>>")
|
||||||
|
def threading_tail_macro(tree):
|
||||||
|
tree.pop(0)
|
||||||
|
ret = tree.pop(0)
|
||||||
|
for node in tree:
|
||||||
|
if not isinstance(node, HyExpression):
|
||||||
|
nnode = HyExpression([node])
|
||||||
|
nnode.replace(node)
|
||||||
|
node = nnode
|
||||||
|
node.append(ret)
|
||||||
|
ret = node
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
@macro("car")
|
@macro("car")
|
||||||
@macro("first")
|
@macro("first")
|
||||||
def first_macro(tree):
|
def first_macro(tree):
|
||||||
@ -114,3 +128,19 @@ def rest_macro(tree):
|
|||||||
return HyExpression([HySymbol('slice'),
|
return HyExpression([HySymbol('slice'),
|
||||||
ret,
|
ret,
|
||||||
HyInteger(1)])
|
HyInteger(1)])
|
||||||
|
|
||||||
|
|
||||||
|
@macro("let")
|
||||||
|
def let_macro(tree):
|
||||||
|
tree.pop(0) # "let"
|
||||||
|
ret = tree.pop(0) # vars
|
||||||
|
# tree is now the body
|
||||||
|
expr = HyExpression([HySymbol("fn"), HyList([])])
|
||||||
|
|
||||||
|
for var in ret:
|
||||||
|
expr.append(HyExpression([HySymbol("setf"), var[0], var[1]]))
|
||||||
|
|
||||||
|
for stmt in tree:
|
||||||
|
expr.append(stmt)
|
||||||
|
|
||||||
|
return HyExpression([expr])
|
||||||
|
85
hy/core/mangles.py
Normal file
85
hy/core/mangles.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
# copy of this software and associated documentation files (the "Software"),
|
||||||
|
# to deal in the Software without restriction, including without limitation
|
||||||
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
# and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
# Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
# DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
from hy.models.expression import HyExpression
|
||||||
|
from hy.models.symbol import HySymbol
|
||||||
|
from hy.models.list import HyList
|
||||||
|
|
||||||
|
import hy.mangle
|
||||||
|
|
||||||
|
|
||||||
|
class HoistableMangle(hy.mangle.Mangle):
|
||||||
|
def should_hoist(self):
|
||||||
|
for frame in self.stack:
|
||||||
|
if frame is self.scope:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if isinstance(frame, HyExpression) and frame != []:
|
||||||
|
call = frame[0]
|
||||||
|
if call in self.ignore:
|
||||||
|
continue
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionMangle(HoistableMangle):
|
||||||
|
hoistable = ["fn"]
|
||||||
|
ignore = ["def", "decorate_with", "setf", "setv"]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.series = 0
|
||||||
|
|
||||||
|
def unique_name(self):
|
||||||
|
self.series += 1
|
||||||
|
return "_hy_hoisted_fn_%s" % (self.series)
|
||||||
|
|
||||||
|
def visit(self, tree):
|
||||||
|
if isinstance(tree, HyExpression) and tree != []:
|
||||||
|
call = tree[0]
|
||||||
|
if call == "fn" and self.should_hoist():
|
||||||
|
new_name = HySymbol(self.unique_name())
|
||||||
|
new_name.replace(tree)
|
||||||
|
fn_def = HyExpression([HySymbol("def"),
|
||||||
|
new_name,
|
||||||
|
tree])
|
||||||
|
fn_def.replace(tree)
|
||||||
|
self.hoist(fn_def)
|
||||||
|
return new_name
|
||||||
|
|
||||||
|
|
||||||
|
class IfMangle(HoistableMangle):
|
||||||
|
ignore = []
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.series = 0
|
||||||
|
|
||||||
|
def visit(self, tree):
|
||||||
|
if isinstance(tree, HyExpression) and tree != []:
|
||||||
|
call = tree[0]
|
||||||
|
if call == "if" and self.should_hoist():
|
||||||
|
fn = HyExpression([HyExpression([HySymbol("fn"),
|
||||||
|
HyList([]),
|
||||||
|
tree])])
|
||||||
|
fn.replace(tree)
|
||||||
|
return fn
|
||||||
|
|
||||||
|
|
||||||
|
hy.mangle.MANGLES.append(IfMangle)
|
||||||
|
hy.mangle.MANGLES.append(FunctionMangle)
|
@ -19,11 +19,12 @@
|
|||||||
# DEALINGS IN THE SOFTWARE.
|
# DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
from hy.compiler import hy_compile
|
from hy.compiler import hy_compile
|
||||||
from hy.lex import tokenize
|
|
||||||
from hy.core import process
|
|
||||||
from py_compile import wr_long, MAGIC
|
from py_compile import wr_long, MAGIC
|
||||||
|
from hy.core import process
|
||||||
|
from hy.lex import tokenize
|
||||||
|
|
||||||
|
|
||||||
|
from io import open
|
||||||
import marshal
|
import marshal
|
||||||
import imp
|
import imp
|
||||||
import sys
|
import sys
|
||||||
@ -43,7 +44,7 @@ def import_buffer_to_hst(fd):
|
|||||||
|
|
||||||
|
|
||||||
def import_file_to_hst(fpath):
|
def import_file_to_hst(fpath):
|
||||||
return import_buffer_to_hst(open(fpath, 'r'))
|
return import_buffer_to_hst(open(fpath, 'r', encoding='utf-8'))
|
||||||
|
|
||||||
|
|
||||||
def import_file_to_ast(fpath):
|
def import_file_to_ast(fpath):
|
||||||
|
@ -166,6 +166,9 @@ class ListeyThing(State):
|
|||||||
if char == self.end_char:
|
if char == self.end_char:
|
||||||
return Idle
|
return Idle
|
||||||
|
|
||||||
|
if char in ")]}":
|
||||||
|
raise LexException("Unexpected closing character: `%s'" % (char))
|
||||||
|
|
||||||
if char in WHITESPACE:
|
if char in WHITESPACE:
|
||||||
self.commit()
|
self.commit()
|
||||||
return
|
return
|
||||||
@ -241,6 +244,9 @@ class String(State):
|
|||||||
if char == "\\":
|
if char == "\\":
|
||||||
self.nodes.append("\\")
|
self.nodes.append("\\")
|
||||||
return
|
return
|
||||||
|
if char == "\"":
|
||||||
|
self.nodes.append("\"")
|
||||||
|
return
|
||||||
|
|
||||||
raise LexException("Unknown modifier: `%s'" % (char))
|
raise LexException("Unknown modifier: `%s'" % (char))
|
||||||
|
|
||||||
|
109
hy/mangle.py
Normal file
109
hy/mangle.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
# copy of this software and associated documentation files (the "Software"),
|
||||||
|
# to deal in the Software without restriction, including without limitation
|
||||||
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
# and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
# Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
# DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
from hy.models.expression import HyExpression
|
||||||
|
# from hy.models.list import HyList
|
||||||
|
|
||||||
|
MANGLES = []
|
||||||
|
|
||||||
|
|
||||||
|
class Mangle(object):
|
||||||
|
"""
|
||||||
|
Mangle (n.)
|
||||||
|
|
||||||
|
1. To mutilate or disfigure by battering, hacking, cutting,
|
||||||
|
or tearing. See Synonyms at batter1.
|
||||||
|
|
||||||
|
(but mostly hacking)
|
||||||
|
"""
|
||||||
|
|
||||||
|
class TreeChanged(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _mangle(self, tree):
|
||||||
|
# Things that force a scope push to go into:
|
||||||
|
#
|
||||||
|
# - Functions
|
||||||
|
# - If
|
||||||
|
scopable = ["fn", "if"]
|
||||||
|
scoped = False
|
||||||
|
|
||||||
|
self.push_stack(tree)
|
||||||
|
|
||||||
|
if isinstance(tree, HyExpression):
|
||||||
|
what = tree[0]
|
||||||
|
if what in scopable:
|
||||||
|
self.push_scope(tree)
|
||||||
|
scoped = True
|
||||||
|
|
||||||
|
if isinstance(tree, list):
|
||||||
|
for i, element in enumerate(tree):
|
||||||
|
nel = self.visit(element)
|
||||||
|
if nel:
|
||||||
|
tree[i] = nel
|
||||||
|
self.tree_changed()
|
||||||
|
|
||||||
|
self._mangle(element)
|
||||||
|
|
||||||
|
if scoped:
|
||||||
|
self.pop_scope()
|
||||||
|
self.pop_stack()
|
||||||
|
|
||||||
|
def hoist(self, what):
|
||||||
|
scope = self.scope
|
||||||
|
for point, el in enumerate(scope):
|
||||||
|
if el in self.stack:
|
||||||
|
break
|
||||||
|
self.scope.insert(point, what)
|
||||||
|
|
||||||
|
def get_scope(self):
|
||||||
|
return self.scopes[0]
|
||||||
|
|
||||||
|
def tree_changed(self):
|
||||||
|
raise self.TreeChanged()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def scope(self):
|
||||||
|
return self.get_scope()
|
||||||
|
|
||||||
|
def push_scope(self, tree):
|
||||||
|
self.scopes.insert(0, tree)
|
||||||
|
|
||||||
|
def push_stack(self, tree):
|
||||||
|
self.stack.insert(0, tree)
|
||||||
|
|
||||||
|
def pop_scope(self):
|
||||||
|
return self.scopes.pop(0)
|
||||||
|
|
||||||
|
def pop_stack(self):
|
||||||
|
return self.stack.pop(0)
|
||||||
|
|
||||||
|
def mangle(self, tree):
|
||||||
|
unfinished = True
|
||||||
|
while unfinished:
|
||||||
|
self.root = tree
|
||||||
|
self.scopes = []
|
||||||
|
self.stack = []
|
||||||
|
self.push_scope(tree)
|
||||||
|
try:
|
||||||
|
self._mangle(tree)
|
||||||
|
unfinished = False
|
||||||
|
except self.TreeChanged:
|
||||||
|
pass
|
@ -23,18 +23,15 @@ import sys
|
|||||||
|
|
||||||
|
|
||||||
if sys.version_info[0] >= 3:
|
if sys.version_info[0] >= 3:
|
||||||
_str_type = str
|
str_type = str
|
||||||
else:
|
else:
|
||||||
_str_type = unicode
|
str_type = unicode
|
||||||
|
|
||||||
|
|
||||||
class HyString(HyObject, _str_type):
|
class HyString(HyObject, str_type):
|
||||||
"""
|
"""
|
||||||
Generic Hy String object. Helpful to store string literals from Hy
|
Generic Hy String object. Helpful to store string literals from Hy
|
||||||
scripts. It's either a ``str`` or a ``unicode``, depending on the
|
scripts. It's either a ``str`` or a ``unicode``, depending on the
|
||||||
Python version.
|
Python version.
|
||||||
"""
|
"""
|
||||||
|
pass
|
||||||
def __new__(cls, value):
|
|
||||||
obj = _str_type.__new__(cls, value)
|
|
||||||
return obj
|
|
||||||
|
28
hy/util.py
Normal file
28
hy/util.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
def flatten_literal_list(entry):
|
||||||
|
for e in entry:
|
||||||
|
if type(e) == list:
|
||||||
|
for x in flatten_literal_list(e):
|
||||||
|
yield x # needs more yield-from
|
||||||
|
else:
|
||||||
|
yield e
|
@ -28,6 +28,6 @@
|
|||||||
(post-route hy2py "/hy2py" []
|
(post-route hy2py "/hy2py" []
|
||||||
(try
|
(try
|
||||||
(hy-to-py (get request.form "code"))
|
(hy-to-py (get request.form "code"))
|
||||||
(catch LexException e (err "Incomplete Code."))
|
(catch [e LexException] (err "Incomplete Code."))
|
||||||
(catch HyError e (err "Generic error during processing."))
|
(catch [e HyError] (err "Generic error during processing."))
|
||||||
(catch Exception e (err "Erm, you broke something."))))
|
(catch [e Exception] (err "Erm, you broke something."))))
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
import hy
|
import hy # noqa
|
||||||
from .native_tests.math import *
|
from .native_tests.math import * # noqa
|
||||||
from .native_tests.language import *
|
from .native_tests.language import * # noqa
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
|
# Copyright (c) 2013 Paul Tagliamonte <paultag@debian.org>
|
||||||
|
# Copyright (c) 2013 Julien Danjou <julien@danjou.info>
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
# copy of this software and associated documentation files (the "Software"),
|
# copy of this software and associated documentation files (the "Software"),
|
||||||
@ -34,6 +35,15 @@ def _ast_spotcheck(arg, root, secondary):
|
|||||||
assert getattr(root, arg) == getattr(secondary, arg)
|
assert getattr(root, arg) == getattr(secondary, arg)
|
||||||
|
|
||||||
|
|
||||||
|
def cant_compile(expr):
|
||||||
|
expr = tokenize(expr)
|
||||||
|
try:
|
||||||
|
hy_compile(expr)
|
||||||
|
assert False
|
||||||
|
except HyCompileError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def test_ast_bad_type():
|
def test_ast_bad_type():
|
||||||
"Make sure AST breakage can happen"
|
"Make sure AST breakage can happen"
|
||||||
try:
|
try:
|
||||||
@ -43,21 +53,239 @@ def test_ast_bad_type():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_if():
|
||||||
|
"Make sure AST can't compile invalid if"
|
||||||
|
cant_compile("(if)")
|
||||||
|
cant_compile("(if foobar)")
|
||||||
|
cant_compile("(if 1 2 3 4 5)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_valid_if():
|
||||||
|
"Make sure AST can't compile invalid if"
|
||||||
|
hy_compile(tokenize("(if foo bar)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_valid_unary_op():
|
||||||
|
"Make sure AST can compile valid unary operator"
|
||||||
|
hy_compile(tokenize("(not 2)"))
|
||||||
|
hy_compile(tokenize("(~ 1)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_invalid_unary_op():
|
||||||
|
"Make sure AST can't compile invalid unary operator"
|
||||||
|
cant_compile("(not 2 3 4)")
|
||||||
|
cant_compile("(not)")
|
||||||
|
cant_compile("(not 2 3 4)")
|
||||||
|
cant_compile("(~ 2 2 3 4)")
|
||||||
|
cant_compile("(~)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_while():
|
||||||
|
"Make sure AST can't compile invalid while"
|
||||||
|
cant_compile("(while)")
|
||||||
|
cant_compile("(while (true))")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_do():
|
||||||
|
"Make sure AST can compile valid do"
|
||||||
|
hy_compile(tokenize("(do)"))
|
||||||
|
hy_compile(tokenize("(do 1)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_throw():
|
||||||
|
"Make sure AST can compile valid throw"
|
||||||
|
hy_compile(tokenize("(throw)"))
|
||||||
|
hy_compile(tokenize("(throw 1)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_throw():
|
||||||
|
"Make sure AST can't compile invalid throw"
|
||||||
|
cant_compile("(raise 1 2 3)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_raise():
|
||||||
|
"Make sure AST can compile valid raise"
|
||||||
|
hy_compile(tokenize("(raise)"))
|
||||||
|
hy_compile(tokenize("(raise 1)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_raise():
|
||||||
|
"Make sure AST can't compile invalid raise"
|
||||||
|
cant_compile("(raise 1 2 3)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_try():
|
||||||
|
"Make sure AST can compile valid try"
|
||||||
|
hy_compile(tokenize("(try)"))
|
||||||
|
hy_compile(tokenize("(try 1)"))
|
||||||
|
hy_compile(tokenize("(try 1 (except) (else 1))"))
|
||||||
|
hy_compile(tokenize("(try 1 (else 1) (except))"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_try():
|
||||||
|
"Make sure AST can't compile invalid try"
|
||||||
|
cant_compile("(try 1 bla)")
|
||||||
|
cant_compile("(try 1 bla bla)")
|
||||||
|
cant_compile("(try (do) (else 1) (else 2))")
|
||||||
|
cant_compile("(try 1 (else 1))")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_catch():
|
||||||
|
"Make sure AST can compile valid catch"
|
||||||
|
hy_compile(tokenize("(catch)"))
|
||||||
|
hy_compile(tokenize("(catch [])"))
|
||||||
|
hy_compile(tokenize("(catch [Foobar])"))
|
||||||
|
hy_compile(tokenize("(catch [[]])"))
|
||||||
|
hy_compile(tokenize("(catch [x FooBar])"))
|
||||||
|
hy_compile(tokenize("(catch [x [FooBar BarFoo]])"))
|
||||||
|
hy_compile(tokenize("(catch [x [FooBar BarFoo]])"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_catch():
|
||||||
|
"Make sure AST can't compile invalid catch"
|
||||||
|
cant_compile("(catch 1)")
|
||||||
|
cant_compile("(catch \"A\")")
|
||||||
|
cant_compile("(catch [1 3])")
|
||||||
|
cant_compile("(catch [x [FooBar] BarBar])")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_except():
|
||||||
|
"Make sure AST can compile valid except"
|
||||||
|
hy_compile(tokenize("(except)"))
|
||||||
|
hy_compile(tokenize("(except [])"))
|
||||||
|
hy_compile(tokenize("(except [Foobar])"))
|
||||||
|
hy_compile(tokenize("(except [[]])"))
|
||||||
|
hy_compile(tokenize("(except [x FooBar])"))
|
||||||
|
hy_compile(tokenize("(except [x [FooBar BarFoo]])"))
|
||||||
|
hy_compile(tokenize("(except [x [FooBar BarFoo]])"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_except():
|
||||||
|
"Make sure AST can't compile invalid except"
|
||||||
|
cant_compile("(except 1)")
|
||||||
|
cant_compile("(except [1 3])")
|
||||||
|
cant_compile("(except [x [FooBar] BarBar])")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_assert():
|
||||||
|
"Make sure AST can compile valid assert"
|
||||||
|
hy_compile(tokenize("(assert 1)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_assert():
|
||||||
|
"Make sure AST can't compile invalid assert"
|
||||||
|
cant_compile("(assert)")
|
||||||
|
cant_compile("(assert 1 2)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_lambda():
|
||||||
|
"Make sure AST can compile valid lambda"
|
||||||
|
hy_compile(tokenize("(lambda [] 1)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_lambda():
|
||||||
|
"Make sure AST can't compile invalid lambda"
|
||||||
|
cant_compile("(lambda)")
|
||||||
|
cant_compile("(lambda [])")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_pass():
|
||||||
|
"Make sure AST can compile valid pass"
|
||||||
|
hy_compile(tokenize("(pass)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_pass():
|
||||||
|
"Make sure AST can't compile invalid pass"
|
||||||
|
cant_compile("(pass 1)")
|
||||||
|
cant_compile("(pass 1 2)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_yield():
|
||||||
|
"Make sure AST can compile valid yield"
|
||||||
|
hy_compile(tokenize("(yield 1)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_yield():
|
||||||
|
"Make sure AST can't compile invalid yield"
|
||||||
|
cant_compile("(yield)")
|
||||||
|
cant_compile("(yield 1 2)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_import_from():
|
||||||
|
"Make sure AST can compile valid import-from"
|
||||||
|
hy_compile(tokenize("(import-from x y)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_import_from():
|
||||||
|
"Make sure AST can't compile invalid import-from"
|
||||||
|
cant_compile("(import-from)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_get():
|
||||||
|
"Make sure AST can compile valid get"
|
||||||
|
hy_compile(tokenize("(get x y)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_get():
|
||||||
|
"Make sure AST can't compile invalid get"
|
||||||
|
cant_compile("(get)")
|
||||||
|
cant_compile("(get 1)")
|
||||||
|
cant_compile("(get 1 2 3)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_slice():
|
||||||
|
"Make sure AST can compile valid slice"
|
||||||
|
hy_compile(tokenize("(slice x)"))
|
||||||
|
hy_compile(tokenize("(slice x y)"))
|
||||||
|
hy_compile(tokenize("(slice x y z)"))
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_bad_slice():
|
||||||
|
"Make sure AST can't compile invalid slice"
|
||||||
|
cant_compile("(slice)")
|
||||||
|
cant_compile("(slice 1 2 3 4)")
|
||||||
|
|
||||||
|
|
||||||
|
def test_ast_good_assoc():
|
||||||
|
"Make sure AST can compile valid assoc"
|
||||||
|
hy_compile(tokenize("(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"
|
||||||
|
hy_compile(tokenize("(while foo bar)"))
|
||||||
|
|
||||||
|
|
||||||
def test_ast_expression_basics():
|
def test_ast_expression_basics():
|
||||||
""" Ensure basic AST expression conversion works. """
|
""" Ensure basic AST expression conversion works. """
|
||||||
code = hy_compile(tokenize("(foo bar)")).body[0]
|
code = hy_compile(tokenize("(foo bar)")).body[0]
|
||||||
tree = ast.Expr(value=ast.Call(
|
tree = ast.Expr(value=ast.Call(
|
||||||
func=ast.Name(
|
func=ast.Name(
|
||||||
id="foo",
|
id="foo",
|
||||||
ctx=ast.Load(),
|
ctx=ast.Load(),
|
||||||
),
|
),
|
||||||
args=[
|
args=[
|
||||||
ast.Name(id="bar", ctx=ast.Load())
|
ast.Name(id="bar", ctx=ast.Load())
|
||||||
],
|
],
|
||||||
keywords=[],
|
keywords=[],
|
||||||
starargs=None,
|
starargs=None,
|
||||||
kwargs=None,
|
kwargs=None,
|
||||||
))
|
))
|
||||||
|
|
||||||
_ast_spotcheck("value.func.id", code, tree)
|
_ast_spotcheck("value.func.id", code, tree)
|
||||||
|
|
||||||
@ -70,11 +298,7 @@ def test_ast_anon_fns_basics():
|
|||||||
|
|
||||||
def test_ast_non_decoratable():
|
def test_ast_non_decoratable():
|
||||||
""" Ensure decorating garbage breaks """
|
""" Ensure decorating garbage breaks """
|
||||||
try:
|
cant_compile("(decorate-with (foo) (* x x))")
|
||||||
hy_compile(tokenize("(decorate-with (foo) (* x x))"))
|
|
||||||
assert True is False
|
|
||||||
except TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def test_ast_non_kwapplyable():
|
def test_ast_non_kwapplyable():
|
||||||
@ -84,7 +308,7 @@ def test_ast_non_kwapplyable():
|
|||||||
try:
|
try:
|
||||||
hy_compile(code)
|
hy_compile(code)
|
||||||
assert True is False
|
assert True is False
|
||||||
except TypeError:
|
except HyCompileError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ import ast
|
|||||||
|
|
||||||
def test_basics():
|
def test_basics():
|
||||||
"Make sure the basics of the importer work"
|
"Make sure the basics of the importer work"
|
||||||
module = import_file_to_module("basic",
|
import_file_to_module("basic",
|
||||||
"tests/resources/importer/basic.hy")
|
"tests/resources/importer/basic.hy")
|
||||||
|
|
||||||
|
|
||||||
def test_stringer():
|
def test_stringer():
|
||||||
|
@ -33,13 +33,28 @@ from hy.lex import tokenize
|
|||||||
def test_lex_exception():
|
def test_lex_exception():
|
||||||
""" Ensure tokenize throws a fit on a partial input """
|
""" Ensure tokenize throws a fit on a partial input """
|
||||||
try:
|
try:
|
||||||
objs = tokenize("(foo")
|
tokenize("(foo")
|
||||||
assert True is False
|
assert True is False
|
||||||
except LexException:
|
except LexException:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
objs = tokenize("&foo&")
|
tokenize("&foo&")
|
||||||
|
assert True is False
|
||||||
|
except LexException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_unbalanced_exception():
|
||||||
|
"""Ensure the tokenization fails on unbalanced expressions"""
|
||||||
|
try:
|
||||||
|
tokenize("(bar))")
|
||||||
|
assert True is False
|
||||||
|
except LexException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
tokenize("(baz [quux]])")
|
||||||
assert True is False
|
assert True is False
|
||||||
except LexException:
|
except LexException:
|
||||||
pass
|
pass
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
from hy.macros import macro, process
|
from hy.macros import macro, process
|
||||||
from hy.lex import tokenize
|
from hy.lex import tokenize
|
||||||
|
|
||||||
from hy.models.expression import HyExpression
|
|
||||||
from hy.models.string import HyString
|
from hy.models.string import HyString
|
||||||
from hy.models.symbol import HySymbol
|
|
||||||
from hy.models.list import HyList
|
from hy.models.list import HyList
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
;
|
;
|
||||||
|
|
||||||
(import-from tests.resources kwtest)
|
(import-from tests.resources kwtest function-with-a-dash)
|
||||||
(import-from os.path exists isdir isfile)
|
(import-from os.path exists isdir isfile)
|
||||||
(import sys)
|
|
||||||
(import-as sys systest)
|
(import-as sys systest)
|
||||||
|
(import sys)
|
||||||
|
|
||||||
|
|
||||||
(defn test-sys-argv []
|
(defn test-sys-argv []
|
||||||
@ -32,6 +32,30 @@
|
|||||||
(assert (= count 150)))
|
(assert (= count 150)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-while-loop []
|
||||||
|
"NATIVE: test while loops?"
|
||||||
|
(setv count 5)
|
||||||
|
(setv fact 1)
|
||||||
|
(while (> count 0)
|
||||||
|
(setv fact (* fact count))
|
||||||
|
(setv count (- count 1)))
|
||||||
|
(assert (= count 0))
|
||||||
|
(assert (= fact 120)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-not []
|
||||||
|
"NATIVE: test not"
|
||||||
|
(assert (not (= 1 2)))
|
||||||
|
(assert (= true (not false)))
|
||||||
|
(assert (= false (not 42))) )
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-inv []
|
||||||
|
"NATIVE: test inv"
|
||||||
|
(assert (= (~ 1) -2))
|
||||||
|
(assert (= (~ -2) 1)))
|
||||||
|
|
||||||
|
|
||||||
(defn test-in []
|
(defn test-in []
|
||||||
"NATIVE: test in"
|
"NATIVE: test in"
|
||||||
(assert (in "a" ["a" "b" "c" "d"]))
|
(assert (in "a" ["a" "b" "c" "d"]))
|
||||||
@ -74,6 +98,17 @@
|
|||||||
(assert (= 1 1))
|
(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 []
|
(defn test-cond []
|
||||||
"NATIVE: test if cond sorta works."
|
"NATIVE: test if cond sorta works."
|
||||||
@ -84,7 +119,7 @@
|
|||||||
|
|
||||||
(defn test-index []
|
(defn test-index []
|
||||||
"NATIVE: Test that dict access works"
|
"NATIVE: Test that dict access works"
|
||||||
(assert (get {"one" "two"} "one") "two")
|
(assert (= (get {"one" "two"} "one") "two"))
|
||||||
(assert (= (get [1 2 3 4 5] 1) 2)))
|
(assert (= (get [1 2 3 4 5] 1) 2)))
|
||||||
|
|
||||||
|
|
||||||
@ -125,12 +160,134 @@
|
|||||||
(assert (= (.join " " ["one" "two"]) "one two")))
|
(assert (= (.join " " ["one" "two"]) "one two")))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-do []
|
||||||
|
"NATIVE: test do"
|
||||||
|
(do))
|
||||||
|
|
||||||
|
|
||||||
(defn test-exceptions []
|
(defn test-exceptions []
|
||||||
"NATIVE: test Exceptions"
|
"NATIVE: test Exceptions"
|
||||||
|
|
||||||
|
(try)
|
||||||
|
|
||||||
|
(try (do))
|
||||||
|
|
||||||
|
(try (pass))
|
||||||
|
|
||||||
|
(try (pass) (except))
|
||||||
|
|
||||||
|
(try (pass) (except [IOError]) (except))
|
||||||
|
|
||||||
|
;; Test correct (raise)
|
||||||
|
(let [[passed false]]
|
||||||
|
(try
|
||||||
|
(try
|
||||||
|
(raise IndexError)
|
||||||
|
(except [IndexError] (raise)))
|
||||||
|
(except [IndexError]
|
||||||
|
(setv passed true)))
|
||||||
|
(assert passed))
|
||||||
|
|
||||||
|
;; Test incorrect (raise)
|
||||||
|
(let [[passed false]]
|
||||||
|
(try
|
||||||
|
(raise)
|
||||||
|
;; Python 2 raises TypeError
|
||||||
|
;; Python 3 raises RuntimeError
|
||||||
|
(except [[TypeError RuntimeError]]
|
||||||
|
(setv passed true)))
|
||||||
|
(assert passed))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(raise (KeyError))
|
||||||
|
(catch [[IOError]] (assert false))
|
||||||
|
(catch [e [KeyError]] (assert e)))
|
||||||
|
|
||||||
(try
|
(try
|
||||||
(throw (KeyError))
|
(throw (KeyError))
|
||||||
(catch IOError e (assert (= 2 1)))
|
(except [[IOError]] (assert false))
|
||||||
(catch KeyError e (+ 1 1) (assert (= 1 1)))))
|
(catch [e [KeyError]] (assert e)))
|
||||||
|
|
||||||
|
|
||||||
|
(try
|
||||||
|
(get [1] 3)
|
||||||
|
(catch [IndexError] (assert true))
|
||||||
|
(except [IndexError] (pass)))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(print foobar42ofthebaz)
|
||||||
|
(catch [IndexError] (assert false))
|
||||||
|
(except [NameError] (pass)))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(get [1] 3)
|
||||||
|
(except [e IndexError] (assert (isinstance e IndexError))))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(get [1] 3)
|
||||||
|
(catch [e [IndexError NameError]] (assert (isinstance e IndexError))))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(print foobar42ofthebaz)
|
||||||
|
(except [e [IndexError NameError]] (assert (isinstance e NameError))))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(print foobar42)
|
||||||
|
(catch [[IndexError NameError]] (pass)))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(get [1] 3)
|
||||||
|
(catch [[IndexError NameError]] (pass)))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(print foobar42ofthebaz)
|
||||||
|
(catch))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(print foobar42ofthebaz)
|
||||||
|
(except []))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(print foobar42ofthebaz)
|
||||||
|
(except [] (pass)))
|
||||||
|
|
||||||
|
(try
|
||||||
|
(print foobar42ofthebaz)
|
||||||
|
(catch []
|
||||||
|
(setv foobar42ofthebaz 42)
|
||||||
|
(assert (= foobar42ofthebaz 42))))
|
||||||
|
|
||||||
|
(let [[passed false]]
|
||||||
|
(try
|
||||||
|
(try (pass) (except) (else (bla)))
|
||||||
|
(except [NameError] (setv passed true)))
|
||||||
|
(assert passed))
|
||||||
|
|
||||||
|
(let [[x 0]]
|
||||||
|
(try
|
||||||
|
(raise IOError)
|
||||||
|
(except [IOError]
|
||||||
|
(setv x 45))
|
||||||
|
(else (setv x 44)))
|
||||||
|
(assert (= x 45)))
|
||||||
|
|
||||||
|
(let [[x 0]]
|
||||||
|
(try
|
||||||
|
(raise KeyError)
|
||||||
|
(except []
|
||||||
|
(setv x 45))
|
||||||
|
(else (setv x 44)))
|
||||||
|
(assert (= x 45)))
|
||||||
|
|
||||||
|
(let [[x 0]]
|
||||||
|
(try
|
||||||
|
(try
|
||||||
|
(raise KeyError)
|
||||||
|
(except [IOError]
|
||||||
|
(setv x 45))
|
||||||
|
(else (setv x 44)))
|
||||||
|
(except))
|
||||||
|
(assert (= x 0))))
|
||||||
|
|
||||||
(defn test-earmuffs []
|
(defn test-earmuffs []
|
||||||
"NATIVE: Test earmuffs"
|
"NATIVE: Test earmuffs"
|
||||||
@ -146,6 +303,12 @@
|
|||||||
["X" "B" "C" "D"])))
|
["X" "B" "C" "D"])))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-tail-threading []
|
||||||
|
"NATIVE: test tail threading macro"
|
||||||
|
(assert (= (.join ", " (* 10 ["foo"]))
|
||||||
|
(->> ["foo"] (* 10) (.join ", ")))))
|
||||||
|
|
||||||
|
|
||||||
(defn test-threading-two []
|
(defn test-threading-two []
|
||||||
"NATIVE: test threading macro"
|
"NATIVE: test threading macro"
|
||||||
(assert (= (-> "a b c d" .upper (.replace "A" "X") .split)
|
(assert (= (-> "a b c d" .upper (.replace "A" "X") .split)
|
||||||
@ -198,8 +361,18 @@
|
|||||||
|
|
||||||
(defn test-context []
|
(defn test-context []
|
||||||
"NATIVE: test with"
|
"NATIVE: test with"
|
||||||
(with-as (open "README.md" "r") fd
|
(with [fd (open "README.md" "r")] (assert fd))
|
||||||
(pass)))
|
(with [(open "README.md" "r")] (pass)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-for-doodle []
|
||||||
|
"NATIVE: test for-do"
|
||||||
|
(do (do (do (do (do (do (do (do (do (setf (, x y) (, 0 0)))))))))))
|
||||||
|
(foreach [- [1 2]]
|
||||||
|
(do
|
||||||
|
(setf x (+ x 1))
|
||||||
|
(setf y (+ y 1))))
|
||||||
|
(assert (= y x 2)))
|
||||||
|
|
||||||
|
|
||||||
(defn test-comprehensions []
|
(defn test-comprehensions []
|
||||||
@ -207,4 +380,146 @@
|
|||||||
(assert (= (list-comp (* x 2) (x (range 2))) [0 2]))
|
(assert (= (list-comp (* x 2) (x (range 2))) [0 2]))
|
||||||
(assert (= (list-comp (* x 2) (x (range 4)) (% x 2)) [2 6]))
|
(assert (= (list-comp (* x 2) (x (range 4)) (% x 2)) [2 6]))
|
||||||
(assert (= (sorted (list-comp (* y 2) ((, x y) (.items {"1" 1 "2" 2}))))
|
(assert (= (sorted (list-comp (* y 2) ((, x y) (.items {"1" 1 "2" 2}))))
|
||||||
[2 4])))
|
[2 4]))
|
||||||
|
(assert (= (list-comp (, x y) (x (range 2) y (range 2)))
|
||||||
|
[(, 0 0) (, 0 1) (, 1 0) (, 1 1)])))
|
||||||
|
|
||||||
|
|
||||||
|
(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-do []
|
||||||
|
"NATIVE: test defn evaluation order with do"
|
||||||
|
(setv acc [])
|
||||||
|
(defn my-fun []
|
||||||
|
(do
|
||||||
|
(.append acc "Foo")
|
||||||
|
(.append acc "Bar")
|
||||||
|
(.append acc "Baz")))
|
||||||
|
(my-fun)
|
||||||
|
(assert (= acc ["Foo" "Bar" "Baz"])))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-defn-do-return []
|
||||||
|
"NATIVE: test defn return with do"
|
||||||
|
(defn my-fun [x]
|
||||||
|
(do
|
||||||
|
(+ x 42) ; noop
|
||||||
|
(+ x 1)))
|
||||||
|
(assert (= 43 (my-fun 42))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-mangles []
|
||||||
|
"NATIVE: test mangles"
|
||||||
|
(assert (= 2 ((fn [] (+ 1 1))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-fn-return []
|
||||||
|
"NATIVE: test function return"
|
||||||
|
(setv fn-test ((fn [] (fn [] (+ 1 1)))))
|
||||||
|
(assert (= (fn-test) 2)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-let []
|
||||||
|
"NATIVE: test let works rightish"
|
||||||
|
(assert (= (let [[x 1] [y 2] [z 3]] (+ x y z)) 6)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-if-mangler []
|
||||||
|
"NATIVE: test that we return ifs"
|
||||||
|
(assert (= true (if true true true))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-nested-mangles []
|
||||||
|
"NATIVE: test that we can use macros in mangled code"
|
||||||
|
(assert (= ((fn [] (-> 2 (+ 1 1) (* 1 2)))) 8)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-let-scope []
|
||||||
|
"NATIVE: test let works rightish"
|
||||||
|
(setv y 123)
|
||||||
|
(assert (= (let [[x 1]
|
||||||
|
[y 2]
|
||||||
|
[z 3]]
|
||||||
|
(+ x y z))
|
||||||
|
6))
|
||||||
|
(try
|
||||||
|
(assert (= x 42)) ; This ain't true
|
||||||
|
(catch [e [NameError]] (assert e)))
|
||||||
|
(assert (= y 123)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-symbol-utf-8 []
|
||||||
|
"NATIVE: test symbol encoded"
|
||||||
|
(let [[♥ "love"]
|
||||||
|
[⚘ "flower"]]
|
||||||
|
(assert (= (+ ⚘ ♥) "flowerlove"))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-symbol-dash []
|
||||||
|
"NATIVE: test symbol encoded"
|
||||||
|
(let [[♥-♥ "doublelove"]
|
||||||
|
[-_- "what?"]]
|
||||||
|
(assert (= ♥-♥ "doublelove"))
|
||||||
|
(assert (= -_- "what?"))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-and []
|
||||||
|
"NATIVE: test the and function"
|
||||||
|
(let [[and123 (and 1 2 3)]
|
||||||
|
[and-false (and 1 False 3)]]
|
||||||
|
(assert (= and123 3))
|
||||||
|
(assert (= and-false False))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-or []
|
||||||
|
"NATIVE: test the or function"
|
||||||
|
(let [[or-all-true (or 1 2 3 True "string")]
|
||||||
|
[or-some-true (or False "hello")]
|
||||||
|
[or-none-true (or False False)]]
|
||||||
|
(assert (= or-all-true 1))
|
||||||
|
(assert (= or-some-true "hello"))
|
||||||
|
(assert (= or-none-true False))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn test-if-return-branching []
|
||||||
|
"NATIVE: test the if return branching"
|
||||||
|
; thanks, algernon
|
||||||
|
(assert (= 1 (let [[x 1]
|
||||||
|
[y 2]]
|
||||||
|
(if true
|
||||||
|
2)
|
||||||
|
1)))
|
||||||
|
(assert (= 1 (let [[x 1] [y 2]]
|
||||||
|
(pass)
|
||||||
|
(pass)
|
||||||
|
((fn [] 1))))))
|
||||||
|
|
||||||
|
|
||||||
|
; FEATURE: native hy-eval
|
||||||
|
;
|
||||||
|
; - related to bug #64
|
||||||
|
; - https://github.com/paultag/hy/issues/64
|
||||||
|
; - https://github.com/paultag/hy/pull/62
|
||||||
|
;
|
||||||
|
; (defn test-eval []
|
||||||
|
; "NATIVE: test eval"
|
||||||
|
; (assert (= 1 (eval 1)))
|
||||||
|
; (assert (= "foobar" (eval "foobar")))
|
||||||
|
; (setv x 42)
|
||||||
|
; (assert (= x (eval x))))
|
||||||
|
@ -2,3 +2,7 @@
|
|||||||
|
|
||||||
def kwtest(*args, **kwargs):
|
def kwtest(*args, **kwargs):
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
|
||||||
|
def function_with_a_dash():
|
||||||
|
pass
|
||||||
|
Loading…
Reference in New Issue
Block a user