From a102a268a9bd33e8be81b35bebc73357119b020c Mon Sep 17 00:00:00 2001 From: Bertie Wheen Date: Sat, 17 May 2014 18:46:01 +0100 Subject: [PATCH 1/9] Rephrased confusing comment --- docs/language/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index 28c13ba..8bcf285 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -305,7 +305,7 @@ Some example usage: Yeah, really! ;; assuming that (side-effect) is a function that we want to call for each - ;; and every value in the list, but which return values we do not care + ;; and every value in the list, but whose return value we do not care about => (list-comp (do (side-effect x) ... (if (< x 5) (* 2 x) ... (* 4 x))) From 02fa2511751ba2acb03cfb61ff0015b63f296956 Mon Sep 17 00:00:00 2001 From: Bertie Wheen Date: Sat, 17 May 2014 19:04:41 +0100 Subject: [PATCH 2/9] Minor typo Sorry for tiny commits :P --- docs/language/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index 28c13ba..2521b95 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -416,7 +416,7 @@ Parameters may have following keywords in front of them: arguments may be specified after this one. The following code example defines a function that can be given 0 to n - numerical parameters. It then sums every odd number and substracts + numerical parameters. It then sums every odd number and subtracts every even number. .. code-block:: clj From 1da6d0af43958a63e5dfc088ebf6db30d6812d9f Mon Sep 17 00:00:00 2001 From: Abhishek L Date: Fri, 23 May 2014 23:03:38 +0530 Subject: [PATCH 3/9] docs: fix decorator to reflect multiple decorators * docs/language/api.rst: the `with-decorator' builtin supports multiple decorators which it applies in order. Docs are updated to reflect this --- docs/language/api.rst | 45 +++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/docs/language/api.rst b/docs/language/api.rst index f5d50b2..9097910 100644 --- a/docs/language/api.rst +++ b/docs/language/api.rst @@ -1293,23 +1293,48 @@ file is automatically closed after it has been processed. with-decorator -------------- -`with-decorator` is used to wrap a function with another. The function performing -decoration should accept a single value, the function being decorated and return -a new function. `with-decorator` takes two parameters, the function performing -decoration and the function being decorated. - -In the following example, `inc-decorator` is used to decorate function `addition` -with a function that takes two parameters and calls the decorated function with -values that are incremented by 1. When decorated `addition` is called with values -1 and 1, the end result will be 4 (1+1 + 1+1). +`with-decorator` is used to wrap a function with another. The function +performing decoration should accept a single value, the function being +decorated and return a new function. `with-decorator` takes a minimum +of two parameters, the function performing decoration and the function +being decorated. More than one decorator function can be applied, they +will be applied in order from outermost to innermost, ie. the first +decorator will be the outermost one & so on. Decorators with arguments +are called just like a function call. .. code-block:: clj - => (defn inc-decorator [func] + (with-decorator decorator-fun + (defn some-function [] ...) + + (with-decorator decorator1 decorator2 ... + (defn some-function [] ...) + + (with-decorator (decorator arg) .. + (defn some-function [] ...) + + + +In the following example, `inc-decorator` is used to decorate function +`addition` with a function that takes two parameters and calls the +decorated function with values that are incremented by 1. When +decorated `addition` is called with values 1 and 1, the end result +will be 4 (1+1 + 1+1). + +.. code-block:: clj + + => (defn inc-decorator [func] ... (fn [value-1 value-2] (func (+ value-1 1) (+ value-2 1)))) + => (defn inc2-decorator [func] + ... (fn [value-1 value-2] (func (+ value-1 2) (+ value-2 2)))) + => (with-decorator inc-decorator (defn addition [a b] (+ a b))) => (addition 1 1) 4 + => (with-decorator inc2-decorator inc-decorator + ... (defn addition [a b] (+ a b))) + => (addition 1 1) + 8 .. _with-gensyms: From c2982a9ae34d2fe45d962d511f6210c168b7d186 Mon Sep 17 00:00:00 2001 From: Abhishek L Date: Thu, 15 May 2014 23:41:24 +0530 Subject: [PATCH 4/9] anaphoric: fix first & last when conditions fail * hy/contrib/anaphoric.hy: `ap-first` and `ap-last` now handle cases when failure happens for the predicate. Thanks to @tutorto for reporting this bug --- hy/contrib/anaphoric.hy | 18 ++++++++++-------- tests/native_tests/contrib/anaphoric.hy | 6 ++++-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/hy/contrib/anaphoric.hy b/hy/contrib/anaphoric.hy index 5a6b236..5000cbf 100644 --- a/hy/contrib/anaphoric.hy +++ b/hy/contrib/anaphoric.hy @@ -84,18 +84,20 @@ (defmacro ap-first [predfn lst] "Yield the first element that passes `predfn`" - `(let [[n (gensym)]] - (ap-each ~lst (when ~predfn (setv n it) (break))) - n)) + (with-gensyms [n] + `(let [[~n None]] + (ap-each ~lst (when ~predfn (setv ~n it) (break))) + ~n))) (defmacro ap-last [predfn lst] "Yield the last element that passes `predfn`" - `(let [[n (gensym)]] - (ap-each ~lst (none? n) - (when ~predfn - (setv n it))) - n)) + (with-gensyms [n] + `(let [[~n None]] + (ap-each ~lst (none? ~n) + (when ~predfn + (setv ~n it))) + ~n))) (defmacro ap-reduce [form lst &optional [initial-value None]] diff --git a/tests/native_tests/contrib/anaphoric.hy b/tests/native_tests/contrib/anaphoric.hy index 3d67e82..50281fa 100644 --- a/tests/native_tests/contrib/anaphoric.hy +++ b/tests/native_tests/contrib/anaphoric.hy @@ -87,12 +87,14 @@ (defn test-ap-first [] "NATIVE: testing anaphoric first" (assert-equal (ap-first (> it 5) (range 10)) 6) - (assert-equal (ap-first (even? it) [1 2 3 4]) 2)) + (assert-equal (ap-first (even? it) [1 2 3 4]) 2) + (assert-equal (ap-first (> it 10) (range 10)) None)) (defn test-ap-last [] "NATIVE: testing anaphoric last" (assert-equal (ap-last (> it 5) (range 10)) 9) - (assert-equal (ap-last (even? it) [1 2 3 4]) 4)) + (assert-equal (ap-last (even? it) [1 2 3 4]) 4) + (assert-equal (ap-last (> it 10) (range 10)) None)) (defn test-ap-reduce [] "NATIVE: testing anaphoric reduce" From 8e173937c358e3f53415b3df8ff163a3f524f6a5 Mon Sep 17 00:00:00 2001 From: James King Date: Fri, 16 May 2014 12:58:57 -0400 Subject: [PATCH 5/9] Add shadow.hy to core This new core module allows us to shadow the builtin Python operators so they may be passed to sequence functions that expect functions: => (map / [1 2 3 4 5]) [1.0, 0.5, 0.3333333333333333, 0.25] --- hy/core/__init__.py | 3 +- hy/core/language.hy | 19 ++++++----- hy/core/shadow.hy | 61 ++++++++++++++++++++++++++++++++++++ tests/native_tests/shadow.hy | 41 ++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 hy/core/shadow.hy create mode 100644 tests/native_tests/shadow.hy diff --git a/hy/core/__init__.py b/hy/core/__init__.py index d5349f3..be885ce 100644 --- a/hy/core/__init__.py +++ b/hy/core/__init__.py @@ -1,3 +1,4 @@ STDLIB = [ - "hy.core.language" + "hy.core.language", + "hy.core.shadow" ] diff --git a/hy/core/language.hy b/hy/core/language.hy index 262a45a..fe921b7 100644 --- a/hy/core/language.hy +++ b/hy/core/language.hy @@ -92,7 +92,8 @@ (setv map itertools.imap) (setv zip itertools.izip) (setv range xrange) - (setv input raw_input)) + (setv input raw_input) + (setv reduce reduce)) (do (setv reduce functools.reduce) (setv filterfalse itertools.filterfalse) @@ -331,10 +332,12 @@ (_numeric_check n) (= n 0)) -(def *exports* '[butlast calling-module-name coll? cons cons? cycle dec distinct - disassemble drop drop-while empty? even? every? first filter - flatten float? gensym identity inc instance? integer - integer? integer-char? iterable? iterate iterator? keyword? - list* macroexpand macroexpand-1 map neg? nil? none? nth - numeric? odd? pos? range remove repeat repeatedly rest second - some string string? take take-nth take-while zero? zip zipwith]) +(def *exports* '[butlast calling-module-name coll? cons cons? cycle + dec distinct disassemble drop drop-while empty? even? + every? first filter flatten float? gensym identity + inc instance? integer integer? integer-char? + iterable? iterate iterator? keyword? list* + macroexpand macroexpand-1 map neg? nil? none? nth + numeric? odd? pos? range remove repeat repeatedly + rest reduce second some string string? take take-nth + take-while zero? zip zipwith]) diff --git a/hy/core/shadow.hy b/hy/core/shadow.hy new file mode 100644 index 0000000..f59f0ca --- /dev/null +++ b/hy/core/shadow.hy @@ -0,0 +1,61 @@ +;; Copyright (c) 2014 Paul Tagliamonte +;; Copyright (c) 2014 James King + +;; Permission is hereby granted, free of charge, to any person obtaining a +;; copy of this software and associated documentation files (the "Software"), +;; to deal in the Software without restriction, including without limitation +;; the rights to use, copy, modify, merge, publish, distribute, sublicense, +;; and/or sell copies of the Software, and to permit persons to whom the +;; Software is furnished to do so, subject to the following conditions: + +;; The above copyright notice and this permission notice shall be included in +;; all copies or substantial portions of the Software. + +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +;; DEALINGS IN THE SOFTWARE. + +;;;; Hy shadow functions + +(import operator) + + +(defn + [&rest args] + "Shadow + operator for when we need to import / map it against something" + (if (= (len args) 0) + 0 + (sum args))) ; shortcut here. + + +(defn - [&rest args] + "Shadow - operator for when we need to import / map it against something" + (let [[count (len args)]] + (if (= count 0) + (raise (TypeError "Need at least 1 argument to subtract")) + (if (= count 1) + (- (get args 0)) + (reduce operator.sub args))))) + + +(defn * [&rest args] + "Shadow * operator for when we need to import / map it against something" + (if (= (len args) 0) + 1 ; identity + (reduce operator.mul args))) + + +(defn / [&rest args] + "Shadow / operator for when we need to import / map it against something" + (let [[count (len args)]] + (if (= count 0) + (raise (TypeError "Need at least 1 argument to divide")) + (if (= count 1) + (operator.truediv 1 (get args 0)) + (reduce operator.truediv args))))) + + +(setv *exports* ['+ '- '* '/]) diff --git a/tests/native_tests/shadow.hy b/tests/native_tests/shadow.hy new file mode 100644 index 0000000..362ac50 --- /dev/null +++ b/tests/native_tests/shadow.hy @@ -0,0 +1,41 @@ + + +(defn test-shadow-addition [] + "NATIVE: test shadow addition" + (let [[x +]] + (assert (= (x) 0)) + (assert (= (x 1 2 3 4) 10)) + (assert (= (x 1 2 3 4 5) 15)))) + + +(defn test-shadow-subtraction [] + "NATIVE: test shadow subtraction" + (let [[x -]] + (assert (try + (x) + (catch [TypeError] True) + (else (throw AssertionError)))) + (assert (= (x 1) -1)) + (assert (= (x 2 1) 1)) + (assert (= (x 2 1 1) 0)))) + + +(defn test-shadow-multiplication [] + "NATIVE: test shadow multiplication" + (let [[x *]] + (assert (= (x) 1)) + (assert (= (x 3) 3)) + (assert (= (x 3 3) 9)))) + + +(defn test-shadow-division [] + "NATIVE: test shadow division" + (let [[x /]] + (assert (try + (x) + (catch [TypeError] True) + (else (throw AssertionError)))) + (assert (= (x 1) 1)) + (assert (= (x 8 2) 4)) + (assert (= (x 8 2 2) 2)) + (assert (= (x 8 2 2 2) 1)))) From 277028cdd5990e5cde4a1bfdfe3434fdcec842a2 Mon Sep 17 00:00:00 2001 From: James King Date: Tue, 3 Jun 2014 21:36:49 -0400 Subject: [PATCH 6/9] Remove HyLambdaListKeyword from the parser It's not a syntactic element and doesn't belong in the parser. Parsing lambda lists is now handled by the compiler alone. --- hy/__init__.py | 1 - hy/compiler.py | 9 +++----- hy/lex/parser.py | 4 ---- hy/models/lambdalist.py | 39 ---------------------------------- tests/lex/test_lex.py | 9 -------- tests/native_tests/language.hy | 7 ++++++ tests/native_tests/quote.hy | 6 ------ 7 files changed, 10 insertions(+), 65 deletions(-) delete mode 100644 hy/models/lambdalist.py diff --git a/hy/__init__.py b/hy/__init__.py index f3a26a1..120a9d9 100644 --- a/hy/__init__.py +++ b/hy/__init__.py @@ -23,7 +23,6 @@ from hy.version import __version__, __appname__ # NOQA from hy.models.expression import HyExpression # NOQA -from hy.models.lambdalist import HyLambdaListKeyword # NOQA from hy.models.integer import HyInteger # NOQA from hy.models.keyword import HyKeyword # NOQA from hy.models.complex import HyComplex # NOQA diff --git a/hy/compiler.py b/hy/compiler.py index fa44676..d177138 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -24,7 +24,6 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. -from hy.models.lambdalist import HyLambdaListKeyword from hy.models.expression import HyExpression from hy.models.keyword import HyKeyword from hy.models.integer import HyInteger @@ -430,6 +429,7 @@ class HyASTCompiler(object): def _parse_lambda_list(self, exprs): """ Return FunctionDef parameter values from lambda list.""" + ll_keywords = ("&rest", "&optional", "&key", "&kwargs") ret = Result() args = [] defaults = [] @@ -439,10 +439,7 @@ class HyASTCompiler(object): for expr in exprs: - if isinstance(expr, HyLambdaListKeyword): - if expr not in expr._valid_types: - raise HyTypeError(expr, "{0} is not a valid " - "lambda-keyword.".format(repr(expr))) + if expr in ll_keywords: if expr == "&rest" and lambda_keyword is None: lambda_keyword = expr elif expr == "&optional": @@ -616,7 +613,7 @@ class HyASTCompiler(object): return imports, ret.replace(form), False - elif isinstance(form, (HySymbol, HyLambdaListKeyword)): + elif isinstance(form, HySymbol): return imports, HyExpression([HySymbol(name), HyString(form)]).replace(form), False diff --git a/hy/lex/parser.py b/hy/lex/parser.py index 0f3a96a..30793f2 100644 --- a/hy/lex/parser.py +++ b/hy/lex/parser.py @@ -30,7 +30,6 @@ from hy.models.expression import HyExpression from hy.models.float import HyFloat from hy.models.integer import HyInteger from hy.models.keyword import HyKeyword -from hy.models.lambdalist import HyLambdaListKeyword from hy.models.list import HyList from hy.models.string import HyString from hy.models.symbol import HySymbol @@ -271,9 +270,6 @@ def t_identifier(p): if obj.startswith(":"): return HyKeyword(obj) - if obj.startswith("&"): - return HyLambdaListKeyword(obj) - def mangle(p): if p.startswith("*") and p.endswith("*") and p not in ("*", "**"): p = p[1:-1].upper() diff --git a/hy/models/lambdalist.py b/hy/models/lambdalist.py deleted file mode 100644 index 1a38066..0000000 --- a/hy/models/lambdalist.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright (c) 2013 James King -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. - -from hy.models.string import HyString - - -class HyLambdaListKeyword(HyString): - """ - Hy LambdaListKeyword. Demarcates arguments in an argument list. - - (defun my-fun (x &rest xs &optional (foo "default string"))) - - becomes: - - def my_fun(x, *xs, foo="default string"): - pass - """ - - _valid_types = ["&rest", "&optional", "&key", "&kwargs"] - - def __init__(self, string): - self += string diff --git a/tests/lex/test_lex.py b/tests/lex/test_lex.py index 7ab30e5..ebf0404 100644 --- a/tests/lex/test_lex.py +++ b/tests/lex/test_lex.py @@ -21,7 +21,6 @@ from hy.models.expression import HyExpression from hy.models.integer import HyInteger -from hy.models.lambdalist import HyLambdaListKeyword from hy.models.float import HyFloat from hy.models.complex import HyComplex from hy.models.symbol import HySymbol @@ -85,14 +84,6 @@ def test_lex_expression_integer(): assert objs == [HyExpression([HySymbol("foo"), HyInteger(2)])] -def test_lex_lambda_list_keyword(): - """ Make sure expressions can produce lambda list keywords """ - objs = tokenize("(x &rest xs)") - assert objs == [HyExpression([HySymbol("x"), - HyLambdaListKeyword("&rest"), - HySymbol("xs")])] - - def test_lex_symbols(): """ Make sure that symbols are valid expressions""" objs = tokenize("foo ") diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index 8bff65c..b655ba6 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -975,3 +975,10 @@ "NATIVE: test keyword quoting magic" (assert (= :foo "\ufdd0:foo")) (assert (= `:foo "\ufdd0:foo"))) + +(defn test-only-parse-lambda-list-in-defn [] + "NATIVE: test lambda lists are only parsed in defn" + (try + (foo [&rest spam] 1) + (catch [NameError] True) + (else (raise AssertionError)))) diff --git a/tests/native_tests/quote.hy b/tests/native_tests/quote.hy index 8900578..c1c0859 100644 --- a/tests/native_tests/quote.hy +++ b/tests/native_tests/quote.hy @@ -77,12 +77,6 @@ (assert (= q qq))) -(defn test-quote-lambdalistkeyword [] - "NATIVE: test quoting lambda list keywords" - (setv opt (quote &optional)) - (assert (isinstance opt hy.HyLambdaListKeyword)) - (assert (= (str opt) "&optional"))) - (defmacro doodle [&rest body] `(do ~@body)) From fb7c7e5794c1b4956528bd8e0a0f50f4305f8c3b Mon Sep 17 00:00:00 2001 From: Bob Tolbert Date: Sun, 22 Jun 2014 10:19:56 -0600 Subject: [PATCH 7/9] Fix #607, remove return from try when there is a generator inside Added the contains_yield attr to 'try' when the body it is wrapping contains 'yeild'. Should also address #600 and #563 --- hy/compiler.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hy/compiler.py b/hy/compiler.py index d177138..a4297e8 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -1,10 +1,10 @@ # -*- encoding: utf-8 -*- # -# Copyright (c) 2013 Paul Tagliamonte +# Copyright (c) 2013, 2014 Paul Tagliamonte # Copyright (c) 2013 Julien Danjou # Copyright (c) 2013 Nicolas Dandrimont # Copyright (c) 2013 James King -# Copyright (c) 2013 Bob Tolbert +# Copyright (c) 2013, 2014 Bob Tolbert # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -704,7 +704,8 @@ class HyASTCompiler(object): lineno=expr.start_line, col_offset=expr.start_column) - returnable = Result(expr=expr_name, temp_variables=[expr_name, name]) + returnable = Result(expr=expr_name, temp_variables=[expr_name, name], + contains_yield=body.contains_yield) body += ast.Assign(targets=[name], value=body.force_expr, From ea5eba59165df74b36351c1acd54126e08b2ff5a Mon Sep 17 00:00:00 2001 From: Bob Tolbert Date: Sun, 22 Jun 2014 14:33:39 -0600 Subject: [PATCH 8/9] Second part of the fix for yield inside a try-finally As noted in #600, Python 3 allows a return inside a generator method, that raises a StopIteration and passes the return value inside the 'value' attr of the exception. To allow this behaviour we simple set 'contains_yield' while compiling 'yield', thus allowing a return statement, but only for Python 3. Then when compiling the try-except, we check for contains_yield to decide whether there will be a return. This allows code like: (defn gen [] (yield 3) "goodbye") to compile in both Py2 and Py3. The return value is simply ignored in Python 2. hy2py in Python 2 gives: def g(): yield 3L u'goodbye' while hy2py in Python 3 gives: def g(): yield 3 return 'goodbye' Turns out return in yield started in Python 3.3 --- hy/compiler.py | 5 ++++- tests/native_tests/language.hy | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/hy/compiler.py b/hy/compiler.py index a4297e8..a82d89e 100644 --- a/hy/compiler.py +++ b/hy/compiler.py @@ -997,7 +997,10 @@ class HyASTCompiler(object): @checkargs(max=1) def compile_yield_expression(self, expr): expr.pop(0) - ret = Result(contains_yield=True) + if PY33: + ret = Result(contains_yield=False) + else: + ret = Result(contains_yield=True) value = None if expr != []: diff --git a/tests/native_tests/language.hy b/tests/native_tests/language.hy index b655ba6..7db5320 100644 --- a/tests/native_tests/language.hy +++ b/tests/native_tests/language.hy @@ -3,6 +3,7 @@ [sys :as systest]) (import sys) +(import [hy._compat [PY33 PY34]]) (defn test-sys-argv [] "NATIVE: test sys.argv" @@ -448,6 +449,29 @@ (for [y (gen)] (setv ret (+ ret y))) (assert (= ret 10))) +(defn test-yield-with-return [] + "NATIVE: test yield with return" + (defn gen [] (yield 3) "goodbye") + (if PY33 + (do (setv gg (gen)) + (assert (= 3 (next gg))) + (try (next gg) + (except [e StopIteration] (assert (hasattr e "value")) + (assert (= (getattr e "value") "goodbye"))))) + (do (setv gg (gen)) + (assert (= 3 (next gg))) + (try (next gg) + (except [e StopIteration] (assert (not (hasattr e "value")))))))) + + +(defn test-yield-in-try [] + "NATIVE: test yield in try" + (defn gen [] + (let [[x 1]] + (try (yield x) + (finally (print x))))) + (setv output (list (gen))) + (assert (= [1] output))) (defn test-first [] "NATIVE: test firsty things" From bd661a3ae8fa54c21166d3601e83d5a0c15d7967 Mon Sep 17 00:00:00 2001 From: Bob Tolbert Date: Sun, 22 Jun 2014 18:08:04 -0600 Subject: [PATCH 9/9] Fix hy2py output on Windows/Python 3 If there are Unicode symbols in the hy2py output (as in tests/native_test/language.hy) and the user is on Windows, and the user is using Python3 and the user doesn't have an appropriate codepage in the terminal for Unicode, then hy2py will fail at encoding the output. This fix makes sure that if encoding fails, the bytes output is shown instead of throwing an exception and failing completely. This also allows the hy2py tests to pass on Windows. If the user does activate an appropriate codepage, for example, chcp 65001 then the Unicode output will show correctly. Converted printing code to small function to eliminate some duplicate code --- hy/cmdline.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/hy/cmdline.py b/hy/cmdline.py index a29d901..51417b2 100644 --- a/hy/cmdline.py +++ b/hy/cmdline.py @@ -47,7 +47,7 @@ from hy.models.expression import HyExpression from hy.models.string import HyString from hy.models.symbol import HySymbol -from hy._compat import builtins +from hy._compat import builtins, PY3 class HyQuitter(object): @@ -327,6 +327,7 @@ def hyc_main(): # entry point for cmd line script "hy2py" def hy2py_main(): + import platform module_name = "" options = dict(prog="hy2py", usage="%(prog)s [options] FILE", @@ -349,17 +350,42 @@ def hy2py_main(): if options.with_source: hst = import_file_to_hst(options.args[0]) - print(hst) + # need special printing on Windows in case the + # codepage doesn't support utf-8 characters + if PY3 and platform.system() == "Windows": + for h in hst: + try: + print(h) + except: + print(str(h).encode('utf-8')) + else: + print(hst) print() print() _ast = import_file_to_ast(options.args[0], module_name) if options.with_ast: - print(astor.dump(_ast)) + if PY3 and platform.system() == "Windows": + _print_for_windows(astor.dump(_ast)) + else: + print(astor.dump(_ast)) print() print() if not options.without_python: - print(astor.codegen.to_source(_ast)) + if PY3 and platform.system() == "Windows": + _print_for_windows(astor.codegen.to_source(_ast)) + else: + print(astor.codegen.to_source(_ast)) parser.exit(0) + + +# need special printing on Windows in case the +# codepage doesn't support utf-8 characters +def _print_for_windows(src): + for line in src.split("\n"): + try: + print(line) + except: + print(line.encode('utf-8'))