java/ch/wlkl/wsm/ExFactory.java

package ch.wlkl.wsm;

import static ch.wlkl.env.Env.*;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/*-------------------- abstract helpers ---------------------------------*/
/**
 * an Expression with no subExpressions
 */

/*-------------------- starting points ---------------------------------*/
class ExCF extends Ex {

    public Flow exe(Frame cf) {
        return Flow.normal(cf);
    }

    public void format(Formatter f) {
    }
}

class ExConst extends Ex {

    final Flow con;

    public ExConst(Flow pCon) {
        con = pCon;
    }

    public Flow exe(Frame cf) {
        return con;
    }

    public void format(Formatter f) {
        f.format(1, con.uString());
    }
}

class ExJFun extends Ex {

    final JFun jFun;
    final Ex[] exs;

    public ExJFun(JFun jf, Ex... e) {
        jFun = jf;
        exs = e;
    }

    @Override
    public Flow exe(Frame cf) {
        JFun jf = jFun.clone(exs.length);
        for (int ix = 0; ix < exs.length; ix++) {
            Flow f = exs[ix].exe(cf);
            if (!f.isNormal()) {
                return f;
            }
            jf.put(ix, f.u());
        }
        try {
            return Flow.normal(jf.eval());
        } catch (Exception e) {
            return Flow.thrw("ExJava jFun.doEval " + a2r("ExJava Exception: ", e));
        }
    }
    
    @Override
    public void format(Formatter f) {
        f.format(1, jFun.name);
        for (int ix=0; ix < exs.length; ix++)
            f.format(2,  exs[ix]);
    }
    
}

/*
class ExJFunDyn extends ExA {
    final private ExFactory factory;
    public ExJFunDyn(ExFactory f, Ex... e) {
        super(e);
        factory = f;
        if (e.length < 1)
            err("missing ExJFunDyn name");
    }

    @Override
    public Flow exe(Frame cf) {
        return factory.jFun(exs[0].exe(cf), this).exe(cf);
    }

    public Flow fun(Frame cf, int depth) {
        Flow f = super.fun(cf, depth);
        if (! f.isNormal())
            return f;
        ExJFunDyn n = (ExJFunDyn) f.u();
        return n.exs[0] instanceof ExConst ? factory.jFun(((ExConst)n.exs[0]).con, n) : f;
    }
} */

 /*-------------------- Maps ---------------------------------*/
class ExNew extends Ex {

    public Flow exe(Frame cf) {
        return Flow.normal(new HashMap<Object, Object>());
    }

    public void format(Formatter f) {
        f.format(1);
    }
}

class ExNF extends Ex {

    @Override
    public Flow exe(Frame cf) {
        return Flow.normal(new Frame());
    }

    public void format(Formatter f) {
        f.format(1, "newframe");
    }
}

class ExGet extends Ex {

    final Ex map, key;

    public ExGet(Ex m, Ex k) {
        map = m;
        key = k;
    }

    @Override
    public Flow exe(Frame cf) {
        Flow f = map.exe(cf);
        if (!f.isNormal()) {
            return f;
        }
        Flow k = key.exe(cf);
        if (!k.isNormal()) {
            return k;
        }
        if ((f.u() instanceof Map)) {
            Map m = (Map) (f.u());
            if (m.containsKey(k.u())) {
                return Flow.normal(m.get(k.u()));
            } else {
                return Flow.thrw("ExGet no key " + k.u() + " in map " + m);
            }
        }
        return Flow.thrw("get map " + f.u() + " not a Map");
    }

    public void format(Formatter f) {
        f.format(1, map);
        f.format(2, key);
    }
}

class ExAss extends Ex {

    final Ex map, key, val;

