blob: e63bed2ee576542a9b512b12faf39b738ce18447 [file] [log] [blame]
/*=============================================================================
Copyright (c) 2001-2007 Joel de Guzman
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)
==============================================================================*/
#if !defined(BOOST_SPIRIT_COMPONENT_JAN_14_2007_1102AM)
#define BOOST_SPIRIT_COMPONENT_JAN_14_2007_1102AM
#include <boost/spirit/home/support/unused.hpp>
#include <boost/spirit/home/support/meta_grammar/grammar.hpp>
#include <boost/proto/core.hpp>
#include <boost/fusion/include/at.hpp>
#include <boost/fusion/include/value_at.hpp>
#include <boost/mpl/void.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/apply.hpp>
namespace boost { namespace spirit
{
///////////////////////////////////////////////////////////////////////////
// component generalizes a spirit component. A component can be a parser,
// a primitive-parser, a composite-parser, a generator, etc.
// A component has:
//
// 1) Domain: The world it operates on (purely a type e.g. qi::domain).
// 2) Director: Its Director (purely a type e.g. qi::sequence)
// 3) Elements: For composites, a tuple of components
// For primitives, a tuple of arbitrary information
//
///////////////////////////////////////////////////////////////////////////
template <typename Domain, typename Director, typename Elements>
struct component
{
typedef Domain domain;
typedef Director director;
typedef Elements elements_type;
component()
{
}
component(Elements const& elements)
: elements(elements)
{
}
template <typename Elements2>
component(component<Domain, Director, Elements2> const& other)
: elements(other.elements)
{
// allow copy from components with compatible elements
}
elements_type elements;
};
///////////////////////////////////////////////////////////////////////////
// Utils for extracting child components
///////////////////////////////////////////////////////////////////////////
namespace result_of
{
template <typename Component>
struct subject
{
typedef typename
fusion::result_of::value_at_c<
typename Component::elements_type, 0>::type
type;
};
template <typename Component>
struct left
{
typedef typename
fusion::result_of::value_at_c<
typename Component::elements_type, 0>::type
type;
};
template <typename Component>
struct right
{
typedef typename
fusion::result_of::value_at_c<
typename Component::elements_type, 1>::type
type;
};
template <typename Component>
struct argument1
{
typedef typename
fusion::result_of::value_at_c<
typename Component::elements_type, 1>::type
type;
};
template <typename Component>
struct argument2
{
typedef typename
fusion::result_of::value_at_c<
typename Component::elements_type, 2>::type
type;
};
template<typename Component, int N>
struct arg_c
: fusion::result_of::value_at_c<
typename Component::elements_type, N>
{};
}
template <typename Component>
typename fusion::result_of::at_c<
typename Component::elements_type const, 0>::type
inline subject(Component const& c)
{
return fusion::at_c<0>(c.elements);
}
template <typename Component>
typename fusion::result_of::at_c<
typename Component::elements_type const, 0>::type
inline left(Component const& c)
{
return fusion::at_c<0>(c.elements);
}
template <typename Component>
typename fusion::result_of::at_c<
typename Component::elements_type const, 1>::type
inline right(Component const& c)
{
return fusion::at_c<1>(c.elements);
}
template <typename Component>
typename fusion::result_of::at_c<
typename Component::elements_type const, 1>::type
inline argument1(Component const& c)
{
return fusion::at_c<1>(c.elements);
}
template <typename Component>
typename fusion::result_of::at_c<
typename Component::elements_type const, 2>::type
inline argument2(Component const& c)
{
return fusion::at_c<2>(c.elements);
}
template <int N, typename Component>
typename fusion::result_of::at_c<
typename Component::elements_type const, N>::type
inline arg_c(Component const& c)
{
return fusion::at_c<N>(c.elements);
}
///////////////////////////////////////////////////////////////////////////
// Test if Expr conforms to the grammar of Domain. If Expr is already
// a component, return mpl::true_.
///////////////////////////////////////////////////////////////////////////
namespace traits
{
template <typename Domain, typename Expr>
struct is_component
: proto::matches<
typename proto::result_of::as_expr<Expr>::type
, typename meta_grammar::grammar<Domain>::type
>
{
};
template <typename Domain, typename Director, typename Elements>
struct is_component<Domain, component<Domain, Director, Elements> > :
mpl::true_
{
};
}
///////////////////////////////////////////////////////////////////////////
// Convert an arbitrary expression to a spirit component. There's
// a metafunction in namespace result_of and a function in main
// spirit namespace. If Expr is already a component, return it as-is.
///////////////////////////////////////////////////////////////////////////
namespace result_of
{
template <
typename Domain, typename Expr, typename State = unused_type,
typename Visitor = unused_type
>
struct as_component
{
typedef typename meta_grammar::grammar<Domain>::type grammar;
typedef typename proto::result_of::as_expr<Expr>::type proto_xpr;
typedef typename grammar::template impl<proto_xpr, State, Visitor> callable;
typedef typename callable::result_type type;
};
// special case for arrays
template <
typename Domain, typename T, int N,
typename State, typename Visitor>
struct as_component<Domain, T[N], State, Visitor>
{
typedef typename meta_grammar::grammar<Domain>::type grammar;
typedef typename proto::result_of::as_expr<T const*>::type proto_xpr;
typedef typename grammar::template impl<proto_xpr, State, Visitor> callable;
typedef typename callable::result_type type;
};
// special case for components
template <typename Domain, typename Director, typename Elements>
struct as_component<Domain, component<Domain, Director, Elements> > :
mpl::identity<component<Domain, Director, Elements> >
{
};
}
namespace detail
{
template<typename T>
T &decay(T &t)
{
return t;
}
template<typename T, int N>
T *decay(T (&t)[N])
{
return t;
}
}
template <typename Domain, typename Expr>
inline typename result_of::as_component<Domain, Expr>::type
as_component(Domain, Expr const& xpr)
{
typedef typename result_of::as_component<Domain, Expr>::callable callable;
return callable()(proto::as_expr(detail::decay(xpr)), unused_type(), unused_type());
}
template <typename Domain, typename Expr, typename State, typename Visitor>
inline typename result_of::as_component<Domain, Expr>::type
as_component(Domain, Expr const& xpr, State const& state, Visitor& visitor)
{
typedef typename result_of::as_component<Domain, Expr, State, Visitor>::callable callable;
return callable()(proto::as_expr(detail::decay(xpr)), state, visitor);
}
template <typename Domain, typename Director, typename Elements>
inline component<Domain, Director, Elements> const&
as_component(Domain, component<Domain, Director, Elements> const& component)
{
return component;
}
///////////////////////////////////////////////////////////////////////////
// Create a component. This is a customization point. Components are
// not created directly; they are created through make_component.
// Clients may customize this to direct the creation of a component.
//
// The extra Modifier template parameter may be used to direct the
// creation of the component. This is the Visitor parameter in Proto
// transforms.
//
// (see also: modifier.hpp)
///////////////////////////////////////////////////////////////////////////
namespace traits
{
template <
typename Domain, typename Director
, typename Elements, typename Modifier, typename Enable = void>
struct make_component
: mpl::identity<component<Domain, Director, Elements> >
{
static component<Domain, Director, Elements>
call(Elements const& elements)
{
return component<Domain, Director, Elements>(elements);
}
};
}
}}
#endif