package parser;

/**
 * Factory for E grammar non-terminal objects.
 */
public class EFact extends ATVFactory {
    /**
     * Token visitor to parse E1 grammar non-terminals.
     */
    private ITokVisitor _parseE1;

    /**
     * Factory to parse E1 grammar non-terminals.
     */
    private E1Fact _e1Fact;

    /**
     * Token visitor to parse S grammar non-terminals.
     */
    private ITokVisitor _parseS;

    /**
     * Factory to parse S grammar non-terminals.
     */
    private SFact _sFact;

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

            // initialize
            _parseE1 = _e1Fact.makeVisitor();
            _parseS = _sFact.makeVisitor();
            return null;
        }
    };

    /**
     * Constructor for the E factory,
     *
     * @param tkz tokenizer to use
     */
    public EFact(ITokenizer tkz) {
        super(tkz);
        _e1Fact = new E1Fact(tkz);
        _sFact = new SFact(tkz);
    }

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

    /**
     * Make a token visitor to parse an E non-terminal.
     *
     * @return token visitor
     */
    public ITokVisitor makeVisitor() {
        initialize();
        return new ITokVisitor() {
            public Object defaultCase(AToken host, Object inp) {
                return new E((S) host.execute(_parseS, inp), (E1) nextToken().execute(_parseE1, 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(_sFact.makeChainedVisitor(successor), inp);
                return (o instanceof S) ? new E((S) o, (E1) nextToken().execute(_parseE1, inp)) : o;
            }
        };
    }

    /**
     * Factory for Empty grammar terminals.
     */
    public class EmptyFact extends ATVFactory {
        /**
         * Constructor for Empty grammar terminals.
         *
         * @param tkz tokenizer to use
         */
        public EmptyFact(ITokenizer tkz) {
            super(tkz);
        }

        /**
         * Make a visitor to parse an empty terminal.
         *
         * @return visitor to parse an empty terminal
         */
        private ITokVisitor makeEmptyVis() {
            return new ITokVisitor() {
                public Object defaultCase(AToken host, Object param) {
                    putBackToken();
                    System.err.println("Pushback");
                    return Empty.Singleton;
                }
            };
        }

        /**
         * Make a token visitor to parse an Empty terminal.
         *
         * @return token visitor
         */
        public ITokVisitor makeVisitor() {
            return makeEmptyVis();
        }

        /**
         * 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(ITokVisitor successor) {
            return makeEmptyVis();
        }
    }

    /**
     * Factory for S grammar non-terminal objects.
     */
    public class SFact extends ATVFactory {
        /**
         * Factory for T grammar non-terminals.
         */
        private TFact _tFact;

        /**
         * Factory for P grammar terminals.
         */
        private PFact _pFact;

        /**
         * Constructor for the S factory,
         *
         * @param tkz tokenizer to use
         */
        public SFact(ITokenizer tkz) {
            super(tkz);
            _tFact = new TFact(tkz);
            _pFact = new PFact(tkz);

        }

        /**
         * Make a token visitor to parse an S non-terminal.
         *
         * @return token visitor
         */
        public ITokVisitor makeVisitor() {
            return _tFact.makeChainedVisitor(_pFact.makeVisitor());
        }

        /**
         * 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(ITokVisitor successor) {
            return _tFact.makeChainedVisitor(_pFact.makeChainedVisitor(successor));
        }

        /**
         * 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
             */
            public TFact(ITokenizer tkz) {
                super(tkz);
                _fFact = new FFact(tkz);
                _t1Fact = new T1Fact(tkz);
            }

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

            /**
             * Factory for F grammar non-terminal objects.
             */
            public class FFact extends ATVFactory {
                /**
                 * Factory for I grammar non-terminal visitors.
                 */
                IFact _iFact;

                /**
                 * Factory for N grammar non-terminal visitors.
                 */
                NFact _nFact;

                /**
                 * Constructor for the F factory,
                 *
                 * @param tkz tokenizer to use
                 */
                public FFact(ITokenizer tkz) {
                    super(tkz);
                    _iFact = new IFact(tkz);
                    _nFact = new NFact(tkz);
                }

                /**
                 * Make a token visitor to parse an F non-terminal.
                 *
                 * @return token visitor
                 */
                public ITokVisitor makeVisitor() {
                    return _iFact.makeChainedVisitor(_nFact.makeVisitor());
                }

                /**
                 * 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) {
                    return _iFact.makeChainedVisitor(_nFact.makeChainedVisitor(successor));
                }

                /**
                 * Factory for I grammar non-terminal objects.
                 */
                public class IFact extends ATVFactory {
                    /**
                     * Initializer lambda for this factory.
                     */
                    private ILambda _initializer = new ILambda() {
                        public Object apply(Object param) {
                            // change state to no-op
                            _initializer = NoOpLambda.Singleton;

                            // nothing to initialize
                            return null;
                        }
                    };

                    /**
                     * Constructor for the I factory.
                     *
                     * @param tkz tokenizer to use
                     */
                    public IFact(ITokenizer tkz) {
                        super(tkz);
                    }

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

                    /**
                     * Make a token visitor to parse an I non-terminal.
                     *
                     * @return token visitor
                     */
                    public ITokVisitor makeVisitor() {
                        initialize();
                        return new IdToken.IIdVisitor() {
                            public Object idCase(IdToken host, Object inp) {
                                return new I(host);
                            }

                            public Object defaultCase(AToken host, Object param) {
                                throw new IllegalArgumentException("Wrong token: '" + host + "'");
                            }
                        };
                    }

                    /**
                     * 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(ITokVisitor successor) {
                        initialize();
                        return new IdToken.AChainVis(successor) {
                            public Object idCase(IdToken host, Object inp) {
                                return new I(host);
                            }
                        };
                    }
                }

                /**
                 * Factory for N grammar non-terminal objects.
                 */
                public class NFact extends ATVFactory {
                    /**
                     * Initializer lambda for this factory.
                     */
                    private ILambda _initializer = new ILambda() {
                        public Object apply(Object param) {
                            // change state to no-op
                            _initializer = NoOpLambda.Singleton;

                            // nothing to initialize
                            return null;
                        }
                    };

                    /**
                     * Constructor for the N factory.
                     *
                     * @param tkz tokenizer to use
                     */
                    public NFact(ITokenizer tkz) {
                        super(tkz);
                    }

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

                    /**
                     * Make a token visitor to parse an N non-terminal.
                     *
                     * @return token visitor
                     */
                    public ITokVisitor makeVisitor() {
                        initialize();
                        return new NumToken.INumVisitor() {
                            public Object numCase(NumToken host, Object inp) {
                                return new N(host);
                            }

                            public Object defaultCase(AToken host, Object param) {
                                throw new IllegalArgumentException("Wrong token: '" + host + "'");
                            }
                        };
                    }

                    /**
                     * 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(ITokVisitor successor) {
                        initialize();
                        return new NumToken.AChainVis(successor) {
                            public Object numCase(NumToken host, Object inp) {
                                return new N(host);
                            }
                        };
                    }
                }
            }

            /**
             * Factory for T1 grammar non-terminal objects.
             */
            public class T1Fact extends ATVFactory {
                /**
                 * Factory for T1a grammar non-terminals.
                 */
                private T1aFact _t1aFact;

                /**
                 * Factory for Empty grammar terminals.
                 */
                private EmptyFact _emptyFact;

                /**
                 * Constructor for the T1 factory,
                 *
                 * @param tkz tokenizer to use
                 */
                public T1Fact(ITokenizer tkz) {
                    super(tkz);
                    _t1aFact = new T1aFact(tkz);
                    _emptyFact = new EmptyFact(tkz);
                }

                /**
                 * Make a token visitor to parse an E1 non-terminal.
                 *
                 * @return token visitor
                 */
                public ITokVisitor makeVisitor() {
                    return _t1aFact.makeChainedVisitor(_emptyFact.makeVisitor());
                }

                /**
                 * 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(ITokVisitor successor) {
                    return _t1aFact.makeChainedVisitor(_emptyFact.makeChainedVisitor(successor));
                }

                /**
                 * Factory for T1a grammar non-terminal objects.
                 */
                public class T1aFact extends ATVFactory {
                    /**
                     * Factory to parse S grammar non-terminals.
                     */
                    private SFact _sFact;

                    /**
                     * Token visitor to parse S grammar non-terminals.
                     */
                    private ITokVisitor _parseS;


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

                            // initialize
                            _parseS = _sFact.makeVisitor();
                            return null;
                        }
                    };

                    /**
                     * Constructor for the T1a factory.
                     *
                     * @param tkz tokenizer to use
                     */
                    public T1aFact(ITokenizer tkz) {
                        super(tkz);
                        _sFact = SFact.this;
                    }

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

                    /**
                     * Make an E1a grammar non-terminal.
                     *
                     * @param host mult token
                     * @param inp  visitor-specific input
                     * @return E1a grammar non-terminal
                     */
                    private T1a makeT1a(MultToken host, Object inp) {
                        return new T1a(host, (S) nextToken().execute(_parseS, inp));
                    }


                    /**
                     * Make a token visitor to parse an E1a non-terminal.
                     *
                     * @return token visitor
                     */
                    public ITokVisitor makeVisitor() {
                        initialize();
                        return new MultToken.IMultVisitor() {
                            public Object multCase(MultToken host, Object inp) {
                                return makeT1a(host, inp);
                            }

                            public Object defaultCase(AToken host, Object param) {
                                throw new IllegalArgumentException("Wrong token: '" + host + "'");
                            }
                        };
                    }

                    /**
                     * 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(ITokVisitor successor) {
                        initialize();
                        return new MultToken.AChainVis(successor) {
                            public Object multCase(MultToken host, Object inp) {
                                return makeT1a(host, inp);
                            }
                        };
                    }
                }
            }

        }

        /**
         * Factory for P grammar non-terminal objects.
         */
        public class PFact extends ATVFactory {
            /**
             * Token visitor to parse E grammar non-terminals.
             */
            private ITokVisitor _parseE;

            /**
             * Factory to parse E grammar non-terminals.
             */
            private EFact _eFact;

            /**
             * Token visitor to parse a right parenthesis terminal.
             */
            private ITokVisitor _parseRP = new RightPToken.IRightPVisitor() {
                public Object rightPCase(RightPToken host, Object param) {
                    return host;
                }

                public Object defaultCase(AToken host, Object param) {
                    throw new IllegalArgumentException("Wrong token: '" + host + "'");
                }
            };

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

                    // initialize
                    _parseE = _eFact.makeVisitor();
                    return null;
                }
            };

            /**
             * Constructor for the T1a factory.
             *
             * @param tkz tokenizer to use
             */
            public PFact(ITokenizer tkz) {
                super(tkz);
                _eFact = EFact.this;
            }

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

            /**
             * Make an P grammar non-terminal.
             *
             * @param host left parenthesis token
             * @param inp  visitor-specific input
             * @return P grammar non-terminal
             */
            private P makeP(LeftPToken host, Object inp) {
                return new P(host,
                             (E) nextToken().execute(_parseE, inp),
                             (RightPToken) nextToken().execute(_parseRP, inp));
            }


            /**
             * Make a token visitor to parse an E1a non-terminal.
             *
             * @return token visitor
             */
            public ITokVisitor makeVisitor() {
                initialize();
                return new LeftPToken.ILeftPVisitor() {
                    public Object leftPCase(LeftPToken host, Object inp) {
                        return makeP(host, inp);
                    }

                    public Object defaultCase(AToken host, Object param) {
                        throw new IllegalArgumentException("Wrong token: '" + host + "'");
                    }
                };
            }

            /**
             * 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(ITokVisitor successor) {
                initialize();
                return new LeftPToken.AChainVis(successor) {
                    public Object leftPCase(LeftPToken host, Object inp) {
                        return makeP(host, inp);
                    }
                };
            }
        }
    }

    /**
     * Factory for E1 grammar non-terminal objects.
     */
    public class E1Fact extends ATVFactory {
        /**
         * Factory for E1a grammar non-terminals.
         */
        private E1aFact _e1aFact;

        /**
         * Factory for Empty grammar terminals.
         */
        private EmptyFact _emptyFact;

        /**
         * Constructor for the E1 factory,
         *
         * @param tkz tokenizer to use
         */
        public E1Fact(ITokenizer tkz) {
            super(tkz);
            _e1aFact = new E1aFact(tkz);
            _emptyFact = new EmptyFact(tkz);
        }

        /**
         * Make a token visitor to parse an E1 non-terminal.
         *
         * @return token visitor
         */
        public ITokVisitor makeVisitor() {
            return _e1aFact.makeChainedVisitor(_emptyFact.makeVisitor());
        }

        /**
         * 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(ITokVisitor successor) {
            return _e1aFact.makeChainedVisitor(_emptyFact.makeChainedVisitor(successor));
        }

        /**
         * Factory for E1a grammar non-terminal objects.
         */
        public class E1aFact extends ATVFactory {
            /**
             * Factory to parse E grammar non-terminals.
             */
            private EFact _eFact;

            /**
             * Token visitor to parse E grammar non-terminals.
             */
            private ITokVisitor _parseE;

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

                    // initialize
                    _parseE = _eFact.makeVisitor();
                    return null;
                }
            };

            /**
             * Constructor for the E1a factory.
             *
             * @param tkz tokenizer to use
             */
            public E1aFact(ITokenizer tkz) {
                super(tkz);
                _eFact = EFact.this;
            }

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

            /**
             * Make an E1a grammar non-terminal.
             *
             * @param host plus token
             * @param inp  visitor-specific input
             * @return E1a grammar non-terminal
             */
            private E1a makeE1a(PlusToken host, Object inp) {
                return new E1a(host, (E) nextToken().execute(_parseE, inp));
            }

            /**
             * Make a token visitor to parse an E1a non-terminal.
             *
             * @return token visitor
             */
            public ITokVisitor makeVisitor() {
                initialize();
                return new PlusToken.IPlusVisitor() {
                    public Object plusCase(PlusToken host, Object inp) {
                        return makeE1a(host, inp);
                    }

                    public Object defaultCase(AToken host, Object param) {
                        throw new IllegalArgumentException("Wrong token: '" + host + "'");
                    }
                };
            }

            /**
             * 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(ITokVisitor successor) {
                initialize();
                return new PlusToken.AChainVis(successor) {
                    public Object plusCase(PlusToken host, Object inp) {
                        return makeE1a(host, inp);
                    }
                };
            }
        }
    }
}

