/*=============================================================================
    Spirit v1.6.0
    Copyright (c) 2002-2003 Hartmut Kaiser
    http://spirit.sourceforge.net/

    Permission to copy, use, modify, sell and distribute this software is
    granted provided this copyright notice appears in all copies. This
    software is provided "as is" without express or implied warranty, and
    with no claim as to its suitability for any purpose.
=============================================================================*/
#ifndef BOOST_SPIRIT_REFACTORING_IPP
#define BOOST_SPIRIT_REFACTORING_IPP

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

///////////////////////////////////////////////////////////////////////////////
//
//  The struct 'self_nested_refactoring' is used to indicate, that the
//  refactoring algorithm should be 'self-nested'.
//
//  The struct 'non_nested_refactoring' is used to indicate, that no nesting
//  of refactoring algorithms is reqired.
//
///////////////////////////////////////////////////////////////////////////////

struct non_nested_refactoring { typedef non_nested_refactoring embed_t; };
struct self_nested_refactoring { typedef self_nested_refactoring embed_t; };

///////////////////////////////////////////////////////////////////////////////
namespace impl {

///////////////////////////////////////////////////////////////////////////////
//
//  Helper templates for refactoring parsers
//
///////////////////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////
    //
    //  refactor the left unary operand of a binary parser
    //
    //      The refactoring should be done only if the left operand is an
    //      unary_parser_category parser.
    //
    ///////////////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////
    template <typename CategoryT>
    struct refactor_unary_nested {

