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     #include <boost/phoenix/scope/detail/local_gen.hpp>
197 #undef BOOST_PHOENIX_SCOPE_ACTOR_GEN_NAME
198 #undef BOOST_PHOENIX_SCOPE_ACTOR_GEN_FUNCTION
199 #undef BOOST_PHOENIX_SCOPE_ACTOR_GEN_CONST
200 
201     template <typename Dummy>
202     struct is_nullary::when<rule::let_, Dummy>
203         : proto::make<
204             mpl::and_<
205                 proto::fold<
206                     proto::call<proto::_value(proto::_child_c<0>)>
207                   , proto::make<mpl::true_()>
208                   , proto::make<
209                         mpl::and_<
210                             proto::_state
211                           , proto::call<
212                                 evaluator(
213                                     proto::_
214                                   , _context
215                                   , proto::make<proto::empty_env()>
216                                 )
217                             >
218                         >()
219                     >
220                 >
221               , evaluator(
222                     proto::_child_c<2>
223                   , proto::call<
224                         functional::context(
225                             proto::make<
226                                 mpl::true_()
227                             >
228                           , proto::make<
229                                 detail::scope_is_nullary_actions()
230                             >
231                         )
232                     >
233                   , proto::make<
234                         proto::empty_env()
235                     >
236                 )
237             >()
238         >
239     {};
240 }}
241 
242 #endif
243