Skip to content

Commit f49c4bd

Browse files
authored
Add several new namespace functions (#405)
* Add several new namespace functions * Use a threading.local object rather than an Atom * Small binding macro test * Fix some tests * Tests * Remove unused type ignore comments for updated MyPy * Undo that * Add additional test case * Use 3.6 base for now * Remove useless returns * Fix error in Test run * Throw RTE for pop-without-corresponding-push * Additional runtime coverage * lol
1 parent 107716f commit f49c4bd

File tree

12 files changed

+694
-264
lines changed

12 files changed

+694
-264
lines changed

src/basilisp/core.lpy

Lines changed: 132 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,6 +1813,24 @@
18131813
(str n ".")))]
18141814
`(~s ~@args))))
18151815

1816+
(defn push-thread-bindings
1817+
"Takes a map of Var/value pairs and applies the given value to the Var in the
1818+
current thread.
1819+
1820+
This call should be accompanied with a pop-thread-bindings call in a
1821+
try/finally block.
1822+
1823+
This function is a very low level function and its use is discouraged in favor
1824+
of a higher level construct like the binding macros."
1825+
[bindings]
1826+
(basilisp.lang.runtime/push-thread-bindings bindings))
1827+
1828+
(defn pop-thread-bindings
1829+
"Pop thread bindings set by a corresponding call to push-thread-bindings. This
1830+
should not be called without a prior call to push-thread-bindings."
1831+
[]
1832+
(basilisp.lang.runtime/pop-thread-bindings))
1833+
18161834
(defmacro binding
18171835
"Establish thread-local bindings for the vars given. The bindings are guaranteed
18181836
to clear once execution passes outside the scope of this block."
@@ -1823,18 +1841,18 @@
18231841
(throw
18241842
(ex-info "Expected an even number of bindings"
18251843
{:bindings bindings})))
1826-
(let [vvar (first bindings)
1827-
val (second bindings)]
1844+
(let [var-bindings (reduce (fn [v pair]
1845+
(let [vvar (first pair)
1846+
vval (second pair)]
1847+
(conj v `(var ~vvar) vval)))
1848+
[]
1849+
(partition 2 bindings))]
18281850
`(try
18291851
(do
1830-
(. (var ~vvar) (~'push-bindings ~val))
1831-
~@(if (nthnext bindings 2)
1832-
[(concat
1833-
(list 'binding (vec (nthrest bindings 2)))
1834-
body)]
1835-
body))
1852+
(push-thread-bindings (hash-map ~@var-bindings))
1853+
~@body)
18361854
(finally
1837-
(. (var ~vvar) ~'pop-bindings)))))
1855+
(pop-thread-bindings)))))
18381856

18391857
(import* [time :as py-time])
18401858

@@ -2194,10 +2212,61 @@
21942212
ctx
21952213
module)))
21962214

2215+
;;;;;;;;;;;;;;;;;;;
2216+
;; Var Utilities ;;
2217+
;;;;;;;;;;;;;;;;;;;
2218+
2219+
(defn alter-var-root
2220+
"Atomically alter the Var root by calling (apply f root args) and setting
2221+
the root as the result."
2222+
[v f & args]
2223+
(apply-method v alter-root f args))
2224+
2225+
(defn find-var
2226+
"Return the Var named by namespace-qualified sym if it exists, or nil otherwise."
2227+
[sym]
2228+
(basilisp.lang.runtime.Var/find sym))
2229+
2230+
(defn thread-bound?
2231+
"Return true if vars are thread-bound, which implies that a set! will succeed.
2232+
Returns true if no vars are given."
2233+
[& vars]
2234+
(loop [v (first vars)
2235+
r (rest vars)]
2236+
(if-not v
2237+
true
2238+
(if (.-is-thread-bound v)
2239+
(recur (first r) (rest r))
2240+
false))))
2241+
2242+
(defn var-get
2243+
"Return the value inside the Var. Return thread local bindings if they exist,
2244+
otherwise, return the root binding."
2245+
[v]
2246+
@v)
2247+
2248+
(defn var-set
2249+
"Set the binding of the Var. Must be thread-local."
2250+
[v val]
2251+
(if (thread-bound? v)
2252+
(set! (.-value v) val)
2253+
(throw
2254+
(ex-info "Cannot set non-thread-bound Var binding" {:var v}))))
2255+
21972256
;;;;;;;;;;;;;;;;;;;;;;;;;
21982257
;; Namespace Utilities ;;
21992258
;;;;;;;;;;;;;;;;;;;;;;;;;
22002259

2260+
(defn all-ns
2261+
"Return a sequence of all namespaces."
2262+
[]
2263+
(vals @basilisp.lang.runtime.Namespace/-NAMESPACES))
2264+
2265+
(defn find-ns
2266+
"Return the namespace named by sym if it exists, or nil otherwise."
2267+
[sym]
2268+
(basilisp.lang.runtime.Namespace/get sym))
2269+
22012270
(defn the-ns
22022271
"If v is a symbol, return the Namespace named by that symbol if it
22032272
exists. If v is a Namespace, return it. Otherwise, throw an exception."
@@ -2215,11 +2284,35 @@
22152284
{:value v
22162285
:type (python/type v)}))))
22172286

2287+
(defn intern
2288+
"Finds or creates a Var in ns (which is either a namespace or symbol),
2289+
setting the root binding to val, if provided. The namespace must exist.
2290+
Return the Var."
2291+
([ns name]
2292+
(let [ns (the-ns ns)
2293+
v (basilisp.lang.runtime/Var ns name)]
2294+
(.intern ns v)))
2295+
([ns name val]
2296+
(let [ns (the-ns ns)
2297+
v (basilisp.lang.runtime/Var ns name)]
2298+
(set! (.-root v) val)
2299+
(.intern ns v))))
2300+
22182301
(defn create-ns
22192302
"Create a Namespace with the name ns-sym or return the existing one
22202303
if it already exists."
22212304
[ns-sym]
2222-
(.get-or-create basilisp.lang.runtime/Namespace ns-sym))
2305+
(basilisp.lang.runtime.Namespace/get-or-create ns-sym))
2306+
2307+
(defn remove-ns
2308+
"Remove the namespace named by the symbol."
2309+
[ns-sym]
2310+
(basilisp.lang.runtime.Namespace/remove ns-sym))
2311+
2312+
(defn ns-name
2313+
"Return the name of the namespace, a symbol."
2314+
[ns]
2315+
(.-name ns))
22232316

22242317
(defn ns-aliases
22252318
"Return a map of Basilisp namespaces which are aliased in the current
@@ -2232,27 +2325,37 @@
22322325
m
22332326
(assoc m alias namespace))))
22342327
{}
2235-
(.-aliases ns)))
2328+
(.-aliases (the-ns ns))))
22362329

22372330
(defn ns-imports
22382331
"Return a set of Python modules which are imported in the current
22392332
namespace."
22402333
[ns]
2241-
(.-imports ns))
2334+
(.-imports (the-ns ns)))
22422335

22432336
(defn ns-interns
22442337
"Return a map of symbols to Vars which are interned in the current
22452338
namespace."
22462339
[ns]
2247-
(.-interns ns))
2340+
(.-interns (the-ns ns)))
2341+
2342+
(defn ns-unalias
2343+
"Remove the alias for the symbol sym from ns. Return nil."
2344+
[ns sym]
2345+
(.remove-alias (the-ns ns) sym))
2346+
2347+
(defn ns-unmap
2348+
"Remove the mapping for the symbol sym from ns. Return nil."
2349+
[ns sym]
2350+
(.unmap (the-ns ns) sym))
22482351

22492352
(defn ns-publics
22502353
"Return a map of symbols to public Vars which are interned in the
22512354
current namespace.
22522355

22532356
Public vars are Vars which are declared without :private metadata."
22542357
[ns]
2255-
(let [interns (ns-interns ns)]
2358+
(let [interns (ns-interns (the-ns ns))]
22562359
(if-not (seq interns)
22572360
{}
22582361
(reduce (fn [m entry]
@@ -2266,22 +2369,23 @@
22662369
"Return a map of symbols to Vars which are referred in the current
22672370
namespace."
22682371
[ns]
2269-
(.-refers ns))
2372+
(.-refers (the-ns ns)))
22702373

22712374
(defn ns-map
22722375
"Return a map of all the mapped symbols in the namespace.
22732376

22742377
Includes the return values of ns-interns and ns-refers in one map."
22752378
([] (ns-map *ns*))
22762379
([ns]
2277-
(merge
2278-
(ns-interns ns)
2279-
(ns-refers ns))))
2380+
(let [resolved-ns (the-ns ns)]
2381+
(merge
2382+
(ns-interns resolved-ns)
2383+
(ns-refers resolved-ns)))))
22802384

22812385
(defn ns-resolve
22822386
"Return the Var which will be resolved by the symbol in the given namespace."
22832387
[ns sym]
2284-
(basilisp.lang.runtime/resolve-var sym ns))
2388+
(basilisp.lang.runtime/resolve-var sym (the-ns ns)))
22852389

22862390
(defn resolve
22872391
"Return the Var which will be resolved by the symbol in the namespace currently
@@ -2339,6 +2443,14 @@
23392443
(recur (rest refers)))))]
23402444
(do-refer interns)))))
23412445

2446+
(def refer-basilisp
2447+
"Refer Vars from basilisp.core using the same filter syntax as refer."
2448+
(partial refer 'basilisp.core))
2449+
2450+
(def refer-clojure
2451+
"Compatibility layer with JVM Clojure, which points to refer-basilisp."
2452+
refer-basilisp)
2453+
23422454
(import importlib)
23432455

23442456
(defn ^:private add-refers
@@ -3333,3 +3445,4 @@
33333445
((.- ~type-name ~'create) m#))
33343446

33353447
~type-name)))
3448+

src/basilisp/importer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def _basilisp_bytecode(
4040
data = bytearray(MAGIC_NUMBER)
4141
data.extend(_w_long(mtime))
4242
data.extend(_w_long(source_size))
43-
data.extend(marshal.dumps(code)) # type: ignore
43+
data.extend(marshal.dumps(code))
4444
return data
4545

4646

@@ -77,7 +77,7 @@ def _get_basilisp_bytecode(
7777
logger.debug(message)
7878
raise ImportError(message, **exc_details) # type: ignore
7979

80-
return marshal.loads(cache_data[12:]) # type: ignore
80+
return marshal.loads(cache_data[12:])
8181

8282

8383
def _cache_from_source(path: str) -> str:

src/basilisp/lang/interfaces.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,7 @@ def disj(self, *elems: T) -> "IPersistentSet[T]":
141141
raise NotImplementedError()
142142

143143

144-
# MyPy has a lot of trouble dealing with the fact that Vectors are
145-
# considered as mapping types (from int -> T) and more traditional
146-
# sequential collections since the Python supertypes signatures conflict.
147-
# Below, we override the supertype signatures to select the signature
148-
# we specifically want to appear, but MyPy still complains. For now,
149-
# we will simply silence MyPy.
150-
class IPersistentVector( # type: ignore
151-
Sequence[T], IAssociative[int, T], IPersistentStack[T]
152-
):
144+
class IPersistentVector(Sequence[T], IAssociative[int, T], IPersistentStack[T]):
153145
__slots__ = ()
154146

155147
@abstractmethod

src/basilisp/lang/list.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
T = TypeVar("T")
1111

1212

13-
class List(IMeta, ISeq[T], IPersistentList[T]): # type: ignore
13+
class List(IMeta, ISeq[T], IPersistentList[T]):
1414
"""Basilisp List. Delegates internally to a pyrsistent.PList object.
1515
1616
Do not instantiate directly. Instead use the l() and list() factory

src/basilisp/lang/map.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
V = TypeVar("V")
2020

2121

22-
class MapEntry(IMapEntry[K, V], Vector[Union[K, V]]): # type: ignore
22+
class MapEntry(IMapEntry[K, V], Vector[Union[K, V]]):
2323
__slots__ = ()
2424

2525
def __init__(self, wrapped: "PVector[Union[K, V]]") -> None:

0 commit comments

Comments
 (0)