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     typedef TupleArgsT parent_t;
41 
local_tuplephoenix::local_tuple42     local_tuple(TupleArgsT const& args, TupleLocsT const& locs_)
43     :   TupleArgsT(args), locs(locs_) {}
44 
parentphoenix::local_tuple45     TupleArgsT&         parent()        { return *this; }
parentphoenix::local_tuple46     TupleArgsT const&   parent() const  { return *this; }
47 
48     mutable TupleLocsT locs;
49 };
50 
51 ///////////////////////////////////////////////////////////////////////////////
52 //
53 //  local_var_result
54 //
55 //      This is a return type computer. Given a constant integer N, a
56 //      parent index and a tuple, get the Nth local variable type. The
57 //      parent index is an integer specifying which parent scope to
58 //      access; 0==current scope, 1==parent scope, 2==parent's parent
59 //      scope.
60 //
61 //      This is a metaprogram with partial specializations. There is a
62 //      general case, a special case for local_tuples and a terminating
63 //      special case for local_tuples.
64 //
65 //      General case: If TupleT is not really a local_tuple, we just return nil_t.
66 //
67 //      local_tuples case:
68 //          Parent index is 0: We get the Nth local variable.
69 //          Otherwise: We subclass from local_tuples<N, Parent-1, TupleArgsT>
70 //
71 ///////////////////////////////////////////////////////////////////////////////
72 template <int N, int Parent, typename TupleT>
73 struct local_var_result {
74 
75     typedef nil_t type;
76 };
77 
78 //////////////////////////////////
79 template <int N, int Parent, typename TupleArgsT, typename TupleLocsT>
80 struct local_var_result<N, Parent, local_tuple<TupleArgsT, TupleLocsT> >
81 :   public local_var_result<N, Parent-1, TupleArgsT> {};
82 
83 //////////////////////////////////
84 template <int N, typename TupleArgsT, typename TupleLocsT>
85 struct local_var_result<N, 0, local_tuple<TupleArgsT, TupleLocsT> > {
86 
87     typedef typename tuple_element<
88         N, TupleLocsT
89     >::type& type;
90 
getphoenix::local_var_result91     static type get(local_tuple<TupleArgsT, TupleLocsT> const& tuple)
92     { return tuple.locs[tuple_index<N>()]; }
93 };
94 
95 ///////////////////////////////////////////////////////////////////////////////
96 //
97 //  local_var
98 //
99 //      This class looks so curiously like the argument class. local_var
100 //      provides access to the Nth local variable packed in the tuple
101 //      duo local_tuple above. Parent specifies the Nth parent scope.
102 //      0==current scope, 1==parent scope, 2==parent's parent scope. The
103 //      member function parent<N>() may be called to provide access to
104 //      outer scopes.
105 //
106 //      Note that the member function eval expects a local_tuple
107 //      argument. Otherwise there will be acompile-time error. local_var
108 //      primitives only work within the context of a context_composite
109 //      (see below).
110 //
111 //      Provided are some predefined local_var actors for 0..N local
112 //      variable access: loc1..locN.
113 //
114 ///////////////////////////////////////////////////////////////////////////////
115 template <int N, int Parent = 0>
116 struct local_var {
117 
118     template <typename TupleT>
119     struct result {
120 
121         typedef typename local_var_result<N, Parent, TupleT>::type type;
122     };
123 
124     template <typename TupleT>
125     typename local_var_result<N, Parent, TupleT>::type
evalphoenix::local_var126     eval(TupleT const& tuple) const
127     {
128         return local_var_result<N, Parent, TupleT>::get(tuple);
129     }
130 
131     template <int PIndex>
132     actor<local_var<N, Parent+PIndex> >
parentphoenix::local_var133     parent() const
134     {
135         return local_var<N, Parent+PIndex>();
136     }
137 };
138 
139 //////////////////////////////////
140 namespace locals {
141 
142     actor<local_var<0> > const result   = local_var<0>();
143     actor<local_var<1> > const loc1     = local_var<1>();
144     actor<local_var<2> > const loc2     = local_var<2>();
145     actor<local_var<3> > const loc3     = local_var<3>();
146     actor<local_var<4> > const loc4     = local_var<4>();
147 }
148 
149 ///////////////////////////////////////////////////////////////////////////////
150 //
151 //  context_composite
152 //
153 //      This class encapsulates an actor and some local variable
154 //      initializers packed in a tuple.
155 //
156 //      context_composite is just like a proxy and delegates the actual
157 //      evaluation to the actor. The actor does the actual work. In the
158 //      eval member function, before invoking the embedded actor's eval
159 //      member function, we first stuff an instance of our locals and
160 //      bundle both 'args' and 'locals' in a local_tuple. This
161 //      local_tuple instance is created in the stack initializing it
162 //      with our locals member. We then pass this local_tuple instance
163 //      as an argument to the actor's eval member function.
164 //
165 ///////////////////////////////////////////////////////////////////////////////
166 template <typename ActorT, typename LocsT>
167 struct context_composite {
168 
169     typedef context_composite<ActorT, LocsT> self_t;
170 
171     template <typename TupleT>
172     struct result { typedef typename tuple_element<0, LocsT>::type type; };
173 
context_compositephoenix::context_composite174     context_composite(ActorT const& actor_, LocsT const& locals_)
175     :   actor(actor_), locals(locals_) {}
176 
177     template <typename TupleT>
178     typename tuple_element<0, LocsT>::type
evalphoenix::context_composite179     eval(TupleT const& args) const
180     {
181         local_tuple<TupleT, LocsT>  local_context(args, locals);
182         actor.eval(local_context);
183         return local_context.locs[tuple_index<0>()];
184     }
185 
186     ActorT actor;
187     LocsT locals;
188 };
189 
190 ///////////////////////////////////////////////////////////////////////////////
191 //
192 //  context_gen
193 //
194 //      At construction time, this class is given some local var-
195 //      initializers packed in a tuple. We just store this for later.
196 //      The operator[] of this class creates the actual context_composite
197 //      given an actor. This is responsible for the construct
198 //      context<types>[actor].
199 //
200 ///////////////////////////////////////////////////////////////////////////////
201 template <typename LocsT>
202 struct context_gen {
203 
context_genphoenix::context_gen204     context_gen(LocsT const& locals_)
205     :   locals(locals_) {}
206 
207     template <typename ActorT>
208     actor<context_composite<typename as_actor<ActorT>::type, LocsT> >
operator []phoenix::context_gen209     operator[](ActorT const& actor)
210     {
211         return context_composite<typename as_actor<ActorT>::type, LocsT>
212             (as_actor<ActorT>::convert(actor), locals);
213     }
214 
215     LocsT locals;
216 };
217 
218 ///////////////////////////////////////////////////////////////////////////////
219 //
220 //    Front end generator functions. These generators are overloaded for
221 //    1..N local variables. context<T0,... TN>(i0,...iN) generate context_gen
222 //    objects (see above).
223 //
224 ///////////////////////////////////////////////////////////////////////////////
225 template <typename T0>
226 inline context_gen<tuple<T0> >
context()227 context()
228 {
229     typedef tuple<T0> tuple_t;
230     return context_gen<tuple_t>(tuple_t(T0()));
231 }
232 
233 //////////////////////////////////
234 template <typename T0, typename T1>
235 inline context_gen<tuple<T0, T1> >
context(T1 const & _1=T1 ())236 context(
237     T1 const& _1 = T1()
238 )
239 {
240     typedef tuple<T0, T1> tuple_t;
241     return context_gen<tuple_t>(tuple_t(T0(), _1));
242 }
243 
244 //////////////////////////////////
245 template <typename T0, typename T1, typename T2>
246 inline context_gen<tuple<T0, T1, T2> >
context(T1 const & _1=T1 (),T2 const & _2=T2 ())247 context(
248     T1 const& _1 = T1(),
249     T2 const& _2 = T2()
250 )
251 {
252     typedef tuple<T0, T1, T2> tuple_t;
253     return context_gen<tuple_t>(tuple_t(T0(), _1, _2));
254 }
255 
256 //////////////////////////////////
257 template <typename T0, typename T1, typename T2, typename T3>
258 inline context_gen<tuple<T0, T1, T2, T3> >
context(T1 const & _1=T1 (),T2 const & _2=T2 (),T3 const & _3=T3 ())259 context(
260     T1 const& _1 = T1(),
261     T2 const& _2 = T2(),
262     T3 const& _3 = T3()
263 )
264 {
265     typedef tuple<T0, T1, T2, T3> tuple_t;
266     return context_gen<tuple_t>(tuple_t(T0(), _1, _2, _3));
267 }
268 
269 //////////////////////////////////
270 template <typename T0, typename T1, typename T2, typename T3, typename T4>
271 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 ())272 context(
273     T1 const& _1 = T1(),
274     T2 const& _2 = T2(),
275     T3 const& _3 = T3(),
276     T4 const& _4 = T4()
277 )
278 {
279     typedef tuple<T0, T1, T2, T3> tuple_t;
280     return context_gen<tuple_t>(tuple_t(T0(), _1, _2, _3, _4));
281 }
282 
283 ///////////////////////////////////////////////////////////////////////////////
284 }
285 
286 //////////////////////////////////
287 using namespace std;
288 using namespace phoenix;
289 using namespace phoenix::locals;
290 
291 //////////////////////////////////
292 int
main()293 main()
294 {
295     context<nil_t>(1)
296     [
297         cout << loc1 << '\n',
298         context<nil_t>(2)
299         [
300             cout << loc1.parent<1>() << ' ' << loc1 << '\n',
301             context<nil_t>(3)
302             [
303                 cout << loc1.parent<2>() << ' ' << loc1.parent<1>() << ' ' << loc1 << '\n'
304             ]
305         ]
306     ]
307 
308     ();
309 
310     return 0;
311 }
312