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/config.hpp> 17 #include <boost/spirit/include/phoenix_core.hpp> 18 #include <boost/spirit/include/phoenix_function.hpp> 19 #include <boost/proto/proto.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 // incomplete type: should not be appeared unused_type in nonlazy arg. 240 template <> 241 struct to_nonlazy_arg<unused_type>; 242 } 243 244 template <typename Terminal> 245 struct terminal 246 : proto::extends< 247 typename proto::terminal<Terminal>::type 248 , terminal<Terminal> 249 > 250 { 251 typedef terminal<Terminal> this_type; 252 typedef Terminal terminal_type; 253 254 typedef proto::extends< 255 typename proto::terminal<Terminal>::type 256 , terminal<Terminal> 257 > base_type; 258 terminalboost::spirit::terminal259 terminal() {} 260 terminalboost::spirit::terminal261 terminal(Terminal const& t) 262 : base_type(proto::terminal<Terminal>::type::make(t)) 263 {} 264 265 #if defined(BOOST_MSVC) 266 #pragma warning(push) 267 // warning C4348: 'boost::spirit::terminal<...>::result_helper': redefinition of default parameter: parameter 3, 4 268 #pragma warning(disable: 4348) 269 #endif 270 271 template < 272 bool Lazy 273 , typename A0 274 , typename A1 = unused_type 275 , typename A2 = unused_type 276 > 277 struct result_helper; 278 279 #if defined(BOOST_MSVC) 280 #pragma warning(pop) 281 #endif 282 283 template < 284 typename A0 285 > 286 struct result_helper<false, A0> 287 { 288 typedef typename 289 proto::terminal< 290 terminal_ex< 291 Terminal 292 , typename detail::result_of::make_vector< 293 typename detail::to_nonlazy_arg<A0>::type>::type> 294 >::type 295 type; 296 }; 297 298 template < 299 typename A0 300 , typename A1 301 > 302 struct result_helper<false, A0, A1> 303 { 304 typedef typename 305 proto::terminal< 306 terminal_ex< 307 Terminal 308 , typename detail::result_of::make_vector< 309 typename detail::to_nonlazy_arg<A0>::type 310 , typename detail::to_nonlazy_arg<A1>::type>::type> 311 >::type 312 type; 313 }; 314 315 template < 316 typename A0 317 , typename A1 318 , typename A2 319 > 320 struct result_helper<false, A0, A1, A2> 321 { 322 typedef typename 323 proto::terminal< 324 terminal_ex< 325 Terminal 326 , typename detail::result_of::make_vector< 327 typename detail::to_nonlazy_arg<A0>::type 328 , typename detail::to_nonlazy_arg<A1>::type 329 , typename detail::to_nonlazy_arg<A2>::type>::type> 330 >::type 331 type; 332 }; 333 334 template < 335 typename A0 336 , typename A1 337 , typename A2 338 > 339 struct result_helper<true, A0, A1, A2> 340 { 341 typedef typename 342 make_lazy<this_type 343 , typename detail::to_lazy_arg<A0>::type 344 , typename detail::to_lazy_arg<A1>::type 345 , typename detail::to_lazy_arg<A2>::type>::type 346 type; 347 }; 348 349 // FIXME: we need to change this to conform to the result_of protocol 350 template < 351 typename A0 352 , typename A1 = unused_type 353 , typename A2 = unused_type // Support up to 3 args 354 > 355 struct result 356 { 357 typedef typename 358 result_helper< 359 detail::contains_actor<A0, A1, A2>::value 360 , A0, A1, A2 361 >::type 362 type; 363 }; 364 365 template <typename This, typename A0> 366 struct result<This(A0)> 367 { 368 typedef typename 369 result_helper< 370 detail::contains_actor<A0, unused_type, unused_type>::value 371 , A0, unused_type, unused_type 372 >::type 373 type; 374 }; 375 376 template <typename This, typename A0, typename A1> 377 struct result<This(A0, A1)> 378 { 379 typedef typename 380 result_helper< 381 detail::contains_actor<A0, A1, unused_type>::value 382 , A0, A1, unused_type 383 >::type 384 type; 385 }; 386 387 388 template <typename This, typename A0, typename A1, typename A2> 389 struct result<This(A0, A1, A2)> 390 { 391 typedef typename 392 result_helper< 393 detail::contains_actor<A0, A1, A2>::value 394 , A0, A1, A2 395 >::type 396 type; 397 }; 398 399 // Note: in the following overloads, SFINAE cannot 400 // be done on return type because of gcc bug #24915: 401 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24915 402 // Hence an additional, fake argument is used for SFINAE, 403 // using a type which can never be a real argument type. 404 405 // Non-lazy overloads. Only enabled when all 406 // args are immediates (no Phoenix actor). 407 408 template <typename A0> 409 typename result<A0>::type operator ()boost::spirit::terminal410 operator()(A0 const& _0_ 411 , typename detail::contains_actor<A0>::is_false = 0) const 412 { 413 typedef typename result<A0>::type result_type; 414 typedef typename result_type::proto_child0 child_type; 415 return result_type::make( 416 child_type( 417 detail::make_vector(_0_) 418 , this->proto_base().child0) 419 ); 420 } 421 422 template <typename A0, typename A1> 423 typename result<A0, A1>::type operator ()boost::spirit::terminal424 operator()(A0 const& _0_, A1 const& _1_ 425 , typename detail::contains_actor<A0, A1>::is_false = 0) const 426 { 427 typedef typename result<A0, A1>::type result_type; 428 typedef typename result_type::proto_child0 child_type; 429 return result_type::make( 430 child_type( 431 detail::make_vector(_0_, _1_) 432 , this->proto_base().child0) 433 ); 434 } 435 436 template <typename A0, typename A1, typename A2> 437 typename result<A0, A1, A2>::type operator ()boost::spirit::terminal438 operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_ 439 , typename detail::contains_actor<A0, A1, A2>::is_false = 0) const 440 { 441 typedef typename result<A0, A1, A2>::type result_type; 442 typedef typename result_type::proto_child0 child_type; 443 return result_type::make( 444 child_type( 445 detail::make_vector(_0_, _1_, _2_) 446 , this->proto_base().child0) 447 ); 448 } 449 450 // Lazy overloads. Enabled when at 451 // least one arg is a Phoenix actor. 452 template <typename A0> 453 typename result<A0>::type operator ()boost::spirit::terminal454 operator()(A0 const& _0_ 455 , typename detail::contains_actor<A0>::is_true = 0) const 456 { 457 return make_lazy<this_type 458 , typename phoenix::as_actor<A0>::type>()(*this 459 , phoenix::as_actor<A0>::convert(_0_)); 460 } 461 462 template <typename A0, typename A1> 463 typename result<A0, A1>::type operator ()boost::spirit::terminal464 operator()(A0 const& _0_, A1 const& _1_ 465 , typename detail::contains_actor<A0, A1>::is_true = 0) const 466 { 467 return make_lazy<this_type 468 , typename phoenix::as_actor<A0>::type 469 , typename phoenix::as_actor<A1>::type>()(*this 470 , phoenix::as_actor<A0>::convert(_0_) 471 , phoenix::as_actor<A1>::convert(_1_)); 472 } 473 474 template <typename A0, typename A1, typename A2> 475 typename result<A0, A1, A2>::type operator ()boost::spirit::terminal476 operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_ 477 , typename detail::contains_actor<A0, A1, A2>::is_true = 0) const 478 { 479 return make_lazy<this_type 480 , typename phoenix::as_actor<A0>::type 481 , typename phoenix::as_actor<A1>::type 482 , typename phoenix::as_actor<A2>::type>()(*this 483 , phoenix::as_actor<A0>::convert(_0_) 484 , phoenix::as_actor<A1>::convert(_1_) 485 , phoenix::as_actor<A2>::convert(_2_)); 486 } 487 488 private: 489 // silence MSVC warning C4512: assignment operator could not be generated 490 terminal& operator= (terminal const&); 491 }; 492 493 /////////////////////////////////////////////////////////////////////////// 494 namespace result_of 495 { 496 // Calculate the type of the compound terminal if generated by one of 497 // the spirit::terminal::operator() overloads above 498 499 // The terminal type itself is passed through without modification 500 template <typename Tag> 501 struct terminal 502 { 503 typedef spirit::terminal<Tag> type; 504 }; 505 506 template <typename Tag, typename A0> 507 struct terminal<Tag(A0)> 508 { 509 typedef typename spirit::terminal<Tag>:: 510 template result<A0>::type type; 511 }; 512 513 template <typename Tag, typename A0, typename A1> 514 struct terminal<Tag(A0, A1)> 515 { 516 typedef typename spirit::terminal<Tag>:: 517 template result<A0, A1>::type type; 518 }; 519 520 template <typename Tag, typename A0, typename A1, typename A2> 521 struct terminal<Tag(A0, A1, A2)> 522 { 523 typedef typename spirit::terminal<Tag>:: 524 template result<A0, A1, A2>::type type; 525 }; 526 } 527 528 /////////////////////////////////////////////////////////////////////////// 529 // support for stateful tag types 530 namespace tag 531 { 532 template < 533 typename Data, typename Tag 534 , typename DataTag1 = unused_type, typename DataTag2 = unused_type> 535 struct stateful_tag 536 { 537 BOOST_SPIRIT_IS_TAG() 538 539 typedef Data data_type; 540 stateful_tagboost::spirit::tag::stateful_tag541 stateful_tag() {} stateful_tagboost::spirit::tag::stateful_tag542 stateful_tag(data_type const& data) : data_(data) {} 543 544 data_type data_; 545 546 private: 547 // silence MSVC warning C4512: assignment operator could not be generated 548 stateful_tag& operator= (stateful_tag const&); 549 }; 550 } 551 552 template < 553 typename Data, typename Tag 554 , typename DataTag1 = unused_type, typename DataTag2 = unused_type> 555 struct stateful_tag_type 556 : spirit::terminal<tag::stateful_tag<Data, Tag, DataTag1, DataTag2> > 557 { 558 typedef tag::stateful_tag<Data, Tag, DataTag1, DataTag2> tag_type; 559 stateful_tag_typeboost::spirit::stateful_tag_type560 stateful_tag_type() {} stateful_tag_typeboost::spirit::stateful_tag_type561 stateful_tag_type(Data const& data) 562 : spirit::terminal<tag_type>(data) 563 {} 564 565 private: 566 // silence MSVC warning C4512: assignment operator could not be generated 567 stateful_tag_type& operator= (stateful_tag_type const&); 568 }; 569 570 namespace detail 571 { 572 // extract expression if this is a Tag 573 template <typename StatefulTag> 574 struct get_stateful_data 575 { 576 typedef typename StatefulTag::data_type data_type; 577 578 // is invoked if given tag is != Tag 579 template <typename Tag_> callboost::spirit::detail::get_stateful_data580 static data_type call(Tag_) { return data_type(); } 581 582 // this is invoked if given tag is same as'Tag' callboost::spirit::detail::get_stateful_data583 static data_type const& call(StatefulTag const& t) { return t.data_; } 584 }; 585 } 586 587 }} 588 589 namespace boost { namespace phoenix 590 { 591 template <typename Tag> 592 struct is_custom_terminal<Tag, typename Tag::is_spirit_tag> 593 : mpl::true_ 594 {}; 595 596 template <typename Tag> 597 struct custom_terminal<Tag, typename Tag::is_spirit_tag> 598 { 599 #ifndef BOOST_PHOENIX_NO_SPECIALIZE_CUSTOM_TERMINAL 600 typedef void _is_default_custom_terminal; // fix for #7730 601 #endif 602 603 typedef spirit::terminal<Tag> result_type; 604 605 template <typename Context> operator ()boost::phoenix::custom_terminal606 result_type operator()(Tag const & t, Context const &) 607 { 608 return spirit::terminal<Tag>(t); 609 } 610 }; 611 }} 612 613 // Define a spirit terminal. This macro may be placed in any namespace. 614 // Common placeholders are placed in the main boost::spirit namespace 615 // (see common_terminals.hpp) 616 617 #define BOOST_SPIRIT_TERMINAL_X(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_Y 618 #define BOOST_SPIRIT_TERMINAL_Y(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_X 619 #define BOOST_SPIRIT_TERMINAL_X0 620 #define BOOST_SPIRIT_TERMINAL_Y0 621 622 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 623 624 #define BOOST_SPIRIT_TERMINAL_NAME(name, type_name) \ 625 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \ 626 typedef boost::proto::terminal<tag::name>::type type_name; \ 627 type_name const name = {{}}; \ 628 inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \ 629 /***/ 630 631 #else 632 633 #define BOOST_SPIRIT_TERMINAL_NAME(name, type_name) \ 634 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \ 635 typedef boost::proto::terminal<tag::name>::type type_name; \ 636 /***/ 637 638 #endif 639 640 #define BOOST_SPIRIT_TERMINAL(name) \ 641 BOOST_SPIRIT_TERMINAL_NAME(name, name ## _type) \ 642 /***/ 643 644 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A(r, _, names) \ 645 BOOST_SPIRIT_TERMINAL_NAME( \ 646 BOOST_PP_TUPLE_ELEM(2, 0, names), \ 647 BOOST_PP_TUPLE_ELEM(2, 1, names) \ 648 ) \ 649 /***/ 650 651 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME(seq) \ 652 BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A, _, \ 653 BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0)) \ 654 /***/ 655 656 // Define a spirit extended terminal. This macro may be placed in any namespace. 657 // Common placeholders are placed in the main boost::spirit namespace 658 // (see common_terminals.hpp) 659 660 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS 661 662 #define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name) \ 663 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \ 664 typedef boost::spirit::terminal<tag::name> type_name; \ 665 type_name const name = type_name(); \ 666 inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \ 667 /***/ 668 669 #else 670 671 #define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name) \ 672 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \ 673 typedef boost::spirit::terminal<tag::name> type_name; \ 674 /***/ 675 676 #endif 677 678 #define BOOST_SPIRIT_TERMINAL_EX(name) \ 679 BOOST_SPIRIT_TERMINAL_NAME_EX(name, name ## _type) \ 680 /***/ 681 682 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A(r, _, names) \ 683 BOOST_SPIRIT_TERMINAL_NAME_EX( \ 684 BOOST_PP_TUPLE_ELEM(2, 0, names), \ 685 BOOST_PP_TUPLE_ELEM(2, 1, names) \ 686 ) \ 687 /***/ 688 689 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(seq) \ 690 BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A, _, \ 691 BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0)) \ 692 /***/ 693 694 #endif 695 696 697