123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- /*=============================================================================
- Copyright (c) 2002-2003 Hartmut Kaiser
- http://spirit.sourceforge.net/
- Use, modification and distribution is subject to the Boost Software
- License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt)
- =============================================================================*/
- ///////////////////////////////////////////////////////////////////////////////
- //
- // Traversal tests
- //
- ///////////////////////////////////////////////////////////////////////////////
- #include <boost/detail/lightweight_test.hpp>
- #include <iostream>
- #include <string>
- #include <vector>
- #include <boost/config.hpp>
- #include <boost/static_assert.hpp>
- #ifdef BOOST_NO_STRINGSTREAM
- #include <strstream>
- #define OSSTREAM std::ostrstream
- std::string GETSTRING(std::ostrstream& ss)
- {
- ss << ends;
- std::string rval = ss.str();
- ss.freeze(false);
- return rval;
- }
- #else
- #include <sstream>
- #define GETSTRING(ss) ss.str()
- #define OSSTREAM std::ostringstream
- #endif
- #ifndef BOOST_SPIRIT_DEBUG
- #define BOOST_SPIRIT_DEBUG // needed for parser_name functions
- #endif
- #include <boost/spirit/include/classic_core.hpp>
- #include <boost/spirit/include/classic_assign_actor.hpp>
- #include <boost/spirit/include/classic_meta.hpp>
- using namespace BOOST_SPIRIT_CLASSIC_NS;
- typedef ref_value_actor<char, assign_action> assign_actor;
- ///////////////////////////////////////////////////////////////////////////////
- //
- // Test identity transformation
- //
- ///////////////////////////////////////////////////////////////////////////////
- void
- traverse_identity_tests()
- {
- // test type equality
- typedef sequence<chlit<char>, chlit<char> > test_sequence1_t;
- BOOST_STATIC_ASSERT((
- ::boost::is_same<
- test_sequence1_t,
- post_order::result<identity_transform, test_sequence1_t>::type
- >::value
- ));
- // test (rough) runtime equality
- BOOST_TEST(
- parse(
- "ab",
- post_order::traverse(identity_transform(), ch_p('a') >> 'b')
- ).full
- );
- BOOST_TEST(
- !parse(
- "ba",
- post_order::traverse(identity_transform(), ch_p('a') >> 'b')
- ).hit
- );
- ///////////////////////////////////////////////////////////////////////////
- BOOST_TEST(
- !parse(
- "cba",
- post_order::traverse(
- identity_transform(),
- ch_p('a') >> 'b' >> 'c'
- )
- ).hit
- );
- ///////////////////////////////////////////////////////////////////////////////
- // Test more complex sequences
- char c;
- ///////////////////////////////////////////////////////////////////////////////
- // test: ((a >> b) >> c) >> d
- typedef
- sequence<
- sequence<
- sequence<
- kleene_star<chlit<> >,
- action<chlit<>, assign_actor>
- >,
- chlit<>
- >,
- optional<chlit<> >
- > test_sequence2_t;
- BOOST_STATIC_ASSERT((
- ::boost::is_same<
- test_sequence2_t,
- post_order::result<identity_transform, test_sequence2_t>::type
- >::value
- ));
- c = 0;
- BOOST_TEST(
- parse(
- "aabcd",
- post_order::traverse(
- identity_transform(),
- ((*ch_p('a') >> ch_p('b')[assign_a(c)]) >> 'c') >> !ch_p('d')
- )
- ).full
- );
- BOOST_TEST(c == 'b');
- ///////////////////////////////////////////////////////////////////////////////
- // test: (a >> (b >> c)) >> d
- typedef
- sequence<
- sequence<
- kleene_star<chlit<> >,
- sequence<
- action<chlit<>, assign_actor>,
- chlit<>
- >
- >,
- optional<chlit<char> >
- > test_sequence3_t;
- BOOST_STATIC_ASSERT((
- ::boost::is_same<
- test_sequence3_t,
- post_order::result<identity_transform, test_sequence3_t>::type
- >::value
- ));
- c = 0;
- BOOST_TEST(
- parse(
- "aabcd",
- post_order::traverse(
- identity_transform(),
- (*ch_p('a') >> (ch_p('b')[assign_a(c)] >> 'c')) >> !ch_p('d')
- )
- ).full
- );
- BOOST_TEST(c == 'b');
- ///////////////////////////////////////////////////////////////////////////////
- // test: a >> (b >> (c >> d))
- typedef
- sequence<
- kleene_star<chlit<> >,
- sequence<
- action<chlit<>, assign_actor>,
- sequence<
- chlit<>,
- optional<chlit<> >
- >
- >
- > test_sequence4_t;
- BOOST_STATIC_ASSERT((
- ::boost::is_same<
- test_sequence4_t,
- post_order::result<identity_transform, test_sequence4_t>::type
- >::value
- ));
- c = 0;
- BOOST_TEST(
- parse(
- "aabcd",
- post_order::traverse(
- identity_transform(),
- *ch_p('a') >> (ch_p('b')[assign_a(c)] >> ('c' >> !ch_p('d')))
- )
- ).full
- );
- BOOST_TEST(c == 'b');
- ///////////////////////////////////////////////////////////////////////////////
- // test: a >> ((b >> c) >> d)
- typedef
- sequence<
- kleene_star<chlit<> >,
- sequence<
- sequence<
- action<chlit<>, assign_actor>,
- chlit<>
- >,
- optional<chlit<> >
- >
- > test_sequence5_t;
- BOOST_STATIC_ASSERT((
- ::boost::is_same<
- test_sequence5_t,
- post_order::result<identity_transform, test_sequence5_t>::type
- >::value
- ));
- c = 0;
- BOOST_TEST(
- parse(
- "aabcd",
- post_order::traverse(
- identity_transform(),
- *ch_p('a') >> ((ch_p('b')[assign_a(c)] >> 'c') >> !ch_p('d'))
- )
- ).full
- );
- BOOST_TEST(c == 'b');
- ///////////////////////////////////////////////////////////////////////////////
- // test: (a >> b) >> (c >> d)
- typedef
- sequence<
- sequence<
- kleene_star<chlit<> >,
- action<chlit<>, assign_actor>
- >,
- sequence<
- chlit<>,
- optional<chlit<> >
- >
- > test_sequence6_t;
- BOOST_STATIC_ASSERT((
- ::boost::is_same<
- test_sequence6_t,
- post_order::result<identity_transform, test_sequence6_t>::type
- >::value
- ));
- c = 0;
- BOOST_TEST(
- parse(
- "aabcd",
- post_order::traverse(
- identity_transform(),
- (*ch_p('a') >> ch_p('b')[assign_a(c)]) >> ('c' >> !ch_p('d'))
- )
- ).full
- );
- BOOST_TEST(c == 'b');
- }
- ///////////////////////////////////////////////////////////////////////////////
- //
- // The following is a tracing identity_transform traverse metafunction
- //
- ///////////////////////////////////////////////////////////////////////////////
- class trace_identity_transform
- : public transform_policies<trace_identity_transform> {
- public:
- typedef trace_identity_transform self_t;
- typedef transform_policies<trace_identity_transform> base_t;
- template <typename ParserT, typename EnvT>
- typename parser_traversal_plain_result<self_t, ParserT, EnvT>::type
- generate_plain(ParserT const &parser_, EnvT const &env) const
- {
- OSSTREAM strout;
- strout
- << EnvT::node
- << ": plain ("
- << EnvT::level << ", "
- << EnvT::index
- << "): "
- << parser_name(parser_);
- traces.push_back(GETSTRING(strout));
- return this->base_t::generate_plain(parser_, env);
- }
- template <typename UnaryT, typename SubjectT, typename EnvT>
- typename parser_traversal_unary_result<self_t, UnaryT, SubjectT, EnvT>::type
- generate_unary(UnaryT const &unary_, SubjectT const &subject_,
- EnvT const &env) const
- {
- OSSTREAM strout;
- strout
- << EnvT::node << ": unary ("
- << EnvT::level
- << "): "
- << parser_name(unary_);
- traces.push_back(GETSTRING(strout));
- return this->base_t::generate_unary(unary_, subject_, env);
- }
- template <typename ActionT, typename SubjectT, typename EnvT>
- typename parser_traversal_action_result<self_t, ActionT, SubjectT, EnvT>::type
- generate_action(ActionT const &action_, SubjectT const &subject_,
- EnvT const &env) const
- {
- OSSTREAM strout;
- strout
- << EnvT::node << ": action("
- << EnvT::level
- << "): "
- << parser_name(action_);
- traces.push_back(GETSTRING(strout));
- return this->base_t::generate_action(action_, subject_, env);
- }
- template <typename BinaryT, typename LeftT, typename RightT, typename EnvT>
- 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) const
- {
- OSSTREAM strout;
- strout
- << EnvT::node << ": binary("
- << EnvT::level
- << "): "
- << parser_name(binary_);
- traces.push_back(GETSTRING(strout));
- return this->base_t::generate_binary(binary_, left_, right_, env);
- }
- std::vector<std::string> const &get_output() const { return traces; }
- private:
- mutable std::vector<std::string> traces;
- };
- template <typename ParserT>
- void
- post_order_trace_test(ParserT const &parser_, char const *first[], size_t cnt)
- {
- // traverse
- trace_identity_transform trace_vector;
- post_order::traverse(trace_vector, parser_);
- // The following two re-find loops ensure, that both string arrays contain the
- // same entries, only their order may differ. The differences in the trace
- // string order is based on the different parameter evaluation order as it is
- // implemented by different compilers.
- // re-find all trace strings in the array of expected strings
- std::vector<std::string>::const_iterator it = trace_vector.get_output().begin();
- std::vector<std::string>::const_iterator end = trace_vector.get_output().end();
- BOOST_TEST(cnt == trace_vector.get_output().size());
- for (/**/; it != end; ++it)
- {
- if (std::find(first, first + cnt, *it) == first + cnt)
- std::cerr << "node in question: " << *it << std::endl;
- BOOST_TEST(std::find(first, first + cnt, *it) != first + cnt);
- }
- // re-find all expected strings in the vector of trace strings
- std::vector<std::string>::const_iterator begin = trace_vector.get_output().begin();
- char const *expected = first[0];
- for (size_t i = 0; i < cnt - 1; expected = first[++i])
- {
- if (std::find(begin, end, std::string(expected)) == end)
- std::cerr << "node in question: " << expected << std::endl;
- BOOST_TEST(std::find(begin, end, std::string(expected)) != end);
- }
- }
- #if defined(_countof)
- #undef _countof
- #endif
- #define _countof(x) (sizeof(x)/sizeof(x[0]))
- void
- traverse_trace_tests()
- {
- const char *test_result1[] = {
- "0: plain (1, 0): chlit('a')",
- "1: plain (1, 1): chlit('b')",
- "2: binary(0): sequence[chlit('a'), chlit('b')]",
- };
- post_order_trace_test(
- ch_p('a') >> 'b',
- test_result1, _countof(test_result1)
- );
- char c = 0;
- // test: ((a >> b) >> c) >> d
- const char *test_result2[] = {
- "0: plain (4, 0): chlit('a')",
- "1: unary (3): kleene_star[chlit('a')]",
- "2: plain (4, 1): chlit('b')",
- "3: action(3): action[chlit('b')]",
- "4: binary(2): sequence[kleene_star[chlit('a')], action[chlit('b')]]",
- "5: plain (2, 2): chlit('c')",
- "6: binary(1): sequence[sequence[kleene_star[chlit('a')], action[chlit('b')]], chlit('c')]",
- "7: plain (2, 3): chlit('d')",
- "8: unary (1): optional[chlit('d')]",
- "9: binary(0): sequence[sequence[sequence[kleene_star[chlit('a')], action[chlit('b')]], chlit('c')], optional[chlit('d')]]",
- };
- post_order_trace_test(
- ((*ch_p('a') >> ch_p('b')[assign_a(c)]) >> 'c') >> !ch_p('d'),
- test_result2, _countof(test_result2)
- );
- // test: (a >> (b >> c)) >> d
- const char *test_result3[] = {
- "0: plain (3, 0): chlit('a')",
- "1: unary (2): kleene_star[chlit('a')]",
- "2: plain (4, 1): chlit('b')",
- "3: action(3): action[chlit('b')]",
- "4: plain (3, 2): chlit('c')",
- "5: binary(2): sequence[action[chlit('b')], chlit('c')]",
- "6: binary(1): sequence[kleene_star[chlit('a')], sequence[action[chlit('b')], chlit('c')]]",
- "7: plain (2, 3): chlit('d')",
- "8: unary (1): optional[chlit('d')]",
- "9: binary(0): sequence[sequence[kleene_star[chlit('a')], sequence[action[chlit('b')], chlit('c')]], optional[chlit('d')]]",
- };
- post_order_trace_test(
- (*ch_p('a') >> (ch_p('b')[assign_a(c)] >> 'c')) >> !ch_p('d'),
- test_result3, _countof(test_result3)
- );
- // test: a >> (b >> (c >> d))
- const char *test_result4[] = {
- "0: plain (2, 0): chlit('a')",
- "1: unary (1): kleene_star[chlit('a')]",
- "2: plain (3, 1): chlit('b')",
- "3: action(2): action[chlit('b')]",
- "4: plain (3, 2): chlit('c')",
- "5: plain (4, 3): chlit('d')",
- "6: unary (3): optional[chlit('d')]",
- "7: binary(2): sequence[chlit('c'), optional[chlit('d')]]",
- "8: binary(1): sequence[action[chlit('b')], sequence[chlit('c'), optional[chlit('d')]]]",
- "9: binary(0): sequence[kleene_star[chlit('a')], sequence[action[chlit('b')], sequence[chlit('c'), optional[chlit('d')]]]]",
- };
- post_order_trace_test(
- *ch_p('a') >> (ch_p('b')[assign_a(c)] >> ('c' >> !ch_p('d'))),
- test_result4, _countof(test_result4)
- );
- // test: a >> ((b >> c) >> d)
- const char *test_result5[] = {
- "0: plain (2, 0): chlit('a')",
- "1: unary (1): kleene_star[chlit('a')]",
- "2: plain (4, 1): chlit('b')",
- "3: action(3): action[chlit('b')]",
- "4: plain (3, 2): chlit('c')",
- "5: binary(2): sequence[action[chlit('b')], chlit('c')]",
- "6: plain (3, 3): chlit('d')",
- "7: unary (2): optional[chlit('d')]",
- "8: binary(1): sequence[sequence[action[chlit('b')], chlit('c')], optional[chlit('d')]]",
- "9: binary(0): sequence[kleene_star[chlit('a')], sequence[sequence[action[chlit('b')], chlit('c')], optional[chlit('d')]]]",
- };
- post_order_trace_test(
- *ch_p('a') >> ((ch_p('b')[assign_a(c)] >> 'c') >> !ch_p('d')),
- test_result5, _countof(test_result5)
- );
- // test: (a >> b) >> (c >> d)
- const char *test_result6[] = {
- "0: plain (3, 0): chlit('a')",
- "1: unary (2): kleene_star[chlit('a')]",
- "2: plain (3, 1): chlit('b')",
- "3: action(2): action[chlit('b')]",
- "4: binary(1): sequence[kleene_star[chlit('a')], action[chlit('b')]]",
- "5: plain (2, 2): chlit('c')",
- "6: plain (3, 3): chlit('d')",
- "7: unary (2): optional[chlit('d')]",
- "8: binary(1): sequence[chlit('c'), optional[chlit('d')]]",
- "9: binary(0): sequence[sequence[kleene_star[chlit('a')], action[chlit('b')]], sequence[chlit('c'), optional[chlit('d')]]]",
- };
- post_order_trace_test(
- (*ch_p('a') >> ch_p('b')[assign_a(c)]) >> ('c' >> !ch_p('d')),
- test_result6, _countof(test_result6)
- );
- }
- ///////////////////////////////////////////////////////////////////////////////
- //
- // Main
- //
- ///////////////////////////////////////////////////////////////////////////////
- int
- main()
- {
- traverse_identity_tests();
- traverse_trace_tests();
- return boost::report_errors();
- }
|