/*============================================================================= 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 struct subrule_group : proto::extends< typename proto::terminal< spirit::qi::reference const> >::type , subrule_group > , spirit::qi::parser > { // 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 this_type; typedef spirit::qi::reference reference_; typedef typename proto::terminal::type terminal; typedef proto::extends base_type; static size_t const params_size = // Forward to first subrule. remove_reference< typename fusion::result_of::front::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 struct def_type { typedef mpl::int_ 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_)); typedef typename fusion::result_of::at_key::type type; }; // from a subrule ID, get a reference to its definition template typename def_type::type def() const { return fusion::at_key >(defs); } template struct attribute // Forward to first subrule. : mpl::identity< typename remove_reference< typename fusion::result_of::front::type >::type::second_type::attr_type> {}; template 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 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 bool parse_subrule_id(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper , Attribute& attr) const { return parse_subrule(def() , first, last, context, skipper, attr); } template bool parse_subrule_id(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper , Attribute& attr, Params const& params) const { return parse_subrule(def() , first, last, context, skipper, attr, params); } template 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 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 info what(Context& context) const { // Forward to first subrule. return fusion::front(defs).second.binder.p.what(context); } template subrule_group< typename fusion::result_of::as_map< typename fusion::result_of::join< Defs const, Defs2 const>::type>::type> operator,(subrule_group 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 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_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_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 const> >::type , subrule > , spirit::qi::parser > { typedef mpl::int_ id_type; BOOST_STATIC_CONSTANT(int, ID = ID_); typedef subrule this_type; typedef spirit::qi::reference reference_; typedef typename proto::terminal::type terminal; typedef proto::extends base_type; typedef mpl::vector template_params; // locals_type is a sequence of types to be used as local variables typedef typename spirit::detail::extract_locals::type locals_type; typedef typename spirit::detail::extract_sig::type sig_type; // This is the subrule's attribute type typedef typename spirit::detail::attr_from_sig::type attr_type; typedef typename add_reference::type attr_reference_type; // parameter_types is a sequence of types passed as parameters to the subrule typedef typename spirit::detail::params_from_sig::type parameter_types; static size_t const params_size = fusion::result_of::size::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 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 struct group_type_helper { typedef typename def_type_helper::type def_type; // create Defs map with only one entry: (ID -> def) typedef typename fusion::result_of::make_map::type defs_type; typedef subrule_group type; }; template typename group_type_helper::type operator=(Expr const& expr) const { typedef group_type_helper helper; typedef typename helper::def_type def_type; typedef typename helper::type result_type; return result_type(fusion::make_map( def_type(compile(expr), name_))); } template friend typename group_type_helper::type operator%=(subrule const& sr, Expr const& expr) { typedef group_type_helper helper; typedef typename helper::def_type def_type; typedef typename helper::type result_type; return result_type(fusion::make_map( def_type(compile(expr), sr.name_))); } // non-const versions needed to suppress proto's %= kicking in template friend typename group_type_helper::type operator%=(subrule const& sr, Expr& expr) { return operator%=( sr , static_cast(expr)); } template friend typename group_type_helper::type operator%=(subrule& sr, Expr const& expr) { return operator%=( static_cast(sr) , expr); } template friend typename group_type_helper::type operator%=(subrule& sr, Expr& expr) { return operator%=( static_cast(sr) , static_cast(expr)); } std::string const& name() const { return name_; } void name(std::string const& str) { name_ = str; } template struct attribute { typedef attr_type type; }; template bool parse(Iterator& first, Iterator const& last , subrule_context& context , Skipper const& skipper, Attribute& attr) const { return context.group.template parse_subrule_id( first, last, context, skipper, attr); } template 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 bool parse(Iterator& first, Iterator const& last , subrule_context& context , Skipper const& skipper, Attribute& attr , Params const& params) const { return context.group.template parse_subrule_id( first, last, context, skipper, attr, params); } template 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 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 std::string name_; }; }}}} #if defined(BOOST_MSVC) # pragma warning(pop) #endif #endif