]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2008 Francois Barel | |
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 | =============================================================================*/ | |
7c673cae FG |
7 | #include <boost/type_traits/is_same.hpp> |
8 | ||
9 | #include <boost/spirit/include/qi_operator.hpp> | |
10 | #include <boost/spirit/include/qi_char.hpp> | |
1e59de90 TL |
11 | #include <boost/phoenix/core.hpp> |
12 | #include <boost/phoenix/operator.hpp> | |
7c673cae FG |
13 | |
14 | #include <iterator> | |
15 | #include "test.hpp" | |
16 | ||
17 | ||
18 | namespace testns | |
19 | { | |
20 | ||
21 | BOOST_SPIRIT_TERMINAL_NAME_EX( ops, ops_type ) | |
22 | ||
23 | ||
24 | /////////////////////////////////////////////////////////////////////////// | |
25 | // Parsers | |
26 | /////////////////////////////////////////////////////////////////////////// | |
27 | ||
28 | template <typename T1> | |
29 | struct ops_1_parser | |
30 | : boost::spirit::qi::primitive_parser<ops_1_parser<T1> > | |
31 | { | |
32 | ops_1_parser(T1 t1) | |
33 | : t1(t1) | |
34 | {} | |
35 | ||
36 | template <typename Context, typename Iterator> | |
37 | struct attribute | |
38 | { | |
39 | typedef int type; // Number of parsed chars. | |
40 | }; | |
41 | ||
42 | template <typename Iterator, typename Context | |
43 | , typename Skipper, typename Attribute> | |
44 | bool parse(Iterator& first, Iterator const& last | |
45 | , Context& /*context*/, Skipper const& skipper | |
46 | , Attribute& attr) const | |
47 | { | |
48 | boost::spirit::qi::skip_over(first, last, skipper); | |
49 | ||
50 | int count = 0; | |
51 | ||
52 | Iterator it = first; | |
53 | typedef typename std::iterator_traits<Iterator>::value_type Char; | |
54 | for (T1 t = 0; t < t1; t++, count++) | |
55 | if (it == last || *it++ != Char('+')) | |
56 | return false; | |
57 | ||
58 | boost::spirit::traits::assign_to(count, attr); | |
59 | first = it; | |
60 | return true; | |
61 | } | |
62 | ||
63 | template <typename Context> | |
64 | boost::spirit::qi::info what(Context& /*context*/) const | |
65 | { | |
66 | return boost::spirit::qi::info("ops_1"); | |
67 | } | |
68 | ||
69 | const T1 t1; | |
70 | ||
7c673cae | 71 | // silence MSVC warning C4512: assignment operator could not be generated |
92f5a8d4 | 72 | BOOST_DELETED_FUNCTION(ops_1_parser& operator= (ops_1_parser const&)); |
7c673cae FG |
73 | }; |
74 | ||
75 | template <typename T1, typename T2> | |
76 | struct ops_2_parser | |
77 | : boost::spirit::qi::primitive_parser<ops_2_parser<T1, T2> > | |
78 | { | |
79 | ops_2_parser(T1 t1, T2 t2) | |
80 | : t1(t1) | |
81 | , t2(t2) | |
82 | {} | |
83 | ||
84 | template <typename Context, typename Iterator> | |
85 | struct attribute | |
86 | { | |
87 | typedef int type; // Number of parsed chars. | |
88 | }; | |
89 | ||
90 | template <typename Iterator, typename Context | |
91 | , typename Skipper, typename Attribute> | |
92 | bool parse(Iterator& first, Iterator const& last | |
93 | , Context& /*context*/, Skipper const& skipper | |
94 | , Attribute& attr) const | |
95 | { | |
96 | boost::spirit::qi::skip_over(first, last, skipper); | |
97 | ||
98 | int count = 0; | |
99 | ||
100 | Iterator it = first; | |
101 | typedef typename std::iterator_traits<Iterator>::value_type Char; | |
102 | for (T1 t = 0; t < t1; t++, count++) | |
103 | if (it == last || *it++ != Char('+')) | |
104 | return false; | |
105 | for (T2 t = 0; t < t2; t++, count++) | |
106 | if (it == last || *it++ != Char('-')) | |
107 | return false; | |
108 | ||
109 | boost::spirit::traits::assign_to(count, attr); | |
110 | first = it; | |
111 | return true; | |
112 | } | |
113 | ||
114 | template <typename Context> | |
115 | boost::spirit::qi::info what(Context& /*context*/) const | |
116 | { | |
117 | return boost::spirit::qi::info("ops_2"); | |
118 | } | |
119 | ||
120 | const T1 t1; | |
121 | const T2 t2; | |
122 | ||
7c673cae | 123 | // silence MSVC warning C4512: assignment operator could not be generated |
92f5a8d4 | 124 | BOOST_DELETED_FUNCTION(ops_2_parser& operator= (ops_2_parser const&)); |
7c673cae FG |
125 | }; |
126 | ||
127 | template <typename T1, typename T2, typename T3> | |
128 | struct ops_3_parser | |
129 | : boost::spirit::qi::primitive_parser<ops_3_parser<T1, T2, T3> > | |
130 | { | |
131 | ops_3_parser(T1 t1, T2 t2, T3 t3) | |
132 | : t1(t1) | |
133 | , t2(t2) | |
134 | , t3(t3) | |
135 | {} | |
136 | ||
137 | template <typename Context, typename Iterator> | |
138 | struct attribute | |
139 | { | |
140 | typedef int type; // Number of parsed chars. | |
141 | }; | |
142 | ||
143 | template <typename Iterator, typename Context | |
144 | , typename Skipper, typename Attribute> | |
145 | bool parse(Iterator& first, Iterator const& last | |
146 | , Context& /*context*/, Skipper const& skipper | |
147 | , Attribute& attr) const | |
148 | { | |
149 | boost::spirit::qi::skip_over(first, last, skipper); | |
150 | ||
151 | int count = 0; | |
152 | ||
153 | Iterator it = first; | |
154 | typedef typename std::iterator_traits<Iterator>::value_type Char; | |
155 | for (T1 t = 0; t < t1; t++, count++) | |
156 | if (it == last || *it++ != Char('+')) | |
157 | return false; | |
158 | for (T2 t = 0; t < t2; t++, count++) | |
159 | if (it == last || *it++ != Char('-')) | |
160 | return false; | |
161 | for (T3 t = 0; t < t3; t++, count++) | |
162 | if (it == last || *it++ != Char('*')) | |
163 | return false; | |
164 | ||
165 | boost::spirit::traits::assign_to(count, attr); | |
166 | first = it; | |
167 | return true; | |
168 | } | |
169 | ||
170 | template <typename Context> | |
171 | boost::spirit::qi::info what(Context& /*context*/) const | |
172 | { | |
173 | return boost::spirit::qi::info("ops_3"); | |
174 | } | |
175 | ||
176 | const T1 t1; | |
177 | const T2 t2; | |
178 | const T3 t3; | |
179 | ||
7c673cae | 180 | // silence MSVC warning C4512: assignment operator could not be generated |
92f5a8d4 | 181 | BOOST_DELETED_FUNCTION(ops_3_parser& operator= (ops_3_parser const&)); |
7c673cae FG |
182 | }; |
183 | ||
184 | } | |
185 | ||
186 | ||
187 | namespace boost { namespace spirit | |
188 | { | |
189 | ||
190 | /////////////////////////////////////////////////////////////////////////// | |
191 | // Enablers | |
192 | /////////////////////////////////////////////////////////////////////////// | |
193 | ||
194 | template <typename T1> | |
195 | struct use_terminal<qi::domain | |
196 | , terminal_ex<testns::tag::ops, fusion::vector1<T1> > > | |
197 | : mpl::true_ {}; | |
198 | ||
199 | template <typename T1, typename T2> | |
200 | struct use_terminal<qi::domain | |
201 | , terminal_ex<testns::tag::ops, fusion::vector2<T1, T2> > > | |
202 | : mpl::true_ {}; | |
203 | ||
204 | template <typename T1, typename T2, typename T3> | |
205 | struct use_terminal<qi::domain | |
206 | , terminal_ex<testns::tag::ops, fusion::vector3<T1, T2, T3> > > | |
207 | : mpl::true_ {}; | |
208 | ||
209 | template <> | |
210 | struct use_lazy_terminal<qi::domain, testns::tag::ops, 1> | |
211 | : mpl::true_ {}; | |
212 | ||
213 | template <> | |
214 | struct use_lazy_terminal<qi::domain, testns::tag::ops, 2> | |
215 | : mpl::true_ {}; | |
216 | ||
217 | template <> | |
218 | struct use_lazy_terminal<qi::domain, testns::tag::ops, 3> | |
219 | : mpl::true_ {}; | |
220 | ||
221 | }} | |
222 | ||
223 | namespace boost { namespace spirit { namespace qi | |
224 | { | |
225 | ||
226 | /////////////////////////////////////////////////////////////////////////// | |
227 | // Parser generators: make_xxx function (objects) | |
228 | /////////////////////////////////////////////////////////////////////////// | |
229 | ||
230 | template <typename Modifiers, typename T1> | |
231 | struct make_primitive< | |
232 | terminal_ex<testns::tag::ops, fusion::vector1<T1> > | |
233 | , Modifiers> | |
234 | { | |
235 | typedef testns::ops_1_parser<T1> result_type; | |
236 | template <typename Terminal> | |
237 | result_type operator()(const Terminal& term, unused_type) const | |
238 | { | |
239 | return result_type( | |
240 | fusion::at_c<0>(term.args) | |
241 | ); | |
242 | } | |
243 | }; | |
244 | ||
245 | template <typename Modifiers, typename T1, typename T2> | |
246 | struct make_primitive< | |
247 | terminal_ex<testns::tag::ops, fusion::vector2<T1, T2> > | |
248 | , Modifiers> | |
249 | { | |
250 | typedef testns::ops_2_parser<T1, T2> result_type; | |
251 | template <typename Terminal> | |
252 | result_type operator()(const Terminal& term, unused_type) const | |
253 | { | |
254 | return result_type( | |
255 | fusion::at_c<0>(term.args) | |
256 | , fusion::at_c<1>(term.args) | |
257 | ); | |
258 | } | |
259 | }; | |
260 | ||
261 | template <typename Modifiers, typename T1, typename T2, typename T3> | |
262 | struct make_primitive< | |
263 | terminal_ex<testns::tag::ops, fusion::vector3<T1, T2, T3> > | |
264 | , Modifiers> | |
265 | { | |
266 | typedef testns::ops_3_parser<T1, T2, T3> result_type; | |
267 | template <typename Terminal> | |
268 | result_type operator()(const Terminal& term, unused_type) const | |
269 | { | |
270 | return result_type( | |
271 | fusion::at_c<0>(term.args) | |
272 | , fusion::at_c<1>(term.args) | |
273 | , fusion::at_c<2>(term.args) | |
274 | ); | |
275 | } | |
276 | }; | |
277 | ||
278 | }}} | |
279 | ||
280 | ||
281 | namespace testns | |
282 | { | |
283 | template <typename T1, typename T> | |
284 | void check_type_1(const T& /*t*/) | |
285 | { | |
286 | BOOST_STATIC_ASSERT(( boost::is_same<T | |
287 | , typename boost::spirit::terminal<testns::tag::ops>::result<T1>::type >::value )); | |
288 | } | |
289 | ||
290 | template <typename T1, typename T2, typename T> | |
291 | void check_type_2(const T& /*t*/) | |
292 | { | |
293 | BOOST_STATIC_ASSERT(( boost::is_same<T | |
294 | , typename boost::spirit::terminal<testns::tag::ops>::result<T1, T2>::type >::value )); | |
295 | } | |
296 | ||
297 | template <typename T1, typename T2, typename T3, typename T> | |
298 | void check_type_3(const T& /*t*/) | |
299 | { | |
300 | BOOST_STATIC_ASSERT(( boost::is_same<T | |
301 | , typename boost::spirit::terminal<testns::tag::ops>::result<T1, T2, T3>::type >::value )); | |
302 | } | |
303 | } | |
304 | ||
305 | ||
306 | int | |
307 | main() | |
308 | { | |
309 | using spirit_test::test_attr; | |
310 | using spirit_test::test; | |
311 | ||
312 | using testns::ops; | |
313 | using testns::check_type_1; | |
314 | using testns::check_type_2; | |
315 | using testns::check_type_3; | |
316 | ||
317 | { // immediate args | |
318 | int c = 0; | |
319 | #define IP1 ops(2) | |
320 | check_type_1<int>(IP1); | |
321 | BOOST_TEST(test_attr("++/", IP1 >> '/', c) && c == 2); | |
322 | ||
323 | c = 0; | |
324 | #define IP2 ops(2, 3) | |
325 | check_type_2<int, int>(IP2); | |
326 | BOOST_TEST(test_attr("++---/", IP2 >> '/', c) && c == 5); | |
327 | ||
328 | c = 0; | |
329 | #define IP3 ops(2, 3, 4) | |
330 | check_type_3<int, int, int>(IP3); | |
331 | BOOST_TEST(!test("++---***/", IP3 >> '/')); | |
332 | #define IP4 ops(2, 3, 4) | |
333 | check_type_3<int, int, int>(IP4); | |
334 | BOOST_TEST(test_attr("++---****/", IP4 >> '/', c) && c == 9); | |
335 | } | |
336 | ||
337 | using boost::phoenix::val; | |
338 | using boost::phoenix::actor; | |
339 | using boost::phoenix::expression::value; | |
340 | ||
341 | { // all lazy args | |
342 | int c = 0; | |
343 | #define LP1 ops(val(1)) | |
344 | check_type_1<value<int>::type>(LP1); | |
345 | BOOST_TEST(test_attr("+/", LP1 >> '/', c) && c == 1); | |
346 | ||
347 | c = 0; | |
348 | #define LP2 ops(val(1), val(4)) | |
349 | check_type_2<value<int>::type, value<int>::type>(LP2); | |
350 | BOOST_TEST(test_attr("+----/", LP2 >> '/', c) && c == 5); | |
351 | ||
352 | c = 0; | |
353 | #define LP3 ops(val((char)2), val(3.), val(4)) | |
354 | check_type_3<value<char>::type, value<double>::type, value<int>::type>(LP3); | |
355 | BOOST_TEST(!test("++---***/", LP3 >> '/')); | |
356 | #define LP4 ops(val(1), val(2), val(3)) | |
357 | check_type_3<value<int>::type, value<int>::type, value<int>::type>(LP4); | |
358 | BOOST_TEST(test_attr("+--***/", LP4 >> '/', c) && c == 6); | |
359 | } | |
360 | ||
361 | { // mixed immediate and lazy args | |
362 | namespace fusion = boost::fusion; | |
363 | namespace phx = boost::phoenix; | |
364 | ||
365 | int c = 0; | |
366 | #define MP1 ops(val(3), 2) | |
367 | check_type_2<value<int>::type, int>(MP1); | |
368 | BOOST_TEST(test_attr("+++--/", MP1 >> '/', c) && c == 5); | |
369 | ||
370 | c = 0; | |
371 | #define MP2 ops(4, val(1)) | |
372 | check_type_2<int, value<int>::type>(MP2); | |
373 | BOOST_TEST(test_attr("++++-/", MP2 >> '/', c) && c == 5); | |
374 | ||
375 | c = 0; | |
376 | #define MP3 ops(2, val(2), val(2)) | |
377 | check_type_3<int, value<int>::type, value<int>::type>(MP3); | |
378 | BOOST_TEST(!test("++-**/", MP3 >> '/')); | |
379 | #define MP4 ops(2, val(2), 2) | |
380 | check_type_3<int, value<int>::type, int>(MP4); | |
381 | BOOST_TEST(test_attr("++--**/", MP4 >> '/', c) && c == 6); | |
382 | ||
383 | c = 0; | |
384 | #define MP5 ops(val(5) - val(3), 2, val(2)) | |
385 | check_type_3<phx::expression::minus<value<int>::type, value<int>::type>::type, int, value<int>::type>(MP5); | |
386 | BOOST_TEST(test_attr("++--**/", MP5 >> '/', c) && c == 6); | |
387 | } | |
388 | ||
389 | return boost::report_errors(); | |
390 | } | |
391 |