// Copyright (c) 2009 Francois Barel // Copyright (c) 2001-2011 Joel de Guzman // Copyright (c) 2001-2012 Hartmut Kaiser // // 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_KARMA_SUBRULE_AUGUST_12_2009_0813PM) #define BOOST_SPIRIT_REPOSITORY_KARMA_SUBRULE_AUGUST_12_2009_0813PM #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 karma { /////////////////////////////////////////////////////////////////////////// // subrule_group: // - generator 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::karma::reference const> >::type , subrule_group > , spirit::karma::generator > { struct properties // Forward to first subrule. : remove_reference< typename fusion::result_of::front::type >::type::second_type::subject_type::properties {}; // 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::karma::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 generate(OutputIterator& sink, Context& context , Delimiter const& delimiter, Attribute const& attr) const { // Forward to first subrule. return generate_subrule(fusion::front(defs).second , sink, context, delimiter, attr); } template bool generate(OutputIterator& sink, Context& context , Delimiter const& delimiter, Attribute const& attr , Params const& params) const { // Forward to first subrule. return generate_subrule(fusion::front(defs).second , sink, context, delimiter, attr, params); } template bool generate_subrule_id(OutputIterator& sink , Context& context, Delimiter const& delimiter , Attribute const& attr) const { return generate_subrule(def() , sink, context, delimiter, attr); } template bool generate_subrule_id(OutputIterator& sink , Context& context, Delimiter const& delimiter , Attribute const& attr, Params const& params) const { return generate_subrule(def() , sink, context, delimiter, attr, params); } template bool generate_subrule(Def const& def, OutputIterator& sink , Context& /*caller_context*/, Delimiter const& delimiter , Attribute const& 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; // Create an attribute if none is supplied. typedef traits::make_attribute make_attribute; // 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 , traits::pre_transform( make_attribute::call(attr))); return def.binder(sink, context, delimiter); } template bool generate_subrule(Def const& def, OutputIterator& sink , Context& caller_context, Delimiter const& delimiter , Attribute const& 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; // Create an attribute if none is supplied. typedef traits::make_attribute make_attribute; // 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 , traits::pre_transform( make_attribute::call(attr)), params, caller_context); return def.binder(sink, context, delimiter); } template info what(Context& context) const { // Forward to first subrule. return fusion::front(defs).second.binder.g.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::karma::detail::generator_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 generator. /////////////////////////////////////////////////////////////////////////// template < int ID_ , typename T1 = unused_type , typename T2 = unused_type > struct subrule : proto::extends< typename proto::terminal< spirit::karma::reference const> >::type , subrule > , spirit::karma::generator > { //FIXME should go fetch the real properties of this subrule's definition in the current context, but we don't // have the context here (properties would need to be 'template struct properties' instead) typedef mpl::int_< spirit::karma::generator_properties::all_properties> properties; typedef mpl::int_ id_type; BOOST_STATIC_CONSTANT(int, ID = ID_); typedef subrule this_type; typedef spirit::karma::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< typename add_const::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::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 karma expression. BOOST_SPIRIT_ASSERT_MATCH(spirit::karma::domain, Expr); typedef typename result_of::compile< spirit::karma::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 generate(OutputIterator& sink , subrule_context& context , Delimiter const& delimiter, Attribute const& attr) const { return context.group.template generate_subrule_id( sink, context, delimiter, attr); } template bool generate(OutputIterator& /*sink*/ , Context& /*context*/ , Delimiter const& /*delimiter*/, Attribute const& /*attr*/) const { // If you are seeing a compilation error here, you are trying // to use a subrule as a generator outside of a subrule group. BOOST_SPIRIT_ASSERT_MSG(false , subrule_used_outside_subrule_group, (id_type)); return false; } template bool generate(OutputIterator& sink , subrule_context& context , Delimiter const& delimiter, Attribute const& attr , Params const& params) const { return context.group.template generate_subrule_id( sink, context, delimiter, attr, params); } template bool generate(OutputIterator& /*sink*/ , Context& /*context*/ , Delimiter const& /*delimiter*/, Attribute const& /*attr*/ , Params const& /*params*/) const { // If you are seeing a compilation error here, you are trying // to use a subrule as a generator 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