X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FParsedCommand.hh;h=af8dfe7041afd67084bb21dc28de9a40d5c1d614;hb=0eaf5340de8c2fbb02b1e0e13a797931e221dff3;hp=9f43d157be19f8ba6bb68d5f49db700849a021ce;hpb=63c40810b93b4d8f3d6dad5f987adc5f2bf5b5ed;p=senf.git diff --git a/Console/ParsedCommand.hh b/Console/ParsedCommand.hh index 9f43d15..af8dfe7 100644 --- a/Console/ParsedCommand.hh +++ b/Console/ParsedCommand.hh @@ -27,10 +27,12 @@ #define HH_ParsedCommand_ 1 // Custom includes + +#define BOOST_PARAMETER_MAX_ARITY 6 + #include #include #include -#include #include #include #include @@ -135,15 +137,13 @@ namespace console { typedef boost::intrusive_ptr ptr; detail::ArgumentInfoBase & arg(unsigned n) const; - template detail::ArgumentInfo & arg(unsigned n) const; void doc(std::string const & d); protected: ParsedCommandOverloadBase(); - template - void addParameter(); + template void addParameter(); private: virtual unsigned v_numArguments() const; @@ -166,8 +166,10 @@ namespace console { \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 + template class ParsedCommandOverload : public ParsedCommandOverloadBase { public: @@ -194,6 +196,8 @@ namespace console { 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 { @@ -206,11 +210,11 @@ namespace console { 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: @@ -225,9 +229,8 @@ namespace console { 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. - - \fixme Implement compile-time checking, that after a defaulted arg only defaulted args are - allowed. + + \see \ref console_autoparse */ template class ParsedCommandAttributor @@ -248,21 +251,134 @@ namespace console { href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter library. - For the keyword tags, the standard C++ scoping rules apply: - \li Either qualify them with their complete namespace: arg( senf::console::kw::name = - "name" ) - \li or use a namespace alias: namespace kw = senf::console::kw; arg( kw::name = "name" - ); - \li import the keywords into your namespace: using namespace senf::console::kw; arg( - name = "name"); + 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) ///< Argument name - BOOST_PARAMETER_KEYWORD(type, description) ///< One-line Argument description + /**< 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. */ } /** \brief Derived class dependent ParsedCommandBase attributes @@ -272,14 +388,28 @@ namespace console { 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 + template class ParsedArgumentAttributorBase : public ParsedCommandAttributor { public: 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: ParsedArgumentAttributorBase(Overload & overload, unsigned index); @@ -287,6 +417,23 @@ namespace console { private: }; +#ifndef DOXYGEN + + template + class ParsedArgumentAttributorBase + : public ParsedCommandAttributor + { + public: + Self doc(std::string const & doc) const; ///< Set documentation for all overloads + Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation + + protected: + ParsedArgumentAttributorBase(Overload & overload, unsigned index); + + private: + }; + +#endif /** \brief Argument dependent ParsedCommandBase attributes @@ -295,10 +442,10 @@ namespace console { 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=0, - bool flag=(index < unsigned(Overload::traits::arity)) > + template < class Overload, unsigned index, bool flag> class ParsedArgumentAttributor : public ParsedArgumentAttributorBase< Overload, ParsedArgumentAttributor > @@ -306,7 +453,10 @@ namespace console { 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; public: typedef OverloadedCommandNode node_type; @@ -322,16 +472,27 @@ namespace console { argument. The attributes are passed to arg() as keyword arguments using the Boost.Parameter - library. The valid keywords are defined in the - senf::console::kw namespace. - - This member is only present, if there is an argument at - the current index. */ + 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, 3, SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), 5)) +# 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 @@ -342,45 +503,43 @@ namespace console { 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 ParsedArgumentAttributor; -#ifndef DOXYGEN - - template - friend ParsedArgumentAttributor< - ParsedCommandOverload::traits> > - senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); - - template - friend ParsedArgumentAttributor< - 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); - -#endif + friend class detail::ParsedCommandAddNodeAccess; }; #ifndef DOXYGEN @@ -399,29 +558,20 @@ namespace console { template friend class ParsedArgumentAttributor; - - template - friend ParsedArgumentAttributor< - ParsedCommandOverload::traits> > - senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); - - template - friend ParsedArgumentAttributor< - 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 detail::ParsedCommandAddNodeAccess; }; template - ParsedArgumentAttributor< - 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 - ParsedArgumentAttributor< - 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<