• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////////////////////
2 // test_actions.cpp
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 
8 //#define BOOST_XPRESSIVE_BETTER_ERRORS
9 
10 #include <map>
11 #include <list>
12 #include <stack>
13 #include <numeric>
14 #include <boost/version.hpp>
15 #include <boost/xpressive/xpressive_static.hpp>
16 #include <boost/xpressive/regex_actions.hpp>
17 #include <boost/test/unit_test.hpp>
18 
19 namespace xp = boost::xpressive;
20 
21 ///////////////////////////////////////////////////////////////////////////////
22 // test1
23 //  simple action which builds a string
test1()24 void test1()
25 {
26     using namespace boost::xpressive;
27 
28     std::string result;
29     std::string str("foo bar baz foo bar baz");
30     sregex rx = (+_w)[ xp::ref(result) += _ ] >> *(' ' >> (+_w)[ xp::ref(result) += ',' + _ ]);
31 
32     if(!regex_match(str, rx))
33     {
34         BOOST_ERROR("oops");
35     }
36     else
37     {
38         BOOST_CHECK_EQUAL(result, "foo,bar,baz,foo,bar,baz");
39     }
40 }
41 
42 ///////////////////////////////////////////////////////////////////////////////
43 // test2
44 //  test backtracking over actions
test2()45 void test2()
46 {
47     using namespace boost::xpressive;
48 
49     std::string result;
50     std::string str("foo bar baz foo bar baz");
51     sregex rx = (+_w)[ xp::ref(result) += _ ] >> *(' ' >> (+_w)[ xp::ref(result) += ',' + _ ]) >> repeat<4>(_);
52 
53     if(!regex_match(str, rx))
54     {
55         BOOST_ERROR("oops");
56     }
57     else
58     {
59         BOOST_CHECK_EQUAL(result, "foo,bar,baz,foo,bar");
60     }
61 }
62 
63 ///////////////////////////////////////////////////////////////////////////////
64 // test3
65 //  cast string to int, push back into list, use alternate ->* syntax
test3()66 void test3()
67 {
68     using namespace boost::xpressive;
69 
70     std::list<int> result;
71     std::string str("1 23 456 7890");
72 #if BOOST_VERSION >= 103500
73     sregex rx = (+_d)[ xp::ref(result)->*push_back( as<int>(_) ) ]
74         >> *(' ' >> (+_d)[ xp::ref(result)->*push_back( as<int>(_) ) ]);
75 #else
76     sregex rx = (+_d)[ push_back(xp::ref(result), as<int>(_) ) ]
77         >> *(' ' >> (+_d)[ push_back(xp::ref(result), as<int>(_) ) ]);
78 #endif
79 
80     if(!regex_match(str, rx))
81     {
82         BOOST_ERROR("oops");
83     }
84     else
85     {
86         BOOST_REQUIRE_EQUAL(result.size(), 4u);
87         BOOST_CHECK_EQUAL(*result.begin(), 1);
88         BOOST_CHECK_EQUAL(*++result.begin(), 23);
89         BOOST_CHECK_EQUAL(*++++result.begin(), 456);
90         BOOST_CHECK_EQUAL(*++++++result.begin(), 7890);
91     }
92 }
93 
94 ///////////////////////////////////////////////////////////////////////////////
95 // test4
96 //  build a map of strings to integers
test4()97 void test4()
98 {
99     using namespace boost::xpressive;
100 
101     std::map<std::string, int> result;
102     std::string str("aaa=>1 bbb=>23 ccc=>456");
103     sregex pair = ( (s1= +_w) >> "=>" >> (s2= +_d) )[ xp::ref(result)[s1] = as<int>(s2) ];
104     sregex rx = pair >> *(+_s >> pair);
105 
106     if(!regex_match(str, rx))
107     {
108         BOOST_ERROR("oops");
109     }
110     else
111     {
112         BOOST_REQUIRE_EQUAL(result.size(), 3u);
113         BOOST_CHECK_EQUAL(result["aaa"], 1);
114         BOOST_CHECK_EQUAL(result["bbb"], 23);
115         BOOST_CHECK_EQUAL(result["ccc"], 456);
116     }
117 }
118 
119 ///////////////////////////////////////////////////////////////////////////////
120 // test4_aux
121 //  build a map of strings to integers, with a late-bound action argument.
test4_aux()122 void test4_aux()
123 {
124     using namespace boost::xpressive;
125     placeholder< std::map<std::string, int> > const _map = {{}};
126 
127     sregex pair = ( (s1= +_w) >> "=>" >> (s2= +_d) )[ _map[s1] = as<int>(s2) ];
128     sregex rx = pair >> *(+_s >> pair);
129 
130     std::string str("aaa=>1 bbb=>23 ccc=>456");
131     smatch what;
132     std::map<std::string, int> result;
133     what.let(_map = result); // bind the argument!
134 
135     BOOST_REQUIRE(regex_match(str, what, rx));
136     BOOST_REQUIRE_EQUAL(result.size(), 3u);
137     BOOST_CHECK_EQUAL(result["aaa"], 1);
138     BOOST_CHECK_EQUAL(result["bbb"], 23);
139     BOOST_CHECK_EQUAL(result["ccc"], 456);
140 
141     // Try the same test with regex_iterator
142     result.clear();
143     sregex_iterator it(str.begin(), str.end(), pair, let(_map=result)), end;
144     BOOST_REQUIRE_EQUAL(3, std::distance(it, end));
145     BOOST_REQUIRE_EQUAL(result.size(), 3u);
146     BOOST_CHECK_EQUAL(result["aaa"], 1);
147     BOOST_CHECK_EQUAL(result["bbb"], 23);
148     BOOST_CHECK_EQUAL(result["ccc"], 456);
149 
150     // Try the same test with regex_token_iterator
151     result.clear();
152     sregex_token_iterator it2(str.begin(), str.end(), pair, (s1,s2), let(_map=result)), end2;
153     BOOST_REQUIRE_EQUAL(6, std::distance(it2, end2));
154     BOOST_REQUIRE_EQUAL(result.size(), 3u);
155     BOOST_CHECK_EQUAL(result["aaa"], 1);
156     BOOST_CHECK_EQUAL(result["bbb"], 23);
157     BOOST_CHECK_EQUAL(result["ccc"], 456);
158 }
159 
160 ///////////////////////////////////////////////////////////////////////////////
161 // test5
162 //  calculator that calculates. This is just silly, but hey.
test5()163 void test5()
164 {
165     using namespace boost::xpressive;
166 
167     // test for "local" variables.
168     local<int> left, right;
169 
170     // test for reference<> to an existing variable
171     std::stack<int> stack_;
172     reference<std::stack<int> > stack(stack_);
173 
174     std::string str("4+5*(3-1)");
175 
176     sregex group, factor, term, expression;
177 
178     group       = '(' >> by_ref(expression) >> ')';
179     factor      = (+_d)[ push(stack, as<int>(_)) ] | group;
180     term        = factor >> *(
181                                 ('*' >> factor)
182                                     [ right = top(stack)
183                                     , pop(stack)
184                                     , left = top(stack)
185                                     , pop(stack)
186                                     , push(stack, left * right)
187                                     ]
188                               | ('/' >> factor)
189                                     [ right = top(stack)
190                                     , pop(stack)
191                                     , left = top(stack)
192                                     , pop(stack)
193                                     , push(stack, left / right)
194                                     ]
195                              );
196     expression  = term >> *(
197                                 ('+' >> term)
198                                     [ right = top(stack)
199                                     , pop(stack)
200                                     , left = top(stack)
201                                     , pop(stack)
202                                     , push(stack, left + right)
203                                     ]
204                               | ('-' >> term)
205                                     [ right = top(stack)
206                                     , pop(stack)
207                                     , left = top(stack)
208                                     , pop(stack)
209                                     , push(stack, left - right)
210                                     ]
211                              );
212 
213     if(!regex_match(str, expression))
214     {
215         BOOST_ERROR("oops");
216     }
217     else
218     {
219         BOOST_REQUIRE_EQUAL(stack_.size(), 1u);
220         BOOST_CHECK_EQUAL(stack_.top(), 14);
221 
222         BOOST_REQUIRE_EQUAL(stack.get().size(), 1u);
223         BOOST_CHECK_EQUAL(stack.get().top(), 14);
224     }
225 }
226 
227 ///////////////////////////////////////////////////////////////////////////////
228 // test6
229 //  Test as<>() with wide strings. Bug #4496.
test6()230 void test6()
231 {
232 #if !defined(BOOST_XPRESSIVE_NO_WREGEX)
233     using namespace boost::xpressive;
234 
235     std::wstring version(L"0.9.500");
236 
237     local<int> maj1(0), min1(0), build1(0);
238 
239     wsregex re1 = (+_d)[maj1 = as<int>(_)] >> L"." >>
240                   (+_d)[min1 = as<int>(_)] >> L"." >>
241                   (+_d)[build1 = as<int>(_)];
242 
243     BOOST_REQUIRE(regex_match(version, re1));
244 
245     BOOST_CHECK_EQUAL(maj1.get(), 0);
246     BOOST_CHECK_EQUAL(min1.get(), 9);
247     BOOST_CHECK_EQUAL(build1.get(), 500);
248 #endif
249 }
250 
251 ///////////////////////////////////////////////////////////////////////////////
252 // test7
253 //  Test regex_replace with an xpressive lambda
test7()254 void test7()
255 {
256     namespace xp = boost::xpressive;
257     using namespace xp;
258 
259     std::map<std::string, std::string> env;
260     env["XXX"] = "!!!";
261     env["YYY"] = "???";
262 
263     std::string text("This is a %XXX% string %YYY% and stuff.");
264     sregex var = '%' >> (s1 = +_w) >> '%';
265 
266     text = regex_replace(text, var, xp::ref(env)[s1]);
267 
268     BOOST_CHECK_EQUAL(text, "This is a !!! string ??? and stuff.");
269 }
270 
271 using namespace boost::unit_test;
272 
273 ///////////////////////////////////////////////////////////////////////////////
274 // init_unit_test_suite
275 //
init_unit_test_suite(int argc,char * argv[])276 test_suite* init_unit_test_suite( int argc, char* argv[] )
277 {
278     test_suite *test = BOOST_TEST_SUITE("test_actions");
279     test->add(BOOST_TEST_CASE(&test1));
280     test->add(BOOST_TEST_CASE(&test2));
281     test->add(BOOST_TEST_CASE(&test3));
282     test->add(BOOST_TEST_CASE(&test4));
283     test->add(BOOST_TEST_CASE(&test4_aux));
284     test->add(BOOST_TEST_CASE(&test5));
285     test->add(BOOST_TEST_CASE(&test6));
286     test->add(BOOST_TEST_CASE(&test7));
287     return test;
288 }
289 
290