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;
    }
}