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