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

// as_action.hpp

//

//  Copyright 2007 Eric Niebler.

//  Copyright 2007 David Jenkins.

//

//  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)



#ifndef BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_ACTION_HPP_EAN_04_05_2007

#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_ACTION_HPP_EAN_04_05_2007



// MS compatible compilers support #pragma once

#if defined(_MSC_VER) && (_MSC_VER >= 1020)

# pragma once

#endif



#include <boost/mpl/sizeof.hpp>

#include <boost/mpl/min_max.hpp>

#include <boost/mpl/apply_wrap.hpp>

#include <boost/xpressive/detail/detail_fwd.hpp>

#include <boost/xpressive/detail/core/matcher/attr_end_matcher.hpp>

#include <boost/xpressive/detail/static/static.hpp>

#include <boost/xpressive/detail/static/transforms/as_quantifier.hpp>

#include <boost/xpressive/proto/proto.hpp>

#include <boost/xpressive/proto/transform/arg.hpp>

#include <boost/xpressive/proto/transform/fold.hpp>



namespace boost { namespace xpressive { namespace detail

{

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

    // FindAttr

    //  Look for patterns like (a1= terminal<RHS>) and return the type of the RHS.

    template<typename Nbr>

    struct FindAttr

      : proto::or_<

            proto::transform::state< proto::terminal<proto::_> >

            // Ignore nested actions, because attributes are scoped:

          , proto::transform::state< proto::subscript<proto::_, proto::_> >

          , proto::transform::arg<

                proto::transform::right<

                    proto::assign<

                        proto::terminal<xpressive::detail::attribute_placeholder<Nbr> >

                      , proto::_

                    >

                >

            >

          , proto::transform::fold<proto::nary_expr<proto::_, proto::vararg<FindAttr<Nbr> > > >

        >

    {};



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

    // by_value

    //  Store all terminals within an action by value to avoid dangling references.

    template<typename Terminal>

    struct by_value

      : Terminal

    {

        template<typename Expr, typename State, typename Visitor>

        struct apply

          : proto::result_of::as_expr<typename proto::result_of::arg<Expr>::type>

        {};



        template<typename Expr, typename State, typename Visitor>

        static typename apply<Expr, State, Visitor>::type

        call(Expr const &expr, State const &, Visitor &)

        {

            return proto::as_expr(proto::arg(expr));

        }

    };



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

    // read_attr

    //  Placeholder that knows the slot number of an attribute as well as the type

    //  of the object stored in it.

    template<typename Nbr, typename Matcher>

    struct read_attr

    {

        typedef Nbr nbr_type;

        typedef Matcher matcher_type;

    };



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

    // as_read_attr

    //  For patterns like (a1 = RHS)[ref(i) = a1], transform to

    //  (a1 = RHS)[ref(i) = read_attr<1, RHS>] so that when reading the attribute

    //  we know what type is stored in the attribute slot.

    template<typename Grammar>

    struct as_read_attr

      : Grammar

    {

        template<typename Expr, typename State, typename Visitor>

        struct apply

          : proto::result_of::as_expr<

                read_attr<

                    typename Expr::proto_arg0::nbr_type

                  , typename FindAttr<typename Expr::proto_arg0::nbr_type>

                        ::template apply<State, mpl::void_, int>::type

                >

            >

        {};



        template<typename Expr, typename State, typename Visitor>

        static typename apply<Expr, State, Visitor>::type

        call(Expr const &, State const &, Visitor &)

        {

            typename apply<Expr, State, Visitor>::type that = {{}};

            return that;

        }

    };



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

    // DeepCopy

    //  Turn all refs into values, and also bind all attribute placeholders with

    //  the types from which they are being assigned.

    struct DeepCopy

      : proto::or_<

            as_read_attr<proto::terminal<xpressive::detail::attribute_placeholder<proto::_> > >

          , by_value<proto::terminal<proto::_> >

          , proto::nary_expr<proto::_, proto::vararg<DeepCopy> >

        >

    {};



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

    // max_attr

    //  Take the maximum of the current attr slot number and the state.

    template<typename Grammar>

    struct max_attr

      : Grammar

    {

        template<typename Expr, typename State, typename Visitor>

        struct apply

          : mpl::max<State, typename Grammar::template apply<Expr, State, Visitor>::type>

        {};

    };



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

    // attr_nbr

    //  For an attribute placeholder, return the attribute's slot number.

    template<typename Grammar>

    struct attr_nbr

      : Grammar

    {

        template<typename Expr, typename State, typename Visitor>

        struct apply

          : Expr::proto_arg0::nbr_type

        {};

    };



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

    // MaxAttr

    //  In an action (rx)[act], find the largest attribute slot being used.

    struct MaxAttr

      : proto::or_<

            attr_nbr< proto::terminal< xpressive::detail::attribute_placeholder<proto::_> > >

