gensym in Hy
Simple implementation of gensym in Hy. Returns a new HySymbol. Usable in macros like: (defmacro nif [expr pos zero neg] (let [[g (gensym)]] `(let [[~g ~expr]] (cond [(pos? ~g) ~pos] [(zero? ~g) ~zero] [(neg? ~g) ~neg])))) This addresses all the general comments about (gensym), and doesn't try to implement "auto-gensym" yet. But clearly the macro approach instead of the pre-processor approach (as described in the letoverlambda (http://letoverlambda.com/index.cl/guest/chap3.html#sec_5) is the way to go
This commit is contained in:
parent
c11b231c1c
commit
f5d88bb108
@ -23,6 +23,7 @@
|
||||
;;;; to make functional programming slightly easier.
|
||||
;;;;
|
||||
|
||||
|
||||
(import [hy._compat [long-type]]) ; long for python2, int for python3
|
||||
|
||||
(defn _numeric-check [x]
|
||||
@ -91,6 +92,20 @@
|
||||
"Return True if x is float"
|
||||
(isinstance x float))
|
||||
|
||||
(import [threading [Lock]])
|
||||
(setv _gensym_counter 1234)
|
||||
(setv _gensym_lock (Lock))
|
||||
|
||||
(defn gensym [&optional [g "G"]]
|
||||
(let [[new_symbol None]]
|
||||
(global _gensym_counter)
|
||||
(global _gensym_lock)
|
||||
(.acquire _gensym_lock)
|
||||
(try (do (setv _gensym_counter (inc _gensym_counter))
|
||||
(setv new_symbol (HySymbol (.format ":{0}_{1}" g _gensym_counter))))
|
||||
(finally (.release _gensym_lock)))
|
||||
new_symbol))
|
||||
|
||||
(defn inc [n]
|
||||
"Increment n by 1"
|
||||
(_numeric-check n)
|
||||
@ -223,6 +238,7 @@
|
||||
(= n 0))
|
||||
|
||||
(def *exports* '[cycle dec distinct drop drop-while empty? even? filter float?
|
||||
gensym
|
||||
inc instance? integer integer? iterable? iterate iterator? neg?
|
||||
none? nth numeric? odd? pos? remove repeat repeatedly second
|
||||
string string? take take-nth take-while zero?])
|
||||
|
@ -113,6 +113,6 @@
|
||||
|
||||
(defmacro yield-from [iterable]
|
||||
"Yield all the items from iterable"
|
||||
;; TODO: this needs some gensym love
|
||||
`(foreach [_hy_yield_from_x ~iterable]
|
||||
(yield _hy_yield_from_x)))
|
||||
(let [[x (gensym)]]
|
||||
`(foreach [~x ~iterable]
|
||||
(yield ~x))))
|
||||
|
@ -141,6 +141,18 @@
|
||||
(assert-true (float? -3.2))
|
||||
(assert-false (float? "foo")))
|
||||
|
||||
(defn test-gensym []
|
||||
"NATIVE: testing the gensym function"
|
||||
(import [hy.models.symbol [HySymbol]])
|
||||
(setv s1 (gensym))
|
||||
(assert (isinstance s1 HySymbol))
|
||||
(assert (= 0 (.find s1 ":G_")))
|
||||
(setv s2 (gensym "xx"))
|
||||
(setv s3 (gensym "xx"))
|
||||
(assert (= 0 (.find s2 ":xx_")))
|
||||
(assert (not (= s2 s3)))
|
||||
(assert (not (= (str s2) (str s3)))))
|
||||
|
||||
(defn test-inc []
|
||||
"NATIVE: testing the inc function"
|
||||
(assert-equal 3 (inc 2))
|
||||
@ -393,3 +405,4 @@
|
||||
(assert-equal res [None None])
|
||||
(setv res (list (take-while (fn [x] (not (none? x))) [1 2 3 4 None 5 6 None 7])))
|
||||
(assert-equal res [1 2 3 4]))
|
||||
|
||||
|
@ -94,7 +94,6 @@
|
||||
(assert initialized)
|
||||
(assert (test-initialized))
|
||||
|
||||
|
||||
(defn test-yield-from []
|
||||
"NATIVE: testing yield from"
|
||||
(defn yield-from-test []
|
||||
@ -107,3 +106,28 @@
|
||||
(import sys)
|
||||
(assert (= (get sys.version_info 0)
|
||||
(if-python2 2 3))))
|
||||
|
||||
(defn test-gensym-in-macros []
|
||||
(import ast)
|
||||
(import [astor.codegen [to_source]])
|
||||
(import [hy.importer [import_buffer_to_ast]])
|
||||
(setv macro1 "(defmacro nif [expr pos zero neg]
|
||||
(let [[g (gensym)]]
|
||||
`(let [[~g ~expr]]
|
||||
(cond [(pos? ~g) ~pos]
|
||||
[(zero? ~g) ~zero]
|
||||
[(neg? ~g) ~neg]))))
|
||||
|
||||
(print (nif (inc -1) 1 0 -1))
|
||||
")
|
||||
;; expand the macro twice, should use a different
|
||||
;; gensym each time
|
||||
(setv _ast1 (import_buffer_to_ast macro1 "foo"))
|
||||
(setv _ast2 (import_buffer_to_ast macro1 "foo"))
|
||||
(setv s1 (to_source _ast1))
|
||||
(setv s2 (to_source _ast2))
|
||||
;; and make sure there is something new that starts with :G_
|
||||
(assert (in ":G_" s1))
|
||||
(assert (in ":G_" s2))
|
||||
;; but make sure the two don't match each other
|
||||
(assert (not (= s1 s2))))
|
||||
|
Loading…
Reference in New Issue
Block a user