| 1 | /*============================================================================= |
| 2 | Copyright (c) 2001-2014 Joel de Guzman |
| 3 | |
| 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying |
| 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 6 | ==============================================================================*/ |
| 7 | #if !defined(BOOST_SPIRIT_X3_RULE_JAN_08_2012_0326PM) |
| 8 | #define BOOST_SPIRIT_X3_RULE_JAN_08_2012_0326PM |
| 9 | |
| 10 | #include <boost/spirit/home/x3/nonterminal/detail/rule.hpp> |
| 11 | #include <boost/type_traits/is_same.hpp> |
| 12 | #include <boost/spirit/home/x3/support/context.hpp> |
| 13 | #include <boost/preprocessor/variadic/to_seq.hpp> |
| 14 | #include <boost/preprocessor/variadic/elem.hpp> |
| 15 | #include <boost/preprocessor/seq/for_each.hpp> |
| 16 | #include <type_traits> |
| 17 | |
| 18 | #if !defined(BOOST_SPIRIT_X3_NO_RTTI) |
| 19 | #include <typeinfo> |
| 20 | #endif |
| 21 | |
| 22 | namespace boost { namespace spirit { namespace x3 |
| 23 | { |
| 24 | // default parse_rule implementation |
| 25 | template <typename ID, typename Iterator |
| 26 | , typename Context, typename ActualAttribute> |
| 27 | inline detail::default_parse_rule_result |
| 28 | parse_rule( |
| 29 | detail::rule_id<ID> |
| 30 | , Iterator& first, Iterator const& last |
| 31 | , Context const& context, ActualAttribute& attr) |
| 32 | { |
| 33 | static_assert(!is_same<decltype(x3::get<ID>(context)), unused_type>::value, |
| 34 | "BOOST_SPIRIT_DEFINE undefined for this rule." ); |
| 35 | return x3::get<ID>(context).parse(first, last, context, unused, attr); |
| 36 | } |
| 37 | |
| 38 | template <typename ID, typename RHS, typename Attribute, bool force_attribute_, bool skip_definition_injection = false> |
| 39 | struct rule_definition : parser<rule_definition<ID, RHS, Attribute, force_attribute_, skip_definition_injection>> |
| 40 | { |
| 41 | typedef rule_definition<ID, RHS, Attribute, force_attribute_, skip_definition_injection> this_type; |
| 42 | typedef ID id; |
| 43 | typedef RHS rhs_type; |
| 44 | typedef rule<ID, Attribute, force_attribute_> lhs_type; |
| 45 | typedef Attribute attribute_type; |
| 46 | |
| 47 | static bool const has_attribute = |
| 48 | !is_same<Attribute, unused_type>::value; |
| 49 | static bool const handles_container = |
| 50 | traits::is_container<Attribute>::value; |
| 51 | static bool const force_attribute = |
| 52 | force_attribute_; |
| 53 | |
| 54 | constexpr rule_definition(RHS const& rhs, char const* name) |
| 55 | : rhs(rhs), name(name) {} |
| 56 | |
| 57 | template <typename Iterator, typename Context, typename Attribute_> |
| 58 | bool parse(Iterator& first, Iterator const& last |
| 59 | , Context const& context, unused_type, Attribute_& attr) const |
| 60 | { |
| 61 | return detail::rule_parser<attribute_type, ID, skip_definition_injection> |
| 62 | ::call_rule_definition( |
| 63 | rhs, name, first, last |
| 64 | , context |
| 65 | , attr |
| 66 | , mpl::bool_<force_attribute>()); |
| 67 | } |
| 68 | |
| 69 | RHS rhs; |
| 70 | char const* name; |
| 71 | }; |
| 72 | |
| 73 | template <typename ID, typename Attribute, bool force_attribute_> |
| 74 | struct rule : parser<rule<ID, Attribute, force_attribute_>> |
| 75 | { |
| 76 | static_assert(!std::is_reference<Attribute>::value, |
| 77 | "Reference qualifier on rule attribute type is meaningless" ); |
| 78 | |
| 79 | typedef ID id; |
| 80 | typedef Attribute attribute_type; |
| 81 | static bool const has_attribute = |
| 82 | !std::is_same<std::remove_const_t<Attribute>, unused_type>::value; |
| 83 | static bool const handles_container = |
| 84 | traits::is_container<Attribute>::value; |
| 85 | static bool const force_attribute = force_attribute_; |
| 86 | |
| 87 | #if !defined(BOOST_SPIRIT_X3_NO_RTTI) |
| 88 | rule() : name(typeid(rule).name()) {} |
| 89 | #else |
| 90 | constexpr rule() : name("unnamed" ) {} |
| 91 | #endif |
| 92 | |
| 93 | constexpr rule(char const* name) |
| 94 | : name(name) {} |
| 95 | |
| 96 | constexpr rule(rule const& r) |
| 97 | : name(r.name) |
| 98 | { |
| 99 | // Assert that we are not copying an unitialized static rule. If |
| 100 | // the static is in another TU, it may be initialized after we copy |
| 101 | // it. If so, its name member will be nullptr. |
| 102 | BOOST_ASSERT_MSG(r.name, "uninitialized rule" ); // static initialization order fiasco |
| 103 | } |
| 104 | |
| 105 | template <typename RHS> |
| 106 | constexpr rule_definition< |
| 107 | ID, typename extension::as_parser<RHS>::value_type, Attribute, force_attribute_> |
| 108 | operator=(RHS const& rhs) const& |
| 109 | { |
| 110 | return { as_parser(rhs), name }; |
| 111 | } |
| 112 | |
| 113 | template <typename RHS> |
| 114 | constexpr rule_definition< |
| 115 | ID, typename extension::as_parser<RHS>::value_type, Attribute, true> |
| 116 | operator%=(RHS const& rhs) const& |
| 117 | { |
| 118 | return { as_parser(rhs), name }; |
| 119 | } |
| 120 | |
| 121 | // When a rule placeholder constructed and immediately consumed it cannot be used recursively, |
| 122 | // that's why the rule definition injection into a parser context can be skipped. |
| 123 | // This optimization has a huge impact on compile times because immediate rules are commonly |
| 124 | // used to cast an attribute like `as`/`attr_cast` does in Qi. |
| 125 | template <typename RHS> |
| 126 | constexpr rule_definition< |
| 127 | ID, typename extension::as_parser<RHS>::value_type, Attribute, force_attribute_, true> |
| 128 | operator=(RHS const& rhs) const&& |
| 129 | { |
| 130 | return { as_parser(rhs), name }; |
| 131 | } |
| 132 | |
| 133 | template <typename RHS> |
| 134 | constexpr rule_definition< |
| 135 | ID, typename extension::as_parser<RHS>::value_type, Attribute, true, true> |
| 136 | operator%=(RHS const& rhs) const&& |
| 137 | { |
| 138 | return { as_parser(rhs), name }; |
| 139 | } |
| 140 | |
| 141 | |
| 142 | template <typename Iterator, typename Context, typename Attribute_> |
| 143 | bool parse(Iterator& first, Iterator const& last |
| 144 | , Context const& context, unused_type, Attribute_& attr) const |
| 145 | { |
| 146 | static_assert(has_attribute, |
| 147 | "The rule does not have an attribute. Check your parser." ); |
| 148 | |
| 149 | using transform = traits::transform_attribute< |
| 150 | Attribute_, attribute_type, parser_id>; |
| 151 | |
| 152 | using transform_attr = typename transform::type; |
| 153 | transform_attr attr_ = transform::pre(attr); |
| 154 | |
| 155 | if (parse_rule(detail::rule_id<ID>{}, first, last, context, attr_)) { |
| 156 | transform::post(attr, std::forward<transform_attr>(attr_)); |
| 157 | return true; |
| 158 | } |
| 159 | return false; |
| 160 | } |
| 161 | |
| 162 | template <typename Iterator, typename Context> |
| 163 | bool parse(Iterator& first, Iterator const& last |
| 164 | , Context const& context, unused_type, unused_type) const |
| 165 | { |
| 166 | // make sure we pass exactly the rule attribute type |
| 167 | attribute_type no_attr{}; |
| 168 | return parse_rule(detail::rule_id<ID>{}, first, last, context, no_attr); |
| 169 | } |
| 170 | |
| 171 | char const* name; |
| 172 | }; |
| 173 | |
| 174 | namespace traits |
| 175 | { |
| 176 | template <typename T, typename Enable = void> |
| 177 | struct is_rule : mpl::false_ {}; |
| 178 | |
| 179 | template <typename ID, typename Attribute, bool force_attribute> |
| 180 | struct is_rule<rule<ID, Attribute, force_attribute>> : mpl::true_ {}; |
| 181 | |
| 182 | template <typename ID, typename Attribute, typename RHS, bool force_attribute, bool skip_definition_injection> |
| 183 | struct is_rule<rule_definition<ID, RHS, Attribute, force_attribute, skip_definition_injection>> : mpl::true_ {}; |
| 184 | } |
| 185 | |
| 186 | template <typename T> |
| 187 | struct get_info<T, typename enable_if<traits::is_rule<T>>::type> |
| 188 | { |
| 189 | typedef std::string result_type; |
| 190 | std::string operator()(T const& r) const |
| 191 | { |
| 192 | BOOST_ASSERT_MSG(r.name, "uninitialized rule" ); // static initialization order fiasco |
| 193 | return r.name? r.name : "uninitialized" ; |
| 194 | } |
| 195 | }; |
| 196 | |
| 197 | #define BOOST_SPIRIT_DECLARE_(r, data, rule_type) \ |
| 198 | template <typename Iterator, typename Context> \ |
| 199 | bool parse_rule( \ |
| 200 | ::boost::spirit::x3::detail::rule_id<rule_type::id> \ |
| 201 | , Iterator& first, Iterator const& last \ |
| 202 | , Context const& context, rule_type::attribute_type& attr); \ |
| 203 | /***/ |
| 204 | |
| 205 | #define BOOST_SPIRIT_DECLARE(...) BOOST_PP_SEQ_FOR_EACH( \ |
| 206 | BOOST_SPIRIT_DECLARE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \ |
| 207 | /***/ |
| 208 | |
| 209 | #if BOOST_WORKAROUND(BOOST_MSVC, < 1910) |
| 210 | #define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \ |
| 211 | using BOOST_PP_CAT(rule_name, _synonym) = decltype(rule_name); \ |
| 212 | template <typename Iterator, typename Context> \ |
| 213 | inline bool parse_rule( \ |
| 214 | ::boost::spirit::x3::detail::rule_id<BOOST_PP_CAT(rule_name, _synonym)::id> \ |
| 215 | , Iterator& first, Iterator const& last \ |
| 216 | , Context const& context, BOOST_PP_CAT(rule_name, _synonym)::attribute_type& attr) \ |
| 217 | { \ |
| 218 | using rule_t = BOOST_JOIN(rule_name, _synonym); \ |
| 219 | return ::boost::spirit::x3::detail \ |
| 220 | ::rule_parser<typename rule_t::attribute_type, rule_t::id, true> \ |
| 221 | ::call_rule_definition( \ |
| 222 | BOOST_JOIN(rule_name, _def), rule_name.name \ |
| 223 | , first, last, context, attr \ |
| 224 | , ::boost::mpl::bool_<rule_t::force_attribute>()); \ |
| 225 | } \ |
| 226 | /***/ |
| 227 | #else |
| 228 | #define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \ |
| 229 | template <typename Iterator, typename Context> \ |
| 230 | inline bool parse_rule( \ |
| 231 | ::boost::spirit::x3::detail::rule_id<decltype(rule_name)::id> \ |
| 232 | , Iterator& first, Iterator const& last \ |
| 233 | , Context const& context, decltype(rule_name)::attribute_type& attr) \ |
| 234 | { \ |
| 235 | using rule_t = decltype(rule_name); \ |
| 236 | return ::boost::spirit::x3::detail \ |
| 237 | ::rule_parser<typename rule_t::attribute_type, rule_t::id, true> \ |
| 238 | ::call_rule_definition( \ |
| 239 | BOOST_JOIN(rule_name, _def), rule_name.name \ |
| 240 | , first, last, context, attr \ |
| 241 | , ::boost::mpl::bool_<rule_t::force_attribute>()); \ |
| 242 | } \ |
| 243 | /***/ |
| 244 | #endif |
| 245 | |
| 246 | #define BOOST_SPIRIT_DEFINE(...) BOOST_PP_SEQ_FOR_EACH( \ |
| 247 | BOOST_SPIRIT_DEFINE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \ |
| 248 | /***/ |
| 249 | |
| 250 | #define BOOST_SPIRIT_INSTANTIATE(rule_type, Iterator, Context) \ |
| 251 | template bool parse_rule<Iterator, Context>( \ |
| 252 | ::boost::spirit::x3::detail::rule_id<rule_type::id> \ |
| 253 | , Iterator& first, Iterator const& last \ |
| 254 | , Context const& context, rule_type::attribute_type&); \ |
| 255 | /***/ |
| 256 | |
| 257 | |
| 258 | }}} |
| 259 | |
| 260 | #endif |
| 261 | |