alternative.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*=============================================================================
  2. Copyright (c) 2001-2011 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/mpl/print.hpp>
  9. #include <boost/spirit/include/qi_operator.hpp>
  10. #include <boost/spirit/include/qi_char.hpp>
  11. #include <boost/spirit/include/qi_string.hpp>
  12. #include <boost/spirit/include/qi_numeric.hpp>
  13. #include <boost/spirit/include/qi_directive.hpp>
  14. #include <boost/spirit/include/qi_action.hpp>
  15. #include <boost/spirit/include/qi_nonterminal.hpp>
  16. #include <boost/spirit/include/qi_auxiliary.hpp>
  17. #include <boost/spirit/include/qi_rule.hpp>
  18. #include <boost/spirit/include/support_argument.hpp>
  19. #include <boost/spirit/include/phoenix_core.hpp>
  20. #include <boost/spirit/include/phoenix_operator.hpp>
  21. #include <boost/fusion/include/adapt_struct.hpp>
  22. #include <boost/variant.hpp>
  23. #include <boost/assert.hpp>
  24. #include <string>
  25. #include <iostream>
  26. #include <vector>
  27. #include "test.hpp"
  28. struct test_action
  29. {
  30. test_action(char last)
  31. : last_(last) {}
  32. template<typename Context>
  33. void operator()(std::vector<char> const& v, Context const&, bool&) const
  34. {
  35. BOOST_TEST(v.size() == 4 &&
  36. v[0] == 'a' && v[1] == 'b' && v[2] == '1' && v[3] == last_);
  37. }
  38. char last_;
  39. };
  40. struct test_action_2
  41. {
  42. typedef std::vector<boost::optional<char> > result_type;
  43. template<typename Context>
  44. void operator()(result_type const& v, Context const&, bool&) const
  45. {
  46. BOOST_TEST(v.size() == 5 &&
  47. !v[0] && v[1] == 'a' && v[2] == 'b' && v[3] == '1' && v[4] == '2');
  48. }
  49. };
  50. struct DIgnore
  51. {
  52. std::string text;
  53. };
  54. struct DInclude
  55. {
  56. std::string FileName;
  57. };
  58. BOOST_FUSION_ADAPT_STRUCT(
  59. DIgnore,
  60. (std::string, text)
  61. )
  62. BOOST_FUSION_ADAPT_STRUCT(
  63. DInclude,
  64. (std::string, FileName)
  65. )
  66. int
  67. main()
  68. {
  69. using spirit_test::test;
  70. using spirit_test::test_attr;
  71. using boost::spirit::ascii::char_;
  72. using boost::spirit::qi::int_;
  73. using boost::spirit::qi::lit;
  74. using boost::spirit::qi::unused_type;
  75. using boost::spirit::qi::_1;
  76. using boost::spirit::qi::omit;
  77. {
  78. BOOST_TEST((test("a", char_ | char_)));
  79. BOOST_TEST((test("x", lit('x') | lit('i'))));
  80. BOOST_TEST((test("i", lit('x') | lit('i'))));
  81. BOOST_TEST((!test("z", lit('x') | lit('o'))));
  82. BOOST_TEST((test("rock", lit("rock") | lit("roll"))));
  83. BOOST_TEST((test("roll", lit("rock") | lit("roll"))));
  84. BOOST_TEST((test("rock", lit("rock") | int_)));
  85. BOOST_TEST((test("12345", lit("rock") | int_)));
  86. }
  87. {
  88. boost::variant<unused_type, int, char> v;
  89. BOOST_TEST((test_attr("12345", lit("rock") | int_ | char_, v)));
  90. BOOST_TEST(boost::get<int>(v) == 12345);
  91. BOOST_TEST((test_attr("rock", lit("rock") | int_ | char_, v)));
  92. BOOST_TEST(v.which() == 1);
  93. BOOST_TEST((test_attr("x", lit("rock") | int_ | char_, v)));
  94. BOOST_TEST(boost::get<char>(v) == 'x');
  95. }
  96. { // Make sure that we are using the actual supplied attribute types
  97. // from the variant and not the expected type.
  98. // $$$ Fixed: <2/19/2011> JDG $$$
  99. boost::variant<int, std::string> v;
  100. BOOST_TEST((test_attr("12345", int_ | +char_, v)));
  101. BOOST_TEST(boost::get<int>(v) == 12345);
  102. BOOST_TEST((test_attr("abc", int_ | +char_, v)));
  103. BOOST_TEST(boost::get<std::string>(v) == "abc");
  104. BOOST_TEST((test_attr("12345", +char_ | int_, v)));
  105. BOOST_TEST(boost::get<std::string>(v) == "12345");
  106. }
  107. { // test action
  108. namespace phx = boost::phoenix;
  109. boost::optional<boost::variant<int, char> > v;
  110. BOOST_TEST((test("12345", (lit("rock") | int_ | char_)[phx::ref(v) = _1])));
  111. BOOST_TEST(boost::get<int>(boost::get(v)) == 12345);
  112. BOOST_TEST((test("rock", (lit("rock") | int_ | char_)[phx::ref(v) = _1])));
  113. BOOST_TEST(!v);
  114. }
  115. {
  116. unused_type x;
  117. BOOST_TEST((test_attr("rock", lit("rock") | lit('x'), x)));
  118. }
  119. {
  120. // test if alternatives with all components having unused
  121. // attributes have an unused attribute
  122. using boost::fusion::vector;
  123. using boost::fusion::at_c;
  124. vector<char, char> v;
  125. BOOST_TEST((test_attr("abc",
  126. char_ >> (omit[char_] | omit[char_]) >> char_, v)));
  127. BOOST_TEST((at_c<0>(v) == 'a'));
  128. BOOST_TEST((at_c<1>(v) == 'c'));
  129. }
  130. {
  131. // Test that we can still pass a "compatible" attribute to
  132. // an alternate even if its "expected" attribute is unused type.
  133. std::string s;
  134. BOOST_TEST((test_attr("...", *(char_('.') | char_(',')), s)));
  135. BOOST_TEST(s == "...");
  136. }
  137. { // make sure collapsing eps works as expected
  138. // (compile check only)
  139. using boost::spirit::qi::rule;
  140. using boost::spirit::qi::_val;
  141. using boost::spirit::qi::_1;
  142. using boost::spirit::eps;
  143. rule<const wchar_t*, wchar_t()> r1, r2, r3;
  144. r3 = ((eps >> r1))[_val += _1];
  145. r3 = ((r1 ) | r2)[_val += _1];
  146. r3 %= ((eps >> r1) | r2);
  147. r3 = ((eps >> r1) | r2)[_val += _1];
  148. }
  149. // make sure the attribute of an alternative gets properly collapsed
  150. {
  151. using boost::spirit::qi::lexeme;
  152. using boost::spirit::ascii::alnum;
  153. using boost::spirit::ascii::alpha;
  154. using boost::spirit::ascii::digit;
  155. using boost::spirit::ascii::string;
  156. namespace phx = boost::phoenix;
  157. BOOST_TEST( (test("ab1_", (*(alnum | char_('_')))[test_action('_')])) );
  158. BOOST_TEST( (test("ab12", (*(alpha | digit))[test_action('2')])) );
  159. BOOST_TEST( (test("abcab12", (*("abc" | alnum))[test_action_2()])) );
  160. std::vector<boost::optional<char> > v;
  161. BOOST_TEST( (test("x,y,z", (*(',' | char_))[phx::ref(v) = _1])) );
  162. BOOST_ASSERT(v[0] == 'x');
  163. BOOST_ASSERT(!v[1]);
  164. BOOST_ASSERT(v[2] == 'y');
  165. BOOST_ASSERT(!v[3]);
  166. BOOST_ASSERT(v[4] == 'z');
  167. }
  168. {
  169. using boost::spirit::qi::eps;
  170. // testing a sequence taking a container as attribute
  171. std::string s;
  172. BOOST_TEST( (test_attr("abc,a,b,c",
  173. char_ >> char_ >> (char_ % ','), s )) );
  174. BOOST_TEST(s == "abcabc");
  175. // test having an optional<container> inside a sequence
  176. s.erase();
  177. BOOST_TEST( (test_attr("ab",
  178. char_ >> char_ >> -(char_ % ','), s )) );
  179. BOOST_TEST(s == "ab");
  180. // test having a variant<container, ...> inside a sequence
  181. s.erase();
  182. BOOST_TEST( (test_attr("ab",
  183. char_ >> char_ >> ((char_ % ',') | eps), s )) );
  184. BOOST_TEST(s == "ab");
  185. s.erase();
  186. BOOST_TEST( (test_attr("abc",
  187. char_ >> char_ >> ((char_ % ',') | eps), s )) );
  188. BOOST_TEST(s == "abc");
  189. }
  190. {
  191. using boost::spirit::qi::int_;
  192. int i = 0;
  193. BOOST_TEST( (test_attr("10", int_(5) | int_(10), i)) );
  194. BOOST_TEST(i == 10);
  195. }
  196. {
  197. #ifdef SPIRIT_NO_COMPILE_CHECK
  198. //compile test only (bug_march_10_2011_8_35_am)
  199. // TODO: does not work as intended with std <= c++03
  200. typedef boost::variant<double, std::string> value_type;
  201. using boost::spirit::qi::rule;
  202. using boost::spirit::qi::eps;
  203. rule<std::string::const_iterator, value_type()> r1 = r1 | eps;
  204. #endif
  205. }
  206. {
  207. using boost::spirit::qi::rule;
  208. typedef boost::variant<DIgnore, DInclude> DLine;
  209. rule<char*, DIgnore()> ignore;
  210. rule<char*, DInclude()> include;
  211. rule<char*, DLine()> line = include | ignore;
  212. }
  213. return boost::report_errors();
  214. }