/*=============================================================================

    Copyright (c) 2002-2003 Joel de Guzman

    Copyright (c) 2002-2003 Martin Wille

    http://spirit.sourceforge.net/



    Use, modification and distribution is subject to the Boost Software

    License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at

    http://www.boost.org/LICENSE_1_0.txt)

=============================================================================*/

#ifndef BOOST_SPIRIT_WHILE_HPP

#define BOOST_SPIRIT_WHILE_HPP



#include <boost/spirit/core/parser.hpp>

#include <boost/spirit/core/composite/composite.hpp>

#include <boost/spirit/dynamic/impl/conditions.ipp>



////////////////////////////////////////////////////////////////////////////////

namespace boost { namespace spirit {



    namespace impl {



    //////////////////////////////////

    // while parser

    // object are created by while_parser_gen and do_parser_gen

    template <typename ParsableT, typename CondT, bool is_do_parser>

    struct while_parser

        : public condition_evaluator< typename as_parser<CondT>::type >

        , public unary // the parent stores a copy of the body parser

        <

            typename as_parser<ParsableT>::type,

            parser<while_parser<ParsableT, CondT, is_do_parser> >

        >

    {

        typedef while_parser<ParsableT, CondT, is_do_parser> self_t;



        typedef as_parser<ParsableT>            as_parser_t;

        typedef typename as_parser_t::type      parser_t;

        typedef as_parser<CondT>                cond_as_parser_t;

        typedef typename cond_as_parser_t::type condition_t;



        typedef unary<parser_t, parser<self_t> > base_t;

        typedef condition_evaluator<condition_t> eval_t;





        //////////////////////////////

        // constructor, saves condition and body parser

        while_parser(ParsableT const &body, CondT const &cond)

            : eval_t(cond_as_parser_t::convert(cond))

            , base_t(as_parser_t::convert(body))

        {}



        //////////////////////////////

        // result type computer.

        template <typename ScannerT>

        struct result

        {

            typedef typename match_result

                <ScannerT, nil_t>::type type;

        };



        //////////////////////////////

        // parse member function

        template <typename ScannerT>

        typename parser_result<self_t, ScannerT>::type

        parse(ScannerT const& scan) const

        {

            typedef typename parser_result<parser_t, ScannerT>::type sresult_t;

            typedef typename ScannerT::iterator_t                    iterator_t;



            iterator_t save(scan.first);

            std::size_t length = 0;

            int eval_length = 0;



            bool dont_check_condition = is_do_parser;



            while (dont_check_condition || (eval_length=this->evaluate(scan))>=0)

            {

                dont_check_condition = false;

                length += eval_length;

                sresult_t tmp(this->subject().parse(scan));

                if (tmp)

                {

                    length+=tmp.length();

                }

                else

                {

                    return scan.no_match();

                }

            }

            return scan.create_match(length, nil_t(), save, scan.first);

        }

    };



    //////////////////////////////////

    // while-parser generator, takes the body-parser in brackets

    // and returns the actual while-parser.

    template <typename CondT>

    struct while_parser_gen

    {

        //////////////////////////////

        // constructor, saves the condition for use by operator[]

        while_parser_gen(CondT const& cond_) : cond(cond_) {}



        //////////////////////////////

        // operator[] returns the actual while-parser object

        template <typename ParsableT>

        while_parser<ParsableT, CondT, false>

        operator[](ParsableT const &subject) const

        {

            return while_parser<ParsableT, CondT, false>(subject, cond);

        }

    private:



        //////////////////////////////

        // the condition is stored by reference here.

        // this should not cause any harm since object of type

        // while_parser_gen<> are only used as temporaries

        // the while-parser object constructed by the operator[]

        // stores a copy of the condition.

        CondT const &cond;

    };



    //////////////////////////////////

    // do-while-parser generator, takes the condition as

    // parameter to while_p member function and returns the

    // actual do-while-parser.

    template <typename ParsableT>

    struct do_while_parser_gen

    {

        //////////////////////////////

        // constructor. saves the body parser for use by while_p.

        explicit do_while_parser_gen(ParsableT const &body_parser)

            : body(body_parser)

        {}



        //////////////////////////////

        // while_p returns the actual while-parser object

        template <typename CondT>

        while_parser<ParsableT, CondT, true>

        while_p(CondT cond) const

        {

            return while_parser<ParsableT, CondT, true>(body, cond);

        }

    private:



        //////////////////////////////

        // the body is stored by reference here

        // this should not cause any harm since object of type

        // do_while_parser_gen<> are only used as temporaries

        // the while-parser object constructed by the while_p

        // member function stores a copy of the body parser.

        ParsableT const &body;

    };



    struct do_parser_gen

    {

        inline do_parser_gen() {}



        template <typename ParsableT>

        impl::do_while_parser_gen<ParsableT>

        operator[](ParsableT const& body) const

        {

            return impl::do_while_parser_gen<ParsableT>(body);

        }

    };

} // namespace impl



//////////////////////////////////

// while_p function, while-parser generator

// Usage: spirit::while_p(Condition)[Body]

template <typename CondT>

impl::while_parser_gen<CondT>

while_p(CondT const& cond)

{

    return impl::while_parser_gen<CondT>(cond);

}



//////////////////////////////////

// do_p functor, do-while-parser generator

// Usage: spirit::do_p[Body].while_p(Condition)

impl::do_parser_gen const do_p = impl::do_parser_gen();



}} // namespace boost::spirit



#endif // BOOST_SPIRIT_WHILE_HPP

