X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FParsedCommand.hh;h=af8dfe7041afd67084bb21dc28de9a40d5c1d614;hb=0eaf5340de8c2fbb02b1e0e13a797931e221dff3;hp=7df4366b4b98118f64a8dce0b1ae215e424ce007;hpb=f47679431aa3461936ee4a85c0c4216e44292b55;p=senf.git diff --git a/Console/ParsedCommand.hh b/Console/ParsedCommand.hh index 7df4366..af8dfe7 100644 --- a/Console/ParsedCommand.hh +++ b/Console/ParsedCommand.hh @@ -27,17 +27,19 @@ #define HH_ParsedCommand_ 1 // Custom includes + +#define BOOST_PARAMETER_MAX_ARITY 6 + #include #include #include -#include #include #include #include #include #include "../config.hh" #include "OverloadedCommand.hh" -#include "ParseParameter.hh" +#include "Traits.hh" #include "../Utils/type_traits.hh" #include "ParsedCommand.ih" @@ -47,6 +49,8 @@ namespace senf { namespace console { + namespace detail { class ArgumentInfoBase; } + /** \brief CommandOverload implementation with automatic argument parsing ParsedCommandOverloadBase implements a CommandOverload implementation supporting automatic @@ -69,7 +73,7 @@ namespace console { \endcode There are quite a number of additional parameters available to be set. These parameters are - documented in ParsedAttributeAttributor. Parameters are set by adding them as additional + documented in ParsedArgumentAttributor. Parameters are set by adding them as additional calls after adding the node: \code @@ -115,13 +119,13 @@ namespace console { used as argument type. However, argument parsing can be configured by specializing - senf::console::detail::ParameterTraits. See that class for more information. + senf::console::ArgumentTraits. See that class for more information. \section overload_format Custom return-value formatters By default, return values are streamed to an ostream. This automatically allows any streamable type to be used as return value. To add new types or customize the formating, the - senf::console::detail::ReturnValueTraits template needs to be specialized for that type. See + senf::console::ReturnValueTraits template needs to be specialized for that type. See that class for more information. \ingroup console_commands @@ -132,51 +136,85 @@ namespace console { public: typedef boost::intrusive_ptr ptr; - detail::ParameterInfoBase & arg(unsigned n) const; - template detail::ParameterInfo & arg(unsigned n) const; + detail::ArgumentInfoBase & arg(unsigned n) const; void doc(std::string const & d); protected: ParsedCommandOverloadBase(); - template - void addParameter(); + template void addParameter(); private: virtual unsigned v_numArguments() const; virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const; virtual std::string v_doc() const; - typedef std::vector Parameters; + typedef std::vector Parameters; Parameters parameters_; std::string doc_; }; - template - class ParsedCommandOverload {}; + /** \brief Parsed command overload + + ParsedCommandOverload provides the command overload added to an OverloadedCommandNode for an + automatically parsed command. + + This class is normally instantiated automatically when adding a function or member-function + pointer as callback to the tree. Manually instantiation this type of overload is \e not + simple, since the function signature has to be manipulated correctly to support the optional + \c std::ostream first argument. + + \implementation This class is specialized for each supported number of command arguments. + + \todo Implement automatic binding of member functions for parser and formatter + */ + template + class ParsedCommandOverload : public ParsedCommandOverloadBase + { + public: + typedef boost::intrusive_ptr ptr; + +#ifdef DOXYGEN + static ptr create(Function fn); +#endif + }; + +#ifndef DOXYGEN # define BOOST_PP_ITERATION_PARAMS_1 (4, (0, SENF_CONSOLE_MAX_COMMAND_ARITY, \ SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), \ 1)) # include BOOST_PP_ITERATE() +#endif + + /** \brief Generic ParsedCommandOverladBase attributes + + Attributes for parsed commands are not set directly on the node. They are set via a special + attributor temporary returned when adding a parsed command to the tree. + + This class is the base class for those attributors. It provides members which do not depend + in any way on the exact type of command added. + + \see \ref console_autoparse + */ class ParsedCommandAttributorBase { public: - OverloadedCommandNode & node() const; - operator OverloadedCommandNode & () const; + OverloadedCommandNode & node() const; ///< Return the node object + operator OverloadedCommandNode & () const; ///< Automatically convert to node object protected: ParsedCommandAttributorBase(ParsedCommandOverloadBase & overload, unsigned index); void argName(std::string const & name) const; void argDoc(std::string const & doc) const; - template void defaultValue(Type const & value) const; + void typeName(std::string const & doc) const; + void defaultDoc(std::string const & doc) const; ParsedCommandOverloadBase & overload() const; void overloadDoc(std::string const & doc) const; - void nodeDoc(std::string const & doc) const; private: @@ -184,148 +222,356 @@ namespace console { unsigned index_; }; + /** \brief Non argument dependent ParsedCommandBase attributes + + Attributes for parsed commands are not set directly on the node. They are set via a special + attributor temporary returned when adding a parsed command to the tree. + + This class adds all those members, which do depend on the type of command added (and thereby + on that commands signature) but do not depend on the type of any single argument. + + \see \ref console_autoparse + */ template class ParsedCommandAttributor : public ParsedCommandAttributorBase { public: - Overload & overload() const; + Overload & overload() const; ///< Get the command overload protected: ParsedCommandAttributor(Overload & overload, unsigned index); private: }; - + + /** \brief Keyword argument tags + + The tags defined in this namespace are used as keyword arguments via the Boost.Parameter + library. + + For the keyword tags, the standard C++ scoping rules apply + \code + // Either qualify them with their complete namespace + dir.add(...) + .arg( senf::console::kw::name = "name" ); + + // Or use a namespace alias + namespace kw = senf::console::kw; + dir.add(...) + .arg( kw::name = "name" ); + + // Or import the keywords into the current namespace (beware of name collisions) + using namespace senf::console::kw; + dir.add(...) + .arg( name = "name" ); + \endcode + + The second alternative is preferred, the using namespace directive may be used as + long as the keyword names do not clash with another visible symbol. + + \section kw_attributes Argument attribute values + + The keywords are used to set argument attributes. The keywords \ref default_value and \ref + parser influence, how an argument is parsed/interpreted whereas \ref name, \ref description, + \ref type_name and \ref default_doc are used to change the arguments documentation: + \code + void command(int); + + dir.add("command", &command) + .arg( kw::name = "name", + kw::description = "description", + kw::default_value = 1, + kw::type_name = "type_name", + kw::default_doc = "default_doc" ); + \endcode + Will create the following documentation: + \htmlonly +
+        Usage:
+            command [name:type_name]
+        
+        With:
+            name      description
+                default: default_doc
+        
+ \endhtmlonly + + \see \ref senf::console::ParsedArgumentAttributor::arg() + */ namespace kw { - BOOST_PARAMETER_KEYWORD(type, name); - BOOST_PARAMETER_KEYWORD(type, description); - BOOST_PARAMETER_KEYWORD(type, default_value); + BOOST_PARAMETER_KEYWORD(type, name) ///< Argument name + /**< Sets the displayed name of the argument. */ + BOOST_PARAMETER_KEYWORD(type, description) ///< One-line argument description + /**< This description is shown in the argument + reference. If several overloads have same-named + arguments, only one of them should be documented. This + documentation then applies to all arguments of that + name. */ + BOOST_PARAMETER_KEYWORD(type, default_value) ///< Argument default value + /**< If a default value is specified for an argument, that + argument is optional. If an overload is called with + fewer arguments than defined, optional values will be + used beginning at the last optional argument and going + forward until all arguments have values assigned. E.g., + an overload with 5 parameters \a a - \a e with two + defaults attached: +
+                                             command a:int [b:int] c:int [d:int] e:int
+                                             
+ When calling the overload, the arguments will be + assigned in the following way: + + + + + + + + + + + + + + + + + + + + + +
command 1 2SyntaxErrorException: invalid number of + arguments
command 1 2 3\a a = 1\a b = \e default\a c = 2\a d = \e default\a e = 3
command 1 2 3 4\a a = 1\a b = 2\a c = 3\a d = \e default\a e = 4
command 1 2 3 4 5\a a = 1\a b = 2\a c = 3\a d = 4\a e = 5
command 1 2 3 4 5 6SyntaxErrorException: invalid number of + arguments
+ So, if you use default values as you are used to, + assigning default values to consecutive trailing + arguments, they work like they do in C++ and most other + languages */ + BOOST_PARAMETER_KEYWORD(type, type_name) ///< Type name of this arguments type + /**< By default, the type of an argument is extracted from + the C++ type name by taking the last component of the + fully scoped name. This value can be changed by setting + this attribute. */ + BOOST_PARAMETER_KEYWORD(type, default_doc) ///< String rep of default value + /**< By default, the default value is documented by + converting the value to it's string representation + using \c boost::lexical_cast / \c iostreams. The + displayed value can be changed by setting this + attribute. */ + BOOST_PARAMETER_KEYWORD(type, parser) ///< Argument parser + /**< The argument parser is used to convert the argument + token list returned by the console/config parser into + the appropriate value. If not set explicitly, this + conversion is supplied by the ArgumentTraits + class. + + Setting the \a parser attribute allows to use a custom + parser. The parser is an arbitrary callable object with + the signature + \code + void parser(senf::console::ParseCommandInfo::TokensRange const & tokens, value_type & out); + \endcode + where \c value_type is the type of the overload + parameter. The parser must read and parse the complete + \a tokens range and return the parsed value in \a + out. If the parser fails, it must raise a + senf::console::SyntaxErrorException. */ } - template - class ParsedAttributeAttributorBase + /** \brief Derived class dependent ParsedCommandBase attributes + + Attributes for parsed commands are not set directly on the node. They are set via a special + attributor temporary returned when adding a parsed command to the tree. + + This class adds all those members, which do not depend on any specific argument but which + need to return the correct attributor type. + + \see \ref console_autoparse + */ + template + class ParsedArgumentAttributorBase : public ParsedCommandAttributor { public: - Self doc(std::string const & doc) const; - Self overloadDoc(std::string const & doc) const; + Self doc(std::string const & doc) const; ///< Set documentation for all overloads + Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation + Self formatter(typename Overload::Formatter formatter) const; + ///< Set return value formatter + /**< This member is only available, if the \a ReturnType of + the installed callback is not \c void. + + If \a ReturnType is not \c void, the \a formatter must + be a callable with a signature compatible with + \code + void formatter(ReturnType const & value, std::ostream & os); + \endcode + The \a formatter takes the return value of the call \a + value and writes it properly formated to \a os. */ protected: - ParsedAttributeAttributorBase(Overload & overload, unsigned index); + ParsedArgumentAttributorBase(Overload & overload, unsigned index); private: }; - template < class Overload, - unsigned index=0, - bool flag=(index < unsigned(Overload::traits::arity)) > - class ParsedAttributeAttributor - : public ParsedAttributeAttributorBase< Overload, - ParsedAttributeAttributor > +#ifndef DOXYGEN + + template + class ParsedArgumentAttributorBase + : public ParsedCommandAttributor { public: - typedef typename senf::function_traits_arg_type< - typename Overload::traits, int(index) >::type arg_type; - typedef typename senf::remove_cvref< arg_type >::type value_type; - typedef ParsedAttributeAttributor next_type; + Self doc(std::string const & doc) const; ///< Set documentation for all overloads + Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation - typedef OverloadedCommandNode node_type; - typedef ParsedAttributeAttributor return_type; + protected: + ParsedArgumentAttributorBase(Overload & overload, unsigned index); + + private: + }; +#endif + + /** \brief Argument dependent ParsedCommandBase attributes + + Attributes for parsed commands are not set directly on the node. They are set via a special + attributor temporary returned when adding a parsed command to the tree. + + This class adds all those members, which depend on a specific argument. Each call to \c arg + will advance to the next argument. + + \see \ref console_autoparse + */ + template < class Overload, unsigned index, bool flag> + class ParsedArgumentAttributor + : public ParsedArgumentAttributorBase< Overload, + ParsedArgumentAttributor > + { typedef boost::parameter::parameters< kw::type::name, kw::type::description, - kw::type::default_value> arg_params; + kw::type::default_value, + kw::type::type_name, + kw::type::default_doc, + kw::type::parser> arg_params; - next_type arg() const; + public: + typedef OverloadedCommandNode node_type; + typedef ParsedArgumentAttributor return_type; -# define BOOST_PP_ITERATION_PARAMS_1 \ - (4, (1, 3, SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), 5)) + typedef typename senf::function_traits_arg_type< + typename Overload::traits, int(index) >::type arg_type; + typedef typename senf::remove_cvref< arg_type >::type value_type; + typedef ParsedArgumentAttributor next_type; + + next_type arg() const; ///< Set argument attributes + /**< This member changes the attributes for the current + argument. The attributes are passed to arg() as keyword + arguments using the Boost.Parameter + library. + \code + ... + .arg( kw::name = "name", + kw::default_value = 1 ) + ... + \endcode + The valid keywords are defined in the senf::console::kw + namespace. + + Each call to arg() will increment the argument index + and advance to the next argument. This member is only + present, if there is an argument at the current + index. */ + +#ifndef DOXYVEN + +# define BOOST_PP_ITERATION_PARAMS_1 \ + (4, (1, BOOST_PARAMETER_MAX_ARITY, \ + SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), \ + 5)) # include BOOST_PP_ITERATE() +#endif + private: - explicit ParsedAttributeAttributor(Overload & overload); + explicit ParsedArgumentAttributor(Overload & overload); template next_type argInfo(ArgumentPack const & args) const; - template - void argInfo(Kw const &, ArgumentPack const &, boost::mpl::true_) + void argInfo(Kw const &, ArgumentPack const &, boost::mpl::false_) const; + template void argInfo(boost::parameter::keyword const &, - ArgumentPack const & args, boost::mpl::false_) + ArgumentPack const & args, boost::mpl::true_) const; template void argInfo(boost::parameter::keyword const &, - ArgumentPack const & args, boost::mpl::false_) + ArgumentPack const & args, boost::mpl::true_) const; template void argInfo(boost::parameter::keyword const &, - ArgumentPack const & args, boost::mpl::false_) + ArgumentPack const & args, boost::mpl::true_) + const; + template + void argInfo(boost::parameter::keyword const &, + ArgumentPack const & args, boost::mpl::true_) + const; + template + void argInfo(boost::parameter::keyword const &, + ArgumentPack const & args, boost::mpl::true_) + const; + template + void argInfo(boost::parameter::keyword const &, + ArgumentPack const & args, boost::mpl::true_) const; next_type next() const; void defaultValue(value_type const & value) const; + template void parser(Fn fn) const; template - friend class ParsedAttributeAttributor; - - template - friend ParsedAttributeAttributor< - ParsedCommandOverload::traits> > - senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); - - template - friend ParsedAttributeAttributor< - ParsedCommandOverload::traits> > - senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, - Function fn, int, - typename boost::enable_if_c< - detail::ParsedCommandTraits::is_member>::type * = 0); + friend class ParsedArgumentAttributor; + + friend class detail::ParsedCommandAddNodeAccess; }; +#ifndef DOXYGEN + template - class ParsedAttributeAttributor - : public ParsedAttributeAttributorBase< Overload, - ParsedAttributeAttributor > + class ParsedArgumentAttributor + : public ParsedArgumentAttributorBase< Overload, + ParsedArgumentAttributor > { public: typedef OverloadedCommandNode node_type; - typedef ParsedAttributeAttributor return_type; + typedef ParsedArgumentAttributor return_type; private: - explicit ParsedAttributeAttributor(Overload & overload); + explicit ParsedArgumentAttributor(Overload & overload); template - friend class ParsedAttributeAttributor; - - template - friend ParsedAttributeAttributor< - ParsedCommandOverload::traits> > - senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); - - template - friend ParsedAttributeAttributor< - ParsedCommandOverload::traits> > - senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, - Function fn, int, - typename boost::enable_if_c< - detail::ParsedCommandTraits::is_member>::type * = 0); - }; + friend class ParsedArgumentAttributor; -#ifndef DOXYGEN + friend class detail::ParsedCommandAddNodeAccess; + }; template - ParsedAttributeAttributor< - ParsedCommandOverload::traits> > + typename detail::ParsedCommandTraits::Attributor senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); + template + typename detail::ParsedCommandTraits::Attributor + senf_console_add_node(DirectoryNode & node, std::string const & name, boost::function fn, int); + template - ParsedAttributeAttributor< - ParsedCommandOverload::traits> > + typename detail::ParsedCommandTraits::Attributor senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, Function fn, int, typename boost::enable_if_c< @@ -338,7 +584,7 @@ namespace console { #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedCommandOverload, (class,unsigned)) -BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedAttributeAttributor, (class, unsigned, bool)) +BOOST_TYPEOF_REGISTER_TEMPLATE(senf::console::ParsedArgumentAttributor, (class, unsigned, bool)) BOOST_TYPEOF_REGISTER_TEMPLATE(boost::function_traits, 1) ///////////////////////////////hh.e////////////////////////////////////////