1 /*=============================================================================
2 Copyright (c) 2001-2010 Joel de Guzman
3 Copyright (c) 2009 Francois Barel
4
5 Distributed under the Boost Software License, Version 1.0. (See accompanying
6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 #include <boost/detail/lightweight_test.hpp>
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_auxiliary.hpp>
14 #include <boost/spirit/include/qi_nonterminal.hpp>
15 #include <boost/spirit/include/qi_action.hpp>
16 #include <boost/spirit/include/phoenix_core.hpp>
17 #include <boost/spirit/include/phoenix_operator.hpp>
18 #include <boost/spirit/include/phoenix_object.hpp>
19 #include <boost/spirit/include/phoenix_bind.hpp>
20 #include <boost/fusion/include/std_pair.hpp>
21
22 #include <boost/spirit/repository/include/qi_subrule.hpp>
23
24 #include <string>
25 #include <cstring>
26 #include <iostream>
27 #include "test.hpp"
28
29 int
main()30 main()
31 {
32 using spirit_test::test_attr;
33 using spirit_test::test;
34
35 using namespace boost::spirit::ascii;
36 using namespace boost::spirit::qi::labels;
37 using boost::spirit::qi::locals;
38 using boost::spirit::qi::rule;
39 using boost::spirit::qi::int_;
40 using boost::spirit::qi::fail;
41 using boost::spirit::qi::on_error;
42 using boost::spirit::qi::debug;
43 using boost::spirit::repository::qi::subrule;
44
45 namespace phx = boost::phoenix;
46
47
48 { // basic tests
49
50 subrule<99> entry;
51 subrule<42> a;
52 subrule<48> b;
53 subrule<16> c;
54 rule<char const*> start;
55
56 entry.name("entry");
57 a.name("a");
58 b.name("b");
59 c.name("c");
60 start.name("start");
61
62 // debug(entry);
63 // debug(a);
64 // debug(b);
65 // debug(c);
66 debug(start);
67
68 // subrules with no rule
69 BOOST_TEST(test("abcabcacb", (
70 entry = *(a | b | c)
71 , a = 'a'
72 , b = 'b'
73 , c = 'c'
74 )));
75
76 // check subrule group behaves as a parser
77 BOOST_TEST(test("xabcabcacb", 'x' >> (
78 entry = *(a | b | c)
79 , a = 'a'
80 , b = 'b'
81 , c = 'c'
82 )));
83
84 // subrules in a rule
85 start = (
86 entry = *(a | b | c)
87 , a = 'a'
88 , b = 'b'
89 , c = 'c'
90 );
91 BOOST_TEST(test("abcabcacb", start));
92
93 // subrule -> rule call
94 start = (
95 entry = (a | b) >> (start | b)
96 , a = 'a'
97 , b = 'b'
98 );
99 BOOST_TEST(test("aaaabababaaabbb", start));
100 BOOST_TEST(test("aaaabababaaabba", start, false));
101
102 // subrule recursion
103 start = (
104 entry = (a | b) >> (entry | b)
105 , a = 'a'
106 , b = 'b'
107 );
108 BOOST_TEST(test("aaaabababaaabbb", start));
109 BOOST_TEST(test("aaaabababaaabba", start, false));
110
111 // no-ops
112 #if defined(BOOST_CLANG) && defined(__has_warning)
113 # pragma clang diagnostic push
114 # if __has_warning("-Wself-assign-overloaded")
115 # pragma clang diagnostic ignored "-Wself-assign-overloaded"
116 # endif
117 #endif
118 a = a;
119 #if defined(BOOST_CLANG) && defined(__has_warning)
120 # pragma clang diagnostic pop
121 #endif
122 subrule<42> aa(a);
123 }
124
125 { // basic tests w/ skipper, subrules declared const
126
127 subrule<0> const entry("entry");
128 subrule<1> const a("a");
129 subrule<2> const b("b");
130 subrule<3> const c("c");
131 rule<char const*, space_type> start("start");
132
133 // debug(entry);
134 // debug(a);
135 // debug(b);
136 // debug(c);
137 debug(start);
138
139 start = (
140 entry = *(a | b | c)
141 , a = 'a'
142 , b = 'b'
143 , c = 'c'
144 );
145 BOOST_TEST(test(" a b c a b c a c b ", start, space));
146
147 start = (
148 entry = (a | b) >> (entry | b)
149 , a = 'a'
150 , b = 'b'
151 );
152 BOOST_TEST(test(" a a a a b a b a b a a a b b b ", start, space));
153 BOOST_TEST(test(" a a a a b a b a b a a a b b a ", start, space, false));
154
155 // no-ops
156 #if defined(BOOST_CLANG) && defined(__has_warning)
157 # pragma clang diagnostic push
158 # if __has_warning("-Wself-assign-overloaded")
159 # pragma clang diagnostic ignored "-Wself-assign-overloaded"
160 # endif
161 #endif
162 a = a;
163 #if defined(BOOST_CLANG) && defined(__has_warning)
164 # pragma clang diagnostic pop
165 #endif
166 subrule<1> aa(a);
167 }
168
169 { // context tests
170
171 char ch;
172 rule<char const*, char()> a;
173 subrule<0, char()> entry;
174
175 a = (entry = alpha[_val = _1])[_val = _1];
176 BOOST_TEST(test("x", a[phx::ref(ch) = _1]));
177 BOOST_TEST(ch == 'x');
178
179 a %= (entry = alpha[_val = _1]);
180 BOOST_TEST(test_attr("z", a, ch)); // attribute is given.
181 BOOST_TEST(ch == 'z');
182 }
183
184 { // auto subrules tests
185
186 char ch;
187 rule<char const*, char()> a;
188 subrule<0, char()> entry;
189
190 a = (entry %= alpha)[_val = _1];
191 BOOST_TEST(test("x", a[phx::ref(ch) = _1]));
192 BOOST_TEST(ch == 'x');
193
194 a %= (entry %= alpha);
195 BOOST_TEST(test_attr("z", a, ch)); // attribute is given.
196 BOOST_TEST(ch == 'z');
197 }
198
199 { // auto subrules tests: allow stl containers as attributes to
200 // sequences (in cases where attributes of the elements
201 // are convertible to the value_type of the container or if
202 // the element itself is an stl container with value_type
203 // that is convertible to the value_type of the attribute).
204
205 std::string s;
206 rule<char const*, std::string()> r;
207 subrule<0, std::string()> entry;
208
209 r %= (entry %= char_ >> *(',' >> char_));
210 BOOST_TEST(test("a,b,c,d,e,f", r[phx::ref(s) = _1]));
211 BOOST_TEST(s == "abcdef");
212
213 BOOST_TEST(test("abcdef", (
214 entry %= char_ >> char_ >> char_ >> char_ >> char_ >> char_
215 )[phx::ref(s) = _1]));
216 BOOST_TEST(s == "abcdef");
217 }
218
219 { // synth attribute value-init
220
221 std::string s;
222 subrule<0, char()> sr;
223 BOOST_TEST(test_attr("abcdef", +(sr = alpha[_val += _1]), s));
224 BOOST_TEST(s == "abcdef");
225 }
226
227 { // auto subrules aliasing tests
228
229 char ch;
230 rule<char const*, char()> r;
231 subrule<0, char()> a;
232 subrule<1, char()> b;
233 r %= (
234 a %= b
235 , b %= alpha
236 );
237
238 BOOST_TEST(test("x", r[phx::ref(ch) = _1]));
239 BOOST_TEST(ch == 'x');
240
241 BOOST_TEST(test_attr("z", r, ch)); // attribute is given.
242 BOOST_TEST(ch == 'z');
243 }
244
245 { // context (w/arg) tests
246
247 char ch;
248
249 // entry subrule with 1 arg
250 rule<char const*, char(int)> a;
251 subrule<1, char(int)> sr1;
252 a %= (
253 sr1 = alpha[_val = _1 + _r1]
254 )(_r1);
255 BOOST_TEST(test("x", a(phx::val(1))[phx::ref(ch) = _1]));
256 BOOST_TEST(ch == 'x' + 1);
257
258 // other subrule with 1 arg
259 subrule<0, char()> sr0;
260 a %= (
261 sr0 %= sr1(1)
262 , sr1 = alpha[_val = _1 + _r1]
263 );
264
265 // allow scalars as subrule args too
266 rule<char const*, char()> b;
267 b %= (
268 sr1 = alpha[_val = _1 + _r1]
269 )(1);
270 BOOST_TEST(test_attr("b", b, ch));
271 BOOST_TEST(ch == 'b' + 1);
272
273 // entry subrule with 2 args
274 subrule<2, char(int, int)> sr2;
275 BOOST_TEST(test_attr("a", (
276 sr2 = alpha[_val = _1 + _r1 + _r2]
277 )(1, 2), ch));
278 BOOST_TEST(ch == 'a' + 1 + 2);
279
280 // multiple subrules + args
281 BOOST_TEST(test_attr("ba", (
282 sr2 = alpha[_val = _1 + _r1 + _r2] >> sr1(3)[_val -= _1]
283 , sr1 = alpha[_val = _1 + _r1]
284 )(1, 2), ch));
285 BOOST_TEST(ch == ('b' + 1 + 2) - ('a' + 3));
286 }
287
288 { // context (w/ reference arg) tests
289
290 char ch;
291 subrule<0, void(char&)> sr; // 1 arg (reference) - direct
292 BOOST_TEST(test("x", (sr = alpha[_r1 = _1])(phx::ref(ch))));
293 BOOST_TEST(ch == 'x');
294
295 rule<char const*, void(char&)> a; // forwarded via a rule
296 a = (sr = alpha[_r1 = _1])(_r1);
297 BOOST_TEST(test("y", a(phx::ref(ch))));
298 BOOST_TEST(ch == 'y');
299 }
300
301 { // context (w/locals) tests
302
303 rule<char const*> r;
304 subrule<0, locals<char> > a; // 1 local
305 r = (
306 a = alpha[_a = _1] >> char_(_a)
307 );
308 BOOST_TEST(test("aa", r));
309 BOOST_TEST(!test("ax", r));
310 }
311
312 { // context (w/args and locals) tests
313
314 rule<char const*, void(int)> a;
315 subrule<0, void(int), locals<char> > sr; // 1 arg + 1 local
316 a = (
317 sr = alpha[_a = _1 + _r1] >> char_(_a)
318 )(_r1);
319 BOOST_TEST(test("ab", a(phx::val(1))));
320 BOOST_TEST(test("xy", a(phx::val(1))));
321 BOOST_TEST(!test("ax", a(phx::val(1))));
322 }
323
324 { // void() has unused type (void == unused_type)
325
326 std::pair<int, char> attr;
327 subrule<0, void()> sr;
328 BOOST_TEST(test_attr("123ax", int_ >> char_ >> (sr = char_), attr));
329 BOOST_TEST(attr.first == 123);
330 BOOST_TEST(attr.second == 'a');
331 }
332
333 { // test that injected attributes are ok
334
335 rule<char const*> r;
336 subrule<0, char(int)> sr;
337
338 r = (
339 sr = char_(_r1)[_val = _1]
340 )(42);
341 }
342
343 { // show that sra = srb and sra %= srb works as expected
344 subrule<0, int()> sra;
345 subrule<1, int()> srb;
346 int attr;
347
348 BOOST_TEST(test_attr("123", (sra %= int_), attr));
349 BOOST_TEST(attr == 123);
350
351 BOOST_TEST(test_attr("123", (srb %= sra, sra %= int_), attr));
352 BOOST_TEST(attr == 123);
353
354 BOOST_TEST(test_attr("123", (srb = sra, sra %= int_), attr));
355 BOOST_TEST(attr == 123);
356 }
357
358 { // std::string as container attribute with auto subrules
359
360 subrule<0, std::string()> text;
361 std::string attr;
362 BOOST_TEST(test_attr("x", (
363 text %= +(!char_(')') >> !char_('>') >> char_)
364 ), attr));
365 BOOST_TEST(attr == "x");
366 }
367
368 // { // error handling
369 //
370 // using namespace boost::spirit::ascii;
371 // using boost::phoenix::construct;
372 // using boost::phoenix::bind;
373 //
374 // rule<char const*> r;
375 // r = '(' > int_ > ',' > int_ > ')';
376 //
377 // on_error<fail>
378 // (
379 // r, std::cout
380 // << phx::val("Error! Expecting: ")
381 // << _4
382 // << phx::val(", got: \"")
383 // << construct<std::string>(_3, _2)
384 // << phx::val("\"")
385 // << std::endl
386 // );
387 //
388 // BOOST_TEST(test("(123,456)", r));
389 // BOOST_TEST(!test("(abc,def)", r));
390 // BOOST_TEST(!test("(123,456]", r));
391 // BOOST_TEST(!test("(123;456)", r));
392 // BOOST_TEST(!test("[123,456]", r));
393 // }
394
395 return boost::report_errors();
396 }
397
398