Console; Fix second console segfault
[senf.git] / Console / ParsedCommand.hh
index 9f43d15..af8dfe7 100644 (file)
 #define HH_ParsedCommand_ 1
 
 // Custom includes
+
+#define BOOST_PARAMETER_MAX_ARITY 6
+
 #include <vector>
 #include <boost/type_traits/function_traits.hpp>
 #include <boost/type_traits/is_member_pointer.hpp>
-#include <boost/type_traits/is_same.hpp>
 #include <boost/mpl/if.hpp>
 #include <boost/utility.hpp>
 #include <boost/parameter/keyword.hpp>
@@ -135,15 +137,13 @@ namespace console {
         typedef boost::intrusive_ptr<ParsedCommandOverloadBase> ptr;
 
         detail::ArgumentInfoBase & arg(unsigned n) const;
-        template <class Type> detail::ArgumentInfo<Type> & arg(unsigned n) const;
 
         void doc(std::string const & d);
 
     protected:
         ParsedCommandOverloadBase();
 
-        template <class Type>
-        void addParameter();
+        template <class Type> 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 <class FunctionTraits, unsigned arity=FunctionTraits::arity>
+    template <class FunctionTraits, class ReturnType, unsigned arity>
     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 <class Type> 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 Overload>
     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</a>
         library.
 
-        For the keyword tags, the standard C++ scoping rules apply:
-        \li Either qualify them with their complete namespace: <tt>arg( senf::console::kw::name =
-            "name" )</tt>
-        \li or use a namespace alias: <tt>namespace kw = senf::console::kw; arg( kw::name = "name"
-            );</tt>
-        \li import the keywords into your namespace: <tt>using namespace senf::console::kw; arg(
-            name = "name");</tt>
+        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 <tt>using namespace</tt> 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
+        <pre>
+        Usage:
+            command [name:type_name]
+        
+        With:
+            name      description
+                default: default_doc
+        </pre>
+        \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:
+                                             <pre>
+                                             command a:int [b:int] c:int [d:int] e:int
+                                             </pre>
+                                             When calling the overload, the arguments will be
+                                             assigned in the following way:
+                                             <table class="senf fixedwidth">
+                                             <tr>
+                                               <td style="whitespace:no-wrap"><tt>command 1 2</tt></td>
+                                               <td colspan="5">SyntaxErrorException: invalid number of
+                                                 arguments</td>
+                                             </tr>
+                                             <tr>
+                                               <td style="white-space:nowrap"><tt>command 1 2 3</tt></td>
+                                               <td style="width:6em">\a a = 1</td><td style="width:6em">\a b = \e default</td><td style="width:6em">\a c = 2</td><td style="width:6em">\a d = \e default</td><td style="width:6em">\a e = 3</td>
+                                             </tr>
+                                             <tr>
+                                               <td style="white-space:nowrap"><tt>command 1 2 3 4</tt></td>
+                                               <td>\a a = 1</td><td>\a b = 2</td><td>\a c = 3</td><td>\a d = \e default</td><td>\a e = 4</td>
+                                             </tr>
+                                             <tr>
+                                               <td style="white-space:nowrap"><tt>command 1 2 3 4 5</tt></td>
+                                               <td>\a a = 1</td><td>\a b = 2</td><td>\a c = 3</td><td>\a d = 4</td><td>\a e = 5</td>
+                                             </tr>
+                                             <tr>
+                                               <td style="white-space:nowrap"><tt>command 1 2 3 4 5 6</tt></td>
+                                               <td colspan="5">SyntaxErrorException: invalid number of
+                                                 arguments</td>
+                                             </tr>
+                                             </table>
+                                             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 <class Overload, class Self>
+    template <class Overload, class Self, class ReturnType=typename Overload::traits::result_type>
     class ParsedArgumentAttributorBase
         : public ParsedCommandAttributor<Overload>
     {
     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 Overload, class Self>
+    class ParsedArgumentAttributorBase<Overload, Self, void>
+        : public ParsedCommandAttributor<Overload>
+    {
+    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<Overload, index, flag> >
@@ -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 <a
                                              href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
-                                             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 <class ArgumentPack>
         next_type argInfo(ArgumentPack const & args) const;
         template <class Kw, class ArgumentPack>
-        void argInfo(Kw const &, ArgumentPack const &, boost::mpl::true_) 
+        void argInfo(Kw const &, ArgumentPack const &, boost::mpl::false_) 
             const;
 
         template <class ArgumentPack>
         void argInfo(boost::parameter::keyword<kw::type::name> const &, 
-                     ArgumentPack const & args, boost::mpl::false_) 
+                     ArgumentPack const & args, boost::mpl::true_) 
             const;
         template <class ArgumentPack>
         void argInfo(boost::parameter::keyword<kw::type::description> const &, 
-                     ArgumentPack const & args, boost::mpl::false_) 
+                     ArgumentPack const & args, boost::mpl::true_) 
             const;
         template <class ArgumentPack>
         void argInfo(boost::parameter::keyword<kw::type::default_value> const &, 
-                     ArgumentPack const & args, boost::mpl::false_) 
+                     ArgumentPack const & args, boost::mpl::true_) 
+            const;
+        template <class ArgumentPack>
+        void argInfo(boost::parameter::keyword<kw::type::type_name> const &, 
+                     ArgumentPack const & args, boost::mpl::true_) 
+            const;
+        template <class ArgumentPack>
+        void argInfo(boost::parameter::keyword<kw::type::default_doc> const &, 
+                     ArgumentPack const & args, boost::mpl::true_) 
+            const;
+        template <class ArgumentPack>
+        void argInfo(boost::parameter::keyword<kw::type::parser> const &, 
+                     ArgumentPack const & args, boost::mpl::true_) 
             const;
 
         next_type next() const;
 
         void defaultValue(value_type const & value) const;
+        template <class Fn> void parser(Fn fn) const;
 
         template <class O, unsigned i, bool f>
         friend class ParsedArgumentAttributor;
 
-#ifndef DOXYGEN
-        
-        template <class Function>
-        friend ParsedArgumentAttributor<
-            ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
-        senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
-        
-        template <class Owner, class Function>
-        friend ParsedArgumentAttributor<
-            ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
-        senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
-                              Function fn, int,
-                              typename boost::enable_if_c<
-                                  detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
-
-#endif
+        friend class detail::ParsedCommandAddNodeAccess;
     };
 
 #ifndef DOXYGEN
@@ -399,29 +558,20 @@ namespace console {
 
         template <class O, unsigned i, bool f>
         friend class ParsedArgumentAttributor;
-        
-        template <class Function>
-        friend ParsedArgumentAttributor<
-            ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
-        senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
-        
-        template <class Owner, class Function>
-        friend ParsedArgumentAttributor<
-            ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
-        senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
-                              Function fn, int,
-                              typename boost::enable_if_c<
-                                  detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
+
+        friend class detail::ParsedCommandAddNodeAccess;
     };
 
     template <class Function>
-    ParsedArgumentAttributor<
-        ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
+    typename detail::ParsedCommandTraits<Function>::Attributor
     senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
 
+    template <class Signature>
+    typename detail::ParsedCommandTraits<Signature>::Attributor
+    senf_console_add_node(DirectoryNode & node, std::string const & name, boost::function<Signature> fn, int);
+
     template <class Owner, class Function>
-    ParsedArgumentAttributor<
-        ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
+    typename detail::ParsedCommandTraits<Function>::Attributor
     senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
                           Function fn, int,
                           typename boost::enable_if_c<