tree_tests.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*=============================================================================
  2. Copyright (c) 2003 Giovanni Bajo
  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. #include <boost/spirit/include/classic_core.hpp>
  9. #include <boost/spirit/include/classic_ast.hpp>
  10. #include <boost/spirit/include/classic_tree_to_xml.hpp>
  11. #include <boost/preprocessor/arithmetic/inc.hpp>
  12. #include <boost/preprocessor/punctuation/comma_if.hpp>
  13. #include <boost/preprocessor/repetition.hpp>
  14. #include <boost/preprocessor/arithmetic/sub.hpp>
  15. #include <boost/mpl/list.hpp>
  16. #include <boost/mpl/apply.hpp>
  17. #include <boost/mpl/remove.hpp>
  18. #include <boost/mpl/size.hpp>
  19. #include <boost/mpl/for_each.hpp>
  20. #include <map>
  21. #include <string>
  22. #include <fstream>
  23. #include <boost/detail/lightweight_test.hpp>
  24. #include "impl/string_length.hpp"
  25. #define DEBUG_DUMP_TREES (1)
  26. //////////////////////////////////////////////////////////////////////////////
  27. // rule_id helper
  28. // http://sf.net/tracker/index.php?func=detail&aid=715483&group_id=28447&atid=393389)
  29. namespace boost { namespace spirit {
  30. template <
  31. typename ScannerT,
  32. unsigned long ID = 0,
  33. typename ContextT = parser_context<> >
  34. class rule_id
  35. : public rule<ScannerT, ContextT, parser_tag<ID> >
  36. {
  37. typedef rule<ScannerT, ContextT, parser_tag<ID> > base_t;
  38. public:
  39. // Forward ctors and operator=.
  40. rule_id()
  41. {}
  42. template <typename T>
  43. rule_id(const T& a)
  44. : base_t(a) {}
  45. template <typename T>
  46. rule_id& operator=(const T& a)
  47. { base_t::operator=(a); return *this; }
  48. };
  49. }}
  50. //////////////////////////////////////////////////////////////////////////////
  51. // Framework setup
  52. namespace mpl = boost::mpl;
  53. using namespace BOOST_SPIRIT_CLASSIC_NS;
  54. using namespace std;
  55. enum RULE_ID
  56. {
  57. ID_A = 1,
  58. ID_B,
  59. ID_C,
  60. ID_ROOT
  61. };
  62. map<parser_id, string> rule_names;
  63. //////////////////////////////////////////////////////////////////////////////
  64. // Generic tree manipulation tools
  65. template <typename TreeT>
  66. RULE_ID id(TreeT& t)
  67. { return (RULE_ID)t.value.id().to_long(); }
  68. template <typename TreeT>
  69. TreeT& child(TreeT& t, unsigned n)
  70. {
  71. return t.children[n];
  72. }
  73. template <typename TreeT>
  74. size_t num_children(const TreeT& t)
  75. { return t.children.size(); }
  76. template <typename TreeT>
  77. typename TreeT::parse_node_t::iterator_t ValueBeginIterator(TreeT& t)
  78. { return t.value.begin(); }
  79. template <typename TreeT>
  80. typename TreeT::parse_node_t::iterator_t ValueEndIterator(TreeT& t)
  81. { return t.value.end(); }
  82. template <typename TreeT>
  83. bool equal(TreeT& a, TreeT& b)
  84. {
  85. if (id(a) != id(b))
  86. return false;
  87. if (num_children(a) != num_children(b))
  88. return false;
  89. unsigned n = num_children(a);
  90. for (unsigned i=0;i<n;i++)
  91. if (!equal(child(a, i), child(b, i)))
  92. return false;
  93. return true;
  94. }
  95. template <typename TreeT>
  96. void dump(ostream& o, TreeT& t, int level = 0)
  97. {
  98. string name;
  99. string value;
  100. map<parser_id, string>::iterator iter =
  101. rule_names.find(id(t));
  102. if (iter == rule_names.end())
  103. name = "noname";
  104. else
  105. name = iter->second;
  106. value.assign(ValueBeginIterator(t), ValueEndIterator(t));
  107. for (int i=0;i<level;i++)
  108. o << " ";
  109. o << name << ": " << value << endl;
  110. unsigned n = num_children(t);
  111. for (unsigned c=0;c<n;c++)
  112. dump(o, child(t, c), level+1);
  113. }
  114. //////////////////////////////////////////////////////////////////////////////
  115. // Tree folding
  116. namespace test_impl {
  117. template <typename ParmT>
  118. struct fold_node
  119. {
  120. // assign a subtree
  121. void operator()(ParmT& t, ParmT ch) const
  122. { t = ch; }
  123. // wrong specialization
  124. template <typename TreeT>
  125. void operator()(TreeT& t, ParmT p) const
  126. { typedef typename TreeT::this_should_never_be_compiled type; }
  127. };
  128. template <>
  129. struct fold_node<nil_t>
  130. {
  131. template <typename TreeT>
  132. void operator()(TreeT& t, nil_t) const
  133. { typedef typename TreeT::this_should_never_be_compiled type; }
  134. };
  135. template <>
  136. struct fold_node<RULE_ID>
  137. {
  138. template <typename TreeT>
  139. void operator()(TreeT& t, RULE_ID id) const
  140. { t.value.id(id); }
  141. };
  142. template <typename ParmT>
  143. struct fold_child
  144. {
  145. template <typename TreeT>
  146. void operator()(TreeT& t, ParmT p, unsigned n) const
  147. { fold_node<ParmT>()(t.children[n], p); }
  148. };
  149. template <>
  150. struct fold_child<nil_t>
  151. {
  152. template <typename TreeT>
  153. void operator()(TreeT& t, nil_t, unsigned n) const
  154. {}
  155. };
  156. }
  157. template <typename TreeT,
  158. typename T, typename T1, typename T2, typename T3, typename T4,
  159. typename T5, typename T6, typename T7, typename T8>
  160. TreeT fold(T p, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8)
  161. {
  162. // Prepare a list with all the template types
  163. typedef mpl::list<T1,T2,T3,T4,T5,T6,T7,T8> full_list_t;
  164. // Remove the ones equal to nil_t: they are the default parameters
  165. // unspecified from the user
  166. typedef typename mpl::remove<full_list_t, nil_t>::type parm_list_t;
  167. // Get the size of the list = number of parameters specified by the user
  168. typedef typename mpl::size<parm_list_t>::type parm_list_size_t;
  169. enum { NUM_CHILDREN = parm_list_size_t::value };
  170. TreeT t;
  171. // Generate the root of the tree (specialized for the first parameter)
  172. test_impl::fold_node<T>()(t, p);
  173. // Make room for the children
  174. if (NUM_CHILDREN > 0)
  175. t.children.resize(NUM_CHILDREN);
  176. // For each children, call the GenerateChild function, which is specialized
  177. // on the different types
  178. test_impl::fold_child<T1>()(t, p1, 0);
  179. test_impl::fold_child<T2>()(t, p2, 1);
  180. test_impl::fold_child<T3>()(t, p3, 2);
  181. test_impl::fold_child<T4>()(t, p4, 3);
  182. test_impl::fold_child<T5>()(t, p5, 4);
  183. test_impl::fold_child<T6>()(t, p6, 5);
  184. test_impl::fold_child<T7>()(t, p7, 6);
  185. test_impl::fold_child<T8>()(t, p8, 7);
  186. return t;
  187. }
  188. // Define fold() wrapper for 1->7 parameters: they just call the 8 parameter
  189. // version passing nil_t for the other arguments
  190. #define PUT_EMPTY(Z, N, _) nil_t()
  191. #define DEFINE_FOLD(Z, N, _) \
  192. template <typename TreeT, typename T BOOST_PP_COMMA_IF(N) \
  193. BOOST_PP_ENUM_PARAMS(N, typename T) > \
  194. TreeT fold(T p BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_BINARY_PARAMS(N, T, p)) \
  195. { \
  196. return fold<TreeT>(p \
  197. BOOST_PP_COMMA_IF(N) BOOST_PP_ENUM_PARAMS(N, p) \
  198. BOOST_PP_COMMA_IF(BOOST_PP_SUB(8,N)) \
  199. BOOST_PP_ENUM(BOOST_PP_SUB(8,N), PUT_EMPTY, _)); \
  200. }
  201. BOOST_PP_REPEAT(7, DEFINE_FOLD, _)
  202. #undef PUT_EMPTY
  203. #undef DEFINE_FOLD
  204. //////////////////////////////////////////////////////////////////////////////
  205. // test_banal: simple tree construction
  206. struct test_banal : public grammar<test_banal>
  207. {
  208. template <class T>
  209. struct definition
  210. {
  211. rule_id<T, ID_ROOT> root;
  212. rule_id<T, ID_A> a;
  213. rule_id<T, ID_B> b;
  214. rule_id<T, ID_C> c;
  215. definition(const test_banal&)
  216. {
  217. root = a >> c;
  218. a = b;
  219. b = chlit<>('b');
  220. c = chlit<>('c');
  221. }
  222. const rule_id<T, ID_ROOT>& start()
  223. { return root; }
  224. };
  225. const char* pattern(void)
  226. {
  227. return "bc";
  228. }
  229. template <typename TreeT>
  230. TreeT expected_tree(void)
  231. {
  232. return fold<TreeT>(
  233. ID_ROOT, fold<TreeT>(
  234. ID_A,
  235. ID_B),
  236. ID_C);
  237. }
  238. };
  239. //////////////////////////////////////////////////////////////////////////////
  240. // All the tests
  241. typedef mpl::list
  242. <
  243. test_banal
  244. > tests_t;
  245. //////////////////////////////////////////////////////////////////////////////
  246. // run_test - code to run a test
  247. struct run_test
  248. {
  249. template <typename TestT>
  250. void operator()(TestT gram)
  251. {
  252. typedef const char* iterator_t;
  253. typedef node_val_data_factory<nil_t> factory_t;
  254. typedef typename
  255. factory_t
  256. ::BOOST_NESTED_TEMPLATE factory<iterator_t>
  257. ::node_t node_t;
  258. typedef tree_node<node_t> tree_t;
  259. iterator_t text_begin = gram.pattern();
  260. iterator_t text_end = text_begin + test_impl::string_length(text_begin);
  261. tree_parse_info<iterator_t, factory_t> info =
  262. ast_parse(text_begin, text_end, gram);
  263. BOOST_TEST(info.full);
  264. tree_t expected = gram.template expected_tree<tree_t>();
  265. #if DEBUG_DUMP_TREES
  266. dump(cout, info.trees[0]);
  267. dump(cout, expected);
  268. #endif
  269. BOOST_TEST(equal(info.trees[0], expected));
  270. }
  271. };
  272. //////////////////////////////////////////////////////////////////////////////
  273. // main() stuff
  274. #ifdef BOOST_NO_EXCEPTIONS
  275. namespace boost
  276. {
  277. void throw_exception(std::exception const & )
  278. {
  279. std::cerr << "Exception caught" << std::endl;
  280. BOOST_TEST(0);
  281. }
  282. }
  283. #endif
  284. void init(void)
  285. {
  286. rule_names[ID_ROOT] = "ID_ROOT";
  287. rule_names[ID_A] = "ID_A";
  288. rule_names[ID_B] = "ID_B";
  289. rule_names[ID_C] = "ID_C";
  290. }
  291. int main()
  292. {
  293. init();
  294. mpl::for_each<tests_t, mpl::_> (run_test());
  295. return boost::report_errors();
  296. }