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
19namespace xp = boost::xpressive;
20
21///////////////////////////////////////////////////////////////////////////////
22// test1
23// simple action which builds a string
24void 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(t&: result) += _ ] >> *(' ' >> (+_w)[ xp::ref(t&: result) += ',' + _ ]);
31
32 if(!regex_match(rng&: str, re: 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
45void 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(t&: result) += _ ] >> *(' ' >> (+_w)[ xp::ref(t&: result) += ',' + _ ]) >> repeat<4>(expr2: _);
52
53 if(!regex_match(rng&: str, re: 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
66void 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(t&: result)->*push_back( as<int>(a: _) ) ]
74 >> *(' ' >> (+_d)[ xp::ref(t&: result)->*push_back( as<int>(a: _) ) ]);
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(rng&: str, re: 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
97void 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(t&: result)[s1] = as<int>(a: s2) ];
104 sregex rx = pair >> *(+_s >> pair);
105
106 if(!regex_match(rng&: str, re: 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.
122void test4_aux()
123{
124 using namespace boost::xpressive;
125 placeholder< std::map<std::string, int> > const _map = {.proto_expr_: {}};
126
127 sregex pair = ( (s1= +_w) >> "=>" >> (s2= +_d) )[ _map[s1] = as<int>(a: 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(arg: _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.
163void 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(rex: expression) >> ')';
179 factor = (+_d)[ push(stack, as<int>(a: _)) ] | 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(rng&: str, re: 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.
230void 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>(a: _)] >> L"." >>
240 (+_d)[min1 = as<int>(a: _)] >> L"." >>
241 (+_d)[build1 = as<int>(a: _)];
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
254void 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(str&: text, re: var, format: xp::ref(t&: env)[s1]);
267
268 BOOST_CHECK_EQUAL(text, "This is a !!! string ??? and stuff.");
269}
270
271using namespace boost::unit_test;
272
273///////////////////////////////////////////////////////////////////////////////
274// init_unit_test_suite
275//
276test_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

source code of boost/libs/xpressive/test/test_actions.cpp