        template <
            typename ParserT, typename NestedT,
            typename ScannerT, typename BinaryT
        >
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, BinaryT const& binary,
            NestedT const& /*nested_d*/)
        {
            return binary.parse(scan);
        }
    };

    template <>
    struct refactor_unary_nested<unary_parser_category> {

        template <
            typename ParserT, typename ScannerT, typename BinaryT,
            typename NestedT
        >
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, BinaryT const& binary,
            NestedT const& nested_d)
        {
            typedef typename BinaryT::parser_generator_t op_t;
            typedef
                typename BinaryT::left_t::parser_generator_t
                unary_t;

            return
                unary_t::generate(
                    nested_d[
                        op_t::generate(binary.left().subject(), binary.right())
                    ]
                ).parse(scan);
        }
    };

    ///////////////////////////////////////////////////////////////////////////
    template <typename CategoryT>
    struct refactor_unary_non_nested {

        template <typename ParserT, typename ScannerT, typename BinaryT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, BinaryT const& binary)
        {
            return binary.parse(scan);
        }
    };

    template <>
    struct refactor_unary_non_nested<unary_parser_category> {

        template <typename ParserT, typename ScannerT, typename BinaryT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, BinaryT const& binary)
        {
            typedef typename BinaryT::parser_generator_t op_t;
            typedef
                typename BinaryT::left_t::parser_generator_t
                unary_t;

            return unary_t::generate(
                op_t::generate(binary.left().subject(), binary.right())
            ).parse(scan);
        }
    };

    ///////////////////////////////////////////////////////////////////////////
    template <typename NestedT>
    struct refactor_unary_type {

        template <typename ParserT, typename ScannerT, typename BinaryT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &p, ScannerT const& scan, BinaryT const& binary,
            NestedT const& nested_d)
        {
            typedef
                typename BinaryT::left_t::parser_category_t
                parser_category_t;

            return refactor_unary_nested<parser_category_t>::
                    parse(p, scan, binary, nested_d);
        }
    };

    template <>
    struct refactor_unary_type<non_nested_refactoring> {

        template <typename ParserT, typename ScannerT, typename BinaryT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &p, ScannerT const& scan, BinaryT const& binary,
            non_nested_refactoring const&)
        {
            typedef
                typename BinaryT::left_t::parser_category_t
                parser_category_t;

            return refactor_unary_non_nested<parser_category_t>::
                    parse(p, scan, binary);
        }

    };

    template <>
    struct refactor_unary_type<self_nested_refactoring> {

        template <typename ParserT, typename ScannerT, typename BinaryT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &p, ScannerT const& scan, BinaryT const& binary,
            self_nested_refactoring const &nested_tag)
        {
            typedef
                typename BinaryT::left_t::parser_category_t
                parser_category_t;
            typedef typename ParserT::parser_generator_t parser_generator_t;

            parser_generator_t nested_d(nested_tag);
            return refactor_unary_nested<parser_category_t>::
                    parse(p, scan, binary, nested_d);
        }

    };

    ///////////////////////////////////////////////////////////////////////////
    //
    //  refactor the action on the left operand of a binary parser
    //
    //      The refactoring should be done only if the left operand is an
    //      action_parser_category parser.
    //
    ///////////////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////
    template <typename CategoryT>
    struct refactor_action_nested {

        template <
            typename ParserT, typename ScannerT, typename BinaryT,
            typename NestedT
        >
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, BinaryT const& binary,
            NestedT const& nested_d)
        {
            return nested_d[binary].parse(scan);
        }
    };

    template <>
    struct refactor_action_nested<action_parser_category> {

        template <
            typename ParserT, typename ScannerT, typename BinaryT,
            typename NestedT
        >
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, BinaryT const& binary,
            NestedT const& nested_d)
        {
            typedef typename BinaryT::parser_generator_t binary_gen_t;

            return (
                nested_d[
                    binary_gen_t::generate(
                        binary.left().subject(),
                        binary.right()
                    )
                ][binary.left().predicate()]
            ).parse(scan);
        }
    };

    ///////////////////////////////////////////////////////////////////////////
    template <typename CategoryT>
    struct refactor_action_non_nested {

        template <typename ParserT, typename ScannerT, typename BinaryT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, BinaryT const& binary)
        {
            return binary.parse(scan);
        }
    };

    template <>
    struct refactor_action_non_nested<action_parser_category> {

        template <typename ParserT, typename ScannerT, typename BinaryT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, BinaryT const& binary)
        {
            typedef typename BinaryT::parser_generator_t binary_gen_t;

            return (
                binary_gen_t::generate(
                    binary.left().subject(),
                    binary.right()
                )[binary.left().predicate()]
            ).parse(scan);
        }
    };

    ///////////////////////////////////////////////////////////////////////////
    template <typename NestedT>
    struct refactor_action_type {

        template <typename ParserT, typename ScannerT, typename BinaryT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &p, ScannerT const& scan, BinaryT const& binary,
            NestedT const& nested_d)
        {
            typedef
                typename BinaryT::left_t::parser_category_t
                parser_category_t;

            return refactor_action_nested<parser_category_t>::
                    parse(p, scan, binary, nested_d);
        }
    };

    template <>
    struct refactor_action_type<non_nested_refactoring> {

        template <typename ParserT, typename ScannerT, typename BinaryT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &p, ScannerT const& scan, BinaryT const& binary,
            non_nested_refactoring const&)
        {
            typedef
                typename BinaryT::left_t::parser_category_t
                parser_category_t;

            return refactor_action_non_nested<parser_category_t>::
                parse(p, scan, binary);
        }
    };

    template <>
    struct refactor_action_type<self_nested_refactoring> {

        template <typename ParserT, typename ScannerT, typename BinaryT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &p, ScannerT const& scan, BinaryT const& binary,
            self_nested_refactoring const &nested_tag)
        {
            typedef typename ParserT::parser_generator_t parser_generator_t;
            typedef
                typename BinaryT::left_t::parser_category_t
                parser_category_t;

            parser_generator_t nested_d(nested_tag);
            return refactor_action_nested<parser_category_t>::
                    parse(p, scan, binary, nested_d);
        }
    };

    ///////////////////////////////////////////////////////////////////////////
    //
    //  refactor the action attached to a binary parser
    //
    //      The refactoring should be done only if the given parser is an
    //      binary_parser_category parser.
    //
    ///////////////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////////////
    template <typename CategoryT>
    struct attach_action_nested {

        template <
            typename ParserT, typename ScannerT, typename ActionT,
            typename NestedT
        >
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, ActionT const &action,
            NestedT const& nested_d)
        {
            return action.parse(scan);
        }
    };

    template <>
    struct attach_action_nested<binary_parser_category> {

        template <
            typename ParserT, typename ScannerT, typename ActionT,
            typename NestedT
        >
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, ActionT const &action,
            NestedT const& nested_d)
        {
            typedef
                typename ActionT::subject_t::parser_generator_t
                binary_gen_t;

            return (
                binary_gen_t::generate(
                    nested_d[action.subject().left()[action.predicate()]],
                    nested_d[action.subject().right()[action.predicate()]]
                )
            ).parse(scan);
        }
    };

    ///////////////////////////////////////////////////////////////////////////
    template <typename CategoryT>
    struct attach_action_non_nested {

        template <typename ParserT, typename ScannerT, typename ActionT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, ActionT const &action)
        {
            return action.parse(scan);
        }
    };

    template <>
    struct attach_action_non_nested<binary_parser_category> {

        template <typename ParserT, typename ScannerT, typename ActionT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &, ScannerT const& scan, ActionT const &action)
        {
            typedef
                typename ActionT::subject_t::parser_generator_t
                binary_gen_t;

            return (
                binary_gen_t::generate(
                    action.subject().left()[action.predicate()],
                    action.subject().right()[action.predicate()]
                )
            ).parse(scan);
        }
    };

    ///////////////////////////////////////////////////////////////////////////
    template <typename NestedT>
    struct attach_action_type {

        template <typename ParserT, typename ScannerT, typename ActionT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &p, ScannerT const& scan, ActionT const& action,
            NestedT const& nested_d)
        {
            typedef
                typename ActionT::subject_t::parser_category_t
                parser_category_t;

            return attach_action_nested<parser_category_t>::
                    parse(p, scan, action, nested_d);
        }
    };

    template <>
    struct attach_action_type<non_nested_refactoring> {

        template <typename ParserT, typename ScannerT, typename ActionT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &p, ScannerT const& scan, ActionT const &action,
            non_nested_refactoring const&)
        {
            typedef
                typename ActionT::subject_t::parser_category_t
                parser_category_t;

            return attach_action_non_nested<parser_category_t>::
                parse(p, scan, action);
        }
    };

    template <>
    struct attach_action_type<self_nested_refactoring> {

        template <typename ParserT, typename ScannerT, typename ActionT>
        static typename parser_result<ParserT, ScannerT>::type
        parse(ParserT const &p, ScannerT const& scan, ActionT const &action,
            self_nested_refactoring const& nested_tag)
        {
            typedef typename ParserT::parser_generator_t parser_generator_t;
            typedef
                typename ActionT::subject_t::parser_category_t
                parser_category_t;

            parser_generator_t nested_d(nested_tag);
            return attach_action_nested<parser_category_t>::
                    parse(p, scan, action, nested_d);
        }
    };

}   // namespace impl

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

#endif

