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 
15 #include <boost/detail/lightweight_test.hpp>
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
GETSTRING(std::ostrstream & ss)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 
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
traverse_identity_tests()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
generate_plain(ParserT const & parser_,EnvT const & env) const278     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
generate_unary(UnaryT const & unary_,SubjectT const & subject_,EnvT const & env) const295     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
generate_action(ActionT const & action_,SubjectT const & subject_,EnvT const & env) const311     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
generate_binary(BinaryT const & binary_,LeftT const & left_,RightT const & right_,EnvT const & env) const327     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 
get_output() const341     std::vector<std::string> const &get_output() const { return traces; }
342 
343 private:
344     mutable std::vector<std::string> traces;
345 };
346 
347 template <typename ParserT>
348 void
post_order_trace_test(ParserT const & parser_,char const * first[],size_t cnt)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)
369             std::cerr << "node in question: " << *it << std::endl;
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 
378     for (size_t i = 0; i < cnt - 1; expected = first[++i])
379     {
380         if (std::find(begin, end, std::string(expected)) == end)
381             std::cerr << "node in question: " << expected << std::endl;
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
traverse_trace_tests()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
main()510 main()
511 {
512     traverse_identity_tests();
513     traverse_trace_tests();
514 
515     return boost::report_errors();
516 }
517 
518