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 Attribute, typename Iterator 26 , typename Context, typename ActualAttribute> 27 inline detail::default_parse_rule_result parse_rule(rule<ID,Attribute>,Iterator & first,Iterator const & last,Context const & context,ActualAttribute & attr)28 parse_rule( 29 rule<ID, Attribute> /* rule_ */ 30 , Iterator& first, Iterator const& last 31 , Context const& context, ActualAttribute& attr) 32 { 33 static_assert(!is_same<decltype(get<ID>(context)), unused_type>::value, 34 "BOOST_SPIRIT_DEFINE undefined for this rule."); 35 return get<ID>(context).parse(first, last, context, unused, attr); 36 } 37 38 template <typename ID, typename RHS, typename Attribute, bool force_attribute_> 39 struct rule_definition : parser<rule_definition<ID, RHS, Attribute, force_attribute_>> 40 { 41 typedef rule_definition<ID, RHS, Attribute, force_attribute_> this_type; 42 typedef ID id; 43 typedef RHS rhs_type; 44 typedef rule<ID, 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 rule_definitionboost::spirit::x3::rule_definition54 constexpr rule_definition(RHS const& rhs, char const* name) 55 : rhs(rhs), name(name) {} 56 57 template <typename Iterator, typename Context, typename Attribute_> parseboost::spirit::x3::rule_definition58 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> 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>> 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) ruleboost::spirit::x3::rule88 rule() : name(typeid(rule).name()) {} 89 #else ruleboost::spirit::x3::rule90 constexpr rule() : name("unnamed") {} 91 #endif 92 ruleboost::spirit::x3::rule93 constexpr rule(char const* name) 94 : name(name) {} 95 ruleboost::spirit::x3::rule96 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_> operator =boost::spirit::x3::rule108 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> operator %=boost::spirit::x3::rule116 operator%=(RHS const& rhs) const 117 { 118 return { as_parser(rhs), name }; 119 } 120 121 122 template <typename Iterator, typename Context, typename Attribute_> parseboost::spirit::x3::rule123 bool parse(Iterator& first, Iterator const& last 124 , Context const& context, unused_type, Attribute_& attr) const 125 { 126 static_assert(has_attribute, 127 "The rule does not have an attribute. Check your parser."); 128 129 using transform = traits::transform_attribute< 130 Attribute_, attribute_type, parser_id>; 131 132 using transform_attr = typename transform::type; 133 transform_attr attr_ = transform::pre(attr); 134 135 if (parse_rule(*this, first, last, context, attr_)) { 136 transform::post(attr, std::forward<transform_attr>(attr_)); 137 return true; 138 } 139 return false; 140 } 141 142 template <typename Iterator, typename Context> parseboost::spirit::x3::rule143 bool parse(Iterator& first, Iterator const& last 144 , Context const& context, unused_type, unused_type) const 145 { 146 // make sure we pass exactly the rule attribute type 147 attribute_type no_attr{}; 148 return parse_rule(*this, first, last, context, no_attr); 149 } 150 151 char const* name; 152 }; 153 154 namespace traits 155 { 156 template <typename T, typename Enable = void> 157 struct is_rule : mpl::false_ {}; 158 159 template <typename ID, typename Attribute> 160 struct is_rule<rule<ID, Attribute>> : mpl::true_ {}; 161 162 template <typename ID, typename Attribute, typename RHS, bool force_attribute> 163 struct is_rule<rule_definition<ID, RHS, Attribute, force_attribute>> : mpl::true_ {}; 164 } 165 166 template <typename T> 167 struct get_info<T, typename enable_if<traits::is_rule<T>>::type> 168 { 169 typedef std::string result_type; operator ()boost::spirit::x3::get_info170 std::string operator()(T const& r) const 171 { 172 BOOST_ASSERT_MSG(r.name, "uninitialized rule"); // static initialization order fiasco 173 return r.name? r.name : "uninitialized"; 174 } 175 }; 176 177 #define BOOST_SPIRIT_DECLARE_(r, data, rule_type) \ 178 template <typename Iterator, typename Context> \ 179 bool parse_rule( \ 180 rule_type rule_ \ 181 , Iterator& first, Iterator const& last \ 182 , Context const& context, rule_type::attribute_type& attr); \ 183 /***/ 184 185 #define BOOST_SPIRIT_DECLARE(...) BOOST_PP_SEQ_FOR_EACH( \ 186 BOOST_SPIRIT_DECLARE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \ 187 /***/ 188 189 #if BOOST_WORKAROUND(BOOST_MSVC, < 1910) 190 #define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \ 191 using BOOST_PP_CAT(rule_name, _synonym) = decltype(rule_name); \ 192 template <typename Iterator, typename Context> \ 193 inline bool parse_rule( \ 194 BOOST_PP_CAT(rule_name, _synonym) /* rule_ */ \ 195 , Iterator& first, Iterator const& last \ 196 , Context const& context, BOOST_PP_CAT(rule_name, _synonym)::attribute_type& attr) \ 197 { \ 198 using boost::spirit::x3::unused; \ 199 static auto const def_ = (rule_name = BOOST_PP_CAT(rule_name, _def)); \ 200 return def_.parse(first, last, context, unused, attr); \ 201 } \ 202 /***/ 203 #else 204 #define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \ 205 template <typename Iterator, typename Context> \ 206 inline bool parse_rule( \ 207 decltype(rule_name) /* rule_ */ \ 208 , Iterator& first, Iterator const& last \ 209 , Context const& context, decltype(rule_name)::attribute_type& attr) \ 210 { \ 211 using boost::spirit::x3::unused; \ 212 static auto const def_ = (rule_name = BOOST_PP_CAT(rule_name, _def)); \ 213 return def_.parse(first, last, context, unused, attr); \ 214 } \ 215 /***/ 216 #endif 217 218 #define BOOST_SPIRIT_DEFINE(...) BOOST_PP_SEQ_FOR_EACH( \ 219 BOOST_SPIRIT_DEFINE_, _, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \ 220 /***/ 221 222 #define BOOST_SPIRIT_INSTANTIATE(rule_type, Iterator, Context) \ 223 template bool parse_rule<Iterator, Context>( \ 224 rule_type rule_ \ 225 , Iterator& first, Iterator const& last \ 226 , Context const& context, rule_type::attribute_type&); \ 227 /***/ 228 229 230 }}} 231 232 #endif 233