1 /*=============================================================================
2     Phoenix V1.2.1
3     Copyright (c) 2001-2003 Joel de Guzman
4 
5     Use, modification and distribution is subject to the Boost Software
6     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7     http://www.boost.org/LICENSE_1_0.txt)
8 ==============================================================================*/
9 #include <vector>
10 #include <algorithm>
11 #include <iostream>
12 
13 #define PHOENIX_LIMIT 5
14 #include <boost/spirit/include/phoenix1_operators.hpp>
15 #include <boost/spirit/include/phoenix1_primitives.hpp>
16 #include <boost/spirit/include/phoenix1_composite.hpp>
17 #include <boost/spirit/include/phoenix1_special_ops.hpp>
18 #include <boost/spirit/include/phoenix1_statements.hpp>
19 
20 namespace phoenix {
21 
22 ///////////////////////////////////////////////////////////////////////////////
23 //
24 //  local_tuple
25 //
26 //      This *is a* tuple like the one we see in TupleT in any actor
27 //      base class' eval member function. local_tuple should look and
28 //      feel the same as a tupled-args, that's why it is derived from
29 //      TupleArgsT. It has an added member, locs which is another tuple
30 //      where the local variables will be stored. locs is mutable to
31 //      allow read-write access to our locals regardless of
32 //      local_tuple's constness (The eval member function accepts it as
33 //      a const argument).
34 //
35 ///////////////////////////////////////////////////////////////////////////////
36 template <typename TupleArgsT, typename TupleLocsT>
37 struct local_tuple : public TupleArgsT {
38 
39     typedef TupleLocsT local_vars_t;
40 
local_tuplephoenix::local_tuple41     local_tuple(TupleArgsT const& args, TupleLocsT const& locs_)
42     :   TupleArgsT(args), locs(locs_) {}
43 
44     mutable TupleLocsT locs;
45 };
46 
47 ///////////////////////////////////////////////////////////////////////////////
48 //
49 //  local_var_result
50 //
51 //      This is a return type computer. Given a constant integer N and a
52 //      tuple, get the Nth local variable type. If TupleT is not really
53 //      a local_tuple, we just return nil_t. Otherwise we get the Nth
54 //      local variable type.
55 //
56 ///////////////////////////////////////////////////////////////////////////////
57 template <int N, typename TupleT>
58 struct local_var_result {
59 
60     typedef nil_t type;
61 };
62 
63 //////////////////////////////////
64 template <int N, typename TupleArgsT, typename TupleLocsT>
65 struct local_var_result<N, local_tuple<TupleArgsT, TupleLocsT> > {
66 
67     typedef typename tuple_element<N, TupleLocsT>::type& type;
68 };
69 
70 ///////////////////////////////////////////////////////////////////////////////
71 //
72 //  local_var
73 //
74 //      This class looks so curiously like the argument class. local_var
75 //      provides access to the Nth local variable packed in the tuple
76 //      duo local_tuple above. Note that the member function eval
77 //      expects a local_tuple argument. Otherwise the expression
78 //      'tuple.locs' will fail (compile-time error). local_var
79 //      primitives only work within the context of a context_composite
80 //      (see below).
81 //
82 //      Provided are some predefined local_var actors for 0..N local
83 //      variable access: loc1..locN.
84 //
85 ///////////////////////////////////////////////////////////////////////////////
86 template <int N>
87 struct local_var {
88 
89     template <typename TupleT>
90     struct result {
91 
92         typedef typename local_var_result<N, TupleT>::type type;
93     };
94 
95     template <typename TupleT>
96     typename local_var_result<N, TupleT>::type
evalphoenix::local_var97     eval(TupleT const& tuple) const
98     {
99         return tuple.locs[tuple_index<N>()];
100     }
101 };
102 
103 //////////////////////////////////
104 namespace locals {
105 
106     actor<local_var<0> > const result   = local_var<0>();
107     actor<local_var<1> > const loc1     = local_var<1>();
108     actor<local_var<2> > const loc2     = local_var<2>();
109     actor<local_var<3> > const loc3     = local_var<3>();
110     actor<local_var<4> > const loc4     = local_var<4>();
111 }
112 
113 ///////////////////////////////////////////////////////////////////////////////
114 //
115 //  context_composite
116 //
117 //      This class encapsulates an actor and some local variable
118 //      initializers packed in a tuple.
119 //
120 //      context_composite is just like a proxy and delegates the actual
121 //      evaluation to the actor. The actor does the actual work. In the
122 //      eval member function, before invoking the embedded actor's eval
123 //      member function, we first stuff an instance of our locals and
124 //      bundle both 'args' and 'locals' in a local_tuple. This
125 //      local_tuple instance is created in the stack initializing it
126 //      with our locals member. We then pass this local_tuple instance
127 //      as an argument to the actor's eval member function.
128 //
129 ///////////////////////////////////////////////////////////////////////////////
130 template <typename ActorT, typename LocsT>
131 struct context_composite {
132 
133     typedef context_composite<ActorT, LocsT> self_t;
134 
135     template <typename TupleT>
136     struct result { typedef typename tuple_element<0, LocsT>::type type; };
137 
context_compositephoenix::context_composite138     context_composite(ActorT const& actor_, LocsT const& locals_)
139     :   actor(actor_), locals(locals_) {}
140 
141     template <typename TupleT>
142     typename tuple_element<0, LocsT>::type
evalphoenix::context_composite143     eval(TupleT const& args) const
144     {
145         local_tuple<TupleT, LocsT>  local_context(args, locals);
146         actor.eval(local_context);
147         return local_context.locs[tuple_index<0>()];
148     }
149 
150     ActorT actor;
151     LocsT locals;
152 };
153 
154 ///////////////////////////////////////////////////////////////////////////////
155 //
156 //  context_gen
157 //
158 //      At construction time, this class is given some local var-
159 //      initializers packed in a tuple. We just store this for later.
160 //      The operator[] of this class creates the actual context_composite
161 //      given an actor. This is responsible for the construct
162 //      context<types>[actor].
163 //
164 ///////////////////////////////////////////////////////////////////////////////
165 template <typename LocsT>
166 struct context_gen {
167 
context_genphoenix::context_gen168     context_gen(LocsT const& locals_)
169     :   locals(locals_) {}
170 
171     template <typename ActorT>
172     actor<context_composite<typename as_actor<ActorT>::type, LocsT> >
operator []phoenix::context_gen173     operator[](ActorT const& actor)
174     {
175         return context_composite<typename as_actor<ActorT>::type, LocsT>
176             (as_actor<ActorT>::convert(actor), locals);
177     }
178 
179     LocsT locals;
180 };
181 
182 ///////////////////////////////////////////////////////////////////////////////
183 //
184 //    Front end generator functions. These generators are overloaded for
185 //    1..N local variables. context<T0,... TN>(i0,...iN) generate context_gen
186 //    objects (see above).
187 //
188 ///////////////////////////////////////////////////////////////////////////////
189 template <typename T0>
190 inline context_gen<tuple<T0> >
context()191 context()
192 {
193     typedef tuple<T0> tuple_t;
194     return context_gen<tuple_t>(tuple_t(T0()));
195 }
196 
197 //////////////////////////////////
198 template <typename T0, typename T1>
199 inline context_gen<tuple<T0, T1> >
context(T1 const & _1=T1 ())200 context(
201     T1 const& _1 = T1()
202 )
203 {
204     typedef tuple<T0, T1> tuple_t;
205     return context_gen<tuple_t>(tuple_t(T0(), _1));
206 }
207 
208 //////////////////////////////////
209 template <typename T0, typename T1, typename T2>
210 inline context_gen<tuple<T0, T1, T2> >
context(T1 const & _1=T1 (),T2 const & _2=T2 ())211 context(
212     T1 const& _1 = T1(),
213     T2 const& _2 = T2()
214 )
215 {
216     typedef tuple<T0, T1, T2> tuple_t;
217     return context_gen<tuple_t>(tuple_t(T0(), _1, _2));
218 }
219 
220 //////////////////////////////////
221 template <typename T0, typename T1, typename T2, typename T3>
222 inline context_gen<tuple<T0, T1, T2, T3> >
context(T1 const & _1=T1 (),T2 const & _2=T2 (),T3 const & _3=T3 ())223 context(
224     T1 const& _1 = T1(),
225     T2 const& _2 = T2(),
226     T3 const& _3 = T3()
227 )
228 {
229     typedef tuple<T0, T1, T2, T3> tuple_t;
230     return context_gen<tuple_t>(tuple_t(T0(), _1, _2, _3));
231 }
232 
233 //////////////////////////////////
234 template <typename T0, typename T1, typename T2, typename T3, typename T4>
235 inline context_gen<tuple<T0, T1, T2, T3, T4> >
context(T1 const & _1=T1 (),T2 const & _2=T2 (),T3 const & _3=T3 (),T4 const & _4=T4 ())236 context(
237     T1 const& _1 = T1(),
238     T2 const& _2 = T2(),
239     T3 const& _3 = T3(),
240     T4 const& _4 = T4()
241 )
242 {
243     typedef tuple<T0, T1, T2, T3> tuple_t;
244     return context_gen<tuple_t>(tuple_t(T0(), _1, _2, _3, _4));
245 }
246 
247 ///////////////////////////////////////////////////////////////////////////////
248 }
249 
250 //////////////////////////////////
251 using namespace std;
252 using namespace phoenix;
253 using namespace phoenix::locals;
254 
255 //////////////////////////////////
256 int
main()257 main()
258 {
259     int init[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
260     vector<int> c(init, init + 10);
261     typedef vector<int>::iterator iterator;
262 
263     //  find the first element > 5, print each element
264     //  as we traverse the container c. Print the result
265     //  if one is found.
266 
267     find_if(c.begin(), c.end(),
268         context<bool>()
269         [
270             cout << arg1,
271             result = arg1 > 5,
272             if_(!result)
273             [
274                 cout << val(", ")
275             ]
276             .else_
277             [
278                 cout << val(" found result == ") << arg1
279             ]
280         ]
281     );
282 
283     return 0;
284 }
285