• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2015 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 #include <boost/detail/lightweight_test.hpp>
8 #include <boost/spirit/home/x3.hpp>
9 #include <boost/fusion/include/vector.hpp>
10 #include <boost/fusion/include/deque.hpp>
11 #include <boost/fusion/include/at.hpp>
12 #include <boost/fusion/include/comparison.hpp>
13 
14 #include <string>
15 #include <iostream>
16 #include "test.hpp"
17 #include "utils.hpp"
18 
19 int
main()20 main()
21 {
22     using boost::spirit::x3::unused_type;
23 
24     using boost::spirit::x3::char_;
25     using boost::spirit::x3::space;
26     using boost::spirit::x3::string;
27     using boost::spirit::x3::attr;
28     using boost::spirit::x3::omit;
29     using boost::spirit::x3::lit;
30     using boost::spirit::x3::unused;
31     using boost::spirit::x3::int_;
32     using boost::spirit::x3::float_;
33     using boost::spirit::x3::no_case;
34     using boost::spirit::x3::rule;
35     using boost::spirit::x3::alnum;
36 
37     using boost::spirit::x3::traits::attribute_of;
38 
39     using boost::fusion::vector;
40     using boost::fusion::deque;
41     using boost::fusion::at_c;
42 
43     using spirit_test::test;
44     using spirit_test::test_attr;
45 
46     BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(char_ >> char_);
47 
48     {
49         BOOST_TEST((test("aa", char_ >> char_)));
50         BOOST_TEST((test("aa", char_ >> 'a')));
51         BOOST_TEST((test("aaa", char_ >> char_ >> char_('a'))));
52         BOOST_TEST((test("xi", char_('x') >> char_('i'))));
53         BOOST_TEST((!test("xi", char_('x') >> char_('o'))));
54         BOOST_TEST((test("xin", char_('x') >> char_('i') >> char_('n'))));
55     }
56 
57 #ifdef BOOST_SPIRIT_COMPILE_ERROR_CHECK
58     {
59         // Compile check only
60         struct x {};
61         char_ >> x(); // this should give a reasonable error message
62     }
63 #endif
64 
65     {
66         BOOST_TEST((test(" a a", char_ >> char_, space)));
67         BOOST_TEST((test(" x i", char_('x') >> char_('i'), space)));
68         BOOST_TEST((!test(" x i", char_('x') >> char_('o'), space)));
69     }
70 
71 
72     {
73         BOOST_TEST((test(" Hello, World", lit("Hello") >> ',' >> "World", space)));
74     }
75 
76 
77     {
78         vector<char, char> attr;
79         BOOST_TEST((test_attr("ab", char_ >> char_, attr)));
80         BOOST_TEST((at_c<0>(attr) == 'a'));
81         BOOST_TEST((at_c<1>(attr) == 'b'));
82     }
83 
84 #ifdef BOOST_SPIRIT_COMPILE_ERROR_CHECK
85     {
86         // Compile check only
87         vector<char, char> attr;
88 
89         // error: attr does not have enough elements
90         test_attr("abc", char_ >> char_ >> char_, attr);
91     }
92 #endif
93 
94     {
95         vector<char, char, char> attr;
96         BOOST_TEST((test_attr(" a\n  b\n  c", char_ >> char_ >> char_, attr, space)));
97         BOOST_TEST((at_c<0>(attr) == 'a'));
98         BOOST_TEST((at_c<1>(attr) == 'b'));
99         BOOST_TEST((at_c<2>(attr) == 'c'));
100     }
101 
102     {
103         // 'b' has an unused_type. unused attributes are not part of the sequence
104         vector<char, char> attr;
105         BOOST_TEST((test_attr("abc", char_ >> 'b' >> char_, attr)));
106         BOOST_TEST((at_c<0>(attr) == 'a'));
107         BOOST_TEST((at_c<1>(attr) == 'c'));
108     }
109 
110     {
111         // 'b' has an unused_type. unused attributes are not part of the sequence
112         vector<char, char> attr;
113         BOOST_TEST((test_attr("acb", char_ >> char_ >> 'b', attr)));
114         BOOST_TEST((at_c<0>(attr) == 'a'));
115         BOOST_TEST((at_c<1>(attr) == 'c'));
116     }
117 
118     {
119         // "hello" has an unused_type. unused attributes are not part of the sequence
120         vector<char, char> attr;
121         BOOST_TEST((test_attr("a hello c", char_ >> "hello" >> char_, attr, space)));
122         BOOST_TEST((at_c<0>(attr) == 'a'));
123         BOOST_TEST((at_c<1>(attr) == 'c'));
124     }
125 
126     {
127         // a single element
128         char attr;
129         BOOST_TEST((test_attr("ab", char_ >> 'b', attr)));
130         BOOST_TEST((attr == 'a'));
131     }
132 
133     {
134         // a single element fusion sequence
135         vector<char> attr;
136         BOOST_TEST((test_attr("ab", char_ >> 'b', attr)));
137         BOOST_TEST((at_c<0>(attr) == 'a'));
138     }
139 
140     {
141         // make sure single element tuples get passed through if the rhs
142         // has a single element tuple as its attribute. Edit JDG 2014:
143         // actually he issue here is that if the rhs in this case a rule
144         // (r), it should get it (i.e. the sequence parser should not
145         // unwrap it). It's odd that the RHS (r) does not really have a
146         // single element tuple (it's a deque<char, int>), so the original
147         // comment is not accurate.
148 
149         typedef deque<char, int> attr_type;
150         attr_type fv;
151 
152         auto r = rule<class r, attr_type>()
153             = char_ >> ',' >> int_;
154 
155         BOOST_TEST((test_attr("test:x,1", "test:" >> r, fv) &&
156             fv == attr_type('x', 1)));
157     }
158 
159     {
160         // make sure single element tuples get passed through if the rhs
161         // has a single element tuple as its attribute. This is a correction
162         // of the test above.
163 
164         typedef deque<int> attr_type;
165         attr_type fv;
166 
167         auto r = rule<class r, attr_type>()
168             = int_;
169 
170         BOOST_TEST((test_attr("test:1", "test:" >> r, fv) &&
171             fv == attr_type(1)));
172     }
173 
174     {
175         // unused means we don't care about the attribute
176         BOOST_TEST((test_attr("abc", char_ >> 'b' >> char_, unused)));
177     }
178 
179     {
180         BOOST_TEST((test("aA", no_case[char_('a') >> 'a'])));
181         BOOST_TEST((test("BEGIN END", no_case[lit("begin") >> "end"], space)));
182         BOOST_TEST((!test("BEGIN END", no_case[lit("begin") >> "nend"], space)));
183     }
184 
185     { // check attribute is passed through unary to another sequence
186         using boost::spirit::x3::eps;
187         std::string s;
188         BOOST_TEST(test_attr("ab", eps >> no_case[char_ >> char_], s));
189         BOOST_TEST("ab" == s);
190         s.clear();
191         BOOST_TEST(test_attr("ab", no_case[char_ >> char_] >> eps, s));
192         BOOST_TEST("ab" == s);
193         s.clear();
194         BOOST_TEST(test_attr("abc", char_ >> no_case[char_ >> char_], s));
195         BOOST_TEST("abc" == s);
196         s.clear();
197         BOOST_TEST(test_attr("abc", no_case[char_ >> char_] >> char_, s));
198         BOOST_TEST("abc" == s);
199     }
200 
201     {
202 #ifdef SPIRIT_NO_COMPILE_CHECK
203         char_ >> char_ = char_ >> char_; // disallow this!
204 #endif
205     }
206 
207     { // alternative forms of attributes. Allow sequences to take in
208       // stl containers.
209 
210         std::vector<char> v;
211         BOOST_TEST(test_attr("abc", char_ >> char_ >> char_, v));
212         BOOST_TEST(v.size() == 3);
213         BOOST_TEST(v[0] == 'a');
214         BOOST_TEST(v[1] == 'b');
215         BOOST_TEST(v[2] == 'c');
216     }
217 
218     { // alternative forms of attributes. Allow sequences to take in
219       // stl containers.
220 
221         std::vector<char> v;
222         BOOST_TEST(test_attr("a,b,c", char_ >> *(',' >> char_), v));
223         BOOST_TEST(v.size() == 3);
224         BOOST_TEST(v[0] == 'a');
225         BOOST_TEST(v[1] == 'b');
226         BOOST_TEST(v[2] == 'c');
227     }
228 
229     { // alternative forms of attributes. Allow sequences to take in
230       // stl containers.
231 
232         std::vector<char> v;
233         BOOST_TEST(test_attr("abc", char_ >> *char_, v));
234         BOOST_TEST(v.size() == 3);
235         BOOST_TEST(v[0] == 'a');
236         BOOST_TEST(v[1] == 'b');
237         BOOST_TEST(v[2] == 'c');
238     }
239 
240     { // alternative forms of attributes. Allow sequences to take in
241       // stl containers.
242         //~ using boost::spirit::x3::hold;
243 
244         std::vector<char> v;
245         BOOST_TEST(test_attr("abc", char_ >> *(char_ >> char_), v));
246         BOOST_TEST(v.size() == 3);
247         BOOST_TEST(v[0] == 'a');
248         BOOST_TEST(v[1] == 'b');
249         BOOST_TEST(v[2] == 'c');
250 
251         v.clear();
252         BOOST_TEST(!test_attr("abcd", char_ >> *(char_ >> char_), v));
253 
254         // $$$ hold not yet implemented $$$
255         //~ v.clear();
256         //~ BOOST_TEST(test_attr("abcdef", char_ >> *hold[char_ >> char_] >> char_, v));
257         //~ BOOST_TEST(v.size() == 6);
258         //~ BOOST_TEST(v[0] == 'a');
259         //~ BOOST_TEST(v[1] == 'b');
260         //~ BOOST_TEST(v[2] == 'c');
261         //~ BOOST_TEST(v[3] == 'd');
262         //~ BOOST_TEST(v[4] == 'e');
263         //~ BOOST_TEST(v[5] == 'f');
264 
265         v.clear();
266         BOOST_TEST(test_attr("abc", char_ >> +(char_ >> char_), v));
267         BOOST_TEST(v.size() == 3);
268         BOOST_TEST(v[0] == 'a');
269         BOOST_TEST(v[1] == 'b');
270         BOOST_TEST(v[2] == 'c');
271     }
272 
273     { // alternative forms of attributes. Allow sequences to take in
274       // stl containers.
275 
276         std::vector<char> v;
277         BOOST_TEST(test_attr("abc", char_ >> -(+char_), v));
278         BOOST_TEST(v.size() == 3);
279         BOOST_TEST(v[0] == 'a');
280         BOOST_TEST(v[1] == 'b');
281         BOOST_TEST(v[2] == 'c');
282     }
283 
284     { // alternative forms of attributes. Allow sequences to take in
285       // stl containers.
286 
287         std::string s;
288         BOOST_TEST(test_attr("foobar", string("foo") >> string("bar"), s));
289         BOOST_TEST(s == "foobar");
290 
291         s.clear();
292 
293         // $$$ hold not yet implemented $$$
294         //~ using boost::spirit::x3::hold;
295 
296         //~ rule<char const*, std::string()> word = +char_("abc");
297         //~ BOOST_TEST(test_attr("ab.bc.ca", *hold[word >> string(".")] >> word, s));
298         //~ BOOST_TEST(s == "ab.bc.ca");
299     }
300 
301     // Make sure get_sequence_types works for sequences of sequences.
302     {
303         std::vector<char> v;
304         BOOST_TEST(test_attr(" a b", (' ' >> char_) >> (' ' >> char_), v));
305         BOOST_TEST(v.size() == 2);
306         BOOST_TEST(v[0] == 'a');
307         BOOST_TEST(v[1] == 'b');
308     }
309 
310     // alternative forms of attributes. Allow sequences to take in
311     // stl containers of stl containers.
312     {
313         std::vector<std::string> v;
314         BOOST_TEST(test_attr("abc1,abc2",
315             *~char_(',') >> *(',' >> *~char_(',')), v));
316         BOOST_TEST(v.size() == 2 && v[0] == "abc1" && v[1] == "abc2");
317     }
318 
319     {
320         std::vector<std::string> v;
321 
322         auto e = rule<class e, std::string>()
323             = *~char_(',');
324 
325         auto l = rule<class l, std::vector<std::string>>()
326             = e >> *(',' >> e);
327 
328         BOOST_TEST(test_attr("abc1,abc2,abc3", l, v));
329         BOOST_TEST(v.size() == 3);
330         BOOST_TEST(v[0] == "abc1");
331         BOOST_TEST(v[1] == "abc2");
332         BOOST_TEST(v[2] == "abc3");
333     }
334 
335     // do the same with a plain string object
336     {
337         std::string s;
338         BOOST_TEST(test_attr("abc1,abc2",
339             *~char_(',') >> *(',' >> *~char_(',')), s));
340         BOOST_TEST(s == "abc1abc2");
341     }
342 
343     {
344         std::string s;
345         auto e = rule<class e, std::string>()
346             = *~char_(',');
347 
348         auto l = rule<class l, std::string>()
349             = e >> *(',' >> e);
350 
351         BOOST_TEST(test_attr("abc1,abc2,abc3", l, s));
352         BOOST_TEST(s == "abc1abc2abc3");
353     }
354 
355     {
356         std::vector<char> v;
357         BOOST_TEST(test_attr("ab", char_ >> -char_, v));
358         BOOST_TEST(v.size() == 2 && v[0] == 'a' && v[1] == 'b');
359 
360         v.clear();
361         BOOST_TEST(test_attr("a", char_ >> -char_, v));
362         BOOST_TEST(v.size() == 1 && v[0] == 'a');
363 
364         // $$$ should this be allowed? I don't think so... $$$
365         //~ v.clear();
366         //~ BOOST_TEST(test_attr("a", char_, v));
367         //~ BOOST_TEST(v.size() == 1 && v[0] == 'a');
368     }
369 
370     {
371         std::vector<boost::optional<char>> v;
372         BOOST_TEST(test_attr("ab", char_ >> -char_, v));
373         BOOST_TEST(v.size() == 2 && v[0] == 'a' && v[1] == 'b');
374 
375         v.clear();
376         BOOST_TEST(test_attr("a", char_ >> -char_, v));
377         BOOST_TEST(v.size() == 2 && v[0] == 'a' && !v[1]);
378 
379         // $$$ should this be allowed? I don't think so... $$$
380         //~ v.clear();
381         //~ BOOST_TEST(test_attr("a", char_, v));
382         //~ BOOST_TEST(v.size() == 1 && v[0] == 'a');
383     }
384 
385     // test from spirit mailing list
386     // "Optional operator causes string attribute concatenation"
387     {
388         typedef vector<char, char, int> attr_type;
389         attr_type attr;
390 
391         auto node = alnum >> -('[' >> alnum >> '=' >> int_ >> ']');
392 
393         BOOST_TEST(test_attr("x[y=123]", node, attr));
394         BOOST_TEST(attr == attr_type('x', 'y', 123));
395     }
396 
397     // test from spirit mailing list (variation of above)
398     // "Optional operator causes string attribute concatenation"
399     {
400         typedef vector<std::string, std::string, int> attr_type;
401         attr_type attr;
402 
403         auto node = +alnum >> -('[' >> +alnum >> '=' >> int_ >> ']');
404 
405         BOOST_TEST(test_attr("xxx[yyy=123]", node, attr));
406         BOOST_TEST(attr == attr_type("xxx", "yyy", 123));
407     }
408 
409     // test from spirit mailing list
410     // "Error with container within sequence"
411     {
412         typedef vector<std::string> attr_type;
413         attr_type attr;
414 
415         auto r = *alnum;
416 
417         BOOST_TEST(test_attr("abcdef", r, attr));
418         BOOST_TEST(at_c<0>(attr) == "abcdef");
419     }
420 
421     // test from spirit mailing list (variation of above)
422     // "Error with container within sequence"
423     {
424         typedef vector<std::vector<int>> attr_type;
425         attr_type attr;
426 
427         auto r = *int_;
428 
429         BOOST_TEST(test_attr("123 456", r, attr, space));
430         BOOST_TEST(at_c<0>(attr).size() == 2);
431         BOOST_TEST(at_c<0>(attr)[0] == 123);
432         BOOST_TEST(at_c<0>(attr)[1] == 456);
433     }
434 
435     {
436         using Attr = boost::variant<int, float>;
437         Attr attr;
438         auto const term = rule<class term, Attr>("term") = int_ | float_;
439         auto const expr = rule<class expr, Attr>("expr") = term | ('(' > term > ')');
440         BOOST_TEST((test_attr("(1)", expr, attr, space)));
441     }
442 
443     // test that failing sequence leaves attribute consistent
444     {
445 	std::string attr;
446 	//no need to use omit[], but lit() is buggy ATM
447 	BOOST_TEST(test_attr("A\nB\nC", *(char_ >> omit[lit("\n")]), attr, false));
448 	BOOST_TEST(attr == "AB");
449     }
450 
451     // test that sequence with only one parser producing attribute
452     // makes it unwrapped
453     {
454 	BOOST_TEST((boost::is_same<
455 		    typename attribute_of<decltype(lit("abc") >> attr(long())), unused_type>::type,
456 		    long>() ));
457     }
458 
459     {   // test action
460         using boost::fusion::at_c;
461 
462         char c = 0;
463         int n = 0;
464         auto f = [&](auto& ctx)
465             {
466                 c = at_c<0>(_attr(ctx));
467                 n = at_c<1>(_attr(ctx));
468             };
469 
470         BOOST_TEST(test("x123\"a string\"", (char_ >> int_ >> "\"a string\"")[f]));
471         BOOST_TEST(c == 'x');
472         BOOST_TEST(n == 123);
473     }
474 
475     {   // test action
476         char c = 0;
477         int n = 0;
478         auto f = [&](auto& ctx)
479             {
480                 c = at_c<0>(_attr(ctx));
481                 n = at_c<1>(_attr(ctx));
482             };
483 
484         BOOST_TEST(test("x 123 \"a string\"", (char_ >> int_ >> "\"a string\"")[f], space));
485         BOOST_TEST(c == 'x');
486         BOOST_TEST(n == 123);
487     }
488 
489     {
490 #ifdef SPIRIT_NO_COMPILE_CHECK
491         char const* const s = "";
492         int i;
493         parse(s, s, int_ >> int_, i);
494 #endif
495     }
496 
497     { // test move only types
498         using boost::spirit::x3::eps;
499         std::vector<move_only> v;
500         BOOST_TEST(test_attr("ssszs", *synth_move_only >> 'z' >> synth_move_only, v));
501         BOOST_TEST_EQ(v.size(), 4);
502     }
503 
504     return boost::report_errors();
505 }
506