test_actions.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // test_actions.cpp
  3. //
  4. // Copyright 2008 Eric Niebler. Distributed under the Boost
  5. // Software License, Version 1.0. (See accompanying file
  6. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. //#define BOOST_XPRESSIVE_BETTER_ERRORS
  8. #include <map>
  9. #include <list>
  10. #include <stack>
  11. #include <numeric>
  12. #include <boost/version.hpp>
  13. #include <boost/xpressive/xpressive_static.hpp>
  14. #include <boost/xpressive/regex_actions.hpp>
  15. #include <boost/test/unit_test.hpp>
  16. namespace xp = boost::xpressive;
  17. ///////////////////////////////////////////////////////////////////////////////
  18. // test1
  19. // simple action which builds a string
  20. void test1()
  21. {
  22. using namespace boost::xpressive;
  23. std::string result;
  24. std::string str("foo bar baz foo bar baz");
  25. sregex rx = (+_w)[ xp::ref(result) += _ ] >> *(' ' >> (+_w)[ xp::ref(result) += ',' + _ ]);
  26. if(!regex_match(str, rx))
  27. {
  28. BOOST_ERROR("oops");
  29. }
  30. else
  31. {
  32. BOOST_CHECK_EQUAL(result, "foo,bar,baz,foo,bar,baz");
  33. }
  34. }
  35. ///////////////////////////////////////////////////////////////////////////////
  36. // test2
  37. // test backtracking over actions
  38. void test2()
  39. {
  40. using namespace boost::xpressive;
  41. std::string result;
  42. std::string str("foo bar baz foo bar baz");
  43. sregex rx = (+_w)[ xp::ref(result) += _ ] >> *(' ' >> (+_w)[ xp::ref(result) += ',' + _ ]) >> repeat<4>(_);
  44. if(!regex_match(str, rx))
  45. {
  46. BOOST_ERROR("oops");
  47. }
  48. else
  49. {
  50. BOOST_CHECK_EQUAL(result, "foo,bar,baz,foo,bar");
  51. }
  52. }
  53. ///////////////////////////////////////////////////////////////////////////////
  54. // test3
  55. // cast string to int, push back into list, use alternate ->* syntax
  56. void test3()
  57. {
  58. using namespace boost::xpressive;
  59. std::list<int> result;
  60. std::string str("1 23 456 7890");
  61. #if BOOST_VERSION >= 103500
  62. sregex rx = (+_d)[ xp::ref(result)->*push_back( as<int>(_) ) ]
  63. >> *(' ' >> (+_d)[ xp::ref(result)->*push_back( as<int>(_) ) ]);
  64. #else
  65. sregex rx = (+_d)[ push_back(xp::ref(result), as<int>(_) ) ]
  66. >> *(' ' >> (+_d)[ push_back(xp::ref(result), as<int>(_) ) ]);
  67. #endif
  68. if(!regex_match(str, rx))
  69. {
  70. BOOST_ERROR("oops");
  71. }
  72. else
  73. {
  74. BOOST_REQUIRE_EQUAL(result.size(), 4u);
  75. BOOST_CHECK_EQUAL(*result.begin(), 1);
  76. BOOST_CHECK_EQUAL(*++result.begin(), 23);
  77. BOOST_CHECK_EQUAL(*++++result.begin(), 456);
  78. BOOST_CHECK_EQUAL(*++++++result.begin(), 7890);
  79. }
  80. }
  81. ///////////////////////////////////////////////////////////////////////////////
  82. // test4
  83. // build a map of strings to integers
  84. void test4()
  85. {
  86. using namespace boost::xpressive;
  87. std::map<std::string, int> result;
  88. std::string str("aaa=>1 bbb=>23 ccc=>456");
  89. sregex pair = ( (s1= +_w) >> "=>" >> (s2= +_d) )[ xp::ref(result)[s1] = as<int>(s2) ];
  90. sregex rx = pair >> *(+_s >> pair);
  91. if(!regex_match(str, rx))
  92. {
  93. BOOST_ERROR("oops");
  94. }
  95. else
  96. {
  97. BOOST_REQUIRE_EQUAL(result.size(), 3u);
  98. BOOST_CHECK_EQUAL(result["aaa"], 1);
  99. BOOST_CHECK_EQUAL(result["bbb"], 23);
  100. BOOST_CHECK_EQUAL(result["ccc"], 456);
  101. }
  102. }
  103. ///////////////////////////////////////////////////////////////////////////////
  104. // test4_aux
  105. // build a map of strings to integers, with a late-bound action argument.
  106. void test4_aux()
  107. {
  108. using namespace boost::xpressive;
  109. placeholder< std::map<std::string, int> > const _map = {{}};
  110. sregex pair = ( (s1= +_w) >> "=>" >> (s2= +_d) )[ _map[s1] = as<int>(s2) ];
  111. sregex rx = pair >> *(+_s >> pair);
  112. std::string str("aaa=>1 bbb=>23 ccc=>456");
  113. smatch what;
  114. std::map<std::string, int> result;
  115. what.let(_map = result); // bind the argument!
  116. BOOST_REQUIRE(regex_match(str, what, rx));
  117. BOOST_REQUIRE_EQUAL(result.size(), 3u);
  118. BOOST_CHECK_EQUAL(result["aaa"], 1);
  119. BOOST_CHECK_EQUAL(result["bbb"], 23);
  120. BOOST_CHECK_EQUAL(result["ccc"], 456);
  121. // Try the same test with regex_iterator
  122. result.clear();
  123. sregex_iterator it(str.begin(), str.end(), pair, let(_map=result)), end;
  124. BOOST_REQUIRE_EQUAL(3, std::distance(it, end));
  125. BOOST_REQUIRE_EQUAL(result.size(), 3u);
  126. BOOST_CHECK_EQUAL(result["aaa"], 1);
  127. BOOST_CHECK_EQUAL(result["bbb"], 23);
  128. BOOST_CHECK_EQUAL(result["ccc"], 456);
  129. // Try the same test with regex_token_iterator
  130. result.clear();
  131. sregex_token_iterator it2(str.begin(), str.end(), pair, (s1,s2), let(_map=result)), end2;
  132. BOOST_REQUIRE_EQUAL(6, std::distance(it2, end2));
  133. BOOST_REQUIRE_EQUAL(result.size(), 3u);
  134. BOOST_CHECK_EQUAL(result["aaa"], 1);
  135. BOOST_CHECK_EQUAL(result["bbb"], 23);
  136. BOOST_CHECK_EQUAL(result["ccc"], 456);
  137. }
  138. ///////////////////////////////////////////////////////////////////////////////
  139. // test5
  140. // calculator that calculates. This is just silly, but hey.
  141. void test5()
  142. {
  143. using namespace boost::xpressive;
  144. // test for "local" variables.
  145. local<int> left, right;
  146. // test for reference<> to an existing variable
  147. std::stack<int> stack_;
  148. reference<std::stack<int> > stack(stack_);
  149. std::string str("4+5*(3-1)");
  150. sregex group, factor, term, expression;
  151. group = '(' >> by_ref(expression) >> ')';
  152. factor = (+_d)[ push(stack, as<int>(_)) ] | group;
  153. term = factor >> *(
  154. ('*' >> factor)
  155. [ right = top(stack)
  156. , pop(stack)
  157. , left = top(stack)
  158. , pop(stack)
  159. , push(stack, left * right)
  160. ]
  161. | ('/' >> factor)
  162. [ right = top(stack)
  163. , pop(stack)
  164. , left = top(stack)
  165. , pop(stack)
  166. , push(stack, left / right)
  167. ]
  168. );
  169. expression = term >> *(
  170. ('+' >> term)
  171. [ right = top(stack)
  172. , pop(stack)
  173. , left = top(stack)
  174. , pop(stack)
  175. , push(stack, left + right)
  176. ]
  177. | ('-' >> term)
  178. [ right = top(stack)
  179. , pop(stack)
  180. , left = top(stack)
  181. , pop(stack)
  182. , push(stack, left - right)
  183. ]
  184. );
  185. if(!regex_match(str, expression))
  186. {
  187. BOOST_ERROR("oops");
  188. }
  189. else
  190. {
  191. BOOST_REQUIRE_EQUAL(stack_.size(), 1u);
  192. BOOST_CHECK_EQUAL(stack_.top(), 14);
  193. BOOST_REQUIRE_EQUAL(stack.get().size(), 1u);
  194. BOOST_CHECK_EQUAL(stack.get().top(), 14);
  195. }
  196. }
  197. ///////////////////////////////////////////////////////////////////////////////
  198. // test6
  199. // Test as<>() with wide strings. Bug #4496.
  200. void test6()
  201. {
  202. using namespace boost::xpressive;
  203. std::wstring version(L"0.9.500");
  204. local<int> maj1(0), min1(0), build1(0);
  205. wsregex re1 = (+_d)[maj1 = as<int>(_)] >> L"." >>
  206. (+_d)[min1 = as<int>(_)] >> L"." >>
  207. (+_d)[build1 = as<int>(_)];
  208. BOOST_REQUIRE(regex_match(version, re1));
  209. BOOST_CHECK_EQUAL(maj1.get(), 0);
  210. BOOST_CHECK_EQUAL(min1.get(), 9);
  211. BOOST_CHECK_EQUAL(build1.get(), 500);
  212. }
  213. ///////////////////////////////////////////////////////////////////////////////
  214. // test7
  215. // Test regex_replace with an xpressive lambda
  216. void test7()
  217. {
  218. namespace xp = boost::xpressive;
  219. using namespace xp;
  220. std::map<std::string, std::string> env;
  221. env["XXX"] = "!!!";
  222. env["YYY"] = "???";
  223. std::string text("This is a %XXX% string %YYY% and stuff.");
  224. sregex var = '%' >> (s1 = +_w) >> '%';
  225. text = regex_replace(text, var, xp::ref(env)[s1]);
  226. BOOST_CHECK_EQUAL(text, "This is a !!! string ??? and stuff.");
  227. }
  228. using namespace boost::unit_test;
  229. ///////////////////////////////////////////////////////////////////////////////
  230. // init_unit_test_suite
  231. //
  232. test_suite* init_unit_test_suite( int argc, char* argv[] )
  233. {
  234. test_suite *test = BOOST_TEST_SUITE("test_actions");
  235. test->add(BOOST_TEST_CASE(&test1));
  236. test->add(BOOST_TEST_CASE(&test2));
  237. test->add(BOOST_TEST_CASE(&test3));
  238. test->add(BOOST_TEST_CASE(&test4));
  239. test->add(BOOST_TEST_CASE(&test4_aux));
  240. test->add(BOOST_TEST_CASE(&test5));
  241. test->add(BOOST_TEST_CASE(&test6));
  242. test->add(BOOST_TEST_CASE(&test7));
  243. return test;
  244. }