Commit | Line | Data |
---|---|---|
4e6705bd FT |
1 | package jrw; |
2 | ||
3 | import java.util.*; | |
4 | import java.util.function.*; | |
5 | ||
6 | public class Environment { | |
14326e72 | 7 | public static final Environment root = new Environment(null); |
4e6705bd FT |
8 | private static final ThreadLocal<Environment> current = new ThreadLocal<>(); |
9 | public final Environment parent; | |
10 | private Map<Variable<?>, Object> data = Collections.emptyMap(); | |
11 | ||
12 | public static class Variable<T> { | |
13 | private final Supplier<? extends T> ival; | |
14 | private T rval; | |
15 | private boolean inited; | |
16 | ||
17 | public Variable(Supplier<? extends T> ival) { | |
18 | this.ival = ival; | |
19 | } | |
20 | ||
21 | @SuppressWarnings("unchecked") | |
22 | public T get() { | |
23 | for(Environment env = current(); env != null; env = env.parent) { | |
24 | Map<Variable<?>, Object> data = env.data; | |
25 | if(data.containsKey(this)) | |
26 | return((T)data.get(this)); | |
27 | } | |
28 | if(!inited) { | |
29 | synchronized(this) { | |
30 | if(!inited) { | |
31 | rval = (this.ival == null) ? null : this.ival.get(); | |
32 | inited = true; | |
33 | } | |
34 | } | |
35 | } | |
36 | return(rval); | |
37 | } | |
38 | } | |
39 | ||
40 | public Environment(Environment parent) { | |
41 | this.parent = parent; | |
42 | } | |
43 | ||
44 | public Environment() { | |
45 | this(current()); | |
46 | } | |
47 | ||
48 | public <T> void set(Variable<T> var, T val) { | |
49 | synchronized(this) { | |
50 | Map<Variable<?>, Object> data = new IdentityHashMap<>(this.data); | |
51 | data.put(var, val); | |
52 | this.data = data; | |
53 | } | |
54 | } | |
55 | ||
56 | public <T> void clear(Variable<T> var, T val) { | |
57 | synchronized(this) { | |
58 | Map<Variable<?>, Object> data = new IdentityHashMap<>(this.data); | |
59 | data.remove(var); | |
60 | this.data = data; | |
61 | } | |
62 | } | |
63 | ||
64 | public static Environment current() { | |
65 | Environment ret = current.get(); | |
66 | return((ret == null) ? root : ret); | |
67 | } | |
68 | ||
69 | public class Frame implements AutoCloseable { | |
70 | private final Environment prev; | |
71 | ||
72 | private Frame() { | |
73 | this.prev = current.get(); | |
74 | current.set(Environment.this); | |
75 | } | |
76 | ||
77 | public void close() { | |
78 | current.set(prev); | |
79 | } | |
80 | } | |
81 | ||
82 | public Frame frame() { | |
83 | return(new Frame()); | |
84 | } | |
85 | } |