/*=============================================================================
    Copyright (c) 2002-2003 Joel de Guzman
    Copyright (c) 2002-2003 Hartmut Kaiser
    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_TRAVERSE_HPP)
#define BOOST_SPIRIT_TRAVERSE_HPP

#include <boost/spirit/home/classic/meta/impl/traverse.ipp>
#include <boost/spirit/home/classic/namespace.hpp>

namespace boost {
namespace spirit {

BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN

///////////////////////////////////////////////////////////////////////////
//
//  Post-order traversal of auxilliary parsers.
//
///////////////////////////////////////////////////////////////////////////
struct post_order {
  //  Return the parser type, which is generated as the result of the
  //  traverse function below.

  template <typename MetaT, typename ParserT> struct result {
    typedef typename traverse_post_order_return<
        MetaT, ParserT, traverse_post_order_env<0, 0, 0, 0>>::type type;
  };

  //  Traverse a given parser and refactor it with the help of the given
  //  MetaT metafunction template.

  template <typename MetaT, typename ParserT>
  static typename result<MetaT, ParserT>::type
  traverse(MetaT const &meta_, ParserT const &parser_) {
    typedef typename ParserT::parser_category_t parser_category_t;
    return impl::traverse_post_order<parser_category_t>::generate(
        meta_, parser_, traverse_post_order_env<0, 0, 0, 0>());
  }
};

///////////////////////////////////////////////////////////////////////////
//
//  Transform policies
//
//      The following policy classes could be used to assemble some new
//      transformation metafunction which uses identity transformations
//      for some parser_category type parsers.
//
///////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
//  transform plain parsers
template <typename TransformT> struct plain_identity_policy {
  template <typename ParserT, typename EnvT> struct plain_result {
    // plain parsers should be embedded and returned correctly
    typedef typename ParserT::embed_t type;
  };

  template <typename ParserT, typename EnvT>
  typename parser_traversal_plain_result<TransformT, ParserT, EnvT>::type
  generate_plain(ParserT const &parser_, EnvT const & /*env*/) const {
    return parser_;
  }
};

//////////////////////////////////
//  transform unary parsers
template <typename UnaryT, typename SubjectT>
struct unary_identity_policy_return {
  typedef typename UnaryT::parser_generator_t parser_generator_t;
  typedef typename parser_generator_t ::template result<SubjectT>::type type;
};

template <typename TransformT> struct unary_identity_policy {
  template <typename UnaryT, typename SubjectT, typename EnvT>
  struct unary_result {
    typedef typename unary_identity_policy_return<UnaryT, SubjectT>::type type;
  };

  template <typename UnaryT, typename SubjectT, typename EnvT>
  typename parser_traversal_unary_result<TransformT, UnaryT, SubjectT,
                                         EnvT>::type
  generate_unary(UnaryT const &, SubjectT const &subject_,
                 EnvT const & /*env*/) const {
    typedef typename UnaryT::parser_generator_t parser_generator_t;
    return parser_generator_t::template generate<SubjectT>(subject_);
  }
};

//////////////////////////////////
//  transform action parsers
template <typename TransformT> struct action_identity_policy {
  template <typename ActionT, typename SubjectT, typename EnvT>
  struct action_result {
    typedef action<SubjectT, typename ActionT::predicate_t> type;
  };

  template <typename ActionT, typename SubjectT, typename EnvT>
  typename parser_traversal_action_result<TransformT, ActionT, SubjectT,
                                          EnvT>::type
  generate_action(ActionT const &action_, SubjectT const &subject_,
                  EnvT const & /*env*/) const {
    return subject_[action_.predicate()];
  }
};

//////////////////////////////////
//  transform binary parsers
template <typename BinaryT, typename LeftT, typename RightT>
struct binary_identity_policy_return {
  typedef typename BinaryT::parser_generator_t parser_generator_t;
  typedef
      typename parser_generator_t ::template result<LeftT, RightT>::type type;
};

template <typename TransformT> struct binary_identity_policy {
  template <typename BinaryT, typename LeftT, typename RightT, typename EnvT>
  struct binary_result {

    typedef typename binary_identity_policy_return<BinaryT, LeftT, RightT>::type
        type;
  };

  template <typename BinaryT, typename LeftT, typename RightT, typename EnvT>
  typename parser_traversal_binary_result<TransformT, BinaryT, LeftT, RightT,
                                          EnvT>::type
  generate_binary(BinaryT const &, LeftT const &left_, RightT const &right_,
                  EnvT const & /*env*/) const {
    typedef typename BinaryT::parser_generator_t parser_generator_t;
    return parser_generator_t::template generate<LeftT, RightT>(left_, right_);
  }
};

///////////////////////////////////////////////////////////////////////////
//
//  transform_policies template
//
//      The transform_policies template metafunction could serve as a
//      base class for new metafunctions to be passed to the traverse meta
//      template (see above), where only minimal parts have to be
//      overwritten.
//
///////////////////////////////////////////////////////////////////////////

template <typename TransformT,
          typename PlainPolicyT = plain_identity_policy<TransformT>,
          typename UnaryPolicyT = unary_identity_policy<TransformT>,
          typename ActionPolicyT = action_identity_policy<TransformT>,
          typename BinaryPolicyT = binary_identity_policy<TransformT>>
struct transform_policies : public PlainPolicyT,
                            public UnaryPolicyT,
                            public ActionPolicyT,
                            public BinaryPolicyT {};

///////////////////////////////////////////////////////////////////////////
//
//  Identity transformation
//
//      The identity_transform metafunction supplied to the traverse
//      template will generate a new parser, which will be exactly
//      identical to the parser given as the parameter to the traverse
//      metafunction. I.e. the following conceptual 'equation' will be
//      always true:
//
//      some_parser ==
//          post_order::traverse(identity_transform(), some_parser)
//
///////////////////////////////////////////////////////////////////////////

struct identity_transform : transform_policies<identity_transform> {};

BOOST_SPIRIT_CLASSIC_NAMESPACE_END

} // namespace spirit
} // namespace boost

#endif // !defined(BOOST_SPIRIT_TRAVERSE_HPP)