          , proto::transform::state< proto::terminal<proto::_> >

            // Ignore nested actions, because attributes are scoped:

          , proto::transform::state< proto::subscript<proto::_, proto::_> >

          , proto::transform::fold<proto::nary_expr<proto::_, max_attr<proto::vararg<MaxAttr> > > >

        >

    {};



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

    // as_attr_matcher

    //  turn a1=matcher into attr_matcher<Matcher>(1)

    template<typename Grammar>

    struct as_attr_matcher

      : Grammar

    {

        as_attr_matcher();



        template<typename Expr, typename State, typename Visitor>

        struct apply

        {

            typedef

                attr_matcher<

                    typename proto::result_of::arg<typename Expr::proto_arg1>::type

                  , typename Visitor::traits_type

                  , Visitor::icase_type::value

                >

            type;

        };



        template<typename Expr, typename State, typename Visitor>

        static typename apply<Expr, State, Visitor>::type

        call(Expr const &expr, State const &, Visitor &visitor)

        {

            return typename apply<Expr, State, Visitor>::type(

                Expr::proto_arg0::proto_base_expr::proto_arg0::nbr_type::value

              , proto::arg(proto::right(expr))

              , visitor.traits()

            );

        }

    };



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

    // add_attrs

    //  Wrap an expression in attr_begin_matcher/attr_end_matcher pair

    template<typename Grammar>

    struct add_attrs

      : Grammar

    {

        add_attrs();



        template<typename Expr, typename, typename>

        struct apply

          : proto::shift_right<

                typename proto::terminal<

                    attr_begin_matcher<typename MaxAttr::apply<Expr, mpl::int_<0>, int>::type>

                >::type

              , typename proto::shift_right<

                    Expr

                  , proto::terminal<attr_end_matcher>::type

                >::type

            >

        {};



        template<typename Expr, typename State, typename Visitor>

        static typename apply<Expr, State, Visitor>::type

        call(Expr const &expr, State const &, Visitor &)

        {

            attr_begin_matcher<typename MaxAttr::apply<Expr, mpl::int_<0>, int>::type> begin;

            attr_end_matcher end;

            typename apply<Expr, State, Visitor>::type that = {{begin}, {expr, {end}}};

            return that;

        }

    };



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

    // InsertAttrs

    struct InsertAttrs

      : proto::or_<

            add_attrs<proto::if_<mpl::apply_wrap3<MaxAttr, mpl::_, mpl::int_<0>, int> > >

          , proto::_

        >

    {};



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

    // CheckAssertion

    struct CheckAssertion

      : proto::function<

            proto::terminal<check_tag>

          , proto::_

        >

    {};



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

    // action_transform

    //  Turn A[B] into (mark_begin(n) >> A >> mark_end(n) >> action_matcher<B>(n))

    //  If A and B use attributes, wrap the above expression in

    //  a attr_begin_matcher<Count> / attr_end_matcher pair, where Count is

    //  the number of attribute slots used by the pattern/action.

    template<typename Grammar>

    struct as_action

      : Grammar

    {

        as_action();



        template<typename Expr, typename State, typename Visitor>

        struct apply

        {

            typedef typename proto::result_of::left<Expr>::type expr_type;

            typedef typename proto::result_of::right<Expr>::type action_type;

            typedef typename DeepCopy::apply<action_type, expr_type, int>::type action_copy_type;



            typedef

                typename InsertMark::apply<expr_type, State, Visitor>::type

            marked_expr_type;



            typedef

                typename mpl::if_<

                    proto::matches<action_type, CheckAssertion>

                  , predicate_matcher<action_copy_type>

                  , action_matcher<action_copy_type>

                >::type

            matcher_type;



            typedef

                typename proto::shift_right<

                    marked_expr_type

                  , typename proto::terminal<matcher_type>::type

                >::type

            no_attr_type;



            typedef

                typename InsertAttrs::apply<no_attr_type, State, Visitor>::type

            type;

        };



        template<typename Expr, typename State, typename Visitor>

        static typename apply<Expr, State, Visitor>::type

        call(Expr const &expr, State const &state, Visitor &visitor)

        {

            typedef apply<Expr, State, Visitor> apply_type;

            typedef typename apply_type::matcher_type matcher_type;



            int dummy = 0;

            typename apply_type::marked_expr_type marked_expr =

                InsertMark::call(proto::left(expr), state, visitor);



            typename apply_type::no_attr_type that =

            {

                marked_expr

              , {

                    matcher_type

                    (

                        DeepCopy::call(proto::right(expr), proto::left(expr), dummy)

                      , proto::arg(proto::left(marked_expr)).mark_number_

                    )

                }

            };



            return InsertAttrs::call(that, state, visitor);

        }

    };



}}}



#endif

