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