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/home/support/meta_compiler.hpp> 18 #include <boost/spirit/home/support/detail/make_vector.hpp> 19 #include <boost/spirit/home/support/unused.hpp> 20 #include <boost/spirit/home/support/detail/is_spirit_tag.hpp> 21 #include <boost/spirit/home/support/terminal_expression.hpp> 22 #include <boost/phoenix/core/as_actor.hpp> 23 #include <boost/phoenix/core/is_actor.hpp> 24 #include <boost/phoenix/core/terminal_fwd.hpp> 25 #include <boost/phoenix/core/value.hpp> // includes as_actor specialization 26 #include <boost/phoenix/function/function.hpp> 27 #include <boost/preprocessor/tuple/elem.hpp> 28 #include <boost/proto/extends.hpp> 29 #include <boost/proto/traits.hpp> 30 31 namespace boost { namespace spirit 32 { 33 template <typename Terminal, typename Args> 34 struct terminal_ex 35 { 36 typedef Terminal terminal_type; 37 typedef Args args_type; 38 terminal_exboost::spirit::terminal_ex39 terminal_ex(Args const& args_) 40 : args(args_) {} terminal_exboost::spirit::terminal_ex41 terminal_ex(Args const& args_, Terminal const& term_) 42 : args(args_), term(term_) {} 43 44 Args args; // Args is guaranteed to be a fusion::vectorN so you 45 // can use that template for detection and specialization 46 Terminal term; 47 }; 48 49 template <typename Terminal, typename Actor, int Arity> 50 struct lazy_terminal 51 { 52 typedef Terminal terminal_type; 53 typedef Actor actor_type; 54 static int const arity = Arity; 55 lazy_terminalboost::spirit::lazy_terminal56 lazy_terminal(Actor const& actor_) 57 : actor(actor_) {} lazy_terminalboost::spirit::lazy_terminal58 lazy_terminal(Actor const& actor_, Terminal const& term_) 59 : actor(actor_), term(term_) {} 60 61 Actor actor; 62 Terminal term; 63 }; 64 65 template <typename Domain, typename Terminal, int Arity, typename Enable = void> 66 struct use_lazy_terminal : mpl::false_ {}; 67 68 template <typename Domain, typename Terminal, int Arity, typename Enable = void> 69 struct use_lazy_directive : mpl::false_ {}; 70 71 template <typename Terminal> 72 struct terminal; 73 74 template <typename Domain, typename Terminal> 75 struct use_terminal<Domain, terminal<Terminal> > 76 : use_terminal<Domain, Terminal> {}; 77 78 template <typename Domain, typename Terminal, int Arity, typename Actor> 79 struct use_terminal<Domain, lazy_terminal<Terminal, Actor, Arity> > 80 : use_lazy_terminal<Domain, Terminal, Arity> {}; 81 82 template <typename Domain, typename Terminal, int Arity, typename Actor> 83 struct use_directive<Domain, lazy_terminal<Terminal, Actor, Arity> > 84 : use_lazy_directive<Domain, Terminal, Arity> {}; 85 86 template < 87 typename F 88 , typename A0 = unused_type 89 , typename A1 = unused_type 90 , typename A2 = unused_type 91 , typename Unused = unused_type 92 > 93 struct make_lazy; 94 95 template <typename F, typename A0> 96 struct make_lazy<F, A0> 97 { 98 typedef typename 99 proto::terminal< 100 lazy_terminal< 101 typename F::terminal_type 102 , typename phoenix::detail::expression::function_eval<F, A0>::type 103 , 1 // arity 104 > 105 >::type 106 result_type; 107 typedef result_type type; 108 109 result_type operator ()boost::spirit::make_lazy110 operator()(F f, A0 const& _0_) const 111 { 112 typedef typename result_type::proto_child0 child_type; 113 return result_type::make(child_type( 114 phoenix::detail::expression::function_eval<F, A0>::make(f, _0_) 115 , f.proto_base().child0 116 )); 117 } 118 }; 119 120 template <typename F, typename A0, typename A1> 121 struct make_lazy<F, A0, A1> 122 { 123 typedef typename 124 proto::terminal< 125 lazy_terminal< 126 typename F::terminal_type 127 , typename phoenix::detail::expression::function_eval<F, A0, A1>::type 128 , 2 // arity 129 > 130 >::type 131 result_type; 132 typedef result_type type; 133 134 result_type operator ()boost::spirit::make_lazy135 operator()(F f, A0 const& _0_, A1 const& _1_) const 136 { 137 typedef typename result_type::proto_child0 child_type; 138 return result_type::make(child_type( 139 phoenix::detail::expression::function_eval<F, A0, A1>::make(f, _0_, _1_) 140 , f.proto_base().child0 141 )); 142 } 143 }; 144 145 template <typename F, typename A0, typename A1, typename A2> 146 struct make_lazy<F, A0, A1, A2> 147 { 148 typedef typename 149 proto::terminal< 150 lazy_terminal< 151 typename F::terminal_type 152 , typename phoenix::detail::expression::function_eval<F, A0, A1, A2>::type 153 , 3 // arity 154 > 155 >::type 156 result_type; 157 typedef result_type type; 158 159 result_type operator ()boost::spirit::make_lazy160 operator()(F f, A0 const& _0_, A1 const& _1_, A2 const& _2_) const 161 { 162 typedef typename result_type::proto_child0 child_type; 163 return result_type::make(child_type( 164 phoenix::detail::expression::function_eval<F, A0, A1, A2>::make(f, _0_, _1_, _2_) 165 , f.proto_base().child0 166 )); 167 } 168 }; 169 170 namespace detail 171 { 172 // Helper struct for SFINAE purposes 173 template <bool C> struct bool_; 174 175 template <> 176 struct bool_<true> : mpl::bool_<true> 177 { 178 typedef bool_<true>* is_true; 179 }; 180 181 template <> 182 struct bool_<false> : mpl::bool_<false> 183 { 184 typedef bool_<false>* is_false; 185 }; 186 187 // Metafunction to detect if at least one arg is a Phoenix actor 188 template < 189 typename A0 190 , typename A1 = unused_type 191 , typename A2 = unused_type 192 > 193 struct contains_actor 194 : bool_< 195 phoenix::is_actor<A0>::value 196 || phoenix::is_actor<A1>::value 197 || phoenix::is_actor<A2>::value 198 > 199 {}; 200 201 // to_lazy_arg: convert a terminal arg type to the type make_lazy needs 202 template <typename A> 203 struct to_lazy_arg 204 : phoenix::as_actor<A> // wrap A in a Phoenix actor if not already one 205 {}; 206 207 template <typename A> 208 struct to_lazy_arg<const A> 209 : to_lazy_arg<A> 210 {}; 211 212 template <typename A> 213 struct to_lazy_arg<A &> 214 : to_lazy_arg<A> 215 {}; 216 217 template <> 218 struct to_lazy_arg<unused_type> 219 { 220 // unused arg: make_lazy wants unused_type 221 typedef unused_type type; 222 }; 223 224 // to_nonlazy_arg: convert a terminal arg type to the type make_vector needs 225 template <typename A> 226 struct to_nonlazy_arg 227 { 228 // identity 229 typedef A type; 230 }; 231 232 template <typename A> 233 struct to_nonlazy_arg<const A> 234 : to_nonlazy_arg<A> 235 {}; 236 237 template <typename A> 238 struct to_nonlazy_arg<A &> 239 : to_nonlazy_arg<A> 240 {}; 241 242 // incomplete type: should not be appeared unused_type in nonlazy arg. 243 template <> 244 struct to_nonlazy_arg<unused_type>; 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 #if defined(BOOST_MSVC) 269 #pragma warning(push) 270 // warning C4348: 'boost::spirit::terminal<...>::result_helper': redefinition of default parameter: parameter 3, 4 271 #pragma warning(disable: 4348) 272 #endif 273 274 template < 275 bool Lazy 276 , typename A0 277 , typename A1 = unused_type 278 , typename A2 = unused_type 279 > 280 struct result_helper; 281 282 #if defined(BOOST_MSVC) 283 #pragma warning(pop) 284 #endif 285 286 template < 287 typename A0 288 > 289 struct result_helper<false, A0> 290 { 291 typedef typename 292 proto::terminal< 293 terminal_ex< 294 Terminal 295 , typename detail::result_of::make_vector< 296 typename detail::to_nonlazy_arg<A0>::type>::type> 297 >::type 298 type; 299 }; 300 301 template < 302 typename A0 303 , typename A1 304 > 305 struct result_helper<false, A0, A1> 306 { 307 typedef typename 308 proto::terminal< 309 terminal_ex< 310 Terminal 311 , typename detail::result_of::make_vector< 312 typename detail::to_nonlazy_arg<A0>::type 313 , typename detail::to_nonlazy_arg<A1>::type>::type> 314 >::type 315 type; 316 }; 317 318 template < 319 typename A0 320 , typename A1 321 , typename A2 322 > 323 struct result_helper<false, A0, A1, A2> 324 { 325 typedef typename 326 proto::terminal< 327 terminal_ex< 328 Terminal 329 , typename detail::result_of::make_vector< 330 typename detail::to_nonlazy_arg<A0>::type 331 , typename detail::to_nonlazy_arg<A1>::type 332 , typename detail::to_nonlazy_arg<A2>::type>::type> 333 >::type 334 type; 335 }; 336 337 template < 338 typename A0 339 , typename A1 340 , typename A2 341 > 342 struct result_helper<true, A0, A1, A2> 343 { 344 typedef typename 345 make_lazy<this_type 346 , typename detail::to_lazy_arg<A0>::type 347 , typename detail::to_lazy_arg<A1>::type 348 , typename detail::to_lazy_arg<A2>::type>::type 349 type; 350 }; 351 352 // FIXME: we need to change this to conform to the result_of protocol 353 template < 354 typename A0 355 , typename A1 = unused_type 356 , typename A2 = unused_type // Support up to 3 args 357 > 358 struct result 359 { 360 typedef typename 361 result_helper< 362 detail::contains_actor<A0, A1, A2>::value 363 , A0, A1, A2 364 >::type 365 type; 366 }; 367 368 template <typename This, typename A0> 369 struct result<This(A0)> 370 { 371 typedef typename 372 result_helper< 373 detail::contains_actor<A0, unused_type, unused_type>::value 374 , A0, unused_type, unused_type 375 >::type 376 type; 377 }; 378 379 template <typename This, typename A0, typename A1> 380 struct result<This(A0, A1)> 381 { 382 typedef typename 383 result_helper< 384 detail::contains_actor<A0, A1, unused_type>::value 385 , A0, A1, unused_type 386 >::type 387 type; 388 }; 389 390 391 template <typename This, typename A0, typename A1, typename A2> 392 struct result<This(A0, A1, A2)> 393 { 394 typedef typename 395 result_helper< 396 detail::contains_actor<A0, A1, A2>::value 397 , A0, A1, A2 398 >::type 399 type; 400 }; 401 402 // Note: in the following overloads, SFINAE cannot 403 // be done on return type because of gcc bug #24915: 404 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24915 405 // Hence an additional, fake argument is used for SFINAE, 406 // using a type which can never be a real argument type. 407 408 // Non-lazy overloads. Only enabled when all 409 // args are immediates (no Phoenix actor). 410 411 template <typename A0> 412 typename result<A0>::type operator ()boost::spirit::terminal413 operator()(A0 const& _0_ 414 , typename detail::contains_actor<A0>::is_false = 0) const 415 { 416 typedef typename result<A0>::type result_type; 417 typedef typename result_type::proto_child0 child_type; 418 return result_type::make( 419 child_type( 420 detail::make_vector(_0_) 421 , this->proto_base().child0) 422 ); 423 } 424 425 template <typename A0, typename A1> 426 typename result<A0, A1>::type operator ()boost::spirit::terminal427 operator()(A0 const& _0_, A1 const& _1_ 428 , typename detail::contains_actor<A0, A1>::is_false = 0) const 429 { 430 typedef typename result<A0, A1>::type result_type; 431 typedef typename result_type::proto_child0 child_type; 432 return result_type::make( 433 child_type( 434 detail::make_vector(_0_, _1_) 435 , this->proto_base().child0) 436 ); 437 } 438 439 template <typename A0, typename A1, typename A2> 440 typename result<A0, A1, A2>::type operator ()boost::spirit::terminal441 operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_ 442 , typename detail::contains_actor<A0, A1, A2>::is_false = 0) const 443 { 444 typedef typename result<A0, A1, A2>::type result_type; 445 typedef typename result_type::proto_child0 child_type; 446 return result_type::make( 447 child_type( 448 detail::make_vector(_0_, _1_, _2_) 449 , this->proto_base().child0) 450 ); 451 } 452 453 // Lazy overloads. Enabled when at 454 // least one arg is a Phoenix actor. 455 template <typename A0> 456 typename result<A0>::type operator ()boost::spirit::terminal457 operator()(A0 const& _0_ 458 , typename detail::contains_actor<A0>::is_true = 0) const 459 { 460 return make_lazy<this_type 461 , typename phoenix::as_actor<A0>::type>()(*this 462 , phoenix::as_actor<A0>::convert(_0_)); 463 } 464 465 template <typename A0, typename A1> 466 typename result<A0, A1>::type operator ()boost::spirit::terminal467 operator()(A0 const& _0_, A1 const& _1_ 468 , typename detail::contains_actor<A0, A1>::is_true = 0) const 469 { 470 return make_lazy<this_type 471 , typename phoenix::as_actor<A0>::type 472 , typename phoenix::as_actor<A1>::type>()(*this 473 , phoenix::as_actor<A0>::convert(_0_) 474 , phoenix::as_actor<A1>::convert(_1_)); 475 } 476 477 template <typename A0, typename A1, typename A2> 478 typename result<A0, A1, A2>::type operator ()boost::spirit::terminal479 operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_ 480 , typename detail::contains_actor<A0, A1, A2>::is_true = 0) const 481 { 482 return make_lazy<this_type 483 , typename phoenix::as_actor<A0>::type 484 , typename phoenix::as_actor<A1>::type 485 , typename phoenix::as_actor<A2>::type>()(*this 486 , phoenix::as_actor<A0>::convert(_0_) 487 , phoenix::as_actor<A1>::convert(_1_) 488 , phoenix::as_actor<A2>::convert(_2_)); 489 } 490 491 // silence MSVC warning C4512: assignment operator could not be generated 492 BOOST_DELETED_FUNCTION(terminal& operator= (terminal const&)) 493 }; 494 495 /////////////////////////////////////////////////////////////////////////// 496 namespace result_of 497 { 498 // Calculate the type of the compound terminal if generated by one of 499 // the spirit::terminal::operator() overloads above 500 501 // The terminal type itself is passed through without modification 502 template <typename Tag> 503 struct terminal 504 { 505 typedef spirit::terminal<Tag> type; 506 }; 507 508 template <typename Tag, typename A0> 509 struct terminal<Tag(A0)> 510 { 511 typedef typename spirit::terminal<Tag>:: 512 template result<A0>::type type; 513 }; 514 515 template <typename Tag, typename A0, typename A1> 516 struct terminal<Tag(A0, A1)> 517 { 518 typedef typename spirit::terminal<Tag>:: 519 template result<A0, A1>::type type; 520 }; 521 522 template <typename Tag, typename A0, typename A1, typename A2> 523 struct terminal<Tag(A0, A1, A2)> 524 { 525 typedef typename spirit::terminal<Tag>:: 526 template result<A0, A1, A2>::type type; 527 }; 528 } 529 530 /////////////////////////////////////////////////////////////////////////// 531 // support for stateful tag types 532 namespace tag 533 { 534 template < 535 typename Data, typename Tag 536 , typename DataTag1 = unused_type, typename DataTag2 = unused_type> 537 struct stateful_tag 538 { 539 BOOST_SPIRIT_IS_TAG() 540 541 typedef Data data_type; 542 stateful_tagboost::spirit::tag::stateful_tag543 stateful_tag() {} stateful_tagboost::spirit::tag::stateful_tag544 stateful_tag(data_type const& data) : data_(data) {} 545 546 data_type data_; 547 548 // silence MSVC warning C4512: assignment operator could not be generated 549 BOOST_DELETED_FUNCTION(stateful_tag& operator= (stateful_tag const&)) 550 }; 551 } 552 553 template < 554 typename Data, typename Tag 555 , typename DataTag1 = unused_type, typename DataTag2 = unused_type> 556 struct stateful_tag_type 557 : spirit::terminal<tag::stateful_tag<Data, Tag, DataTag1, DataTag2> > 558 { 559 typedef tag::stateful_tag<Data, Tag, DataTag1, DataTag2> tag_type; 560 stateful_tag_typeboost::spirit::stateful_tag_type561 stateful_tag_type() {} stateful_tag_typeboost::spirit::stateful_tag_type562 stateful_tag_type(Data const& data) 563 : spirit::terminal<tag_type>(data) 564 {} 565 566 // silence MSVC warning C4512: assignment operator could not be generated 567 BOOST_DELETED_FUNCTION(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