From ba898aa8d8ef616bf36b0cf0b1c0ca6382ccf057 Mon Sep 17 00:00:00 2001 From: gilch Date: Mon, 18 Sep 2017 13:50:41 -0600 Subject: [PATCH] support (nonlocal) in `let` --- hy/contrib/walk.hy | 9 ++---- tests/native_tests/contrib/walk.hy | 36 +++++++++++++++-------- tests/native_tests/py3_only_tests.hy | 43 ++++++++++++++++++++++------ 3 files changed, 61 insertions(+), 27 deletions(-) diff --git a/hy/contrib/walk.hy b/hy/contrib/walk.hy index 73e556c..2d2a202 100644 --- a/hy/contrib/walk.hy +++ b/hy/contrib/walk.hy @@ -161,7 +161,7 @@ as can nested let forms. ;; else expand if applicable (if (and (in form bound-symbols) (not-in form protected-symbols)) - `(get ~g!let ~(name form)) + (HySymbol (+ g!let "::" form)) form))] ;; We have to treat special forms differently. ;; Quotation should suppress symbol expansion, @@ -232,15 +232,10 @@ as can nested let forms. [True form])) (expand-symbols #{} `(do - (setv ~g!let {} - ~@bindings) + (setv ~@bindings) ~@body))) #_[special cases for let - ;; this means we can't use a list for our let scope - ;; we're using a dict instead. - 'del', - ;; Symbols containing a dot should be converted to this form. ;; attrs should not get expanded, ;; but [] lookups should. diff --git a/tests/native_tests/contrib/walk.hy b/tests/native_tests/contrib/walk.hy index caf9151..1a7b4e3 100644 --- a/tests/native_tests/contrib/walk.hy +++ b/tests/native_tests/contrib/walk.hy @@ -135,8 +135,8 @@ (do foo (assert False)) - (except [ke LookupError] - (setv error ke))) + (except [ne NameError] + (setv error ne))) (setv foo 16) (assert (= foo 16)) (setv [foo bar baz] [1 2 3]) @@ -153,6 +153,14 @@ (if done (break)))) (assert (= x 1))) +(defn test-let-continue [] + (let [foo []] + (for [x (range 10)] + (let [odd (odd? x)] + (if odd (continue)) + (.append foo x))) + (assert (= foo [0 2 4 6 8])))) + (defn test-let-yield [] (defn grind [] (yield 0) @@ -231,16 +239,15 @@ &rest 12] (defn foo [a b &rest xs] (-= a 1) - (-= c 1) (setv xs (list xs)) (.append xs 42) (, &rest a b c xs)) (assert (= xs 6)) (assert (= a 88)) (assert (= (foo 1 2 3 4) - (, 12 0 2 63 [3 4 42]))) + (, 12 0 2 64 [3 4 42]))) (assert (= xs 6)) - (assert (= c 63)) + (assert (= c 64)) (assert (= a 88)))) (defn test-let-kwargs [] @@ -275,12 +282,17 @@ (, 10 20 30))) (assert (= (, a b d) (, 1 6 2))))) -;; TODO -;; test-let-continue -;; test-let-closure -;; test-let-global + +(defn test-let-closure [] + (let [count [0]] + (defn +count [&optional [x 1]] + (+= (get count 0) x) + (get count 0))) + ;; let bindings can still exist outside of a let body + (assert (= 1 (+count))) + (assert (= 2 (+count))) + (assert (= 42 (+count 40)))) ;; TODO -;;; Python 3 only -;; test-let-nonlocal -;; test-let-kwonly +;; test-let-global + diff --git a/tests/native_tests/py3_only_tests.hy b/tests/native_tests/py3_only_tests.hy index 84b8053..90331fd 100644 --- a/tests/native_tests/py3_only_tests.hy +++ b/tests/native_tests/py3_only_tests.hy @@ -8,8 +8,8 @@ (defn test-exception-cause [] (try (raise ValueError :from NameError) - (except [e [ValueError]] - (assert (= (type (. e __cause__)) NameError))))) + (except [e [ValueError]] + (assert (= (type (. e __cause__)) NameError))))) (defn test-kwonly [] @@ -21,8 +21,8 @@ ;; keyword-only without default ... (defn kwonly-foo-no-default [&kwonly foo] foo) (setv attempt-to-omit-default (try - (kwonly-foo-no-default) - (except [e [Exception]] e))) + (kwonly-foo-no-default) + (except [e [Exception]] e))) ;; works (assert (= (kwonly-foo-no-default :foo "quux") "quux")) ;; raises TypeError with appropriate message if not supplied @@ -64,9 +64,36 @@ (assert 0)) (defn yield-from-test [] (for* [i (range 3)] - (yield i)) + (yield i)) (try - (yield-from (yield-from-subgenerator-test)) - (except [e AssertionError] - (yield 4)))) + (yield-from (yield-from-subgenerator-test)) + (except [e AssertionError] + (yield 4)))) (assert (= (list (yield-from-test)) [0 1 2 1 2 3 4]))) + +(require [hy.contrib.walk [let]]) +(defn test-let-nonlocal [] + (let [a 88 + c 64] + (defn foo [a b] + (nonlocal c) + (-= a 1) + (-= c 1) + (, a b c)) + (assert (= a 88)) + (assert (= (foo 1 2) + (, 0 2 63))) + (assert (= c 63)) + (assert (= a 88)))) + +(defn test-let-optional [] + (let [a 1 + b 6 + d 2] + (defn foo [&kwonly [a a] b [c d]] + (, a b c)) + (assert (= (foo :b "b") + (, 1 "b" 2))) + (assert (= (foo :b 20 :a 10 :c 30) + (, 10 20 30))))) +