boost/xpressive/detail/static/transforms/as_set.hpp
///////////////////////////////////////////////////////////////////////////////
// as_set.hpp
//
// Copyright 2007 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/xpressive/proto/proto.hpp>
#include <boost/xpressive/proto/transform/arg.hpp>
#include <boost/xpressive/proto/transform/apply.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 detail
{
template<typename I>
typename I::next next_(I)
{
return typename I::next();
}
template<typename Grammar>
struct next
: Grammar
{
next();
template<typename Expr, typename State, typename Visitor>
struct apply
: Grammar::template apply<Expr, State, Visitor>::type::next
{};
template<typename Expr, typename State, typename Visitor>
static typename apply<Expr, State, Visitor>::type
call(Expr const &expr, State const &state, Visitor &visitor)
{
return detail::next_(Grammar::call(expr, state, visitor));
}
};
template<typename Grammar>
struct push_back
: Grammar
{
push_back();
template<typename Expr, typename State, typename Visitor>
static typename Grammar::template apply<Expr, State, Visitor>::type
call(Expr const &expr, State const &state, Visitor &visitor)
{
visitor.accept(proto::arg(expr));
return Grammar::call(expr, state, visitor);
}
};
///////////////////////////////////////////////////////////////////////////
// CharLiteral
template<typename Char>
struct CharLiteral
: proto::or_<
proto::terminal<char>
, proto::terminal<Char>
>
{};
template<>
struct CharLiteral<char>
: proto::terminal<char>
{};
///////////////////////////////////////////////////////////////////////////
// ListSet
// matches expressions like (set= 'a','b','c')
// calculates the size of the set
// populates an array of characters
template<typename Char>
struct ListSet
: proto::transform::left<
proto::or_<
proto::comma<
next<ListSet<Char> >
, push_back<CharLiteral<Char> >
>
, proto::assign<
proto::transform::always<set_initializer_type, mpl::int_<1> >
, push_back<CharLiteral<Char> >
>
>
>
{};
///////////////////////////////////////////////////////////////////////////
// set_fill_visitor
template<typename Traits>
struct set_fill_visitor
{
typedef typename Traits::char_type char_type;
set_fill_visitor(char_type *buffer, Traits const &traits)
: buffer_(buffer)
, traits_(traits)
{}
template<typename Char>
void accept(Char ch)
{
*this->buffer_++ = this->traits_.translate(
char_cast<typename Traits::char_type>(ch, this->traits_)
);
}
char_type *buffer_;
Traits const &traits_;
};
///////////////////////////////////////////////////////////////////////////////
// as_list_set
template<typename Grammar>
struct as_list_set
: Grammar
{
as_list_set();
template<typename Expr, typename State, typename Visitor>
struct apply
{
typedef typename Visitor::traits_type traits_type;
typedef set_matcher<
traits_type
, Grammar::template apply<Expr, State, set_fill_visitor<traits_type> >::type::value
> type;
};
template<typename Expr, typename State, typename Visitor>
static typename apply<Expr, State, Visitor>::type
call(Expr const &expr, State const &state, Visitor &visitor)
{
typename apply<Expr, State, Visitor>::type set;
set_fill_visitor<typename Visitor::traits_type> filler(set.set_, visitor.traits());
Grammar::call(expr, state, filler);
return set;
}
};
///////////////////////////////////////////////////////////////////////////////
// charset_context
//
template<typename Grammar, typename CharSet, typename Visitor>
struct charset_context
{
template<typename Expr, typename Tag>
struct eval_
{
typedef void result_type;
void operator()(Expr const &expr, charset_context const &ctx) const
{
ctx.set(Grammar::call(expr, end_xpression(), ctx.visitor_));
}
};
template<typename Expr>
struct eval_<Expr, proto::tag::bitwise_or>
{
typedef void result_type;
void operator()(Expr const &expr, charset_context const &ctx) const
{
proto::eval(proto::left(expr), ctx);
proto::eval(proto::right(expr), ctx);
}
};
// Gah, this is to work around a MSVC bug.
template<typename Expr>
struct eval
: eval_<Expr, typename Expr::proto_tag>
{};
typedef typename Visitor::traits_type traits_type;
typedef typename CharSet::char_type char_type;
typedef typename CharSet::icase_type icase_type;
explicit charset_context(CharSet &charset, Visitor &visitor)
: charset_(charset)
, visitor_(visitor)
{}
template<bool Not>
void set(literal_matcher<traits_type, icase_type::value, Not> const &ch) const
{
// BUGBUG fixme!
BOOST_MPL_ASSERT_NOT((mpl::bool_<Not>));
set_char(this->charset_.charset_, ch.ch_, this->visitor_.traits(), icase_type());
}
void set(range_matcher<traits_type, icase_type::value> 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<int Size>
void set(set_matcher<traits_type, Size> const &set_) const
{
// BUGBUG fixme!
BOOST_ASSERT(!set_.not_);
for(int i=0; i<Size; ++i)
{
set_char(this->charset_.charset_, set_.set_[i], this->visitor_.traits(), icase_type::value);
}
}
void set(posix_charset_matcher<traits_type> const &posix) const
{
set_class(this->charset_.charset_, posix.mask_, posix.not_, this->visitor_.traits());
}
CharSet &charset_;
Visitor &visitor_;
};
///////////////////////////////////////////////////////////////////////////////
//
template<typename Grammar>
struct as_set
: Grammar
{
as_set();
template<typename, typename, typename Visitor>
struct apply
{
typedef typename Visitor::char_type char_type;
// if sizeof(char_type)==1, merge everything into a basic_chset
// BUGBUG this is not optimal.
typedef typename mpl::if_<
is_narrow_char<char_type>
, basic_chset<char_type>
, compound_charset<typename Visitor::traits_type>
>::type charset_type;
typedef charset_matcher<
typename Visitor::traits_type
, Visitor::icase_type::value
, charset_type
> type;
};
template<typename Expr, typename State, typename Visitor>
static typename apply<Expr, State, Visitor>::type
call(Expr const &expr, State const &, Visitor &visitor)
{
typedef typename apply<Expr, State, Visitor>::type set_type;
set_type matcher;
charset_context<Grammar, set_type, Visitor> ctx(matcher, visitor);
// Walks the tree and fills in the charset
proto::eval(expr, ctx);
return matcher;
}
};
}}}
#endif