]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // lookbehind_matcher.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_MATCHER_LOOKBEHIND_MATCHER_HPP_EAN_10_04_2005 | |
9 | #define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_LOOKBEHIND_MATCHER_HPP_EAN_10_04_2005 | |
10 | ||
11 | // MS compatible compilers support #pragma once | |
12 | #if defined(_MSC_VER) | |
13 | # pragma once | |
14 | #endif | |
15 | ||
16 | #include <boost/assert.hpp> | |
17 | #include <boost/xpressive/regex_error.hpp> | |
18 | #include <boost/xpressive/regex_constants.hpp> | |
19 | #include <boost/xpressive/detail/detail_fwd.hpp> | |
20 | #include <boost/xpressive/detail/core/quant_style.hpp> | |
21 | #include <boost/xpressive/detail/core/state.hpp> | |
22 | #include <boost/xpressive/detail/utility/algorithm.hpp> | |
23 | #include <boost/xpressive/detail/utility/save_restore.hpp> | |
24 | #include <boost/xpressive/detail/utility/ignore_unused.hpp> | |
25 | ||
26 | namespace boost { namespace xpressive { namespace detail | |
27 | { | |
28 | ||
29 | /////////////////////////////////////////////////////////////////////////////// | |
30 | // lookbehind_matcher | |
31 | // Xpr can be either a static_xpression or a shared_matchable | |
32 | template<typename Xpr> | |
33 | struct lookbehind_matcher | |
34 | : quant_style<quant_none, 0, Xpr::pure> | |
35 | { | |
36 | lookbehind_matcher(Xpr const &xpr, std::size_t wid, bool no, bool pure = Xpr::pure) | |
37 | : xpr_(xpr) | |
38 | , not_(no) | |
39 | , pure_(pure) | |
40 | , width_(wid) | |
41 | { | |
42 | BOOST_XPR_ENSURE_(!is_unknown(this->width_), regex_constants::error_badlookbehind, | |
43 | "Variable-width look-behind assertions are not supported"); | |
44 | } | |
45 | ||
46 | void inverse() | |
47 | { | |
48 | this->not_ = !this->not_; | |
49 | } | |
50 | ||
51 | template<typename BidiIter, typename Next> | |
52 | bool match(match_state<BidiIter> &state, Next const &next) const | |
53 | { | |
54 | return Xpr::pure || this->pure_ | |
55 | ? this->match_(state, next, mpl::true_()) | |
56 | : this->match_(state, next, mpl::false_()); | |
57 | } | |
58 | ||
59 | template<typename BidiIter, typename Next> | |
60 | bool match_(match_state<BidiIter> &state, Next const &next, mpl::true_) const | |
61 | { | |
62 | typedef typename iterator_difference<BidiIter>::type difference_type; | |
63 | BidiIter const tmp = state.cur_; | |
64 | if(!detail::advance_to(state.cur_, -static_cast<difference_type>(this->width_), state.begin_)) | |
65 | { | |
66 | state.cur_ = tmp; | |
67 | return this->not_ ? next.match(state) : false; | |
68 | } | |
69 | ||
70 | if(this->not_) | |
71 | { | |
72 | if(this->xpr_.match(state)) | |
73 | { | |
74 | BOOST_ASSERT(state.cur_ == tmp); | |
75 | return false; | |
76 | } | |
77 | state.cur_ = tmp; | |
78 | if(next.match(state)) | |
79 | { | |
80 | return true; | |
81 | } | |
82 | } | |
83 | else | |
84 | { | |
85 | if(!this->xpr_.match(state)) | |
86 | { | |
87 | state.cur_ = tmp; | |
88 | return false; | |
89 | } | |
90 | BOOST_ASSERT(state.cur_ == tmp); | |
91 | if(next.match(state)) | |
92 | { | |
93 | return true; | |
94 | } | |
95 | } | |
96 | ||
97 | BOOST_ASSERT(state.cur_ == tmp); | |
98 | return false; | |
99 | } | |
100 | ||
101 | template<typename BidiIter, typename Next> | |
102 | bool match_(match_state<BidiIter> &state, Next const &next, mpl::false_) const | |
103 | { | |
104 | typedef typename iterator_difference<BidiIter>::type difference_type; | |
105 | BidiIter const tmp = state.cur_; | |
106 | if(!detail::advance_to(state.cur_, -static_cast<difference_type>(this->width_), state.begin_)) | |
107 | { | |
108 | state.cur_ = tmp; | |
109 | return this->not_ ? next.match(state) : false; | |
110 | } | |
111 | ||
112 | // matching xpr could produce side-effects, save state | |
113 | memento<BidiIter> mem = save_sub_matches(state); | |
114 | ||
115 | if(this->not_) | |
116 | { | |
117 | // negative look-ahead assertions do not trigger partial matches. | |
118 | save_restore<bool> partial_match(state.found_partial_match_); | |
119 | detail::ignore_unused(partial_match); | |
120 | ||
121 | if(this->xpr_.match(state)) | |
122 | { | |
123 | restore_action_queue(mem, state); | |
124 | restore_sub_matches(mem, state); | |
125 | BOOST_ASSERT(state.cur_ == tmp); | |
126 | return false; | |
127 | } | |
128 | state.cur_ = tmp; | |
129 | restore_action_queue(mem, state); | |
130 | if(next.match(state)) | |
131 | { | |
132 | reclaim_sub_matches(mem, state, true); | |
133 | return true; | |
134 | } | |
135 | reclaim_sub_matches(mem, state, false); | |
136 | } | |
137 | else | |
138 | { | |
139 | if(!this->xpr_.match(state)) | |
140 | { | |
141 | state.cur_ = tmp; | |
142 | restore_action_queue(mem, state); | |
143 | reclaim_sub_matches(mem, state, false); | |
144 | return false; | |
145 | } | |
146 | BOOST_ASSERT(state.cur_ == tmp); | |
147 | restore_action_queue(mem, state); | |
148 | if(next.match(state)) | |
149 | { | |
150 | reclaim_sub_matches(mem, state, true); | |
151 | return true; | |
152 | } | |
153 | restore_sub_matches(mem, state); | |
154 | } | |
155 | ||
156 | BOOST_ASSERT(state.cur_ == tmp); | |
157 | return false; | |
158 | } | |
159 | ||
160 | Xpr xpr_; | |
161 | bool not_; | |
162 | bool pure_; // false if matching xpr_ could modify the sub-matches | |
163 | std::size_t width_; | |
164 | }; | |
165 | ||
166 | }}} | |
167 | ||
168 | #endif |