1 /*==============================================================================
2     Copyright (c) 2001-2010 Joel de Guzman
3     Copyright (c) 2004 Daniel Wallin
4     Copyright (c) 2010 Thomas Heller
5     Copyright (c) 2015 John Fletcher
6 
7     Distributed under the Boost Software License, Version 1.0. (See accompanying
8     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 ==============================================================================*/
10 #ifndef BOOST_PHOENIX_SCOPE_LET_HPP
11 #define BOOST_PHOENIX_SCOPE_LET_HPP
12 
13 //#include <boost/assert.hpp>
14 //#include <sstream>
15 #include <boost/phoenix/core/limits.hpp>
16 #include <boost/fusion/include/transform.hpp>
17 #include <boost/fusion/include/as_vector.hpp>
18 #include <boost/phoenix/core/call.hpp>
19 #include <boost/phoenix/core/expression.hpp>
20 #include <boost/phoenix/core/meta_grammar.hpp>
21 #include <boost/phoenix/scope/scoped_environment.hpp>
22 #include <boost/phoenix/scope/local_variable.hpp>
23 #include <boost/phoenix/support/iterate.hpp>
24 #include <boost/phoenix/support/vector.hpp>
25 
26 BOOST_PHOENIX_DEFINE_EXPRESSION(
27     (boost)(phoenix)(let_)
28   , (proto::terminal<proto::_>) // Locals
29     (proto::terminal<proto::_>) // Map
30     (meta_grammar)
31 )
32 
33 namespace boost { namespace phoenix
34 {
35     struct let_eval
36     {
37           template <typename Sig>
38           struct result;
39 
40           template <typename This, typename Vars, typename Map, typename Expr, typename Context>
41           struct result<This(Vars, Map, Expr, Context)>
42           {
43             typedef
44                 typename proto::detail::uncvref<
45                     typename result_of::env<Context>::type
46                 >::type
47                 env_type;
48             typedef
49                 typename proto::detail::uncvref<
50                     typename result_of::actions<Context>::type
51                 >::type
52                 actions_type;
53             typedef
54                 typename proto::detail::uncvref<
55                     typename proto::result_of::value<Vars>::type
56                      >::type
57                      vars_type;
58             typedef
59                 typename proto::detail::uncvref<
60                     typename proto::result_of::value<Map>::type
61                      >::type
62                      map_type;
63 
64             typedef
65                 typename proto::detail::uncvref<Expr>::type
66                      expr_type;
67 
68             typedef typename
69                 detail::result_of::initialize_locals<
70                     vars_type
71                   , Context
72                 >::type
73             locals_type;
74 
75             typedef typename
76                 result_of::eval<
77                     expr_type
78                   , typename result_of::context<
79                         scoped_environment<
80                             env_type
81                           , env_type
82                           , locals_type
83                           , map_type
84                         >
85                       , actions_type
86                     >::type
87                 >::type
88                 type;
89           };
90 
91         template <typename Vars, typename Map, typename Expr, typename Context>
92         typename result<let_eval(Vars const&, Map const&, Expr const &, Context const &)>::type const
operator ()boost::phoenix::let_eval93         operator()(Vars const & vars, Map, Expr const & expr, Context const & ctx) const
94         {
95             Vars vars_(vars);
96 
97             typedef
98                 typename proto::detail::uncvref<
99                     typename result_of::env<Context>::type
100                 >::type
101                 env_type;
102             typedef
103                 typename proto::detail::uncvref<
104                     typename proto::result_of::value<Vars>::type
105                 >::type
106                 vars_type;
107             typedef
108                 typename proto::detail::uncvref<
109                     typename proto::result_of::value<Map>::type
110                 >::type
111                 map_type;
112 
113             typedef typename
114                 detail::result_of::initialize_locals<
115                     vars_type
116                   , Context
117                 >::type
118             locals_type;
119 
120             locals_type locals = initialize_locals(proto::value(vars_), ctx);
121 
122             //typedef typename result<let_eval(Vars const&, Map const&, Expr const &, Context const &)>::type result_type;
123 
124             scoped_environment<
125                 env_type
126               , env_type
127               , locals_type
128               , map_type
129             >
130             env(phoenix::env(ctx), phoenix::env(ctx), locals);
131 
132             // Fix for bugs (trial)
133             // The idea is to do something which will not be optimised away.
134             //int vsize = boost::fusion::size(vars);
135             //std::stringstream strm;
136             //strm << vsize << std::endl;
137             //int size = strm.str().length();
138             //BOOST_ASSERT(size >= 0);
139             return eval(expr, phoenix::context(env, phoenix::actions(ctx)));
140             // typedef is_value<result_type> is_val;
141             //if(is_val::value) This seems always to be true
142             //{
143             //   std::cout << "let result has value type" << std::endl;
144             // }
145             //if (is_val(r) ) std::cout << "let returns val" << std::endl;
146             //std::cout << "result is " << r << std::endl;
147             //return r;
148         }
149     };
150 
151     template <typename Dummy>
152     struct default_actions::when<rule::let_, Dummy>
153         : call<let_eval, Dummy>
154     {};
155 
156     template <typename Locals, typename Map>
157     struct let_actor_gen
158     {
let_actor_genboost::phoenix::let_actor_gen159         let_actor_gen(Locals const & locals_)
160             : locals(locals_)
161         {}
162 
let_actor_genboost::phoenix::let_actor_gen163         let_actor_gen(let_actor_gen const & o)
164             : locals(o.locals)
165         {}
166 
167         template <typename Expr>
168         typename expression::let_<
169             Locals
170           , Map
171           , Expr
172         >::type const
operator []boost::phoenix::let_actor_gen173         operator[](Expr const & expr) const
174         {
175            typedef typename expression::let_<
176               Locals
177             , Map
178             , Expr
179            >::type let_type;
180            //typedef is_value<let_type> is_val;
181 
182            let_type let_exp = expression::let_<Locals, Map, Expr>::make(locals, Map(), expr);
183            //if(is_val::value) //This seems always to be true
184            //{
185            //  std::cout << "let has value type" << std::endl;
186            //}
187            return let_exp;
188         }
189 
190         Locals locals;
191     };
192 
193 #define BOOST_PHOENIX_SCOPE_ACTOR_GEN_NAME let_actor_gen
194 #define BOOST_PHOENIX_SCOPE_ACTOR_GEN_FUNCTION let
195 #define BOOST_PHOENIX_SCOPE_ACTOR_GEN_CONST
196 #if defined(BOOST_PHOENIX_NO_VARIADIC_SCOPE)
197     #include <boost/phoenix/scope/detail/cpp03/local_gen.hpp>
198 #else
199     #include <boost/phoenix/scope/detail/local_gen.hpp>
200 #endif
201 #undef BOOST_PHOENIX_SCOPE_ACTOR_GEN_NAME
202 #undef BOOST_PHOENIX_SCOPE_ACTOR_GEN_FUNCTION
203 #undef BOOST_PHOENIX_SCOPE_ACTOR_GEN_CONST
204 
205     template <typename Dummy>
206     struct is_nullary::when<rule::let_, Dummy>
207         : proto::make<
208             mpl::and_<
209                 proto::fold<
210                     proto::call<proto::_value(proto::_child_c<0>)>
211                   , proto::make<mpl::true_()>
212                   , proto::make<
213                         mpl::and_<
214                             proto::_state
215                           , proto::call<
216                                 evaluator(
217                                     proto::_
218                                   , _context
219                                   , proto::make<proto::empty_env()>
220                                 )
221                             >
222                         >()
223                     >
224                 >
225               , evaluator(
226                     proto::_child_c<2>
227                   , proto::call<
228                         functional::context(
229                             proto::make<
230                                 mpl::true_()
231                             >
232                           , proto::make<
233                                 detail::scope_is_nullary_actions()
234                             >
235                         )
236                     >
237                   , proto::make<
238                         proto::empty_env()
239                     >
240                 )
241             >()
242         >
243     {};
244 }}
245 
246 #endif
247