X-Git-Url: http://www.dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fjrw%2FEnvironment.java;fp=src%2Fjrw%2FEnvironment.java;h=a93b149648b5721d7fd13ee6c8cdffe702adeeec;hb=4e6705bd163a303c3ffb5e306162cbd7660b8dd8;hp=0000000000000000000000000000000000000000;hpb=d3d92d6cb3b182798cf7cfb8dcd265b0727a663a;p=jrw.git diff --git a/src/jrw/Environment.java b/src/jrw/Environment.java new file mode 100644 index 0000000..a93b149 --- /dev/null +++ b/src/jrw/Environment.java @@ -0,0 +1,85 @@ +package jrw; + +import java.util.*; +import java.util.function.*; + +public class Environment { + public static final Environment root = new Environment(); + private static final ThreadLocal current = new ThreadLocal<>(); + public final Environment parent; + private Map, Object> data = Collections.emptyMap(); + + public static class Variable { + private final Supplier ival; + private T rval; + private boolean inited; + + public Variable(Supplier ival) { + this.ival = ival; + } + + @SuppressWarnings("unchecked") + public T get() { + for(Environment env = current(); env != null; env = env.parent) { + Map, Object> data = env.data; + if(data.containsKey(this)) + return((T)data.get(this)); + } + if(!inited) { + synchronized(this) { + if(!inited) { + rval = (this.ival == null) ? null : this.ival.get(); + inited = true; + } + } + } + return(rval); + } + } + + public Environment(Environment parent) { + this.parent = parent; + } + + public Environment() { + this(current()); + } + + public void set(Variable var, T val) { + synchronized(this) { + Map, Object> data = new IdentityHashMap<>(this.data); + data.put(var, val); + this.data = data; + } + } + + public void clear(Variable var, T val) { + synchronized(this) { + Map, Object> data = new IdentityHashMap<>(this.data); + data.remove(var); + this.data = data; + } + } + + public static Environment current() { + Environment ret = current.get(); + return((ret == null) ? root : ret); + } + + public class Frame implements AutoCloseable { + private final Environment prev; + + private Frame() { + this.prev = current.get(); + current.set(Environment.this); + } + + public void close() { + current.set(prev); + } + } + + public Frame frame() { + return(new Frame()); + } +}