static.hpp 7.45 KB
Newer Older
xuebingbing's avatar
xuebingbing committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
///////////////////////////////////////////////////////////////////////////////
// static.hpp
//
//  Copyright 2008 Eric Niebler. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_XPRESSIVE_DETAIL_STATIC_STATIC_HPP_EAN_10_04_2005
#define BOOST_XPRESSIVE_DETAIL_STATIC_STATIC_HPP_EAN_10_04_2005

// MS compatible compilers support #pragma once
#if defined(_MSC_VER)
# pragma once
#endif

#include <boost/mpl/assert.hpp>
#include <boost/xpressive/detail/detail_fwd.hpp>
#include <boost/xpressive/detail/core/state.hpp>
#include <boost/xpressive/detail/core/linker.hpp>
#include <boost/xpressive/detail/core/peeker.hpp>
#include <boost/xpressive/detail/static/placeholders.hpp>
#include <boost/xpressive/detail/utility/width.hpp>

// Random thoughts:
// - must support indirect repeat counts {$n,$m}
// - add ws to eat whitespace (make *ws illegal)
// - a{n,m}    -> repeat<n,m>(a)
// - a{$n,$m}  -> repeat(n,m)(a)
// - add nil to match nothing
// - instead of s1, s2, etc., how about s[1], s[2], etc.? Needlessly verbose?

namespace boost { namespace xpressive { namespace detail
{

///////////////////////////////////////////////////////////////////////////////
// stacked_xpression
//
template<typename Top, typename Next>
struct stacked_xpression
  : Next
{
    // match
    //  delegates to Next
    template<typename BidiIter>
    bool match(match_state<BidiIter> &state) const
    {
        return static_cast<Next const *>(this)->
            BOOST_NESTED_TEMPLATE push_match<Top>(state);
    }

    // top_match
    //   jump back to the xpression on top of the xpression stack,
    //   and keep the xpression on the stack.
    template<typename BidiIter>
    static bool top_match(match_state<BidiIter> &state, void const *top)
    {
        return static_cast<Top const *>(top)->
            BOOST_NESTED_TEMPLATE push_match<Top>(state);
    }

    // pop_match
    //   jump back to the xpression on top of the xpression stack,
    //   pop the xpression off the stack.
    template<typename BidiIter>
    static bool pop_match(match_state<BidiIter> &state, void const *top)
    {
        return static_cast<Top const *>(top)->match(state);
    }

    // skip_match
    //   pop the xpression off the top of the stack and ignore it; call
    //   match on next.
    template<typename BidiIter>
    bool skip_match(match_state<BidiIter> &state) const
    {
        // could be static_xpression::skip_impl or stacked_xpression::skip_impl
        // depending on if there is 1 or more than 1 xpression on the
        // xpression stack
        return Top::skip_impl(*static_cast<Next const *>(this), state);
    }

//protected:

    // skip_impl
    //   implementation of skip_match.
    template<typename That, typename BidiIter>
    static bool skip_impl(That const &that, match_state<BidiIter> &state)
    {
        return that.BOOST_NESTED_TEMPLATE push_match<Top>(state);
    }
};

///////////////////////////////////////////////////////////////////////////////
// stacked_xpression_cast
//
template<typename Top, typename Next>
inline stacked_xpression<Top, Next> const &stacked_xpression_cast(Next const &next)
{
    // NOTE: this is a little white lie. The "next" object doesn't really have
    // the type to which we're casting it. It is harmless, though. We are only using
    // the cast to decorate the next object with type information. It is done
    // this way to save stack space.
    BOOST_MPL_ASSERT_RELATION(sizeof(stacked_xpression<Top, Next>), ==, sizeof(Next));
    return *static_cast<stacked_xpression<Top, Next> const *>(&next);
}

///////////////////////////////////////////////////////////////////////////////
// static_xpression
//
template<typename Matcher, typename Next>
struct static_xpression
  : Matcher
{
    Next next_;

    BOOST_STATIC_CONSTANT(bool, pure = Matcher::pure && Next::pure);
    BOOST_STATIC_CONSTANT(
        std::size_t
      , width =
            Matcher::width != unknown_width::value && Next::width != unknown_width::value
          ? Matcher::width + Next::width
          : unknown_width::value
    );

    static_xpression(Matcher const &matcher = Matcher(), Next const &next = Next())
      : Matcher(matcher)
      , next_(next)
    {
    }

    // match
    //  delegates to the Matcher
    template<typename BidiIter>
    bool match(match_state<BidiIter> &state) const
    {
        return this->Matcher::match(state, this->next_);
    }

    // push_match
    //   call match on this, but also push "Top" onto the xpression
    //   stack so we know what we are jumping back to later.
    template<typename Top, typename BidiIter>
    bool push_match(match_state<BidiIter> &state) const
    {
        return this->Matcher::match(state, stacked_xpression_cast<Top>(this->next_));
    }

    // skip_impl
    //   implementation of skip_match, called from stacked_xpression::skip_match
    template<typename That, typename BidiIter>
    static bool skip_impl(That const &that, match_state<BidiIter> &state)
    {
        return that.match(state);
    }

    // for linking a compiled regular xpression
    template<typename Char>
    void link(xpression_linker<Char> &linker) const
    {
        linker.accept(*static_cast<Matcher const *>(this), &this->next_);
        this->next_.link(linker);
    }

    // for building a lead-follow
    template<typename Char>
    void peek(xpression_peeker<Char> &peeker) const
    {
        this->peek_next_(peeker.accept(*static_cast<Matcher const *>(this)), peeker);
    }

    // for getting xpression width
    detail::width get_width() const
    {
        return this->get_width_(mpl::size_t<width>());
    }

private:

    static_xpression &operator =(static_xpression const &);

    template<typename Char>
    void peek_next_(mpl::true_, xpression_peeker<Char> &peeker) const
    {
        this->next_.peek(peeker);
    }

    template<typename Char>
    void peek_next_(mpl::false_, xpression_peeker<Char> &) const
    {
        // no-op
    }

    template<std::size_t Width>
    detail::width get_width_(mpl::size_t<Width>) const
    {
        return Width;
    }

    detail::width get_width_(unknown_width) const
    {
        // Should only be called in contexts where the width is
        // known to be fixed.
        return this->Matcher::get_width() + this->next_.get_width();
    }
};

///////////////////////////////////////////////////////////////////////////////
// make_static
//
template<typename Matcher>
inline static_xpression<Matcher> const
make_static(Matcher const &matcher)
{
    return static_xpression<Matcher>(matcher);
}

template<typename Matcher, typename Next>
inline static_xpression<Matcher, Next> const
make_static(Matcher const &matcher, Next const &next)
{
    return static_xpression<Matcher, Next>(matcher, next);
}

///////////////////////////////////////////////////////////////////////////////
// no_next
//
struct no_next
{
    BOOST_STATIC_CONSTANT(std::size_t, width = 0);
    BOOST_STATIC_CONSTANT(bool, pure = true);

    template<typename Char>
    void link(xpression_linker<Char> &) const
    {
    }

    template<typename Char>
    void peek(xpression_peeker<Char> &peeker) const
    {
        peeker.fail();
    }

    detail::width get_width() const
    {
        return 0;
    }
};

///////////////////////////////////////////////////////////////////////////////
// get_mark_number
//
inline int get_mark_number(basic_mark_tag const &mark)
{
    return proto::value(mark).mark_number_;
}

}}} // namespace boost::xpressive::detail

#endif