/*=============================================================================
    Spirit v1.6.2
    Copyright (c) 1998-2003 Joel de Guzman
    http://spirit.sourceforge.net/

    Distributed under 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_MATCH_IPP)
#define BOOST_SPIRIT_MATCH_IPP

///////////////////////////////////////////////////////////////////////////////
#include <boost/ref.hpp>

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit {

    template <typename T>
    class match;

    namespace impl
    {
        ///////////////////////////////////////////////////////////////////////
        //
        //  Assignment of the match result
        //
        //      Implementation note: This assignment is wrapped by a
        //      template to allow its specialization for other types
        //      elsewhere.
        //
        ///////////////////////////////////////////////////////////////////////
        template <typename DestT>
        struct match_attr_traits
        {
            static DestT
            convert(DestT const& attr)  //  case where input *IS*
            { return DestT(attr); }     //  convertible to DestT

            static DestT
            convert(...)                //  case where input *IS NOT*
            { return DestT(); }         //  convertible to DestT
        };

    #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)

        struct match_attr_helper1   // T is not a boost::reference_wrapper
        {
            template <typename T>
            struct apply
            {
                template <typename MatchT>
                static T get(MatchT const& m)
                { return match_attr_traits<T>::convert(m.value()); }

                static T get(match<nil_t> const&)
                { return T(); }

                static T get_default()
                { return T(); }
            };
        };

        struct match_attr_helper2   // T is a boost::reference_wrapper
        {
            template <typename T>
            struct apply
            {
                template <typename MatchT>
                static T get(MatchT const& m)
                {
                    return T(m.value());
                }

                static T get(match<nil_t> const&)
                {
                    typedef typename T::type plain_type;
                    static plain_type v;
                    return T(v);
                }

                static T get_default()
                {
                    typedef typename T::type plain_type;
                    static plain_type v;
                    return T(v);
                }
            };
        };

        template <typename T>
        struct match_attr
        {
            typedef mpl::if_<
                boost::is_reference_wrapper<T>, //  IF
                match_attr_helper2,             //  THEN
                match_attr_helper1              //  ELSE
            >::type select_t;

            template <typename MatchT>
            static T get(MatchT const& m)
            { return select_t::template apply<T>::get(m); }

            static T get(match<nil_t> const& m)
            { return select_t::template apply<T>::get(m); }

            static T get_default()
            { return select_t::template apply<T>::get_default(); }
        };

    #else // !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)

        template <typename T>
        struct match_attr
        {
            template <typename MatchT>
            static T get(MatchT const& m)
            { return match_attr_traits<T>::convert(m.value()); }

            static T get(match<nil_t> const&)
            { return T(); }

            static T get_default()
            { return T(); }
        };

        template <typename T>
        struct match_attr<boost::reference_wrapper<T> >
        {
            template <typename MatchT>
            static boost::reference_wrapper<T>
            get(MatchT const& m)
            { return boost::reference_wrapper<T>(m.value()); }

            static boost::reference_wrapper<T>
            get(match<nil_t> const&)
            { static T v; return boost::reference_wrapper<T>(v); }

            static boost::reference_wrapper<T>
            get_default()
            { static T v; return boost::reference_wrapper<T>(v); }
        };

    #endif // defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)

        template <>
        struct match_attr<nil_t>
        {
            template <typename MatchT>
            static nil_t get(MatchT const&)
            { return nil_t(); }
            static nil_t get_default()
            { return nil_t(); }
        };

    #if !defined(__BORLANDC__)
        struct dummy { void nonnull() {}; };
        typedef void (dummy::*safe_bool)();
    #else
        typedef bool safe_bool;
    #endif

    #if !defined(__BORLANDC__)
    #define BOOST_SPIRIT_SAFE_BOOL(cond)  ((cond) ? &impl::dummy::nonnull : 0)
    #else
    #define BOOST_SPIRIT_SAFE_BOOL(cond)  (cond)
    #endif

}}} // namespace boost::spirit::impl

#endif

