1/*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
3 Copyright (c) 2001-2011 Hartmut Kaiser
4
5 Distributed under the Boost Software License, Version 1.0. (See accompanying
6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7=============================================================================*/
8#include <boost/spirit/include/qi_alternative.hpp>
9
10#include <boost/spirit/include/qi_operator.hpp>
11#include <boost/spirit/include/qi_char.hpp>
12#include <boost/spirit/include/qi_string.hpp>
13#include <boost/spirit/include/qi_numeric.hpp>
14#include <boost/spirit/include/qi_directive.hpp>
15#include <boost/spirit/include/qi_action.hpp>
16#include <boost/spirit/include/qi_nonterminal.hpp>
17#include <boost/spirit/include/qi_auxiliary.hpp>
18#include <boost/spirit/include/qi_rule.hpp>
19#include <boost/spirit/include/support_argument.hpp>
20#include <boost/phoenix/core.hpp>
21#include <boost/phoenix/operator.hpp>
22#include <boost/fusion/include/adapt_struct.hpp>
23#include <boost/variant.hpp>
24#include <boost/assert.hpp>
25
26#include <string>
27#include <iostream>
28#include <vector>
29#include "test.hpp"
30
31#ifdef _MSC_VER
32// bogus https://developercommunity.visualstudio.com/t/buggy-warning-c4709/471956
33# pragma warning(disable: 4709) // comma operator within array index expression
34#endif
35
36struct test_action
37{
38 test_action(char last)
39 : last_(last) {}
40
41 template<typename Context>
42 void operator()(std::vector<char> const& v, Context const&, bool&) const
43 {
44 BOOST_TEST(v.size() == 4 &&
45 v[0] == 'a' && v[1] == 'b' && v[2] == '1' && v[3] == last_);
46 }
47
48 char last_;
49};
50
51struct test_action_2
52{
53 typedef std::vector<boost::optional<char> > result_type;
54
55 template<typename Context>
56 void operator()(result_type const& v, Context const&, bool&) const
57 {
58 BOOST_TEST(v.size() == 5 &&
59 !v[0] && v[1] == 'a' && v[2] == 'b' && v[3] == '1' && v[4] == '2');
60 }
61};
62
63struct DIgnore
64{
65 std::string text;
66};
67
68struct DInclude
69{
70 std::string FileName;
71};
72
73BOOST_FUSION_ADAPT_STRUCT(
74 DIgnore,
75 (std::string, text)
76)
77
78BOOST_FUSION_ADAPT_STRUCT(
79 DInclude,
80 (std::string, FileName)
81)
82
83int
84main()
85{
86 using spirit_test::test;
87 using spirit_test::test_attr;
88
89 using boost::spirit::ascii::char_;
90 using boost::spirit::qi::int_;
91 using boost::spirit::qi::lit;
92 using boost::spirit::qi::unused_type;
93 using boost::spirit::qi::_1;
94 using boost::spirit::qi::omit;
95
96 {
97 BOOST_TEST((test("a", char_ | char_)));
98 BOOST_TEST((test("x", lit('x') | lit('i'))));
99 BOOST_TEST((test("i", lit('x') | lit('i'))));
100 BOOST_TEST((!test("z", lit('x') | lit('o'))));
101 BOOST_TEST((test("rock", lit("rock") | lit("roll"))));
102 BOOST_TEST((test("roll", lit("rock") | lit("roll"))));
103 BOOST_TEST((test("rock", lit("rock") | int_)));
104 BOOST_TEST((test("12345", lit("rock") | int_)));
105 }
106
107 {
108 boost::variant<unused_type, int, char> v;
109
110 BOOST_TEST((test_attr("12345", lit("rock") | int_ | char_, v)));
111 BOOST_TEST(boost::get<int>(v) == 12345);
112
113 BOOST_TEST((test_attr("rock", lit("rock") | int_ | char_, v)));
114 BOOST_TEST(v.which() == 1);
115
116 BOOST_TEST((test_attr("x", lit("rock") | int_ | char_, v)));
117 BOOST_TEST(boost::get<char>(v) == 'x');
118 }
119
120 { // Make sure that we are using the actual supplied attribute types
121 // from the variant and not the expected type.
122 // $$$ Fixed: <2/19/2011> JDG $$$
123 boost::variant<int, std::string> v;
124 BOOST_TEST((test_attr("12345", int_ | +char_, v)));
125 BOOST_TEST(boost::get<int>(v) == 12345);
126
127 BOOST_TEST((test_attr("abc", int_ | +char_, v)));
128 BOOST_TEST(boost::get<std::string>(v) == "abc");
129
130 BOOST_TEST((test_attr("12345", +char_ | int_, v)));
131 BOOST_TEST(boost::get<std::string>(v) == "12345");
132 }
133
134 { // test action
135
136 namespace phx = boost::phoenix;
137 boost::optional<boost::variant<int, char> > v;
138
139 BOOST_TEST((test("12345", (lit("rock") | int_ | char_)[phx::ref(v) = _1])));
140 BOOST_TEST(boost::get<int>(boost::get(v)) == 12345);
141 BOOST_TEST((test("rock", (lit("rock") | int_ | char_)[phx::ref(v) = _1])));
142 BOOST_TEST(!v);
143 }
144
145 {
146 unused_type x;
147 BOOST_TEST((test_attr("rock", lit("rock") | lit('x'), x)));
148 }
149
150 {
151 // test if alternatives with all components having unused
152 // attributes have an unused attribute
153
154 using boost::fusion::vector;
155 using boost::fusion::at_c;
156
157 vector<char, char> v;
158 BOOST_TEST((test_attr("abc",
159 char_ >> (omit[char_] | omit[char_]) >> char_, v)));
160 BOOST_TEST((at_c<0>(v) == 'a'));
161 BOOST_TEST((at_c<1>(v) == 'c'));
162 }
163
164 {
165 // Test that we can still pass a "compatible" attribute to
166 // an alternate even if its "expected" attribute is unused type.
167
168 std::string s;
169 BOOST_TEST((test_attr("...", *(char_('.') | char_(',')), s)));
170 BOOST_TEST(s == "...");
171 }
172
173 { // make sure collapsing eps works as expected
174 // (compile check only)
175
176 using boost::spirit::qi::rule;
177 using boost::spirit::qi::_val;
178 using boost::spirit::qi::_1;
179 using boost::spirit::eps;
180 rule<const wchar_t*, wchar_t()> r1, r2, r3;
181
182 r3 = ((eps >> r1))[_val += _1];
183 r3 = ((r1 ) | r2)[_val += _1];
184
185 r3 %= ((eps >> r1) | r2);
186 r3 = ((eps >> r1) | r2)[_val += _1];
187 }
188
189 // make sure the attribute of an alternative gets properly collapsed
190 {
191 using boost::spirit::qi::lexeme;
192 using boost::spirit::ascii::alnum;
193 using boost::spirit::ascii::alpha;
194 using boost::spirit::ascii::digit;
195 using boost::spirit::ascii::string;
196 namespace phx = boost::phoenix;
197
198
199 BOOST_TEST( (test("ab1_", (*(alnum | char_('_')))[test_action('_')])) );
200 BOOST_TEST( (test("ab12", (*(alpha | digit))[test_action('2')])) );
201
202 BOOST_TEST( (test("abcab12", (*("abc" | alnum))[test_action_2()])) );
203
204 std::vector<boost::optional<char> > v;
205 BOOST_TEST( (test("x,y,z", (*(',' | char_))[phx::ref(v) = _1])) );
206 BOOST_ASSERT(v[0] == 'x');
207 BOOST_ASSERT(!v[1]);
208 BOOST_ASSERT(v[2] == 'y');
209 BOOST_ASSERT(!v[3]);
210 BOOST_ASSERT(v[4] == 'z');
211 }
212
213 {
214 using boost::spirit::qi::eps;
215
216 // testing a sequence taking a container as attribute
217 std::string s;
218 BOOST_TEST( (test_attr("abc,a,b,c",
219 char_ >> char_ >> (char_ % ','), s )) );
220 BOOST_TEST(s == "abcabc");
221
222 // test having an optional<container> inside a sequence
223 s.erase();
224 BOOST_TEST( (test_attr("ab",
225 char_ >> char_ >> -(char_ % ','), s )) );
226 BOOST_TEST(s == "ab");
227
228 // test having a variant<container, ...> inside a sequence
229 s.erase();
230 BOOST_TEST( (test_attr("ab",
231 char_ >> char_ >> ((char_ % ',') | eps), s )) );
232 BOOST_TEST(s == "ab");
233 s.erase();
234 BOOST_TEST( (test_attr("abc",
235 char_ >> char_ >> ((char_ % ',') | eps), s )) );
236 BOOST_TEST(s == "abc");
237 }
238
239 {
240 using boost::spirit::qi::int_;
241
242 int i = 0;
243 BOOST_TEST( (test_attr("10", int_(5) | int_(10), i)) );
244 BOOST_TEST(i == 10);
245 }
246
247 {
248#ifdef SPIRIT_NO_COMPILE_CHECK
249 //compile test only (bug_march_10_2011_8_35_am)
250 // TODO: does not work as intended with std <= c++03
251 typedef boost::variant<double, std::string> value_type;
252
253 using boost::spirit::qi::rule;
254 using boost::spirit::qi::eps;
255 rule<std::string::const_iterator, value_type()> r1 = r1 | eps;
256#endif
257 }
258
259 {
260 using boost::spirit::qi::rule;
261 typedef boost::variant<DIgnore, DInclude> DLine;
262
263 rule<char*, DIgnore()> ignore;
264 rule<char*, DInclude()> include;
265 rule<char*, DLine()> line = include | ignore;
266 }
267
268 return boost::report_errors();
269}
270
271

source code of boost/libs/spirit/test/qi/alternative.cpp