/*============================================================================= Phoenix V1.2.1 Copyright (c) 2001-2003 Joel de Guzman Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ==============================================================================*/ #include #include #include #define PHOENIX_LIMIT 5 #include #include #include #include #include #include namespace phoenix { /////////////////////////////////////////////////////////////////////////////// // // local_tuple // // This *is a* tuple like the one we see in TupleT in any actor // base class' eval member function. local_tuple should look and // feel the same as a tupled-args, that's why it is derived from // TupleArgsT. It has an added member, locs which is another tuple // where the local variables will be stored. locs is mutable to // allow read-write access to our locals regardless of // local_tuple's constness (The eval member function accepts it as // a const argument). // /////////////////////////////////////////////////////////////////////////////// template struct local_tuple : public TupleArgsT { local_tuple(TupleArgsT const& args, TupleLocsT const& locs_) : TupleArgsT(args), locs(locs_) {} mutable TupleLocsT locs; }; /////////////////////////////////////////////////////////////////////////////// // // local_var_result // // This is a return type computer. Given a constant integer N, a // parent index and a tuple, get the Nth local variable type. The // parent index is an integer specifying which parent scope to // access; 0==current scope, 1==parent scope, 2==parent's parent // scope etc. // // This is a metaprogram with partial specializations. There is a // general case, a special case for local_tuples and a terminating // special case for local_tuples. // // General case: If TupleT is not really a local_tuple, we just return nil_t. // // local_tuples case: // Parent index is 0: We get the Nth local variable. // Otherwise: We subclass from local_tuples // /////////////////////////////////////////////////////////////////////////////// template struct local_var_result { typedef nil_t type; }; ////////////////////////////////// template struct local_var_result > : public local_var_result {}; ////////////////////////////////// template struct local_var_result > { typedef typename tuple_element::type& type; static type get(local_tuple const& tuple) { return tuple.locs[tuple_index()]; } }; /////////////////////////////////////////////////////////////////////////////// // // local_var // // This class looks so curiously like the argument class. local_var // provides access to the Nth local variable packed in the tuple // duo local_tuple above. Parent specifies the Nth parent scope. // 0==current scope, 1==parent scope, 2==parent's parent scope etc. // The member function parent() may be called to provide access // to outer scopes. // // Note that the member function eval expects a local_tuple // argument. Otherwise there will be acompile-time error. local_var // primitives only work within the context of a context_composite // (see below). // // Provided are some predefined local_var actors for 0..N local // variable access: lvar1..locN. // /////////////////////////////////////////////////////////////////////////////// template struct local_var { typedef local_var self_t; template struct result { typedef typename local_var_result::type type; }; template typename actor_result::type eval(TupleT const& tuple) const { return local_var_result::get(tuple); } template actor > parent() const { return local_var(); } }; ////////////////////////////////// namespace locals { actor > const result = local_var<0>(); actor > const lvar1 = local_var<1>(); actor > const lvar2 = local_var<2>(); actor > const lvar3 = local_var<3>(); actor > const lvar4 = local_var<4>(); } /////////////////////////////////////////////////////////////////////////////// template struct local_func_result { typedef nil_t type; }; ////////////////////////////////// template struct local_func_result > : public local_func_result {}; ////////////////////////////////// template struct local_func_result > { typedef typename actor_result< typename tuple_element::type, local_tuple >::type type; template static type eval(local_tuple const& tuple) { return tuple.locs[tuple_index()].eval(tuple); } }; template < int N, int Parent, typename A0 = nil_t, typename A1 = nil_t, typename A2 = nil_t, typename A3 = nil_t, typename A4 = nil_t > struct local_function_actor; ////////////////////////////////// template struct local_function_base { template struct result { typedef typename local_func_result::type type; }; }; ////////////////////////////////// template struct local_function_actor : public local_function_base { template typename local_func_result< N, Parent, local_tuple >::type eval(local_tuple const& args) const { typedef local_tuple local_tuple_t; typedef tuple<> tuple_t; tuple_t local_args; local_tuple local_context(local_args, args.locs); return local_func_result< N, Parent, local_tuple_t> ::eval(local_context); } }; ////////////////////////////////// template struct local_function_actor : public local_function_base { local_function_actor( A0 const& _0) : a0(_0) {} template typename local_func_result< N, Parent, local_tuple >::type eval(local_tuple const& args) const { typedef local_tuple local_tuple_t; typename actor_result::type r0 = a0.eval(args); typedef tuple< typename actor_result::type > tuple_t; tuple_t local_args(r0); local_tuple local_context(local_args, args.locs); return local_func_result< N, Parent, local_tuple_t> ::eval(local_context); } A0 a0; // actors }; namespace impl { template < int N, int Parent, typename T0 = nil_t, typename T1 = nil_t, typename T2 = nil_t, typename T3 = nil_t, typename T4 = nil_t > struct make_local_function_actor { typedef local_function_actor< N, Parent, typename as_actor::type, typename as_actor::type, typename as_actor::type, typename as_actor::type, typename as_actor::type > composite_type; typedef actor type; }; } template struct local_function { actor > operator()() const { return local_function_actor(); } template typename impl::make_local_function_actor::type operator()(T0 const& _0) const { return impl::make_local_function_actor::composite_type(_0); } template local_function parent() const { return local_function(); } }; ////////////////////////////////// namespace locals { local_function<1> const lfun1 = local_function<1>(); local_function<2> const lfun2 = local_function<2>(); local_function<3> const lfun3 = local_function<3>(); local_function<4> const lfun4 = local_function<4>(); } /////////////////////////////////////////////////////////////////////////////// // // context_composite // // This class encapsulates an actor and some local variable // initializers packed in a tuple. // // context_composite is just like a proxy and delegates the actual // evaluation to the actor. The actor does the actual work. In the // eval member function, before invoking the embedded actor's eval // member function, we first stuff an instance of our locals and // bundle both 'args' and 'locals' in a local_tuple. This // local_tuple instance is created in the stack initializing it // with our locals member. We then pass this local_tuple instance // as an argument to the actor's eval member function. // /////////////////////////////////////////////////////////////////////////////// template struct context_composite { typedef context_composite self_t; template struct result { typedef typename tuple_element<0, LocsT>::type type; }; context_composite(ActorT const& actor_, LocsT const& locals_) : actor(actor_), locals(locals_) {} template typename tuple_element<0, LocsT>::type eval(TupleT const& args) const { local_tuple local_context(args, locals); actor.eval(local_context); return local_context.locs[tuple_index<0>()]; } ActorT actor; LocsT locals; }; /////////////////////////////////////////////////////////////////////////////// // // context_gen // // At construction time, this class is given some local var- // initializers packed in a tuple. We just store this for later. // The operator[] of this class creates the actual context_composite // given an actor. This is responsible for the construct // context[actor]. // /////////////////////////////////////////////////////////////////////////////// template struct context_gen { context_gen(LocsT const& locals_) : locals(locals_) {} template actor::type, LocsT> > operator[](ActorT const& actor) { return context_composite::type, LocsT> (as_actor::convert(actor), locals); } LocsT locals; }; /////////////////////////////////////////////////////////////////////////////// // // Front end generator functions. These generators are overloaded for // 1..N local variables. context(i0,...iN) generate // context_gen objects (see above). // /////////////////////////////////////////////////////////////////////////////// template inline context_gen > context() { typedef tuple tuple_t; return context_gen(tuple_t(T0())); } ////////////////////////////////// template inline context_gen > context( T1 const& _1 = T1() ) { typedef tuple tuple_t; return context_gen(tuple_t(T0(), _1)); } ////////////////////////////////// template inline context_gen > context( T1 const& _1 = T1(), T2 const& _2 = T2() ) { typedef tuple tuple_t; return context_gen(tuple_t(T0(), _1, _2)); } ////////////////////////////////// template inline context_gen > context( T1 const& _1 = T1(), T2 const& _2 = T2(), T3 const& _3 = T3() ) { typedef tuple tuple_t; return context_gen(tuple_t(T0(), _1, _2, _3)); } ////////////////////////////////// template inline context_gen > context( T1 const& _1 = T1(), T2 const& _2 = T2(), T3 const& _3 = T3(), T4 const& _4 = T4() ) { typedef tuple tuple_t; return context_gen(tuple_t(T0(), _1, _2, _3, _4)); } /////////////////////////////////////////////////////////////////////////////// } ////////////////////////////////// using namespace std; using namespace phoenix; using namespace phoenix::locals; ////////////////////////////////// int main() { int _10 = 10; #ifndef __BORLANDC__ context ( 1000, // lvar1: local int variable cout << arg1 << '\n', // lfun2: local function w/ 1 argument (arg1) lvar1 * 2, // lfun3: local function that accesses local variable lvar1 lfun2(2 * arg1) // lfun4: local function that calls local function lfun2 ) [ lfun2(arg1 + 2000), lfun2(val(5000) * 2), lfun2(lvar1 + lfun3()), lfun4(val(55)), cout << lvar1 << '\n', cout << lfun3() << '\n', cout << val("bye bye\n") ] (_10); #else // Borland does not like local variables w/ local functions // we can have local variables (see sample 7..9) *OR* // local functions (this: sample 10) but not both // Sigh... Borland :-{ context ( 12345, cout << arg1 << '\n' ) [ lfun2(arg1 + 687), lfun2(val(9999) * 2), cout << val("bye bye\n") ] (_10); #endif return 0; }