traverse_tests.cpp 16 KB

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