123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- /*=============================================================================
- Copyright (c) 2001-2014 Joel de Guzman
- Distributed under the Boost Software License, Version 1.0. (See accompanying
- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- ==============================================================================*/
- #if !defined(BOOST_SPIRIT_X3_RULE_JAN_08_2012_0326PM)
- #define BOOST_SPIRIT_X3_RULE_JAN_08_2012_0326PM
- #include <boost/spirit/home/x3/nonterminal/detail/rule.hpp>
- #include <boost/type_traits/is_same.hpp>
- #include <boost/spirit/home/x3/support/context.hpp>
- #include <boost/preprocessor/variadic/to_seq.hpp>
- #include <boost/preprocessor/variadic/elem.hpp>
- #include <boost/preprocessor/seq/for_each.hpp>
- #include <type_traits>
- #if !defined(BOOST_SPIRIT_X3_NO_RTTI)
- #include <typeinfo>
- #endif
- namespace boost { namespace spirit { namespace x3
- {
- // default parse_rule implementation
- template <typename ID, typename Iterator
- , typename Context, typename ActualAttribute>
- inline detail::default_parse_rule_result
- parse_rule(
- detail::rule_id<ID>
- , Iterator& first, Iterator const& last
- , Context const& context, ActualAttribute& attr)
- {
- static_assert(!is_same<decltype(x3::get<ID>(context)), unused_type>::value,
- "BOOST_SPIRIT_DEFINE undefined for this rule.");
- return x3::get<ID>(context).parse(first, last, context, unused, attr);
- }
- template <typename ID, typename RHS, typename Attribute, bool force_attribute_, bool skip_definition_injection = false>
- struct rule_definition : parser<rule_definition<ID, RHS, Attribute, force_attribute_>>
- {
- typedef rule_definition<ID, RHS, Attribute, force_attribute_, skip_definition_injection> this_type;
- typedef ID id;
- typedef RHS rhs_type;
- typedef rule<ID, Attribute, force_attribute_> lhs_type;
- typedef Attribute attribute_type;
- static bool const has_attribute =
- !is_same<Attribute, unused_type>::value;
- static bool const handles_container =
- traits::is_container<Attribute>::value;
- static bool const force_attribute =
- force_attribute_;
- constexpr rule_definition(RHS const& rhs, char const* name)
- : rhs(rhs), name(name) {}
- template <typename Iterator, typename Context, typename Attribute_>
- bool parse(Iterator& first, Iterator const& last
- , Context const& context, unused_type, Attribute_& attr) const
- {
- return detail::rule_parser<attribute_type, ID, skip_definition_injection>
- ::call_rule_definition(
- rhs, name, first, last
- , context
- , attr
- , mpl::bool_<force_attribute>());
- }
- RHS rhs;
- char const* name;
- };
- template <typename ID, typename Attribute, bool force_attribute_>
- struct rule : parser<rule<ID, Attribute, force_attribute_>>
- {
- static_assert(!std::is_reference<Attribute>::value,
- "Reference qualifier on rule attribute type is meaningless");
- typedef ID id;
- typedef Attribute attribute_type;
- static bool const has_attribute =
- !std::is_same<std::remove_const_t<Attribute>, unused_type>::value;
- static bool const handles_container =
- traits::is_container<Attribute>::value;
- static bool const force_attribute = force_attribute_;
- #if !defined(BOOST_SPIRIT_X3_NO_RTTI)
- rule() : name(typeid(rule).name()) {}
- #else
- constexpr rule() : name("unnamed") {}
- #endif
- constexpr rule(char const* name)
- : name(name) {}
- constexpr rule(rule const& r)
- : name(r.name)
- {
- // Assert that we are not copying an unitialized static rule. If
- // the static is in another TU, it may be initialized after we copy
- // it. If so, its name member will be nullptr.
- BOOST_ASSERT_MSG(r.name, "uninitialized rule"); // static initialization order fiasco
- }
- template <typename RHS>
- constexpr rule_definition<
- ID, typename extension::as_parser<RHS>::value_type, Attribute, force_attribute_>
- operator=(RHS const& rhs) const&
- {
- return { as_parser(rhs), name };
- }
- template <typename RHS>
- constexpr rule_definition<
- ID, typename extension::as_parser<RHS>::value_type, Attribute, true>
- operator%=(RHS const& rhs) const&
- {
- return { as_parser(rhs), name };
- }
- // When a rule placeholder constructed and immediately consumed it cannot be used recursively,
- // that's why the rule definition injection into a parser context can be skipped.
- // This optimization has a huge impact on compile times because immediate rules are commonly
- // used to cast an attribute like `as`/`attr_cast` does in Qi.
- template <typename RHS>
- constexpr rule_definition<
- ID, typename extension::as_parser<RHS>::value_type, Attribute, force_attribute_, true>
- operator=(RHS const& rhs) const&&
- {
- return { as_parser(rhs), name };
- }
- template <typename RHS>
- constexpr rule_definition<
- ID, typename extension::as_parser<RHS>::value_type, Attribute, true, true>
- operator%=(RHS const& rhs) const&&
- {
- return { as_parser(rhs), name };
- }
- template <typename Iterator, typename Context, typename Attribute_>
- bool parse(Iterator& first, Iterator const& last
- , Context const& context, unused_type, Attribute_& attr) const
- {
- static_assert(has_attribute,
- "The rule does not have an attribute. Check your parser.");
- using transform = traits::transform_attribute<
- Attribute_, attribute_type, parser_id>;
- using transform_attr = typename transform::type;
- transform_attr attr_ = transform::pre(attr);
- if (parse_rule(detail::rule_id<ID>{}, first, last, context, attr_)) {
- transform::post(attr, std::forward<transform_attr>(attr_));
- return true;
- }
- return false;
- }
- template <typename Iterator, typename Context>
- bool parse(Iterator& first, Iterator const& last
- , Context const& context, unused_type, unused_type) const
- {
- // make sure we pass exactly the rule attribute type
- attribute_type no_attr{};
- return parse_rule(detail::rule_id<ID>{}, first, last, context, no_attr);
- }
- char const* name;
- };
- namespace traits
- {
- template <typename T, typename Enable = void>
- struct is_rule : mpl::false_ {};
- template <typename ID, typename Attribute, bool force_attribute>
- struct is_rule<rule<ID, Attribute, force_attribute>> : mpl::true_ {};
- template <typename ID, typename Attribute, typename RHS, bool force_attribute, bool skip_definition_injection>
- struct is_rule<rule_definition<ID, RHS, Attribute, force_attribute, skip_definition_injection>> : mpl::true_ {};
- }
- template <typename T>
- struct get_info<T, typename enable_if<traits::is_rule<T>>::type>
- {
- typedef std::string result_type;
- std::string operator()(T const& r) const
- {
- BOOST_ASSERT_MSG(r.name, "uninitialized rule"); // static initialization order fiasco
- return r.name? r.name : "uninitialized";
- }
- };
- #define BOOST_SPIRIT_DECLARE_(r, data, rule_type) \
- template <typename Iterator, typename Context> \
- bool parse_rule( \
- ::boost::spirit::x3::detail::rule_id<rule_type::id> \
- , Iterator& first, Iterator const& last \
- , Context const& context, rule_type::attribute_type& attr); \
- /***/
- #define BOOST_SPIRIT_DECLARE(...) BOOST_PP_SEQ_FOR_EACH( \
- BOOST_SPIRIT_DECLARE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
- /***/
- #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
- #define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \
- using BOOST_PP_CAT(rule_name, _synonym) = decltype(rule_name); \
- template <typename Iterator, typename Context> \
- inline bool parse_rule( \
- ::boost::spirit::x3::detail::rule_id<BOOST_PP_CAT(rule_name, _synonym)::id> \
- , Iterator& first, Iterator const& last \
- , Context const& context, BOOST_PP_CAT(rule_name, _synonym)::attribute_type& attr) \
- { \
- using rule_t = BOOST_JOIN(rule_name, _synonym); \
- return ::boost::spirit::x3::detail \
- ::rule_parser<typename rule_t::attribute_type, rule_t::id, true> \
- ::call_rule_definition( \
- BOOST_JOIN(rule_name, _def), rule_name.name \
- , first, last, context, attr \
- , ::boost::mpl::bool_<rule_t::force_attribute>()); \
- } \
- /***/
- #else
- #define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \
- template <typename Iterator, typename Context> \
- inline bool parse_rule( \
- ::boost::spirit::x3::detail::rule_id<decltype(rule_name)::id> \
- , Iterator& first, Iterator const& last \
- , Context const& context, decltype(rule_name)::attribute_type& attr) \
- { \
- using rule_t = decltype(rule_name); \
- return ::boost::spirit::x3::detail \
- ::rule_parser<typename rule_t::attribute_type, rule_t::id, true> \
- ::call_rule_definition( \
- BOOST_JOIN(rule_name, _def), rule_name.name \
- , first, last, context, attr \
- , ::boost::mpl::bool_<rule_t::force_attribute>()); \
- } \
- /***/
- #endif
- #define BOOST_SPIRIT_DEFINE(...) BOOST_PP_SEQ_FOR_EACH( \
- BOOST_SPIRIT_DEFINE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \
- /***/
- #define BOOST_SPIRIT_INSTANTIATE(rule_type, Iterator, Context) \
- template bool parse_rule<Iterator, Context>( \
- ::boost::spirit::x3::detail::rule_id<rule_type::id> \
- , Iterator& first, Iterator const& last \
- , Context const& context, rule_type::attribute_type&); \
- /***/
- }}}
- #endif
|