1 ///////////////////////////////////////////////////////////////////////////////
2 // static.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_STATIC_STATIC_HPP_EAN_10_04_2005
9 #define BOOST_XPRESSIVE_DETAIL_STATIC_STATIC_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/mpl/assert.hpp>
17 #include <boost/xpressive/detail/detail_fwd.hpp>
18 #include <boost/xpressive/detail/core/state.hpp>
19 #include <boost/xpressive/detail/core/linker.hpp>
20 #include <boost/xpressive/detail/core/peeker.hpp>
21 #include <boost/xpressive/detail/static/placeholders.hpp>
22 #include <boost/xpressive/detail/utility/width.hpp>
23 
24 // Random thoughts:
25 // - must support indirect repeat counts {$n,$m}
26 // - add ws to eat whitespace (make *ws illegal)
27 // - a{n,m}    -> repeat<n,m>(a)
28 // - a{$n,$m}  -> repeat(n,m)(a)
29 // - add nil to match nothing
30 // - instead of s1, s2, etc., how about s[1], s[2], etc.? Needlessly verbose?
31 
32 namespace boost { namespace xpressive { namespace detail
33 {
34 
35 ///////////////////////////////////////////////////////////////////////////////
36 // stacked_xpression
37 //
38 template<typename Top, typename Next>
39 struct stacked_xpression
40   : Next
41 {
42     // match
43     //  delegates to Next
44     template<typename BidiIter>
matchboost::xpressive::detail::stacked_xpression45     bool match(match_state<BidiIter> &state) const
46     {
47         return static_cast<Next const *>(this)->
48             BOOST_NESTED_TEMPLATE push_match<Top>(state);
49     }
50 
51     // top_match
52     //   jump back to the xpression on top of the xpression stack,
53     //   and keep the xpression on the stack.
54     template<typename BidiIter>
top_matchboost::xpressive::detail::stacked_xpression55     static bool top_match(match_state<BidiIter> &state, void const *top)
56     {
57         return static_cast<Top const *>(top)->
58             BOOST_NESTED_TEMPLATE push_match<Top>(state);
59     }
60 
61     // pop_match
62     //   jump back to the xpression on top of the xpression stack,
63     //   pop the xpression off the stack.
64     template<typename BidiIter>
pop_matchboost::xpressive::detail::stacked_xpression65     static bool pop_match(match_state<BidiIter> &state, void const *top)
66     {
67         return static_cast<Top const *>(top)->match(state);
68     }
69 
70     // skip_match
71     //   pop the xpression off the top of the stack and ignore it; call
72     //   match on next.
73     template<typename BidiIter>
skip_matchboost::xpressive::detail::stacked_xpression74     bool skip_match(match_state<BidiIter> &state) const
75     {
76         // could be static_xpression::skip_impl or stacked_xpression::skip_impl
77         // depending on if there is 1 or more than 1 xpression on the
78         // xpression stack
79         return Top::skip_impl(*static_cast<Next const *>(this), state);
80     }
81 
82 //protected:
83 
84     // skip_impl
85     //   implementation of skip_match.
86     template<typename That, typename BidiIter>
skip_implboost::xpressive::detail::stacked_xpression87     static bool skip_impl(That const &that, match_state<BidiIter> &state)
88     {
89         return that.BOOST_NESTED_TEMPLATE push_match<Top>(state);
90     }
91 };
92 
93 ///////////////////////////////////////////////////////////////////////////////
94 // stacked_xpression_cast
95 //
96 template<typename Top, typename Next>
stacked_xpression_cast(Next const & next)97 inline stacked_xpression<Top, Next> const &stacked_xpression_cast(Next const &next)
98 {
99     // NOTE: this is a little white lie. The "next" object doesn't really have
100     // the type to which we're casting it. It is harmless, though. We are only using
101     // the cast to decorate the next object with type information. It is done
102     // this way to save stack space.
103     BOOST_MPL_ASSERT_RELATION(sizeof(stacked_xpression<Top, Next>), ==, sizeof(Next));
104     return *static_cast<stacked_xpression<Top, Next> const *>(&next);
105 }
106 
107 ///////////////////////////////////////////////////////////////////////////////
108 // static_xpression
109 //
110 template<typename Matcher, typename Next>
111 struct static_xpression
112   : Matcher
113 {
114     Next next_;
115 
116     BOOST_STATIC_CONSTANT(bool, pure = Matcher::pure && Next::pure);
117     BOOST_STATIC_CONSTANT(
118         std::size_t
119       , width =
120             Matcher::width != unknown_width::value && Next::width != unknown_width::value
121           ? Matcher::width + Next::width
122           : unknown_width::value
123     );
124 
static_xpressionboost::xpressive::detail::static_xpression125     static_xpression(Matcher const &matcher = Matcher(), Next const &next = Next())
126       : Matcher(matcher)
127       , next_(next)
128     {
129     }
130 
131     // match
132     //  delegates to the Matcher
133     template<typename BidiIter>
matchboost::xpressive::detail::static_xpression134     bool match(match_state<BidiIter> &state) const
135     {
136         return this->Matcher::match(state, this->next_);
137     }
138 
139     // push_match
140     //   call match on this, but also push "Top" onto the xpression
141     //   stack so we know what we are jumping back to later.
142     template<typename Top, typename BidiIter>
push_matchboost::xpressive::detail::static_xpression143     bool push_match(match_state<BidiIter> &state) const
144     {
145         return this->Matcher::match(state, stacked_xpression_cast<Top>(this->next_));
146     }
147 
148     // skip_impl
149     //   implementation of skip_match, called from stacked_xpression::skip_match
150     template<typename That, typename BidiIter>
skip_implboost::xpressive::detail::static_xpression151     static bool skip_impl(That const &that, match_state<BidiIter> &state)
152     {
153         return that.match(state);
154     }
155 
156     // for linking a compiled regular xpression
157     template<typename Char>
linkboost::xpressive::detail::static_xpression158     void link(xpression_linker<Char> &linker) const
159     {
160         linker.accept(*static_cast<Matcher const *>(this), &this->next_);
161         this->next_.link(linker);
162     }
163 
164     // for building a lead-follow
165     template<typename Char>
peekboost::xpressive::detail::static_xpression166     void peek(xpression_peeker<Char> &peeker) const
167     {
168         this->peek_next_(peeker.accept(*static_cast<Matcher const *>(this)), peeker);
169     }
170 
171     // for getting xpression width
get_widthboost::xpressive::detail::static_xpression172     detail::width get_width() const
173     {
174         return this->get_width_(mpl::size_t<width>());
175     }
176 
177 private:
178 
179     static_xpression &operator =(static_xpression const &);
180 
181     template<typename Char>
peek_next_boost::xpressive::detail::static_xpression182     void peek_next_(mpl::true_, xpression_peeker<Char> &peeker) const
183     {
184         this->next_.peek(peeker);
185     }
186 
187     template<typename Char>
peek_next_boost::xpressive::detail::static_xpression188     void peek_next_(mpl::false_, xpression_peeker<Char> &) const
189     {
190         // no-op
191     }
192 
193     template<std::size_t Width>
get_width_boost::xpressive::detail::static_xpression194     detail::width get_width_(mpl::size_t<Width>) const
195     {
196         return Width;
197     }
198 
get_width_boost::xpressive::detail::static_xpression199     detail::width get_width_(unknown_width) const
200     {
201         // Should only be called in contexts where the width is
202         // known to be fixed.
203         return this->Matcher::get_width() + this->next_.get_width();
204     }
205 };
206 
207 ///////////////////////////////////////////////////////////////////////////////
208 // make_static
209 //
210 template<typename Matcher>
211 inline static_xpression<Matcher> const
make_static(Matcher const & matcher)212 make_static(Matcher const &matcher)
213 {
214     return static_xpression<Matcher>(matcher);
215 }
216 
217 template<typename Matcher, typename Next>
218 inline static_xpression<Matcher, Next> const
make_static(Matcher const & matcher,Next const & next)219 make_static(Matcher const &matcher, Next const &next)
220 {
221     return static_xpression<Matcher, Next>(matcher, next);
222 }
223 
224 ///////////////////////////////////////////////////////////////////////////////
225 // no_next
226 //
227 struct no_next
228 {
229     BOOST_STATIC_CONSTANT(std::size_t, width = 0);
230     BOOST_STATIC_CONSTANT(bool, pure = true);
231 
232     template<typename Char>
linkboost::xpressive::detail::no_next233     void link(xpression_linker<Char> &) const
234     {
235     }
236 
237     template<typename Char>
peekboost::xpressive::detail::no_next238     void peek(xpression_peeker<Char> &peeker) const
239     {
240         peeker.fail();
241     }
242 
get_widthboost::xpressive::detail::no_next243     detail::width get_width() const
244     {
245         return 0;
246     }
247 };
248 
249 ///////////////////////////////////////////////////////////////////////////////
250 // get_mark_number
251 //
get_mark_number(basic_mark_tag const & mark)252 inline int get_mark_number(basic_mark_tag const &mark)
253 {
254     return proto::value(mark).mark_number_;
255 }
256 
257 }}} // namespace boost::xpressive::detail
258 
259 #endif
260