alternative.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /*=============================================================================
  2. Copyright (c) 2001-2015 Joel de Guzman
  3. Copyright (c) 2001-2011 Hartmut Kaiser
  4. Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. =============================================================================*/
  7. #include <boost/detail/lightweight_test.hpp>
  8. #include <boost/spirit/home/x3.hpp>
  9. #include <boost/fusion/include/adapt_struct.hpp>
  10. #include <boost/variant.hpp>
  11. #include <boost/fusion/include/vector.hpp>
  12. #include <boost/fusion/include/at.hpp>
  13. #include <string>
  14. #include <iostream>
  15. #include <vector>
  16. #include "test.hpp"
  17. struct di_ignore
  18. {
  19. std::string text;
  20. };
  21. struct di_include
  22. {
  23. std::string FileName;
  24. };
  25. BOOST_FUSION_ADAPT_STRUCT(di_ignore,
  26. text
  27. )
  28. BOOST_FUSION_ADAPT_STRUCT(di_include,
  29. FileName
  30. )
  31. struct undefined {};
  32. struct stationary : boost::noncopyable
  33. {
  34. explicit stationary(int i) : val{i} {}
  35. // TODO: fix unneeded self move in alternative
  36. stationary& operator=(stationary&&) { std::abort(); }
  37. stationary& operator=(int i) { val = i; return *this; }
  38. int val;
  39. };
  40. int
  41. main()
  42. {
  43. using spirit_test::test;
  44. using spirit_test::test_attr;
  45. using boost::spirit::x3::attr;
  46. using boost::spirit::x3::char_;
  47. using boost::spirit::x3::int_;
  48. using boost::spirit::x3::lit;
  49. using boost::spirit::x3::unused_type;
  50. using boost::spirit::x3::unused;
  51. using boost::spirit::x3::omit;
  52. using boost::spirit::x3::eps;
  53. {
  54. BOOST_TEST((test("a", char_ | char_)));
  55. BOOST_TEST((test("x", lit('x') | lit('i'))));
  56. BOOST_TEST((test("i", lit('x') | lit('i'))));
  57. BOOST_TEST((!test("z", lit('x') | lit('o'))));
  58. BOOST_TEST((test("rock", lit("rock") | lit("roll"))));
  59. BOOST_TEST((test("roll", lit("rock") | lit("roll"))));
  60. BOOST_TEST((test("rock", lit("rock") | int_)));
  61. BOOST_TEST((test("12345", lit("rock") | int_)));
  62. }
  63. {
  64. typedef boost::variant<undefined, int, char> attr_type;
  65. attr_type v;
  66. BOOST_TEST((test_attr("12345", int_ | char_, v)));
  67. BOOST_TEST(boost::get<int>(v) == 12345);
  68. BOOST_TEST((test_attr("12345", lit("rock") | int_ | char_, v)));
  69. BOOST_TEST(boost::get<int>(v) == 12345);
  70. v = attr_type();
  71. BOOST_TEST((test_attr("rock", lit("rock") | int_ | char_, v)));
  72. BOOST_TEST(v.which() == 0);
  73. BOOST_TEST((test_attr("x", lit("rock") | int_ | char_, v)));
  74. BOOST_TEST(boost::get<char>(v) == 'x');
  75. }
  76. { // Make sure that we are using the actual supplied attribute types
  77. // from the variant and not the expected type.
  78. boost::variant<int, std::string> v;
  79. BOOST_TEST((test_attr("12345", int_ | +char_, v)));
  80. BOOST_TEST(boost::get<int>(v) == 12345);
  81. BOOST_TEST((test_attr("abc", int_ | +char_, v)));
  82. BOOST_TEST(boost::get<std::string>(v) == "abc");
  83. BOOST_TEST((test_attr("12345", +char_ | int_, v)));
  84. BOOST_TEST(boost::get<std::string>(v) == "12345");
  85. }
  86. {
  87. unused_type x;
  88. BOOST_TEST((test_attr("rock", lit("rock") | lit('x'), x)));
  89. }
  90. {
  91. // test if alternatives with all components having unused
  92. // attributes have an unused attribute
  93. using boost::fusion::vector;
  94. using boost::fusion::at_c;
  95. vector<char, char> v;
  96. BOOST_TEST((test_attr("abc",
  97. char_ >> (omit[char_] | omit[char_]) >> char_, v)));
  98. BOOST_TEST((at_c<0>(v) == 'a'));
  99. BOOST_TEST((at_c<1>(v) == 'c'));
  100. }
  101. {
  102. // Test that we can still pass a "compatible" attribute to
  103. // an alternate even if its "expected" attribute is unused type.
  104. std::string s;
  105. BOOST_TEST((test_attr("...", *(char_('.') | char_(',')), s)));
  106. BOOST_TEST(s == "...");
  107. }
  108. { // make sure collapsing eps works as expected
  109. // (compile check only)
  110. using boost::spirit::x3::rule;
  111. using boost::spirit::x3::eps;
  112. using boost::spirit::x3::_attr;
  113. using boost::spirit::x3::_val;
  114. rule<class r1, wchar_t> r1;
  115. rule<class r2, wchar_t> r2;
  116. rule<class r3, wchar_t> r3;
  117. auto f = [&](auto& ctx){ _val(ctx) = _attr(ctx); };
  118. r3 = ((eps >> r1))[f];
  119. r3 = ((r1) | r2)[f];
  120. r3 = ((eps >> r1) | r2);
  121. }
  122. {
  123. std::string s;
  124. using boost::spirit::x3::eps;
  125. // test having a variant<container, ...>
  126. BOOST_TEST( (test_attr("a,b", (char_ % ',') | eps, s )) );
  127. BOOST_TEST(s == "ab");
  128. }
  129. {
  130. using boost::spirit::x3::eps;
  131. // testing a sequence taking a container as attribute
  132. std::string s;
  133. BOOST_TEST( (test_attr("abc,a,b,c",
  134. char_ >> char_ >> (char_ % ','), s )) );
  135. BOOST_TEST(s == "abcabc");
  136. // test having an optional<container> inside a sequence
  137. s.erase();
  138. BOOST_TEST( (test_attr("ab",
  139. char_ >> char_ >> -(char_ % ','), s )) );
  140. BOOST_TEST(s == "ab");
  141. // test having a variant<container, ...> inside a sequence
  142. s.erase();
  143. BOOST_TEST( (test_attr("ab",
  144. char_ >> char_ >> ((char_ % ',') | eps), s )) );
  145. BOOST_TEST(s == "ab");
  146. s.erase();
  147. BOOST_TEST( (test_attr("abc",
  148. char_ >> char_ >> ((char_ % ',') | eps), s )) );
  149. BOOST_TEST(s == "abc");
  150. }
  151. {
  152. //compile test only (bug_march_10_2011_8_35_am)
  153. typedef boost::variant<double, std::string> value_type;
  154. using boost::spirit::x3::rule;
  155. using boost::spirit::x3::eps;
  156. rule<class r1, value_type> r1;
  157. auto r1_ = r1 = r1 | eps; // left recursive!
  158. unused = r1_; // silence unused local warning
  159. }
  160. {
  161. using boost::spirit::x3::rule;
  162. typedef boost::variant<di_ignore, di_include> d_line;
  163. rule<class ignore, di_ignore> ignore;
  164. rule<class include, di_include> include;
  165. rule<class line, d_line> line;
  166. auto start =
  167. line = include | ignore;
  168. unused = start; // silence unused local warning
  169. }
  170. // single-element fusion vector tests
  171. {
  172. boost::fusion::vector<boost::variant<int, std::string>> fv;
  173. BOOST_TEST((test_attr("12345", int_ | +char_, fv)));
  174. BOOST_TEST(boost::get<int>(boost::fusion::at_c<0>(fv)) == 12345);
  175. boost::fusion::vector<boost::variant<int, std::string>> fvi;
  176. BOOST_TEST((test_attr("12345", int_ | int_, fvi)));
  177. BOOST_TEST(boost::get<int>(boost::fusion::at_c<0>(fvi)) == 12345);
  178. }
  179. // alternative over single element sequences as part of another sequence
  180. {
  181. auto key1 = lit("long") >> attr(long());
  182. auto key2 = lit("char") >> attr(char());
  183. auto keys = key1 | key2;
  184. auto pair = keys >> lit("=") >> +char_;
  185. boost::fusion::deque<boost::variant<long, char>, std::string> attr_;
  186. BOOST_TEST(test_attr("long=ABC", pair, attr_));
  187. BOOST_TEST(boost::get<long>(&boost::fusion::front(attr_)) != nullptr);
  188. BOOST_TEST(boost::get<char>(&boost::fusion::front(attr_)) == nullptr);
  189. }
  190. { // ensure no unneded synthesization, copying and moving occured
  191. auto p = '{' >> int_ >> '}';
  192. stationary st { 0 };
  193. BOOST_TEST(test_attr("{42}", p | eps | p, st));
  194. BOOST_TEST_EQ(st.val, 42);
  195. }
  196. return boost::report_errors();
  197. }