]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
92f5a8d4 | 16 | #include <type_traits> |
7c673cae FG |
17 | |
18 | #if !defined(BOOST_SPIRIT_X3_NO_RTTI) | |
19 | #include <typeinfo> | |
20 | #endif | |
21 | ||
22 | namespace boost { namespace spirit { namespace x3 | |
23 | { | |
7c673cae | 24 | // default parse_rule implementation |
1e59de90 | 25 | template <typename ID, typename Iterator |
7c673cae FG |
26 | , typename Context, typename ActualAttribute> |
27 | inline detail::default_parse_rule_result | |
28 | parse_rule( | |
1e59de90 | 29 | detail::rule_id<ID> |
7c673cae FG |
30 | , Iterator& first, Iterator const& last |
31 | , Context const& context, ActualAttribute& attr) | |
32 | { | |
1e59de90 | 33 | static_assert(!is_same<decltype(x3::get<ID>(context)), unused_type>::value, |
7c673cae | 34 | "BOOST_SPIRIT_DEFINE undefined for this rule."); |
1e59de90 | 35 | return x3::get<ID>(context).parse(first, last, context, unused, attr); |
7c673cae FG |
36 | } |
37 | ||
1e59de90 | 38 | template <typename ID, typename RHS, typename Attribute, bool force_attribute_, bool skip_definition_injection = false> |
7c673cae FG |
39 | struct rule_definition : parser<rule_definition<ID, RHS, Attribute, force_attribute_>> |
40 | { | |
1e59de90 | 41 | typedef rule_definition<ID, RHS, Attribute, force_attribute_, skip_definition_injection> this_type; |
7c673cae FG |
42 | typedef ID id; |
43 | typedef RHS rhs_type; | |
1e59de90 | 44 | typedef rule<ID, Attribute, force_attribute_> lhs_type; |
7c673cae FG |
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 | ||
f67539c2 | 54 | constexpr rule_definition(RHS const& rhs, char const* name) |
7c673cae FG |
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 | { | |
1e59de90 | 61 | return detail::rule_parser<attribute_type, ID, skip_definition_injection> |
7c673cae FG |
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_> | |
1e59de90 | 74 | struct rule : parser<rule<ID, Attribute, force_attribute_>> |
7c673cae | 75 | { |
f67539c2 TL |
76 | static_assert(!std::is_reference<Attribute>::value, |
77 | "Reference qualifier on rule attribute type is meaningless"); | |
78 | ||
7c673cae FG |
79 | typedef ID id; |
80 | typedef Attribute attribute_type; | |
81 | static bool const has_attribute = | |
92f5a8d4 | 82 | !std::is_same<std::remove_const_t<Attribute>, unused_type>::value; |
7c673cae FG |
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 | |
f67539c2 | 90 | constexpr rule() : name("unnamed") {} |
7c673cae FG |
91 | #endif |
92 | ||
f67539c2 | 93 | constexpr rule(char const* name) |
7c673cae FG |
94 | : name(name) {} |
95 | ||
f67539c2 TL |
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 | ||
7c673cae | 105 | template <typename RHS> |
f67539c2 | 106 | constexpr rule_definition< |
7c673cae | 107 | ID, typename extension::as_parser<RHS>::value_type, Attribute, force_attribute_> |
1e59de90 | 108 | operator=(RHS const& rhs) const& |
7c673cae FG |
109 | { |
110 | return { as_parser(rhs), name }; | |
111 | } | |
112 | ||
113 | template <typename RHS> | |
f67539c2 | 114 | constexpr rule_definition< |
7c673cae | 115 | ID, typename extension::as_parser<RHS>::value_type, Attribute, true> |
1e59de90 TL |
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&& | |
7c673cae FG |
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 | { | |
92f5a8d4 TL |
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 | ||
1e59de90 | 155 | if (parse_rule(detail::rule_id<ID>{}, first, last, context, attr_)) { |
92f5a8d4 TL |
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 | |
f67539c2 | 167 | attribute_type no_attr{}; |
1e59de90 | 168 | return parse_rule(detail::rule_id<ID>{}, first, last, context, no_attr); |
7c673cae FG |
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 | ||
1e59de90 TL |
179 | template <typename ID, typename Attribute, bool force_attribute> |
180 | struct is_rule<rule<ID, Attribute, force_attribute>> : mpl::true_ {}; | |
7c673cae | 181 | |
1e59de90 TL |
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_ {}; | |
7c673cae FG |
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 | { | |
b32b8144 FG |
192 | BOOST_ASSERT_MSG(r.name, "uninitialized rule"); // static initialization order fiasco |
193 | return r.name? r.name : "uninitialized"; | |
7c673cae FG |
194 | } |
195 | }; | |
196 | ||
197 | #define BOOST_SPIRIT_DECLARE_(r, data, rule_type) \ | |
92f5a8d4 | 198 | template <typename Iterator, typename Context> \ |
7c673cae | 199 | bool parse_rule( \ |
1e59de90 | 200 | ::boost::spirit::x3::detail::rule_id<rule_type::id> \ |
7c673cae | 201 | , Iterator& first, Iterator const& last \ |
92f5a8d4 | 202 | , Context const& context, rule_type::attribute_type& attr); \ |
7c673cae FG |
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 | ||
11fdf7f2 TL |
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); \ | |
92f5a8d4 | 212 | template <typename Iterator, typename Context> \ |
11fdf7f2 | 213 | inline bool parse_rule( \ |
1e59de90 | 214 | ::boost::spirit::x3::detail::rule_id<BOOST_PP_CAT(rule_name, _synonym)::id> \ |
11fdf7f2 | 215 | , Iterator& first, Iterator const& last \ |
92f5a8d4 | 216 | , Context const& context, BOOST_PP_CAT(rule_name, _synonym)::attribute_type& attr) \ |
11fdf7f2 | 217 | { \ |
1e59de90 TL |
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>()); \ | |
11fdf7f2 TL |
225 | } \ |
226 | /***/ | |
227 | #else | |
7c673cae | 228 | #define BOOST_SPIRIT_DEFINE_(r, data, rule_name) \ |
92f5a8d4 | 229 | template <typename Iterator, typename Context> \ |
7c673cae | 230 | inline bool parse_rule( \ |
1e59de90 | 231 | ::boost::spirit::x3::detail::rule_id<decltype(rule_name)::id> \ |
7c673cae | 232 | , Iterator& first, Iterator const& last \ |
92f5a8d4 | 233 | , Context const& context, decltype(rule_name)::attribute_type& attr) \ |
7c673cae | 234 | { \ |
1e59de90 TL |
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>()); \ | |
7c673cae FG |
242 | } \ |
243 | /***/ | |
11fdf7f2 | 244 | #endif |
7c673cae FG |
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) \ | |
92f5a8d4 | 251 | template bool parse_rule<Iterator, Context>( \ |
1e59de90 | 252 | ::boost::spirit::x3::detail::rule_id<rule_type::id> \ |
7c673cae | 253 | , Iterator& first, Iterator const& last \ |
92f5a8d4 | 254 | , Context const& context, rule_type::attribute_type&); \ |
7c673cae FG |
255 | /***/ |
256 | ||
257 | ||
258 | }}} | |
259 | ||
260 | #endif |