    public ExAss(Ex m, Ex k, Ex v) {
        map = m;
        key = k;
        val = v;
    }
    @Override
    public Flow exe(Frame cf) {
        Flow f = map.exe(cf);
        if (!f.isNormal()) {
            return f;
        }
        Flow k = key.exe(cf);
        if (!k.isNormal()) {
            return k;
        }
        Flow v = val.exe(cf);
        if (!v.isNormal()) {
            return v;
        }
        if ((f.u() instanceof Map)) {
            Map m = (Map) (f.u());
            m.put(k.u(), v.u());
            return f;
        }
        return Flow.thrw("put map " + f.u() + " not a Map");
    }

    public void format(Formatter f) {
        f.format(1, map);
        f.format(2, key);
        f.format(3, val);
    }
}

class ExFor extends Ex {

    final Ex eFor, eIn, eDo;

    public ExFor(Ex f, Ex i, Ex d) {
        eFor = f;
        eIn = i;
        eDo = d;
    }

    @Override
    public Flow exe(Frame cf) {
        Flow f = eIn.exe(cf);
        if (!f.isNormal()) {
            return f;
        }
        if (f.u() instanceof Map) {
            Map m = (Map) f.u();
            Flow res = Flow.normal(null);
            for (Iterator iterator = m.keySet().iterator(); iterator.hasNext();) {
                Object ky = iterator.next();
                Flow k = eFor.exe(cf);
                if (!k.isNormal()) {
                    return k;
                }
                cf.put(k.u(), ky);
                f = eDo.exe(cf);
                if (!f.isNormal()) {
                    return f;
                }
            }
            return f;
        }
        return Flow.thrw("ExFor.exe map=" + f.u() + " is not a Map");
    }

    public void format(Formatter f) {
        f.format(1, eFor);
        f.format(2, eIn);
        f.format(3, eDo);
    }
}

/*-------------------- control flow ---------------------------------*/
class ExIf extends Ex {

    final Ex eIf, eThen, eElse;

    public ExIf(Ex i, Ex t, Ex e) {
        eIf = i;
        eThen = t;
        eElse = e;
    }

    @Override
    public Flow exe(Frame cf) {
        boolean cond;
        Flow f = eIf.exe(cf);
        if (!f.isNormal()) {
            return f;
        }
        Flow r;
        if (f.u().equals(true)) {
            return eThen.exe(cf);
        } else if (f.u().equals(false)) {
            return eElse.exe(cf);
        } else {
            return Flow.thrw("if cond " + f.u() + " not boolean");
        }
    }

    public void format(Formatter f) {
        f.format(1, eIf);
        f.format(2, eThen);
        f.format(3, eElse);
   }
}

class ExSeq extends Ex {

    final Ex[] seq;

    public ExSeq(Ex... e) {
        seq = e;
    }

    @Override
    public Flow exe(Frame cf) {
        Flow f = null;
        for (int sx = 0; sx < seq.length; sx++) {
            f = seq[sx].exe(cf);
            if (!f.isNormal()) {
                return f;
            }
        }
        return f != null ? f : Flow.normal(null);
    }

    public void format(Formatter f) {
        for (int i = 0; i < seq.length; i++) {
                f.format(1, seq[i]);
            }
    }
}

class ExWhile extends Ex {

    final Ex eW, eDo;

    public ExWhile(Ex cond, Ex st) {
        eW = cond;
        eDo = st;
    }

    @Override
    public Flow exe(Frame cf) {
        boolean cond;
        Flow stmt = null;
        while (true) {
            Flow w = eW.exe(cf);
            if (!w.isNormal()) {
                return w;
            }
            boolean wb;
            try {
                wb = (Boolean) w.u();
            } catch (Exception e) {
                return Flow.thrw("while condition not boolean: " + w.u() + ": " + a2r("while condition not boolean: ", e));
            }
            if (!wb) {
                return stmt == null ? Flow.normal(null) : stmt;
            }
            stmt = eDo.exe(cf);
            if (!stmt.isNormal()) {
                return stmt;
            }
        }
    }

