commit
0de8557fb5
@ -305,6 +305,7 @@ as can nested let forms.
|
||||
(macro-error bindings "let bindings must be paired"))
|
||||
(setv g!let (gensym 'let)
|
||||
replacements (OrderedDict)
|
||||
keys []
|
||||
values [])
|
||||
(defn expander [symbol]
|
||||
(.get replacements symbol symbol))
|
||||
@ -313,63 +314,15 @@ as can nested let forms.
|
||||
(macro-error k "bind targets must be symbols")
|
||||
(if (in '. k)
|
||||
(macro-error k "binding target may not contain a dot")))
|
||||
(.append values (symbolexpand (macroexpand-all v &name) expander))
|
||||
(assoc replacements k `(get ~g!let ~(name k))))
|
||||
(.append values (symbolexpand (macroexpand-all v &name)
|
||||
expander))
|
||||
(.append keys `(get ~g!let ~(name k)))
|
||||
(assoc replacements k (last keys)))
|
||||
`(do
|
||||
(setv ~g!let {}
|
||||
~@(interleave (.values replacements) values))
|
||||
~@(symbolexpand (macroexpand-all body &name) expander)))
|
||||
~@(interleave keys values))
|
||||
~@(symbolexpand (macroexpand-all body &name)
|
||||
expander)))
|
||||
|
||||
;; (defmacro macrolet [])
|
||||
|
||||
#_[special cases for let
|
||||
;; Symbols containing a dot should be converted to this form.
|
||||
;; attrs should not get expanded,
|
||||
;; but [] lookups should.
|
||||
'.',
|
||||
|
||||
;;; can shadow let bindings with Python locals
|
||||
;; protect its bindings for the lexical scope of its body.
|
||||
'fn',
|
||||
'fn*',
|
||||
;; protect as bindings for the lexical scope of its body
|
||||
'except',
|
||||
|
||||
;;; changes scope of named variables
|
||||
;; protect the variables they name for the lexical scope of their container
|
||||
'global',
|
||||
'nonlocal',
|
||||
;; should we provide a protect form?
|
||||
;; it's an anaphor only valid in a `let` body.
|
||||
;; this would make the named variables python-scoped in its body
|
||||
;; expands to a do
|
||||
'protect',
|
||||
|
||||
;;; quoted variables must not be expanded.
|
||||
;; but unprotected, unquoted variables must be.
|
||||
'quasiquote',
|
||||
'quote',
|
||||
'unquote',
|
||||
'unquote-splice',
|
||||
|
||||
;;;; deferred
|
||||
|
||||
;; should really only exist at toplevel. Ignore until someone complains?
|
||||
;; raise an error? treat like fn?
|
||||
;; should probably be implemented as macros in terms of fn/setv anyway.
|
||||
'defmacro',
|
||||
'deftag',
|
||||
|
||||
;;; create Python-scoped variables. It's probably hard to avoid this.
|
||||
;; Best just doc this behavior for now.
|
||||
;; we can't avoid clobbering enclosing python scope, unless we use a gensym,
|
||||
;; but that corrupts '__name__'.
|
||||
;; It could be set later, but that could mess up metaclasses!
|
||||
;; Should the class name update let variables too?
|
||||
'defclass',
|
||||
;; should this update let variables?
|
||||
;; it could be done with gensym/setv.
|
||||
'import',
|
||||
|
||||
;; I don't understand these. Ignore until someone complains?
|
||||
'eval_and_compile', 'eval_when_compile', 'require',]
|
||||
|
@ -64,16 +64,16 @@
|
||||
b "b")
|
||||
(let [a "x"
|
||||
b "y"]
|
||||
(assert (= (+ a b)
|
||||
"xy"))
|
||||
(let [a "z"]
|
||||
(assert (= (+ a b)
|
||||
"zy")))
|
||||
;; let-shadowed variable doesn't get clobbered.
|
||||
(assert (= (+ a b)
|
||||
"xy")))
|
||||
(assert (= (+ a b)
|
||||
"xy"))
|
||||
(let [a "z"]
|
||||
(assert (= (+ a b)
|
||||
"zy")))
|
||||
;; let-shadowed variable doesn't get clobbered.
|
||||
(assert (= (+ a b)
|
||||
"xy")))
|
||||
(let [q "q"]
|
||||
(assert (= q "q")))
|
||||
(assert (= q "q")))
|
||||
(assert (= a "a"))
|
||||
(assert (= b "b"))
|
||||
(assert (in "a" (.keys (vars))))
|
||||
@ -85,86 +85,86 @@
|
||||
(let [a "a"
|
||||
b "b"
|
||||
ab (+ a b)]
|
||||
(assert (= ab "ab"))
|
||||
(let [c "c"
|
||||
abc (+ ab c)]
|
||||
(assert (= abc "abc")))))
|
||||
(assert (= ab "ab"))
|
||||
(let [c "c"
|
||||
abc (+ ab c)]
|
||||
(assert (= abc "abc")))))
|
||||
|
||||
(defn test-let-early []
|
||||
(setv a "a")
|
||||
(let [q (+ a "x")
|
||||
a 2 ; should not affect q
|
||||
b 3]
|
||||
(assert (= q "ax"))
|
||||
(let [q (* a b)
|
||||
a (+ a b)
|
||||
b (* a b)]
|
||||
(assert (= q 6))
|
||||
(assert (= a 5))
|
||||
(assert (= b 15))))
|
||||
(assert (= q "ax"))
|
||||
(let [q (* a b)
|
||||
a (+ a b)
|
||||
b (* a b)]
|
||||
(assert (= q 6))
|
||||
(assert (= a 5))
|
||||
(assert (= b 15))))
|
||||
(assert (= a "a")))
|
||||
|
||||
(defn test-let-special []
|
||||
;; special forms in function position still work as normal
|
||||
(let [, 1]
|
||||
(assert (= (, , ,)
|
||||
(, 1 1)))))
|
||||
(assert (= (, , ,)
|
||||
(, 1 1)))))
|
||||
|
||||
(defn test-let-quasiquote []
|
||||
(setv a-symbol 'a)
|
||||
(let [a "x"]
|
||||
(assert (= a "x"))
|
||||
(assert (= 'a a-symbol))
|
||||
(assert (= `a a-symbol))
|
||||
(assert (= `(foo ~a)
|
||||
'(foo "x")))
|
||||
(assert (= `(foo `(bar a ~a ~~a))
|
||||
'(foo `(bar a ~a ~"x"))))
|
||||
(assert (= `(foo ~@[a])
|
||||
'(foo "x")))
|
||||
(assert (= `(foo `(bar [a] ~@[a] ~@~[a 'a `a] ~~@[a]))
|
||||
'(foo `(bar [a] ~@[a] ~@["x" a a] ~"x"))))))
|
||||
(assert (= a "x"))
|
||||
(assert (= 'a a-symbol))
|
||||
(assert (= `a a-symbol))
|
||||
(assert (= `(foo ~a)
|
||||
'(foo "x")))
|
||||
(assert (= `(foo `(bar a ~a ~~a))
|
||||
'(foo `(bar a ~a ~"x"))))
|
||||
(assert (= `(foo ~@[a])
|
||||
'(foo "x")))
|
||||
(assert (= `(foo `(bar [a] ~@[a] ~@~[a 'a `a] ~~@[a]))
|
||||
'(foo `(bar [a] ~@[a] ~@["x" a a] ~"x"))))))
|
||||
|
||||
(defn test-let-except []
|
||||
(let [foo 42
|
||||
bar 33]
|
||||
(assert (= foo 42))
|
||||
(try
|
||||
(do
|
||||
1/0
|
||||
(assert False))
|
||||
(except [foo Exception]
|
||||
;; let bindings should work in except block
|
||||
(assert (= bar 33))
|
||||
;; but exception bindings can shadow let bindings
|
||||
(assert (instance? Exception foo))))
|
||||
;; let binding did not get clobbered.
|
||||
(assert (= foo 42))))
|
||||
(assert (= foo 42))
|
||||
(try
|
||||
(do
|
||||
1/0
|
||||
(assert False))
|
||||
(except [foo Exception]
|
||||
;; let bindings should work in except block
|
||||
(assert (= bar 33))
|
||||
;; but exception bindings can shadow let bindings
|
||||
(assert (instance? Exception foo))))
|
||||
;; let binding did not get clobbered.
|
||||
(assert (= foo 42))))
|
||||
|
||||
(defn test-let-mutation []
|
||||
(setv foo 42)
|
||||
(setv error False)
|
||||
(let [foo 12
|
||||
bar 13]
|
||||
(assert (= foo 12))
|
||||
(setv foo 14)
|
||||
(assert (= foo 14))
|
||||
(del foo)
|
||||
;; deleting a let binding should not affect others
|
||||
(assert (= bar 13))
|
||||
(try
|
||||
;; foo=42 is still shadowed, but the let binding was deleted.
|
||||
(do
|
||||
foo
|
||||
(assert False))
|
||||
(except [le LookupError]
|
||||
(setv error le)))
|
||||
(setv foo 16)
|
||||
(assert (= foo 16))
|
||||
(setv [foo bar baz] [1 2 3])
|
||||
(assert (= foo 1))
|
||||
(assert (= bar 2))
|
||||
(assert (= baz 3)))
|
||||
(assert (= foo 12))
|
||||
(setv foo 14)
|
||||
(assert (= foo 14))
|
||||
(del foo)
|
||||
;; deleting a let binding should not affect others
|
||||
(assert (= bar 13))
|
||||
(try
|
||||
;; foo=42 is still shadowed, but the let binding was deleted.
|
||||
(do
|
||||
foo
|
||||
(assert False))
|
||||
(except [le LookupError]
|
||||
(setv error le)))
|
||||
(setv foo 16)
|
||||
(assert (= foo 16))
|
||||
(setv [foo bar baz] [1 2 3])
|
||||
(assert (= foo 1))
|
||||
(assert (= bar 2))
|
||||
(assert (= baz 3)))
|
||||
(assert error)
|
||||
(assert (= foo 42))
|
||||
(assert (= baz 3)))
|
||||
@ -172,40 +172,40 @@
|
||||
(defn test-let-break []
|
||||
(for [x (range 3)]
|
||||
(let [done (odd? x)]
|
||||
(if done (break))))
|
||||
(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]))))
|
||||
(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)
|
||||
(let [a 1
|
||||
b 2]
|
||||
(yield a)
|
||||
(yield b)))
|
||||
(yield a)
|
||||
(yield b)))
|
||||
(assert (= (tuple (grind))
|
||||
(, 0 1 2))))
|
||||
|
||||
(defn test-let-return []
|
||||
(defn get-answer []
|
||||
(let [answer 42]
|
||||
(return answer)))
|
||||
(return answer)))
|
||||
(assert (= (get-answer)
|
||||
42)))
|
||||
|
||||
(defn test-let-import []
|
||||
(let [types 6]
|
||||
;; imports don't fail, even if using a let-bound name
|
||||
(import types)
|
||||
;; let-bound name is not affected
|
||||
(assert (= types 6)))
|
||||
;; imports don't fail, even if using a let-bound name
|
||||
(import types)
|
||||
;; let-bound name is not affected
|
||||
(assert (= types 6)))
|
||||
;; import happened in Python scope.
|
||||
(assert (in "types" (vars)))
|
||||
(assert (instance? types.ModuleType types)))
|
||||
@ -213,13 +213,13 @@
|
||||
(defn test-let-defclass []
|
||||
(let [Foo 42
|
||||
quux object]
|
||||
;; 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)
|
||||
;; quux is not local
|
||||
(setv quux "quux"))
|
||||
(assert (= quux "quux")))
|
||||
;; 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)
|
||||
;; 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)))
|
||||
|
||||
@ -229,82 +229,82 @@
|
||||
(let [a 1
|
||||
b []
|
||||
bar (fn [])]
|
||||
(setv bar.a 13)
|
||||
(assert (= bar.a 13))
|
||||
(setv (. bar a) 14)
|
||||
(assert (= bar.a 14))
|
||||
(assert (= a 1))
|
||||
(assert (= b []))
|
||||
;; method syntax not affected
|
||||
(.append b 2)
|
||||
(assert (= b [2]))
|
||||
;; attrs access is not affected
|
||||
(assert (= foo.a 42))
|
||||
(assert (= (. foo a)
|
||||
42))
|
||||
;; but indexing is
|
||||
(assert (= (. [1 2 3]
|
||||
[a])
|
||||
2))))
|
||||
(setv bar.a 13)
|
||||
(assert (= bar.a 13))
|
||||
(setv (. bar a) 14)
|
||||
(assert (= bar.a 14))
|
||||
(assert (= a 1))
|
||||
(assert (= b []))
|
||||
;; method syntax not affected
|
||||
(.append b 2)
|
||||
(assert (= b [2]))
|
||||
;; attrs access is not affected
|
||||
(assert (= foo.a 42))
|
||||
(assert (= (. foo a)
|
||||
42))
|
||||
;; but indexing is
|
||||
(assert (= (. [1 2 3]
|
||||
[a])
|
||||
2))))
|
||||
|
||||
(defn test-let-positional []
|
||||
(let [a 0
|
||||
b 1
|
||||
c 2]
|
||||
(defn foo [a b]
|
||||
(, a b c))
|
||||
(assert (= (foo 100 200)
|
||||
(, 100 200 2)))
|
||||
(setv c 300)
|
||||
(assert (= (foo 1000 2000)
|
||||
(, 1000 2000 300)))
|
||||
(assert (= a 0))
|
||||
(assert (= b 1))
|
||||
(assert (= c 300))))
|
||||
(defn foo [a b]
|
||||
(, a b c))
|
||||
(assert (= (foo 100 200)
|
||||
(, 100 200 2)))
|
||||
(setv c 300)
|
||||
(assert (= (foo 1000 2000)
|
||||
(, 1000 2000 300)))
|
||||
(assert (= a 0))
|
||||
(assert (= b 1))
|
||||
(assert (= c 300))))
|
||||
|
||||
(defn test-let-rest []
|
||||
(let [xs 6
|
||||
a 88
|
||||
c 64
|
||||
&rest 12]
|
||||
(defn foo [a b &rest xs]
|
||||
(-= a 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 64 [3 4 42])))
|
||||
(assert (= xs 6))
|
||||
(assert (= c 64))
|
||||
(assert (= a 88))))
|
||||
(defn foo [a b &rest xs]
|
||||
(-= a 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 64 [3 4 42])))
|
||||
(assert (= xs 6))
|
||||
(assert (= c 64))
|
||||
(assert (= a 88))))
|
||||
|
||||
(defn test-let-kwargs []
|
||||
(let [kws 6
|
||||
&kwargs 13]
|
||||
(defn foo [&kwargs kws]
|
||||
(, &kwargs kws))
|
||||
(assert (= kws 6))
|
||||
(assert (= (foo :a 1)
|
||||
(, 13 {"a" 1})))))
|
||||
(defn foo [&kwargs kws]
|
||||
(, &kwargs kws))
|
||||
(assert (= kws 6))
|
||||
(assert (= (foo :a 1)
|
||||
(, 13 {"a" 1})))))
|
||||
|
||||
(defn test-let-optional []
|
||||
(let [a 1
|
||||
b 6
|
||||
d 2]
|
||||
(defn foo [&optional [a a] b [c d]]
|
||||
(, a b c))
|
||||
(assert (= (foo)
|
||||
(, 1 None 2)))
|
||||
(assert (= (foo 10 20 30)
|
||||
(, 10 20 30)))))
|
||||
(defn foo [&optional [a a] b [c d]]
|
||||
(, a b c))
|
||||
(assert (= (foo)
|
||||
(, 1 None 2)))
|
||||
(assert (= (foo 10 20 30)
|
||||
(, 10 20 30)))))
|
||||
|
||||
(defn test-let-closure []
|
||||
(let [count 0]
|
||||
(defn +count [&optional [x 1]]
|
||||
(+= count x)
|
||||
count))
|
||||
(defn +count [&optional [x 1]]
|
||||
(+= count x)
|
||||
count))
|
||||
;; let bindings can still exist outside of a let body
|
||||
(assert (= 1 (+count)))
|
||||
(assert (= 2 (+count)))
|
||||
@ -323,9 +323,18 @@
|
||||
(let [a 1
|
||||
b (triple a)
|
||||
c (ap-triple)]
|
||||
(assert (= (triple a)
|
||||
3))
|
||||
(assert (= (ap-triple)
|
||||
3))
|
||||
(assert (= b 3))
|
||||
(assert (= c 3))))
|
||||
(assert (= (triple a)
|
||||
3))
|
||||
(assert (= (ap-triple)
|
||||
3))
|
||||
(assert (= b 3))
|
||||
(assert (= c 3))))
|
||||
|
||||
(defn test-let-rebind []
|
||||
(let [x "foo"
|
||||
y "bar"
|
||||
x (+ x y)
|
||||
y (+ y x)
|
||||
x (+ x x)]
|
||||
(assert (= x "foobarfoobar"))
|
||||
(assert (= y "barfoobar"))))
|
||||
|
Loading…
x
Reference in New Issue
Block a user