1
1
import itertools
2
2
import threading
3
+ import types
3
4
from typing import Optional
4
5
5
6
from functional import seq
19
20
_PRINT_GENERATED_PY_VAR_NAME = '*print-generated-python*'
20
21
21
22
23
+ def _new_module (name : str , doc = None ) -> types .ModuleType :
24
+ """Create a new empty Basilisp Python module.
25
+
26
+ Modules are created for each Namespace when it is created."""
27
+ mod = types .ModuleType (name , doc = doc )
28
+ mod .__loader__ = None
29
+ mod .__package__ = None
30
+ mod .__spec__ = None
31
+ mod .__basilisp_bootstrapped__ = False # type: ignore
32
+ return mod
33
+
34
+
35
+ class RuntimeException (Exception ):
36
+ pass
37
+
38
+
22
39
class Var :
23
40
__slots__ = ('_name' , '_ns' , '_root' , '_dynamic' , '_is_bound' , '_tl' , '_meta' )
24
41
@@ -118,14 +135,14 @@ def intern_unbound(ns: sym.Symbol,
118
135
return var
119
136
120
137
@staticmethod
121
- def find_in_ns (ns_sym : sym .Symbol , name_sym : sym .Symbol ) -> "Var" :
138
+ def find_in_ns (ns_sym : sym .Symbol , name_sym : sym .Symbol ) -> "Optional[ Var] " :
122
139
"""Return the value current bound to the name `name_sym` in the namespace
123
140
specified by `ns_sym`."""
124
141
ns = Namespace .get_or_create (ns_sym )
125
142
return ns .find (name_sym )
126
143
127
144
@staticmethod
128
- def find (ns_qualified_sym : sym .Symbol ) -> "Var" :
145
+ def find (ns_qualified_sym : sym .Symbol ) -> "Optional[ Var] " :
129
146
"""Return the value currently bound to the name in the namespace specified
130
147
by `ns_qualified_sym`."""
131
148
ns = Maybe (ns_qualified_sym .ns ).or_else_raise (
@@ -175,8 +192,9 @@ class Namespace:
175
192
176
193
__slots__ = ('_name' , '_module' , '_mappings' , '_refers' , '_aliases' , '_imports' )
177
194
178
- def __init__ (self , name : sym .Symbol ) -> None :
195
+ def __init__ (self , name : sym .Symbol , module : types . ModuleType = None ) -> None :
179
196
self ._name = name
197
+ self ._module = Maybe (module ).or_else (lambda : _new_module (name ._as_python_sym ))
180
198
self ._mappings : atom .Atom = atom .Atom (pmap ())
181
199
self ._aliases : atom .Atom = atom .Atom (pmap ())
182
200
self ._imports : atom .Atom = atom .Atom (pset (Namespace .DEFAULT_IMPORTS .deref ()))
@@ -194,6 +212,18 @@ def add_default_import(cls, module: str):
194
212
def name (self ) -> str :
195
213
return self ._name .name
196
214
215
+ @property
216
+ def module (self ):
217
+ return self ._module
218
+
219
+ @module .setter
220
+ def module (self , m : types .ModuleType ):
221
+ """Override the Python module for this Namespace.
222
+
223
+ This should only be done by basilisp.importer code to make sure the
224
+ correct module is generated for `basilisp.core`."""
225
+ self ._module = m
226
+
197
227
@property
198
228
def aliases (self ) -> PMap :
199
229
return self ._aliases .deref ()
@@ -239,7 +269,7 @@ def _intern(m: PMap, sym: sym.Symbol, new_var: Var,
239
269
return m .set (sym , new_var )
240
270
return m
241
271
242
- def find (self , sym : sym .Symbol ) -> Var :
272
+ def find (self , sym : sym .Symbol ) -> Optional [ Var ] :
243
273
"""Find Vars mapped by the given Symbol input or None if no Vars are
244
274
mapped by that Symbol."""
245
275
return self .mappings .get (sym , None )
@@ -273,25 +303,26 @@ def __import_core_mappings(ns_cache: PMap,
273
303
@staticmethod
274
304
def __get_or_create (ns_cache : PMap ,
275
305
name : sym .Symbol ,
306
+ module : types .ModuleType = None ,
276
307
core_ns_name = _CORE_NS ) -> PMap :
277
308
"""Private swap function used by `get_or_create` to atomically swap
278
309
the new namespace map into the global cache."""
279
310
ns = ns_cache .get (name , None )
280
311
if ns is not None :
281
312
return ns_cache
282
- new_ns = Namespace (name )
313
+ new_ns = Namespace (name , module = module )
283
314
if name .name != core_ns_name :
284
315
Namespace .__import_core_mappings (
285
316
ns_cache , new_ns , core_ns_name = core_ns_name )
286
317
return ns_cache .set (name , new_ns )
287
318
288
319
@classmethod
289
- def get_or_create (cls , name : sym .Symbol ) -> "Namespace" :
320
+ def get_or_create (cls , name : sym .Symbol , module : types . ModuleType = None ) -> "Namespace" :
290
321
"""Get the namespace bound to the symbol `name` in the global namespace
291
322
cache, creating it if it does not exist.
292
323
293
324
Return the namespace."""
294
- return cls ._NAMESPACES .swap (Namespace .__get_or_create , name )[name ]
325
+ return cls ._NAMESPACES .swap (Namespace .__get_or_create , name , module = module )[name ]
295
326
296
327
@classmethod
297
328
def remove (cls , name : sym .Symbol ) -> Optional ["Namespace" ]:
@@ -412,12 +443,14 @@ def init_ns_var(which_ns: str = _CORE_NS,
412
443
413
444
414
445
def set_current_ns (ns_name : str ,
446
+ module : types .ModuleType = None ,
415
447
ns_var_name : str = _NS_VAR_NAME ,
416
448
ns_var_ns : str = _NS_VAR_NS ) -> Var :
417
449
"""Set the value of the dynamic variable `*ns*` in the current thread."""
418
450
symbol = sym .Symbol (ns_name )
419
- ns = Namespace .get_or_create (symbol )
420
- ns_var = Var .find (sym .Symbol (ns_var_name , ns = ns_var_ns ))
451
+ ns = Namespace .get_or_create (symbol , module = module )
452
+ ns_var = Maybe (Var .find (sym .Symbol (ns_var_name , ns = ns_var_ns ))) \
453
+ .or_else_raise (lambda : RuntimeException (f"Dynamic Var { sym .Symbol (ns_var_name , ns = ns_var_ns )} not bound!" ))
421
454
ns_var .push_bindings (ns )
422
455
return ns_var
423
456
@@ -426,7 +459,9 @@ def get_current_ns(ns_var_name: str = _NS_VAR_NAME,
426
459
ns_var_ns : str = _NS_VAR_NS ) -> Namespace :
427
460
"""Get the value of the dynamic variable `*ns*` in the current thread."""
428
461
ns_sym = sym .Symbol (ns_var_name , ns = ns_var_ns )
429
- ns : Namespace = Var .find (ns_sym ).value
462
+ ns : Namespace = Maybe (Var .find (ns_sym )) \
463
+ .map (lambda v : v .value ) \
464
+ .or_else_raise (lambda : RuntimeException (f"Dynamic Var { ns_sym } not bound!" ))
430
465
return ns
431
466
432
467
@@ -451,7 +486,9 @@ def print_generated_python(var_name: str = _PRINT_GENERATED_PY_VAR_NAME,
451
486
core_ns_name : str = _CORE_NS ) -> bool :
452
487
"""Return the value of the `*print-generated-python*` dynamic variable."""
453
488
ns_sym = sym .Symbol (var_name , ns = core_ns_name )
454
- return Var .find (ns_sym ).value
489
+ return Maybe (Var .find (ns_sym )) \
490
+ .map (lambda v : v .value ) \
491
+ .or_else_raise (lambda : RuntimeException (f"Dynamic Var { ns_sym } not bound!" ))
455
492
456
493
457
494
def bootstrap (ns_var_name : str = _NS_VAR_NAME ,
@@ -460,13 +497,15 @@ def bootstrap(ns_var_name: str = _NS_VAR_NAME,
460
497
express with the very minimal lisp environment."""
461
498
core_ns_sym = sym .symbol (core_ns_name )
462
499
ns_var_sym = sym .symbol (ns_var_name , ns = core_ns_name )
463
- __NS = Var .find (ns_var_sym )
500
+ __NS = Maybe (Var .find (ns_var_sym )) \
501
+ .or_else_raise (lambda : RuntimeException (f"Dynamic Var { ns_var_sym } not bound!" ))
464
502
465
503
def set_BANG_ (var_sym : sym .Symbol , expr ):
466
504
ns = Maybe (var_sym .ns ).or_else (lambda : __NS .value .name )
467
505
name = var_sym .name
468
506
469
- v = Var .find (sym .symbol (name , ns = ns ))
507
+ v = Maybe (Var .find (sym .symbol (name , ns = ns ))) \
508
+ .or_else_raise (lambda : RuntimeException (f"Var { ns_var_sym } not bound!" ))
470
509
v .value = expr
471
510
return expr
472
511
0 commit comments