    public void format(Formatter f) {
        f.format(1, eW);
        f.format(2, eDo);

    }
}

/*-------------------- 


class ExFun extends Ex {
    public ExFun(Ex e1) {
        super(e1);
    }

    @Override
    public Flow exe(Frame cf) {
        return ex.fun(cf, 1);
    }

    @Override
    public Flow fun(Frame cf, int depth) {
        return super.fun(cf, depth+1);
    }
} */

class ExCall extends Ex {

    final Ex code, frame;

    public ExCall(Ex c, Ex f) {
        code = c;
        frame = f;
    }

    @Override
    public Flow exe(Frame cf) {
        Flow fl = code.exe(cf);
        if (!fl.isNormal()) {
            return fl;
        }
        Ex cd;
        try {
            cd = (Ex) fl.u();
        } catch (Exception e) {
            return Flow.thrw("ExCall no code: " + fl.u() + ": " + a2r("ExCall not code: ", e));
        }
        fl = frame.exe(cf);
        if (!fl.isNormal()) {
            return fl;
        }
        Frame fr;
        try {
            fr = (Frame) fl.u();
        } catch (Exception e) {
            return Flow.thrw("ExCall no frame: " + fl.u() + ": " + a2r("ExCall not frame: ", e));
        }
        fl = cd.exe(fr);
        return fl.isReturn() ? Flow.normal(fl.u()) : fl;
    }
}

class ExReturn extends Ex {

    final Ex ret;

    public ExReturn(Ex e1) {
        ret = e1;
    }

    @Override
    public Flow exe(Frame cf) {
        Flow f = ret.exe(cf);
        return f.isNormal() ? Flow.ret(f.u()) : f;
    }

    public void format(Formatter f) {
        f.format(1, ret);
    }
}

/*-------------------- throw and try ---------------------------------*/
class ExThrow extends Ex {

    final Ex thrw;

    public ExThrow(Ex e1) {
        thrw = e1;
    }

    @Override
    public Flow exe(Frame cf) {
        Flow f = thrw.exe(cf);
        return f.isNormal() ? Flow.thrw(f.u()) : f;
    }
    
    @Override
    public void format(Formatter f) {
        f.format(1, thrw);
    }    
}

class ExTry extends Ex {

    final Ex eTry, eCatch, eHandle;

    public ExTry(Ex t, Ex c, Ex h) {
        eTry = t;
        eCatch = c;
        eHandle = h;
    }

    @Override
    public Flow exe(Frame cf) {
        Flow t = eTry.exe(cf);
        if (!t.isThrow()) {
            return t;
        }
        Flow c = eCatch.exe(cf);
        if (!c.isNormal()) {
            return c;
        }
        cf.put(c.u(), t.u());
        return eHandle.exe(cf);
    }
}

/*-------------------- finally, the factory ---------------------------------*/
public class ExFactory {

    final static ExCF cf0 = new ExCF();
    final static ExNF nf0 = new ExNF();
    final static ExNew new0 = new ExNew();
    final static Flow constNull = Flow.normal(null);
    final Map<Object, JFun> jFunMap = new HashMap<Object, JFun>();

    public Ex cf() {
        return cf0;
    }

    public ExConst cnst(Object u) {
        return new ExConst(Flow.normal(u));
    }

    public void jFunAdd(String key, JFun j) {
        if (AbstractCompiler.resWords.matcher(key).matches()) {
            err("jFunAdd illegal name " + key);
        }
        if (j.name == null) {
            j.name = key;
        } else {
            err("jFunAdd but already registered: " + j.name + " key " + key);
        }
        jFunMap.put(key, j);
    }

    public boolean jFunExists(Object key) {
        return jFunMap.get(key) != null;
    }

    public Ex jFun(Object key, Ex... e) {
        JFun jf = jFunMap.get(key);
        if (jf == null) {
            if (key instanceof JFun) {
                jf = (JFun) key;
            } else {
                err("syntax jFun no JFun at key=" + key);
            }
        }
        return new ExJFun(jf, e);
    }

