| /*============================================================================= |
| Copyright (c) 2009 Francois Barel |
| Copyright (c) 2001-2010 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_REPOSITORY_QI_SUBRULE_AUGUST_06_2009_0239AM) |
| #define BOOST_SPIRIT_REPOSITORY_QI_SUBRULE_AUGUST_06_2009_0239AM |
| |
| #if defined(_MSC_VER) |
| #pragma once |
| #endif |
| |
| #include <boost/spirit/home/qi/domain.hpp> |
| #include <boost/spirit/home/qi/meta_compiler.hpp> |
| #include <boost/spirit/home/qi/parser.hpp> |
| #include <boost/spirit/home/qi/reference.hpp> |
| #include <boost/spirit/home/qi/nonterminal/detail/parameterized.hpp> |
| #include <boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp> |
| #include <boost/spirit/home/support/argument.hpp> |
| #include <boost/spirit/home/support/assert_msg.hpp> |
| #include <boost/spirit/home/qi/detail/attributes.hpp> |
| #include <boost/spirit/home/support/info.hpp> |
| #include <boost/spirit/home/support/unused.hpp> |
| #include <boost/spirit/home/support/nonterminal/extract_param.hpp> |
| #include <boost/spirit/home/support/nonterminal/locals.hpp> |
| #include <boost/spirit/repository/home/support/subrule_context.hpp> |
| |
| #include <boost/fusion/include/as_map.hpp> |
| #include <boost/fusion/include/at_key.hpp> |
| #include <boost/fusion/include/cons.hpp> |
| #include <boost/fusion/include/front.hpp> |
| #include <boost/fusion/include/has_key.hpp> |
| #include <boost/fusion/include/join.hpp> |
| #include <boost/fusion/include/make_map.hpp> |
| #include <boost/fusion/include/make_vector.hpp> |
| #include <boost/fusion/include/size.hpp> |
| #include <boost/fusion/include/vector.hpp> |
| #include <boost/mpl/bool.hpp> |
| #include <boost/mpl/identity.hpp> |
| #include <boost/mpl/int.hpp> |
| #include <boost/mpl/vector.hpp> |
| #include <boost/type_traits/add_reference.hpp> |
| #include <boost/type_traits/is_same.hpp> |
| #include <boost/type_traits/remove_reference.hpp> |
| |
| #if defined(BOOST_MSVC) |
| # pragma warning(push) |
| # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning |
| #endif |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace boost { namespace spirit { namespace repository { namespace qi |
| { |
| /////////////////////////////////////////////////////////////////////////// |
| // subrule_group: |
| // - parser representing a group of subrule definitions (one or more), |
| // invokes first subrule on entry, |
| // - also a Proto terminal, so that a group behaves like any Spirit |
| // expression. |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename Defs> |
| struct subrule_group |
| : proto::extends< |
| typename proto::terminal< |
| spirit::qi::reference<subrule_group<Defs> const> |
| >::type |
| , subrule_group<Defs> |
| > |
| , spirit::qi::parser<subrule_group<Defs> > |
| { |
| // Fusion associative sequence, associating each subrule ID in this |
| // group (as an MPL integral constant) with its definition |
| typedef Defs defs_type; |
| |
| typedef subrule_group<Defs> this_type; |
| typedef spirit::qi::reference<this_type const> reference_; |
| typedef typename proto::terminal<reference_>::type terminal; |
| typedef proto::extends<terminal, this_type> base_type; |
| |
| static size_t const params_size = |
| // Forward to first subrule. |
| remove_reference< |
| typename fusion::result_of::front<Defs>::type |
| >::type::second_type::params_size; |
| |
| subrule_group(subrule_group const& rhs) |
| : base_type(terminal::make(reference_(*this))) |
| , defs(rhs.defs) |
| { |
| } |
| |
| explicit subrule_group(Defs const& defs) |
| : base_type(terminal::make(reference_(*this))) |
| , defs(defs) |
| { |
| } |
| |
| // from a subrule ID, get the type of a reference to its definition |
| template <int ID> |
| struct def_type |
| { |
| typedef mpl::int_<ID> id_type; |
| |
| // If you are seeing a compilation error here, you are trying |
| // to use a subrule which was not defined in this group. |
| BOOST_SPIRIT_ASSERT_MSG( |
| (fusion::result_of::has_key< |
| defs_type const, id_type>::type::value) |
| , subrule_used_without_being_defined, (mpl::int_<ID>)); |
| |
| typedef typename |
| fusion::result_of::at_key<defs_type const, id_type>::type |
| type; |
| }; |
| |
| // from a subrule ID, get a reference to its definition |
| template <int ID> |
| typename def_type<ID>::type def() const |
| { |
| return fusion::at_key<mpl::int_<ID> >(defs); |
| } |
| |
| template <typename Context, typename Iterator> |
| struct attribute |
| // Forward to first subrule. |
| : mpl::identity< |
| typename remove_reference< |
| typename fusion::result_of::front<Defs>::type |
| >::type::second_type::attr_type> {}; |
| |
| template <typename Iterator, typename Context |
| , typename Skipper, typename Attribute> |
| bool parse(Iterator& first, Iterator const& last |
| , Context& context, Skipper const& skipper |
| , Attribute& attr) const |
| { |
| // Forward to first subrule. |
| return parse_subrule(fusion::front(defs).second |
| , first, last, context, skipper, attr); |
| } |
| |
| template <typename Iterator, typename Context |
| , typename Skipper, typename Attribute, typename Params> |
| bool parse(Iterator& first, Iterator const& last |
| , Context& context, Skipper const& skipper |
| , Attribute& attr, Params const& params) const |
| { |
| // Forward to first subrule. |
| return parse_subrule(fusion::front(defs).second |
| , first, last, context, skipper, attr, params); |
| } |
| |
| template <int ID, typename Iterator, typename Context |
| , typename Skipper, typename Attribute> |
| bool parse_subrule_id(Iterator& first, Iterator const& last |
| , Context& context, Skipper const& skipper |
| , Attribute& attr) const |
| { |
| return parse_subrule(def<ID>() |
| , first, last, context, skipper, attr); |
| } |
| |
| template <int ID, typename Iterator, typename Context |
| , typename Skipper, typename Attribute, typename Params> |
| bool parse_subrule_id(Iterator& first, Iterator const& last |
| , Context& context, Skipper const& skipper |
| , Attribute& attr, Params const& params) const |
| { |
| return parse_subrule(def<ID>() |
| , first, last, context, skipper, attr, params); |
| } |
| |
| template <typename Def |
| , typename Iterator, typename Context |
| , typename Skipper, typename Attribute> |
| bool parse_subrule(Def const& def |
| , Iterator& first, Iterator const& last |
| , Context& /*caller_context*/, Skipper const& skipper |
| , Attribute& attr) const |
| { |
| // compute context type for this subrule |
| typedef typename Def::locals_type subrule_locals_type; |
| typedef typename Def::attr_type subrule_attr_type; |
| typedef typename Def::attr_reference_type subrule_attr_reference_type; |
| typedef typename Def::parameter_types subrule_parameter_types; |
| |
| typedef |
| subrule_context< |
| this_type |
| , fusion::cons< |
| subrule_attr_reference_type, subrule_parameter_types> |
| , subrule_locals_type |
| > |
| context_type; |
| |
| // prepare attribute |
| typedef traits::make_attribute< |
| subrule_attr_type, Attribute> make_attribute; |
| |
| // do down-stream transformation, provides attribute for |
| // rhs parser |
| typedef traits::transform_attribute< |
| typename make_attribute::type, subrule_attr_type, domain> |
| transform; |
| |
| typename make_attribute::type made_attr = make_attribute::call(attr); |
| typename transform::type attr_ = transform::pre(made_attr); |
| |
| // If you are seeing a compilation error here, you are probably |
| // trying to use a subrule which has inherited attributes, |
| // without passing values for them. |
| context_type context(*this, attr_); |
| |
| if (def.binder(first, last, context, skipper)) |
| { |
| // do up-stream transformation, this integrates the results |
| // back into the original attribute value, if appropriate |
| traits::post_transform(attr, attr_); |
| return true; |
| } |
| |
| // inform attribute transformation of failed rhs |
| traits::fail_transform(attr, attr_); |
| return false; |
| } |
| |
| template <typename Def |
| , typename Iterator, typename Context |
| , typename Skipper, typename Attribute, typename Params> |
| bool parse_subrule(Def const& def |
| , Iterator& first, Iterator const& last |
| , Context& caller_context, Skipper const& skipper |
| , Attribute& attr, Params const& params) const |
| { |
| // compute context type for this subrule |
| typedef typename Def::locals_type subrule_locals_type; |
| typedef typename Def::attr_type subrule_attr_type; |
| typedef typename Def::attr_reference_type subrule_attr_reference_type; |
| typedef typename Def::parameter_types subrule_parameter_types; |
| |
| typedef |
| subrule_context< |
| this_type |
| , fusion::cons< |
| subrule_attr_reference_type, subrule_parameter_types> |
| , subrule_locals_type |
| > |
| context_type; |
| |
| // prepare attribute |
| typedef traits::make_attribute< |
| subrule_attr_type, Attribute> make_attribute; |
| |
| // do down-stream transformation, provides attribute for |
| // rhs parser |
| typedef traits::transform_attribute< |
| typename make_attribute::type, subrule_attr_type, domain> |
| transform; |
| |
| typename make_attribute::type made_attr = make_attribute::call(attr); |
| typename transform::type attr_ = transform::pre(made_attr); |
| |
| // If you are seeing a compilation error here, you are probably |
| // trying to use a subrule which has inherited attributes, |
| // passing values of incompatible types for them. |
| context_type context(*this, attr_, params, caller_context); |
| |
| if (def.binder(first, last, context, skipper)) |
| { |
| // do up-stream transformation, this integrates the results |
| // back into the original attribute value, if appropriate |
| traits::post_transform(attr, attr_); |
| return true; |
| } |
| |
| // inform attribute transformation of failed rhs |
| traits::fail_transform(attr, attr_); |
| return false; |
| } |
| |
| template <typename Context> |
| info what(Context& context) const |
| { |
| // Forward to first subrule. |
| return fusion::front(defs).second.binder.p.what(context); |
| } |
| |
| template <typename Defs2> |
| subrule_group< |
| typename fusion::result_of::as_map< |
| typename fusion::result_of::join< |
| Defs const, Defs2 const>::type>::type> |
| operator,(subrule_group<Defs2> const& other) const |
| { |
| typedef subrule_group< |
| typename fusion::result_of::as_map< |
| typename fusion::result_of::join< |
| Defs const, Defs2 const>::type>::type> result_type; |
| return result_type(fusion::as_map(fusion::join(defs, other.defs))); |
| } |
| |
| // bring in the operator() overloads |
| this_type const& get_parameterized_subject() const { return *this; } |
| typedef this_type parameterized_subject_type; |
| #include <boost/spirit/home/qi/nonterminal/detail/fcall.hpp> |
| |
| Defs defs; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // subrule_definition: holds one particular definition of a subrule |
| /////////////////////////////////////////////////////////////////////////// |
| template < |
| int ID_ |
| , typename Locals |
| , typename Attr |
| , typename AttrRef |
| , typename Parameters |
| , size_t ParamsSize |
| , typename Subject |
| , bool Auto_ |
| > |
| struct subrule_definition |
| { |
| typedef mpl::int_<ID_> id_type; |
| BOOST_STATIC_CONSTANT(int, ID = ID_); |
| |
| typedef Locals locals_type; |
| typedef Attr attr_type; |
| typedef AttrRef attr_reference_type; |
| typedef Parameters parameter_types; |
| static size_t const params_size = ParamsSize; |
| |
| typedef Subject subject_type; |
| typedef mpl::bool_<Auto_> auto_type; |
| BOOST_STATIC_CONSTANT(bool, Auto = Auto_); |
| |
| typedef spirit::qi::detail::parser_binder< |
| Subject, auto_type> binder_type; |
| |
| subrule_definition(Subject const& subject, std::string const& name) |
| : binder(subject), name(name) |
| { |
| } |
| |
| binder_type const binder; |
| std::string const name; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // subrule placeholder: |
| // - on subrule definition: helper for creation of subrule_group, |
| // - on subrule invocation: Proto terminal and parser. |
| /////////////////////////////////////////////////////////////////////////// |
| template < |
| int ID_ |
| , typename T1 = unused_type |
| , typename T2 = unused_type |
| > |
| struct subrule |
| : proto::extends< |
| typename proto::terminal< |
| spirit::qi::reference<subrule<ID_, T1, T2> const> |
| >::type |
| , subrule<ID_, T1, T2> |
| > |
| , spirit::qi::parser<subrule<ID_, T1, T2> > |
| { |
| typedef mpl::int_<ID_> id_type; |
| BOOST_STATIC_CONSTANT(int, ID = ID_); |
| |
| typedef subrule<ID_, T1, T2> this_type; |
| typedef spirit::qi::reference<this_type const> reference_; |
| typedef typename proto::terminal<reference_>::type terminal; |
| typedef proto::extends<terminal, this_type> base_type; |
| |
| typedef mpl::vector<T1, T2> template_params; |
| |
| // locals_type is a sequence of types to be used as local variables |
| typedef typename |
| spirit::detail::extract_locals<template_params>::type |
| locals_type; |
| |
| typedef typename |
| spirit::detail::extract_sig<template_params>::type |
| sig_type; |
| |
| // This is the subrule's attribute type |
| typedef typename |
| spirit::detail::attr_from_sig<sig_type>::type |
| attr_type; |
| typedef typename add_reference<attr_type>::type attr_reference_type; |
| |
| // parameter_types is a sequence of types passed as parameters to the subrule |
| typedef typename |
| spirit::detail::params_from_sig<sig_type>::type |
| parameter_types; |
| |
| static size_t const params_size = |
| fusion::result_of::size<parameter_types>::type::value; |
| |
| explicit subrule(std::string const& name_ = "unnamed-subrule") |
| : base_type(terminal::make(reference_(*this))) |
| , name_(name_) |
| { |
| } |
| |
| // compute type of this subrule's definition for expr type Expr |
| template <typename Expr, bool Auto> |
| struct def_type_helper |
| { |
| // Report invalid expression error as early as possible. |
| // If you got an error_invalid_expression error message here, |
| // then the expression (Expr) is not a valid spirit qi expression. |
| BOOST_SPIRIT_ASSERT_MATCH(spirit::qi::domain, Expr); |
| |
| typedef typename result_of::compile< |
| spirit::qi::domain, Expr>::type subject_type; |
| |
| typedef subrule_definition< |
| ID_ |
| , locals_type |
| , attr_type |
| , attr_reference_type |
| , parameter_types |
| , params_size |
| , subject_type |
| , Auto |
| > const type; |
| }; |
| |
| // compute type of subrule group containing only this |
| // subrule's definition for expr type Expr |
| template <typename Expr, bool Auto> |
| struct group_type_helper |
| { |
| typedef typename def_type_helper<Expr, Auto>::type def_type; |
| |
| // create Defs map with only one entry: (ID -> def) |
| typedef typename |
| fusion::result_of::make_map<id_type, def_type>::type |
| defs_type; |
| |
| typedef subrule_group<defs_type> type; |
| }; |
| |
| template <typename Expr> |
| typename group_type_helper<Expr, false>::type |
| operator=(Expr const& expr) const |
| { |
| typedef group_type_helper<Expr, false> helper; |
| typedef typename helper::def_type def_type; |
| typedef typename helper::type result_type; |
| return result_type(fusion::make_map<id_type>( |
| def_type(compile<spirit::qi::domain>(expr), name_))); |
| } |
| |
| template <typename Expr> |
| friend typename group_type_helper<Expr, true>::type |
| operator%=(subrule const& sr, Expr const& expr) |
| { |
| typedef group_type_helper<Expr, true> helper; |
| typedef typename helper::def_type def_type; |
| typedef typename helper::type result_type; |
| return result_type(fusion::make_map<id_type>( |
| def_type(compile<spirit::qi::domain>(expr), sr.name_))); |
| } |
| |
| // non-const versions needed to suppress proto's %= kicking in |
| template <typename Expr> |
| friend typename group_type_helper<Expr, true>::type |
| operator%=(subrule const& sr, Expr& expr) |
| { |
| return operator%=( |
| sr |
| , static_cast<Expr const&>(expr)); |
| } |
| template <typename Expr> |
| friend typename group_type_helper<Expr, true>::type |
| operator%=(subrule& sr, Expr const& expr) |
| { |
| return operator%=( |
| static_cast<subrule const&>(sr) |
| , expr); |
| } |
| template <typename Expr> |
| friend typename group_type_helper<Expr, true>::type |
| operator%=(subrule& sr, Expr& expr) |
| { |
| return operator%=( |
| static_cast<subrule const&>(sr) |
| , static_cast<Expr const&>(expr)); |
| } |
| |
| std::string const& name() const |
| { |
| return name_; |
| } |
| |
| void name(std::string const& str) |
| { |
| name_ = str; |
| } |
| |
| template <typename Context, typename Iterator> |
| struct attribute |
| { |
| typedef attr_type type; |
| }; |
| |
| template <typename Iterator, typename Group |
| , typename Attributes, typename Locals |
| , typename Skipper, typename Attribute> |
| bool parse(Iterator& first, Iterator const& last |
| , subrule_context<Group, Attributes, Locals>& context |
| , Skipper const& skipper, Attribute& attr) const |
| { |
| return context.group.template parse_subrule_id<ID_>( |
| first, last, context, skipper, attr); |
| } |
| |
| template <typename Iterator, typename Context |
| , typename Skipper, typename Attribute> |
| bool parse(Iterator& /*first*/, Iterator const& /*last*/ |
| , Context& /*context*/ |
| , Skipper const& /*skipper*/, Attribute& /*attr*/) const |
| { |
| // If you are seeing a compilation error here, you are trying |
| // to use a subrule as a parser outside of a subrule group. |
| BOOST_SPIRIT_ASSERT_MSG(false |
| , subrule_used_outside_subrule_group, (id_type)); |
| |
| return false; |
| } |
| |
| template <typename Iterator, typename Group |
| , typename Attributes, typename Locals |
| , typename Skipper, typename Attribute |
| , typename Params> |
| bool parse(Iterator& first, Iterator const& last |
| , subrule_context<Group, Attributes, Locals>& context |
| , Skipper const& skipper, Attribute& attr |
| , Params const& params) const |
| { |
| return context.group.template parse_subrule_id<ID_>( |
| first, last, context, skipper, attr, params); |
| } |
| |
| template <typename Iterator, typename Context |
| , typename Skipper, typename Attribute |
| , typename Params> |
| bool parse(Iterator& /*first*/, Iterator const& /*last*/ |
| , Context& /*context*/ |
| , Skipper const& /*skipper*/, Attribute& /*attr*/ |
| , Params const& /*params*/) const |
| { |
| // If you are seeing a compilation error here, you are trying |
| // to use a subrule as a parser outside of a subrule group. |
| BOOST_SPIRIT_ASSERT_MSG(false |
| , subrule_used_outside_subrule_group, (id_type)); |
| |
| return false; |
| } |
| |
| template <typename Context> |
| info what(Context& /*context*/) const |
| { |
| return info(name_); |
| } |
| |
| // bring in the operator() overloads |
| this_type const& get_parameterized_subject() const { return *this; } |
| typedef this_type parameterized_subject_type; |
| #include <boost/spirit/home/qi/nonterminal/detail/fcall.hpp> |
| |
| std::string name_; |
| }; |
| }}}} |
| |
| #if defined(BOOST_MSVC) |
| # pragma warning(pop) |
| #endif |
| |
| #endif |