1 | /*============================================================================= |
2 | Copyright (c) 2001-2011 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/spirit/include/qi_sequence.hpp> |
8 | |
9 | #include <boost/spirit/include/qi_operator.hpp> |
10 | #include <boost/spirit/include/qi_char.hpp> |
11 | #include <boost/spirit/include/qi_string.hpp> |
12 | #include <boost/spirit/include/qi_numeric.hpp> |
13 | #include <boost/spirit/include/qi_directive.hpp> |
14 | #include <boost/spirit/include/qi_action.hpp> |
15 | #include <boost/spirit/include/qi_nonterminal.hpp> |
16 | #include <boost/spirit/include/support_argument.hpp> |
17 | #include <boost/phoenix/core.hpp> |
18 | #include <boost/phoenix/operator.hpp> |
19 | |
20 | #include <string> |
21 | #include <iostream> |
22 | #include "test.hpp" |
23 | |
24 | int |
25 | main() |
26 | { |
27 | using namespace boost::spirit::ascii; |
28 | using boost::spirit::qi::lit; |
29 | using boost::spirit::qi::unused; |
30 | using boost::spirit::qi::int_; |
31 | using boost::spirit::qi::double_; |
32 | using boost::spirit::qi::what; |
33 | using boost::spirit::qi::rule; |
34 | using boost::spirit::qi::_1; |
35 | using boost::spirit::qi::_2; |
36 | |
37 | using boost::fusion::vector; |
38 | using boost::fusion::at_c; |
39 | |
40 | using spirit_test::test; |
41 | using spirit_test::test_attr; |
42 | using spirit_test::print_info; |
43 | |
44 | { |
45 | BOOST_TEST((test("aa" , char_ >> char_))); |
46 | BOOST_TEST((test("aaa" , char_ >> char_ >> char_('a')))); |
47 | BOOST_TEST((test("xi" , char_('x') >> char_('i')))); |
48 | BOOST_TEST((!test("xi" , char_('x') >> char_('o')))); |
49 | BOOST_TEST((test("xin" , char_('x') >> char_('i') >> char_('n')))); |
50 | } |
51 | |
52 | { |
53 | BOOST_TEST((test(" a a" , char_ >> char_, space))); |
54 | BOOST_TEST((test(" x i" , char_('x') >> char_('i'), space))); |
55 | BOOST_TEST((!test(" x i" , char_('x') >> char_('o'), space))); |
56 | } |
57 | |
58 | { |
59 | BOOST_TEST((test(" Hello, World" , lit("Hello" ) >> ',' >> "World" , space))); |
60 | } |
61 | |
62 | { |
63 | vector<char, char> attr; |
64 | BOOST_TEST((test_attr("abcdefg" , char_ >> char_ >> "cdefg" , attr))); |
65 | BOOST_TEST((at_c<0>(attr) == 'a')); |
66 | BOOST_TEST((at_c<1>(attr) == 'b')); |
67 | } |
68 | |
69 | { |
70 | vector<char, char, char> attr; |
71 | BOOST_TEST((test_attr(" a\n b\n c" , char_ >> char_ >> char_, attr, space))); |
72 | BOOST_TEST((at_c<0>(attr) == 'a')); |
73 | BOOST_TEST((at_c<1>(attr) == 'b')); |
74 | BOOST_TEST((at_c<2>(attr) == 'c')); |
75 | } |
76 | |
77 | { |
78 | // unused_type means we don't care about the attribute |
79 | vector<char, char> attr; |
80 | BOOST_TEST((test_attr("abc" , char_ >> 'b' >> char_, attr))); |
81 | BOOST_TEST((at_c<0>(attr) == 'a')); |
82 | BOOST_TEST((at_c<1>(attr) == 'c')); |
83 | } |
84 | |
85 | { |
86 | // unused_type means we don't care about the attribute, even at the end |
87 | vector<char, char> attr; |
88 | BOOST_TEST((test_attr("acb" , char_ >> char_ >> 'b', attr))); |
89 | BOOST_TEST((at_c<0>(attr) == 'a')); |
90 | BOOST_TEST((at_c<1>(attr) == 'c')); |
91 | } |
92 | |
93 | { |
94 | // "hello" has an unused_type. unused attributes are not part of the sequence |
95 | vector<char, char> attr; |
96 | BOOST_TEST((test_attr("a hello c" , char_ >> "hello" >> char_, attr, space))); |
97 | BOOST_TEST((at_c<0>(attr) == 'a')); |
98 | BOOST_TEST((at_c<1>(attr) == 'c')); |
99 | } |
100 | |
101 | { |
102 | // a single element |
103 | char attr; |
104 | BOOST_TEST((test_attr("ab" , char_ >> 'b', attr))); |
105 | BOOST_TEST((attr == 'a')); |
106 | } |
107 | |
108 | { |
109 | // a single element fusion sequence |
110 | vector<char> attr; |
111 | BOOST_TEST((test_attr("ab" , char_ >> 'b', attr))); |
112 | BOOST_TEST((at_c<0>(attr) == 'a')); |
113 | } |
114 | |
115 | { |
116 | // make sure single element tuples get passed through if the rhs |
117 | // has a single element tuple as its attribute |
118 | vector<double, int> fv; |
119 | rule<char const*, vector<double, int>()> r; |
120 | r %= double_ >> ',' >> int_; |
121 | BOOST_TEST((test_attr("test:2.0,1" , "test:" >> r, fv) && |
122 | fv == vector<double, int>(2.0, 1))); |
123 | } |
124 | |
125 | { |
126 | // unused means we don't care about the attribute |
127 | BOOST_TEST((test_attr("abc" , char_ >> 'b' >> char_, unused))); |
128 | } |
129 | |
130 | { |
131 | BOOST_TEST((test("aA" , no_case[char_('a') >> 'a']))); |
132 | BOOST_TEST((test("BEGIN END" , no_case[lit("begin" ) >> "end" ], space))); |
133 | BOOST_TEST((!test("BEGIN END" , no_case[lit("begin" ) >> "nend" ], space))); |
134 | } |
135 | |
136 | { |
137 | #ifdef SPIRIT_NO_COMPILE_CHECK |
138 | char_ >> char_ = char_ >> char_; // disallow this! |
139 | #endif |
140 | } |
141 | |
142 | { // alternative forms of attributes. Allow sequences to take in |
143 | // stl containers. |
144 | |
145 | std::vector<char> v; |
146 | BOOST_TEST(test_attr("abc" , char_ >> char_ >> char_, v)); |
147 | BOOST_TEST(v.size() == 3); |
148 | BOOST_TEST(v[0] == 'a'); |
149 | BOOST_TEST(v[1] == 'b'); |
150 | BOOST_TEST(v[2] == 'c'); |
151 | } |
152 | |
153 | { // alternative forms of attributes. Allow sequences to take in |
154 | // stl containers. |
155 | |
156 | std::vector<char> v; |
157 | BOOST_TEST(test_attr("a,b,c" , char_ >> *(',' >> char_), v)); |
158 | BOOST_TEST(v.size() == 3); |
159 | BOOST_TEST(v[0] == 'a'); |
160 | BOOST_TEST(v[1] == 'b'); |
161 | BOOST_TEST(v[2] == 'c'); |
162 | } |
163 | |
164 | { // alternative forms of attributes. Allow sequences to take in |
165 | // stl containers. |
166 | |
167 | std::vector<char> v; |
168 | BOOST_TEST(test_attr("abc" , char_ >> *char_, v)); |
169 | BOOST_TEST(v.size() == 3); |
170 | BOOST_TEST(v[0] == 'a'); |
171 | BOOST_TEST(v[1] == 'b'); |
172 | BOOST_TEST(v[2] == 'c'); |
173 | } |
174 | |
175 | { // alternative forms of attributes. Allow sequences to take in |
176 | // stl containers. |
177 | using boost::spirit::qi::hold; |
178 | |
179 | std::vector<char> v; |
180 | BOOST_TEST(test_attr("abc" , char_ >> *(char_ >> char_), v)); |
181 | BOOST_TEST(v.size() == 3); |
182 | BOOST_TEST(v[0] == 'a'); |
183 | BOOST_TEST(v[1] == 'b'); |
184 | BOOST_TEST(v[2] == 'c'); |
185 | |
186 | v.clear(); |
187 | BOOST_TEST(!test_attr("abcd" , char_ >> *(char_ >> char_), v)); |
188 | |
189 | v.clear(); |
190 | BOOST_TEST(test_attr("abcdef" , char_ >> *hold[char_ >> char_] >> char_, v)); |
191 | BOOST_TEST(v.size() == 6); |
192 | BOOST_TEST(v[0] == 'a'); |
193 | BOOST_TEST(v[1] == 'b'); |
194 | BOOST_TEST(v[2] == 'c'); |
195 | BOOST_TEST(v[3] == 'd'); |
196 | BOOST_TEST(v[4] == 'e'); |
197 | BOOST_TEST(v[5] == 'f'); |
198 | |
199 | v.clear(); |
200 | BOOST_TEST(test_attr("abc" , char_ >> +(char_ >> char_), v)); |
201 | BOOST_TEST(v.size() == 3); |
202 | BOOST_TEST(v[0] == 'a'); |
203 | BOOST_TEST(v[1] == 'b'); |
204 | BOOST_TEST(v[2] == 'c'); |
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_), 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::string s; |
222 | BOOST_TEST(test_attr("foobar" , string("foo" ) >> string("bar" ), s)); |
223 | BOOST_TEST(s == "foobar" ); |
224 | |
225 | s.clear(); |
226 | |
227 | using boost::spirit::qi::hold; |
228 | |
229 | rule<char const*, std::string()> word = +char_("abc" ); |
230 | BOOST_TEST(test_attr("ab.bc.ca" , *hold[word >> string("." )] >> word, s)); |
231 | BOOST_TEST(s == "ab.bc.ca" ); |
232 | } |
233 | |
234 | // alternative forms of attributes. Allow sequences to take in |
235 | // stl containers of stl containers. |
236 | { |
237 | std::vector<std::string> v; |
238 | BOOST_TEST(test_attr("abc1,abc2" , |
239 | *~char_(',') >> *(',' >> *~char_(',')), v)); |
240 | BOOST_TEST(v.size() == 2 && v[0] == "abc1" && v[1] == "abc2" ); |
241 | } |
242 | |
243 | { |
244 | std::vector<std::string> v; |
245 | rule<char const*, std::string()> e = *~char_(','); |
246 | rule<char const*, std::vector<std::string>()> l = e >> *(',' >> e); |
247 | |
248 | BOOST_TEST(test_attr("abc1,abc2,abc3" , l, v)); |
249 | BOOST_TEST(v.size() == 3); |
250 | BOOST_TEST(v[0] == "abc1" ); |
251 | BOOST_TEST(v[1] == "abc2" ); |
252 | BOOST_TEST(v[2] == "abc3" ); |
253 | } |
254 | |
255 | // do the same with a plain string object |
256 | { |
257 | std::string s; |
258 | BOOST_TEST(test_attr("abc1,abc2" , |
259 | *~char_(',') >> *(',' >> *~char_(',')), s)); |
260 | BOOST_TEST(s == "abc1abc2" ); |
261 | } |
262 | |
263 | { |
264 | std::string s; |
265 | rule<char const*, std::string()> e = *~char_(','); |
266 | rule<char const*, std::string()> l = e >> *(',' >> e); |
267 | |
268 | BOOST_TEST(test_attr("abc1,abc2,abc3" , l, s)); |
269 | BOOST_TEST(s == "abc1abc2abc3" ); |
270 | } |
271 | |
272 | { |
273 | std::vector<char> v; |
274 | BOOST_TEST(test_attr("ab" , char_ >> -char_, v)); |
275 | BOOST_TEST(v.size() == 2 && v[0] == 'a' && v[1] == 'b'); |
276 | |
277 | v.clear(); |
278 | BOOST_TEST(test_attr("a" , char_ >> -char_, v)); |
279 | BOOST_TEST(v.size() == 1 && v[0] == 'a'); |
280 | |
281 | v.clear(); |
282 | BOOST_TEST(test_attr("a" , char_, v)); |
283 | BOOST_TEST(v.size() == 1 && v[0] == 'a'); |
284 | } |
285 | |
286 | { |
287 | std::vector<boost::optional<char> > v; |
288 | BOOST_TEST(test_attr("ab" , char_ >> -char_, v)); |
289 | BOOST_TEST(v.size() == 2 && v[0] == 'a' && v[1] == 'b'); |
290 | |
291 | v.clear(); |
292 | BOOST_TEST(test_attr("a" , char_ >> -char_, v)); |
293 | BOOST_TEST(v.size() == 2 && v[0] == 'a' && !v[1]); |
294 | |
295 | v.clear(); |
296 | BOOST_TEST(test_attr("a" , char_, v)); |
297 | BOOST_TEST(v.size() == 1 && v[0] == 'a'); |
298 | } |
299 | |
300 | { // test action |
301 | using boost::phoenix::ref; |
302 | char c = 0; |
303 | int n = 0; |
304 | |
305 | BOOST_TEST(test("x123\"a string\"" , (char_ >> int_ >> "\"a string\"" ) |
306 | [(ref(c) = _1, ref(n) = _2)])); |
307 | BOOST_TEST(c == 'x'); |
308 | BOOST_TEST(n == 123); |
309 | } |
310 | |
311 | { // test action |
312 | using boost::phoenix::ref; |
313 | char c = 0; |
314 | int n = 0; |
315 | |
316 | BOOST_TEST(test("x 123 \"a string\"" , (char_ >> int_ >> "\"a string\"" ) |
317 | [(ref(c) = _1, ref(n) = _2)], space)); |
318 | BOOST_TEST(c == 'x'); |
319 | BOOST_TEST(n == 123); |
320 | } |
321 | |
322 | { // testing "what" |
323 | print_info(what: what(expr: alpha | char_('x') >> lit("hello" ) >> int_)); |
324 | } |
325 | |
326 | // { // compile check only |
327 | // using boost::spirit::qi::rule; |
328 | // typedef boost::fusion::vector<int, double> tuple_type; |
329 | // typedef std::vector<boost::fusion::vector<int, double> > attr_type; |
330 | // |
331 | // rule<char const*, tuple_type()> r = int_ >> ',' >> double_; |
332 | // rule<char const*, attr_type()> r2 = r >> *(',' >> r); |
333 | // //~ rule<char const*, attr_type()> r2 = r % ','; |
334 | // } |
335 | |
336 | return boost::report_errors(); |
337 | } |
338 | |
339 | |