package parser;

/**
 * Factory for T grammar non-terminal objects.
 */
public class TFact extends ATVFactory {
    /**
     * Token visitor to parse F grammar non-terminals.
     */
    private FFact _fFact;

    /**
     * Token visitor to parse F grammar non-terminals.
     */
    private ITokVisitor _parseF;

    /**
     * Token visitor to parse T1 grammar non-terminals.
     */
    private T1Fact _t1Fact;

    /**
     * Token visitor to parse T1 grammar non-terminals.
     */
    private ITokVisitor _parseT1;

    /**
     * Initializer lambda for this factory.
     */
    private ILambda _initializer = new ILambda() {
        public Object apply(Object param) {
            // change state to no-op
            _initializer = NoOpLambda.Singleton;

            // initialize
            _parseF = _fFact.makeVisitor();
            _parseT1 = _t1Fact.makeVisitor();
            return null;
        }
    };

    /**
     * Constructor for the T factory,
     *
     * @param tkz    tokenizer to use
     * @param fFact  factory for F non-terminals
     * @param t1Fact factory for T1 non-terminals
     */
    public TFact(ITokenizer tkz, FFact fFact, T1Fact t1Fact) {
        super(tkz);
        _fFact = fFact;
        _t1Fact = t1Fact;
    }

    /**
     * Make the visitor.
     */
    private void initialize() {
        _initializer.apply(null);
    }

    /**
     * Make a token visitor to parse an T non-terminal.
     *
     * @return token visitor
     */
    public ITokVisitor makeVisitor() {
        initialize();
        return new ITokVisitor() {
            public Object defaultCase(AToken host, Object inp) {
                return new T((F) host.execute(_parseF, inp), (T1) nextToken().execute(_parseT1, inp));
            }
        };
    }

    /**
     * Make a token visitor that delegates to the given visitor in a chain of responsibility.
     *
     * @param successor visitor to serve as successor in the chain
     */
    public ITokVisitor makeChainedVisitor(final ITokVisitor successor) {
        initialize();
        return new ITokVisitor() {
            public Object defaultCase(AToken host, Object inp) {
                Object o = host.execute(_fFact.makeChainedVisitor(successor), inp);
                return (o instanceof F) ? new T((F) o, (T1) nextToken().execute(_parseT1, inp)) : o;
            }
        };
    }
}

