summaryrefslogtreecommitdiffstats
blob: 1ad7932d864f23cafbc442b5381323d5030250ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*=============================================================================
    Copyright (c) 2001-2007 Joel de Guzman
    Copyright (c) 2004 Daniel Wallin

    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 PHOENIX_SCOPE_DETAIL_LOCAL_VARIABLE_HPP
#define PHOENIX_SCOPE_DETAIL_LOCAL_VARIABLE_HPP

#include <boost/mpl/int.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/less.hpp>
#include <boost/mpl/size.hpp>
#include <boost/fusion/include/at.hpp>
#include <boost/fusion/include/value_at.hpp>
#include <boost/preprocessor/enum.hpp>
#include <boost/preprocessor/repeat.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/is_reference.hpp>

#define PHOENIX_MAP_LOCAL_TEMPLATE_PARAM(z, n, data) \
    typename T##n = unused<n>

#define PHOENIX_MAP_LOCAL_DISPATCH(z, n, data)  \
    typedef char(&result##n)[n+2];              \
    static result##n get(T##n*);

namespace boost { namespace phoenix
{
    template <typename Env, typename OuterEnv, typename Locals, typename Map>
    struct scoped_environment;

    namespace detail
    {
        template <typename Env>
        struct initialize_local
        {
            template <class F>
            struct result;

            template <class F, class Actor>
            struct result<F(Actor)>
            {
                typedef typename remove_reference<Actor>::type actor_type;
                typedef typename actor_type::template result<Env>::type type;
            };

            initialize_local(Env const& env)
                : env(env) {}

            template <typename Actor>
            typename result<initialize_local(Actor)>::type
            operator()(Actor const& actor) const
            {
                return actor.eval(env);
            }

            Env const& env;

        private:
            // silence MSVC warning C4512: assignment operator could not be generated
            initialize_local& operator= (initialize_local const&);
        };

        template <typename T>
        struct is_scoped_environment : mpl::false_ {};

        template <typename Env, typename OuterEnv, typename Locals, typename Map>
        struct is_scoped_environment<scoped_environment<Env, OuterEnv, Locals, Map> >
            : mpl::true_ {};

        template <int N>
        struct unused;

        template <BOOST_PP_ENUM(
            PHOENIX_LOCAL_LIMIT, PHOENIX_MAP_LOCAL_TEMPLATE_PARAM, _)>
        struct map_local_index_to_tuple
        {
            typedef char(&not_found)[1];
            static not_found get(...);

            BOOST_PP_REPEAT(PHOENIX_LOCAL_LIMIT, PHOENIX_MAP_LOCAL_DISPATCH, _)
        };

        template<typename T>
        T* generate_pointer();

        template <typename Map, typename Tag>
        struct get_index
        {
            BOOST_STATIC_CONSTANT(int,
                value = (
                    static_cast<int>((sizeof(Map::get(generate_pointer<Tag>()))) / sizeof(char)) - 2
                ));

            // if value == -1, Tag is not found
            typedef mpl::int_<value> type;
        };

        template <typename Local, typename Env>
        struct apply_local;

        template <typename Local, typename Env>
        struct outer_local
        {
            typedef typename
                apply_local<Local, typename Env::outer_env_type>::type
            type;
        };

        template <typename Locals, typename Index>
        struct get_local_or_void
        {
            typedef typename
                mpl::eval_if<
                    mpl::less<Index, mpl::size<Locals> >
                  , fusion::result_of::at<Locals, Index>
                  , mpl::identity<fusion::void_>
                >::type
            type;
        };

        template <typename Local, typename Env, typename Index>
        struct get_local_from_index
        {
            typedef typename
                mpl::eval_if<
                    mpl::equal_to<Index, mpl::int_<-1> >
                  , outer_local<Local, Env>
                  , get_local_or_void<typename Env::locals_type, Index>
                >::type
            type;
        };

        template <typename Local, typename Env>
        struct get_local
        {
            typedef typename
                get_index<
                    typename Env::map_type, typename Local::key_type>::type
            index_type;

            typedef typename
                get_local_from_index<Local, Env, index_type>::type
            type;
        };

        template <typename Local, typename Env>
        struct apply_local
        {
            // $$$ TODO: static assert that Env is a scoped_environment $$$
            typedef typename get_local<Local, Env>::type type;
        };

        template <typename Key>
        struct eval_local
        {
            template <typename RT, typename Env, typename Index>
            static RT
            get(Env const& env, Index, mpl::false_)
            {
                return RT(fusion::at<Index>(env.locals));
            }

            template <typename RT, typename Env, typename Index>
            static RT
            get(Env const& env, Index index, mpl::true_)
            {
                typedef typename
                    get_index<typename Env::outer_env_type::map_type, Key>::type
                index_type;

                return get<RT>(
                    env.outer_env
                  , index_type()
                  , mpl::equal_to<index_type, mpl::int_<-1> >());
            }

            template <typename RT, typename Env, typename Index>
            static RT
            get(Env const& env, Index index)
            {
                return get<RT>(
                    env
                  , index
                  , mpl::equal_to<Index, mpl::int_<-1> >());
            }
        };
    }
}}

#undef PHOENIX_MAP_LOCAL_TEMPLATE_PARAM
#undef PHOENIX_MAP_LOCAL_DISPATCH
#endif