• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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