Commit | Line | Data |
---|---|---|
e88ff533 FT |
1 | import threading, weakref |
2 | ||
3 | __all__ = ["environment", "root", "get", "binding", "var"] | |
4 | ||
5 | class stack(object): | |
6 | __slots__ = ["env", "prev"] | |
7 | def __init__(self, env, prev): | |
8 | self.env = env | |
9 | self.prev = prev | |
10 | ||
11 | class environment(object): | |
12 | __slots__ = ["parent", "map"] | |
9bc70dab | 13 | def __init__(self, parent=None): |
8d285e43 | 14 | self.parent = parent |
e88ff533 FT |
15 | self.map = weakref.WeakKeyDictionary() |
16 | ||
17 | def get(self, var): | |
18 | if var in self.map: | |
19 | return self.map[var] | |
20 | if self.parent is None: | |
21 | return None | |
22 | return self.parent.get(var) | |
23 | ||
24 | def set(self, var, val): | |
25 | self.map[var] = val | |
26 | ||
27 | def __enter__(self): | |
28 | cur = context.env | |
29 | context.prev = stack(cur, context.prev) | |
30 | context.env = self | |
31 | return None | |
32 | ||
33 | def __exit__(self, *excinfo): | |
34 | prev = context.prev | |
35 | if prev is None: | |
36 | raise Exception("Unbalanced __enter__/__exit__") | |
37 | context.env = prev.env | |
38 | context.prev = prev.prev | |
39 | return False | |
40 | ||
41 | root = environment() | |
42 | ||
43 | class context(threading.local): | |
44 | env = root | |
45 | prev = None | |
46 | context = context() | |
47 | ||
48 | def get(): | |
49 | return context.env | |
50 | ||
51 | class binding(object): | |
52 | __slots__ = ["bindings"] | |
53 | def __init__(self, bindings): | |
54 | if isinstance(bindings, dict): | |
55 | bindings = bindings.items() | |
56 | self.bindings = bindings | |
57 | ||
58 | def __enter__(self): | |
59 | cur = context.env | |
60 | new = environment(cur) | |
61 | for var, val in self.bindings: | |
62 | new.map[var] = val | |
63 | context.prev = stack(cur, context.prev) | |
64 | context.env = new | |
65 | return None | |
66 | ||
67 | def __exit__(self, *excinfo): | |
68 | prev = context.prev | |
69 | if prev is None: | |
70 | raise Exception("Unbalanced __enter__/__exit__") | |
71 | context.env = prev.env | |
72 | context.prev = prev.prev | |
73 | return False | |
74 | ||
75 | class var(object): | |
76 | __slots__ = ["__weakref__"] | |
9bc70dab | 77 | def __init__(self, default=None): |
e88ff533 FT |
78 | if default is not None: |
79 | root.map[self] = default | |
80 | ||
81 | @property | |
82 | def val(self): | |
83 | return context.env.get(self) | |
84 | ||
85 | def binding(self, val): | |
86 | return binding([(self, val)]) |