back let with dict for better defclass behavior

This commit is contained in:
gilch 2017-09-23 23:50:44 -06:00
parent 3707681056
commit e90f082baf
4 changed files with 15 additions and 50 deletions

View File

@ -224,10 +224,6 @@ Arguments in nested functions and bindings in nested ``let`` forms can shadow th
6 6
5 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, Basic assignments (e.g. ``setv``, ``+=``) will update the local variable named by a let binding,
when they assign to a let-bound name. 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, Use ``__import__`` and ``type`` (or whatever metaclass) instead,
if you must avoid this hoisting. 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* The ``let`` macro takes two parameters: a list defining *variables*
and the *body* which gets executed. *variables* is a vector of and the *body* which gets executed. *variables* is a vector of
variable and value pairs. variable and value pairs.
@ -254,4 +247,4 @@ variable and value pairs.
... (print x y)) ... (print x y))
5 6 5 6
It is an error to use a let-bound name in a ``global`` or ``nonlocal`` form.

View File

@ -74,6 +74,7 @@
(expand form)) (expand form))
;; TODO: move to hy.extra.reserved? ;; TODO: move to hy.extra.reserved?
(import hy)
(setv special-forms (list-comp k (setv special-forms (list-comp k
[k (.keys hy.compiler._compile-table)] [k (.keys hy.compiler._compile-table)]
(isinstance k hy._compat.string-types))) (isinstance k hy._compat.string-types)))
@ -246,10 +247,9 @@ Arguments without a header are under None.
(defn handle-call [self] (defn handle-call [self]
(setv head (first self.form)) (setv head (first self.form))
(if (in head '[fn fn*]) (self.handle-fn) (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 'except) (self.handle-except)
(= head ".") (self.handle-dot) (= head ".") (self.handle-dot)
(= head 'global) (self.handle-global)
(= head 'defclass) (self.handle-defclass) (= head 'defclass) (self.handle-defclass)
(= head 'quasiquote) (self.+quote) (= head 'quasiquote) (self.+quote)
;; must be checked last! ;; must be checked last!
@ -320,9 +320,10 @@ as can nested let forms.
(if (in '. k) (if (in '. k)
(macro-error k "binding target may not contain a dot"))) (macro-error k "binding target may not contain a dot")))
(.append values (symbolexpand (macroexpand-all v &name) expander)) (.append values (symbolexpand (macroexpand-all v &name) expander))
(assoc replacements k (HySymbol (+ g!let "::" k)))) (assoc replacements k `(get ~g!let ~(name k))))
`(do `(do
(setv ~@(interleave (.values replacements) values)) (setv ~g!let {}
~@(interleave (.values replacements) values))
~@(symbolexpand (macroexpand-all body &name) expander))) ~@(symbolexpand (macroexpand-all body &name) expander)))
;; (defmacro macrolet []) ;; (defmacro macrolet [])

View File

@ -158,8 +158,8 @@
(do (do
foo foo
(assert False)) (assert False))
(except [ne NameError] (except [le LookupError]
(setv error ne))) (setv error le)))
(setv foo 16) (setv foo 16)
(assert (= foo 16)) (assert (= foo 16))
(setv [foo bar baz] [1 2 3]) (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 ;; 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 (defclass Foo [quux] ; let bindings apply in inheritance list
;; let bindings apply inside class body ;; 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 ;; defclass always creates a python-scoped variable, even if it's a let binding name
(assert (= Foo.x 42))) (assert (= Foo.x 42)))
@ -307,33 +310,15 @@
(, 1 6 2))))) (, 1 6 2)))))
(defn test-let-closure [] (defn test-let-closure []
(let [count [0]] (let [count 0]
(defn +count [&optional [x 1]] (defn +count [&optional [x 1]]
(+= (get count 0) x) (+= count x)
(get count 0))) count))
;; let bindings can still exist outside of a let body ;; let bindings can still exist outside of a let body
(assert (= 1 (+count))) (assert (= 1 (+count)))
(assert (= 2 (+count))) (assert (= 2 (+count)))
(assert (= 42 (+count 40)))) (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] (defmacro triple [a]
(setv g!a (gensym a)) (setv g!a (gensym a))
`(do `(do
@ -353,4 +338,3 @@
3)) 3))
(assert (= b 3)) (assert (= b 3))
(assert (= c 3)))) (assert (= c 3))))

View File

@ -72,19 +72,6 @@
(assert (= (list (yield-from-test)) [0 1 2 1 2 3 4]))) (assert (= (list (yield-from-test)) [0 1 2 1 2 3 4])))
(require [hy.contrib.walk [let]]) (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 [] (defn test-let-optional []
(let [a 1 (let [a 1