1 /*============================================================================= 2 Copyright (c) 2001-2011 Joel de Guzman 3 Copyright (c) 2001-2011 Hartmut Kaiser 4 Copyright (c) 2011 Thomas Heller 5 6 Distributed under the Boost Software License, Version 1.0. (See accompanying 7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 ==============================================================================*/ 9 #if !defined(BOOST_SPIRIT_TERMINAL_NOVEMBER_04_2008_0906AM) 10 #define BOOST_SPIRIT_TERMINAL_NOVEMBER_04_2008_0906AM 11 12 #if defined(_MSC_VER) 13 #pragma once 14 #endif 15 16 #include <boost/spirit/include/phoenix_core.hpp> 17 #include <boost/spirit/include/phoenix_function.hpp> 18 #include <boost/proto/proto.hpp> 19 #include <boost/fusion/include/void.hpp> 20 #include <boost/spirit/home/support/meta_compiler.hpp> 21 #include <boost/spirit/home/support/detail/make_vector.hpp> 22 #include <boost/spirit/home/support/unused.hpp> 23 #include <boost/spirit/home/support/detail/is_spirit_tag.hpp> 24 #include <boost/preprocessor/tuple/elem.hpp> 25 26 #include <boost/spirit/home/support/terminal_expression.hpp> 27 28 namespace boost { namespace spirit 29 { 30 template <typename Terminal, typename Args> 31 struct terminal_ex 32 { 33 typedef Terminal terminal_type; 34 typedef Args args_type; 35 terminal_exboost::spirit::terminal_ex36 terminal_ex(Args const& args) 37 : args(args) {} terminal_exboost::spirit::terminal_ex38 terminal_ex(Args const& args, Terminal const& term) 39 : args(args), term(term) {} 40 41 Args args; // Args is guaranteed to be a fusion::vectorN so you 42 // can use that template for detection and specialization 43 Terminal term; 44 }; 45 46 template <typename Terminal, typename Actor, int Arity> 47 struct lazy_terminal 48 { 49 typedef Terminal terminal_type; 50 typedef Actor actor_type; 51 static int const arity = Arity; 52 lazy_terminalboost::spirit::lazy_terminal53 lazy_terminal(Actor const& actor) 54 : actor(actor) {} lazy_terminalboost::spirit::lazy_terminal55 lazy_terminal(Actor const& actor, Terminal const& term) 56 : actor(actor), term(term) {} 57 58 Actor actor; 59 Terminal term; 60 }; 61 62 template <typename Domain, typename Terminal, int Arity, typename Enable = void> 63 struct use_lazy_terminal : mpl::false_ {}; 64 65 template <typename Domain, typename Terminal, int Arity, typename Enable = void> 66 struct use_lazy_directive : mpl::false_ {}; 67 68 template <typename Terminal> 69 struct terminal; 70 71 template <typename Domain, typename Terminal> 72 struct use_terminal<Domain, terminal<Terminal> > 73 : use_terminal<Domain, Terminal> {}; 74 75 template <typename Domain, typename Terminal, int Arity, typename Actor> 76 struct use_terminal<Domain, lazy_terminal<Terminal, Actor, Arity> > 77 : use_lazy_terminal<Domain, Terminal, Arity> {}; 78 79 template <typename Domain, typename Terminal, int Arity, typename Actor> 80 struct use_directive<Domain, lazy_terminal<Terminal, Actor, Arity> > 81 : use_lazy_directive<Domain, Terminal, Arity> {}; 82 83 template < 84 typename F 85 , typename A0 = unused_type 86 , typename A1 = unused_type 87 , typename A2 = unused_type 88 , typename Unused = unused_type 89 > 90 struct make_lazy; 91 92 template <typename F, typename A0> 93 struct make_lazy<F, A0> 94 { 95 typedef typename 96 proto::terminal< 97 lazy_terminal< 98 typename F::terminal_type 99 , typename phoenix::detail::expression::function_eval<F, A0>::type 100 , 1 // arity 101 > 102 >::type 103 result_type; 104 typedef result_type type; 105 106 result_type operator ()boost::spirit::make_lazy107 operator()(F f, A0 const& _0) const 108 { 109 typedef typename result_type::proto_child0 child_type; 110 return result_type::make(child_type( 111 phoenix::detail::expression::function_eval<F, A0>::make(f, _0) 112 , f.proto_base().child0 113 )); 114 } 115 }; 116 117 template <typename F, typename A0, typename A1> 118 struct make_lazy<F, A0, A1> 119 { 120 typedef typename 121 proto::terminal< 122 lazy_terminal< 123 typename F::terminal_type 124 , typename phoenix::detail::expression::function_eval<F, A0, A1>::type 125 , 2 // arity 126 > 127 >::type 128 result_type; 129 typedef result_type type; 130 131 result_type operator ()boost::spirit::make_lazy132 operator()(F f, A0 const& _0, A1 const& _1) const 133 { 134 typedef typename result_type::proto_child0 child_type; 135 return result_type::make(child_type( 136 phoenix::detail::expression::function_eval<F, A0, A1>::make(f, _0, _1) 137 , f.proto_base().child0 138 )); 139 } 140 }; 141 142 template <typename F, typename A0, typename A1, typename A2> 143 struct make_lazy<F, A0, A1, A2> 144 { 145 typedef typename 146 proto::terminal< 147 lazy_terminal< 148 typename F::terminal_type 149 , typename phoenix::detail::expression::function_eval<F, A0, A1, A2>::type 150 , 3 // arity 151 > 152 >::type 153 result_type; 154 typedef result_type type; 155 156 result_type operator ()boost::spirit::make_lazy157 operator()(F f, A0 const& _0, A1 const& _1, A2 const& _2) const 158 { 159 typedef typename result_type::proto_child0 child_type; 160 return result_type::make(child_type( 161 phoenix::detail::expression::function_eval<F, A0, A1, A2>::make(f, _0, _1, _2) 162 , f.proto_base().child0 163 )); 164 } 165 }; 166 167 namespace detail 168 { 169 // Helper struct for SFINAE purposes 170 template <bool C> struct bool_; 171 172 template <> 173 struct bool_<true> : mpl::bool_<true> 174 { 175 typedef bool_<true>* is_true; 176 }; 177 178 template <> 179 struct bool_<false> : mpl::bool_<false> 180 { 181 typedef bool_<false>* is_false; 182 }; 183 184 // Metafunction to detect if at least one arg is a Phoenix actor 185 template < 186 typename A0 187 , typename A1 = unused_type 188 , typename A2 = unused_type 189 > 190 struct contains_actor 191 : bool_< 192 phoenix::is_actor<A0>::value 193 || phoenix::is_actor<A1>::value 194 || phoenix::is_actor<A2>::value 195 > 196 {}; 197 198 // to_lazy_arg: convert a terminal arg type to the type make_lazy needs 199 template <typename A> 200 struct to_lazy_arg 201 : phoenix::as_actor<A> // wrap A in a Phoenix actor if not already one 202 {}; 203 204 template <typename A> 205 struct to_lazy_arg<const A> 206 : to_lazy_arg<A> 207 {}; 208 209 template <typename A> 210 struct to_lazy_arg<A &> 211 : to_lazy_arg<A> 212 {}; 213 214 template <> 215 struct to_lazy_arg<unused_type> 216 { 217 // unused arg: make_lazy wants unused_type 218 typedef unused_type type; 219 }; 220 221 // to_nonlazy_arg: convert a terminal arg type to the type make_vector needs 222 template <typename A> 223 struct to_nonlazy_arg 224 { 225 // identity 226 typedef A type; 227 }; 228 229 template <typename A> 230 struct to_nonlazy_arg<const A> 231 : to_nonlazy_arg<A> 232 {}; 233 234 template <typename A> 235 struct to_nonlazy_arg<A &> 236 : to_nonlazy_arg<A> 237 {}; 238 239 template <> 240 struct to_nonlazy_arg<unused_type> 241 { 242 // unused arg: make_vector wants fusion::void_ 243 typedef fusion::void_ type; 244 }; 245 } 246 247 template <typename Terminal> 248 struct terminal 249 : proto::extends< 250 typename proto::terminal<Terminal>::type 251 , terminal<Terminal> 252 > 253 { 254 typedef terminal<Terminal> this_type; 255 typedef Terminal terminal_type; 256 257 typedef proto::extends< 258 typename proto::terminal<Terminal>::type 259 , terminal<Terminal> 260 > base_type; 261 terminalboost::spirit::terminal262 terminal() {} 263 terminalboost::spirit::terminal264 terminal(Terminal const& t) 265 : base_type(proto::terminal<Terminal>::type::make(t)) 266 {} 267 268 template < 269 bool Lazy 270 , typename A0 271 , typename A1 272 , typename A2 273 > 274 struct result_helper; 275 276 template < 277 typename A0 278 , typename A1 279 , typename A2 280 > 281 struct result_helper<false, A0, A1, A2> 282 { 283 typedef typename 284 proto::terminal< 285 terminal_ex< 286 Terminal 287 , typename detail::result_of::make_vector< 288 typename detail::to_nonlazy_arg<A0>::type 289 , typename detail::to_nonlazy_arg<A1>::type 290 , typename detail::to_nonlazy_arg<A2>::type>::type> 291 >::type 292 type; 293 }; 294 295 template < 296 typename A0 297 , typename A1 298 , typename A2 299 > 300 struct result_helper<true, A0, A1, A2> 301 { 302 typedef typename 303 make_lazy<this_type 304 , typename detail::to_lazy_arg<A0>::type 305 , typename detail::to_lazy_arg<A1>::type 306 , typename detail::to_lazy_arg<A2>::type>::type 307 type; 308 }; 309 310 // FIXME: we need to change this to conform to the result_of protocol 311 template < 312 typename A0 313 , typename A1 = unused_type 314 , typename A2 = unused_type // Support up to 3 args 315 > 316 struct result 317 { 318 typedef typename 319 result_helper< 320 detail::contains_actor<A0, A1, A2>::value 321 , A0, A1, A2 322 >::type 323 type; 324 }; 325 326 template <typename This, typename A0> 327 struct result<This(A0)> 328 { 329 typedef typename 330 result_helper< 331 detail::contains_actor<A0, unused_type, unused_type>::value 332 , A0, unused_type, unused_type 333 >::type 334 type; 335 }; 336 337 template <typename This, typename A0, typename A1> 338 struct result<This(A0, A1)> 339 { 340 typedef typename 341 result_helper< 342 detail::contains_actor<A0, A1, unused_type>::value 343 , A0, A1, unused_type 344 >::type 345 type; 346 }; 347 348 349 template <typename This, typename A0, typename A1, typename A2> 350 struct result<This(A0, A1, A2)> 351 { 352 typedef typename 353 result_helper< 354 detail::contains_actor<A0, A1, A2>::value 355 , A0, A1, A2 356 >::type 357 type; 358 }; 359 360 // Note: in the following overloads, SFINAE cannot 361 // be done on return type because of gcc bug #24915: 362 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24915 363 // Hence an additional, fake argument is used for SFINAE, 364 // using a type which can never be a real argument type. 365 366 // Non-lazy overloads. Only enabled when all 367 // args are immediates (no Phoenix actor). 368 369 template <typename A0> 370 typename result<A0>::type operator ()boost::spirit::terminal371 operator()(A0 const& _0 372 , typename detail::contains_actor<A0>::is_false = 0) const 373 { 374 typedef typename result<A0>::type result_type; 375 typedef typename result_type::proto_child0 child_type; 376 return result_type::make( 377 child_type( 378 detail::make_vector(_0) 379 , this->proto_base().child0) 380 ); 381 } 382 383 template <typename A0, typename A1> 384 typename result<A0, A1>::type operator ()boost::spirit::terminal385 operator()(A0 const& _0, A1 const& _1 386 , typename detail::contains_actor<A0, A1>::is_false = 0) const 387 { 388 typedef typename result<A0, A1>::type result_type; 389 typedef typename result_type::proto_child0 child_type; 390 return result_type::make( 391 child_type( 392 detail::make_vector(_0, _1) 393 , this->proto_base().child0) 394 ); 395 } 396 397 template <typename A0, typename A1, typename A2> 398 typename result<A0, A1, A2>::type operator ()boost::spirit::terminal399 operator()(A0 const& _0, A1 const& _1, A2 const& _2 400 , typename detail::contains_actor<A0, A1, A2>::is_false = 0) const 401 { 402 typedef typename result<A0, A1, A2>::type result_type; 403 typedef typename result_type::proto_child0 child_type; 404 return result_type::make( 405 child_type( 406 detail::make_vector(_0, _1, _2) 407 , this->proto_base().child0) 408 ); 409 } 410 411 // Lazy overloads. Enabled when at 412 // least one arg is a Phoenix actor. 413 template <typename A0> 414 typename result<A0>::type operator ()boost::spirit::terminal415 operator()(A0 const& _0 416 , typename detail::contains_actor<A0>::is_true = 0) const 417 { 418 return make_lazy<this_type 419 , typename phoenix::as_actor<A0>::type>()(*this 420 , phoenix::as_actor<A0>::convert(_0)); 421 } 422 423 template <typename A0, typename A1> 424 typename result<A0, A1>::type operator ()boost::spirit::terminal425 operator()(A0 const& _0, A1 const& _1 426 , typename detail::contains_actor<A0, A1>::is_true = 0) const 427 { 428 return make_lazy<this_type 429 , typename phoenix::as_actor<A0>::type 430 , typename phoenix::as_actor<A1>::type>()(*this 431 , phoenix::as_actor<A0>::convert(_0) 432 , phoenix::as_actor<A1>::convert(_1)); 433 } 434 435 template <typename A0, typename A1, typename A2> 436 typename result<A0, A1, A2>::type operator ()boost::spirit::terminal437 operator()(A0 const& _0, A1 const& _1, A2 const& _2 438 , typename detail::contains_actor<A0, A1, A2>::is_true = 0) const 439 { 440 return make_lazy<this_type 441 , typename phoenix::as_actor<A0>::type 442 , typename phoenix::as_actor<A1>::type 443 , typename phoenix::as_actor<A2>::type>()(*this 444 , phoenix::as_actor<A0>::convert(_0) 445 , phoenix::as_actor<A1>::convert(_1) 446 , phoenix::as_actor<A2>::convert(_2)); 447 } 448 449 private: 450 // silence MSVC warning C4512: assignment operator could not be generated 451 terminal& operator= (terminal const&); 452 }; 453 454 /////////////////////////////////////////////////////////////////////////// 455 namespace result_of 456 { 457 // Calculate the type of the compound terminal if generated by one of 458 // the spirit::terminal::operator() overloads above 459 460 // The terminal type itself is passed through without modification 461 template <typename Tag> 462 struct terminal 463 { 464 typedef spirit::terminal<Tag> type; 465 }; 466 467 template <typename Tag, typename A0> 468 struct terminal<Tag(A0)> 469 { 470 typedef typename spirit::terminal<Tag>:: 471 template result<A0>::type type; 472 }; 473 474 template <typename Tag, typename A0, typename A1> 475 struct terminal<Tag(A0, A1)> 476 { 477 typedef typename spirit::terminal<Tag>:: 478 template result<A0, A1>::type type; 479 }; 480 481 template <typename Tag, typename A0, typename A1, typename A2> 482 struct terminal<Tag(A0, A1, A2)> 483 { 484 typedef typename spirit::terminal<Tag>:: 485 template result<A0, A1, A2>::type type; 486 }; 487 } 488 489 /////////////////////////////////////////////////////////////////////////// 490 // support for stateful tag types 491 namespace tag 492 { 493 template < 494 typename Data, typename Tag 495 , typename DataTag1 = unused_type, typename DataTag2 = unused_type> 496 struct stateful_tag 497 { 498 BOOST_SPIRIT_IS_TAG() 499 500 typedef Data data_type; 501 stateful_tagboost::spirit::tag::stateful_tag502 stateful_tag() {} stateful_tagboost::spirit::tag::stateful_tag503 stateful_tag(data_type const& data) : data_(data) {} 504 505 data_type data_; 506 507 private: 508 // silence MSVC warning C4512: assignment operator could not be generated 509 stateful_tag& operator= (stateful_tag const&); 510 }; 511 } 512 513 template < 514 typename Data, typename Tag 515 , typename DataTag1 = unused_type, typename DataTag2 = unused_type> 516 struct stateful_tag_type 517 : spirit::terminal<tag::stateful_tag<Data, Tag, DataTag1, DataTag2> > 518 { 519 typedef tag::stateful_tag<Data, Tag, DataTag1, DataTag2> tag_type; 520 stateful_tag_typeboost::spirit::stateful_tag_type521 stateful_tag_type() {} stateful_tag_typeboost::spirit::stateful_tag_type522 stateful_tag_type(Data const& data) 523 : spirit::terminal<tag_type>(data) 524 {} 525 526 private: 527 // silence MSVC warning C4512: assignment operator could not be generated 528 stateful_tag_type& operator= (stateful_tag_type const&); 529 }; 530 531 namespace detail 532 { 533 // extract expression if this is a Tag 534 template <typename StatefulTag> 535 struct get_stateful_data 536 { 537 typedef typename StatefulTag::data_type data_type; 538 539 // is invoked if given tag is != Tag 540 template <typename Tag_> callboost::spirit::detail::get_stateful_data541 static data_type call(Tag_) { return data_type(); } 542 543 // this is invoked if given tag is same as'Tag' callboost::spirit::detail::get_stateful_data544 static data_type const& call(StatefulTag const& t) { return t.data_; } 545 }; 546 } 547 548 }} 549 550 #ifdef BOOST_SPIRIT_USE_PHOENIX_V3 551 namespace boost { namespace phoenix 552 { 553 template <typename Tag> 554 struct is_custom_terminal<Tag, typename Tag::is_spirit_tag> 555 : mpl::true_ 556 {}; 557 558 template <typename Tag> 559 struct custom_terminal<Tag, typename Tag::is_spirit_tag> 560 { 561 typedef spirit::terminal<Tag> result_type; 562 563 template <typename Context> operator ()boost::phoenix::custom_terminal564 result_type operator()(Tag const & t, Context const &) 565 { 566 return spirit::terminal<Tag>(t); 567 } 568 }; 569 }} 570 #endif 571 572 // Define a spirit terminal. This macro may be placed in any namespace. 573 // Common placeholders are placed in the main boost::spirit namespace 574 // (see common_terminals.hpp) 575 576 #define BOOST_SPIRIT_TERMINAL_X(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_Y 577 #define BOOST_SPIRIT_TERMINAL_Y(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_X 578 #define BOOST_SPIRIT_TERMINAL_X0 579 #define BOOST_SPIRIT_TERMINAL_Y0 580 581 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 582 583 #define BOOST_SPIRIT_TERMINAL_NAME(name, type_name) \ 584 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \ 585 typedef boost::proto::terminal<tag::name>::type type_name; \ 586 type_name const name = {{}}; \ 587 inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \ 588 /***/ 589 590 #else 591 592 #define BOOST_SPIRIT_TERMINAL_NAME(name, type_name) \ 593 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \ 594 typedef boost::proto::terminal<tag::name>::type type_name; \ 595 /***/ 596 597 #endif 598 599 #define BOOST_SPIRIT_TERMINAL(name) \ 600 BOOST_SPIRIT_TERMINAL_NAME(name, name ## _type) \ 601 /***/ 602 603 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A(r, _, names) \ 604 BOOST_SPIRIT_TERMINAL_NAME( \ 605 BOOST_PP_TUPLE_ELEM(2, 0, names), \ 606 BOOST_PP_TUPLE_ELEM(2, 1, names) \ 607 ) \ 608 /***/ 609 610 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME(seq) \ 611 BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A, _, \ 612 BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0)) \ 613 /***/ 614 615 // Define a spirit extended terminal. This macro may be placed in any namespace. 616 // Common placeholders are placed in the main boost::spirit namespace 617 // (see common_terminals.hpp) 618 619 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 620 621 #define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name) \ 622 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \ 623 typedef boost::spirit::terminal<tag::name> type_name; \ 624 type_name const name = type_name(); \ 625 inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \ 626 /***/ 627 628 #else 629 630 #define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name) \ 631 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \ 632 typedef boost::spirit::terminal<tag::name> type_name; \ 633 /***/ 634 635 #endif 636 637 #define BOOST_SPIRIT_TERMINAL_EX(name) \ 638 BOOST_SPIRIT_TERMINAL_NAME_EX(name, name ## _type) \ 639 /***/ 640 641 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A(r, _, names) \ 642 BOOST_SPIRIT_TERMINAL_NAME_EX( \ 643 BOOST_PP_TUPLE_ELEM(2, 0, names), \ 644 BOOST_PP_TUPLE_ELEM(2, 1, names) \ 645 ) \ 646 /***/ 647 648 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(seq) \ 649 BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A, _, \ 650 BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0)) \ 651 /***/ 652 653 #endif 654 655 656