1 /*=============================================================================
2 Copyright (c) 2001-2014 Joel de Guzman
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(SPIRIT_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM)
8 #define SPIRIT_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM
10 #include <type_traits>
12 #include <boost/spirit/home/x3/support/traits/container_traits.hpp>
13 #include <boost/spirit/home/x3/support/traits/value_traits.hpp>
14 #include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
15 #include <boost/spirit/home/x3/support/traits/handles_container.hpp>
16 #include <boost/spirit/home/x3/support/traits/has_attribute.hpp>
17 #include <boost/spirit/home/x3/support/traits/is_substitute.hpp>
18 #include <boost/spirit/home/x3/support/traits/move_to.hpp>
19 #include <boost/mpl/and.hpp>
20 #include <boost/fusion/include/front.hpp>
21 #include <boost/fusion/include/back.hpp>
22 #include <boost/variant/apply_visitor.hpp>
24 namespace boost { namespace spirit { namespace x3 { namespace detail
26 template <typename Attribute, typename Value>
29 // save to associative fusion container where Key is simple type
30 template <typename Key, typename Enable = void>
31 struct save_to_assoc_attr
33 template <typename Value, typename Attribute>
34 static void call(const Key, Value& value, Attribute& attr)
36 traits::move_to(value, fusion::at_key<Key>(attr));
40 /* $$$ clang reports: warning: class template partial specialization contains
41 * a template parameter that can not be deduced; this partial specialization
42 * will never be used $$$
44 // save to associative fusion container where Key
45 // is variant over possible keys
46 template <typename ...T>
47 struct save_to_assoc_attr<variant<T...> >
49 typedef variant<T...> variant_t;
51 template <typename Value, typename Attribute>
52 static void call(const variant_t key, Value& value, Attribute& attr)
54 apply_visitor(saver_visitor<Attribute, Value>(attr, value), key);
58 template <typename Attribute, typename Value>
59 struct saver_visitor : boost::static_visitor<void>
61 saver_visitor(Attribute& attr, Value& value)
62 : attr(attr), value(value) {};
67 template <typename Key>
68 void operator()(Key) const
70 save_to_assoc_attr<Key>::call(Key(), value,attr);
74 template <typename Parser, typename Container, typename Context>
75 struct parser_accepts_container
76 : traits::is_substitute<
77 typename traits::attribute_of<Parser, Context>::type
82 template <typename Parser>
83 struct parse_into_container_base_impl
87 // Parser has attribute (synthesize; Attribute is a container)
88 template <typename Iterator, typename Context
89 , typename RContext, typename Attribute>
90 static bool call_synthesize_x(
92 , Iterator& first, Iterator const& last
93 , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
95 // synthesized attribute needs to be value initialized
97 traits::container_value<Attribute>::type
99 value_type val = traits::value_initialize<value_type>::call();
101 if (!parser.parse(first, last, context, rcontext, val))
104 // push the parsed value into our attribute
105 traits::push_back(attr, val);
109 // Parser has attribute (synthesize; Attribute is a container)
110 template <typename Iterator, typename Context
111 , typename RContext, typename Attribute>
112 static bool call_synthesize_x(
114 , Iterator& first, Iterator const& last
115 , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
117 return parser.parse(first, last, context, rcontext, attr);
120 // Parser has attribute (synthesize; Attribute is a container)
121 template <typename Iterator, typename Context
122 , typename RContext, typename Attribute>
123 static bool call_synthesize(
125 , Iterator& first, Iterator const& last
126 , Context const& context, RContext& rcontext, Attribute& attr)
129 parser_accepts_container<Parser, Attribute, Context>
130 parser_accepts_container;
132 return call_synthesize_x(parser, first, last, context, rcontext, attr
133 , parser_accepts_container());
136 // Parser has attribute (synthesize; Attribute is a single element fusion sequence)
137 template <typename Iterator, typename Context
138 , typename RContext, typename Attribute>
139 static bool call_synthesize_into_fusion_seq(Parser const& parser
140 , Iterator& first, Iterator const& last, Context const& context
141 , RContext& rcontext, Attribute& attr, mpl::false_ /* is_associative */)
143 static_assert(traits::has_size<Attribute, 1>::value,
144 "Expecting a single element fusion sequence");
145 return call_synthesize(parser, first, last, context, rcontext,
146 fusion::front(attr));
149 // Parser has attribute (synthesize; Attribute is fusion map sequence)
150 template <typename Iterator, typename Context, typename RContext, typename Attribute>
151 static bool call_synthesize_into_fusion_seq(
153 , Iterator& first, Iterator const& last, Context const& context
154 , RContext& rcontext, Attribute& attr, mpl::true_ /*is_associative*/)
156 using attribute_type = typename traits::attribute_of<Parser, Context>::type;
157 static_assert(traits::has_size<attribute_type, 2>::value,
158 "To parse directly into fusion map parser must produce 2 element attr");
160 // use type of first element of attribute as key
161 using key = typename std::remove_reference<
162 typename fusion::result_of::front<attribute_type>::type>::type;
164 attribute_type attr_;
165 if (!parser.parse(first, last, context, rcontext, attr_))
168 save_to_assoc_attr<key>::call(fusion::front(attr_), fusion::back(attr_), attr);
172 template <typename Iterator, typename Context, typename RContext, typename Attribute>
173 static bool call_synthesize_dispatch_by_seq(Parser const& parser
174 , Iterator& first, Iterator const& last, Context const& context
175 , RContext& rcontext, Attribute& attr, mpl::true_ /*is_sequence*/)
177 return call_synthesize_into_fusion_seq(
178 parser, first, last, context, rcontext, attr
179 , fusion::traits::is_associative<Attribute>());
182 template <typename Iterator, typename Context, typename RContext, typename Attribute>
183 static bool call_synthesize_dispatch_by_seq(Parser const& parser
184 , Iterator& first, Iterator const& last, Context const& context
185 , RContext& rcontext, Attribute& attr, mpl::false_ /*is_sequence*/)
187 return call_synthesize(parser, first, last, context, rcontext, attr);
190 // Parser has attribute (synthesize)
191 template <typename Iterator, typename Context, typename RContext, typename Attribute>
192 static bool call(Parser const& parser
193 , Iterator& first, Iterator const& last, Context const& context
194 , RContext& rcontext, Attribute& attr, mpl::true_)
196 return call_synthesize_dispatch_by_seq(parser, first, last, context, rcontext, attr
197 , fusion::traits::is_sequence<Attribute>());
200 // Parser has no attribute (pass unused)
201 template <typename Iterator, typename Context, typename RContext, typename Attribute>
204 , Iterator& first, Iterator const& last, Context const& context
205 , RContext& rcontext, Attribute& attr, mpl::false_)
207 return parser.parse(first, last, context, rcontext, unused);
213 template <typename Iterator, typename Context, typename RContext, typename Attribute>
214 static bool call(Parser const& parser
215 , Iterator& first, Iterator const& last, Context const& context
216 , RContext& rcontext, Attribute& attr)
218 return call(parser, first, last, context, rcontext, attr
219 , mpl::bool_<traits::has_attribute<Parser, Context>::value>());
223 template <typename Parser, typename Context, typename RContext, typename Enable = void>
224 struct parse_into_container_impl : parse_into_container_base_impl<Parser> {};
226 template <typename Parser, typename Container, typename Context>
227 struct parser_attr_is_substitute_for_container_value
228 : traits::is_substitute<
229 typename traits::attribute_of<Parser, Context>::type
230 , typename traits::container_value<Container>::type
234 template <typename Parser, typename Context, typename RContext>
235 struct parse_into_container_impl<Parser, Context, RContext,
236 typename enable_if<traits::handles_container<Parser, Context>>::type>
238 template <typename Iterator, typename Attribute>
241 , Iterator& first, Iterator const& last
242 , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
244 return parse_into_container_base_impl<Parser>::call(
245 parser, first, last, context, rcontext, attr);
248 template <typename Iterator, typename Attribute>
251 , Iterator& first, Iterator const& last
252 , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
254 return parser.parse(first, last, context, rcontext, attr);
257 template <typename Iterator, typename Attribute>
258 static bool call(Parser const& parser
259 , Iterator& first, Iterator const& last
260 , Context const& context, RContext& rcontext, Attribute& attr)
262 typedef parser_accepts_container<
263 Parser, Attribute, Context>
264 parser_accepts_container;
266 typedef parser_attr_is_substitute_for_container_value<
267 Parser, Attribute, Context>
268 parser_attr_is_substitute_for_container_value;
271 parser_accepts_container
272 , mpl::not_<parser_attr_is_substitute_for_container_value>>
275 return call(parser, first, last, context, rcontext, attr,
276 pass_attibute_as_is());
280 template <typename Parser, typename Iterator, typename Context
281 , typename RContext, typename Attribute>
282 bool parse_into_container(
284 , Iterator& first, Iterator const& last, Context const& context
285 , RContext& rcontext, Attribute& attr)
287 return parse_into_container_impl<Parser, Context, RContext>::call(
288 parser, first, last, context, rcontext, attr);