Fixed root environment bug.
[jrw.git] / src / jrw / Environment.java
CommitLineData
4e6705bd
FT
1package jrw;
2
3import java.util.*;
4import java.util.function.*;
5
6public 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}