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

    Boost.Wave: A Standard compliant C++ preprocessor library



    http://www.boost.org/



    Copyright (c) 2001-2008 Hartmut Kaiser. 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(MACRO_DEFINITION_HPP_D68A639E_2DA5_4E9C_8ACD_CFE6B903831E_INCLUDED)

#define MACRO_DEFINITION_HPP_D68A639E_2DA5_4E9C_8ACD_CFE6B903831E_INCLUDED



#include <vector>

#include <list>



#include <boost/wave/wave_config.hpp>

#if BOOST_WAVE_SERIALIZATION != 0

#include <boost/serialization/serialization.hpp>

#include <boost/serialization/list.hpp>

#include <boost/serialization/vector.hpp>

#endif



#include <boost/wave/token_ids.hpp>



// this must occur after all of the includes and before any code appears

#ifdef BOOST_HAS_ABI_HEADERS

#include BOOST_ABI_PREFIX

#endif



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

namespace boost {

namespace wave {

namespace util {



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

//

//  macro_definition

//

//      This class containes all infos for a defined macro. 

//

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

template <typename TokenT, typename ContainerT>

struct macro_definition {



    typedef std::vector<TokenT> parameter_container_type;

    typedef ContainerT          definition_container_type;

    

    typedef typename parameter_container_type::const_iterator 

        const_parameter_iterator_t;

    typedef typename definition_container_type::const_iterator 

        const_definition_iterator_t;



    macro_definition(TokenT const &token_, bool has_parameters, 

            bool is_predefined_, long uid_)

    :   macroname(token_), uid(uid_), is_functionlike(has_parameters), 

        replaced_parameters(false), is_available_for_replacement(true),

        is_predefined(is_predefined_)

#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0

        , has_ellipsis(false)

#endif

    {

    }

    // generated copy constructor

    // generated destructor

    // generated assignment operator



    // Replace all occurrences of the parameters throughout the macrodefinition

    // with special parameter tokens to simplify later macro replacement.

    // Additionally mark all occurrences of the macro name itself throughout

    // the macro definition

    void replace_parameters()

    {

        using namespace boost::wave;

        

        if (!replaced_parameters) {

        typename definition_container_type::iterator end = macrodefinition.end();

        typename definition_container_type::iterator it = macrodefinition.begin(); 



            for (/**/; it != end; ++it) {

            token_id id = *it;

            

                if (T_IDENTIFIER == id || 

                    IS_CATEGORY(id, KeywordTokenType) ||

                    IS_EXTCATEGORY(id, OperatorTokenType|AltExtTokenType) ||

                    IS_CATEGORY(id, OperatorTokenType)) 

                {

                // may be a parameter to replace

                    const_parameter_iterator_t cend = macroparameters.end();

                    const_parameter_iterator_t cit = macroparameters.begin();

                    for (typename parameter_container_type::size_type i = 0; 

                        cit != cend; ++cit, ++i) 

                    {

                        if ((*it).get_value() == (*cit).get_value()) {

                            (*it).set_token_id(token_id(T_PARAMETERBASE+i));

                            break;

                        }

#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0

                        else if (T_ELLIPSIS == token_id(*cit) && 

                            "__VA_ARGS__" == (*it).get_value()) 

                        {

                        // __VA_ARGS__ requires special handling

                            (*it).set_token_id(token_id(T_EXTPARAMETERBASE+i));

                            break;

                        }

#endif

                    }

                }

            }

            

#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0 

        // we need to know, if the last of the formal arguments is an ellipsis

            if (macroparameters.size() > 0 &&

                T_ELLIPSIS == token_id(macroparameters.back())) 

            {

                has_ellipsis = true;

            }

#endif 

            replaced_parameters = true;     // do it only once

        }

    }



    TokenT macroname;                       // macro name

    parameter_container_type macroparameters;  // formal parameters

    definition_container_type macrodefinition; // macro definition token sequence

    long uid;                               // unique id of this macro

    bool is_functionlike;

    bool replaced_parameters;

    bool is_available_for_replacement;

    bool is_predefined;

#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0

    bool has_ellipsis;

#endif



#if BOOST_WAVE_SERIALIZATION != 0

    // default constructor is needed for serialization only

    macro_definition() 

    :   uid(0), is_functionlike(false), replaced_parameters(false),

        is_available_for_replacement(false), is_predefined(false)

#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0

      , has_ellipsis(false)

#endif

    {}



private:

    friend class boost::serialization::access;

    template<typename Archive>

    void serialize(Archive &ar, const unsigned int version)

    {

        using namespace boost::serialization;

        ar & make_nvp("name", macroname);

        ar & make_nvp("parameters", macroparameters);

        ar & make_nvp("definition", macrodefinition);

        ar & make_nvp("uid", uid);

        ar & make_nvp("is_functionlike", is_functionlike);

        ar & make_nvp("has_replaced_parameters", replaced_parameters);

        ar & make_nvp("is_available_for_replacement", is_available_for_replacement);

        ar & make_nvp("is_predefined", is_predefined);

#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0

        ar & make_nvp("has_ellipsis", has_ellipsis);

#endif

    }

#endif

};



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

}   // namespace util

}   // namespace wave

}   // namespace boost



// the suffix header occurs after all of the code

#ifdef BOOST_HAS_ABI_HEADERS

#include BOOST_ABI_SUFFIX

#endif



#endif // !defined(MACRO_DEFINITION_HPP_D68A639E_2DA5_4E9C_8ACD_CFE6B903831E_INCLUDED)

