X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fjrw%2FEnvironment.java;h=57642e649ec6a7809dcc5e9c9a04f2c29b0a9ef2;hb=HEAD;hp=f0f1347bdd59f954c27a1339064662610f5aa703;hpb=3e20c35c34d322ae53cf9feb005e6404f9cdc0a5;p=jrw.git diff --git a/src/jrw/Environment.java b/src/jrw/Environment.java index f0f1347..57642e6 100644 --- a/src/jrw/Environment.java +++ b/src/jrw/Environment.java @@ -1,15 +1,85 @@ package jrw; import java.util.*; +import java.util.function.*; public class Environment { - public static Map dispatch(Handler handler, Request req) { - while(true) { - try { - return(handler.handle(req)); - } catch(Restart r) { - handler = r; + public static final Environment root = new Environment(null); + 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()); + } }