java/ch/wlkl/wsm/Compiler.java

package ch.wlkl.wsm;

import java.util.ArrayList;
import java.util.List;

/**
 * @author walter
 *
 */
public class Compiler extends AbstractCompiler {
    public Compiler() {
        super();
    }
    public Compiler(ExFactory f) {
        super(f);
    }

    Ex seq() {
        final ArrayList<Ex> eles = new ArrayList<Ex>();
        Ex e1;
        do {
            if ((e1 = ex()) != null)
                eles.add(e1);
        } while    (skip().lit(";"));
        return eles.size() == 1 ? eles.get(0) : factory.seq(eles.toArray(Ex.a0));
    }
    
    Ex ex() {
        Ex map = exOne();
        while (true) {
            if (skip().lit("[")) 
                map = checkLit(assOrGet(map, false), "]");
            else if (lit("(")) 
                map = factory.call(map, checkLit(assOrGet(map, true), ")"));
            else
                return map;
        }
    }

    Ex assOrGet(Ex map, boolean isCall) {
        Ex cur = null;
        do {
            Ex ky = ex();
            if (ky == null) {
                if (isCall && cur == null)
                    return factory.nf();
                fail("ass or get expected");
            }
            if (! skip().lit(":=")) {
                if (cur == null)
                    return isCall ? ky : factory.get(map, ky);
                fail(":= in call arguments expected");
            }
            Ex val = ex();
            if (cur == null)
                cur = isCall ? factory.nf(): map;
            cur = factory.ass(cur, ky, val);
        } while (skip().lit(","));
        return cur; 
    }

    Ex exOne() {
        skip();
        if (! next(name)) {
            return exConst();
        } else if ("begin".equals(tok)) {
            return checkName(seq(), "end");
        } else if ("cf".equals(tok)) {
            return factory.cf();
/*        } else if ("det".equals(tok)) {
            return factory.det(checkName(seq(), "detEnd"));
        } else if ("exe".equals(tok)) {
            return factory.exExe(checkName(seq(), "exeEnd"));
*/        } else if ("for".equals(tok)) {
            return factory.exFor(checkName(ex(), "in"), checkName(ex(), "do"), checkName(seq(), "forEnd"));
        } else if ("fun".equals(tok)) {
            return factory.cnst(checkName(seq(), "funEnd"));
        } else if ("if".equals(tok)) {
            return compIf();
        } else if ("new".equals(tok)) {
            return factory.exNew();
        } else if ("return".equals(tok)) {
            return factory.ret(ex());
        } else if ("throw".equals(tok)) {
            return factory.thrw(ex());
        } else if ("try".equals(tok)) {
            return factory.exTry(checkName(seq(), "catch"), checkName(ex(), "handle"), checkName(seq(), "tryEnd"));
        } else if ("while".equals(tok)) {
            return factory.whl(checkName(seq(), "do"), checkName(seq(), "wEnd"));
        } else if (resWords.matcher(tok).matches()) { // ignore, for later usage!
        } else if (factory.jFunExists(tok)) {
            return jfun(tok);
        } 
        back();
        return null; 
    }
    
    Ex compIf() {
        Ex eIf = checkName(seq(), "then");
        Ex eTh = seq();
        return factory.exIf(eIf, eTh, name("else", "elif").equals("else") ? checkName(seq(), "ifEnd") : compIf());
    }

    Ex jfun(String fun) {
        List<Ex> exs = new ArrayList<Ex>();
        if (skip().lit("(")) {
            do {
                skip();
                Ex e1 = ex();
                if (e1 == null) {
                    if (exs.size() == 0)
                        break;
                    else
                        fail("expression expected");
                }
                exs.add(e1);
            } while (skip().lit(","));
        checkLit(null, ")");
        }
        return factory.jFun(fun, exs.toArray(new Ex[exs.size()]));
    }
}