java/ch/wlkl/wsm/FormatFactory.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package ch.wlkl.wsm;
import ch.wlkl.env.A2S;
import ch.wlkl.env.All2S;
import static ch.wlkl.env.Env.*;
import ch.wlkl.wsm.FormatFactory.Fmt.FctNst;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import static ch.wlkl.wsm.Formatter.toCode;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author walter
*/
public class FormatFactory {
public final HashMap<Object, Format> k2f = new HashMap();
public Format fmt(String g, Format... e) {
return new Fmt(null, g, e);
}
public Format fmt(Object b, String g, Format... e) {
return b == null ? new Fmt(b, g, e) : add(b, new Fmt(b, g, e));
}
public Format fmt(Object k, Object f, String g, Format... e) {
Fmt n = new Fmt(f, g, e);
return k == null ? n : add(k, n);
}
public Format chc(String g, Format... e) {
return new Fmt.Chc(g, e);
}
public Format chc(Object b, String g, Format... e) {
return b == null ? new Fmt.Chc(g, e) : add(b, new Fmt.Chc(g, e));
}
public Format fct(Object k, Object f, String g) {
return k == null ? new Fmt.Fct(this, f, g) : add(k, new Fmt.Fct(this, f, g));
}
public Format fct(Object f, String g) {
return fct(f, f, g);
}
public Format fctNst(Object k, String g) {
return k == null ? new FctNst(this, null, g) : add(k, new FctNst(this, null, g));
}
/**
* return Format at key k, create new placeholder if missing
* @param k
* @return
*/
public Format at(Object k) {
Format r = k2f.get(k);
if (r == null) {
r = new Fmt();
k2f.put(k, r);
}
return r;
}
/**
* return Format at key k, fail if missing
* @param k
* @return
*/
public Format atKey(Object k) {
Format r = k2f.get(k);
if (r == null) {
dy("key not found " + k);
}
return r;
}
/**
* return Format for Formattable f, fail if missing
* @param k
* @return
*/
public Format atFor(Formattable f) {
return atKey(f.getClass());
}
public Format add(Object k, Format f) {
final Fmt o;
assert k != null;
if (!k2f.containsKey(k)) {
k2f.put(k, f);
} else if (!(k2f.get(k) instanceof Fmt) || (o = (Fmt) k2f.get(k)).code != null) {
dy("key " + k + " already set");
} else {
k2f.put(k, o.ele[0] = (Fmt) f);
}
return f;
}
public Format add(Format f) {
return add(((Fmt)f).chcKey, f);
}
public void clear() {
k2f.clear();
}
/**
* replace all placeholders by its final format, fail on unresolved placeholders
*/
public void finish() {
Set<Format> done = new HashSet();
for (Map.Entry<Object, Format> e : k2f.entrySet()) {
assert e.getValue() instanceof Fmt && ((Fmt) e.getValue()).code != null : assFail("unresolved format", e);
((Fmt) e.getValue()).finish(done);
}
}
static class Fmt implements Format, A2S {
final Object chcKey;
final String[][] code;
final Fmt[] ele;
public Fmt(Object ck, String g, Format... e) {
chcKey = ck;
code = toCode(g, e.length);
if (e == null || e.length == 0) {
ele = null;
} else {
ele = new Fmt[e.length + 1];
System.arraycopy(e, 0, ele, 1, e.length);
}
}
protected Fmt() {
chcKey = null;
code = null;
ele = new Fmt[1];
}
@Override
public String[][] code() {
return code;
}
@Override
/* format: if i=0 format e globally else format subElement with index i */
public int format(Formatter f, int i, Formattable e) {
if (i == 0) {
e.format(f);
} else if (i >= 1 && i < ele.length && ele[i] != null) {
f.format(ele[i], e);
} else {
assert false: assFail("bad i " + i, this, ", ele=", e);
}
return -1;
}
public void mergeLex(String lex) {
Formatter.mergeLex(lex, 0, code);
}
public void mergeSyn(String syn) {
String [][] n = Formatter.toCode(syn, ele.length - 1);
assert(n.length == code.length);
System.arraycopy(n, 0, code, 0, n.length);
}
private void finish(Set<Format> done) {
if (ele == null || done.contains(this)) {
return;
}
done.add(this);
for (int i = 0; i < ele.length; i++) {
if (ele[i] instanceof Fmt) {
Fmt e = (Fmt) ele[i];
if (e.code == null) {
assert e.ele[0] != null : assFail("ele[" + i + "] not resolved", this);
ele[i] = e.ele[0];
}
e.finish(done);
}
}
}
@Override
public void a2s(All2S a) {
a.a2s("chcKey=", chcKey, ", code=", code, ", ele=", ele);
}
static class Chc extends Fmt {
public Chc(String g, Format... e) {
super(e.length == 1 ? ((Fmt) e[0]).chcKey : null, g, e);
}
@Override
/* format e, if i=0 first applicable choice else chc index i
* return next choice or -1
*/
public int format(Formatter f, int i, Formattable e) {
if (i == 0) {
for (i = 1; i < ele.length && ele[i] != null && ele[i].chcKey != null && ele[i].chcKey != e.getClass(); i++) {
}
}
assert i >= 1 && i < ele.length && ele[i] != null && (ele[i].chcKey == null || ele[i].chcKey == e.getClass()) : assFail("bad i " + i, "this=", this, ", ele=", ele);
f.format(ele[i], e);
int j;
for (j = i + 1; j < ele.length && ele[j] != null && ele[j].chcKey != e.getClass(); j++) {
}
return j < ele.length ? j : -1;
}
}
static class Fct extends Fmt {
final FormatFactory fact;
public Fct(FormatFactory f, Object ck, String g) {
super(ck, g);
fact = f;
}
@Override
/* format e, if i=0 first applicable choice else chc index i
* return next choice or -1
*/
public int format(Formatter f, int i, Formattable e) {
if (i == 0) {
e.format(f);
} else if (i > 0) {
f.format(fact.atFor(e), e);
} else {
dy("i=" + i);
}
return -1;
}
}
static class FctNst extends Fmt {
final FormatFactory fact;
public FctNst(FormatFactory f, Object ck, String g) {
super(ck, g);
fact = f;
}
@Override
/* format e, if i=0 first applicable choice else chc index i
* return next choice or -1
*/
public int format(Formatter f, int i, Formattable e) {
assert i == 0;
f.format(fact.atFor(e), e);
return -1;
}
}
}
}