1 /*=============================================================================
2     Copyright (c) 2001-2011 Joel de Guzman
3 
4     Distributed under the Boost Software License, Version 1.0. (See accompanying
5     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 ==============================================================================*/
7 #if !defined(BOOST_SPIRIT_SYMBOLS_MARCH_11_2007_1055AM)
8 #define BOOST_SPIRIT_SYMBOLS_MARCH_11_2007_1055AM
9 
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13 
14 #include <boost/spirit/home/qi/domain.hpp>
15 #include <boost/spirit/home/qi/skip_over.hpp>
16 #include <boost/spirit/home/qi/string/tst.hpp>
17 #include <boost/spirit/home/qi/reference.hpp>
18 #include <boost/spirit/home/qi/meta_compiler.hpp>
19 #include <boost/spirit/home/qi/detail/assign_to.hpp>
20 #include <boost/spirit/home/qi/parser.hpp>
21 #include <boost/spirit/home/support/detail/get_encoding.hpp>
22 #include <boost/spirit/home/support/modify.hpp>
23 #include <boost/spirit/home/support/info.hpp>
24 #include <boost/spirit/home/support/unused.hpp>
25 #include <boost/spirit/home/support/string_traits.hpp>
26 #include <boost/proto/extends.hpp>
27 #include <boost/proto/traits.hpp>
28 #include <boost/range/begin.hpp>
29 #include <boost/range/end.hpp>
30 #include <boost/shared_ptr.hpp>
31 
32 #if defined(BOOST_MSVC)
33 # pragma warning(push)
34 # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning
35 #endif
36 
37 namespace boost { namespace spirit { namespace qi
38 {
39     template <
40         typename Char = char
41       , typename T = unused_type
42       , typename Lookup = tst<Char, T>
43       , typename Filter = tst_pass_through>
44     struct symbols
45       : proto::extends<
46             typename proto::terminal<
47                 reference<symbols<Char, T, Lookup, Filter> >
48             >::type
49           , symbols<Char, T, Lookup, Filter>
50         >
51       , primitive_parser<symbols<Char, T, Lookup, Filter> >
52     {
53         typedef Char char_type; // the character type
54         typedef T value_type; // the value associated with each entry
55         typedef symbols<Char, T, Lookup, Filter> this_type;
56         typedef reference<this_type> reference_;
57         typedef typename proto::terminal<reference_>::type terminal;
58         typedef proto::extends<terminal, this_type> base_type;
59 
60         template <typename Context, typename Iterator>
61         struct attribute
62         {
63             typedef value_type type;
64         };
65 
symbolsboost::spirit::qi::symbols66         symbols(std::string const& name = "symbols")
67           : base_type(terminal::make(reference_(*this)))
68           , add(*this)
69           , remove(*this)
70           , lookup(new Lookup())
71           , name_(name)
72         {
73         }
74 
symbolsboost::spirit::qi::symbols75         symbols(symbols const& syms)
76           : base_type(terminal::make(reference_(*this)))
77           , add(*this)
78           , remove(*this)
79           , lookup(syms.lookup)
80           , name_(syms.name_)
81         {
82         }
83 
84         template <typename Filter_>
symbolsboost::spirit::qi::symbols85         symbols(symbols<Char, T, Lookup, Filter_> const& syms)
86           : base_type(terminal::make(reference_(*this)))
87           , add(*this)
88           , remove(*this)
89           , lookup(syms.lookup)
90           , name_(syms.name_)
91         {
92         }
93 
94         template <typename Symbols>
symbolsboost::spirit::qi::symbols95         symbols(Symbols const& syms, std::string const& name = "symbols")
96           : base_type(terminal::make(reference_(*this)))
97           , add(*this)
98           , remove(*this)
99           , lookup(new Lookup())
100           , name_(name)
101         {
102             typename range_const_iterator<Symbols>::type si = boost::begin(syms);
103             while (si != boost::end(syms))
104                 add(*si++);
105         }
106 
107         template <typename Symbols, typename Data>
symbolsboost::spirit::qi::symbols108         symbols(Symbols const& syms, Data const& data
109               , std::string const& name = "symbols")
110           : base_type(terminal::make(reference_(*this)))
111           , add(*this)
112           , remove(*this)
113           , lookup(new Lookup())
114           , name_(name)
115         {
116             typename range_const_iterator<Symbols>::type si = boost::begin(syms);
117             typename range_const_iterator<Data>::type di = boost::begin(data);
118             while (si != boost::end(syms))
119                 add(*si++, *di++);
120         }
121 
122         symbols&
operator =boost::spirit::qi::symbols123         operator=(symbols const& rhs)
124         {
125             name_ = rhs.name_;
126             *lookup = *rhs.lookup;
127             return *this;
128         }
129 
130         template <typename Filter_>
131         symbols&
operator =boost::spirit::qi::symbols132         operator=(symbols<Char, T, Lookup, Filter_> const& rhs)
133         {
134             name_ = rhs.name_;
135             *lookup = *rhs.lookup;
136             return *this;
137         }
138 
clearboost::spirit::qi::symbols139         void clear()
140         {
141             lookup->clear();
142         }
143 
144         struct adder;
145         struct remover;
146 
147         template <typename Str>
148         adder const&
operator =boost::spirit::qi::symbols149         operator=(Str const& str)
150         {
151             lookup->clear();
152             return add(str);
153         }
154 
155         template <typename Str>
156         friend adder const&
operator +=(symbols & sym,Str const & str)157         operator+=(symbols& sym, Str const& str)
158         {
159             return sym.add(str);
160         }
161 
162         template <typename Str>
163         friend remover const&
operator -=(symbols & sym,Str const & str)164         operator-=(symbols& sym, Str const& str)
165         {
166             return sym.remove(str);
167         }
168 
169 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
170         // non-const version needed to suppress proto's += kicking in
171         template <typename Str>
172         friend adder const&
operator +=(symbols & sym,Str & str)173         operator+=(symbols& sym, Str& str)
174         {
175             return sym.add(str);
176         }
177 
178         // non-const version needed to suppress proto's -= kicking in
179         template <typename Str>
180         friend remover const&
operator -=(symbols & sym,Str & str)181         operator-=(symbols& sym, Str& str)
182         {
183             return sym.remove(str);
184         }
185 #else
186         // for rvalue references
187         template <typename Str>
188         friend adder const&
operator +=(symbols & sym,Str && str)189         operator+=(symbols& sym, Str&& str)
190         {
191             return sym.add(str);
192         }
193 
194         // for rvalue references
195         template <typename Str>
196         friend remover const&
operator -=(symbols & sym,Str && str)197         operator-=(symbols& sym, Str&& str)
198         {
199             return sym.remove(str);
200         }
201 #endif
202         template <typename F>
for_eachboost::spirit::qi::symbols203         void for_each(F f) const
204         {
205             lookup->for_each(f);
206         }
207 
208         template <typename Str>
atboost::spirit::qi::symbols209         value_type& at(Str const& str)
210         {
211             return *lookup->add(traits::get_begin<Char>(str)
212                 , traits::get_end<Char>(str), T());
213         }
214 
215         template <typename Iterator>
prefix_findboost::spirit::qi::symbols216         value_type* prefix_find(Iterator& first, Iterator const& last)
217         {
218             return lookup->find(first, last, Filter());
219         }
220 
221         template <typename Iterator>
prefix_findboost::spirit::qi::symbols222         value_type const* prefix_find(Iterator& first, Iterator const& last) const
223         {
224             return lookup->find(first, last, Filter());
225         }
226 
227         template <typename Str>
findboost::spirit::qi::symbols228         value_type* find(Str const& str)
229         {
230             return find_impl(traits::get_begin<Char>(str)
231                 , traits::get_end<Char>(str));
232         }
233 
234         template <typename Str>
findboost::spirit::qi::symbols235         value_type const* find(Str const& str) const
236         {
237             return find_impl(traits::get_begin<Char>(str)
238                 , traits::get_end<Char>(str));
239         }
240 
241 private:
242         template <typename Iterator>
find_implboost::spirit::qi::symbols243         value_type* find_impl(Iterator begin, Iterator end)
244         {
245             value_type* r = lookup->find(begin, end, Filter());
246             return begin == end ? r : 0;
247         }
248 
249         template <typename Iterator>
find_implboost::spirit::qi::symbols250         value_type const* find_impl(Iterator begin, Iterator end) const
251         {
252             value_type const* r = lookup->find(begin, end, Filter());
253             return begin == end ? r : 0;
254         }
255 
256 public:
257         template <typename Iterator, typename Context
258           , typename Skipper, typename Attribute>
parseboost::spirit::qi::symbols259         bool parse(Iterator& first, Iterator const& last
260           , Context& /*context*/, Skipper const& skipper, Attribute& attr_) const
261         {
262             qi::skip_over(first, last, skipper);
263 
264             if (value_type* val_ptr
265                 = lookup->find(first, last, Filter()))
266             {
267                 spirit::traits::assign_to(*val_ptr, attr_);
268                 return true;
269             }
270             return false;
271         }
272 
273         template <typename Context>
whatboost::spirit::qi::symbols274         info what(Context& /*context*/) const
275         {
276             return info(name_);
277         }
278 
nameboost::spirit::qi::symbols279         void name(std::string const &str)
280         {
281             name_ = str;
282         }
nameboost::spirit::qi::symbols283         std::string const &name() const
284         {
285             return name_;
286         }
287 
288         struct adder
289         {
290             template <typename, typename = unused_type, typename = unused_type>
291             struct result { typedef adder const& type; };
292 
adderboost::spirit::qi::symbols::adder293             adder(symbols& sym_)
294               : sym(sym_)
295             {
296             }
297 
298             template <typename Iterator>
299             adder const&
operator ()boost::spirit::qi::symbols::adder300             operator()(Iterator const& first, Iterator const& last, T const& val) const
301             {
302                 sym.lookup->add(first, last, val);
303                 return *this;
304             }
305 
306             template <typename Str>
307             adder const&
operator ()boost::spirit::qi::symbols::adder308             operator()(Str const& s, T const& val = T()) const
309             {
310                 sym.lookup->add(traits::get_begin<Char>(s)
311                   , traits::get_end<Char>(s), val);
312                 return *this;
313             }
314 
315             template <typename Str>
316             adder const&
operator ,boost::spirit::qi::symbols::adder317             operator,(Str const& s) const
318             {
319                 sym.lookup->add(traits::get_begin<Char>(s)
320                   , traits::get_end<Char>(s), T());
321                 return *this;
322             }
323 
324             symbols& sym;
325 
326             // silence MSVC warning C4512: assignment operator could not be generated
327             BOOST_DELETED_FUNCTION(adder& operator= (adder const&))
328         };
329 
330         struct remover
331         {
332             template <typename, typename = unused_type, typename = unused_type>
333             struct result { typedef remover const& type; };
334 
removerboost::spirit::qi::symbols::remover335             remover(symbols& sym_)
336               : sym(sym_)
337             {
338             }
339 
340             template <typename Iterator>
341             remover const&
operator ()boost::spirit::qi::symbols::remover342             operator()(Iterator const& first, Iterator const& last) const
343             {
344                 sym.lookup->remove(first, last);
345                 return *this;
346             }
347 
348             template <typename Str>
349             remover const&
operator ()boost::spirit::qi::symbols::remover350             operator()(Str const& s) const
351             {
352                 sym.lookup->remove(traits::get_begin<Char>(s)
353                   , traits::get_end<Char>(s));
354                 return *this;
355             }
356 
357             template <typename Str>
358             remover const&
operator ,boost::spirit::qi::symbols::remover359             operator,(Str const& s) const
360             {
361                 sym.lookup->remove(traits::get_begin<Char>(s)
362                   , traits::get_end<Char>(s));
363                 return *this;
364             }
365 
366             symbols& sym;
367 
368             // silence MSVC warning C4512: assignment operator could not be generated
369             BOOST_DELETED_FUNCTION(remover& operator= (remover const&))
370         };
371 
372         adder add;
373         remover remove;
374         shared_ptr<Lookup> lookup;
375         std::string name_;
376     };
377 
378     ///////////////////////////////////////////////////////////////////////////
379     // Parser generators: make_xxx function (objects)
380     ///////////////////////////////////////////////////////////////////////////
381     template <typename Char, typename T, typename Lookup
382       , typename Filter, typename Modifiers>
383     struct make_primitive<reference<symbols<Char, T, Lookup, Filter> >, Modifiers>
384     {
385         template <typename CharEncoding>
386         struct no_case_filter
387         {
operator ()boost::spirit::qi::make_primitive::no_case_filter388             Char operator()(Char ch) const
389             {
390                 return static_cast<Char>(CharEncoding::tolower(ch));
391             }
392         };
393 
394         typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case;
395         typedef reference<symbols<Char, T, Lookup, Filter> > reference_;
396         typedef no_case_filter<
397             typename spirit::detail::get_encoding_with_case<
398                 Modifiers
399               , char_encoding::standard
400               , no_case::value>::type>
401         nc_filter;
402 
403         typedef typename mpl::if_<
404             no_case
405           , symbols<Char, T, Lookup, nc_filter>
406           , reference_>::type
407         result_type;
408 
operator ()boost::spirit::qi::make_primitive409         result_type operator()(reference_ ref, unused_type) const
410         {
411             return result_type(ref.ref.get());
412         }
413     };
414 }}}
415 
416 namespace boost { namespace spirit { namespace traits
417 {
418     ///////////////////////////////////////////////////////////////////////////
419     template <typename Char, typename T, typename Lookup, typename Filter
420       , typename Attr, typename Context, typename Iterator>
421     struct handles_container<qi::symbols<Char, T, Lookup, Filter>, Attr, Context, Iterator>
422       : traits::is_container<Attr> {};
423 }}}
424 
425 #if defined(BOOST_MSVC)
426 # pragma warning(pop)
427 #endif
428 
429 #endif
430