    /*    
    public Flow jFun(Flow f, ExJFunDyn j) {
        return f.isNormal() ? Flow.normal(jFun(f.u(), Arrays.copyOfRange(j.exs, 1, j.exs.length))) : f;
    }

    public ExJFunDyn jFunDyn(Ex... e) {
        return new ExJFunDyn(this, e);
    }

    public ExJFunDyn jFunDyn(Map<Object, Object> m) {
        ArrayList<Ex> exs = new ArrayList<Ex>();
        exs.add((Ex)m.get("fun"));
        for(int ix=1; ; ix++) {
            if (m.containsKey(ix))
                exs.add((Ex)m.get(ix));
            else
                return jFunDyn(exs.toArray(new Ex[exs.size()]));
        }
    }
     */
    public Ex exNew() {
        return new0;
    }

    public Ex nf() {
        return nf0;
    }

    public ExGet get(Ex map, Ex key) {
        return new ExGet(map, key);
    }

    public ExAss ass(Ex map, Ex key, Ex val) {
        return new ExAss(map, key, val);
    }

    public Ex exFor(Ex eFor, Ex eIn, Ex eDo) {
        return new ExFor(eFor, eIn, eDo);
    }

    public Ex exIf(Ex i, Ex t, Ex e) {
        return new ExIf(i, t, e);
    }

    public ExSeq seq(Ex... exs) {
        if (exs.length == 0) {
            out("???exs empty");
        } else if (exs[0] == null) {
            out("???ex[0] null");
        }
        return new ExSeq(exs);
    }

    public Ex whl(Ex cond, Ex st) {
        return new ExWhile(cond, st);
    }

    /*    public Ex fun(Ex e) {
        return new ExFun(e);
    }
     */
    public Ex call(Ex code, Ex frame) {
        return new ExCall(code, frame);
    }

    /*
    public Ex det(Ex e) {
        return new ExDet(e);
    }
    
    public Ex exExe(Ex e) {
        return new ExCall(e, null);
    }
     */
    public Ex ret(Ex e) {
        return new ExReturn(e);
    }

    public Ex ret(Object o) {
        return new ExReturn(cnst(o));
    }

    public Ex thrw(Ex e) {
        return new ExThrow(e);
    }

    public Ex thrw(Object o) {
        return new ExThrow(cnst(o));
    }

    public Ex exTry(Ex eTry, Ex eCatch, Ex eHandle) {
        return new ExTry(eTry, eCatch, eHandle);
    }

    public Ex ex(String name, Ex... exs) {
        if (exs == null || exs.length == 0) {
            if ("cf".equals(name)) {
                return cf();
            }
            if ("new".equals(name)) {
                return exNew();
            }
        } else if (exs.length == 1) {
            if ("return".equals(name)) {
                return ret(exs[0]);
            }
            if ("throw".equals(name)) {
                return thrw(exs[0]);
            }
        } else if (exs.length == 2) {
            if ("call".equals(name)) {
                return call(exs[0], exs[1]);
            }
            if ("get".equals(name)) {
                return get(exs[0], exs[1]);
            }
            if ("while".equals(name)) {
                return whl(exs[0], exs[1]);
            }
        } else if (exs.length == 3) {
            if ("ass".equals(name)) {
                return ass(exs[0], exs[1], exs[2]);
            }
            if ("for".equals(name)) {
                return exFor(exs[0], exs[1], exs[2]);
            }
            if ("if".equals(name)) {
                return exIf(exs[0], exs[1], exs[2]);
            }
            if ("try".equals(name)) {
                return exTry(exs[0], exs[1], exs[2]);
            }

        }
        if ("seq".equals(name)) {
            return seq(exs);
        }

        err("no Ex named " + name + " with " + (exs == null ? "null" : exs.length) + " operands");
        return null;
    }
}