• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2015 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/detail/lightweight_test.hpp>
9 #include <boost/spirit/home/x3.hpp>
10 #include <boost/fusion/include/adapt_struct.hpp>
11 #include <boost/variant.hpp>
12 #include <boost/fusion/include/vector.hpp>
13 #include <boost/fusion/include/at.hpp>
14 
15 #include <string>
16 #include <iostream>
17 #include <vector>
18 #include "test.hpp"
19 
20 struct di_ignore
21 {
22     std::string text;
23 };
24 
25 struct di_include
26 {
27     std::string FileName;
28 };
29 
30 BOOST_FUSION_ADAPT_STRUCT(di_ignore,
31     text
32 )
33 
34 BOOST_FUSION_ADAPT_STRUCT(di_include,
35     FileName
36 )
37 
38 struct undefined {};
39 
40 
41 struct stationary : boost::noncopyable
42 {
stationarystationary43     explicit stationary(int i) : val{i} {}
operator =stationary44     stationary& operator=(int i) { val = i; return *this; }
45 
46     int val;
47 };
48 
49 
50 int
main()51 main()
52 {
53     using spirit_test::test;
54     using spirit_test::test_attr;
55 
56     using boost::spirit::x3::attr;
57     using boost::spirit::x3::char_;
58     using boost::spirit::x3::int_;
59     using boost::spirit::x3::lit;
60     using boost::spirit::x3::unused_type;
61     using boost::spirit::x3::unused;
62     using boost::spirit::x3::omit;
63     using boost::spirit::x3::eps;
64 
65     BOOST_SPIRIT_ASSERT_CONSTEXPR_CTORS(char_ | char_);
66 
67     {
68         BOOST_TEST((test("a", char_ | char_)));
69         BOOST_TEST((test("x", lit('x') | lit('i'))));
70         BOOST_TEST((test("i", lit('x') | lit('i'))));
71         BOOST_TEST((!test("z", lit('x') | lit('o'))));
72         BOOST_TEST((test("rock", lit("rock") | lit("roll"))));
73         BOOST_TEST((test("roll", lit("rock") | lit("roll"))));
74         BOOST_TEST((test("rock", lit("rock") | int_)));
75         BOOST_TEST((test("12345", lit("rock") | int_)));
76     }
77 
78     {
79         typedef boost::variant<undefined, int, char> attr_type;
80         attr_type v;
81 
82         BOOST_TEST((test_attr("12345", int_ | char_, v)));
83         BOOST_TEST(boost::get<int>(v) == 12345);
84 
85         BOOST_TEST((test_attr("12345", lit("rock") | int_ | char_, v)));
86         BOOST_TEST(boost::get<int>(v) == 12345);
87 
88         v = attr_type();
89         BOOST_TEST((test_attr("rock", lit("rock") | int_ | char_, v)));
90         BOOST_TEST(v.which() == 0);
91 
92         BOOST_TEST((test_attr("x", lit("rock") | int_ | char_, v)));
93         BOOST_TEST(boost::get<char>(v) == 'x');
94     }
95 
96     {   // Make sure that we are using the actual supplied attribute types
97         // from the variant and not the expected type.
98         boost::variant<int, std::string> v;
99         BOOST_TEST((test_attr("12345", int_ | +char_, v)));
100         BOOST_TEST(boost::get<int>(v) == 12345);
101 
102         BOOST_TEST((test_attr("abc", int_ | +char_, v)));
103         BOOST_TEST(boost::get<std::string>(v) == "abc");
104 
105         BOOST_TEST((test_attr("12345", +char_ | int_, v)));
106         BOOST_TEST(boost::get<std::string>(v) == "12345");
107     }
108 
109     {
110         unused_type x;
111         BOOST_TEST((test_attr("rock", lit("rock") | lit('x'), x)));
112     }
113 
114     {
115         // test if alternatives with all components having unused
116         // attributes have an unused attribute
117 
118         using boost::fusion::vector;
119         using boost::fusion::at_c;
120 
121         vector<char, char> v;
122         BOOST_TEST((test_attr("abc",
123             char_ >> (omit[char_] | omit[char_]) >> char_, v)));
124         BOOST_TEST((at_c<0>(v) == 'a'));
125         BOOST_TEST((at_c<1>(v) == 'c'));
126     }
127 
128     {
129         // Test that we can still pass a "compatible" attribute to
130         // an alternate even if its "expected" attribute is unused type.
131 
132         std::string s;
133         BOOST_TEST((test_attr("...", *(char_('.') | char_(',')), s)));
134         BOOST_TEST(s == "...");
135     }
136 
137     {   // make sure collapsing eps works as expected
138         // (compile check only)
139 
140         using boost::spirit::x3::rule;
141         using boost::spirit::x3::eps;
142         using boost::spirit::x3::_attr;
143         using boost::spirit::x3::_val;
144 
145         rule<class r1, wchar_t> r1;
146         rule<class r2, wchar_t> r2;
147         rule<class r3, wchar_t> r3;
148 
149         auto f = [&](auto& ctx){ _val(ctx) = _attr(ctx); };
150 
151         r3  = ((eps >> r1))[f];
152         r3  = ((r1) | r2)[f];
153         r3 = ((eps >> r1) | r2);
154     }
155 
156     {
157         std::string s;
158         using boost::spirit::x3::eps;
159 
160         // test having a variant<container, ...>
161         BOOST_TEST( (test_attr("a,b", (char_ % ',') | eps, s )) );
162         BOOST_TEST(s == "ab");
163     }
164 
165     {
166         using boost::spirit::x3::eps;
167 
168         // testing a sequence taking a container as attribute
169         std::string s;
170         BOOST_TEST( (test_attr("abc,a,b,c",
171             char_ >> char_ >> (char_ % ','), s )) );
172         BOOST_TEST(s == "abcabc");
173 
174         // test having an optional<container> inside a sequence
175         s.erase();
176         BOOST_TEST( (test_attr("ab",
177             char_ >> char_ >> -(char_ % ','), s )) );
178         BOOST_TEST(s == "ab");
179 
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     {
192         //compile test only (bug_march_10_2011_8_35_am)
193         typedef boost::variant<double, std::string> value_type;
194 
195         using boost::spirit::x3::rule;
196         using boost::spirit::x3::eps;
197 
198         rule<class r1, value_type> r1;
199         auto r1_ = r1 = r1 | eps; // left recursive!
200 
201         unused = r1_; // silence unused local warning
202     }
203 
204     {
205         using boost::spirit::x3::rule;
206         typedef boost::variant<di_ignore, di_include> d_line;
207 
208         rule<class ignore, di_ignore> ignore;
209         rule<class include, di_include> include;
210         rule<class line, d_line> line;
211 
212         auto start =
213             line = include | ignore;
214 
215         unused = start; // silence unused local warning
216     }
217 
218     // single-element fusion vector tests
219     {
220         boost::fusion::vector<boost::variant<int, std::string>> fv;
221         BOOST_TEST((test_attr("12345", int_ | +char_, fv)));
222         BOOST_TEST(boost::get<int>(boost::fusion::at_c<0>(fv)) == 12345);
223 
224         boost::fusion::vector<boost::variant<int, std::string>> fvi;
225         BOOST_TEST((test_attr("12345", int_ | int_, fvi)));
226         BOOST_TEST(boost::get<int>(boost::fusion::at_c<0>(fvi)) == 12345);
227     }
228 
229     // alternative over single element sequences as part of another sequence
230     {
231         auto  key1 = lit("long") >> attr(long());
232         auto  key2 = lit("char") >> attr(char());
233         auto  keys = key1 | key2;
234         auto pair = keys >> lit("=") >> +char_;
235 
236         boost::fusion::deque<boost::variant<long, char>, std::string> attr_;
237 
238         BOOST_TEST(test_attr("long=ABC", pair, attr_));
239         BOOST_TEST(boost::get<long>(&boost::fusion::front(attr_)) != nullptr);
240         BOOST_TEST(boost::get<char>(&boost::fusion::front(attr_)) == nullptr);
241     }
242 
243     { // ensure no unneeded synthesization, copying and moving occurred
244         auto p = '{' >> int_ >> '}';
245 
246         stationary st { 0 };
247         BOOST_TEST(test_attr("{42}", p | eps | p, st));
248         BOOST_TEST_EQ(st.val, 42);
249     }
250 
251     { // attributeless parsers must not insert values
252         std::vector<int> v;
253         BOOST_TEST(test_attr("1 2 3 - 5 - - 7 -", (int_ | '-') % ' ', v));
254         BOOST_TEST_EQ(v.size(), 5)
255             && BOOST_TEST_EQ(v[0], 1)
256             && BOOST_TEST_EQ(v[1], 2)
257             && BOOST_TEST_EQ(v[2], 3)
258             && BOOST_TEST_EQ(v[3], 5)
259             && BOOST_TEST_EQ(v[4], 7)
260             ;
261     }
262 
263     { // regressing test for #603
264         using boost::spirit::x3::attr;
265         struct X {};
266         std::vector<boost::variant<std::string, int, X>> v;
267         BOOST_TEST(test_attr("xx42x9y", *(int_ | +char_('x') | 'y' >> attr(X{})), v));
268         BOOST_TEST_EQ(v.size(), 5);
269     }
270 
271     { // sequence parser in alternative into container
272         std::string s;
273         BOOST_TEST(test_attr("abcbbcd",
274             *(char_('a') >> *(*char_('b') >> char_('c')) | char_('d')), s));
275         BOOST_TEST_EQ(s, "abcbbcd");
276     }
277 
278     return boost::report_errors();
279 }
280