1 /*============================================================================= 2 Copyright (c) 2001-2011 Joel de Guzman 3 http://spirit.sourceforge.net/ 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_SPIRIT_META_COMPILER_OCTOBER_16_2008_1258PM 9 #define BOOST_SPIRIT_META_COMPILER_OCTOBER_16_2008_1258PM 10 11 #if defined(_MSC_VER) 12 #pragma once 13 #endif 14 15 #include <boost/config.hpp> 16 #include <boost/spirit/include/phoenix_limits.hpp> 17 #include <boost/detail/workaround.hpp> 18 #include <boost/spirit/include/phoenix_limits.hpp> // needs to be included before proto 19 #include <boost/proto/proto.hpp> 20 #include <boost/spirit/home/support/make_component.hpp> 21 #include <boost/spirit/home/support/modify.hpp> 22 #include <boost/spirit/home/support/detail/make_cons.hpp> 23 #include <boost/spirit/home/support/unused.hpp> 24 #include <boost/spirit/home/support/assert_msg.hpp> 25 #include <boost/utility/enable_if.hpp> 26 #include <boost/type_traits/remove_reference.hpp> 27 28 namespace boost { namespace spirit 29 { 30 // Some defaults... 31 32 template <typename Domain, typename Tag, typename Enable = void> 33 struct use_operator : mpl::false_ {}; 34 35 template <typename Domain, typename T, typename Enable = void> 36 struct use_function : mpl::false_ {}; 37 38 template <typename Domain, typename T, typename Enable = void> 39 struct use_directive : mpl::false_ {}; 40 41 template <typename Domain, typename T, typename Enable /* = void */> 42 struct is_modifier_directive : mpl::false_ {}; 43 44 template <typename Domain, typename T, typename Enable = void> 45 struct use_terminal : mpl::false_ {}; 46 47 template <typename Domain, typename T, typename Enable /*= void*/> 48 struct flatten_tree : mpl::false_ {}; 49 50 // Our meta-compiler. This is the main engine that hooks Spirit 51 // to the proto expression template engine. 52 53 template <typename Domain> 54 struct meta_compiler 55 { 56 struct meta_grammar; 57 58 BOOST_SPIRIT_ASSERT_MSG(( 59 !use_operator<Domain, proto::tag::subscript>::value 60 ), error_proto_tag_subscript_cannot_be_used, ()); 61 62 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1400) 63 // this is the non-broken part for compilers properly supporting 64 // partial template specialization (VC7.1 does not) 65 struct cases 66 { 67 template <typename Tag, typename Enable = void> 68 struct case_ 69 : proto::not_<proto::_> 70 {}; 71 72 /////////////////////////////////////////////////////////////////// 73 // terminals 74 /////////////////////////////////////////////////////////////////// 75 template <typename Enable> 76 struct case_<proto::tag::terminal, Enable> 77 : proto::when< 78 proto::if_<use_terminal<Domain, proto::_value>()>, 79 detail::make_terminal<Domain> 80 > 81 {}; 82 83 template <typename Tag> 84 struct case_<Tag, typename enable_if<use_operator<Domain, Tag> >::type> 85 : proto::or_< 86 /////////////////////////////////////////////////////////////////// 87 // binary operators 88 /////////////////////////////////////////////////////////////////// 89 proto::when<proto::binary_expr<Tag, meta_grammar, meta_grammar>, 90 detail::make_binary<Domain, Tag, meta_grammar> 91 >, 92 /////////////////////////////////////////////////////////////////// 93 // unary operators 94 /////////////////////////////////////////////////////////////////// 95 proto::when<proto::unary_expr<Tag, meta_grammar>, 96 detail::make_unary<Domain, Tag, meta_grammar> 97 > 98 > 99 {}; 100 101 template <typename Enable> 102 struct case_<proto::tag::subscript, Enable> 103 : proto::or_< 104 /////////////////////////////////////////////////////////////////// 105 // directives 106 /////////////////////////////////////////////////////////////////// 107 proto::when<proto::binary_expr<proto::tag::subscript 108 , proto::and_< 109 proto::terminal<proto::_> 110 , proto::if_<use_directive<Domain, proto::_value >()> > 111 , meta_grammar>, 112 detail::make_directive<Domain, meta_grammar> 113 >, 114 /////////////////////////////////////////////////////////////////// 115 // semantic actions 116 /////////////////////////////////////////////////////////////////// 117 proto::when<proto::binary_expr<proto::tag::subscript 118 , meta_grammar, proto::_>, 119 detail::make_action<Domain, meta_grammar> 120 > 121 > 122 {}; 123 }; 124 #else 125 // this part actually constitutes invalid C++ code, but it allows us to 126 // convince VC7.1 to do what we want 127 struct cases 128 { 129 template <typename Tag, typename Enable = void> 130 struct case_ 131 : proto::not_<proto::_> 132 {}; 133 134 /////////////////////////////////////////////////////////////////// 135 // terminals 136 /////////////////////////////////////////////////////////////////// 137 template <> 138 struct case_<proto::tag::terminal> 139 : proto::when< 140 proto::if_<use_terminal<Domain, proto::_value>()>, 141 detail::make_terminal<Domain> 142 > 143 {}; 144 145 template <typename Tag> 146 struct case_<Tag> 147 : proto::or_< 148 /////////////////////////////////////////////////////////////////// 149 // binary operators 150 /////////////////////////////////////////////////////////////////// 151 proto::when<proto::binary_expr< 152 typename enable_if<use_operator<Domain, Tag>, Tag>::type 153 , meta_grammar, meta_grammar> 154 , detail::make_binary<Domain, Tag, meta_grammar> 155 >, 156 /////////////////////////////////////////////////////////////////// 157 // unary operators 158 /////////////////////////////////////////////////////////////////// 159 proto::when<proto::unary_expr< 160 typename enable_if<use_operator<Domain, Tag>, Tag>::type 161 , meta_grammar> 162 , detail::make_unary<Domain, Tag, meta_grammar> 163 > 164 > 165 {}; 166 167 template <> 168 struct case_<proto::tag::subscript> 169 : proto::or_< 170 /////////////////////////////////////////////////////////////////// 171 // directives 172 /////////////////////////////////////////////////////////////////// 173 proto::when<proto::binary_expr<proto::tag::subscript 174 , proto::and_< 175 proto::terminal<proto::_> 176 , proto::if_<use_directive<Domain, proto::_value >()> > 177 , meta_grammar>, 178 detail::make_directive<Domain, meta_grammar> 179 >, 180 /////////////////////////////////////////////////////////////////// 181 // semantic actions 182 /////////////////////////////////////////////////////////////////// 183 proto::when<proto::binary_expr<proto::tag::subscript 184 , meta_grammar, proto::_>, 185 detail::make_action<Domain, meta_grammar> 186 > 187 > 188 {}; 189 }; 190 #endif 191 192 struct meta_grammar 193 : proto::switch_<cases> 194 {}; 195 }; 196 197 namespace result_of 198 { 199 // Default case 200 template <typename Domain, typename Expr 201 , typename Modifiers = unused_type, typename Enable = void> 202 struct compile 203 { 204 typedef typename meta_compiler<Domain>::meta_grammar meta_grammar; 205 typedef typename meta_grammar:: 206 template result<meta_grammar(Expr, mpl::void_, Modifiers)>::type 207 type; 208 }; 209 210 // If Expr is not a proto expression, make it a terminal 211 template <typename Domain, typename Expr, typename Modifiers> 212 struct compile<Domain, Expr, Modifiers, 213 typename disable_if<proto::is_expr<Expr> >::type> 214 : compile<Domain, typename proto::terminal<Expr>::type, Modifiers> {}; 215 } 216 217 namespace traits 218 { 219 // Check if Expr matches the domain's grammar 220 template <typename Domain, typename Expr> 221 struct matches : 222 proto::matches< 223 typename proto::result_of::as_expr< 224 typename remove_reference<Expr>::type>::type, 225 typename meta_compiler<Domain>::meta_grammar 226 > 227 { 228 }; 229 } 230 231 namespace detail 232 { 233 template <typename Domain> 234 struct compiler 235 { 236 // Default case 237 template <typename Expr, typename Modifiers> 238 static typename spirit::result_of::compile<Domain, Expr, Modifiers>::type compileboost::spirit::detail::compiler239 compile(Expr const& expr, Modifiers modifiers, mpl::true_) 240 { 241 typename meta_compiler<Domain>::meta_grammar compiler; 242 return compiler(expr, mpl::void_(), modifiers); 243 } 244 245 // If Expr is not a proto expression, make it a terminal 246 template <typename Expr, typename Modifiers> 247 static typename spirit::result_of::compile<Domain, Expr, Modifiers>::type compileboost::spirit::detail::compiler248 compile(Expr const& expr, Modifiers modifiers, mpl::false_) 249 { 250 typename meta_compiler<Domain>::meta_grammar compiler; 251 typedef typename detail::as_meta_element<Expr>::type expr_; 252 typename proto::terminal<expr_>::type term = {expr}; 253 return compiler(term, mpl::void_(), modifiers); 254 } 255 }; 256 } 257 258 template <typename Domain, typename Expr> 259 inline typename result_of::compile<Domain, Expr, unused_type>::type compile(Expr const & expr)260 compile(Expr const& expr) 261 { 262 typedef typename proto::is_expr<Expr>::type is_expr; 263 return detail::compiler<Domain>::compile(expr, unused, is_expr()); 264 } 265 266 template <typename Domain, typename Expr, typename Modifiers> 267 inline typename result_of::compile<Domain, Expr, Modifiers>::type compile(Expr const & expr,Modifiers modifiers)268 compile(Expr const& expr, Modifiers modifiers) 269 { 270 typedef typename proto::is_expr<Expr>::type is_expr; 271 return detail::compiler<Domain>::compile(expr, modifiers, is_expr()); 272 } 273 274 /////////////////////////////////////////////////////////////////////////// 275 template <typename Elements, template <typename Subject> class generator> 276 struct make_unary_composite 277 { 278 typedef typename 279 fusion::result_of::value_at_c<Elements, 0>::type 280 element_type; 281 typedef generator<element_type> result_type; operator ()boost::spirit::make_unary_composite282 result_type operator()(Elements const& elements, unused_type) const 283 { 284 return result_type(fusion::at_c<0>(elements)); 285 } 286 }; 287 288 template <typename Elements, template <typename Left, typename Right> class generator> 289 struct make_binary_composite 290 { 291 typedef typename 292 fusion::result_of::value_at_c<Elements, 0>::type 293 left_type; 294 typedef typename 295 fusion::result_of::value_at_c<Elements, 1>::type 296 right_type; 297 typedef generator<left_type, right_type> result_type; 298 operator ()boost::spirit::make_binary_composite299 result_type operator()(Elements const& elements, unused_type) const 300 { 301 return result_type( 302 fusion::at_c<0>(elements) 303 , fusion::at_c<1>(elements) 304 ); 305 } 306 }; 307 308 template <typename Elements, template <typename Elements_> class generator> 309 struct make_nary_composite 310 { 311 typedef generator<Elements> result_type; operator ()boost::spirit::make_nary_composite312 result_type operator()(Elements const& elements, unused_type) const 313 { 314 return result_type(elements); 315 } 316 }; 317 318 }} 319 320 #endif 321