java/ch/wlkl/wsm/SyntaxFactory.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 java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static ch.wlkl.env.Env.*;
import java.util.Arrays;
/**
*
* @author walter
*/
public class SyntaxFactory extends Syntax {
final Map<String, SynRule> rules = new HashMap();
final Map<Class, SynRule> c2r = new HashMap();
final List<SynRule> seq = new ArrayList();
/**
* create a2s reference for rule (possibly unresovled) named n
*/
public Syntax ref(String n) {
return new SynRef(n, rule(n));
}
/**
* create a2s reference for rule (possibly unresovled) named n, with given fx
*/
public Syntax ref(String n, int f) {
SynRef r = new SynRef(n, rule(n));
r.fx = f;
return r;
}
/**
* create or retrieve rule (possibly unresovled) named n
*/
public SynRule rule(String n) {
if (!rules.containsKey(n)) {
rules.put(n, new SynRule(n));
}
return rules.get(n);
}
/**
* resolve rule name n with given syntax
*/
public void rule(String n, Syntax s) {
SynRule r = rule(n);
if (r.nodes[0] != null) {
dy("rule already defined");
}
r.nodes[0] = s;
seq.add(r);
}
/**
* resolve rule name n with given fClass and syntax
*/
public void rule(String n, Class c, Syntax s) {
rule(n, s);
rule(n).fClass = c;
}
/**
* resolve rule name n with given fClass and syntax as a lex rule using the given format
*/
public void ruLx(String n, Class c, String fmt, Syntax s) {
rule(n, s);
rule(n).fClass = c;
rule(n).lex = fmt;
}
/**
* resolve rule name n with given fClass and syntax
*/
public Syntax rule(Class c, Syntax s) {
SynRule r = new SynRule(null);
r.fClass = c;
return r;
}
/**
* create seq for subElements from given Syntaxes
*/
public Syntax seq(Syntax... s) {
return new SynSeq(s);
}
/**
* create nested Format seq: only o2s s with fx>=-1 is allowed, and passed the current ele (not a2s subEle!)
*/
public Syntax nest(Syntax... s) {
SynSeq n = new SynSeq(s);
assert Arrays.stream(s).filter(x -> x.fx >= -1).count() == 1 : assFail("to many fx in nest", s);
n.fx = -5;
return n;
}
public Syntax or(Object... s) {
return new SynOr(s);
}
public Syntax orI(Object... s) {
SynOr o = new SynOr(s);
o.fx = -1;
return o;
}
public Syntax zero2n(Syntax s) {
return new SynLoop(s, 0, Integer.MAX_VALUE);
}
public Syntax one2n(Syntax s) {
return new SynLoop(s, 1, Integer.MAX_VALUE);
}
public Syntax opt(Syntax s) {
return new SynLoop(s, 0, 1);
}
public Syntax lit(Object l) {
return new SynLit(l);
}
public Syntax lex(Object l) {
return new SynLex(l);
}
public Syntax litR(Object l) {
SynLit n = new SynLit(l);
n.fx = -1;
return n;
}
@Override
public void format(Formatter f) {
Set<Object> done = new HashSet();
for (SynRule r : seq) {
f.format(1, r);
done.add(r);
}
for (SynRule r : this.rules.values()) {
if (!done.contains(r)) {
f.format(2, String.valueOf(r.name));
done.add(r);
}
}
}
/**
* create the syntax for my grammar
*/
public void syntaxSyntax() {
rule("syntax", SyntaxFactory.class, one2n(ref("ruleDef")));
rule("ruleDef", SynRule.class, seq(ref("rule"), lit("="), ref("or")));
rule("or", SynOr.class, seq(ref("seq", 1), zero2n(seq(lit("|"), ref("seq", 1)))));
rule("seq", SynSeq.class, one2n(ref("loop")));
rule("loop", SynLoop.class, seq(orI(ref("lit"), ref("rule"), ref("lex"), ref("bracket")), opt(or(litR("?"), litR("*"), litR("+")))));
rule("bracket", nest(lit("("), orI(ref("bracObj"), ref("or")), lit(")")));
rule("bracObj", SynBra.class, ref("or"));
ruLx("rule", SynRef.class, ", $ ,", lex("name"));
ruLx("lit", SynLit.class, ", $ ,", lex("lit"));
ruLx("lex", SynLex.class, "<<< , $ , >>>", seq(lit("<<<"), lex("name"), lit(">>>")));
}
/**
* create the FormatSimlple Formats for syntaxSyntax
* @param f the ForatFactory
*/
public void syntaxFormatSimple(FormatFactory f) {
f.fmt(SyntaxFactory.class, "syntaxFactory , $ , $ ???undefined??? , endFactory :,n$,n$ %,n%", f.at("rule"));
f.fmt("rule", null, ", $, = $, :,, % >$<", null, f.at("or"));
f.chc("or", ",$,$,", f.fmt(SynOr.class, ", | |1 '| | $ , :,|| % |$", f.at("seq")), f.at("seq"));
f.chc("seq", ",$,$,", f.fmt(SynSeq.class, ", | |1 | $ ,:,|| |$", f.at("loop")), f.at("loop"));
f.chc("loop", ",$,$,", f.fmt(SynLoop.class, ", $ , ? , * , + ,", f.at("pr")), f.at("pr"));
f.chc("pr", ",$,$,$,$,", f.fmt(SynLex.class, "<<< , $ , >>>"), f.fmt(SynLit.class, ",$,"), f.fmt(SynRef.class, ",$,"), f.fmt(SynBra.class, "( , $ , )", f.at("or")), f.chc("( , $ , )", f.at("or")));
}
/**
* make all formats
* @param fs
* @return
*/
public Format makeFormat(FormatFactory fs) {
fs.fmt(SynLex.class, SynLex.class, "<<< , $ , >>>");
for (SynRule r : rules.values()) {
r.makeFormat(fs);
}
fs.finish();
return null;
}
}