/*=============================================================================
    Copyright (c) 2001-2007 Joel de Guzman

    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_BASIC_RULES_JAN_14_2007_1222PM)
#define BOOST_SPIRIT_BASIC_RULES_JAN_14_2007_1222PM

#include <boost/spirit/home/support/meta_grammar/grammar.hpp>
#include <boost/spirit/home/support/meta_grammar/basic_transforms.hpp>
#include <boost/spirit/home/support/component.hpp>
#include <boost/fusion/include/cons.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/transform.hpp>
#include <boost/mpl/identity.hpp>

namespace boost { namespace spirit { namespace meta_grammar
{
    namespace detail
    {
        template <typename Director>
        struct director_identity
        {
            template <typename>
            struct apply : mpl::identity<Director> {};
        };
    }

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes an empty (the terminal is not saved in
    //  the elements tuple) terminal spirit::component given a domain,
    //  a proto-tag and a director.  Example:
    //
    //      a
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename Domain, typename Tag, typename Director>
    struct empty_terminal_rule
    : compose_empty<
            proto::terminal<Tag>
          , Domain
          , detail::director_identity<Director>
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a non-empty (the terminal is saved in
    //  the elements tuple) terminal spirit::component given a domain,
    //  a proto-tag and a director.  Example:
    //
    //      a
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename Domain, typename Tag, typename Director>
    struct terminal_rule
    : compose_single<
            proto::terminal<Tag>
          , Domain
          , detail::director_identity<Director>
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a 1-element spirit::component given a
    //  domain, a proto-tag and a director. No folding takes place. Example:
    //
    //      +a
    //
    ///////////////////////////////////////////////////////////////////////////
    template <
        typename Domain, typename Tag, typename Director
      , typename SubjectGrammar = proto::_
    >
    struct unary_rule
    : compose_single<
            proto::unary_expr<
                Tag
              , SubjectGrammar
            >
          , Domain
          , detail::director_identity<Director>
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a 2-element spirit::component given a
    //  domain, a proto-tag and a director. No folding takes place. Example:
    //
    //      a - b
    //
    ///////////////////////////////////////////////////////////////////////////
    template <
        typename Domain, typename Tag, typename Director
      , typename LeftGrammar = proto::_, typename RightGrammar = proto::_
    >
    struct binary_rule
    : compose_double<
            proto::binary_expr<
                Tag
              , LeftGrammar
              , RightGrammar
            >
          , Domain
          , detail::director_identity<Director>
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a 3-element spirit::component given a
    //  domain, a proto-tag and a director. No folding takes place. Example:
    //
    //      if_else(cond_expr,true_exp,false_expr)
    //
    ///////////////////////////////////////////////////////////////////////////

    template <
    typename Domain, typename Tag, typename Director
    , typename Grammar0 = proto::_, typename Grammar1 = proto::_, typename Grammar2 = proto::_
    >
    struct ternary_rule
    : compose_triple<
            proto::nary_expr<
                Tag
              , Grammar0
              , Grammar1
              , Grammar2
            >
          , Domain
          , detail::director_identity<Director>
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a 1-element spirit::component from a
    //  binary expression. Only the RHS is stored.
    //
    //      a[b]
    //
    ///////////////////////////////////////////////////////////////////////////
    template <
        typename Domain, typename Tag, typename Director
      , typename LeftGrammar = proto::_, typename RightGrammar = proto::_
    >
    struct binary_rule_rhs
    : compose_right<
            proto::binary_expr<
                Tag
              , LeftGrammar
              , RightGrammar
            >
          , Domain
          , detail::director_identity<Director>
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a multi-element spirit::component given a
    //  domain, a proto-tag and a director. All like-operators are folded
    //  into one. Example:
    //
    //      a | b | c
    //
    ///////////////////////////////////////////////////////////////////////////
    template <
        typename Domain, typename Tag, typename Director
      , typename Grammar = proto::_
    >
    struct binary_rule_flat
    : compose_list<
            proto::when<
                proto::binary_expr<Tag, Grammar, Grammar>
              , proto::reverse_fold_tree<
                    proto::_
                  , fusion::nil()
                  , fusion::cons<Grammar, proto::_state>(Grammar, proto::_state)
                >
            >
          , Domain
          , Director
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a 1-element function spirit::component
    //  given a domain, a proto-tag and a director. Example:
    //
    //      f(a)
    ///////////////////////////////////////////////////////////////////////////
    template <
        typename Domain, typename Tag
      , typename Director, typename ArgGrammar = proto::_>
    struct function1_rule
    : compose_function1<
            proto::function<proto::terminal<Tag>, ArgGrammar>
          , Domain
          , Director
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a 2-element function spirit::component
    //  given a domain, a proto-tag and a director. Example:
    //
    //      f(a, b)
    ///////////////////////////////////////////////////////////////////////////
    template <
        typename Domain, typename Tag
      , typename Director, typename ArgGrammar = proto::_>
    struct function2_rule
    : compose_function2<
            proto::function<
                proto::terminal<Tag>
              , ArgGrammar
              , ArgGrammar
            >
          , Domain
          , Director
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule for directives. The directive (terminal) tag
    //  is pushed into the modifier state (the Visitor). Example:
    //
    //      directive[a]
    ///////////////////////////////////////////////////////////////////////////
    template <typename Tag, typename SubjectGrammar = proto::_>
    struct deep_directive_meta_grammar
    : meta_grammar::compose_deep_directive<
            proto::when<
                proto::subscript<proto::terminal<Tag>, SubjectGrammar>
              , proto::call<SubjectGrammar(proto::_right)>
            >
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a 2-element spirit::component given a
    //  domain, a proto-tag, a director, and an embedded grammar. 
    //  Example:
    //
    //      directive[p]
    //
    //  The difference to deep_directive_meta_grammar is that it stores both
    //  parts of the expression without modifying the modifier state
    //
    ///////////////////////////////////////////////////////////////////////////
    template <
        typename Domain, typename Tag,
        typename Director, typename EmbeddedGrammar = proto::_
    >
    struct subscript_rule
      : compose_subscript<
            proto::binary_expr<
                proto::tag::subscript, 
                proto::terminal<Tag>, 
                EmbeddedGrammar
            >,
            Domain,
            Director
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a 2-element spirit::component given a
    //  domain, a proto-tag, a director, an argument and an embedded grammar. 
    //  Example:
    //
    //      directive(a)[p]
    //
    ///////////////////////////////////////////////////////////////////////////
    template <
        typename Domain, typename Tag,
        typename Director, typename ArgGrammar = proto::_, 
        typename EmbeddedGrammar = proto::_
    >
    struct subscript_function1_rule
      : compose_subscript_function1<
            proto::binary_expr<
                proto::tag::subscript,
                proto::function<proto::terminal<Tag>, ArgGrammar>,
                EmbeddedGrammar
            >,
            Domain,
            Director
        >
    {};

    ///////////////////////////////////////////////////////////////////////////
    //  A proto rule that composes a 3-element spirit::component given a
    //  domain, a proto-tag, a director, two arguments and an embedded grammar. 
    //  Example:
    //
    //      directive(a, b)[p]
    //
    ///////////////////////////////////////////////////////////////////////////
    template <
        typename Domain, typename Tag,
        typename Director, typename Arg1Grammar = proto::_, 
        typename Arg2Grammar = proto::_, typename EmbeddedGrammar = proto::_
    >
    struct subscript_function2_rule
      : compose_subscript_function2<
            proto::binary_expr<
                proto::tag::subscript,
                proto::function<proto::terminal<Tag>, Arg1Grammar, Arg2Grammar>,
                EmbeddedGrammar
            >,
            Domain,
            Director
        >
    {};

}}}

#endif
