1 /*==============================================================================
2     Copyright (c) 2005-2010 Joel de Guzman
3     Copyright (c) 2010 Thomas Heller
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 ==============================================================================*/
8 #ifndef BOOST_PHOENIX_CORE_TERMINAL_HPP
9 #define BOOST_PHOENIX_CORE_TERMINAL_HPP
10 
11 #include <boost/phoenix/core/limits.hpp>
12 #include <boost/call_traits.hpp>
13 #include <boost/is_placeholder.hpp>
14 #include <boost/phoenix/core/actor.hpp>
15 #include <boost/phoenix/core/meta_grammar.hpp>
16 #include <boost/phoenix/core/terminal_fwd.hpp>
17 #include <boost/proto/matches.hpp>
18 #include <boost/proto/transform/lazy.hpp>
19 #include <boost/proto/functional/fusion/at.hpp>
20 #include <boost/type_traits/remove_pointer.hpp>
21 
22 #define BOOST_PHOENIX_DEFINE_CUSTOM_TERMINAL(Template, Terminal, IsNullary, EvalFun)\
23     namespace boost { namespace phoenix                                         \
24     {                                                                           \
25         namespace result_of                                                     \
26         {                                                                       \
27             Template                                                            \
28             struct is_nullary<                                                  \
29                 custom_terminal<                                                \
30                     Terminal                                                    \
31                 >                                                               \
32             >                                                                   \
33                 : IsNullary                                                     \
34             {};                                                                 \
35         }                                                                       \
36         Template                                                                \
37         struct is_custom_terminal<Terminal >: mpl::true_ {};                    \
38                                                                                 \
39         Template                                                                \
40         struct custom_terminal<Terminal > : proto::call<EvalFun > {};           \
41     }}                                                                          \
42 /**/
43 
44 namespace boost { namespace phoenix
45 {
46     template <typename T, typename Dummy>
47     struct is_custom_terminal
48         : mpl::false_ {};
49 
50     template <typename T, typename Dummy>
51     struct custom_terminal;
52 
53     namespace tag {
54       struct terminal /*: public proto::tag::terminal */ {};
55     }
56 
57     namespace expression
58     {
59         template <typename T, template <typename> class Actor = actor>
60         struct terminal
61             : proto::terminal<
62                 T//typename call_traits<T>::value_type
63             >
64         {
65             typedef
66                 proto::basic_expr<
67                 proto::tag::terminal
68             // tag::terminal //cannot change to use phoenix tag - breaks code.
69                   , proto::term<T>
70                   , 0
71                 >
72                 base_type;
73             typedef Actor<base_type> type;
74 
makeboost::phoenix::expression::terminal75             static const type make(typename call_traits<T>::param_type t)
76             {
77             // ?? Should the next line be Actor not actor which is the default?
78                 actor<base_type> const e = {base_type::make(t)};
79                 //Actor<base_type> const e = {base_type::make(t)};
80                 return e;
81             }
82         };
83     }
84 
85     namespace rule
86     {
87         struct argument
88             : proto::if_<boost::is_placeholder<proto::_value>()>
89         {};
90 
91         struct custom_terminal
92             : proto::if_<boost::phoenix::is_custom_terminal<proto::_value>()>
93         {};
94 
95         struct terminal
96             : proto::terminal<proto::_>
97         {};
98     }
99 
100     template <typename Dummy>
101     struct meta_grammar::case_<proto::tag::terminal, Dummy>
102         : proto::or_<
103             enable_rule<rule::argument       , Dummy>
104           , enable_rule<rule::custom_terminal, Dummy>
105           , enable_rule<rule::terminal       , Dummy>
106         >
107     {};
108 
109     template <typename Dummy>
110     struct default_actions::when<rule::custom_terminal, Dummy>
111         : proto::lazy<
112             custom_terminal<proto::_value>(
113                 proto::_value
114               , _context
115             )
116         >
117     {};
118 
119     namespace detail
120     {
121         template <typename N>
122         struct placeholder_idx
123             : mpl::int_<N::value>
124         {};
125     }
126 
127     template <typename Grammar>
128     struct default_actions::when<rule::argument, Grammar>
129         : proto::call<
130             proto::functional::at(
131                 _env
132               , proto::make<
133                     detail::placeholder_idx<
134                         proto::make<
135                             boost::is_placeholder<proto::_value>()
136                         >
137                     >()
138                 >
139             )
140         >
141     {};
142 }}
143 
144 #endif
145