summaryrefslogtreecommitdiff
path: root/boost/xpressive/detail/static/transforms/as_set.hpp
blob: 6d5c25261046d3382baa774047ca60d201de2889 (plain)
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
///////////////////////////////////////////////////////////////////////////////
// as_set.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_TRANSFORMS_AS_SET_HPP_EAN_04_05_2007
#define BOOST_XPRESSIVE_DETAIL_STATIC_TRANSFORMS_AS_SET_HPP_EAN_04_05_2007

// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

#include <boost/mpl/assert.hpp>
#include <boost/proto/core.hpp>
#include <boost/xpressive/detail/detail_fwd.hpp>
#include <boost/xpressive/detail/static/static.hpp>
#include <boost/xpressive/detail/utility/chset/chset.hpp>
#include <boost/xpressive/detail/utility/traits_utils.hpp>

namespace boost { namespace xpressive { namespace grammar_detail
{

    ///////////////////////////////////////////////////////////////////////////
    // CharLiteral
    template<typename Char>
    struct CharLiteral
      : or_<
            terminal<char>
          , terminal<Char>
        >
    {};

    template<>
    struct CharLiteral<char>
      : terminal<char>
    {};

    ///////////////////////////////////////////////////////////////////////////
    // ListSet
    //  matches expressions like (set= 'a','b','c')
    //  calculates the size of the set
    template<typename Char>
    struct ListSet
      : or_<
            when<
                comma<ListSet<Char>, CharLiteral<Char> >
              , make<mpl::next<call<ListSet<Char>(_left)> > > // TODO make a custom transform for this...
            >
          , when<
                assign<detail::set_initializer_type, CharLiteral<Char> >
              , make<mpl::int_<1> >
            >
        >
    {};

    template<typename Char, typename Traits>
    void fill_list_set(Char *&, detail::set_initializer_type, Traits const &)
    {}

    template<typename Char, typename Expr, typename Traits>
    void fill_list_set(Char *&buffer, Expr const &expr, Traits const &traits)
    {
        fill_list_set(buffer, proto::left(expr), traits);
        *buffer++ = traits.translate(detail::char_cast<Char>(proto::value(proto::right(expr)), traits));
    }

    ///////////////////////////////////////////////////////////////////////////////
    // as_list_set_matcher
    template<typename Char, typename Callable = proto::callable>
    struct as_list_set_matcher : proto::transform<as_list_set_matcher<Char, Callable> >
    {
        template<typename Expr, typename State, typename Data>
        struct impl : proto::transform_impl<Expr, State, Data>
        {
            typedef typename impl::data data_type;
            typedef
                detail::set_matcher<
                    typename data_type::traits_type
                  , typename ListSet<Char>::template impl<Expr, State, Data>::result_type
                >
            result_type;

            result_type operator ()(
                typename impl::expr_param expr
              , typename impl::state_param
              , typename impl::data_param data
            ) const
            {
                result_type set;
                typedef typename impl::data data_type;
                typename data_type::char_type *buffer = set.set_;
                fill_list_set(buffer, expr, data.traits());
                return set;
            }
        };
    };

    ///////////////////////////////////////////////////////////////////////////////
    // merge_charset
    //
    template<typename Grammar, typename CharSet, typename Data>
    struct merge_charset
    {
        typedef typename Data::traits_type traits_type;
        typedef typename CharSet::char_type char_type;
        typedef typename CharSet::icase_type icase_type;

        merge_charset(CharSet &charset, Data &data)
          : charset_(charset)
          , visitor_(data)
        {}

        template<typename Expr>
        void operator ()(Expr const &expr) const
        {
            this->call_(expr, typename Expr::proto_tag());
        }

    private:
        merge_charset &operator =(merge_charset const &);

        template<typename Expr, typename Tag>
        void call_(Expr const &expr, Tag) const
        {
            this->set_(
                typename Grammar::template impl<Expr const &, detail::end_xpression, Data &>()(
                    expr
                  , detail::end_xpression()
                  , this->visitor_
                )
            );
        }

        template<typename Expr>
        void call_(Expr const &expr, tag::bitwise_or) const
        {
            (*this)(proto::left(expr));
            (*this)(proto::right(expr));
        }

        template<typename Not>
        void set_(detail::literal_matcher<traits_type, icase_type, Not> const &ch) const
        {
            // BUGBUG fixme!
            BOOST_MPL_ASSERT_NOT((Not));
            set_char(this->charset_.charset_, ch.ch_, this->visitor_.traits(), icase_type());
        }

        void set_(detail::range_matcher<traits_type, icase_type> const &rg) const
        {
            // BUGBUG fixme!
            BOOST_ASSERT(!rg.not_);
            set_range(this->charset_.charset_, rg.ch_min_, rg.ch_max_, this->visitor_.traits(), icase_type());
        }

        template<typename Size>
        void set_(detail::set_matcher<traits_type, Size> const &set_) const
        {
            // BUGBUG fixme!
            BOOST_ASSERT(!set_.not_);
            for(int i = 0; i < Size::value; ++i)
            {
                set_char(this->charset_.charset_, set_.set_[i], this->visitor_.traits(), icase_type());
            }
        }

        void set_(detail::posix_charset_matcher<traits_type> const &posix) const
        {
            set_class(this->charset_.charset_, posix.mask_, posix.not_, this->visitor_.traits());
        }

        CharSet &charset_;
        Data &visitor_;
    };

    ///////////////////////////////////////////////////////////////////////////////
    //
    template<typename Grammar, typename Callable = proto::callable>
    struct as_set_matcher : proto::transform<as_set_matcher<Grammar, Callable> >
    {
        template<typename Expr, typename State, typename Data>
        struct impl : proto::transform_impl<Expr, State, Data>
        {
            typedef typename impl::data data_type;
            typedef typename data_type::char_type char_type;

            // if sizeof(char_type)==1, merge everything into a basic_chset
            // BUGBUG this is not optimal.
            typedef
                typename mpl::if_c<
                    detail::is_narrow_char<char_type>::value
                  , detail::basic_chset<char_type>
                  , detail::compound_charset<typename data_type::traits_type>
                >::type
            charset_type;

            typedef
                detail::charset_matcher<
                    typename data_type::traits_type
                  , typename data_type::icase_type
                  , charset_type
                >
            result_type;

            result_type operator ()(
                typename impl::expr_param expr
              , typename impl::state_param
              , typename impl::data_param data
            ) const
            {
                result_type matcher;
                merge_charset<Grammar, result_type, typename impl::data> merge(matcher, data);
                merge(expr); // Walks the tree and fills in the charset
                return matcher;
            }
        };
    };

}}}

#endif