/* * This file is part of the Haven & Hearth game client. * Copyright (C) 2009 Fredrik Tolf <fredrik@dolda2000.com>, and * Björn Johannessen <johannessen.bjorn@gmail.com> * * Redistribution and/or modification of this file is subject to the * terms of the GNU Lesser General Public License, version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Other parts of this source tree adhere to other copying * rights. Please see the file `COPYING' in the root directory of the * source tree for details. * * A copy the GNU Lesser General Public License is distributed along * with the source tree of which this file is a part in the file * `doc/LPGL-3'. If it is missing for any reason, please see the Free * Software Foundation's website at <http://www.fsf.org/>, or write * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA */ package haven.glsl; import java.util.*; public class ValBlock { private static final ThreadLocal<Value> processing = new ThreadLocal<Value>(); private final Collection<Value> values = new LinkedList<Value>(); private final Map<Object, Value> ext = new IdentityHashMap<Object, Value>(); public interface Factory { public Value make(ValBlock vals); } public abstract class Value { public final Type type; public final Symbol name; public boolean used; public Variable var; protected Expression init; private final Collection<Value> deps = new LinkedList<Value>(); private final Collection<Value> sdeps = new LinkedList<Value>(); private final OrderList<Macro1<Expression>> mods = new OrderList<Macro1<Expression>>(); private boolean forced; public Value(Type type, Symbol name) { this.type = type; this.name = name; values.add(this); } public Value(Type type) { this(type, new Symbol.Gen()); } public void mod(Macro1<Expression> macro, int order) { mods.add(macro, order); } public abstract Expression root(); public Expression modexpr(Expression expr) { for(Macro1<Expression> mod : mods) expr = mod.expand(expr); return(expr); } protected void cons1() { processing.set(this); try { init = modexpr(root()); } finally { processing.remove(); } } protected void cons2(Block blk) { var = blk.local(type, name, init); } public Expression ref() { return(new Expression() { public Expression process(Context ctx) { if(var == null) throw(new IllegalStateException("Value reference processed before being constructed")); return(var.ref().process(ctx)); } }); } public Expression depref() { if(processing.get() == null) throw(new IllegalStateException("Dependent value reference outside construction")); processing.get().depend(this); return(ref()); } public void force() {forced = true;} public void depend(Value dep) { if(!deps.contains(dep)) deps.add(dep); } public void softdep(Value dep) { if(!sdeps.contains(dep)) sdeps.add(dep); } } public abstract class Group { private final Collection<GValue> values = new LinkedList<GValue>(); private final Collection<Value> deps = new LinkedList<Value>(); private final Collection<Value> sdeps = new LinkedList<Value>(); private int state = 0; protected abstract void cons1(); protected abstract void cons2(Block blk); public class GValue extends Value { public Expression modexpr; public GValue(Type type, Symbol name) { super(type, name); for(Value dep : Group.this.deps) depend1(dep); for(Value dep : Group.this.sdeps) softdep1(dep); Group.this.values.add(this); } public GValue(Type type) { this(type, new Symbol.Gen()); } protected void cons1() { if(state < 1) { Group.this.cons1(); state = 1; } Expression in = ref(); modexpr = modexpr(in); if(modexpr == in) modexpr = null; } protected void cons2(Block blk) { if(state < 2) { Group.this.cons2(blk); state = 2; } } public void addmods(Block blk) { if(modexpr != null) blk.add(Cons.ass(var, modexpr)); } public final Expression root() { throw(new RuntimeException("root() is not applicable for group values")); } private void depend1(Value dep) {super.depend(dep);} public void depend(Value dep) { Group.this.depend(dep); } private void softdep1(Value dep) {super.softdep(dep);} public void softdep(Value dep) { Group.this.softdep(dep); } } public void depend(Value dep) { for(GValue val : values) val.depend1(dep); } public void softdep(Value dep) { for(GValue val : values) val.softdep1(dep); } } private void use(Value val) { if(val.used) return; val.used = true; for(Value dep : val.deps) use(dep); for(Value dep : val.sdeps) { if(!dep.mods.isEmpty()) use(dep); } } private void add(List<Value> buf, List<Value> closed, Value val) { if(buf.contains(val)) return; if(closed.contains(val)) { /* XXX: Detect early in Value.depend/Value.softdep instead. */ throw(new RuntimeException("Cyclical value dependencies")); } closed.add(val); for(Value dep : val.deps) add(buf, closed, dep); for(Value dep : val.sdeps) { if(dep.used) add(buf, closed, dep); } buf.add(val); } public void cons(Block blk) { for(Value val : values) val.cons1(); for(Value val : values) { if(val.forced) use(val); } List<Value> used = new LinkedList<Value>(); List<Value> closed = new LinkedList<Value>(); for(Value val : values) { if(val.used) add(used, closed, val); } for(Value val : used) { val.used = true; val.cons2(blk); } } public Value ext(Object id, Factory f) { Value val = ext.get(id); if(val == null) ext.put(id, val = f.make(this)); return(val); } }