From c8d3a1859ede76c8f2920ffee84634aa42c3d4c9 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Tue, 2 Apr 2013 20:46:32 -0400 Subject: [PATCH 001/114] Reflowing the list-comp bits. --- hy/compiler.py | 72 +++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index bf7e136..69ce2bf 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -134,8 +134,7 @@ class HyASTCompiler(object): name = str(name) else: # Python2 requires an ast.Name, set to ctx Store. - name = self.compile(name) - name.ctx = ast.Store() + name = self._storeize(self.compile(name)) return ast.ExceptHandler( lineno=expr.start_line, @@ -324,12 +323,7 @@ class HyASTCompiler(object): def compile_with_as_expression(self, expr): expr.pop(0) # with-as ctx = self.compile(expr.pop(0)) - thing = self.compile(expr.pop(0)) - if isinstance(thing, ast.Tuple): - for x in thing.elts: - x.ctx = ast.Store() - - thing.ctx = ast.Store() + thing = self._storeize(self.compile(expr.pop(0))) ret = ast.With(context_expr=ctx, lineno=expr.start_line, @@ -353,29 +347,40 @@ class HyASTCompiler(object): @builds("list_comp") def compile_list_comprehension(self, expr): - # (list-comp expr (target iter)) + # (list-comp expr (target iter) cond?) expr.pop(0) - thing = self.compile(expr.pop(0)) - ident, gen = expr.pop(0) + expression = expr.pop(0) + tar_it = iter(expr.pop(0)) + targets = zip(tar_it, tar_it) - ident = self.compile(ident) - gen = self.compile(gen) + cond = None + if expr != []: + cond = self.compile(expr.pop(0)) - if isinstance(ident, ast.Tuple): - for x in ident.elts: - x.ctx = ast.Store() - ident.ctx = ast.Store() - - return ast.ListComp( + lcmp = None + ret = ast.ListComp( lineno=expr.start_line, col_offset=expr.start_column, - elt=thing, - generators=[ - ast.comprehension( - target=ident, - iter=gen, - ifs=[self.compile(x) for x in expr]) - ]) + elt=self.compile(expression), + generators=[]) + + for target, iterable in targets: + ret.generators.append(ast.comprehension( + 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") def compile_kwapply_expression(self, expr): @@ -505,12 +510,7 @@ class HyASTCompiler(object): what.name = str(name) return what - name = self.compile(name) - if isinstance(name, ast.Tuple): - for x in name.elts: - x.ctx = ast.Store() - - name.ctx = ast.Store() + name = self._storeize(self.compile(name)) return ast.Assign( lineno=expression.start_line, @@ -524,13 +524,7 @@ class HyASTCompiler(object): expression.pop(0) # for name, iterable = expression.pop(0) - target = self.compile_symbol(name) - - if isinstance(target, ast.Tuple): - for x in target.elts: - x.ctx = ast.Store() - - target.ctx = ast.Store() + target = self._storeize(self.compile_symbol(name)) # support stuff like: # (for [x [1 2 3 4] # y [a b c d]] ...) From 26f38367e948afc6ee61b1860410c5c527a714fa Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Tue, 2 Apr 2013 20:47:10 -0400 Subject: [PATCH 002/114] cleaning the last bit up --- hy/compiler.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index 69ce2bf..d45d75d 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -357,7 +357,6 @@ class HyASTCompiler(object): if expr != []: cond = self.compile(expr.pop(0)) - lcmp = None ret = ast.ListComp( lineno=expr.start_line, col_offset=expr.start_column, From d316a8fde8725941d2747efeb64e49a95e277227 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Tue, 2 Apr 2013 20:49:42 -0400 Subject: [PATCH 003/114] covering the new bits --- tests/native_tests/language.hy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 8c318d6..2d5ecd3 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -207,4 +207,6 @@ (assert (= (list-comp (* x 2) (x (range 2))) [0 2])) (assert (= (list-comp (* x 2) (x (range 4)) (% x 2)) [2 6])) (assert (= (sorted (list-comp (* y 2) ((, x y) (.items {"1" 1 "2" 2})))) - [2 4]))) + [2 4])) + (assert (= (list-comp (, x y) (x (range 2) y (range 2))) + [(, 0 0) (, 0 1) (, 1 0) (, 1 1)]))) From 4e7362848a37437edee61b9de763968a08394cf5 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Tue, 2 Apr 2013 20:56:10 -0400 Subject: [PATCH 004/114] adding in a bit about the double rainbow --- docs/language/index.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/language/index.rst b/docs/language/index.rst index e0e085a..e8769bb 100644 --- a/docs/language/index.rst +++ b/docs/language/index.rst @@ -342,6 +342,28 @@ In hy, you could do these like: (= (% 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! -------- From 9c3142f7521a834e1c279e1e2d4c440dfc16107f Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Tue, 2 Apr 2013 21:00:50 -0400 Subject: [PATCH 005/114] tigten that code up a skitch --- hy/compiler.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index d45d75d..8000d25 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -353,9 +353,7 @@ class HyASTCompiler(object): tar_it = iter(expr.pop(0)) targets = zip(tar_it, tar_it) - cond = None - if expr != []: - cond = self.compile(expr.pop(0)) + cond = self.compile(expr.pop(0)) if expr != [] else None ret = ast.ListComp( lineno=expr.start_line, From 41f0a6986276b1724f5833985cf2519be96cc463 Mon Sep 17 00:00:00 2001 From: Paul Tagliamonte Date: Tue, 2 Apr 2013 21:33:08 -0400 Subject: [PATCH 006/114] Add in a Python 3 hello world --- eg/python3/futures/hello-world.hy | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 eg/python3/futures/hello-world.hy diff --git a/eg/python3/futures/hello-world.hy b/eg/python3/futures/hello-world.hy new file mode 100644 index 0000000..3b031bc --- /dev/null +++ b/eg/python3/futures/hello-world.hy @@ -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))) From 1c8d21e3de6ca07e2f00510cc642f04d8430891a Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Wed, 3 Apr 2013 11:25:17 +0200 Subject: [PATCH 007/114] Raises TypeError on bad if statements This relates to issue #6. Signed-off-by: Julien Danjou --- hy/compiler.py | 12 ++++++++++-- tests/compilers/test_ast.py | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index bf7e136..afcdb51 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -152,8 +152,16 @@ class HyASTCompiler(object): @builds("if") def compile_if_expression(self, expr): expr.pop(0) - test = self.compile(expr.pop(0)) - body = self._code_branch(self.compile(expr.pop(0))) + try: + test = expr.pop(0) + except IndexError: + raise TypeError("if expects at least 2 arguments, got 0") + test = self.compile(test) + try: + body = expr.pop(0) + except IndexError: + raise TypeError("if expects at least 2 arguments, got 1") + body = self._code_branch(self.compile(body)) orel = [] if len(expr) > 0: orel = self._code_branch(self.compile(expr.pop(0))) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index fafcbcf..8714486 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -43,6 +43,29 @@ def test_ast_bad_type(): pass +def test_ast_bad_if_0_arg(): + "Make sure AST can't compile invalid if" + try: + hy_compile(tokenize("(if)")) + assert False + except TypeError: + pass + + +def test_ast_bad_if_1_arg(): + "Make sure AST can't compile invalid if" + try: + hy_compile(tokenize("(if foobar)")) + assert False + except TypeError: + pass + + +def test_ast_valid_if(): + "Make sure AST can't compile invalid if" + hy_compile(tokenize("(if foo bar)")) + + def test_ast_expression_basics(): """ Ensure basic AST expression conversion works. """ code = hy_compile(tokenize("(foo bar)")).body[0] From bcdf31e28758261e5ca75dcf4e39a7672959c245 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Wed, 3 Apr 2013 11:34:10 +0200 Subject: [PATCH 008/114] Do not quit hy if compile error occurs Signed-off-by: Julien Danjou --- bin/hy | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/hy b/bin/hy index 3998d3b..4167e68 100755 --- a/bin/hy +++ b/bin/hy @@ -51,8 +51,12 @@ class HyREPL(code.InteractiveConsole): tokens = process(_machine.nodes) _machine = Machine(Idle, 1, 0) - _ast = hy_compile(tokens, root=ast.Interactive) - code = compile(_ast, filename, symbol) + try: + _ast = hy_compile(tokens, root=ast.Interactive) + code = compile(_ast, filename, symbol) + except Exception: + self.showtraceback() + return False self.runcode(code) return False From 7fed29dad8dde3dffb4ef2d2867c0315a449d2e4 Mon Sep 17 00:00:00 2001 From: Paul Tagliamonte Date: Wed, 3 Apr 2013 09:22:37 -0400 Subject: [PATCH 009/114] Forgot to add @jd to AUTHORS. Thanks! --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index e49a99e..2a74bb4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,3 +4,4 @@ * Christopher Allan Webber * Will Kahn-Greene * James King +* Julien Danjou From 3537a8285d2e352e43466c4465a49cdc53b71264 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 3 Apr 2013 11:00:35 -0500 Subject: [PATCH 010/114] New (hy) logo! --- docs/_static/CC0_1.0.txt | 121 +++++++++++++++++++++++++++++++ docs/_static/hy_logo-about.txt | 15 ++++ docs/_static/hy_logo-paths.svg | 111 +++++++++++++++++++++++++++++ docs/_static/hy_logo.png | Bin 0 -> 15070 bytes docs/_static/hy_logo.svg | 125 +++++++++++++++++++++++++++++++++ 5 files changed, 372 insertions(+) create mode 100644 docs/_static/CC0_1.0.txt create mode 100644 docs/_static/hy_logo-about.txt create mode 100644 docs/_static/hy_logo-paths.svg create mode 100644 docs/_static/hy_logo.png create mode 100644 docs/_static/hy_logo.svg diff --git a/docs/_static/CC0_1.0.txt b/docs/_static/CC0_1.0.txt new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/docs/_static/CC0_1.0.txt @@ -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. diff --git a/docs/_static/hy_logo-about.txt b/docs/_static/hy_logo-about.txt new file mode 100644 index 0000000..203a1c3 --- /dev/null +++ b/docs/_static/hy_logo-about.txt @@ -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 + . diff --git a/docs/_static/hy_logo-paths.svg b/docs/_static/hy_logo-paths.svg new file mode 100644 index 0000000..392c136 --- /dev/null +++ b/docs/_static/hy_logo-paths.svg @@ -0,0 +1,111 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/_static/hy_logo.png b/docs/_static/hy_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ee62bd078c825b9aca79b845ec5545cda2831731 GIT binary patch literal 15070 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 G{`7xG)_QgT literal 0 HcmV?d00001 diff --git a/docs/_static/hy_logo.svg b/docs/_static/hy_logo.svg new file mode 100644 index 0000000..0b9b3c3 --- /dev/null +++ b/docs/_static/hy_logo.svg @@ -0,0 +1,125 @@ + + + + + + + + + + image/svg+xml + + + + + + + + λ + λ + ( + ) + + From ab1f30def5db48bf11eafb051453ab58c01380be Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 3 Apr 2013 11:27:40 -0500 Subject: [PATCH 011/114] Add hy logo to frontpage of docs --- docs/_static/hy_logo-smaller.png | Bin 0 -> 3857 bytes docs/index.rst | 4 ++++ 2 files changed, 4 insertions(+) create mode 100644 docs/_static/hy_logo-smaller.png diff --git a/docs/_static/hy_logo-smaller.png b/docs/_static/hy_logo-smaller.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd7b4db009dde240b777031f399c2a3e8794151 GIT binary patch literal 3857 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 literal 0 HcmV?d00001 diff --git a/docs/index.rst b/docs/index.rst index 57a77b1..2495b1e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,6 +1,10 @@ Welcome to Hy's documentation! ============================== +.. image:: _static/hy_logo-smaller.png + :alt: Hy logo + :align: left + Welcome to `Hy `_! Hy is a wonderful dialect of Lisp that's embedded in Python. Since Hy transforms its lisp code into the python Abstract Syntax From 4a6fa150992bf77bd572189cd33b57e0822a28b4 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 3 Apr 2013 11:30:22 -0500 Subject: [PATCH 012/114] There's no reason for the " ; and a little more complex" comment --- docs/language/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/language/index.rst b/docs/language/index.rst index e8769bb..d26ca5a 100644 --- a/docs/language/index.rst +++ b/docs/language/index.rst @@ -334,7 +334,6 @@ In hy, you could do these like: .. code-block:: clj - ; and a little more complex (setv odds-squared (list-comp (pow num 2) From c627fad5e2306bef59c83e63ad4b4a08dd82a0f3 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 3 Apr 2013 11:59:52 -0500 Subject: [PATCH 013/114] No documentation of one of .hy's coolest features, bidirectional imports! --- docs/language/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/language/index.rst b/docs/language/index.rst index d26ca5a..657c205 100644 --- a/docs/language/index.rst +++ b/docs/language/index.rst @@ -411,3 +411,4 @@ 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! From d070d3d484f063ab240de978eed6028a59ad1a89 Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Wed, 3 Apr 2013 19:55:09 +0200 Subject: [PATCH 014/114] Add while loops to the compiler --- TODO | 3 --- hy/compiler.py | 20 ++++++++++++++++++++ tests/compilers/test_ast.py | 23 +++++++++++++++++++++++ tests/native_tests/language.hy | 11 +++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/TODO b/TODO index bf2c64d..5d29fb0 100644 --- a/TODO +++ b/TODO @@ -9,9 +9,6 @@ + Use (def) to imply global foo - - New Builtins: - + While - - New macros: + loop diff --git a/hy/compiler.py b/hy/compiler.py index e860195..9e98af5 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -545,6 +545,26 @@ class HyASTCompiler(object): self.returnable = ret_status return ret + @builds("while") + def compile_while_expression(self, expr): + expr.pop(0) # "while" + + try: + test = expr.pop(0) + except IndexError: + raise TypeError("while expects at least 2 arguments, got 0") + test = self.compile(test) + + if not expr: + raise TypeError("while expects a body") + + return ast.While(test=test, + body=self._mangle_branch([ + self.compile(x) for x in expr]), + orelse=[], + lineno=expr.start_line, + col_offset=expr.start_column) + @builds(HyList) def compile_list(self, expr): return ast.List( diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 8714486..88208d1 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -66,6 +66,29 @@ def test_ast_valid_if(): hy_compile(tokenize("(if foo bar)")) +def test_ast_bad_while_0_arg(): + "Make sure AST can't compile invalid while" + try: + hy_compile(tokenize("(while)")) + assert False + except TypeError: + pass + + +def test_ast_bad_while_1_arg(): + "Make sure AST can't compile invalid while" + try: + hy_compile(tokenize("(while (true))")) + assert False + except TypeError: + 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(): """ Ensure basic AST expression conversion works. """ code = hy_compile(tokenize("(foo bar)")).body[0] diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 2d5ecd3..ffc6109 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -32,6 +32,17 @@ (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-in [] "NATIVE: test in" (assert (in "a" ["a" "b" "c" "d"])) From b098070a7d89ffa874f4eb0bf2a2841137d62631 Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Wed, 3 Apr 2013 21:03:34 +0200 Subject: [PATCH 015/114] Add myself to AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 2a74bb4..a3ef4d0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -5,3 +5,4 @@ * Will Kahn-Greene * James King * Julien Danjou +* Nicolas Dandrimont From 976d8b5bf13e64360f3326fa111f7290f132afef Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 3 Apr 2013 16:21:31 -0500 Subject: [PATCH 016/114] Renaming "language spec" to "tutorial" --- docs/index.rst | 2 +- docs/language/{index.rst => tutorial.rst} | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) rename docs/language/{index.rst => tutorial.rst} (99%) diff --git a/docs/index.rst b/docs/index.rst index 2495b1e..9998081 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -36,5 +36,5 @@ Contents: .. toctree:: :maxdepth: 3 - language/index + language/tutorial .. library/index diff --git a/docs/language/index.rst b/docs/language/tutorial.rst similarity index 99% rename from docs/language/index.rst rename to docs/language/tutorial.rst index 657c205..bdbb455 100644 --- a/docs/language/index.rst +++ b/docs/language/tutorial.rst @@ -1,5 +1,6 @@ -Language Spec -============= +Tutorial +======== + This bit covers a bit about Hy's lovable quirks and eccentricities. @@ -380,7 +381,7 @@ Let's take the classic: (loop (print (eval (read)))) Rather then write it like that, we can write it as follows: - +1 .. code-block:: clj (-> (read) (eval) (print) (loop)) From 39bc7e0b97d79e4b0480024c73e779ab573de344 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 3 Apr 2013 16:27:01 -0500 Subject: [PATCH 017/114] Replacing "quirks and eccentricities" with a "welcome" We love welcoming people! --- docs/language/tutorial.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/language/tutorial.rst b/docs/language/tutorial.rst index bdbb455..4efbc82 100644 --- a/docs/language/tutorial.rst +++ b/docs/language/tutorial.rst @@ -1,8 +1,7 @@ Tutorial ======== - -This bit covers a bit about Hy's lovable quirks and eccentricities. +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 From d5d05c1dba3587f04651340783bc6622063cb67f Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber Date: Wed, 3 Apr 2013 16:27:20 -0500 Subject: [PATCH 018/114] Removing accidental 1 insertion. Sorry paultag! --- docs/language/tutorial.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/tutorial.rst b/docs/language/tutorial.rst index 4efbc82..b0d6ed7 100644 --- a/docs/language/tutorial.rst +++ b/docs/language/tutorial.rst @@ -380,7 +380,7 @@ Let's take the classic: (loop (print (eval (read)))) Rather then write it like that, we can write it as follows: -1 + .. code-block:: clj (-> (read) (eval) (print) (loop)) From d421d869af35b1d049c67af74e8a6858c38f993b Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Wed, 3 Apr 2013 20:18:56 -0400 Subject: [PATCH 019/114] Fixing the "olasd" bug --- hy/compiler.py | 19 +++++++++++++++---- tests/native_tests/language.hy | 8 ++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 9e98af5..5514263 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -72,10 +72,21 @@ class HyASTCompiler(object): ret.append(ast.Return(value=el, lineno=el.lineno, col_offset=el.col_offset)) - ret += [ast.Expr(value=el, - lineno=el.lineno, - col_offset=el.col_offset) - if not isinstance(el, ast.stmt) else el for el in tree] # NOQA + + for el in tree: + if type(el) == list: + blob = self._mangle_branch(el) + blob.reverse() + ret += blob + continue + + 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() return ret diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index ffc6109..3e92e1e 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -212,6 +212,14 @@ (with-as (open "README.md" "r") fd (pass))) +(defn test-for-doodle [] + "NATIVE: test for-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 [] "NATIVE: test list comprehensions" From 20df97a66d165171882471bf5398ffeb53217d8d Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Wed, 3 Apr 2013 20:39:00 -0400 Subject: [PATCH 020/114] note to self, changelog --- ChangeLog | 1 + TODO | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index e6c6361..fb26993 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ 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. +(compile_while_expression): New `while' syntax 2013-03-29 Paul Tagliamonte diff --git a/TODO b/TODO index 5d29fb0..13d0ff4 100644 --- a/TODO +++ b/TODO @@ -28,3 +28,5 @@ - core tests (odd? even? true? false?) which build out to a lambda / function / expr + + - add -d flag (debug) for hy REPL based on @jd's try/catch From 99f62fb8b3080156b27334085bbdd4cdd79f17bc Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Thu, 4 Apr 2013 09:29:21 +0200 Subject: [PATCH 021/114] Add some tests for defn --- tests/native_tests/language.hy | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 3e92e1e..0bb9f77 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -229,3 +229,19 @@ [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)))) From 940afcafa92fa45c718499c5412be28a2cacef0d Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Thu, 4 Apr 2013 08:51:59 +0200 Subject: [PATCH 022/114] Allow (do) inside (defn) Closes #59 --- hy/compiler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index 5514263..7294008 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -67,7 +67,7 @@ class HyASTCompiler(object): if self.returnable and len(tree) > 0: el = tree[0] - if not isinstance(el, ast.stmt): + if not isinstance(el, (ast.stmt, list)): el = tree.pop(0) ret.append(ast.Return(value=el, lineno=el.lineno, From 06511fe303aa2d3aff82d5b689fe21b592d64d80 Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Thu, 4 Apr 2013 11:06:03 +0200 Subject: [PATCH 023/114] Add do-in-defn tests --- tests/native_tests/language.hy | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 0bb9f77..0538f44 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -245,3 +245,22 @@ (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)))) From ba021ed7bf8e40584c45721b880567c6afd4c5e3 Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Thu, 4 Apr 2013 11:20:10 +0200 Subject: [PATCH 024/114] Count the number of expressions executed in do --- tests/native_tests/language.hy | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 0538f44..79fa344 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -85,6 +85,17 @@ (assert (= 1 1)) (assert (= 1 1))))) +(defn test-branching-expr-count-with-do [] + "NATIVE: make sure we execute the right number of expressions in the branch" + (setv counter 0) + (if false + (assert (= 2 1)) + (do + (setv counter (+ counter 1)) + (setv counter (+ counter 1)) + (setv counter (+ counter 1)))) + (assert (= counter 3))) + (defn test-cond [] "NATIVE: test if cond sorta works." From b2406a9d728d323a75beece031fa3195b625822a Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Thu, 4 Apr 2013 19:32:56 -0400 Subject: [PATCH 025/114] list flattener --- hy/compiler.py | 11 ++++------- hy/util.py | 28 ++++++++++++++++++++++++++++ tests/native_tests/language.hy | 8 +++++++- 3 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 hy/util.py diff --git a/hy/compiler.py b/hy/compiler.py index 7294008..d97df00 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -27,6 +27,8 @@ from hy.models.symbol import HySymbol from hy.models.list import HyList from hy.models.dict import HyDict +from hy.util import flatten_literal_list + import ast import sys @@ -63,23 +65,18 @@ class HyASTCompiler(object): def _mangle_branch(self, tree): ret = [] + tree = list(flatten_literal_list(tree)) tree.reverse() if self.returnable and len(tree) > 0: el = tree[0] - if not isinstance(el, (ast.stmt, list)): + if not isinstance(el, ast.stmt): el = tree.pop(0) ret.append(ast.Return(value=el, lineno=el.lineno, col_offset=el.col_offset)) for el in tree: - if type(el) == list: - blob = self._mangle_branch(el) - blob.reverse() - ret += blob - continue - if isinstance(el, ast.stmt): ret.append(el) continue diff --git a/hy/util.py b/hy/util.py new file mode 100644 index 0000000..f2ffdf1 --- /dev/null +++ b/hy/util.py @@ -0,0 +1,28 @@ +# Copyright (c) 2013 Paul Tagliamonte +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + + +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 diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 79fa344..153f548 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -223,15 +223,17 @@ (with-as (open "README.md" "r") fd (pass))) + (defn test-for-doodle [] "NATIVE: test for-do" - (setf (, x y) (, 0 0)) + (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 [] "NATIVE: test list comprehensions" (assert (= (list-comp (* x 2) (x (range 2))) [0 2])) @@ -241,6 +243,7 @@ (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 []) @@ -251,12 +254,14 @@ (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 []) @@ -268,6 +273,7 @@ (my-fun) (assert (= acc ["Foo" "Bar" "Baz"]))) + (defn test-defn-do-return [] "NATIVE: test defn return with do" (defn my-fun [x] From 256506ede0705fd6f702d708d36bf0d9474dfe1b Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Thu, 4 Apr 2013 21:47:00 -0400 Subject: [PATCH 026/114] Sketch for #50 - branch mangler This is only slightly better. The insert point needs to walk with the for loop. --- hy/core/__init__.py | 11 ++++- hy/core/mangles.py | 52 ++++++++++++++++++++++++ hy/mangle.py | 99 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 hy/core/mangles.py create mode 100644 hy/mangle.py diff --git a/hy/core/__init__.py b/hy/core/__init__.py index ac5262a..f5d9a52 100644 --- a/hy/core/__init__.py +++ b/hy/core/__init__.py @@ -20,15 +20,22 @@ from hy.macros import process as mprocess +import hy.mangle + MACROS = [ - "hy.core.bootstrap", # defn, cond + "hy.core.bootstrap", + "hy.core.mangles", ] def process(tree): load_macros() - return mprocess(tree) + tree = mprocess(tree) + for m in hy.mangle.MANGLES: + m().mangle(tree) + print tree + return tree def load_macros(): diff --git a/hy/core/mangles.py b/hy/core/mangles.py new file mode 100644 index 0000000..0290382 --- /dev/null +++ b/hy/core/mangles.py @@ -0,0 +1,52 @@ +# Copyright (c) 2013 Paul Tagliamonte +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +from hy.models.expression import HyExpression +from hy.models.symbol import HySymbol + +import hy.mangle + + +class FunctionMangle(hy.mangle.Mangle): + hoistable = ["fn"] + + 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): + call = tree[0] + if isinstance(call, HyExpression) and len(call) != 0: + what = call[0] + if what in self.hoistable: + name = self.unique_name() + call = HyExpression([HySymbol("def"), name, call]) + self.hoist(call) + tree.pop(0) + entry = HySymbol(name) + entry.replace(tree) + tree.insert(0, entry) + raise self.TreeChanged() + +hy.mangle.MANGLES.append(FunctionMangle) diff --git a/hy/mangle.py b/hy/mangle.py new file mode 100644 index 0000000..4cd025e --- /dev/null +++ b/hy/mangle.py @@ -0,0 +1,99 @@ +# Copyright (c) 2013 Paul Tagliamonte +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +from hy.models.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 + + if isinstance(tree, HyExpression): + what = tree[0] + if what in scopable: + self.push_scope(tree) + scoped = True + + if isinstance(tree, list): + for element in tree: + self.visit(element) + self._mangle(element) + + if scoped: + self.pop_scope() + + def hoist(self, what): + #print "HOIST: " + #print " --> (fro) ", what + #print " --> (to) ", self.scope + scope = self.scope + point = 0 + + if isinstance(scope, HyExpression) and len(scope): + if scope[0] == 'fn': + point = 3 + + self.scope.insert(point, what) + #print " --> (aft) ", self.scope + + def get_scope(self): + return self.scopes[0] + + @property + def scope(self): + return self.get_scope() + + def push_scope(self, tree): + self.scopes.insert(0, tree) + + def pop_scope(self): + return self.scopes.pop(0) + + def mangle(self, tree): + unfinished = True + while unfinished: + self.root = tree + self.scopes = [] + self.push_scope(tree) + try: + self._mangle(tree) + unfinished = False + except self.TreeChanged: + pass From 4e2e18576a55c2066c9f7c70c642cd04fa459e32 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Thu, 4 Apr 2013 21:49:04 -0400 Subject: [PATCH 027/114] Fixing a subtle bug. --- hy/mangle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hy/mangle.py b/hy/mangle.py index 4cd025e..d49d3fb 100644 --- a/hy/mangle.py +++ b/hy/mangle.py @@ -68,7 +68,7 @@ class Mangle(object): if isinstance(scope, HyExpression) and len(scope): if scope[0] == 'fn': - point = 3 + point = 2 self.scope.insert(point, what) #print " --> (aft) ", self.scope From 7c9fa3758cce9266de6cc4a66aaa28f476f183a7 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Thu, 4 Apr 2013 21:50:01 -0400 Subject: [PATCH 028/114] Print is for loosers. --- hy/core/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hy/core/__init__.py b/hy/core/__init__.py index f5d9a52..a17b72c 100644 --- a/hy/core/__init__.py +++ b/hy/core/__init__.py @@ -34,7 +34,6 @@ def process(tree): tree = mprocess(tree) for m in hy.mangle.MANGLES: m().mangle(tree) - print tree return tree From 9578ae7a5743f73b577082661b355427d4c15929 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Thu, 4 Apr 2013 21:52:15 -0400 Subject: [PATCH 029/114] This fix is in living memory of paroneayea --- hy/lex/states.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hy/lex/states.py b/hy/lex/states.py index 6966a39..72caba6 100644 --- a/hy/lex/states.py +++ b/hy/lex/states.py @@ -236,6 +236,9 @@ class String(State): if char == "\\": self.nodes.append("\\") return + if char == "\"": + self.nodes.append("\"") + return raise LexException("Unknown modifier: `%s'" % (char)) From 936d1bcec73ea28d179d73b8206bbe304e5cd36e Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Thu, 4 Apr 2013 21:58:26 -0400 Subject: [PATCH 030/114] testing nested things --- tests/native_tests/language.hy | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 153f548..65b66ba 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -281,3 +281,8 @@ (+ x 42) ; noop (+ x 1))) (assert (= 43 (my-fun 42)))) + + +(defn test-mangles [] + "NATIVE: test mangles" + (assert (= 2 ((fn [] (+ 1 1)))))) From 57f764ebfef599ef037e4c96be086bf7164a661e Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 5 Apr 2013 14:56:59 -0400 Subject: [PATCH 031/114] Cosmetic: Fix header formatting This tweaks the header formatting in reST so that we can use --- for 3rd level headers. --- docs/language/tutorial.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/language/tutorial.rst b/docs/language/tutorial.rst index b0d6ed7..f10002f 100644 --- a/docs/language/tutorial.rst +++ b/docs/language/tutorial.rst @@ -1,3 +1,4 @@ +======== Tutorial ======== @@ -20,7 +21,7 @@ This is pretty cool because it means Hy is several things: Basic intro to lisp for pythonistas ------------------------------------ +=================================== Okay, maybe you've never used lisp before, but you've used python! @@ -173,7 +174,7 @@ 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. @@ -364,7 +365,7 @@ In hy, you could do these like: Protips! --------- +======== Hy also features something known as the "threading macro", a really neat feature of Clojure's. The "threading macro" (written as "->"), is used @@ -404,9 +405,8 @@ Which, of course, expands out to: Much more readable, no! Use the threading macro! - TODO ----- +==== - How do I define classes? - Blow your mind with macros! From 39106c9c6279fad71a502fac265022b55022e8a0 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 5 Apr 2013 16:29:32 -0400 Subject: [PATCH 032/114] Add explicit LICENSE file The LICENSE is at the top of setup.py, but ... having a LICENSE or COPYING file is more conventional. So this adds that. --- LICENSE | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c98d41b --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012, 2013 Paul Tagliamonte + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. From 6fbba171581f4248128b6a694e4a0d8161789c94 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 5 Apr 2013 16:30:12 -0400 Subject: [PATCH 033/114] Add quickstart and hacking docs --- README.md | 11 ++++++++ docs/hacking.rst | 67 +++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 2 ++ docs/quickstart.rst | 31 +++++++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 docs/hacking.rst create mode 100644 docs/quickstart.rst diff --git a/README.md b/README.md index 36dffe1..6c398e7 100644 --- a/README.md +++ b/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) + Hylarious Hacks --------------- @@ -28,3 +29,13 @@ Well, I wrote Hy to help people realize one thing about Python: It's really goddamn awesome. 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) diff --git a/docs/hacking.rst b/docs/hacking.rst new file mode 100644 index 0000000..9e64076 --- /dev/null +++ b/docs/hacking.rst @@ -0,0 +1,67 @@ +=============== + 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 spraypaint it on your neighbor's fence! + + +Hack! +===== + +Do this: + +1. create a Python virtual environment +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 +`_. + +To run the tests:: + + $ nosetests + +Write tests---tests are good! + + +Document! +========= + +Documentation is located in ``docs/``. We use `Sphinx +`_. + +To build the docs in html:: + + $ cd docs + $ make html + +Write docs---docs are good! Even this doc! diff --git a/docs/index.rst b/docs/index.rst index 9998081..1618c2f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -36,5 +36,7 @@ Contents: .. toctree:: :maxdepth: 3 + quickstart + hacking language/tutorial .. library/index diff --git a/docs/quickstart.rst b/docs/quickstart.rst new file mode 100644 index 0000000..561418d --- /dev/null +++ b/docs/quickstart.rst @@ -0,0 +1,31 @@ +========== +Quickstart +========== + +I WANT TO BE DOING HY STUFF RIGHT NOW! + +1. create a Python virtual environment +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 [] (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 "hy is the BEST!") + +9. save as ``test_program_of_awesome.hy`` +10. run ``hy test_program_of_awesome.hy`` From b37f5f21d59714ae2418daa5c5db20b8375618a7 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 5 Apr 2013 16:34:25 -0400 Subject: [PATCH 034/114] Fix to be more friendly --- docs/hacking.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hacking.rst b/docs/hacking.rst index 9e64076..5db4a07 100644 --- a/docs/hacking.rst +++ b/docs/hacking.rst @@ -13,7 +13,7 @@ Please talk about it on Twitter with the ``#hy`` hashtag! Please blog about it! -Please spraypaint it on your neighbor's fence! +Please don't spraypaint it on your neighbor's fence (without asking nicely)! Hack! From 4ddae38a8b4a201df8b3c017ea295683a6760669 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 5 Apr 2013 16:39:46 -0400 Subject: [PATCH 035/114] Linkificate the Python virtual environment text --- docs/hacking.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/hacking.rst b/docs/hacking.rst index 5db4a07..10ebc50 100644 --- a/docs/hacking.rst +++ b/docs/hacking.rst @@ -21,7 +21,8 @@ Hack! Do this: -1. create a Python virtual environment +1. create a `Python virtual environment + `_ 2. (optional) go to https://github.com/paultag/hy and fork it 3. get the source code:: From 1d01d8874addf8cf6d9a7ac326b1c25e965a4bce Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Fri, 5 Apr 2013 19:29:31 -0400 Subject: [PATCH 036/114] Bugfix for #50. I'm slowly starting to take a shine to this. --- hy/core/mangles.py | 35 +++++++++++++++++++++++------------ hy/mangle.py | 34 ++++++++++++++++++++++------------ 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/hy/core/mangles.py b/hy/core/mangles.py index 0290382..e44ab16 100644 --- a/hy/core/mangles.py +++ b/hy/core/mangles.py @@ -26,6 +26,7 @@ import hy.mangle class FunctionMangle(hy.mangle.Mangle): hoistable = ["fn"] + ignore = ["def", "decorate_with"] def __init__(self): self.series = 0 @@ -34,19 +35,29 @@ class FunctionMangle(hy.mangle.Mangle): self.series += 1 return "_hy_hoisted_fn_%s" % (self.series) + 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 + def visit(self, tree): - if isinstance(tree, HyExpression): + if isinstance(tree, HyExpression) and tree != []: call = tree[0] - if isinstance(call, HyExpression) and len(call) != 0: - what = call[0] - if what in self.hoistable: - name = self.unique_name() - call = HyExpression([HySymbol("def"), name, call]) - self.hoist(call) - tree.pop(0) - entry = HySymbol(name) - entry.replace(tree) - tree.insert(0, entry) - raise self.TreeChanged() + 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 hy.mangle.MANGLES.append(FunctionMangle) diff --git a/hy/mangle.py b/hy/mangle.py index d49d3fb..a0f2051 100644 --- a/hy/mangle.py +++ b/hy/mangle.py @@ -45,6 +45,8 @@ class Mangle(object): scopable = ["fn", "if"] scoped = False + self.push_stack(tree) + if isinstance(tree, HyExpression): what = tree[0] if what in scopable: @@ -52,30 +54,31 @@ class Mangle(object): scoped = True if isinstance(tree, list): - for element in tree: - self.visit(element) + 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): - #print "HOIST: " - #print " --> (fro) ", what - #print " --> (to) ", self.scope scope = self.scope - point = 0 - - if isinstance(scope, HyExpression) and len(scope): - if scope[0] == 'fn': - point = 2 - + for point, el in enumerate(scope): + if el in self.stack: + break self.scope.insert(point, what) - #print " --> (aft) ", self.scope def get_scope(self): return self.scopes[0] + def tree_changed(self): + raise self.TreeChanged() + @property def scope(self): return self.get_scope() @@ -83,14 +86,21 @@ class Mangle(object): 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) From 65ad7a3b877ef809ca2e563fc1201ee143f4feec Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Fri, 5 Apr 2013 19:46:27 -0400 Subject: [PATCH 037/114] Adding FunctionDef as a returnable --- hy/compiler.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hy/compiler.py b/hy/compiler.py index d97df00..4a72b1a 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -75,6 +75,12 @@ class HyASTCompiler(object): ret.append(ast.Return(value=el, lineno=el.lineno, col_offset=el.col_offset)) + if isinstance(el, ast.FunctionDef): + ret.append(ast.Return( + value=ast.Name( + 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): From 27e4772aa7c460c969cee0dd8bbdaaa1c3218c5c Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Fri, 5 Apr 2013 19:59:33 -0400 Subject: [PATCH 038/114] Test the function return-o-matic --- tests/native_tests/language.hy | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 65b66ba..510a4b0 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -286,3 +286,10 @@ (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))) + From d762625aeb7bc280424c2a13a577af79382dc6d6 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Fri, 5 Apr 2013 20:00:19 -0400 Subject: [PATCH 039/114] also ignore setf / setv --- hy/core/mangles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hy/core/mangles.py b/hy/core/mangles.py index e44ab16..2d16f0a 100644 --- a/hy/core/mangles.py +++ b/hy/core/mangles.py @@ -26,7 +26,7 @@ import hy.mangle class FunctionMangle(hy.mangle.Mangle): hoistable = ["fn"] - ignore = ["def", "decorate_with"] + ignore = ["def", "decorate_with", "setf", "setv"] def __init__(self): self.series = 0 From 3b185250e0d30b799db3142ab7400431c427681c Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Fri, 5 Apr 2013 20:01:37 -0400 Subject: [PATCH 040/114] trailing newlines suck --- tests/native_tests/language.hy | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 510a4b0..3cc7e63 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -292,4 +292,3 @@ "NATIVE: test function return" (setv fn-test ((fn [] (fn [] (+ 1 1))))) (assert (= (fn-test) 2))) - From d206e327a92250616970410cf90184ce4f97c36b Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Fri, 5 Apr 2013 20:04:36 -0400 Subject: [PATCH 041/114] Removing my name from the license. --- LICENSE | 2 -- 1 file changed, 2 deletions(-) diff --git a/LICENSE b/LICENSE index c98d41b..1e4a5f8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,3 @@ -Copyright (c) 2012, 2013 Paul Tagliamonte - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation From fa5ab3b3ad5f59367e8492f61bf59c687f02814e Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Fri, 5 Apr 2013 20:15:02 -0400 Subject: [PATCH 042/114] Tests for a future native-eval. Close #64. --- tests/native_tests/language.hy | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 3cc7e63..83ab1c4 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -292,3 +292,17 @@ "NATIVE: test function return" (setv fn-test ((fn [] (fn [] (+ 1 1))))) (assert (= (fn-test) 2))) + + +; 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)))) From d48c2b7cae29bf768483ef7a0681a2bd4994cc2c Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Fri, 5 Apr 2013 20:47:25 -0400 Subject: [PATCH 043/114] Calling this 0.9.4 --- hy/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hy/__init__.py b/hy/__init__.py index 05ae409..7ac6aac 100644 --- a/hy/__init__.py +++ b/hy/__init__.py @@ -20,7 +20,7 @@ __appname__ = "hy" -__version__ = "0.9.3" +__version__ = "0.9.4" import hy.importer # NOQA From f129c50c1f0871a0ed80cc850ed10be24456387f Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Fri, 5 Apr 2013 21:24:27 -0400 Subject: [PATCH 044/114] We suck at changelog stuff; blasting. --- ChangeLog | 34 ---------------------------------- 1 file changed, 34 deletions(-) delete mode 100644 ChangeLog diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index fb26993..0000000 --- a/ChangeLog +++ /dev/null @@ -1,34 +0,0 @@ -2013-04-01 Paul Tagliamonte - -* 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. -(compile_while_expression): New `while' syntax - -2013-03-29 Paul Tagliamonte - -* New release, 0.9.3. - -2013-03-27 Paul Tagliamonte - -* 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 - -* 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 - -* 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. From f9f99a430b6e9b83f40ae6a172b2c0cea8e8f68e Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 5 Apr 2013 21:22:47 -0400 Subject: [PATCH 045/114] Linkificate the other Python virtual environment text --- docs/quickstart.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 561418d..4015392 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -4,7 +4,8 @@ Quickstart I WANT TO BE DOING HY STUFF RIGHT NOW! -1. create a Python virtual environment +1. create a `Python virtual environment + `_ 2. activate your Python virtual environment 3. ``pip install hy`` 4. start a REPL with ``hy`` From 3cfaf0af1e8f7617bd5b0b3f4ab46bfeda8fb973 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 5 Apr 2013 21:27:30 -0400 Subject: [PATCH 046/114] Tweak runline for easier reading --- docs/quickstart.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 4015392..e2b5902 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -29,4 +29,6 @@ OMG! That's amazing! I want to write a hy program. (print "hy is the BEST!") 9. save as ``test_program_of_awesome.hy`` -10. run ``hy test_program_of_awesome.hy`` +10. run:: + + hy test_program_of_awesome.hy From 9178d541fd17dc0df132cae147439b18f4532b01 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 5 Apr 2013 21:38:18 -0400 Subject: [PATCH 047/114] Add necessary conclusion to quickstart --- docs/quickstart.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index e2b5902..3645873 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -32,3 +32,6 @@ OMG! That's amazing! I want to write a hy program. 10. run:: hy test_program_of_awesome.hy + +11. smile villainously and sneak off to your hydeaway and do + unspeakable things From 7abc47233680bb5305c3daef92b4c1adf15cbf6d Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Fri, 5 Apr 2013 21:53:44 -0400 Subject: [PATCH 048/114] Implementing `let' --- hy/core/bootstrap.py | 16 ++++++++++++++++ tests/native_tests/language.hy | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/hy/core/bootstrap.py b/hy/core/bootstrap.py index 9d46289..e77fb02 100644 --- a/hy/core/bootstrap.py +++ b/hy/core/bootstrap.py @@ -114,3 +114,19 @@ def rest_macro(tree): return HyExpression([HySymbol('slice'), ret, 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]) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 83ab1c4..4366d06 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -294,6 +294,11 @@ (assert (= (fn-test) 2))) +(defn test-let [] + "NATIVE: test let works rightish" + (assert (= (let [[x 1] [y 2] [z 3]] (+ x y z)) 6))) + + ; FEATURE: native hy-eval ; ; - related to bug #64 From 485c98c7991d49612eccb6e22325c5a28535f74a Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Fri, 5 Apr 2013 21:50:13 -0400 Subject: [PATCH 049/114] Add important pause in quickstart to regain composure --- docs/quickstart.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 3645873..e15ecbe 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -2,7 +2,7 @@ Quickstart ========== -I WANT TO BE DOING HY STUFF RIGHT NOW! +HOW TO GET HY REAL FAST: 1. create a `Python virtual environment `_ @@ -33,5 +33,6 @@ OMG! That's amazing! I want to write a hy program. hy test_program_of_awesome.hy -11. smile villainously and sneak off to your hydeaway and do +11. take a deep breath so as to not hyperventilate +12. smile villainously and sneak off to your hydeaway and do unspeakable things From 9768345a7c78b8bf25fb44e8e4e1ab353dbe5924 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sat, 6 Apr 2013 10:12:03 +0200 Subject: [PATCH 050/114] let: add a scope test Signed-off-by: Julien Danjou --- tests/native_tests/language.hy | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 4366d06..0882070 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -299,6 +299,20 @@ (assert (= (let [[x 1] [y 2] [z 3]] (+ x y z)) 6))) +(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 NameError e (assert e))) + (assert (= y 123))) + + ; FEATURE: native hy-eval ; ; - related to bug #64 From b36018981a15db232b572dd9fe5e8f952e183dc3 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Fri, 5 Apr 2013 17:37:55 +0200 Subject: [PATCH 051/114] if: emit error on too many args Signed-off-by: Julien Danjou --- hy/compiler.py | 4 +++- tests/compilers/test_ast.py | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index 4a72b1a..4c19796 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -176,8 +176,10 @@ class HyASTCompiler(object): raise TypeError("if expects at least 2 arguments, got 1") body = self._code_branch(self.compile(body)) orel = [] - if len(expr) > 0: + if len(expr) == 1: orel = self._code_branch(self.compile(expr.pop(0))) + elif len(expr) > 1: + raise TypeError("if expects 2 or 3 arguments, got %d" % (len(expr) + 2)) return ast.If(test=test, body=body, diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 88208d1..87d7cc3 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -61,6 +61,15 @@ def test_ast_bad_if_1_arg(): pass +def test_ast_bad_if_too_much_arg(): + "Make sure AST can't compile invalid if" + try: + hy_compile(tokenize("(if 1 2 3 4 5)")) + assert False + except TypeError: + pass + + def test_ast_valid_if(): "Make sure AST can't compile invalid if" hy_compile(tokenize("(if foo bar)")) From 3e9a2178c52faa3f89a4b4af4ba10675515657cb Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sat, 6 Apr 2013 10:37:21 +0200 Subject: [PATCH 052/114] Add support for unary operators (not, ~) Signed-off-by: Julien Danjou --- hy/compiler.py | 16 ++++++++++++++++ tests/compilers/test_ast.py | 23 +++++++++++++++++++++++ tests/native_tests/language.hy | 13 +++++++++++++ 3 files changed, 52 insertions(+) diff --git a/hy/compiler.py b/hy/compiler.py index 4a72b1a..d6168a5 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -415,6 +415,22 @@ class HyASTCompiler(object): return call + @builds("not") + @builds("~") + def compile_unary_operator(self, expression): + if len(expression) != 2: + raise TypeError("Unary operator expects only 1 argument, got %d" + % (len(expression) - 1)) + 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("=") @builds("!=") @builds("<") diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 88208d1..7db9b57 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -34,6 +34,14 @@ def _ast_spotcheck(arg, root, secondary): assert getattr(root, arg) == getattr(secondary, arg) +def cant_compile(expr): + try: + hy_compile(tokenize(expr)) + assert False + except TypeError: + pass + + def test_ast_bad_type(): "Make sure AST breakage can happen" try: @@ -66,6 +74,21 @@ def test_ast_valid_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_0_arg(): "Make sure AST can't compile invalid while" try: diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 4366d06..3d320c6 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -43,6 +43,19 @@ (assert (= fact 120))) +(defn test-not [] + "NATIVE: test not" + (assert (not (= 1 2))) + (assert (= true (not false))) + (assert (= false (not 42))) ) + + +(defn test-inv [] + "NATIVE: test inv" + (assert (= (~ 1) -2)) + (assert (= (~ -2) 1))) + + (defn test-in [] "NATIVE: test in" (assert (in "a" ["a" "b" "c" "d"])) From c612582e7b41cb653a067b94aad4bf6ce58fb908 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 08:17:04 -0400 Subject: [PATCH 053/114] cosmetic style fix --- hy/compiler.py | 1 - 1 file changed, 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index d6168a5..a93ab26 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -430,7 +430,6 @@ class HyASTCompiler(object): lineno=operator.start_line, col_offset=operator.start_column) - @builds("=") @builds("!=") @builds("<") From a625493a3f5747f65c1c2f6e32021806f906a6d5 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 08:18:45 -0400 Subject: [PATCH 054/114] Style fix --- hy/compiler.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index 174a99b..5563233 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -176,10 +176,12 @@ class HyASTCompiler(object): raise TypeError("if expects at least 2 arguments, got 1") body = self._code_branch(self.compile(body)) orel = [] + if len(expr) == 1: orel = self._code_branch(self.compile(expr.pop(0))) elif len(expr) > 1: - raise TypeError("if expects 2 or 3 arguments, got %d" % (len(expr) + 2)) + raise TypeError("if expects 2 or 3 arguments, got %d" % ( + len(expr) + 2)) return ast.If(test=test, body=body, From 4b57fd0a51965f10ec523b10e92cf86649fd35a5 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 11:10:33 -0400 Subject: [PATCH 055/114] Adding in an If mangle --- hy/core/mangles.py | 43 +++++++++++++++++++++++++--------- tests/native_tests/language.hy | 5 ++++ 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/hy/core/mangles.py b/hy/core/mangles.py index 2d16f0a..69744ec 100644 --- a/hy/core/mangles.py +++ b/hy/core/mangles.py @@ -20,21 +20,12 @@ from hy.models.expression import HyExpression from hy.models.symbol import HySymbol +from hy.models.list import HyList import hy.mangle -class FunctionMangle(hy.mangle.Mangle): - 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) - +class HoistableMangle(hy.mangle.Mangle): def should_hoist(self): for frame in self.stack: if frame is self.scope: @@ -47,6 +38,18 @@ class FunctionMangle(hy.mangle.Mangle): 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] @@ -60,4 +63,22 @@ class FunctionMangle(hy.mangle.Mangle): 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) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 8cb3667..1db6def 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -312,6 +312,11 @@ (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-let-scope [] "NATIVE: test let works rightish" (setv y 123) From 0eb795b4a5c70d11e38f618aff5498daa9bff373 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sat, 6 Apr 2013 16:33:06 +0200 Subject: [PATCH 056/114] Check the number of arguments for each function Signed-off-by: Julien Danjou --- hy/compiler.py | 102 +++++++++++++++------- hy/importer.py | 8 +- tests/compilers/test_ast.py | 149 +++++++++++++++++++++++++++++++-- tests/native_tests/language.hy | 2 +- 4 files changed, 221 insertions(+), 40 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 5563233..20eb094 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -50,6 +50,38 @@ def builds(_type): 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): def __init__(self): @@ -57,9 +89,16 @@ class HyASTCompiler(object): self.anon_fn_count = 0 def compile(self, tree): - for _type in _compile_table: - if type(tree) == _type: - return _compile_table[_type](self, tree) + try: + for _type in _compile_table: + if type(tree) == _type: + return _compile_table[_type](self, tree) + except Exception as e: + err = HyCompileError(str(e)) + err.exception = e + err.start_line = getattr(e, "start_line", None) + err.start_column = getattr(e, "start_column", None) + raise err raise HyCompileError("Unknown type - `%s'" % (str(type(tree)))) @@ -100,10 +139,12 @@ class HyASTCompiler(object): @builds("do") @builds("progn") + @checkargs(min=1) def compile_do_expression(self, expr): return [self.compile(x) for x in expr[1:]] @builds("throw") + @checkargs(min=1) def compile_throw_expression(self, expr): expr.pop(0) exc = self.compile(expr.pop(0)) @@ -116,6 +157,7 @@ class HyASTCompiler(object): tback=None) @builds("try") + @checkargs(min=1) def compile_try_expression(self, expr): expr.pop(0) # try @@ -134,6 +176,7 @@ class HyASTCompiler(object): orelse=[]) @builds("catch") + @checkargs(min=2) def compile_catch_expression(self, expr): expr.pop(0) # catch _type = self.compile(expr.pop(0)) @@ -163,25 +206,16 @@ class HyASTCompiler(object): return self._mangle_branch([branch]) @builds("if") + @checkargs(min=2, max=3) def compile_if_expression(self, expr): - expr.pop(0) - try: - test = expr.pop(0) - except IndexError: - raise TypeError("if expects at least 2 arguments, got 0") - test = self.compile(test) - try: - body = expr.pop(0) - except IndexError: - raise TypeError("if expects at least 2 arguments, got 1") - body = self._code_branch(self.compile(body)) - orel = [] + expr.pop(0) # if + test = self.compile(expr.pop(0)) + body = self._code_branch(self.compile(expr.pop(0))) if len(expr) == 1: orel = self._code_branch(self.compile(expr.pop(0))) - elif len(expr) > 1: - raise TypeError("if expects 2 or 3 arguments, got %d" % ( - len(expr) + 2)) + else: + orel = [] return ast.If(test=test, body=body, @@ -210,6 +244,7 @@ class HyASTCompiler(object): nl=True) @builds("assert") + @checkargs(1) def compile_assert_expression(self, expr): expr.pop(0) # assert e = expr.pop(0) @@ -219,6 +254,7 @@ class HyASTCompiler(object): col_offset=e.start_column) @builds("lambda") + @checkargs(min=2) def compile_lambda_expression(self, expr): expr.pop(0) sig = expr.pop(0) @@ -241,10 +277,12 @@ class HyASTCompiler(object): body=self.compile(body)) @builds("pass") + @checkargs(0) def compile_pass_expression(self, expr): return ast.Pass(lineno=expr.start_line, col_offset=expr.start_column) @builds("yield") + @checkargs(1) def compile_yield_expression(self, expr): expr.pop(0) return ast.Yield( @@ -272,6 +310,7 @@ class HyASTCompiler(object): asname=str(x[1])) for x in modlist]) @builds("import_from") + @checkargs(min=1) def compile_import_from_expression(self, expr): expr.pop(0) # index return ast.ImportFrom( @@ -282,6 +321,7 @@ class HyASTCompiler(object): level=0) @builds("get") + @checkargs(2) def compile_index_expression(self, expr): expr.pop(0) # index val = self.compile(expr.pop(0)) # target @@ -295,6 +335,7 @@ class HyASTCompiler(object): ctx=ast.Load()) @builds("slice") + @checkargs(min=1, max=3) def compile_slice_expression(self, expr): expr.pop(0) # index val = self.compile(expr.pop(0)) # target @@ -317,6 +358,7 @@ class HyASTCompiler(object): ctx=ast.Load()) @builds("assoc") + @checkargs(3) def compile_assoc_expression(self, expr): expr.pop(0) # assoc # (assoc foo bar baz) => foo[bar] = baz @@ -337,6 +379,7 @@ class HyASTCompiler(object): value=self.compile(val)) @builds("decorate_with") + @checkargs(min=1) def compile_decorate_expression(self, expr): expr.pop(0) # decorate-with fn = self.compile(expr.pop(-1)) @@ -346,6 +389,7 @@ class HyASTCompiler(object): return fn @builds("with_as") + @checkargs(min=2) def compile_with_as_expression(self, expr): expr.pop(0) # with-as ctx = self.compile(expr.pop(0)) @@ -372,6 +416,7 @@ class HyASTCompiler(object): ctx=ast.Load()) @builds("list_comp") + @checkargs(min=2, max=3) def compile_list_comprehension(self, expr): # (list-comp expr (target iter) cond?) expr.pop(0) @@ -406,6 +451,7 @@ class HyASTCompiler(object): return name @builds("kwapply") + @checkargs(2) def compile_kwapply_expression(self, expr): expr.pop(0) # kwapply call = self.compile(expr.pop(0)) @@ -421,10 +467,8 @@ class HyASTCompiler(object): @builds("not") @builds("~") + @checkargs(1) def compile_unary_operator(self, expression): - if len(expression) != 2: - raise TypeError("Unary operator expects only 1 argument, got %d" - % (len(expression) - 1)) ops = {"not": ast.Not, "~": ast.Invert} operator = expression.pop(0) @@ -444,6 +488,7 @@ class HyASTCompiler(object): @builds("in") @builds("is_not") @builds("not_in") + @checkargs(min=2) def compile_compare_op_expression(self, expression): ops = {"=": ast.Eq, "!=": ast.NotEq, "<": ast.Lt, "<=": ast.LtE, @@ -467,6 +512,7 @@ class HyASTCompiler(object): @builds("-") @builds("/") @builds("*") + @checkargs(min=2) def compile_maths_expression(self, expression): # operator = Mod | Pow | LShift | RShift | BitOr | # BitXor | BitAnd | FloorDiv @@ -535,6 +581,7 @@ class HyASTCompiler(object): @builds("def") @builds("setf") @builds("setv") + @checkargs(2) def compile_def_expression(self, expression): expression.pop(0) # "def" name = expression.pop(0) @@ -556,6 +603,7 @@ class HyASTCompiler(object): targets=[name], value=what) @builds("foreach") + @checkargs(min=1) def compile_for_expression(self, expression): ret_status = self.returnable self.returnable = False @@ -579,17 +627,10 @@ class HyASTCompiler(object): return ret @builds("while") + @checkargs(min=2) def compile_while_expression(self, expr): expr.pop(0) # "while" - - try: - test = expr.pop(0) - except IndexError: - raise TypeError("while expects at least 2 arguments, got 0") - test = self.compile(test) - - if not expr: - raise TypeError("while expects a body") + test = self.compile(expr.pop(0)) return ast.While(test=test, body=self._mangle_branch([ @@ -607,6 +648,7 @@ class HyASTCompiler(object): col_offset=expr.start_column) @builds("fn") + @checkargs(min=2) def compile_fn_expression(self, expression): expression.pop(0) # fn diff --git a/hy/importer.py b/hy/importer.py index 1569d38..21b6d74 100644 --- a/hy/importer.py +++ b/hy/importer.py @@ -48,7 +48,13 @@ def import_file_to_hst(fpath): def import_file_to_ast(fpath): tree = import_file_to_hst(fpath) - ast = hy_compile(tree) + try: + ast = hy_compile(tree) + except Exception as e: + print("Compilation error at %s:%d,%d" + % (fpath, e.start_line, e.start_column)) + print("Compilation error: " + e.message) + raise e.exception return ast diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 5f03672..23368aa 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -38,7 +38,7 @@ def cant_compile(expr): try: hy_compile(tokenize(expr)) assert False - except TypeError: + except HyCompileError: pass @@ -56,7 +56,7 @@ def test_ast_bad_if_0_arg(): try: hy_compile(tokenize("(if)")) assert False - except TypeError: + except HyCompileError: pass @@ -65,7 +65,7 @@ def test_ast_bad_if_1_arg(): try: hy_compile(tokenize("(if foobar)")) assert False - except TypeError: + except HyCompileError: pass @@ -74,7 +74,7 @@ def test_ast_bad_if_too_much_arg(): try: hy_compile(tokenize("(if 1 2 3 4 5)")) assert False - except TypeError: + except HyCompileError: pass @@ -103,7 +103,7 @@ def test_ast_bad_while_0_arg(): try: hy_compile(tokenize("(while)")) assert False - except TypeError: + except HyCompileError: pass @@ -112,10 +112,143 @@ def test_ast_bad_while_1_arg(): try: hy_compile(tokenize("(while (true))")) assert False - except TypeError: + except HyCompileError: pass +def test_ast_good_do(): + "Make sure AST can compile valid do" + hy_compile(tokenize("(do 1)")) + + +def test_ast_bad_do(): + "Make sure AST can't compile invalid do" + cant_compile("(do)") + + +def test_ast_good_throw(): + "Make sure AST can compile valid throw" + hy_compile(tokenize("(throw 1)")) + + +def test_ast_bad_throw(): + "Make sure AST can't compile invalid throw" + cant_compile("(throw)") + + +def test_ast_good_try(): + "Make sure AST can compile valid try" + hy_compile(tokenize("(try 1)")) + + +def test_ast_bad_try(): + "Make sure AST can't compile invalid try" + cant_compile("(try)") + + +def test_ast_good_catch(): + "Make sure AST can compile valid catch" + hy_compile(tokenize("(catch 1 2)")) + + +def test_ast_bad_catch(): + "Make sure AST can't compile invalid catch" + cant_compile("(catch)") + cant_compile("(catch 1)") + + +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_valid_while(): "Make sure AST can't compile invalid while" hy_compile(tokenize("(while foo bar)")) @@ -151,7 +284,7 @@ def test_ast_non_decoratable(): try: hy_compile(tokenize("(decorate-with (foo) (* x x))")) assert True is False - except TypeError: + except HyCompileError: pass @@ -162,7 +295,7 @@ def test_ast_non_kwapplyable(): try: hy_compile(code) assert True is False - except TypeError: + except HyCompileError: pass diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 1db6def..2f539ec 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -119,7 +119,7 @@ (defn test-index [] "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))) From 914011175fbf2c021afc3aeb2eb2580d15192b94 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 13:15:32 -0400 Subject: [PATCH 057/114] Style fixes --- hy/compiler.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 20eb094..c718128 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -67,14 +67,14 @@ def checkargs(exact=None, min=None, max=None): 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) + _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) + _raise_wrong_args_number( + expression, + "`%%s' needs at most %d arguments, got %%d" % (max)) return fn(self, expression) From ae7d2ee84565eff97fec6b4dff9e1638e5fa396e Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sat, 6 Apr 2013 21:15:23 +0200 Subject: [PATCH 058/114] Add flake8 in tox Signed-off-by: Julien Danjou --- tox.ini | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index bfb0641..1cf91e8 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,11 @@ [tox] -envlist = py27,pypy,py32,py33,py26 +envlist = py27,pypy,py32,py33,py26,flake8 [testenv] commands = nosetests deps = nose setuptools + +[testenv:flake8] +deps = flake8 +commands = flake8 hy bin tests From 78133500cbbf0da07d403af814ff97948d86f4ee Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sat, 6 Apr 2013 21:22:35 +0200 Subject: [PATCH 059/114] Fix flake8 errors in tests Signed-off-by: Julien Danjou --- tests/__init__.py | 6 +++--- tests/compilers/test_ast.py | 22 +++++++++++----------- tests/importer/test_importer.py | 4 ++-- tests/lex/test_lex.py | 4 ++-- tests/macros/test_macro_processor.py | 2 -- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/tests/__init__.py b/tests/__init__.py index 8b85ff7..efc173a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,6 +1,6 @@ # -import hy -from .native_tests.math import * -from .native_tests.language import * +import hy # noqa +from .native_tests.math import * # noqa +from .native_tests.language import * # noqa diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 23368aa..59d976c 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -258,17 +258,17 @@ def test_ast_expression_basics(): """ Ensure basic AST expression conversion works. """ code = hy_compile(tokenize("(foo bar)")).body[0] tree = ast.Expr(value=ast.Call( - func=ast.Name( - id="foo", - ctx=ast.Load(), - ), - args=[ - ast.Name(id="bar", ctx=ast.Load()) - ], - keywords=[], - starargs=None, - kwargs=None, - )) + func=ast.Name( + id="foo", + ctx=ast.Load(), + ), + args=[ + ast.Name(id="bar", ctx=ast.Load()) + ], + keywords=[], + starargs=None, + kwargs=None, + )) _ast_spotcheck("value.func.id", code, tree) diff --git a/tests/importer/test_importer.py b/tests/importer/test_importer.py index a63c071..ce5627c 100644 --- a/tests/importer/test_importer.py +++ b/tests/importer/test_importer.py @@ -4,8 +4,8 @@ import ast def test_basics(): "Make sure the basics of the importer work" - module = import_file_to_module("basic", - "tests/resources/importer/basic.hy") + import_file_to_module("basic", + "tests/resources/importer/basic.hy") def test_stringer(): diff --git a/tests/lex/test_lex.py b/tests/lex/test_lex.py index 7740fed..d3b3706 100644 --- a/tests/lex/test_lex.py +++ b/tests/lex/test_lex.py @@ -32,13 +32,13 @@ from hy.lex import tokenize def test_lex_exception(): """ Ensure tokenize throws a fit on a partial input """ try: - objs = tokenize("(foo") + tokenize("(foo") assert True is False except LexException: pass try: - objs = tokenize("&foo&") + tokenize("&foo&") assert True is False except LexException: pass diff --git a/tests/macros/test_macro_processor.py b/tests/macros/test_macro_processor.py index dd457d3..d9d7144 100644 --- a/tests/macros/test_macro_processor.py +++ b/tests/macros/test_macro_processor.py @@ -2,9 +2,7 @@ from hy.macros import macro, process from hy.lex import tokenize -from hy.models.expression import HyExpression from hy.models.string import HyString -from hy.models.symbol import HySymbol from hy.models.list import HyList From 123339bfcf6fbc62be736b0d70c88208b32e1755 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sat, 6 Apr 2013 21:28:12 +0200 Subject: [PATCH 060/114] tests: simplify not compiling tests Signed-off-by: Julien Danjou --- tests/compilers/test_ast.py | 52 ++++++------------------------------- 1 file changed, 8 insertions(+), 44 deletions(-) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 59d976c..6b59ee3 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -51,31 +51,11 @@ def test_ast_bad_type(): pass -def test_ast_bad_if_0_arg(): +def test_ast_bad_if(): "Make sure AST can't compile invalid if" - try: - hy_compile(tokenize("(if)")) - assert False - except HyCompileError: - pass - - -def test_ast_bad_if_1_arg(): - "Make sure AST can't compile invalid if" - try: - hy_compile(tokenize("(if foobar)")) - assert False - except HyCompileError: - pass - - -def test_ast_bad_if_too_much_arg(): - "Make sure AST can't compile invalid if" - try: - hy_compile(tokenize("(if 1 2 3 4 5)")) - assert False - except HyCompileError: - pass + cant_compile("(if)") + cant_compile("(if foobar)") + cant_compile("(if 1 2 3 4 5)") def test_ast_valid_if(): @@ -98,22 +78,10 @@ def test_ast_invalid_unary_op(): cant_compile("(~)") -def test_ast_bad_while_0_arg(): +def test_ast_bad_while(): "Make sure AST can't compile invalid while" - try: - hy_compile(tokenize("(while)")) - assert False - except HyCompileError: - pass - - -def test_ast_bad_while_1_arg(): - "Make sure AST can't compile invalid while" - try: - hy_compile(tokenize("(while (true))")) - assert False - except HyCompileError: - pass + cant_compile("(while)") + cant_compile("(while (true))") def test_ast_good_do(): @@ -281,11 +249,7 @@ def test_ast_anon_fns_basics(): def test_ast_non_decoratable(): """ Ensure decorating garbage breaks """ - try: - hy_compile(tokenize("(decorate-with (foo) (* x x))")) - assert True is False - except HyCompileError: - pass + cant_compile("(decorate-with (foo) (* x x))") def test_ast_non_kwapplyable(): From 8b144a4f3dd815abbc29b2bdb18eb619ecd25ec7 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Fri, 5 Apr 2013 17:20:12 +0200 Subject: [PATCH 061/114] Make HySymbol bytes free! We can know use any amount and type of bytes to build a HyString, meaning we can use Unicode and UTF-8 for our function and variables. Eat that, snake! Signed-off-by: Julien Danjou --- hy/compiler.py | 94 +++++++++++++++++----------------- hy/contrib/meth.py | 2 +- hy/core/bootstrap.py | 2 +- hy/core/mangles.py | 2 +- hy/importer.py | 3 +- hy/lex/states.py | 11 +--- hy/macros.py | 3 +- hy/models/symbol.py | 14 ++++- tests/native_tests/language.hy | 15 ++++++ 9 files changed, 82 insertions(+), 64 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index c718128..394fd13 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -137,13 +137,13 @@ class HyASTCompiler(object): def compile_raw_list(self, entries): return [self.compile(x) for x in entries] - @builds("do") - @builds("progn") + @builds(HySymbol("do")) + @builds(HySymbol("progn")) @checkargs(min=1) def compile_do_expression(self, expr): return [self.compile(x) for x in expr[1:]] - @builds("throw") + @builds(HySymbol("throw")) @checkargs(min=1) def compile_throw_expression(self, expr): expr.pop(0) @@ -156,7 +156,7 @@ class HyASTCompiler(object): inst=None, tback=None) - @builds("try") + @builds(HySymbol("try")) @checkargs(min=1) def compile_try_expression(self, expr): expr.pop(0) # try @@ -175,7 +175,7 @@ class HyASTCompiler(object): finalbody=[], orelse=[]) - @builds("catch") + @builds(HySymbol("catch")) @checkargs(min=2) def compile_catch_expression(self, expr): expr.pop(0) # catch @@ -205,7 +205,7 @@ class HyASTCompiler(object): return self._mangle_branch(branch) return self._mangle_branch([branch]) - @builds("if") + @builds(HySymbol("if")) @checkargs(min=2, max=3) def compile_if_expression(self, expr): expr.pop(0) # if @@ -223,7 +223,7 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column) - @builds("print") + @builds(HySymbol("print")) def compile_print_expression(self, expr): call = expr.pop(0) # print if sys.version_info[0] >= 3: @@ -243,7 +243,7 @@ class HyASTCompiler(object): values=[self.compile(x) for x in expr], nl=True) - @builds("assert") + @builds(HySymbol("assert")) @checkargs(1) def compile_assert_expression(self, expr): expr.pop(0) # assert @@ -253,7 +253,7 @@ class HyASTCompiler(object): lineno=e.start_line, col_offset=e.start_column) - @builds("lambda") + @builds(HySymbol("lambda")) @checkargs(min=2) def compile_lambda_expression(self, expr): expr.pop(0) @@ -276,12 +276,12 @@ class HyASTCompiler(object): kw_defaults=[]), body=self.compile(body)) - @builds("pass") + @builds(HySymbol("pass")) @checkargs(0) def compile_pass_expression(self, expr): return ast.Pass(lineno=expr.start_line, col_offset=expr.start_column) - @builds("yield") + @builds(HySymbol("yield")) @checkargs(1) def compile_yield_expression(self, expr): expr.pop(0) @@ -290,7 +290,7 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column) - @builds("import") + @builds(HySymbol("import")) def compile_import_expression(self, expr): expr.pop(0) # index return ast.Import( @@ -298,7 +298,7 @@ class HyASTCompiler(object): col_offset=expr.start_column, names=[ast.alias(name=str(x), asname=None) for x in expr]) - @builds("import_as") + @builds(HySymbol("import-as")) def compile_import_as_expression(self, expr): expr.pop(0) # index modlist = [expr[i:i + 2] for i in range(0, len(expr), 2)] @@ -309,7 +309,7 @@ class HyASTCompiler(object): names=[ast.alias(name=str(x[0]), asname=str(x[1])) for x in modlist]) - @builds("import_from") + @builds(HySymbol("import-from")) @checkargs(min=1) def compile_import_from_expression(self, expr): expr.pop(0) # index @@ -320,7 +320,7 @@ class HyASTCompiler(object): names=[ast.alias(name=str(x), asname=None) for x in expr], level=0) - @builds("get") + @builds(HySymbol("get")) @checkargs(2) def compile_index_expression(self, expr): expr.pop(0) # index @@ -334,7 +334,7 @@ class HyASTCompiler(object): slice=ast.Index(value=sli), ctx=ast.Load()) - @builds("slice") + @builds(HySymbol("slice")) @checkargs(min=1, max=3) def compile_slice_expression(self, expr): expr.pop(0) # index @@ -357,7 +357,7 @@ class HyASTCompiler(object): step=None), ctx=ast.Load()) - @builds("assoc") + @builds(HySymbol("assoc")) @checkargs(3) def compile_assoc_expression(self, expr): expr.pop(0) # assoc @@ -378,7 +378,7 @@ class HyASTCompiler(object): ctx=ast.Store())], value=self.compile(val)) - @builds("decorate_with") + @builds(HySymbol("decorate-with")) @checkargs(min=1) def compile_decorate_expression(self, expr): expr.pop(0) # decorate-with @@ -388,7 +388,7 @@ class HyASTCompiler(object): fn.decorator_list = [self.compile(x) for x in expr] return fn - @builds("with_as") + @builds(HySymbol("with-as")) @checkargs(min=2) def compile_with_as_expression(self, expr): expr.pop(0) # with-as @@ -407,7 +407,7 @@ class HyASTCompiler(object): return ret - @builds(",") + @builds(HySymbol(",")) def compile_tuple(self, expr): expr.pop(0) return ast.Tuple(elts=[self.compile(x) for x in expr], @@ -415,7 +415,7 @@ class HyASTCompiler(object): col_offset=expr.start_column, ctx=ast.Load()) - @builds("list_comp") + @builds(HySymbol("list-comp")) @checkargs(min=2, max=3) def compile_list_comprehension(self, expr): # (list-comp expr (target iter) cond?) @@ -450,7 +450,7 @@ class HyASTCompiler(object): name.ctx = ast.Store() return name - @builds("kwapply") + @builds(HySymbol("kwapply")) @checkargs(2) def compile_kwapply_expression(self, expr): expr.pop(0) # kwapply @@ -465,8 +465,8 @@ class HyASTCompiler(object): return call - @builds("not") - @builds("~") + @builds(HySymbol("not")) + @builds(HySymbol("~")) @checkargs(1) def compile_unary_operator(self, expression): ops = {"not": ast.Not, @@ -478,23 +478,23 @@ class HyASTCompiler(object): lineno=operator.start_line, col_offset=operator.start_column) - @builds("=") - @builds("!=") - @builds("<") - @builds("<=") - @builds(">") - @builds(">=") - @builds("is") - @builds("in") - @builds("is_not") - @builds("not_in") + @builds(HySymbol("=")) + @builds(HySymbol("!=")) + @builds(HySymbol("<")) + @builds(HySymbol("<=")) + @builds(HySymbol(">")) + @builds(HySymbol(">=")) + @builds(HySymbol("is")) + @builds(HySymbol("in")) + @builds(HySymbol("is-not")) + @builds(HySymbol("not-in")) @checkargs(min=2) def compile_compare_op_expression(self, expression): ops = {"=": ast.Eq, "!=": ast.NotEq, "<": ast.Lt, "<=": ast.LtE, ">": ast.Gt, ">=": ast.GtE, - "is": ast.Is, "is_not": ast.IsNot, - "in": ast.In, "not_in": ast.NotIn} + "is": ast.Is, "is-not": ast.IsNot, + "in": ast.In, "not-in": ast.NotIn} inv = expression.pop(0) op = ops[inv] @@ -507,11 +507,11 @@ class HyASTCompiler(object): lineno=e.start_line, col_offset=e.start_column) - @builds("+") - @builds("%") - @builds("-") - @builds("/") - @builds("*") + @builds(HySymbol("+")) + @builds(HySymbol("%")) + @builds(HySymbol("-")) + @builds(HySymbol("/")) + @builds(HySymbol("*")) @checkargs(min=2) def compile_maths_expression(self, expression): # operator = Mod | Pow | LShift | RShift | BitOr | @@ -578,9 +578,9 @@ class HyASTCompiler(object): lineno=expression.start_line, col_offset=expression.start_column) - @builds("def") - @builds("setf") - @builds("setv") + @builds(HySymbol("def")) + @builds(HySymbol("setf")) + @builds(HySymbol("setv")) @checkargs(2) def compile_def_expression(self, expression): expression.pop(0) # "def" @@ -602,7 +602,7 @@ class HyASTCompiler(object): col_offset=expression.start_column, targets=[name], value=what) - @builds("foreach") + @builds(HySymbol("foreach")) @checkargs(min=1) def compile_for_expression(self, expression): ret_status = self.returnable @@ -626,7 +626,7 @@ class HyASTCompiler(object): self.returnable = ret_status return ret - @builds("while") + @builds(HySymbol("while")) @checkargs(min=2) def compile_while_expression(self, expr): expr.pop(0) # "while" @@ -647,7 +647,7 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column) - @builds("fn") + @builds(HySymbol("fn")) @checkargs(min=2) def compile_fn_expression(self, expression): expression.pop(0) # fn diff --git a/hy/contrib/meth.py b/hy/contrib/meth.py index 4f64863..3dc59a8 100644 --- a/hy/contrib/meth.py +++ b/hy/contrib/meth.py @@ -40,7 +40,7 @@ def router(tree, rkwargs=None): route = HyExpression([HySymbol("kwapply"), route, HyDict({HyString("methods"): rkwargs})]) - return HyExpression([HySymbol("decorate_with"), route, tree]) + return HyExpression([HySymbol("decorate-with"), route, tree]) @macro("route") diff --git a/hy/core/bootstrap.py b/hy/core/bootstrap.py index e77fb02..7442149 100644 --- a/hy/core/bootstrap.py +++ b/hy/core/bootstrap.py @@ -80,7 +80,7 @@ def for_macro(tree): return root -@macro("_>") +@macro("->") def threading_macro(tree): tree.pop(0) ret = tree.pop(0) diff --git a/hy/core/mangles.py b/hy/core/mangles.py index 69744ec..c82728c 100644 --- a/hy/core/mangles.py +++ b/hy/core/mangles.py @@ -41,7 +41,7 @@ class HoistableMangle(hy.mangle.Mangle): class FunctionMangle(HoistableMangle): hoistable = ["fn"] - ignore = ["def", "decorate_with", "setf", "setv"] + ignore = ["def", "decorate-with", "setf", "setv"] def __init__(self): self.series = 0 diff --git a/hy/importer.py b/hy/importer.py index 21b6d74..11aa653 100644 --- a/hy/importer.py +++ b/hy/importer.py @@ -24,6 +24,7 @@ from hy.core import process from py_compile import wr_long, MAGIC +import io import marshal import imp import sys @@ -43,7 +44,7 @@ def import_buffer_to_hst(fd): def import_file_to_hst(fpath): - return import_buffer_to_hst(open(fpath, 'r')) + return import_buffer_to_hst(io.open(fpath, 'rU', encoding='utf-8')) def import_file_to_ast(fpath): diff --git a/hy/lex/states.py b/hy/lex/states.py index 72caba6..677cb3b 100644 --- a/hy/lex/states.py +++ b/hy/lex/states.py @@ -58,16 +58,7 @@ def _resolve_atom(obj): "null": "None", } - if obj in table: - return HySymbol(table[obj]) - - if obj.startswith("*") and obj.endswith("*") and obj != "*": - obj = obj[1:-1].upper() - - if "-" in obj and obj != "-": - obj = obj.replace("-", "_") - - return HySymbol(obj) + return HySymbol(table.get(obj, obj)) class State(object): diff --git a/hy/macros.py b/hy/macros.py index 3eda0c7..8eb0f7c 100644 --- a/hy/macros.py +++ b/hy/macros.py @@ -22,13 +22,14 @@ from hy.models.expression import HyExpression from hy.models.string import HyString from hy.models.dict import HyDict from hy.models.list import HyList +from hy.models.symbol import HySymbol _hy_macros = {} def macro(name): def _(fn): - _hy_macros[name] = fn + _hy_macros[HySymbol(name)] = fn return fn return _ diff --git a/hy/models/symbol.py b/hy/models/symbol.py index 7a1685c..a6ccb87 100644 --- a/hy/models/symbol.py +++ b/hy/models/symbol.py @@ -1,4 +1,5 @@ # Copyright (c) 2013 Paul Tagliamonte +# Copyright (c) 2013 Julien Danjou # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -18,6 +19,8 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. +import base64 + from hy.models.string import HyString @@ -25,6 +28,13 @@ class HySymbol(HyString): """ Hy Symbol. Basically a String. """ + def encode_symbol(self): + return ("_hy_symbol_" + + base64.b64encode( + self.encode( + 'unicode-escape')).decode('ascii')) - def __init__(self, string): - self += string + def __str__(self): + if all([(c.isalnum() or c == "_" or c == ".") for c in self]): + return super(HyString, self).__str__() + return self.encode_symbol() diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 2f539ec..27069b6 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -160,6 +160,21 @@ (assert (= (.join " " ["one" "two"]) "one two"))) +(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-exceptions [] "NATIVE: test Exceptions" (try From 801c4e0099035bc44a70375b02017e935461daef Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sat, 6 Apr 2013 23:40:21 +0200 Subject: [PATCH 062/114] Remove useless code This seems to have no purpose to me. Signed-off-by: Julien Danjou --- hy/models/string.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hy/models/string.py b/hy/models/string.py index ec64504..8e6f82e 100644 --- a/hy/models/string.py +++ b/hy/models/string.py @@ -34,7 +34,3 @@ class HyString(HyObject, _str_type): scripts. It's either a ``str`` or a ``unicode``, depending on the Python version. """ - - def __new__(cls, value): - obj = _str_type.__new__(cls, value) - return obj From 104b9d1636e3400df11528f14a1b5962097dc64c Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 19:57:59 -0400 Subject: [PATCH 063/114] adding this as testable --- tests/native_tests/language.hy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 27069b6..fa1c8b1 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -141,7 +141,7 @@ (decorate-with foodec - (defn tfunction [] + (defn test-decorator-function [] (* 2 2))) From 262da59c7790cdadd60ea9612bc9e3c1616863fd Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 20:01:55 -0400 Subject: [PATCH 064/114] Revert "Remove useless code" This reverts commit 801c4e0099035bc44a70375b02017e935461daef. --- hy/models/string.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hy/models/string.py b/hy/models/string.py index 8e6f82e..ec64504 100644 --- a/hy/models/string.py +++ b/hy/models/string.py @@ -34,3 +34,7 @@ class HyString(HyObject, _str_type): scripts. It's either a ``str`` or a ``unicode``, depending on the Python version. """ + + def __new__(cls, value): + obj = _str_type.__new__(cls, value) + return obj From e0ed7cac4009b6bdf542f7d8593310af1c19ebd4 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 20:02:08 -0400 Subject: [PATCH 065/114] Revert "Make HySymbol bytes free!" This reverts commit 8b144a4f3dd815abbc29b2bdb18eb619ecd25ec7. --- hy/compiler.py | 94 +++++++++++++++++----------------- hy/contrib/meth.py | 2 +- hy/core/bootstrap.py | 2 +- hy/core/mangles.py | 2 +- hy/importer.py | 3 +- hy/lex/states.py | 11 +++- hy/macros.py | 3 +- hy/models/symbol.py | 14 +---- tests/native_tests/language.hy | 15 ------ 9 files changed, 64 insertions(+), 82 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 394fd13..c718128 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -137,13 +137,13 @@ class HyASTCompiler(object): def compile_raw_list(self, entries): return [self.compile(x) for x in entries] - @builds(HySymbol("do")) - @builds(HySymbol("progn")) + @builds("do") + @builds("progn") @checkargs(min=1) def compile_do_expression(self, expr): return [self.compile(x) for x in expr[1:]] - @builds(HySymbol("throw")) + @builds("throw") @checkargs(min=1) def compile_throw_expression(self, expr): expr.pop(0) @@ -156,7 +156,7 @@ class HyASTCompiler(object): inst=None, tback=None) - @builds(HySymbol("try")) + @builds("try") @checkargs(min=1) def compile_try_expression(self, expr): expr.pop(0) # try @@ -175,7 +175,7 @@ class HyASTCompiler(object): finalbody=[], orelse=[]) - @builds(HySymbol("catch")) + @builds("catch") @checkargs(min=2) def compile_catch_expression(self, expr): expr.pop(0) # catch @@ -205,7 +205,7 @@ class HyASTCompiler(object): return self._mangle_branch(branch) return self._mangle_branch([branch]) - @builds(HySymbol("if")) + @builds("if") @checkargs(min=2, max=3) def compile_if_expression(self, expr): expr.pop(0) # if @@ -223,7 +223,7 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column) - @builds(HySymbol("print")) + @builds("print") def compile_print_expression(self, expr): call = expr.pop(0) # print if sys.version_info[0] >= 3: @@ -243,7 +243,7 @@ class HyASTCompiler(object): values=[self.compile(x) for x in expr], nl=True) - @builds(HySymbol("assert")) + @builds("assert") @checkargs(1) def compile_assert_expression(self, expr): expr.pop(0) # assert @@ -253,7 +253,7 @@ class HyASTCompiler(object): lineno=e.start_line, col_offset=e.start_column) - @builds(HySymbol("lambda")) + @builds("lambda") @checkargs(min=2) def compile_lambda_expression(self, expr): expr.pop(0) @@ -276,12 +276,12 @@ class HyASTCompiler(object): kw_defaults=[]), body=self.compile(body)) - @builds(HySymbol("pass")) + @builds("pass") @checkargs(0) def compile_pass_expression(self, expr): return ast.Pass(lineno=expr.start_line, col_offset=expr.start_column) - @builds(HySymbol("yield")) + @builds("yield") @checkargs(1) def compile_yield_expression(self, expr): expr.pop(0) @@ -290,7 +290,7 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column) - @builds(HySymbol("import")) + @builds("import") def compile_import_expression(self, expr): expr.pop(0) # index return ast.Import( @@ -298,7 +298,7 @@ class HyASTCompiler(object): col_offset=expr.start_column, names=[ast.alias(name=str(x), asname=None) for x in expr]) - @builds(HySymbol("import-as")) + @builds("import_as") def compile_import_as_expression(self, expr): expr.pop(0) # index modlist = [expr[i:i + 2] for i in range(0, len(expr), 2)] @@ -309,7 +309,7 @@ class HyASTCompiler(object): names=[ast.alias(name=str(x[0]), asname=str(x[1])) for x in modlist]) - @builds(HySymbol("import-from")) + @builds("import_from") @checkargs(min=1) def compile_import_from_expression(self, expr): expr.pop(0) # index @@ -320,7 +320,7 @@ class HyASTCompiler(object): names=[ast.alias(name=str(x), asname=None) for x in expr], level=0) - @builds(HySymbol("get")) + @builds("get") @checkargs(2) def compile_index_expression(self, expr): expr.pop(0) # index @@ -334,7 +334,7 @@ class HyASTCompiler(object): slice=ast.Index(value=sli), ctx=ast.Load()) - @builds(HySymbol("slice")) + @builds("slice") @checkargs(min=1, max=3) def compile_slice_expression(self, expr): expr.pop(0) # index @@ -357,7 +357,7 @@ class HyASTCompiler(object): step=None), ctx=ast.Load()) - @builds(HySymbol("assoc")) + @builds("assoc") @checkargs(3) def compile_assoc_expression(self, expr): expr.pop(0) # assoc @@ -378,7 +378,7 @@ class HyASTCompiler(object): ctx=ast.Store())], value=self.compile(val)) - @builds(HySymbol("decorate-with")) + @builds("decorate_with") @checkargs(min=1) def compile_decorate_expression(self, expr): expr.pop(0) # decorate-with @@ -388,7 +388,7 @@ class HyASTCompiler(object): fn.decorator_list = [self.compile(x) for x in expr] return fn - @builds(HySymbol("with-as")) + @builds("with_as") @checkargs(min=2) def compile_with_as_expression(self, expr): expr.pop(0) # with-as @@ -407,7 +407,7 @@ class HyASTCompiler(object): return ret - @builds(HySymbol(",")) + @builds(",") def compile_tuple(self, expr): expr.pop(0) return ast.Tuple(elts=[self.compile(x) for x in expr], @@ -415,7 +415,7 @@ class HyASTCompiler(object): col_offset=expr.start_column, ctx=ast.Load()) - @builds(HySymbol("list-comp")) + @builds("list_comp") @checkargs(min=2, max=3) def compile_list_comprehension(self, expr): # (list-comp expr (target iter) cond?) @@ -450,7 +450,7 @@ class HyASTCompiler(object): name.ctx = ast.Store() return name - @builds(HySymbol("kwapply")) + @builds("kwapply") @checkargs(2) def compile_kwapply_expression(self, expr): expr.pop(0) # kwapply @@ -465,8 +465,8 @@ class HyASTCompiler(object): return call - @builds(HySymbol("not")) - @builds(HySymbol("~")) + @builds("not") + @builds("~") @checkargs(1) def compile_unary_operator(self, expression): ops = {"not": ast.Not, @@ -478,23 +478,23 @@ class HyASTCompiler(object): lineno=operator.start_line, col_offset=operator.start_column) - @builds(HySymbol("=")) - @builds(HySymbol("!=")) - @builds(HySymbol("<")) - @builds(HySymbol("<=")) - @builds(HySymbol(">")) - @builds(HySymbol(">=")) - @builds(HySymbol("is")) - @builds(HySymbol("in")) - @builds(HySymbol("is-not")) - @builds(HySymbol("not-in")) + @builds("=") + @builds("!=") + @builds("<") + @builds("<=") + @builds(">") + @builds(">=") + @builds("is") + @builds("in") + @builds("is_not") + @builds("not_in") @checkargs(min=2) def compile_compare_op_expression(self, expression): ops = {"=": ast.Eq, "!=": ast.NotEq, "<": ast.Lt, "<=": ast.LtE, ">": ast.Gt, ">=": ast.GtE, - "is": ast.Is, "is-not": ast.IsNot, - "in": ast.In, "not-in": ast.NotIn} + "is": ast.Is, "is_not": ast.IsNot, + "in": ast.In, "not_in": ast.NotIn} inv = expression.pop(0) op = ops[inv] @@ -507,11 +507,11 @@ class HyASTCompiler(object): lineno=e.start_line, col_offset=e.start_column) - @builds(HySymbol("+")) - @builds(HySymbol("%")) - @builds(HySymbol("-")) - @builds(HySymbol("/")) - @builds(HySymbol("*")) + @builds("+") + @builds("%") + @builds("-") + @builds("/") + @builds("*") @checkargs(min=2) def compile_maths_expression(self, expression): # operator = Mod | Pow | LShift | RShift | BitOr | @@ -578,9 +578,9 @@ class HyASTCompiler(object): lineno=expression.start_line, col_offset=expression.start_column) - @builds(HySymbol("def")) - @builds(HySymbol("setf")) - @builds(HySymbol("setv")) + @builds("def") + @builds("setf") + @builds("setv") @checkargs(2) def compile_def_expression(self, expression): expression.pop(0) # "def" @@ -602,7 +602,7 @@ class HyASTCompiler(object): col_offset=expression.start_column, targets=[name], value=what) - @builds(HySymbol("foreach")) + @builds("foreach") @checkargs(min=1) def compile_for_expression(self, expression): ret_status = self.returnable @@ -626,7 +626,7 @@ class HyASTCompiler(object): self.returnable = ret_status return ret - @builds(HySymbol("while")) + @builds("while") @checkargs(min=2) def compile_while_expression(self, expr): expr.pop(0) # "while" @@ -647,7 +647,7 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column) - @builds(HySymbol("fn")) + @builds("fn") @checkargs(min=2) def compile_fn_expression(self, expression): expression.pop(0) # fn diff --git a/hy/contrib/meth.py b/hy/contrib/meth.py index 3dc59a8..4f64863 100644 --- a/hy/contrib/meth.py +++ b/hy/contrib/meth.py @@ -40,7 +40,7 @@ def router(tree, rkwargs=None): route = HyExpression([HySymbol("kwapply"), route, HyDict({HyString("methods"): rkwargs})]) - return HyExpression([HySymbol("decorate-with"), route, tree]) + return HyExpression([HySymbol("decorate_with"), route, tree]) @macro("route") diff --git a/hy/core/bootstrap.py b/hy/core/bootstrap.py index 7442149..e77fb02 100644 --- a/hy/core/bootstrap.py +++ b/hy/core/bootstrap.py @@ -80,7 +80,7 @@ def for_macro(tree): return root -@macro("->") +@macro("_>") def threading_macro(tree): tree.pop(0) ret = tree.pop(0) diff --git a/hy/core/mangles.py b/hy/core/mangles.py index c82728c..69744ec 100644 --- a/hy/core/mangles.py +++ b/hy/core/mangles.py @@ -41,7 +41,7 @@ class HoistableMangle(hy.mangle.Mangle): class FunctionMangle(HoistableMangle): hoistable = ["fn"] - ignore = ["def", "decorate-with", "setf", "setv"] + ignore = ["def", "decorate_with", "setf", "setv"] def __init__(self): self.series = 0 diff --git a/hy/importer.py b/hy/importer.py index 11aa653..21b6d74 100644 --- a/hy/importer.py +++ b/hy/importer.py @@ -24,7 +24,6 @@ from hy.core import process from py_compile import wr_long, MAGIC -import io import marshal import imp import sys @@ -44,7 +43,7 @@ def import_buffer_to_hst(fd): def import_file_to_hst(fpath): - return import_buffer_to_hst(io.open(fpath, 'rU', encoding='utf-8')) + return import_buffer_to_hst(open(fpath, 'r')) def import_file_to_ast(fpath): diff --git a/hy/lex/states.py b/hy/lex/states.py index 677cb3b..72caba6 100644 --- a/hy/lex/states.py +++ b/hy/lex/states.py @@ -58,7 +58,16 @@ def _resolve_atom(obj): "null": "None", } - return HySymbol(table.get(obj, obj)) + if obj in table: + return HySymbol(table[obj]) + + if obj.startswith("*") and obj.endswith("*") and obj != "*": + obj = obj[1:-1].upper() + + if "-" in obj and obj != "-": + obj = obj.replace("-", "_") + + return HySymbol(obj) class State(object): diff --git a/hy/macros.py b/hy/macros.py index 8eb0f7c..3eda0c7 100644 --- a/hy/macros.py +++ b/hy/macros.py @@ -22,14 +22,13 @@ from hy.models.expression import HyExpression from hy.models.string import HyString from hy.models.dict import HyDict from hy.models.list import HyList -from hy.models.symbol import HySymbol _hy_macros = {} def macro(name): def _(fn): - _hy_macros[HySymbol(name)] = fn + _hy_macros[name] = fn return fn return _ diff --git a/hy/models/symbol.py b/hy/models/symbol.py index a6ccb87..7a1685c 100644 --- a/hy/models/symbol.py +++ b/hy/models/symbol.py @@ -1,5 +1,4 @@ # Copyright (c) 2013 Paul Tagliamonte -# Copyright (c) 2013 Julien Danjou # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -19,8 +18,6 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. -import base64 - from hy.models.string import HyString @@ -28,13 +25,6 @@ class HySymbol(HyString): """ Hy Symbol. Basically a String. """ - def encode_symbol(self): - return ("_hy_symbol_" - + base64.b64encode( - self.encode( - 'unicode-escape')).decode('ascii')) - def __str__(self): - if all([(c.isalnum() or c == "_" or c == ".") for c in self]): - return super(HyString, self).__str__() - return self.encode_symbol() + def __init__(self, string): + self += string diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index fa1c8b1..7742e9d 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -160,21 +160,6 @@ (assert (= (.join " " ["one" "two"]) "one two"))) -(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-exceptions [] "NATIVE: test Exceptions" (try From bac3f6991c65575263f03ac8270417111f2ae2b5 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 20:03:14 -0400 Subject: [PATCH 066/114] Revert "adding this as testable" This reverts commit 104b9d1636e3400df11528f14a1b5962097dc64c. --- tests/native_tests/language.hy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 7742e9d..2f539ec 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -141,7 +141,7 @@ (decorate-with foodec - (defn test-decorator-function [] + (defn tfunction [] (* 2 2))) From 5a9608926660a756c84238825d87dd431b89080b Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 21:33:52 -0400 Subject: [PATCH 067/114] Using backslashes for now; punycode soon. --- hy/compiler.py | 39 ++++++++++++++++++++-------------- hy/importer.py | 15 +++++-------- hy/models/string.py | 8 +++---- tests/native_tests/language.hy | 15 +++++++++++++ 4 files changed, 47 insertions(+), 30 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index c718128..bb3aaed 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -40,6 +40,13 @@ class HyCompileError(HyError): _compile_table = {} +def ast_str(foobar): + if sys.version_info[0] >= 3: + return str(foobar) + + return str(foobar.encode("ascii", 'backslashreplace')) + + def builds(_type): def _dec(fn): _compile_table[_type] = fn @@ -188,7 +195,7 @@ class HyASTCompiler(object): # # We'll just make sure it's a pure "string", and let it work # it's magic. - name = str(name) + name = ast_str(name) else: # Python2 requires an ast.Name, set to ctx Store. name = self._storeize(self.compile(name)) @@ -264,7 +271,7 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column, 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(), lineno=x.start_line, col_offset=x.start_column) @@ -296,7 +303,7 @@ class HyASTCompiler(object): return ast.Import( lineno=expr.start_line, 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") def compile_import_as_expression(self, expr): @@ -305,9 +312,9 @@ class HyASTCompiler(object): return ast.Import( lineno=expr.start_line, col_offset=expr.start_column, - module=str(expr.pop(0)), - names=[ast.alias(name=str(x[0]), - asname=str(x[1])) for x in modlist]) + module=ast_str(expr.pop(0)), + names=[ast.alias(name=ast_str(x[0]), + asname=ast_str(x[1])) for x in modlist]) @builds("import_from") @checkargs(min=1) @@ -316,8 +323,8 @@ class HyASTCompiler(object): return ast.ImportFrom( lineno=expr.start_line, col_offset=expr.start_column, - module=str(expr.pop(0)), - names=[ast.alias(name=str(x), asname=None) for x in expr], + module=ast_str(expr.pop(0)), + names=[ast.alias(name=ast_str(x), asname=None) for x in expr], level=0) @builds("get") @@ -460,7 +467,7 @@ class HyASTCompiler(object): if type(call) != ast.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] return call @@ -551,7 +558,7 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column, value=self.compile(obj), - attr=str(fn), + attr=ast_str(fn), ctx=ast.Load()), args=[self.compile(x) for x in expr], keywords=[], @@ -592,7 +599,7 @@ class HyASTCompiler(object): # We special case a FunctionDef, since we can define by setting # FunctionDef's .name attribute, rather then foo == anon_fn. This # helps keep things clean. - what.name = str(name) + what.name = ast_str(name) return what name = self._storeize(self.compile(name)) @@ -666,7 +673,7 @@ class HyASTCompiler(object): args=ast.arguments( args=[ ast.Name( - arg=str(x), id=str(x), + arg=ast_str(x), id=ast_str(x), ctx=ast.Param(), lineno=x.start_line, col_offset=x.start_column) @@ -700,19 +707,19 @@ class HyASTCompiler(object): lineno=symbol.start_line, col_offset=symbol.start_column, value=self.compile_symbol(glob), - attr=str(local), + attr=ast_str(local), ctx=ast.Load() ) - return ast.Name(id=str(symbol), - arg=str(symbol), + return ast.Name(id=ast_str(symbol), + arg=ast_str(symbol), ctx=ast.Load(), lineno=symbol.start_line, col_offset=symbol.start_column) @builds(HyString) def compile_string(self, string): - return ast.Str(s=str(string), lineno=string.start_line, + return ast.Str(s=ast_str(string), lineno=string.start_line, col_offset=string.start_column) @builds(HyDict) diff --git a/hy/importer.py b/hy/importer.py index 21b6d74..587d536 100644 --- a/hy/importer.py +++ b/hy/importer.py @@ -19,11 +19,12 @@ # DEALINGS IN THE SOFTWARE. from hy.compiler import hy_compile -from hy.lex import tokenize -from hy.core import process from py_compile import wr_long, MAGIC +from hy.core import process +from hy.lex import tokenize +from io import open import marshal import imp import sys @@ -43,18 +44,12 @@ def import_buffer_to_hst(fd): 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): tree = import_file_to_hst(fpath) - try: - ast = hy_compile(tree) - except Exception as e: - print("Compilation error at %s:%d,%d" - % (fpath, e.start_line, e.start_column)) - print("Compilation error: " + e.message) - raise e.exception + ast = hy_compile(tree) return ast diff --git a/hy/models/string.py b/hy/models/string.py index ec64504..b009ba3 100644 --- a/hy/models/string.py +++ b/hy/models/string.py @@ -23,12 +23,12 @@ import sys if sys.version_info[0] >= 3: - _str_type = str + str_type = str 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 scripts. It's either a ``str`` or a ``unicode``, depending on the @@ -36,5 +36,5 @@ class HyString(HyObject, _str_type): """ def __new__(cls, value): - obj = _str_type.__new__(cls, value) + obj = str_type.__new__(cls, value) return obj diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 2f539ec..93cf3b3 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -331,6 +331,21 @@ (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?")))) + + ; FEATURE: native hy-eval ; ; - related to bug #64 From 0429cbea1262e08d3264a182938e603d70592571 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 22:49:48 -0400 Subject: [PATCH 068/114] Using punycode where we can. --- hy/compiler.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index bb3aaed..247319d 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -29,6 +29,7 @@ from hy.models.dict import HyDict from hy.util import flatten_literal_list +import codecs import ast import sys @@ -44,7 +45,14 @@ def ast_str(foobar): if sys.version_info[0] >= 3: return str(foobar) - return str(foobar.encode("ascii", 'backslashreplace')) + try: + return str(foobar) + except UnicodeEncodeError: + pass + + enc = codecs.getencoder('punycode') + foobar, _ = enc(foobar) + return str(foobar).replace("-", "_") def builds(_type): From 03dfbde1b86356fd94e177996271ad46df9bcabf Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 23:11:43 -0400 Subject: [PATCH 069/114] style voodoo --- hy/core/mangles.py | 1 + tests/native_tests/language.hy | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hy/core/mangles.py b/hy/core/mangles.py index 69744ec..4aaf210 100644 --- a/hy/core/mangles.py +++ b/hy/core/mangles.py @@ -80,5 +80,6 @@ class IfMangle(HoistableMangle): fn.replace(tree) return fn + hy.mangle.MANGLES.append(IfMangle) hy.mangle.MANGLES.append(FunctionMangle) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 93cf3b3..8a4c40b 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -2,8 +2,8 @@ (import-from tests.resources kwtest) (import-from os.path exists isdir isfile) -(import sys) (import-as sys systest) +(import sys) (defn test-sys-argv [] From c657def253cd2cff8725a035552c21bc09381d67 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sat, 6 Apr 2013 23:31:26 -0400 Subject: [PATCH 070/114] namespaceing to __hy in case anyone tries this 4real --- hy/compiler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index 247319d..fd31ec8 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -52,7 +52,7 @@ def ast_str(foobar): enc = codecs.getencoder('punycode') foobar, _ = enc(foobar) - return str(foobar).replace("-", "_") + return "__hy_%s" % (str(foobar).replace("-", "_")) def builds(_type): From 2724478f13c0ebb064fc39eda0a9a033303e7f84 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Sun, 7 Apr 2013 07:55:16 -0400 Subject: [PATCH 071/114] Fix clone url in hacking docs --- docs/hacking.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hacking.rst b/docs/hacking.rst index 10ebc50..404f4f3 100644 --- a/docs/hacking.rst +++ b/docs/hacking.rst @@ -26,7 +26,7 @@ Do this: 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 + $ git clone git://github.com/paultag/hy.git (or use your fork) 4. install for hacking:: From 9d36dab693343121413d84c9914254817b62e792 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 09:54:53 -0400 Subject: [PATCH 072/114] Test importing things with dashes --- tests/native_tests/language.hy | 2 +- tests/resources/__init__.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 8a4c40b..cd3e1b4 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -1,6 +1,6 @@ ; -(import-from tests.resources kwtest) +(import-from tests.resources kwtest function-with-a-dash) (import-from os.path exists isdir isfile) (import-as sys systest) (import sys) diff --git a/tests/resources/__init__.py b/tests/resources/__init__.py index b115480..bb532ec 100644 --- a/tests/resources/__init__.py +++ b/tests/resources/__init__.py @@ -2,3 +2,7 @@ def kwtest(*args, **kwargs): return kwargs + + +def function_with_a_dash(): + pass From 3c735d18bdcff28bbdd765b131649ba57fb612b0 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 10:06:44 -0400 Subject: [PATCH 073/114] Revert "Revert "Remove useless code"" This reverts commit 262da59c7790cdadd60ea9612bc9e3c1616863fd. Conflicts: hy/models/string.py --- hy/models/string.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hy/models/string.py b/hy/models/string.py index b009ba3..a700470 100644 --- a/hy/models/string.py +++ b/hy/models/string.py @@ -34,7 +34,4 @@ class HyString(HyObject, str_type): scripts. It's either a ``str`` or a ``unicode``, depending on the Python version. """ - - def __new__(cls, value): - obj = str_type.__new__(cls, value) - return obj + pass From 46295016286d5448c5eed5941279fbbe29c3a36e Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 11:35:10 -0400 Subject: [PATCH 074/114] Addining some initial docs. --- docs/index.rst | 4 +-- docs/language/api.rst | 47 ++++++++++++++++++++++++++++++++ docs/language/index.rst | 11 ++++++++ docs/language/internals.rst | 27 ++++++++++++++++++ docs/{language => }/tutorial.rst | 0 5 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 docs/language/api.rst create mode 100644 docs/language/index.rst create mode 100644 docs/language/internals.rst rename docs/{language => }/tutorial.rst (100%) diff --git a/docs/index.rst b/docs/index.rst index 1618c2f..2e3d41e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -38,5 +38,5 @@ Contents: quickstart hacking - language/tutorial -.. library/index + tutorial + language/index diff --git a/docs/language/api.rst b/docs/language/api.rst new file mode 100644 index 0000000..b29d849 --- /dev/null +++ b/docs/language/api.rst @@ -0,0 +1,47 @@ +================= +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 `_ 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. diff --git a/docs/language/index.rst b/docs/language/index.rst new file mode 100644 index 0000000..6ca1ffd --- /dev/null +++ b/docs/language/index.rst @@ -0,0 +1,11 @@ + +Documentation Index +=================== + +Contents: + +.. toctree:: + :maxdepth: 3 + + api + internals diff --git a/docs/language/internals.rst b/docs/language/internals.rst new file mode 100644 index 0000000..ccf8263 --- /dev/null +++ b/docs/language/internals.rst @@ -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. diff --git a/docs/language/tutorial.rst b/docs/tutorial.rst similarity index 100% rename from docs/language/tutorial.rst rename to docs/tutorial.rst From 6dec894a0c9e1c94ef6bdb796b2fe9754bbfe557 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sun, 7 Apr 2013 17:22:57 +0200 Subject: [PATCH 075/114] Better catch syntax The syntax is now changed to: (catch [] BODY) (catch [Exception] BODY) (catch [e Exception] BODY) (catch [e [Exception1 Exception2]] BODY) Signed-off-by: Julien Danjou --- hy/compiler.py | 77 ++++++++++++++++++++++++++++------ tests/compilers/test_ast.py | 11 ++++- tests/native_tests/language.hy | 54 ++++++++++++++++++++++-- 3 files changed, 124 insertions(+), 18 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index fd31ec8..4bfbd56 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1,4 +1,7 @@ +# -*- encoding: utf-8 -*- +# # Copyright (c) 2013 Paul Tagliamonte +# Copyright (c) 2013 Julien Danjou # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -191,29 +194,77 @@ class HyASTCompiler(object): orelse=[]) @builds("catch") - @checkargs(min=2) def compile_catch_expression(self, expr): expr.pop(0) # catch - _type = self.compile(expr.pop(0)) - name = expr.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) + try: + exceptions = expr.pop(0) + except IndexError: + exceptions = [] + # exceptions catch should be either: + # [[list of exceptions]] + # or + # [variable [list of exceptions]] + # or + # [variable exception] + # or + # [exception] + # or + # [] + if len(exceptions) > 2: + raise TypeError("`catch' exceptions list is too long") + + # [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: - # Python2 requires an ast.Name, set to ctx Store. - name = self._storeize(self.compile(name)) + name = None + + try: + exceptions_list = exceptions.pop(0) + except IndexError: + exceptions_list = [] + + if isinstance(exceptions_list, list): + if len(exceptions_list): + # [FooBar BarFoo] → catch Foobar and BarFoo exceptions + _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("`catch' needs a valid exception list to catch") + + if len(expr) == 0: + # No body + body = [ast.Pass(lineno=expr.start_line, + col_offset=expr.start_column)] + else: + body = self._code_branch([self.compile(x) for x in expr]) return ast.ExceptHandler( lineno=expr.start_line, col_offset=expr.start_column, type=_type, name=name, - body=self._code_branch([self.compile(x) for x in expr])) + body=body) def _code_branch(self, branch): if isinstance(branch, list): diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 6b59ee3..3633851 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -116,13 +116,20 @@ def test_ast_bad_try(): def test_ast_good_catch(): "Make sure AST can compile valid catch" - hy_compile(tokenize("(catch 1 2)")) + 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)") cant_compile("(catch 1)") + cant_compile("(catch [1 3])") + cant_compile("(catch [x [FooBar] BarBar]])") def test_ast_good_assert(): diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index cd3e1b4..c137cc7 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -164,8 +164,56 @@ "NATIVE: test Exceptions" (try (throw (KeyError)) - (catch IOError e (assert (= 2 1))) - (catch KeyError e (+ 1 1) (assert (= 1 1))))) + (catch [[IOError]] (assert false)) + (catch [e [KeyError]] (assert e))) + + (try + (get [1] 3) + (catch [IndexError] (assert true)) + (catch [IndexError] (pass))) + + (try + (print foobar42ofthebaz) + (catch [IndexError] (assert false)) + (catch [NameError] (pass))) + + (try + (get [1] 3) + (catch [e IndexError] (assert (isinstance e IndexError)))) + + (try + (get [1] 3) + (catch [e [IndexError NameError]] (assert (isinstance e IndexError)))) + + (try + (print foobar42ofthebaz) + (catch [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) + (catch [])) + + (try + (print foobar42ofthebaz) + (catch [] (pass))) + + (try + (print foobar42ofthebaz) + (catch [] + (setv foobar42ofthebaz 42) + (assert (= foobar42ofthebaz 42))))) (defn test-earmuffs [] "NATIVE: Test earmuffs" @@ -327,7 +375,7 @@ 6)) (try (assert (= x 42)) ; This ain't true - (catch NameError e (assert e))) + (catch [e [NameError]] (assert e))) (assert (= y 123))) From 5e5ae07a9f9aa12c94593f8e26faee69b85e301d Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 12:25:13 -0400 Subject: [PATCH 076/114] fixing up the hy site to match the new catch syntax --- site/app.hy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/site/app.hy b/site/app.hy index 82da14a..77ada57 100644 --- a/site/app.hy +++ b/site/app.hy @@ -28,6 +28,6 @@ (post-route hy2py "/hy2py" [] (try (hy-to-py (get request.form "code")) - (catch LexException e (err "Incomplete Code.")) - (catch HyError e (err "Generic error during processing.")) - (catch Exception e (err "Erm, you broke something.")))) + (catch [e LexException] (err "Incomplete Code.")) + (catch [e HyError] (err "Generic error during processing.")) + (catch [e Exception] (err "Erm, you broke something.")))) From 2fd56e8fa1b96bf7fcd199841ca6f1d45c572a78 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sun, 7 Apr 2013 18:20:32 +0200 Subject: [PATCH 077/114] catch: uncomment some tests Signed-off-by: Julien Danjou --- tests/compilers/test_ast.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 3633851..0fc69da 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -119,10 +119,10 @@ def test_ast_good_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]])")) + 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(): From bdd07e125194def23bfc5d345fd8b4d79abbb704 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sun, 7 Apr 2013 18:24:01 +0200 Subject: [PATCH 078/114] Alias `except' to `catch' and `raise' to `throw' Signed-off-by: Julien Danjou --- hy/compiler.py | 2 ++ tests/compilers/test_ast.py | 28 ++++++++++++++++++++++++++++ tests/native_tests/language.hy | 20 +++++++++++++------- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 4bfbd56..e990a41 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -162,6 +162,7 @@ class HyASTCompiler(object): return [self.compile(x) for x in expr[1:]] @builds("throw") + @builds("raise") @checkargs(min=1) def compile_throw_expression(self, expr): expr.pop(0) @@ -194,6 +195,7 @@ class HyASTCompiler(object): orelse=[]) @builds("catch") + @builds("except") def compile_catch_expression(self, expr): expr.pop(0) # catch diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 0fc69da..533f836 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -104,6 +104,16 @@ def test_ast_bad_throw(): cant_compile("(throw)") +def test_ast_good_raise(): + "Make sure AST can compile valid raise" + hy_compile(tokenize("(raise 1)")) + + +def test_ast_bad_raise(): + "Make sure AST can't compile invalid raise" + cant_compile("(raise)") + + def test_ast_good_try(): "Make sure AST can compile valid try" hy_compile(tokenize("(try 1)")) @@ -132,6 +142,24 @@ def test_ast_bad_catch(): 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)")) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index c137cc7..d41d20b 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -163,23 +163,29 @@ (defn test-exceptions [] "NATIVE: test Exceptions" (try - (throw (KeyError)) + (raise (KeyError)) (catch [[IOError]] (assert false)) (catch [e [KeyError]] (assert e))) + (try + (throw (KeyError)) + (except [[IOError]] (assert false)) + (catch [e [KeyError]] (assert e))) + + (try (get [1] 3) (catch [IndexError] (assert true)) - (catch [IndexError] (pass))) + (except [IndexError] (pass))) (try (print foobar42ofthebaz) (catch [IndexError] (assert false)) - (catch [NameError] (pass))) + (except [NameError] (pass))) (try (get [1] 3) - (catch [e IndexError] (assert (isinstance e IndexError)))) + (except [e IndexError] (assert (isinstance e IndexError)))) (try (get [1] 3) @@ -187,7 +193,7 @@ (try (print foobar42ofthebaz) - (catch [e [IndexError NameError]] (assert (isinstance e NameError)))) + (except [e [IndexError NameError]] (assert (isinstance e NameError)))) (try (print foobar42) @@ -203,11 +209,11 @@ (try (print foobar42ofthebaz) - (catch [])) + (except [])) (try (print foobar42ofthebaz) - (catch [] (pass))) + (except [] (pass))) (try (print foobar42ofthebaz) From 070896adca568633319da4d80dec1ebd31c2e98b Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 12:47:07 -0400 Subject: [PATCH 079/114] Adding in a NEW file; filling this in --- NEWS | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 NEWS diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..ce1a46e --- /dev/null +++ b/NEWS @@ -0,0 +1,65 @@ +Changes from Hy 0.9.4 + + [ Syntax Fixes ] + + * Added "not" / "~" as the inline "not" operator. It's advised to still + use "not-in" or "is-not" rather then nesting. (JD) + + * `catch' now accepts a new format: (JD) + (catch [] BODY) + (catch [Exception] BODY) + (catch [e Exception] BODY) + (catch [e [Exception1 Exception2]] BODY) + + * `let' macro added (PT) + + [ Language Changes ] + + * UTF encoded symbols are allowed, but mangled. All Hy source is now + presumed to be UTF-8. (JD + PT) + + * Better builtin signature checking (JD) + + * Function hoisting (for things like inline invocation of functions, + e.g. '((fn [] (print "hi!")))' has been added. + * If hoisting (for things like printing the return of an if statement) + have been added. '(print (if true true true))' + + [ Documentation ] + + * Initial documentation added to the source tree. + + +Changes from Hy 0.9.3 + + [ Syntax Fixes ] + [ Language Changes ] + [ Documentation ] + + +Changes from Hy 0.9.2 + + [ Syntax Fixes ] + [ Language Changes ] + [ Documentation ] + + +Changes from Hy 0.9.1 + + [ Syntax Fixes ] + [ Language Changes ] + [ Documentation ] + + +Changes from Hy 0.9.0 + + [ Syntax Fixes ] + [ Language Changes ] + [ Documentation ] + + +Changes from Hy 0.8.2 + + [ Syntax Fixes ] + [ Language Changes ] + [ Documentation ] From 0d96c95fe942ffae1db0d60d8430cc890211d458 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 13:03:45 -0400 Subject: [PATCH 080/114] Adding 0.9.3 entries --- NEWS | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index ce1a46e..57d673c 100644 --- a/NEWS +++ b/NEWS @@ -2,9 +2,11 @@ Changes from Hy 0.9.4 [ Syntax Fixes ] - * Added "not" / "~" as the inline "not" operator. It's advised to still + * Added "not" as the inline "not" operator. It's advised to still use "not-in" or "is-not" rather then nesting. (JD) + * Added "~" as the "invert" operator. (JD) + * `catch' now accepts a new format: (JD) (catch [] BODY) (catch [Exception] BODY) @@ -20,8 +22,6 @@ Changes from Hy 0.9.4 * Better builtin signature checking (JD) - * Function hoisting (for things like inline invocation of functions, - e.g. '((fn [] (print "hi!")))' has been added. * If hoisting (for things like printing the return of an if statement) have been added. '(print (if true true true))' @@ -33,33 +33,55 @@ Changes from Hy 0.9.4 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 ] + + * `while' form added. (ND) + (while [CONDITIONAL] BODY) + + * 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) + [ Documentation ] + * Initial docs added. (WKG + CW) + Changes from Hy 0.9.2 [ Syntax Fixes ] [ Language Changes ] - [ Documentation ] Changes from Hy 0.9.1 [ Syntax Fixes ] [ Language Changes ] - [ Documentation ] Changes from Hy 0.9.0 [ Syntax Fixes ] [ Language Changes ] - [ Documentation ] Changes from Hy 0.8.2 [ Syntax Fixes ] [ Language Changes ] - [ Documentation ] From eba57bea07700ed678adb819a989e773316e7c26 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 13:24:19 -0400 Subject: [PATCH 081/114] Backfilling NEWS entries --- NEWS | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 57d673c..3572250 100644 --- a/NEWS +++ b/NEWS @@ -65,23 +65,55 @@ Changes from Hy 0.9.3 Changes from Hy 0.9.2 - [ Syntax Fixes ] + [ 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 - [ Syntax Fixes ] + [ 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 - [ Syntax Fixes ] [ Language Changes ] + * Add `throw' (PT) + * Add `try' (PT) + * add `catch' (PT) + Changes from Hy 0.8.2 - [ Syntax Fixes ] - [ Language Changes ] + [ Notes ] + + * Complete rewrite of old-hy. (PT) From 0c0db1ddcb8803ba241f2866ed797ef91daa3974 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 13:24:46 -0400 Subject: [PATCH 082/114] some last entries --- NEWS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 3572250..665f75b 100644 --- a/NEWS +++ b/NEWS @@ -23,11 +23,11 @@ Changes from Hy 0.9.4 * 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))' + have been added. '(print (if true true true))' (PT) [ Documentation ] - * Initial documentation added to the source tree. + * Initial documentation added to the source tree. (PT) Changes from Hy 0.9.3 From 1853b7d33c3f42820fa7a80c56278e8f9834b5e0 Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Sun, 7 Apr 2013 19:42:28 +0200 Subject: [PATCH 083/114] Correctly balance the brackets in the wrong syntax tests We want to test the compiler, not the lexer. --- tests/compilers/test_ast.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 533f836..31daf14 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -139,7 +139,7 @@ def test_ast_bad_catch(): "Make sure AST can't compile invalid catch" cant_compile("(catch 1)") cant_compile("(catch [1 3])") - cant_compile("(catch [x [FooBar] BarBar]])") + cant_compile("(catch [x [FooBar] BarBar])") def test_ast_good_except(): @@ -157,7 +157,7 @@ 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]])") + cant_compile("(except [x [FooBar] BarBar])") def test_ast_good_assert(): From 546e7ff50b728836938c6368dfbef393eeea4eef Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 14:32:47 -0400 Subject: [PATCH 084/114] Style bits --- NEWS | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/NEWS b/NEWS index 665f75b..4439e61 100644 --- a/NEWS +++ b/NEWS @@ -4,24 +4,19 @@ Changes from Hy 0.9.4 * 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) - * `let' macro added (PT) - [ Language Changes ] * 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) @@ -35,28 +30,20 @@ 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 ] - * `while' form added. (ND) - (while [CONDITIONAL] BODY) - * 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 ] From bfc71e4a60d0e8801039a0d20e7e7a06a70fc476 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 15:05:30 -0400 Subject: [PATCH 085/114] Add tail threading (->>) --- hy/core/bootstrap.py | 14 ++++++++++++++ tests/native_tests/language.hy | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/hy/core/bootstrap.py b/hy/core/bootstrap.py index e77fb02..50efc66 100644 --- a/hy/core/bootstrap.py +++ b/hy/core/bootstrap.py @@ -94,6 +94,20 @@ def threading_macro(tree): 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("first") def first_macro(tree): diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index d41d20b..1044c41 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -235,6 +235,12 @@ ["X" "B" "C" "D"]))) +(defn test-tail-threading [] + "NATIVE: test tail threading macro" + (assert (= (.join ", " (* 10 ["foo"])) + (->> ["foo"] (* 10) (.join ", "))))) + + (defn test-threading-two [] "NATIVE: test threading macro" (assert (= (-> "a b c d" .upper (.replace "A" "X") .split) From 3cc165545d34c8272e90adf5da4cbd2be58e433a Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 15:07:24 -0400 Subject: [PATCH 086/114] add to NEWS --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index 4439e61..8e96483 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Changes from Hy 0.9.4 [ Language Changes ] + * 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) From f5dc569de402fbca9a98a02afe77d9c86f3c9ba1 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sun, 7 Apr 2013 23:14:42 +0200 Subject: [PATCH 087/114] compiler: remove old TODO entry Signed-off-by: Julien Danjou --- hy/compiler.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index e990a41..f0b6388 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -679,9 +679,6 @@ class HyASTCompiler(object): expression.pop(0) # for name, iterable = expression.pop(0) target = self._storeize(self.compile_symbol(name)) - # support stuff like: - # (for [x [1 2 3 4] - # y [a b c d]] ...) ret = ast.For(lineno=expression.start_line, col_offset=expression.start_column, From f03b538787fca1bf7458863612c8d963f68cff3c Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Sun, 7 Apr 2013 23:54:56 +0200 Subject: [PATCH 088/114] Implement the (and) function The function takes at least two arguments, and turns it into a pythonic and statement, which returns the last True-ish value, or False. Signed-off-by: Gergely Nagy --- hy/compiler.py | 12 ++++++++++++ tests/native_tests/language.hy | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/hy/compiler.py b/hy/compiler.py index e990a41..026461d 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -546,6 +546,18 @@ class HyASTCompiler(object): lineno=operator.start_line, col_offset=operator.start_column) + @builds("and") + @checkargs(min=2) + def compile_and_operator(self, expression): + operator = expression.pop(0) + values = [] + for child in expression: + values.append (self.compile(child)) + return ast.BoolOp(op=ast.And(), + lineno=operator.start_line, + col_offset=operator.start_column, + values=values) + @builds("=") @builds("!=") @builds("<") diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 1044c41..f533a9b 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -406,6 +406,13 @@ (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)))) + ; FEATURE: native hy-eval ; ; - related to bug #64 From 1b7d145c65ef16181d9dbd59bfd89d741c94ca3a Mon Sep 17 00:00:00 2001 From: Gergely Nagy Date: Mon, 8 Apr 2013 00:00:20 +0200 Subject: [PATCH 089/114] Implement the (or) function too The (or) function is to be constructed similarly to (and), so refactor the compile_and_operator function to handle or aswell. Signed-off-by: Gergely Nagy --- hy/compiler.py | 7 +++++-- tests/native_tests/language.hy | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 026461d..13e9448 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -547,13 +547,16 @@ class HyASTCompiler(object): col_offset=operator.start_column) @builds("and") + @builds("or") @checkargs(min=2) - def compile_and_operator(self, expression): + 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=ast.And(), + return ast.BoolOp(op=ops[operator](), lineno=operator.start_line, col_offset=operator.start_column, values=values) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index f533a9b..9eaf0f5 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -413,6 +413,15 @@ (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)))) + ; FEATURE: native hy-eval ; ; - related to bug #64 From a73d460beb1f5a4f658dff2a45ca02b6c35dfa77 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sun, 7 Apr 2013 19:06:02 +0200 Subject: [PATCH 090/114] try: allow empty body Signed-off-by: Julien Danjou --- hy/compiler.py | 9 +++++++-- tests/compilers/test_ast.py | 6 +----- tests/native_tests/language.hy | 3 +++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index cf0de49..ca4be73 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -176,7 +176,6 @@ class HyASTCompiler(object): tback=None) @builds("try") - @checkargs(min=1) def compile_try_expression(self, expr): expr.pop(0) # try @@ -186,10 +185,16 @@ class HyASTCompiler(object): else: Try = ast.TryExcept + if len(expr) == 0: + body = [ast.Pass(lineno=expr.start_line, + col_offset=expr.start_column)] + else: + body = self._code_branch(self.compile(expr.pop(0))) + return Try( lineno=expr.start_line, col_offset=expr.start_column, - body=self._code_branch(self.compile(expr.pop(0))), + body=body, handlers=[self.compile(s) for s in expr], finalbody=[], orelse=[]) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 31daf14..cfafca2 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -116,14 +116,10 @@ def test_ast_bad_raise(): def test_ast_good_try(): "Make sure AST can compile valid try" + hy_compile(tokenize("(try)")) hy_compile(tokenize("(try 1)")) -def test_ast_bad_try(): - "Make sure AST can't compile invalid try" - cant_compile("(try)") - - def test_ast_good_catch(): "Make sure AST can compile valid catch" hy_compile(tokenize("(catch)")) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 9eaf0f5..cbd5254 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -162,6 +162,9 @@ (defn test-exceptions [] "NATIVE: test Exceptions" + + (try) + (try (raise (KeyError)) (catch [[IOError]] (assert false)) From 47ec1d264c981b6177cd6b257a2c54f9eab93f52 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 18:16:45 -0400 Subject: [PATCH 091/114] style fixes --- hy/compiler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index 0f7b452..cf0de49 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -555,7 +555,7 @@ class HyASTCompiler(object): operator = expression.pop(0) values = [] for child in expression: - values.append (self.compile(child)) + values.append(self.compile(child)) return ast.BoolOp(op=ops[operator](), lineno=operator.start_line, col_offset=operator.start_column, From 4debdf63eaa6e334781eac945587dc18dceebede Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 18:18:02 -0400 Subject: [PATCH 092/114] Adding and / or to NEWS --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index 8e96483..8d2d046 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Changes from Hy 0.9.4 [ 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) From 806f0d900c9e39da7b6ea88f7bf7ab5f138d87cc Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Mon, 8 Apr 2013 00:17:42 +0200 Subject: [PATCH 093/114] Throw an error on unbalanced expressions --- hy/lex/states.py | 3 +++ tests/lex/test_lex.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/hy/lex/states.py b/hy/lex/states.py index 72caba6..52d6fa3 100644 --- a/hy/lex/states.py +++ b/hy/lex/states.py @@ -161,6 +161,9 @@ class ListeyThing(State): if char == self.end_char: return Idle + if char in ")]}": + raise LexException("Unexpected closing character: `%s'" % (char)) + if char in WHITESPACE: self.commit() return diff --git a/tests/lex/test_lex.py b/tests/lex/test_lex.py index d3b3706..45922b9 100644 --- a/tests/lex/test_lex.py +++ b/tests/lex/test_lex.py @@ -44,6 +44,21 @@ def test_lex_exception(): pass +def test_unbalanced_exception(): + """Ensure the tokenization fails on unbalanced expressions""" + try: + tokenize("(bar))") + assert True is False + except LexException: + pass + + try: + tokenize("(baz [quux]])") + assert True is False + except LexException: + pass + + def test_lex_expression_symbols(): """ Make sure that expressions produce symbols """ objs = tokenize("(foo bar)") From 4db944619774c660e1317580e2004a71973b1adb Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 18:35:36 -0400 Subject: [PATCH 094/114] Fixing (with)'s syntax to be more hyish. --- NEWS | 3 +++ hy/compiler.py | 19 ++++++++++++++----- tests/compilers/test_ast.py | 7 +++++++ tests/native_tests/language.hy | 4 ++-- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 8d2d046..ca1932d 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,9 @@ Changes from Hy 0.9.4 (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 ] diff --git a/hy/compiler.py b/hy/compiler.py index cf0de49..898313a 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -456,12 +456,21 @@ class HyASTCompiler(object): fn.decorator_list = [self.compile(x) for x in expr] return fn - @builds("with_as") + @builds("with") @checkargs(min=2) - def compile_with_as_expression(self, expr): - expr.pop(0) # with-as - ctx = self.compile(expr.pop(0)) - thing = self._storeize(self.compile(expr.pop(0))) + def compile_with_expression(self, expr): + expr.pop(0) # with + + 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, lineno=expr.start_line, diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 31daf14..1fb438d 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -252,6 +252,13 @@ def test_ast_bad_assoc(): 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)")) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 9eaf0f5..47dd111 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -293,8 +293,8 @@ (defn test-context [] "NATIVE: test with" - (with-as (open "README.md" "r") fd - (pass))) + (with [fd (open "README.md" "r")] (pass)) + (with [(open "README.md" "r")] (pass))) (defn test-for-doodle [] From 0d3500f6e534cceb257b71d368f8cfa6b3a5d0dd Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 8 Apr 2013 00:36:08 +0200 Subject: [PATCH 095/114] try: accept a simpler form Signed-off-by: Julien Danjou --- hy/compiler.py | 17 ++++++++++++++++- tests/compilers/test_ast.py | 3 +++ tests/native_tests/language.hy | 6 ++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index ca4be73..fff1e60 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -186,16 +186,31 @@ class HyASTCompiler(object): Try = ast.TryExcept if len(expr) == 0: + # (try) body = [ast.Pass(lineno=expr.start_line, col_offset=expr.start_column)] else: + # (try something…) body = self._code_branch(self.compile(expr.pop(0))) + 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: + # (try body except except…) + handlers = [self.compile(s) for s in expr] + return Try( lineno=expr.start_line, col_offset=expr.start_column, body=body, - handlers=[self.compile(s) for s in expr], + handlers=handlers, finalbody=[], orelse=[]) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index cfafca2..3a2d7ca 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -1,4 +1,5 @@ # Copyright (c) 2013 Paul Tagliamonte +# Copyright (c) 2013 Julien Danjou # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -118,6 +119,8 @@ 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 bla)")) + hy_compile(tokenize("(try 1 bla bla)")) def test_ast_good_catch(): diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index cbd5254..588e3af 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -165,6 +165,12 @@ (try) + (try (pass)) + + (try (pass) (except)) + + (try (pass) (except [IOError]) (except)) + (try (raise (KeyError)) (catch [[IOError]] (assert false)) From a81a7164208c5a634dce6af87374cf11165a7e0f Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 8 Apr 2013 00:38:55 +0200 Subject: [PATCH 096/114] Be sure errors are raised at by compile, not tokenize Signed-off-by: Julien Danjou --- tests/compilers/test_ast.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 31daf14..b8cbcd5 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -1,4 +1,5 @@ # Copyright (c) 2013 Paul Tagliamonte +# Copyright (c) 2013 Julien Danjou # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -35,8 +36,9 @@ def _ast_spotcheck(arg, root, secondary): def cant_compile(expr): + expr = tokenize(expr) try: - hy_compile(tokenize(expr)) + hy_compile(expr) assert False except HyCompileError: pass From 83d91c3f8150c041adf7d18c6f299c0fc2604224 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 18:39:30 -0400 Subject: [PATCH 097/114] Asserting `fd' exists inside the with --- tests/native_tests/language.hy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 47dd111..9df1751 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -293,7 +293,7 @@ (defn test-context [] "NATIVE: test with" - (with [fd (open "README.md" "r")] (pass)) + (with [fd (open "README.md" "r")] (assert fd)) (with [(open "README.md" "r")] (pass))) From e22a0ff73c8e567ae4ed58be659b3e2c2927cd22 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 18:41:41 -0400 Subject: [PATCH 098/114] Mangle a macro until it stops moving this helps if we use a macro in something that got tree-mangled back out. --- hy/core/__init__.py | 9 ++++++--- tests/native_tests/language.hy | 5 +++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/hy/core/__init__.py b/hy/core/__init__.py index a17b72c..65be1af 100644 --- a/hy/core/__init__.py +++ b/hy/core/__init__.py @@ -31,9 +31,12 @@ MACROS = [ def process(tree): load_macros() - tree = mprocess(tree) - for m in hy.mangle.MANGLES: - m().mangle(tree) + old = None + while old != tree: + old = tree + tree = mprocess(tree) + for m in hy.mangle.MANGLES: + m().mangle(tree) return tree diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 9eaf0f5..5beaf6f 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -377,6 +377,11 @@ (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) From 5ff40c5e30892f41bd18b94b49c672c6cb1931be Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 18:58:45 -0400 Subject: [PATCH 099/114] Forgot to add @algernon to AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index a3ef4d0..4fae5f8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,3 +6,4 @@ * James King * Julien Danjou * Nicolas Dandrimont +* Gergely Nagy From 5336b2f71ace09ab3df9af56238eb16289f0aafa Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 19:29:45 -0400 Subject: [PATCH 100/114] Fix early returns. Close #83 --- hy/compiler.py | 20 +++++++++++++++++--- tests/native_tests/language.hy | 12 ++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 66f10bf..6851749 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -762,12 +762,27 @@ class HyASTCompiler(object): expression.pop(0) # fn ret_status = self.returnable - self.returnable = True self.anon_fn_count += 1 name = "_hy_anon_fn_%d" % (self.anon_fn_count) 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) + + if body == []: + body = [ast.Pass(lineno=expression.start_line, + col_offset=expression.start_column)] + + self.returnable = True + body = self._code_branch(body) + ret = ast.FunctionDef( name=name, lineno=expression.start_line, @@ -785,8 +800,7 @@ class HyASTCompiler(object): kwonlyargs=[], kw_defaults=[], defaults=[]), - body=self._code_branch([ - self.compile(x) for x in expression]), + body=body, decorator_list=[]) self.returnable = ret_status diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index e029480..6b00a3e 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -427,6 +427,7 @@ (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")] @@ -436,6 +437,17 @@ (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)))) + + ; FEATURE: native hy-eval ; ; - related to bug #64 From 38a714b5c51d1156c458c9196660765a1151ad40 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 19:44:52 -0400 Subject: [PATCH 101/114] Adding more tests; new entries --- NEWS | 1 + tests/native_tests/language.hy | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index ca1932d..b2a7106 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ 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) diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 6b00a3e..35abf96 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -445,7 +445,11 @@ [y 2]] (if true 2) - 1)))) + 1))) + (assert (= 1 (let [[x 1] [y 2]] + (pass) + (pass) + ((fn [] 1)))))) ; FEATURE: native hy-eval From cd1a32ce9f96b224320a73d52aafc9d8ff9daaaf Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 19:45:38 -0400 Subject: [PATCH 102/114] Adding in an upload target. --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index e868f85..25a2517 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,9 @@ site: docs: make -C docs html +upload: r + python setup.py sdist upload + full: d tox site docs venv: From 57fa5c8127faf067e2fc02b886b22e334d4c027d Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Sun, 7 Apr 2013 19:45:50 -0400 Subject: [PATCH 103/114] Time for 0.9.5 --- hy/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hy/__init__.py b/hy/__init__.py index 7ac6aac..f25dd2f 100644 --- a/hy/__init__.py +++ b/hy/__init__.py @@ -20,7 +20,7 @@ __appname__ = "hy" -__version__ = "0.9.4" +__version__ = "0.9.5" import hy.importer # NOQA From cd36a1d7ebd4191296e7cb0fe65ce1d3cd1b344c Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 8 Apr 2013 15:17:11 +0200 Subject: [PATCH 104/114] Allow empty `do' Signed-off-by: Julien Danjou --- hy/compiler.py | 1 - tests/compilers/test_ast.py | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 6851749..35fa962 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -157,7 +157,6 @@ class HyASTCompiler(object): @builds("do") @builds("progn") - @checkargs(min=1) def compile_do_expression(self, expr): return [self.compile(x) for x in expr[1:]] diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index 72f466f..f839feb 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -88,14 +88,10 @@ def test_ast_bad_while(): def test_ast_good_do(): "Make sure AST can compile valid do" + hy_compile(tokenize("(do)")) hy_compile(tokenize("(do 1)")) -def test_ast_bad_do(): - "Make sure AST can't compile invalid do" - cant_compile("(do)") - - def test_ast_good_throw(): "Make sure AST can compile valid throw" hy_compile(tokenize("(throw 1)")) From 3dabc1a72ad5897df5f28d7fa55f8dac515ed689 Mon Sep 17 00:00:00 2001 From: Will Kahn-Greene Date: Mon, 8 Apr 2013 12:03:42 -0400 Subject: [PATCH 105/114] Update example to be more relevant to users --- docs/quickstart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index e15ecbe..c494c39 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -26,7 +26,7 @@ OMG! That's amazing! I want to write a hy program. 7. open up an elite programming editor 8. type:: - (print "hy is the BEST!") + (print "i was going to code in python syntax, but then i got hy") 9. save as ``test_program_of_awesome.hy`` 10. run:: From d7e8dd2a918726d222e9bd6f123392fc4d71eee3 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 8 Apr 2013 19:22:30 +0200 Subject: [PATCH 106/114] compiler: optimize empty tree mangling to ast.Pass Signed-off-by: Julien Danjou --- hy/compiler.py | 78 ++++++++++++++++++++-------------- tests/native_tests/language.hy | 7 +++ 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 35fa962..76b266a 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -120,7 +120,12 @@ class HyASTCompiler(object): 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 = [] tree = list(flatten_literal_list(tree)) tree.reverse() @@ -184,13 +189,15 @@ class HyASTCompiler(object): else: Try = ast.TryExcept - if len(expr) == 0: - # (try) - body = [ast.Pass(lineno=expr.start_line, - col_offset=expr.start_column)] - else: - # (try something…) - body = self._code_branch(self.compile(expr.pop(0))) + try: + body = expr.pop(0) + except IndexError: + body = [] + + # (try something…) + body = self._code_branch(self.compile(body), + expr.start_line, + expr.start_column) if len(expr) == 0: # (try) or (try body) @@ -273,12 +280,9 @@ class HyASTCompiler(object): else: raise TypeError("`catch' needs a valid exception list to catch") - if len(expr) == 0: - # No body - body = [ast.Pass(lineno=expr.start_line, - col_offset=expr.start_column)] - else: - body = self._code_branch([self.compile(x) for x in expr]) + body = self._code_branch([self.compile(x) for x in expr], + expr.start_line, + expr.start_column) return ast.ExceptHandler( lineno=expr.start_line, @@ -287,20 +291,26 @@ class HyASTCompiler(object): name=name, body=body) - def _code_branch(self, branch): - if isinstance(branch, list): - return self._mangle_branch(branch) - return self._mangle_branch([branch]) + def _code_branch(self, branch, start_line, start_column): + return self._mangle_branch((branch + if isinstance(branch, list) + else [branch]), + start_line, + start_column) @builds("if") @checkargs(min=2, max=3) def compile_if_expression(self, expr): expr.pop(0) # if test = self.compile(expr.pop(0)) - body = self._code_branch(self.compile(expr.pop(0))) + body = self._code_branch(self.compile(expr.pop(0)), + expr.start_line, + expr.start_column) if len(expr) == 1: - orel = self._code_branch(self.compile(expr.pop(0))) + orel = self._code_branch(self.compile(expr.pop(0)), + expr.start_line, + expr.start_column) else: orel = [] @@ -495,8 +505,10 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column, optional_vars=thing, - body=self._mangle_branch([ - self.compile(x) for x in expr])) + body=self._code_branch( + [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: ret.items = [ast.withitem(context_expr=ctx, optional_vars=thing)] @@ -727,8 +739,10 @@ class HyASTCompiler(object): col_offset=expression.start_column, target=target, iter=self.compile(iterable), - body=self._mangle_branch([ - self.compile(x) for x in expression]), + body=self._code_branch( + [self.compile(x) for x in expression], + expression.start_line, + expression.start_column), orelse=[]) self.returnable = ret_status @@ -741,8 +755,10 @@ class HyASTCompiler(object): test = self.compile(expr.pop(0)) return ast.While(test=test, - body=self._mangle_branch([ - self.compile(x) for x in expr]), + 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) @@ -775,12 +791,10 @@ class HyASTCompiler(object): body.append(self.compile(el)) body.append(tailop) - if body == []: - body = [ast.Pass(lineno=expression.start_line, - col_offset=expression.start_column)] - self.returnable = True - body = self._code_branch(body) + body = self._code_branch(body, + expression.start_line, + expression.start_column) ret = ast.FunctionDef( name=name, @@ -858,5 +872,5 @@ def hy_compile(tree, root=None): tlo = root if root is None: 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 diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 35abf96..ef2de95 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -160,11 +160,18 @@ (assert (= (.join " " ["one" "two"]) "one two"))) +(defn test-do [] + "NATIVE: test do" + (do)) + + (defn test-exceptions [] "NATIVE: test Exceptions" (try) + (try (do)) + (try (pass)) (try (pass) (except)) From 1c14a69fc98c354f75e0797c3bc9e93f065c5f1b Mon Sep 17 00:00:00 2001 From: Christopher Browne Date: Mon, 8 Apr 2013 17:01:12 -0400 Subject: [PATCH 107/114] example was missing function parameter name --- docs/quickstart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index c494c39..78a84ef 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -13,7 +13,7 @@ HOW TO GET HY REAL FAST: => (print "Hy!") Hy! - => (defn salutationsnm [] (print (+ "Hy " name "!"))) + => (defn salutationsnm [name] (print (+ "Hy " name "!"))) => (salutationsnm "YourName") Hy YourName! From 4ce308193376a142f09fbc58d9546ac8ea54103f Mon Sep 17 00:00:00 2001 From: Christopher Browne Date: Mon, 8 Apr 2013 17:09:00 -0400 Subject: [PATCH 108/114] Typo in tutorial --- docs/tutorial.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index f10002f..584652f 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -339,7 +339,7 @@ In hy, you could do these like: (list-comp (pow num 2) (num (range 100)) - (= (% num 2) 1)) + (= (% num 2) 1))) .. code-block:: clj From 4e61ae59fdf004660e416acad48207cc0251e2c5 Mon Sep 17 00:00:00 2001 From: "Paul R. Tagliamonte" Date: Mon, 8 Apr 2013 21:53:06 -0400 Subject: [PATCH 109/114] small internals tweak --- docs/language/api.rst | 54 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/docs/language/api.rst b/docs/language/api.rst index b29d849..a59a450 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -45,3 +45,57 @@ 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. From ed5a0455b63d084371d8460ee3c87a870c934071 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Tue, 9 Apr 2013 16:05:04 +0200 Subject: [PATCH 110/114] Enhance error reporting We're now able to make the difference between a compiler bug and a user trying to compile wrong thing, and report this correctly on the console. Signed-off-by: Julien Danjou --- hy/compiler.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 76b266a..e109ca0 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -38,7 +38,21 @@ import sys 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 = {} @@ -111,12 +125,15 @@ class HyASTCompiler(object): for _type in _compile_table: 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: - err = HyCompileError(str(e)) - err.exception = e - err.start_line = getattr(e, "start_line", None) - err.start_column = getattr(e, "start_column", None) - raise err + 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)))) From dd90272129de1a8ed095b5c628d3a6e17bf26d43 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Tue, 9 Apr 2013 16:56:45 +0200 Subject: [PATCH 111/114] except/catch: check exceptions list type Signed-off-by: Julien Danjou --- hy/compiler.py | 6 ++++-- tests/compilers/test_ast.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 76b266a..7f56b40 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -223,12 +223,12 @@ class HyASTCompiler(object): @builds("catch") @builds("except") def compile_catch_expression(self, expr): - expr.pop(0) # catch + catch = expr.pop(0) # catch try: exceptions = expr.pop(0) except IndexError: - exceptions = [] + exceptions = HyList() # exceptions catch should be either: # [[list of exceptions]] # or @@ -239,6 +239,8 @@ class HyASTCompiler(object): # [exception] # or # [] + if not isinstance(exceptions, HyList): + raise TypeError("`%s' exceptions list is not a list" % catch) if len(exceptions) > 2: raise TypeError("`catch' exceptions list is too long") diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index f839feb..e9272a3 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -134,6 +134,7 @@ def test_ast_good_catch(): 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])") From 48d5a0abc043e8261bd0107ff2541c7c915338af Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Tue, 9 Apr 2013 16:58:32 +0200 Subject: [PATCH 112/114] catch: use the right symbol name in errors Signed-off-by: Julien Danjou --- hy/compiler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 7f56b40..5ff6d48 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -242,7 +242,7 @@ class HyASTCompiler(object): if not isinstance(exceptions, HyList): raise TypeError("`%s' exceptions list is not a list" % catch) if len(exceptions) > 2: - raise TypeError("`catch' exceptions list is too long") + raise TypeError("`%s' exceptions list is too long" % catch) # [variable [list of exceptions]] # let's pop variable and use it as name @@ -280,7 +280,7 @@ class HyASTCompiler(object): elif isinstance(exceptions_list, HySymbol): _type = self.compile(exceptions_list) else: - raise TypeError("`catch' needs a valid exception list to catch") + raise TypeError("`%s' needs a valid exception list" % catch) body = self._code_branch([self.compile(x) for x in expr], expr.start_line, From f8131d3c36e842832eaa126ffb805fa7f37f4aec Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Mon, 8 Apr 2013 15:58:43 +0200 Subject: [PATCH 113/114] compiler: add `else' support in `try' This is a bit tricky, since we'll also have to support `finally' in the end, I've introduced an Else statement on my own to be able to recognize it. This fixes #74 Signed-off-by: Julien Danjou --- NEWS | 10 ++++++++++ hy/compiler.py | 26 +++++++++++++++++++++++--- tests/compilers/test_ast.py | 12 ++++++++++-- tests/native_tests/language.hy | 34 +++++++++++++++++++++++++++++++++- 4 files changed, 76 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index b2a7106..2a26aed 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,13 @@ +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 ] diff --git a/hy/compiler.py b/hy/compiler.py index 5ff6d48..2121fbc 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -199,6 +199,7 @@ class HyASTCompiler(object): expr.start_line, expr.start_column) + orelse = [] if len(expr) == 0: # (try) or (try body) handlers = [ast.ExceptHandler( @@ -209,8 +210,27 @@ class HyASTCompiler(object): body=[ast.Pass(lineno=expr.start_line, col_offset=expr.start_column)])] else: - # (try body except except…) - handlers = [self.compile(s) for s in expr] + 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( lineno=expr.start_line, @@ -218,7 +238,7 @@ class HyASTCompiler(object): body=body, handlers=handlers, finalbody=[], - orelse=[]) + orelse=orelse) @builds("catch") @builds("except") diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index e9272a3..f7e34ca 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -116,8 +116,16 @@ 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 bla)")) - hy_compile(tokenize("(try 1 bla bla)")) + 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(): diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index ef2de95..5ef858a 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -235,7 +235,39 @@ (print foobar42ofthebaz) (catch [] (setv foobar42ofthebaz 42) - (assert (= 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 [] "NATIVE: Test earmuffs" From b13cc6007582f3b57dbeda1db35087642d48c801 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Tue, 9 Apr 2013 16:50:27 +0200 Subject: [PATCH 114/114] Implements (raise) As in Python, this allows to re-raise the last raised exception. This fixes #86 Signed-off-by: Julien Danjou --- hy/compiler.py | 4 ++-- tests/compilers/test_ast.py | 6 ++++-- tests/native_tests/language.hy | 20 ++++++++++++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index 76b266a..3856616 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -167,10 +167,10 @@ class HyASTCompiler(object): @builds("throw") @builds("raise") - @checkargs(min=1) + @checkargs(max=1) def compile_throw_expression(self, expr): expr.pop(0) - exc = self.compile(expr.pop(0)) + exc = self.compile(expr.pop(0)) if expr else None return ast.Raise( lineno=expr.start_line, col_offset=expr.start_column, diff --git a/tests/compilers/test_ast.py b/tests/compilers/test_ast.py index f839feb..c10b822 100644 --- a/tests/compilers/test_ast.py +++ b/tests/compilers/test_ast.py @@ -94,22 +94,24 @@ def test_ast_good_do(): 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("(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)") + cant_compile("(raise 1 2 3)") def test_ast_good_try(): diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index ef2de95..a47a525 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -178,6 +178,26 @@ (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))