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

    Copyright (c) 1998-2003 Joel de Guzman

    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)

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

#if !defined(BOOST_SPIRIT_STORED_RULE_HPP)

#define BOOST_SPIRIT_STORED_RULE_HPP



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

#include <boost/spirit/core/non_terminal/impl/rule.ipp>

#include <boost/spirit/dynamic/rule_alias.hpp>

#include <boost/shared_ptr.hpp>



#include <boost/spirit/dynamic/stored_rule_fwd.hpp>



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

namespace boost { namespace spirit {



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

    //

    //  stored_rule class

    //

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

    template <

        typename T0 

      , typename T1

      , typename T2

      , bool EmbedByValue

    >

    class stored_rule

        : public impl::rule_base<

            stored_rule<T0, T1, T2, EmbedByValue>

          , typename mpl::if_c<

                EmbedByValue

              , stored_rule<T0, T1, T2, true>

              , stored_rule<T0, T1, T2> const&>::type

          , T0, T1, T2>

    {

    public:



        typedef stored_rule<T0, T1, T2, EmbedByValue> self_t;

        typedef impl::rule_base<

            self_t

          , typename mpl::if_c<

                EmbedByValue

              , stored_rule<T0, T1, T2, true>

              , self_t const&>::type

          , T0, T1, T2>

        base_t;



        typedef typename base_t::scanner_t scanner_t;

        typedef typename base_t::attr_t attr_t;

        typedef impl::abstract_parser<scanner_t, attr_t> abstract_parser_t;

        typedef rule_alias<self_t> alias_t;



        stored_rule() : ptr() {}

        ~stored_rule() {}



        stored_rule(stored_rule const& r)

        : ptr(r.ptr) {}



        template <typename ParserT>

        stored_rule(ParserT const& p)

        : ptr(new impl::concrete_parser<ParserT, scanner_t, attr_t>(p)) {}



        template <typename ParserT>

        stored_rule& operator=(ParserT const& p)

        {

            ptr.reset(new impl::concrete_parser<ParserT, scanner_t, attr_t>(p));

            return *this;

        }



        stored_rule& operator=(stored_rule const& r)

        {

            //  If this is placed above the templatized assignment

            //  operator, VC6 incorrectly complains ambiguity with

            //  r1 = r2, where r1 and r2 are both rules.

            ptr = r.ptr;

            return *this;

        }



        stored_rule<T0, T1, T2, true>

        copy() const

        {

            return stored_rule<T0, T1, T2, true>(ptr);

        }



        alias_t

        alias() const

        {

            return alias_t(*this);

        }



    private:



        friend class impl::rule_base_access;

        friend class stored_rule<T0, T1, T2, !EmbedByValue>;



#if defined(__GNUC__) && (__GNUC__ < 3)

    public:

#endif

        abstract_parser_t*

        get() const

        {

            return ptr.get();

        }

#if defined(__GNUC__) && (__GNUC__ < 3)

    private:

#endif



        stored_rule(shared_ptr<abstract_parser_t> const& ptr)

        : ptr(ptr) {}



        shared_ptr<abstract_parser_t> ptr;

    };



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

}} // namespace boost::spirit



#endif

