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.
|
;;;; to make functional programming slightly easier.
|
||||||
;;;;
|
;;;;
|
||||||
|
|
||||||
|
|
||||||
(import [hy._compat [long-type]]) ; long for python2, int for python3
|
(import [hy._compat [long-type]]) ; long for python2, int for python3
|
||||||
|
|
||||||
(defn _numeric-check [x]
|
(defn _numeric-check [x]
|
||||||
@ -91,6 +92,20 @@
|
|||||||
"Return True if x is float"
|
"Return True if x is float"
|
||||||
(isinstance x 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]
|
(defn inc [n]
|
||||||
"Increment n by 1"
|
"Increment n by 1"
|
||||||
(_numeric-check n)
|
(_numeric-check n)
|
||||||
@ -223,6 +238,7 @@
|
|||||||
(= n 0))
|
(= n 0))
|
||||||
|
|
||||||
(def *exports* '[cycle dec distinct drop drop-while empty? even? filter float?
|
(def *exports* '[cycle dec distinct drop drop-while empty? even? filter float?
|
||||||
|
gensym
|
||||||
inc instance? integer integer? iterable? iterate iterator? neg?
|
inc instance? integer integer? iterable? iterate iterator? neg?
|
||||||
none? nth numeric? odd? pos? remove repeat repeatedly second
|
none? nth numeric? odd? pos? remove repeat repeatedly second
|
||||||
string string? take take-nth take-while zero?])
|
string string? take take-nth take-while zero?])
|
||||||
|
@ -113,6 +113,6 @@
|
|||||||
|
|
||||||
(defmacro yield-from [iterable]
|
(defmacro yield-from [iterable]
|
||||||
"Yield all the items from iterable"
|
"Yield all the items from iterable"
|
||||||
;; TODO: this needs some gensym love
|
(let [[x (gensym)]]
|
||||||
`(foreach [_hy_yield_from_x ~iterable]
|
`(foreach [~x ~iterable]
|
||||||
(yield _hy_yield_from_x)))
|
(yield ~x))))
|
||||||
|
@ -141,6 +141,18 @@
|
|||||||
(assert-true (float? -3.2))
|
(assert-true (float? -3.2))
|
||||||
(assert-false (float? "foo")))
|
(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 []
|
(defn test-inc []
|
||||||
"NATIVE: testing the inc function"
|
"NATIVE: testing the inc function"
|
||||||
(assert-equal 3 (inc 2))
|
(assert-equal 3 (inc 2))
|
||||||
@ -393,3 +405,4 @@
|
|||||||
(assert-equal res [None None])
|
(assert-equal res [None None])
|
||||||
(setv res (list (take-while (fn [x] (not (none? x))) [1 2 3 4 None 5 6 None 7])))
|
(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]))
|
(assert-equal res [1 2 3 4]))
|
||||||
|
|
||||||
|
@ -94,7 +94,6 @@
|
|||||||
(assert initialized)
|
(assert initialized)
|
||||||
(assert (test-initialized))
|
(assert (test-initialized))
|
||||||
|
|
||||||
|
|
||||||
(defn test-yield-from []
|
(defn test-yield-from []
|
||||||
"NATIVE: testing yield from"
|
"NATIVE: testing yield from"
|
||||||
(defn yield-from-test []
|
(defn yield-from-test []
|
||||||
@ -107,3 +106,28 @@
|
|||||||
(import sys)
|
(import sys)
|
||||||
(assert (= (get sys.version_info 0)
|
(assert (= (get sys.version_info 0)
|
||||||
(if-python2 2 3))))
|
(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