]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2002-2003 Hartmut Kaiser | |
3 | http://spirit.sourceforge.net/ | |
4 | ||
5 | Use, modification and distribution is subject to the Boost Software | |
6 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
7 | http://www.boost.org/LICENSE_1_0.txt) | |
8 | =============================================================================*/ | |
9 | /////////////////////////////////////////////////////////////////////////////// | |
10 | // | |
11 | // Traversal tests | |
12 | // | |
13 | /////////////////////////////////////////////////////////////////////////////// | |
14 | ||
1e59de90 | 15 | #include <boost/core/lightweight_test.hpp> |
7c673cae FG |
16 | #include <iostream> |
17 | #include <string> | |
18 | #include <vector> | |
19 | ||
20 | #include <boost/config.hpp> | |
21 | #include <boost/static_assert.hpp> | |
22 | ||
23 | #ifdef BOOST_NO_STRINGSTREAM | |
24 | #include <strstream> | |
25 | #define OSSTREAM std::ostrstream | |
26 | std::string GETSTRING(std::ostrstream& ss) | |
27 | { | |
28 | ss << ends; | |
29 | std::string rval = ss.str(); | |
30 | ss.freeze(false); | |
31 | return rval; | |
32 | } | |
33 | #else | |
34 | #include <sstream> | |
35 | #define GETSTRING(ss) ss.str() | |
36 | #define OSSTREAM std::ostringstream | |
37 | #endif | |
38 | ||
39 | #ifndef BOOST_SPIRIT_DEBUG | |
40 | #define BOOST_SPIRIT_DEBUG // needed for parser_name functions | |
41 | #endif | |
42 | ||
43 | #include <boost/spirit/include/classic_core.hpp> | |
44 | #include <boost/spirit/include/classic_assign_actor.hpp> | |
45 | #include <boost/spirit/include/classic_meta.hpp> | |
46 | ||
7c673cae FG |
47 | using namespace BOOST_SPIRIT_CLASSIC_NS; |
48 | ||
49 | typedef ref_value_actor<char, assign_action> assign_actor; | |
50 | ||
51 | /////////////////////////////////////////////////////////////////////////////// | |
52 | // | |
53 | // Test identity transformation | |
54 | // | |
55 | /////////////////////////////////////////////////////////////////////////////// | |
56 | void | |
57 | traverse_identity_tests() | |
58 | { | |
59 | // test type equality | |
60 | typedef sequence<chlit<char>, chlit<char> > test_sequence1_t; | |
61 | BOOST_STATIC_ASSERT(( | |
62 | ::boost::is_same< | |
63 | test_sequence1_t, | |
64 | post_order::result<identity_transform, test_sequence1_t>::type | |
65 | >::value | |
66 | )); | |
67 | ||
68 | // test (rough) runtime equality | |
69 | BOOST_TEST( | |
70 | parse( | |
71 | "ab", | |
72 | post_order::traverse(identity_transform(), ch_p('a') >> 'b') | |
73 | ).full | |
74 | ); | |
75 | BOOST_TEST( | |
76 | !parse( | |
77 | "ba", | |
78 | post_order::traverse(identity_transform(), ch_p('a') >> 'b') | |
79 | ).hit | |
80 | ); | |
81 | ||
82 | /////////////////////////////////////////////////////////////////////////// | |
83 | BOOST_TEST( | |
84 | !parse( | |
85 | "cba", | |
86 | post_order::traverse( | |
87 | identity_transform(), | |
88 | ch_p('a') >> 'b' >> 'c' | |
89 | ) | |
90 | ).hit | |
91 | ); | |
92 | ||
93 | /////////////////////////////////////////////////////////////////////////////// | |
94 | // Test more complex sequences | |
95 | char c; | |
96 | ||
97 | /////////////////////////////////////////////////////////////////////////////// | |
98 | // test: ((a >> b) >> c) >> d | |
99 | typedef | |
100 | sequence< | |
101 | sequence< | |
102 | sequence< | |
103 | kleene_star<chlit<> >, | |
104 | action<chlit<>, assign_actor> | |
105 | >, | |
106 | chlit<> | |
107 | >, | |
108 | optional<chlit<> > | |
109 | > test_sequence2_t; | |
110 | ||
111 | BOOST_STATIC_ASSERT(( | |
112 | ::boost::is_same< | |
113 | test_sequence2_t, | |
114 | post_order::result<identity_transform, test_sequence2_t>::type | |
115 | >::value | |
116 | )); | |
117 | ||
118 | c = 0; | |
119 | BOOST_TEST( | |
120 | parse( | |
121 | "aabcd", | |
122 | post_order::traverse( | |
123 | identity_transform(), | |
124 | ((*ch_p('a') >> ch_p('b')[assign_a(c)]) >> 'c') >> !ch_p('d') | |
125 | ) | |
126 | ).full | |
127 | ); | |
128 | BOOST_TEST(c == 'b'); | |
129 | ||
130 | /////////////////////////////////////////////////////////////////////////////// | |
131 | // test: (a >> (b >> c)) >> d | |
132 | typedef | |
133 | sequence< | |
134 | sequence< | |
135 | kleene_star<chlit<> >, | |
136 | sequence< | |
137 | action<chlit<>, assign_actor>, | |
138 | chlit<> | |
139 | > | |
140 | >, | |
141 | optional<chlit<char> > | |
142 | > test_sequence3_t; | |
143 | ||
144 | BOOST_STATIC_ASSERT(( | |
145 | ::boost::is_same< | |
146 | test_sequence3_t, | |
147 | post_order::result<identity_transform, test_sequence3_t>::type | |
148 | >::value | |
149 | )); | |
150 | ||
151 | c = 0; | |
152 | BOOST_TEST( | |
153 | parse( | |
154 | "aabcd", | |
155 | post_order::traverse( | |
156 | identity_transform(), | |
157 | (*ch_p('a') >> (ch_p('b')[assign_a(c)] >> 'c')) >> !ch_p('d') | |
158 | ) | |
159 | ).full | |
160 | ); | |
161 | BOOST_TEST(c == 'b'); | |
162 | ||
163 | /////////////////////////////////////////////////////////////////////////////// | |
164 | // test: a >> (b >> (c >> d)) | |
165 | typedef | |
166 | sequence< | |
167 | kleene_star<chlit<> >, | |
168 | sequence< | |
169 | action<chlit<>, assign_actor>, | |
170 | sequence< | |
171 | chlit<>, | |
172 | optional<chlit<> > | |
173 | > | |
174 | > | |
175 | > test_sequence4_t; | |
176 | ||
177 | BOOST_STATIC_ASSERT(( | |
178 | ::boost::is_same< | |
179 | test_sequence4_t, | |
180 | post_order::result<identity_transform, test_sequence4_t>::type | |
181 | >::value | |
182 | )); | |
183 | ||
184 | c = 0; | |
185 | BOOST_TEST( | |
186 | parse( | |
187 | "aabcd", | |
188 | post_order::traverse( | |
189 | identity_transform(), | |
190 | *ch_p('a') >> (ch_p('b')[assign_a(c)] >> ('c' >> !ch_p('d'))) | |
191 | ) | |
192 | ).full | |
193 | ); | |
194 | BOOST_TEST(c == 'b'); | |
195 | ||
196 | /////////////////////////////////////////////////////////////////////////////// | |
197 | // test: a >> ((b >> c) >> d) | |
198 | typedef | |
199 | sequence< | |
200 | kleene_star<chlit<> >, | |
201 | sequence< | |
202 | sequence< | |
203 | action<chlit<>, assign_actor>, | |
204 | chlit<> | |
205 | >, | |
206 | optional<chlit<> > | |
207 | > | |
208 | > test_sequence5_t; | |
209 | ||
210 | BOOST_STATIC_ASSERT(( | |
211 | ::boost::is_same< | |
212 | test_sequence5_t, | |
213 | post_order::result<identity_transform, test_sequence5_t>::type | |
214 | >::value | |
215 | )); | |
216 | ||
217 | c = 0; | |
218 | BOOST_TEST( | |
219 | parse( | |
220 | "aabcd", | |
221 | post_order::traverse( | |
222 | identity_transform(), | |
223 | *ch_p('a') >> ((ch_p('b')[assign_a(c)] >> 'c') >> !ch_p('d')) | |
224 | ) | |
225 | ).full | |
226 | ); | |
227 | BOOST_TEST(c == 'b'); | |
228 | ||
229 | /////////////////////////////////////////////////////////////////////////////// | |
230 | // test: (a >> b) >> (c >> d) | |
231 | typedef | |
232 | sequence< | |
233 | sequence< | |
234 | kleene_star<chlit<> >, | |
235 | action<chlit<>, assign_actor> | |
236 | >, | |
237 | sequence< | |
238 | chlit<>, | |
239 | optional<chlit<> > | |
240 | > | |
241 | > test_sequence6_t; | |
242 | ||
243 | BOOST_STATIC_ASSERT(( | |
244 | ::boost::is_same< | |
245 | test_sequence6_t, | |
246 | post_order::result<identity_transform, test_sequence6_t>::type | |
247 | >::value | |
248 | )); | |
249 | ||
250 | c = 0; | |
251 | BOOST_TEST( | |
252 | parse( | |
253 | "aabcd", | |
254 | post_order::traverse( | |
255 | identity_transform(), | |
256 | (*ch_p('a') >> ch_p('b')[assign_a(c)]) >> ('c' >> !ch_p('d')) | |
257 | ) | |
258 | ).full | |
259 | ); | |
260 | BOOST_TEST(c == 'b'); | |
261 | } | |
262 | ||
263 | /////////////////////////////////////////////////////////////////////////////// | |
264 | // | |
265 | // The following is a tracing identity_transform traverse metafunction | |
266 | // | |
267 | /////////////////////////////////////////////////////////////////////////////// | |
268 | ||
269 | class trace_identity_transform | |
270 | : public transform_policies<trace_identity_transform> { | |
271 | ||
272 | public: | |
273 | typedef trace_identity_transform self_t; | |
274 | typedef transform_policies<trace_identity_transform> base_t; | |
275 | ||
276 | template <typename ParserT, typename EnvT> | |
277 | typename parser_traversal_plain_result<self_t, ParserT, EnvT>::type | |
278 | generate_plain(ParserT const &parser_, EnvT const &env) const | |
279 | { | |
280 | OSSTREAM strout; | |
281 | strout | |
282 | << EnvT::node | |
283 | << ": plain (" | |
284 | << EnvT::level << ", " | |
285 | << EnvT::index | |
286 | << "): " | |
287 | << parser_name(parser_); | |
288 | traces.push_back(GETSTRING(strout)); | |
289 | ||
290 | return this->base_t::generate_plain(parser_, env); | |
291 | } | |
292 | ||
293 | template <typename UnaryT, typename SubjectT, typename EnvT> | |
294 | typename parser_traversal_unary_result<self_t, UnaryT, SubjectT, EnvT>::type | |
295 | generate_unary(UnaryT const &unary_, SubjectT const &subject_, | |
296 | EnvT const &env) const | |
297 | { | |
298 | OSSTREAM strout; | |
299 | strout | |
300 | << EnvT::node << ": unary (" | |
301 | << EnvT::level | |
302 | << "): " | |
303 | << parser_name(unary_); | |
304 | traces.push_back(GETSTRING(strout)); | |
305 | ||
306 | return this->base_t::generate_unary(unary_, subject_, env); | |
307 | } | |
308 | ||
309 | template <typename ActionT, typename SubjectT, typename EnvT> | |
310 | typename parser_traversal_action_result<self_t, ActionT, SubjectT, EnvT>::type | |
311 | generate_action(ActionT const &action_, SubjectT const &subject_, | |
312 | EnvT const &env) const | |
313 | { | |
314 | OSSTREAM strout; | |
315 | strout | |
316 | << EnvT::node << ": action(" | |
317 | << EnvT::level | |
318 | << "): " | |
319 | << parser_name(action_); | |
320 | traces.push_back(GETSTRING(strout)); | |
321 | ||
322 | return this->base_t::generate_action(action_, subject_, env); | |
323 | } | |
324 | ||
325 | template <typename BinaryT, typename LeftT, typename RightT, typename EnvT> | |
326 | typename parser_traversal_binary_result<self_t, BinaryT, LeftT, RightT, EnvT>::type | |
327 | generate_binary(BinaryT const &binary_, LeftT const& left_, | |
328 | RightT const& right_, EnvT const &env) const | |
329 | { | |
330 | OSSTREAM strout; | |
331 | strout | |
332 | << EnvT::node << ": binary(" | |
333 | << EnvT::level | |
334 | << "): " | |
335 | << parser_name(binary_); | |
336 | traces.push_back(GETSTRING(strout)); | |
337 | ||
338 | return this->base_t::generate_binary(binary_, left_, right_, env); | |
339 | } | |
340 | ||
11fdf7f2 | 341 | std::vector<std::string> const &get_output() const { return traces; } |
7c673cae FG |
342 | |
343 | private: | |
344 | mutable std::vector<std::string> traces; | |
345 | }; | |
346 | ||
347 | template <typename ParserT> | |
348 | void | |
349 | post_order_trace_test(ParserT const &parser_, char const *first[], size_t cnt) | |
350 | { | |
351 | // traverse | |
352 | trace_identity_transform trace_vector; | |
353 | ||
354 | post_order::traverse(trace_vector, parser_); | |
355 | ||
356 | // The following two re-find loops ensure, that both string arrays contain the | |
357 | // same entries, only their order may differ. The differences in the trace | |
358 | // string order is based on the different parameter evaluation order as it is | |
359 | // implemented by different compilers. | |
360 | ||
361 | // re-find all trace strings in the array of expected strings | |
362 | std::vector<std::string>::const_iterator it = trace_vector.get_output().begin(); | |
363 | std::vector<std::string>::const_iterator end = trace_vector.get_output().end(); | |
364 | ||
365 | BOOST_TEST(cnt == trace_vector.get_output().size()); | |
366 | for (/**/; it != end; ++it) | |
367 | { | |
368 | if (std::find(first, first + cnt, *it) == first + cnt) | |
11fdf7f2 | 369 | std::cerr << "node in question: " << *it << std::endl; |
7c673cae FG |
370 | |
371 | BOOST_TEST(std::find(first, first + cnt, *it) != first + cnt); | |
372 | } | |
373 | ||
374 | // re-find all expected strings in the vector of trace strings | |
375 | std::vector<std::string>::const_iterator begin = trace_vector.get_output().begin(); | |
376 | char const *expected = first[0]; | |
377 | ||
92f5a8d4 | 378 | for (size_t i = 0; i < cnt - 1; expected = first[++i]) |
7c673cae FG |
379 | { |
380 | if (std::find(begin, end, std::string(expected)) == end) | |
11fdf7f2 | 381 | std::cerr << "node in question: " << expected << std::endl; |
7c673cae FG |
382 | |
383 | BOOST_TEST(std::find(begin, end, std::string(expected)) != end); | |
384 | } | |
385 | } | |
386 | ||
387 | #if defined(_countof) | |
388 | #undef _countof | |
389 | #endif | |
390 | #define _countof(x) (sizeof(x)/sizeof(x[0])) | |
391 | ||
392 | void | |
393 | traverse_trace_tests() | |
394 | { | |
395 | const char *test_result1[] = { | |
396 | "0: plain (1, 0): chlit('a')", | |
397 | "1: plain (1, 1): chlit('b')", | |
398 | "2: binary(0): sequence[chlit('a'), chlit('b')]", | |
399 | }; | |
400 | ||
401 | post_order_trace_test( | |
402 | ch_p('a') >> 'b', | |
403 | test_result1, _countof(test_result1) | |
404 | ); | |
405 | ||
406 | char c = 0; | |
407 | ||
408 | // test: ((a >> b) >> c) >> d | |
409 | const char *test_result2[] = { | |
410 | "0: plain (4, 0): chlit('a')", | |
411 | "1: unary (3): kleene_star[chlit('a')]", | |
412 | "2: plain (4, 1): chlit('b')", | |
413 | "3: action(3): action[chlit('b')]", | |
414 | "4: binary(2): sequence[kleene_star[chlit('a')], action[chlit('b')]]", | |
415 | "5: plain (2, 2): chlit('c')", | |
416 | "6: binary(1): sequence[sequence[kleene_star[chlit('a')], action[chlit('b')]], chlit('c')]", | |
417 | "7: plain (2, 3): chlit('d')", | |
418 | "8: unary (1): optional[chlit('d')]", | |
419 | "9: binary(0): sequence[sequence[sequence[kleene_star[chlit('a')], action[chlit('b')]], chlit('c')], optional[chlit('d')]]", | |
420 | }; | |
421 | ||
422 | post_order_trace_test( | |
423 | ((*ch_p('a') >> ch_p('b')[assign_a(c)]) >> 'c') >> !ch_p('d'), | |
424 | test_result2, _countof(test_result2) | |
425 | ); | |
426 | ||
427 | // test: (a >> (b >> c)) >> d | |
428 | const char *test_result3[] = { | |
429 | "0: plain (3, 0): chlit('a')", | |
430 | "1: unary (2): kleene_star[chlit('a')]", | |
431 | "2: plain (4, 1): chlit('b')", | |
432 | "3: action(3): action[chlit('b')]", | |
433 | "4: plain (3, 2): chlit('c')", | |
434 | "5: binary(2): sequence[action[chlit('b')], chlit('c')]", | |
435 | "6: binary(1): sequence[kleene_star[chlit('a')], sequence[action[chlit('b')], chlit('c')]]", | |
436 | "7: plain (2, 3): chlit('d')", | |
437 | "8: unary (1): optional[chlit('d')]", | |
438 | "9: binary(0): sequence[sequence[kleene_star[chlit('a')], sequence[action[chlit('b')], chlit('c')]], optional[chlit('d')]]", | |
439 | }; | |
440 | ||
441 | post_order_trace_test( | |
442 | (*ch_p('a') >> (ch_p('b')[assign_a(c)] >> 'c')) >> !ch_p('d'), | |
443 | test_result3, _countof(test_result3) | |
444 | ); | |
445 | ||
446 | // test: a >> (b >> (c >> d)) | |
447 | const char *test_result4[] = { | |
448 | "0: plain (2, 0): chlit('a')", | |
449 | "1: unary (1): kleene_star[chlit('a')]", | |
450 | "2: plain (3, 1): chlit('b')", | |
451 | "3: action(2): action[chlit('b')]", | |
452 | "4: plain (3, 2): chlit('c')", | |
453 | "5: plain (4, 3): chlit('d')", | |
454 | "6: unary (3): optional[chlit('d')]", | |
455 | "7: binary(2): sequence[chlit('c'), optional[chlit('d')]]", | |
456 | "8: binary(1): sequence[action[chlit('b')], sequence[chlit('c'), optional[chlit('d')]]]", | |
457 | "9: binary(0): sequence[kleene_star[chlit('a')], sequence[action[chlit('b')], sequence[chlit('c'), optional[chlit('d')]]]]", | |
458 | }; | |
459 | ||
460 | post_order_trace_test( | |
461 | *ch_p('a') >> (ch_p('b')[assign_a(c)] >> ('c' >> !ch_p('d'))), | |
462 | test_result4, _countof(test_result4) | |
463 | ); | |
464 | ||
465 | // test: a >> ((b >> c) >> d) | |
466 | const char *test_result5[] = { | |
467 | "0: plain (2, 0): chlit('a')", | |
468 | "1: unary (1): kleene_star[chlit('a')]", | |
469 | "2: plain (4, 1): chlit('b')", | |
470 | "3: action(3): action[chlit('b')]", | |
471 | "4: plain (3, 2): chlit('c')", | |
472 | "5: binary(2): sequence[action[chlit('b')], chlit('c')]", | |
473 | "6: plain (3, 3): chlit('d')", | |
474 | "7: unary (2): optional[chlit('d')]", | |
475 | "8: binary(1): sequence[sequence[action[chlit('b')], chlit('c')], optional[chlit('d')]]", | |
476 | "9: binary(0): sequence[kleene_star[chlit('a')], sequence[sequence[action[chlit('b')], chlit('c')], optional[chlit('d')]]]", | |
477 | }; | |
478 | ||
479 | post_order_trace_test( | |
480 | *ch_p('a') >> ((ch_p('b')[assign_a(c)] >> 'c') >> !ch_p('d')), | |
481 | test_result5, _countof(test_result5) | |
482 | ); | |
483 | ||
484 | // test: (a >> b) >> (c >> d) | |
485 | const char *test_result6[] = { | |
486 | "0: plain (3, 0): chlit('a')", | |
487 | "1: unary (2): kleene_star[chlit('a')]", | |
488 | "2: plain (3, 1): chlit('b')", | |
489 | "3: action(2): action[chlit('b')]", | |
490 | "4: binary(1): sequence[kleene_star[chlit('a')], action[chlit('b')]]", | |
491 | "5: plain (2, 2): chlit('c')", | |
492 | "6: plain (3, 3): chlit('d')", | |
493 | "7: unary (2): optional[chlit('d')]", | |
494 | "8: binary(1): sequence[chlit('c'), optional[chlit('d')]]", | |
495 | "9: binary(0): sequence[sequence[kleene_star[chlit('a')], action[chlit('b')]], sequence[chlit('c'), optional[chlit('d')]]]", | |
496 | }; | |
497 | ||
498 | post_order_trace_test( | |
499 | (*ch_p('a') >> ch_p('b')[assign_a(c)]) >> ('c' >> !ch_p('d')), | |
500 | test_result6, _countof(test_result6) | |
501 | ); | |
502 | } | |
503 | ||
504 | /////////////////////////////////////////////////////////////////////////////// | |
505 | // | |
506 | // Main | |
507 | // | |
508 | /////////////////////////////////////////////////////////////////////////////// | |
509 | int | |
510 | main() | |
511 | { | |
512 | traverse_identity_tests(); | |
513 | traverse_trace_tests(); | |
514 | ||
515 | return boost::report_errors(); | |
516 | } | |
517 |