1 ///////////////////////////////////////////////////////////////////////////////
2 // linker.hpp
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 #ifndef BOOST_XPRESSIVE_DETAIL_CORE_LINKER_HPP_EAN_10_04_2005
9 #define BOOST_XPRESSIVE_DETAIL_CORE_LINKER_HPP_EAN_10_04_2005
10 
11 // MS compatible compilers support #pragma once
12 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
13 # pragma once
14 #endif
15 
16 #include <boost/config.hpp>
17 #ifndef BOOST_NO_STD_LOCALE
18 # include <locale>
19 #endif
20 #include <stack>
21 #include <limits>
22 #include <typeinfo>
23 #include <boost/shared_ptr.hpp>
24 #include <boost/type_traits/is_same.hpp>
25 #include <boost/version.hpp>
26 
27 #if BOOST_VERSION >= 103500
28 # include <boost/fusion/include/for_each.hpp>
29 #else
30 # include <boost/spirit/fusion/algorithm/for_each.hpp>
31 #endif
32 
33 #include <boost/xpressive/detail/detail_fwd.hpp>
34 #include <boost/xpressive/detail/dynamic/matchable.hpp>
35 #include <boost/xpressive/detail/core/matchers.hpp>
36 #include <boost/xpressive/detail/core/peeker.hpp>
37 #include <boost/xpressive/detail/utility/never_true.hpp>
38 
39 namespace boost { namespace xpressive { namespace detail
40 {
41 
42 ///////////////////////////////////////////////////////////////////////////////
43 // icase_modifier
44 //
45 //   wrapped by the modifier<> template and inserted into the xpression
46 //   template with the icase() helper function. icase_modifier morphs
47 //   a case-sensitive visitor into a case-insensitive visitor, which
48 //   causes all matchers visited to become case-insensitive.
49 //
50 struct icase_modifier
51 {
52     template<typename Visitor>
53     struct apply {};
54 
55     template<typename BidiIter, typename ICase, typename Traits>
56     struct apply<xpression_visitor<BidiIter, ICase, Traits> >
57     {
58         typedef xpression_visitor<BidiIter, mpl::true_, Traits> type;
59     };
60 
61     template<typename Visitor>
62     static typename apply<Visitor>::type
callboost::xpressive::detail::icase_modifier63     call(Visitor &visitor)
64     {
65         return typename apply<Visitor>::type(visitor.traits(), visitor.self());
66     }
67 };
68 
69 ///////////////////////////////////////////////////////////////////////////////
70 // regex_traits_type : wrap a locale in the appropriate regex_traits
71 //
72 template<typename Locale, typename BidiIter>
73 struct regex_traits_type
74 {
75 #ifndef BOOST_NO_STD_LOCALE
76 
77     typedef typename iterator_value<BidiIter>::type char_type;
78 
79     // if Locale is std::locale, wrap it in a cpp_regex_traits<Char>
80     typedef typename mpl::if_
81     <
82         is_same<Locale, std::locale>
83       , cpp_regex_traits<char_type>
84       , Locale
85     >::type type;
86 
87 #else
88 
89     typedef Locale type;
90 
91 #endif
92 };
93 
94 ///////////////////////////////////////////////////////////////////////////////
95 // locale_modifier
96 //
97 //   wrapped by the modifier<> template and inserted into the xpression
98 //   template with the imbue() helper function. Causes a sub-xpression to
99 //   use the specified Locale
100 //
101 template<typename Locale>
102 struct locale_modifier
103 {
104     typedef Locale locale_type;
105 
locale_modifierboost::xpressive::detail::locale_modifier106     locale_modifier(Locale const &loc)
107       : loc_(loc)
108     {
109     }
110 
111     template<typename Visitor>
112     struct apply {};
113 
114     template<typename BidiIter, typename ICase, typename OtherTraits>
115     struct apply<xpression_visitor<BidiIter, ICase, OtherTraits> >
116     {
117         typedef typename regex_traits_type<Locale, BidiIter>::type traits_type;
118         typedef xpression_visitor<BidiIter, ICase, traits_type> type;
119     };
120 
121     template<typename Visitor>
122     typename apply<Visitor>::type
callboost::xpressive::detail::locale_modifier123     call(Visitor &visitor) const
124     {
125         return typename apply<Visitor>::type(this->loc_, visitor.self());
126     }
127 
getlocboost::xpressive::detail::locale_modifier128     Locale getloc() const
129     {
130         return this->loc_;
131     }
132 
133 private:
134     Locale loc_;
135 };
136 
137 ///////////////////////////////////////////////////////////////////////////////
138 // xpression_linker
139 //
140 template<typename Char>
141 struct xpression_linker
142 {
143     template<typename Traits>
xpression_linkerboost::xpressive::detail::xpression_linker144     explicit xpression_linker(Traits const &traits)
145       : back_stack_()
146       , traits_(&traits)
147       , traits_type_(&typeid(Traits))
148       , has_backrefs_(false)
149     {
150     }
151 
152     template<typename Matcher>
acceptboost::xpressive::detail::xpression_linker153     void accept(Matcher const &, void const *)
154     {
155         // no-op
156     }
157 
158     template<typename Traits, typename ICase>
acceptboost::xpressive::detail::xpression_linker159     void accept(mark_matcher<Traits, ICase> const &, void const *)
160     {
161         this->has_backrefs_ = true;
162     }
163 
164     template<typename Action>
acceptboost::xpressive::detail::xpression_linker165     void accept(action_matcher<Action> const &, void const *)
166     {
167         this->has_backrefs_ = true;
168     }
169 
170     template<typename Predicate>
acceptboost::xpressive::detail::xpression_linker171     void accept(predicate_matcher<Predicate> const &, void const *)
172     {
173         this->has_backrefs_ = true;
174     }
175 
acceptboost::xpressive::detail::xpression_linker176     void accept(repeat_begin_matcher const &, void const *next)
177     {
178         this->back_stack_.push(next);
179     }
180 
181     template<typename Greedy>
acceptboost::xpressive::detail::xpression_linker182     void accept(repeat_end_matcher<Greedy> const &matcher, void const *)
183     {
184         matcher.back_ = this->back_stack_.top();
185         this->back_stack_.pop();
186     }
187 
188     template<typename Alternates, typename Traits>
acceptboost::xpressive::detail::xpression_linker189     void accept(alternate_matcher<Alternates, Traits> const &matcher, void const *next)
190     {
191         xpression_peeker<Char> peeker(matcher.bset_, this->get_traits<Traits>());
192         this->alt_link(matcher.alternates_, next, &peeker);
193     }
194 
acceptboost::xpressive::detail::xpression_linker195     void accept(alternate_end_matcher const &matcher, void const *)
196     {
197         matcher.back_ = this->back_stack_.top();
198         this->back_stack_.pop();
199     }
200 
201     template<typename Xpr, typename Greedy>
acceptboost::xpressive::detail::xpression_linker202     void accept(optional_matcher<Xpr, Greedy> const &matcher, void const *next)
203     {
204         this->back_stack_.push(next);
205         matcher.xpr_.link(*this);
206     }
207 
208     template<typename Xpr, typename Greedy>
acceptboost::xpressive::detail::xpression_linker209     void accept(optional_mark_matcher<Xpr, Greedy> const &matcher, void const *next)
210     {
211         this->back_stack_.push(next);
212         matcher.xpr_.link(*this);
213     }
214 
215     template<typename Xpr>
acceptboost::xpressive::detail::xpression_linker216     void accept(keeper_matcher<Xpr> const &matcher, void const *)
217     {
218         matcher.xpr_.link(*this);
219     }
220 
221     template<typename Xpr>
acceptboost::xpressive::detail::xpression_linker222     void accept(lookahead_matcher<Xpr> const &matcher, void const *)
223     {
224         matcher.xpr_.link(*this);
225     }
226 
227     template<typename Xpr>
acceptboost::xpressive::detail::xpression_linker228     void accept(lookbehind_matcher<Xpr> const &matcher, void const *)
229     {
230         matcher.xpr_.link(*this);
231     }
232 
233     template<typename Xpr, typename Greedy>
acceptboost::xpressive::detail::xpression_linker234     void accept(simple_repeat_matcher<Xpr, Greedy> const &matcher, void const *)
235     {
236         matcher.xpr_.link(*this);
237     }
238 
239     // accessors
has_backrefsboost::xpressive::detail::xpression_linker240     bool has_backrefs() const
241     {
242         return this->has_backrefs_;
243     }
244 
245     // for use by alt_link_pred below
246     template<typename Xpr>
alt_branch_linkboost::xpressive::detail::xpression_linker247     void alt_branch_link(Xpr const &xpr, void const *next, xpression_peeker<Char> *peeker)
248     {
249         this->back_stack_.push(next);
250         xpr.link(*this);
251         xpr.peek(*peeker);
252     }
253 
254 private:
255 
256     ///////////////////////////////////////////////////////////////////////////////
257     // alt_link_pred
258     //
259     struct alt_link_pred
260     {
261         xpression_linker<Char> *linker_;
262         xpression_peeker<Char> *peeker_;
263         void const *next_;
264 
alt_link_predboost::xpressive::detail::xpression_linker::alt_link_pred265         alt_link_pred
266         (
267             xpression_linker<Char> *linker
268           , xpression_peeker<Char> *peeker
269           , void const *next
270         )
271           : linker_(linker)
272           , peeker_(peeker)
273           , next_(next)
274         {
275         }
276 
277         template<typename Xpr>
operator ()boost::xpressive::detail::xpression_linker::alt_link_pred278         void operator ()(Xpr const &xpr) const
279         {
280             this->linker_->alt_branch_link(xpr, this->next_, this->peeker_);
281         }
282     };
283 
284     template<typename BidiIter>
alt_linkboost::xpressive::detail::xpression_linker285     void alt_link
286     (
287         alternates_vector<BidiIter> const &alternates
288       , void const *next
289       , xpression_peeker<Char> *peeker
290     )
291     {
292         std::for_each(alternates.begin(), alternates.end(), alt_link_pred(this, peeker, next));
293     }
294 
295     template<typename Alternates>
alt_linkboost::xpressive::detail::xpression_linker296     void alt_link
297     (
298         fusion::sequence_base<Alternates> const &alternates
299       , void const *next
300       , xpression_peeker<Char> *peeker
301     )
302     {
303 #if BOOST_VERSION >= 103500
304         fusion::for_each(alternates.derived(), alt_link_pred(this, peeker, next));
305 #else
306         fusion::for_each(alternates.cast(), alt_link_pred(this, peeker, next));
307 #endif
308     }
309 
310     template<typename Traits>
get_traitsboost::xpressive::detail::xpression_linker311     Traits const &get_traits() const
312     {
313         BOOST_ASSERT(*this->traits_type_ == typeid(Traits));
314         return *static_cast<Traits const *>(this->traits_);
315     }
316 
317     std::stack<void const *> back_stack_;
318     void const *traits_;
319     std::type_info const *traits_type_;
320     bool has_backrefs_;
321 };
322 
323 }}} // namespace boost::xpressive::detail
324 
325 #endif
326