diff --git a/docs/contrib/walk.rst b/docs/contrib/walk.rst index e6044df..fe0eeea 100644 --- a/docs/contrib/walk.rst +++ b/docs/contrib/walk.rst @@ -224,10 +224,6 @@ Arguments in nested functions and bindings in nested ``let`` forms can shadow th 6 5 -The ``global`` special form changes the meaning of names to refer to the -module-level variables instead of locals, and this change still applies inside a ``let`` form, -even if a global has the same name as a let binding. - Basic assignments (e.g. ``setv``, ``+=``) will update the local variable named by a let binding, when they assign to a let-bound name. @@ -238,9 +234,6 @@ even if it shares the name of a let binding. Use ``__import__`` and ``type`` (or whatever metaclass) instead, if you must avoid this hoisting. -When used in a nested function, -nonlocal assignments to let-bound variables still require a ``nonlocal`` form. - The ``let`` macro takes two parameters: a list defining *variables* and the *body* which gets executed. *variables* is a vector of variable and value pairs. @@ -254,4 +247,4 @@ variable and value pairs. ... (print x y)) 5 6 - +It is an error to use a let-bound name in a ``global`` or ``nonlocal`` form. diff --git a/hy/contrib/walk.hy b/hy/contrib/walk.hy index 60d6eca..8106492 100644 --- a/hy/contrib/walk.hy +++ b/hy/contrib/walk.hy @@ -74,6 +74,7 @@ (expand form)) ;; TODO: move to hy.extra.reserved? +(import hy) (setv special-forms (list-comp k [k (.keys hy.compiler._compile-table)] (isinstance k hy._compat.string-types))) @@ -246,10 +247,9 @@ Arguments without a header are under None. (defn handle-call [self] (setv head (first self.form)) (if (in head '[fn fn*]) (self.handle-fn) - (in head '[import quote]) (self.handle-base) + (in head '[import require quote]) (self.handle-base) (= head 'except) (self.handle-except) (= head ".") (self.handle-dot) - (= head 'global) (self.handle-global) (= head 'defclass) (self.handle-defclass) (= head 'quasiquote) (self.+quote) ;; must be checked last! @@ -320,9 +320,10 @@ as can nested let forms. (if (in '. k) (macro-error k "binding target may not contain a dot"))) (.append values (symbolexpand (macroexpand-all v &name) expander)) - (assoc replacements k (HySymbol (+ g!let "::" k)))) + (assoc replacements k `(get ~g!let ~(name k)))) `(do - (setv ~@(interleave (.values replacements) values)) + (setv ~g!let {} + ~@(interleave (.values replacements) values)) ~@(symbolexpand (macroexpand-all body &name) expander))) ;; (defmacro macrolet []) diff --git a/tests/native_tests/contrib/walk.hy b/tests/native_tests/contrib/walk.hy index 4107ec2..689cd2a 100644 --- a/tests/native_tests/contrib/walk.hy +++ b/tests/native_tests/contrib/walk.hy @@ -158,8 +158,8 @@ (do foo (assert False)) - (except [ne NameError] - (setv error ne))) + (except [le LookupError] + (setv error le))) (setv foo 16) (assert (= foo 16)) (setv [foo bar baz] [1 2 3]) @@ -217,7 +217,10 @@ ;; the name of the class is just a symbol, even if it's a let binding (defclass Foo [quux] ; let bindings apply in inheritance list ;; let bindings apply inside class body - (setv x Foo))) + (setv x Foo) + ;; quux is not local + (setv quux "quux")) + (assert (= quux "quux"))) ;; defclass always creates a python-scoped variable, even if it's a let binding name (assert (= Foo.x 42))) @@ -307,33 +310,15 @@ (, 1 6 2))))) (defn test-let-closure [] - (let [count [0]] + (let [count 0] (defn +count [&optional [x 1]] - (+= (get count 0) x) - (get count 0))) + (+= count x) + count)) ;; let bindings can still exist outside of a let body (assert (= 1 (+count))) (assert (= 2 (+count))) (assert (= 42 (+count 40)))) -(defn test-let-global [] - (setv (get (globals) - 'let-global) - "global") - (let [let-global 1] - (assert (= let-global 1)) - (defn foo [] - (assert (= let-global 1)) - (global let-global) - (assert (= let-global "global")) - (setv let-global "mutated") - (assert (= let-global "mutated"))) - (foo) - (assert (= let-global 1)) - (assert (= (get (globals) - 'let-global) - "mutated")))) - (defmacro triple [a] (setv g!a (gensym a)) `(do @@ -353,4 +338,3 @@ 3)) (assert (= b 3)) (assert (= c 3)))) - diff --git a/tests/native_tests/py3_only_tests.hy b/tests/native_tests/py3_only_tests.hy index 90331fd..eb10ec2 100644 --- a/tests/native_tests/py3_only_tests.hy +++ b/tests/native_tests/py3_only_tests.hy @@ -72,19 +72,6 @@ (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