make_expr.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // proto::make_expr.hpp
  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. #include <sstream>
  8. #include <boost/proto/core.hpp>
  9. #include <boost/proto/transform.hpp>
  10. #include <boost/utility/addressof.hpp>
  11. #include <boost/fusion/tuple.hpp>
  12. #include <boost/test/unit_test.hpp>
  13. namespace fusion = boost::fusion;
  14. namespace proto = boost::proto;
  15. template<typename E> struct ewrap;
  16. struct mydomain
  17. : proto::domain<proto::generator<ewrap> >
  18. {};
  19. template<typename E> struct ewrap
  20. : proto::extends<E, ewrap<E>, mydomain>
  21. {
  22. explicit ewrap(E const &e = E())
  23. : proto::extends<E, ewrap<E>, mydomain>(e)
  24. {}
  25. };
  26. void test_make_expr()
  27. {
  28. int i = 42;
  29. proto::terminal<int>::type t1 = proto::make_expr<proto::tag::terminal>(1);
  30. proto::terminal<int>::type t2 = proto::make_expr<proto::tag::terminal>(i);
  31. proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(1);
  32. proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(i);
  33. BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
  34. typedef
  35. ewrap<
  36. proto::basic_expr<
  37. proto::tag::unary_plus
  38. , proto::list1<
  39. ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
  40. >
  41. >
  42. >
  43. p3_type;
  44. p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(i);
  45. BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
  46. typedef
  47. ewrap<
  48. proto::basic_expr<
  49. proto::tag::plus
  50. , proto::list2<
  51. p3_type
  52. , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
  53. >
  54. >
  55. >
  56. p4_type;
  57. p4_type p4 = proto::make_expr<proto::tag::plus>(p3, 0);
  58. BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
  59. }
  60. void test_make_expr_ref()
  61. {
  62. int i = 42;
  63. int const ci = 84;
  64. proto::terminal<int const &>::type t1 = proto::make_expr<proto::tag::terminal>(boost::cref(ci));
  65. proto::terminal<int &>::type t2 = proto::make_expr<proto::tag::terminal>(boost::ref(i));
  66. BOOST_CHECK_EQUAL(&i, &proto::value(t2));
  67. proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(boost::cref(ci));
  68. proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(boost::ref(i));
  69. BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
  70. typedef
  71. ewrap<
  72. proto::basic_expr<
  73. proto::tag::unary_plus
  74. , proto::list1<
  75. ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
  76. >
  77. >
  78. >
  79. p3_type;
  80. p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(boost::ref(i));
  81. BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
  82. typedef
  83. ewrap<
  84. proto::basic_expr<
  85. proto::tag::plus
  86. , proto::list2<
  87. p3_type &
  88. , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
  89. >
  90. >
  91. >
  92. p4_type;
  93. p4_type p4 = proto::make_expr<proto::tag::plus>(boost::ref(p3), 0);
  94. BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
  95. }
  96. void test_make_expr_functional()
  97. {
  98. int i = 42;
  99. proto::terminal<int>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(1);
  100. proto::terminal<int>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(i);
  101. proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(1);
  102. proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(i);
  103. BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
  104. typedef
  105. ewrap<
  106. proto::basic_expr<
  107. proto::tag::unary_plus
  108. , proto::list1<
  109. ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
  110. >
  111. >
  112. >
  113. p3_type;
  114. p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(i);
  115. BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
  116. typedef
  117. ewrap<
  118. proto::basic_expr<
  119. proto::tag::plus
  120. , proto::list2<
  121. p3_type
  122. , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
  123. >
  124. >
  125. >
  126. p4_type;
  127. p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(p3, 0);
  128. }
  129. void test_make_expr_functional_ref()
  130. {
  131. int i = 42;
  132. int const ci = 84;
  133. proto::terminal<int const &>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(boost::cref(ci));
  134. proto::terminal<int &>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(boost::ref(i));
  135. BOOST_CHECK_EQUAL(&i, &proto::value(t2));
  136. proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::cref(ci));
  137. proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::ref(i));
  138. BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
  139. typedef
  140. ewrap<
  141. proto::basic_expr<
  142. proto::tag::unary_plus
  143. , proto::list1<
  144. ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
  145. >
  146. >
  147. >
  148. p3_type;
  149. p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(boost::ref(i));
  150. BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
  151. typedef
  152. ewrap<
  153. proto::basic_expr<
  154. proto::tag::plus
  155. , proto::list2<
  156. p3_type &
  157. , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
  158. >
  159. >
  160. >
  161. p4_type;
  162. p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(boost::ref(p3), 0);
  163. BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
  164. }
  165. void test_unpack_expr()
  166. {
  167. int i = 42;
  168. proto::terminal<int>::type t1 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(1));
  169. proto::terminal<int &>::type t2 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(boost::ref(i)));
  170. proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(1));
  171. proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(boost::ref(i)));
  172. BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
  173. typedef
  174. ewrap<
  175. proto::basic_expr<
  176. proto::tag::unary_plus
  177. , proto::list1<
  178. ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
  179. >
  180. >
  181. >
  182. p3_type;
  183. p3_type p3 = proto::unpack_expr<proto::tag::unary_plus, mydomain>(fusion::make_tuple(boost::ref(i)));
  184. BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
  185. typedef
  186. ewrap<
  187. proto::basic_expr<
  188. proto::tag::plus
  189. , proto::list2<
  190. p3_type &
  191. , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
  192. >
  193. >
  194. >
  195. p4_type;
  196. p4_type p4 = proto::unpack_expr<proto::tag::plus>(fusion::make_tuple(boost::ref(p3), 0));
  197. BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
  198. }
  199. void test_unpack_expr_functional()
  200. {
  201. int i = 42;
  202. proto::terminal<int>::type t1 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(1));
  203. proto::terminal<int &>::type t2 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(boost::ref(i)));
  204. proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(1));
  205. proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(boost::ref(i)));
  206. BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
  207. typedef
  208. ewrap<
  209. proto::basic_expr<
  210. proto::tag::unary_plus
  211. , proto::list1<
  212. ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
  213. >
  214. >
  215. >
  216. p3_type;
  217. p3_type p3 = proto::functional::unpack_expr<proto::tag::unary_plus, mydomain>()(fusion::make_tuple(boost::ref(i)));
  218. BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
  219. typedef
  220. ewrap<
  221. proto::basic_expr<
  222. proto::tag::plus
  223. , proto::list2<
  224. p3_type &
  225. , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
  226. >
  227. >
  228. >
  229. p4_type;
  230. p4_type p4 = proto::functional::unpack_expr<proto::tag::plus>()(fusion::make_tuple(boost::ref(p3), 0));
  231. BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
  232. }
  233. #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
  234. #define _byref(x) call<proto::_byref(x)>
  235. #define _byval(x) call<proto::_byval(x)>
  236. #define Minus(x) proto::call<Minus(x)>
  237. #endif
  238. // Turn all terminals held by reference into ones held by value
  239. struct ByVal
  240. : proto::or_<
  241. proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byval(proto::_value))>
  242. , proto::when<proto::nary_expr<proto::_, proto::vararg<ByVal> > >
  243. >
  244. {};
  245. // Turn all terminals held by value into ones held by reference (not safe in general)
  246. struct ByRef
  247. : proto::or_<
  248. proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byref(proto::_value))>
  249. , proto::when<proto::nary_expr<proto::_, proto::vararg<ByRef> > >
  250. >
  251. {};
  252. // turn all proto::plus nodes to minus nodes:
  253. struct Minus
  254. : proto::or_<
  255. proto::when<proto::terminal<proto::_> >
  256. , proto::when<proto::plus<Minus, Minus>, proto::_make_minus(Minus(proto::_left), Minus(proto::_right)) >
  257. >
  258. {};
  259. struct Square
  260. : proto::or_<
  261. // Not creating new proto::terminal nodes here,
  262. // so hold the existing terminals by reference:
  263. proto::when<proto::terminal<proto::_>, proto::_make_multiplies(proto::_, proto::_)>
  264. , proto::when<proto::plus<Square, Square> >
  265. >
  266. {};
  267. #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
  268. #undef _byref
  269. #undef _byval
  270. #undef Minus
  271. #endif
  272. void test_make_expr_transform()
  273. {
  274. proto::plus<
  275. proto::terminal<int>::type
  276. , proto::terminal<int>::type
  277. >::type t1 = ByVal()(proto::as_expr(1) + 1);
  278. proto::plus<
  279. proto::terminal<int const &>::type
  280. , proto::terminal<int const &>::type
  281. >::type t2 = ByRef()(proto::as_expr(1) + 1);
  282. proto::minus<
  283. proto::terminal<int>::type const &
  284. , proto::terminal<int const &>::type const &
  285. >::type t3 = Minus()(proto::as_expr(1) + 1);
  286. proto::plus<
  287. proto::multiplies<proto::terminal<int>::type const &, proto::terminal<int>::type const &>::type
  288. , proto::multiplies<proto::terminal<int const &>::type const &, proto::terminal<int const &>::type const &>::type
  289. >::type t4 = Square()(proto::as_expr(1) + 1);
  290. }
  291. struct length_impl {};
  292. struct dot_impl {};
  293. proto::terminal<length_impl>::type const length = {{}};
  294. proto::terminal<dot_impl>::type const dot = {{}};
  295. // work around msvc bugs...
  296. #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
  297. #define _byref(a) call<proto::_byref(a)>
  298. #define _byval(a) call<proto::_byval(a)>
  299. #define _child1(a) call<proto::_child1(a)>
  300. #define _make_terminal(a) call<proto::_make_terminal(a)>
  301. #define _make_function(a,b,c) call<proto::_make_function(a,b,c)>
  302. #define dot_impl() proto::make<dot_impl()>
  303. #endif
  304. // convert length(a) < length(b) to dot(a,a) < dot(b,b)
  305. struct Convert
  306. : proto::when<
  307. proto::less<
  308. proto::function<proto::terminal<length_impl>, proto::_>
  309. , proto::function<proto::terminal<length_impl>, proto::_>
  310. >
  311. , proto::_make_less(
  312. proto::_make_function(
  313. proto::_make_terminal(dot_impl())
  314. , proto::_child1(proto::_child0)
  315. , proto::_child1(proto::_child0)
  316. )
  317. , proto::_make_function(
  318. proto::_make_terminal(dot_impl())
  319. , proto::_child1(proto::_child1)
  320. , proto::_child1(proto::_child1)
  321. )
  322. )
  323. >
  324. {};
  325. template<typename Expr>
  326. void test_make_expr_transform2_test(Expr const &expr)
  327. {
  328. void const *addr1 = boost::addressof(proto::child_c<1>(proto::child_c<0>(expr)));
  329. void const *addr2 = boost::addressof(proto::child_c<1>(proto::child_c<0>(Convert()(expr))));
  330. BOOST_CHECK_EQUAL(addr1, addr2);
  331. BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(expr))));
  332. BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(Convert()(expr)))));
  333. }
  334. void test_make_expr_transform2()
  335. {
  336. test_make_expr_transform2_test(length(1) < length(2));
  337. }
  338. #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
  339. #undef _byref
  340. #undef _byval
  341. #undef _child1
  342. #undef _make_terminal
  343. #undef _make_function
  344. #undef dot_impl
  345. #endif
  346. using namespace boost::unit_test;
  347. ///////////////////////////////////////////////////////////////////////////////
  348. // init_unit_test_suite
  349. //
  350. test_suite* init_unit_test_suite( int argc, char* argv[] )
  351. {
  352. test_suite *test = BOOST_TEST_SUITE("test proto::make_expr, proto::unpack_expr and friends");
  353. test->add(BOOST_TEST_CASE(&test_make_expr));
  354. test->add(BOOST_TEST_CASE(&test_make_expr_ref));
  355. test->add(BOOST_TEST_CASE(&test_make_expr_functional));
  356. test->add(BOOST_TEST_CASE(&test_make_expr_functional_ref));
  357. test->add(BOOST_TEST_CASE(&test_unpack_expr));
  358. test->add(BOOST_TEST_CASE(&test_unpack_expr_functional));
  359. test->add(BOOST_TEST_CASE(&test_make_expr_transform));
  360. test->add(BOOST_TEST_CASE(&test_make_expr_transform2));
  361. return test;
  362. }