Skip to content
Snippets Groups Projects
Commit ee49e2cc authored by g0dil's avatar g0dil
Browse files

Console: More documentation and cleanup

parent 61f6d30d
No related branches found
No related tags found
No related merge requests found
......@@ -348,16 +348,18 @@
\li \e default_value: Arguments default value</td></tr>
</table>
See senf::console::ParsedArgumentAttributor 'List of all members'
\section console_memberfn Registering member functions
Member functions are supported like non-member functions. They must however be added through a
senf::console::ScopedDirectory<> instance to bind them to their instance.
senf::console::ScopedDirectory instance to bind them to their instance.
\code
class Test
{
public:
ScopedDirectory<Test> dir;
senf::console::ScopedDirectory<Test> dir;
Test(std::string label) : dir(this), label_ (label) {
dir.add("test4", &Test::test2);
......@@ -379,7 +381,7 @@
\endcode
Binding via senf::console::ScopedDirectory ensures, that the commands are automatically removed
from the tree when an object is destroyed.
from the tree when the object is destroyed.
*/
......
......@@ -507,6 +507,11 @@ namespace console {
{};
#endif
/** \brief Syntax error parsing command arguments exception
All errors while parsing the arguments of a command must be signaled by throwing an instance
of SyntaxErrorException. This is important, so command overloading works.
*/
struct SyntaxErrorException : public senf::Exception
{
explicit SyntaxErrorException(std::string const & msg = "");
......
......@@ -39,11 +39,15 @@ namespace console {
class OverloadedCommandNode;
/** \brief Documentation for a single argument
This struct is used by CommandOverload::argumentDoc()
*/
struct ArgumentDoc {
std::string name;
std::string type;
std::string defaultValue;
std::string doc;
std::string name; ///< Argument name
std::string type; ///< Argument type (string representation)
std::string defaultValue; ///< Default value (string representation) or empty string
std::string doc; ///< Documentation for this argument
};
/** \brief Base class for command overload of OverloadedCommandNode
......@@ -77,14 +81,22 @@ namespace console {
overload, a SyntaxErrorException must be thrown.
Same as execute() */
unsigned numArguments() const;
unsigned numArguments() const; ///< Number of arguments this overload takes
void argumentDoc(unsigned index, ArgumentDoc & doc) const;
std::string doc() const;
///< Get information on argument \a index
/**< The information is returned in \e doc. \e doc must be
empty before this call.
\pre \a index < numArguments()
\param[in] index Argument index
\param[outp doc Argument documentation */
std::string doc() const; ///< Get overload documentation
OverloadedCommandNode & node() const; ///< Access owning node
/**< \pre The command \e must have been added to an
OverloadedCommandNode. */
unsigned overloadIndex() const;
unsigned overloadIndex() const; ///< Get index of overload in it's OverloadedCommandNode
protected:
CommandOverload();
......@@ -93,9 +105,25 @@ namespace console {
private:
#endif
virtual unsigned v_numArguments() const = 0;
///< Return the number of arguments
/**< This member must be implemented in the derived class to
return the number of arguments, the command expects. */
virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const = 0;
///< Return argument documentation
/**< The member must be implemented int the derived class to
return all documentation information for the \a
index'th parameter in \a doc. */
virtual std::string v_doc() const = 0;
///< Return overload documentation
/**< This member must be implemented in the derived class to
return the overloads documentation string. */
virtual void v_execute(std::ostream & os, ParseCommandInfo const & command) const = 0;
///< Execute the overload
/**< This member must be implemented in the derived class
o execute the overload. */
private:
OverloadedCommandNode * node_;
......@@ -153,15 +181,16 @@ namespace console {
template <class Command>
Command & add(boost::intrusive_ptr<Command> overload); ///< Add an additional overload
ptr thisptr();
cptr thisptr() const;
OverloadedCommandNode & doc(std::string const & doc);
///< Assign global help for all overloads
unsigned overloadIndex(CommandOverload const & overload);
///< Return the overload index for \a overload
/**< overloadIndex returns the index of \a overload in the
internal list of overloads. */
protected:
ptr thisptr();
cptr thisptr() const;
private:
OverloadedCommandNode();
......@@ -205,10 +234,8 @@ namespace console {
SimpleCommandOverload & doc(std::string const & doc);
///< Assign overload specific documentation
protected:
private:
SimpleCommandOverload(Function fn);
explicit SimpleCommandOverload(Function fn);
virtual unsigned v_numArguments() const;
virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const;
......
......@@ -227,11 +227,11 @@ namespace console {
friend class detail::ParserAccess;
};
/** \brief Console command
/** \brief Single parsed console command
Every command parsed is returned in a ParseCommandInfo instance. This information is purely
taken from the parser, no semantic information is attached at this point, the config/console
is not involved in any why. ParseCommandInfo consist of
node tree is not involved in any why. ParseCommandInfo consist of
\li the type of command: built-in or normal command represented by a possibly relative path
into the command tree.
......@@ -279,9 +279,9 @@ namespace console {
constitutes one path element. If the first element is
empty, the path is an absolute path, otherwise it is
relative. If the last element is an empty string, the
path ends in a '/' char. */
path ends with a '/' char. */
ArgumentsRange arguments() const; ///< Command arguments
/**< The returned range contains one token range for each
/**< The returned range contains one TokensRange for each
argument. */
TokensRange tokens() const; ///< All argument tokens
/**< The returned range contains \e all argument tokens in a
......
......@@ -46,7 +46,7 @@ prefix_ void senf::console::ParsedCommandOverloadBase::v_argumentDoc(unsigned in
const
{
BOOST_ASSERT( index < parameters_.size() );
detail::ParameterInfoBase & arg (*parameters_[index]);
detail::ArgumentInfoBase & arg (*parameters_[index]);
doc.name = arg.name.empty()
? (boost::format("arg%d%d") % overloadIndex() % (index+1)).str()
: arg.name;
......
......@@ -36,7 +36,7 @@
prefix_ senf::console::ParsedCommandOverloadBase::ParsedCommandOverloadBase()
{}
prefix_ senf::console::detail::ParameterInfoBase &
prefix_ senf::console::detail::ArgumentInfoBase &
senf::console::ParsedCommandOverloadBase::arg(unsigned n)
const
{
......
......@@ -33,21 +33,51 @@
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::ArgumentInfoBase
prefix_ senf::console::detail::ArgumentInfoBase::ArgumentInfoBase(std::string const & type_)
: type (type_), name (), hasDefault (false)
{}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::ArgumentInfo<ParameterType>
template <class ParameterType>
prefix_ typename senf::console::detail::ArgumentInfo<ParameterType>::ptr
senf::console::detail::ArgumentInfo<ParameterType>::create()
{
return ptr(new ArgumentInfo());
}
template <class ParameterType>
prefix_ senf::console::detail::ArgumentInfo<ParameterType>::ArgumentInfo()
: ArgumentInfoBase ( ArgumentTraits<ParameterType>::description() ),
defaultValue ()
{}
template <class ParameterType>
prefix_ std::string senf::console::detail::ArgumentInfo<ParameterType>::defaultValueStr()
const
{
return hasDefault ? ArgumentTraits<ParameterType>::str(defaultValue) : "";
}
///////////////////////////////////////////////////////////////////////////
// senf::console::ParsedCommandOverloadBase
template <class Type>
prefix_ senf::console::detail::ParameterInfo<Type> &
prefix_ senf::console::detail::ArgumentInfo<Type> &
senf::console::ParsedCommandOverloadBase::arg(unsigned n)
const
{
return dynamic_cast<detail::ParameterInfo<Type> &>(arg(n));
return dynamic_cast<detail::ArgumentInfo<Type> &>(arg(n));
}
template <class Type>
prefix_ void senf::console::ParsedCommandOverloadBase::addParameter()
{
parameters_.push_back(detail::ParameterInfo<Type>::create());
parameters_.push_back(detail::ArgumentInfo<Type>::create());
}
///////////////////////////////////////////////////////////////////////////
......@@ -87,11 +117,11 @@ senf::console::ParsedCommandAttributor<Overload>::ParsedCommandAttributor(Overlo
{}
///////////////////////////////////////////////////////////////////////////
// senf::console::ParsedAttributeAttributorBase<Overload,Self>
// senf::console::ParsedArgumentAttributorBase<Overload,Self>
template <class Overload, class Self>
prefix_ Self
senf::console::ParsedAttributeAttributorBase<Overload,Self>::doc(std::string const & doc)
senf::console::ParsedArgumentAttributorBase<Overload,Self>::doc(std::string const & doc)
const
{
this->ParsedCommandAttributorBase::nodeDoc(doc);
......@@ -99,7 +129,7 @@ senf::console::ParsedAttributeAttributorBase<Overload,Self>::doc(std::string con
}
template <class Overload, class Self>
prefix_ Self senf::console::ParsedAttributeAttributorBase<Overload,Self>::
prefix_ Self senf::console::ParsedArgumentAttributorBase<Overload,Self>::
overloadDoc(std::string const & doc)
const
{
......@@ -109,17 +139,17 @@ overloadDoc(std::string const & doc)
template <class Overload, class Self>
prefix_
senf::console::ParsedAttributeAttributorBase<Overload,Self>::
ParsedAttributeAttributorBase(Overload & overload, unsigned index)
senf::console::ParsedArgumentAttributorBase<Overload,Self>::
ParsedArgumentAttributorBase(Overload & overload, unsigned index)
: ParsedCommandAttributor<Overload> (overload, index)
{}
///////////////////////////////////////////////////////////////////////////
// senf::console::ParsedAttributeAttributor<Overload,index,flag>
// senf::console::ParsedArgumentAttributor<Overload,index,flag>
template <class Overload, unsigned index, bool flag>
prefix_ typename senf::console::ParsedAttributeAttributor<Overload,index,flag>::next_type
senf::console::ParsedAttributeAttributor<Overload,index,flag>::arg()
prefix_ typename senf::console::ParsedArgumentAttributor<Overload,index,flag>::next_type
senf::console::ParsedArgumentAttributor<Overload,index,flag>::arg()
const
{
return next();
......@@ -127,8 +157,8 @@ senf::console::ParsedAttributeAttributor<Overload,index,flag>::arg()
template <class Overload, unsigned index, bool flag>
template <class ArgumentPack>
prefix_ typename senf::console::ParsedAttributeAttributor<Overload,index,flag>::next_type
senf::console::ParsedAttributeAttributor<Overload,index,flag>::
prefix_ typename senf::console::ParsedArgumentAttributor<Overload,index,flag>::next_type
senf::console::ParsedArgumentAttributor<Overload,index,flag>::
argInfo(ArgumentPack const & args)
const
{
......@@ -146,14 +176,14 @@ argInfo(ArgumentPack const & args)
template <class Overload, unsigned index, bool flag>
template <class Kw, class ArgumentPack>
prefix_ void senf::console::ParsedAttributeAttributor<Overload,index,flag>::
prefix_ void senf::console::ParsedArgumentAttributor<Overload,index,flag>::
argInfo(Kw const &, ArgumentPack const &, boost::mpl::true_)
const
{}
template <class Overload, unsigned index, bool flag>
template <class ArgumentPack>
prefix_ void senf::console::ParsedAttributeAttributor<Overload,index,flag>::
prefix_ void senf::console::ParsedArgumentAttributor<Overload,index,flag>::
argInfo(boost::parameter::keyword<kw::type::name> const &, ArgumentPack const & args,
boost::mpl::false_)
const
......@@ -163,7 +193,7 @@ argInfo(boost::parameter::keyword<kw::type::name> const &, ArgumentPack const &
template <class Overload, unsigned index, bool flag>
template <class ArgumentPack>
prefix_ void senf::console::ParsedAttributeAttributor<Overload,index,flag>::
prefix_ void senf::console::ParsedArgumentAttributor<Overload,index,flag>::
argInfo(boost::parameter::keyword<kw::type::description> const &, ArgumentPack const & args,
boost::mpl::false_)
const
......@@ -173,7 +203,7 @@ argInfo(boost::parameter::keyword<kw::type::description> const &, ArgumentPack c
template <class Overload, unsigned index, bool flag>
template <class ArgumentPack>
prefix_ void senf::console::ParsedAttributeAttributor<Overload,index,flag>::
prefix_ void senf::console::ParsedArgumentAttributor<Overload,index,flag>::
argInfo(boost::parameter::keyword<kw::type::default_value> const &, ArgumentPack const & args,
boost::mpl::false_)
const
......@@ -183,21 +213,21 @@ argInfo(boost::parameter::keyword<kw::type::default_value> const &, ArgumentPack
template <class Overload, unsigned index, bool flag>
prefix_
senf::console::ParsedAttributeAttributor<Overload,index,flag>::
ParsedAttributeAttributor(Overload & overload)
: ParsedAttributeAttributorBase<Overload, ParsedAttributeAttributor> (overload, index)
senf::console::ParsedArgumentAttributor<Overload,index,flag>::
ParsedArgumentAttributor(Overload & overload)
: ParsedArgumentAttributorBase<Overload, ParsedArgumentAttributor> (overload, index)
{}
template <class Overload, unsigned index, bool flag>
prefix_ typename senf::console::ParsedAttributeAttributor<Overload,index,flag>::next_type
senf::console::ParsedAttributeAttributor<Overload,index,flag>::next()
prefix_ typename senf::console::ParsedArgumentAttributor<Overload,index,flag>::next_type
senf::console::ParsedArgumentAttributor<Overload,index,flag>::next()
const
{
return ParsedAttributeAttributor<Overload, index+1>(this->overload());
return ParsedArgumentAttributor<Overload, index+1>(this->overload());
}
template <class Overload, unsigned index, bool flag>
prefix_ void senf::console::ParsedAttributeAttributor<Overload,index,flag>::
prefix_ void senf::console::ParsedArgumentAttributor<Overload,index,flag>::
defaultValue(value_type const & value)
const
{
......@@ -205,14 +235,14 @@ defaultValue(value_type const & value)
}
///////////////////////////////////////////////////////////////////////////
// senf::console::ParsedAttributeAttributor<Overload, index, false>
// senf::console::ParsedArgumentAttributor<Overload, index, false>
template <class Overload, unsigned index>
prefix_
senf::console::ParsedAttributeAttributor<Overload, index, false>::
ParsedAttributeAttributor(Overload & overload)
: ParsedAttributeAttributorBase< Overload,
ParsedAttributeAttributor<Overload, index, false> > (overload, index)
senf::console::ParsedArgumentAttributor<Overload, index, false>::
ParsedArgumentAttributor(Overload & overload)
: ParsedArgumentAttributorBase< Overload,
ParsedArgumentAttributor<Overload, index, false> > (overload, index)
{}
///////////////////////////////////////////////////////////////////////////
......@@ -256,7 +286,7 @@ namespace {
}
template <class Function>
prefix_ senf::console::ParsedAttributeAttributor<
prefix_ senf::console::ParsedArgumentAttributor<
senf::console::ParsedCommandOverload<
typename senf::console::detail::ParsedCommandTraits<Function>::traits> >
senf::console::senf_console_add_node(DirectoryNode & node, std::string const & name,
......@@ -269,7 +299,7 @@ senf::console::senf_console_add_node(DirectoryNode & node, std::string const & n
typedef detail::ParsedCommandTraits<Function> CmdTraits;
typedef ParsedCommandOverload<typename CmdTraits::traits> Overload;
typedef ParsedAttributeAttributor<Overload> Attributor;
typedef ParsedArgumentAttributor<Overload> Attributor;
return Attributor(
cmdNode.add( CreateParsedCommandOverload<
......@@ -277,7 +307,7 @@ senf::console::senf_console_add_node(DirectoryNode & node, std::string const & n
}
template <class Owner, class Function>
prefix_ senf::console::ParsedAttributeAttributor<
prefix_ senf::console::ParsedArgumentAttributor<
senf::console::ParsedCommandOverload<
typename senf::console::detail::ParsedCommandTraits<Function>::traits> >
senf::console::
......@@ -292,7 +322,7 @@ senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & n
typedef detail::ParsedCommandTraits<Function> CmdTraits;
typedef ParsedCommandOverload<typename CmdTraits::traits> Overload;
typedef ParsedAttributeAttributor<Overload> Attributor;
typedef ParsedArgumentAttributor<Overload> Attributor;
return Attributor(
cmdNode.add( CreateParsedCommandOverload<
......@@ -300,6 +330,23 @@ senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & n
senf::membind(fn,&owner)) ) );
}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::CheckVoidReturn<Type>
template <class Type>
template <class Fn>
prefix_ void senf::console::detail::CheckVoidReturn<Type>::call(Fn fn, std::ostream & os)
{
ReturnValueTraits<Type>::format(fn(),os);
os << "\n";
}
template <class Fn>
prefix_ void senf::console::detail::CheckVoidReturn<void>::call(Fn fn, std::ostream & os)
{
fn();
}
///////////////////////////////cti.e///////////////////////////////////////
#undef prefix_
......
......@@ -37,7 +37,7 @@
#include <boost/parameter/parameters.hpp>
#include "../config.hh"
#include "OverloadedCommand.hh"
#include "ParseParameter.hh"
#include "Traits.hh"
#include "../Utils/type_traits.hh"
#include "ParsedCommand.ih"
......@@ -47,6 +47,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 +71,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 +117,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,8 +134,8 @@ namespace console {
public:
typedef boost::intrusive_ptr<ParsedCommandOverloadBase> ptr;
detail::ParameterInfoBase & arg(unsigned n) const;
template <class Type> detail::ParameterInfo<Type> & arg(unsigned n) const;
detail::ArgumentInfoBase & arg(unsigned n) const;
template <class Type> detail::ArgumentInfo<Type> & arg(unsigned n) const;
void doc(std::string const & d);
......@@ -148,24 +150,56 @@ namespace console {
virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const;
virtual std::string v_doc() const;
typedef std::vector<detail::ParameterInfoBase::ptr> Parameters;
typedef std::vector<detail::ArgumentInfoBase::ptr> Parameters;
Parameters parameters_;
std::string doc_;
};
/** \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.
*/
template <class FunctionTraits, unsigned arity=FunctionTraits::arity>
class ParsedCommandOverload {};
class ParsedCommandOverload : public ParsedCommandOverloadBase
{
public:
typedef boost::intrusive_ptr<ParsedCommandOverload> 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.
*/
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);
......@@ -184,75 +218,133 @@ 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.
\fixme Implement compile-time checking, that after a defaulted arg only defaulted args are
allowed.
*/
template <class Overload>
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 <a
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>
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.
*/
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
BOOST_PARAMETER_KEYWORD(type, description) ///< One-line Argument description
BOOST_PARAMETER_KEYWORD(type, default_value) ///< Argument default value
}
/** \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.
*/
template <class Overload, class Self>
class ParsedAttributeAttributorBase
class ParsedArgumentAttributorBase
: public ParsedCommandAttributor<Overload>
{
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
protected:
ParsedAttributeAttributorBase(Overload & overload, unsigned index);
ParsedArgumentAttributorBase(Overload & overload, unsigned index);
private:
};
/** \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.
*/
template < class Overload,
unsigned index=0,
bool flag=(index < unsigned(Overload::traits::arity)) >
class ParsedAttributeAttributor
: public ParsedAttributeAttributorBase< Overload,
ParsedAttributeAttributor<Overload, index, flag> >
class ParsedArgumentAttributor
: public ParsedArgumentAttributorBase< Overload,
ParsedArgumentAttributor<Overload, index, flag> >
{
typedef boost::parameter::parameters<
kw::type::name,
kw::type::description,
kw::type::default_value> arg_params;
public:
typedef OverloadedCommandNode node_type;
typedef ParsedArgumentAttributor return_type;
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<Overload, index+1> next_type;
typedef ParsedArgumentAttributor<Overload, index+1> next_type;
typedef OverloadedCommandNode node_type;
typedef ParsedAttributeAttributor return_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 <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.
typedef boost::parameter::parameters<
kw::type::name,
kw::type::description,
kw::type::default_value> arg_params;
This member is only present, if there is an argument at
the current index. */
next_type arg() const;
#ifndef DOXYVEN
# define BOOST_PP_ITERATION_PARAMS_1 \
(4, (1, 3, SENF_ABSOLUTE_INCLUDE_PATH(Console/ParsedCommand.mpp), 5))
# include BOOST_PP_ITERATE()
#endif
private:
explicit ParsedAttributeAttributor(Overload & overload);
explicit ParsedArgumentAttributor(Overload & overload);
template <class ArgumentPack>
next_type argInfo(ArgumentPack const & args) const;
template <class Kw, class ArgumentPack>
void argInfo(Kw const &, ArgumentPack const &, boost::mpl::true_)
const;
template <class ArgumentPack>
void argInfo(boost::parameter::keyword<kw::type::name> const &,
ArgumentPack const & args, boost::mpl::false_)
......@@ -271,44 +363,50 @@ namespace console {
void defaultValue(value_type const & value) const;
template <class O, unsigned i, bool f>
friend class ParsedAttributeAttributor;
friend class ParsedArgumentAttributor;
#ifndef DOXYGEN
template <class Function>
friend ParsedAttributeAttributor<
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 ParsedAttributeAttributor<
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
};
#ifndef DOXYGEN
template <class Overload, unsigned index>
class ParsedAttributeAttributor<Overload, index, false>
: public ParsedAttributeAttributorBase< Overload,
ParsedAttributeAttributor<Overload, index, false> >
class ParsedArgumentAttributor<Overload, index, false>
: public ParsedArgumentAttributorBase< Overload,
ParsedArgumentAttributor<Overload, index, false> >
{
public:
typedef OverloadedCommandNode node_type;
typedef ParsedAttributeAttributor return_type;
typedef ParsedArgumentAttributor return_type;
private:
explicit ParsedAttributeAttributor(Overload & overload);
explicit ParsedArgumentAttributor(Overload & overload);
template <class O, unsigned i, bool f>
friend class ParsedAttributeAttributor;
friend class ParsedArgumentAttributor;
template <class Function>
friend ParsedAttributeAttributor<
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 ParsedAttributeAttributor<
friend ParsedArgumentAttributor<
ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
Function fn, int,
......@@ -316,15 +414,13 @@ namespace console {
detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
};
#ifndef DOXYGEN
template <class Function>
ParsedAttributeAttributor<
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>
ParsedAttributeAttributor<
ParsedArgumentAttributor<
ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
Function fn, int,
......@@ -338,7 +434,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////////////////////////////////////////
......
......@@ -34,10 +34,43 @@ namespace senf {
namespace console {
namespace detail {
#ifndef DOXYGEN
struct ArgumentInfoBase
: public intrusive_refcount
{
typedef boost::intrusive_ptr<ArgumentInfoBase> ptr;
std::string type;
std::string name;
bool hasDefault;
std::string doc;
ArgumentInfoBase(std::string const & type);
virtual std::string defaultValueStr() const = 0;
};
template <class ParameterType>
struct ArgumentInfo
: public ArgumentInfoBase
{
typedef boost::intrusive_ptr<ArgumentInfo> ptr;
static ptr create();
ArgumentInfo();
ParameterType defaultValue;
virtual std::string defaultValueStr() const;
};
template <class Function, bool isFN=senf::is_any_function<Function>::value>
struct ParsedCommandTraits
{};
// FirstArgType returns void, if the function has no arguments, otherwise it returns arg1_type
template <class Traits, bool flag=(Traits::arity>0)>
struct FirstArgType
{
......@@ -54,10 +87,8 @@ namespace detail {
struct ParsedCommandTraits<Function, true>
{
typedef Function base_type;
typedef typename senf::remove_member_pointer<
typename boost::remove_pointer<base_type>::type>::type function_type;
typedef typename senf::remove_any_pointer<base_type>::type function_type;
typedef boost::function_traits<function_type> base_traits;
typedef typename FirstArgType<base_traits>::type first_arg_type;
static const bool has_ostream_arg = boost::is_same<first_arg_type, std::ostream &>::value;
......@@ -73,6 +104,22 @@ namespace detail {
typedef typename senf::member_class<base_type>::type class_type;
};
template <class Type>
struct CheckVoidReturn
{
template <class Fn>
static void call(Fn fn, std::ostream & os);
};
template <>
struct CheckVoidReturn<void>
{
template <class Fn>
static void call(Fn fn, std::ostream & os);
};
#endif
}}}
///////////////////////////////ih.e////////////////////////////////////////
......
......@@ -135,14 +135,11 @@ v_execute(std::ostream & os, ParseCommandInfo const & command)
# define mpp_l(z,n,d) \
mpp_ArgTypeN(n) mpp_ArgN(n) (arg< mpp_ArgTypeN(n) >( n ).defaultValue); \
if (i != i_end) \
detail::ParameterTraits< mpp_ArgTypeN(n) >::parse( *(i++), mpp_ArgN(n) );
ArgumentTraits< mpp_ArgTypeN(n) >::parse( *(i++), mpp_ArgN(n) );
BOOST_PP_REPEAT( BOOST_PP_ITERATION(), mpp_l, _ )
# undef mpp_l
// Now call the function binding the arguments to the values parsed above. callAndWrite is
// specialized to ignore a 'void' return value but automatically write all other values to the
// output stream.
detail::ReturnValueTraits<typename traits::result_type>::callAndWrite(
detail::CheckVoidReturn<typename traits::result_type>::call(
boost::bind(function_, boost::ref(os)
mpp_TrailingArgs()),
os );
......
......@@ -163,6 +163,8 @@ namespace console {
Owner * owner_;
};
#ifndef DOXYGEN
template <>
class ScopedDirectory<void> : public ScopedDirectoryBase
{
......@@ -172,7 +174,6 @@ namespace console {
Object const & ob);
};
#ifndef DOXYGEN
template <class Owner, class Function>
SimpleCommandNode & senf_console_add_node(
DirectoryNode & node, Owner & owner, std::string const & name, Function const & fn, ...);
......
......@@ -21,9 +21,9 @@
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief ParseParameter inline template implementation */
\brief Traits inline template implementation */
//#include "ParseParameter.ih"
//#include "Traits.ih"
// Custom includes
#include "../Utils/TypeInfo.hh"
......@@ -31,63 +31,26 @@
#define prefix_ inline
///////////////////////////////cti.p///////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::ParameterInfoBase
prefix_ senf::console::detail::ParameterInfoBase::ParameterInfoBase(std::string const & type_)
: type (type_), name (), hasDefault (false)
{}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::ParameterInfo<ParameterType>
template <class ParameterType>
prefix_ typename senf::console::detail::ParameterInfo<ParameterType>::ptr
senf::console::detail::ParameterInfo<ParameterType>::create()
{
return ptr(new ParameterInfo());
}
template <class ParameterType>
prefix_ senf::console::detail::ParameterInfo<ParameterType>::ParameterInfo()
: ParameterInfoBase ( ParameterTraits<ParameterType>::typeDescription() ),
defaultValue ()
{}
template <class ParameterType>
prefix_ std::string senf::console::detail::ParameterInfo<ParameterType>::defaultValueStr()
const
{
return hasDefault ? ParameterTraits<ParameterType>::dump(defaultValue) : "";
}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::ReturnValueTraits<Type>
template <class Type>
template <class Fn>
prefix_ void senf::console::detail::ReturnValueTraits<Type>::callAndWrite(Fn const & fn,
std::ostream & os)
prefix_ void senf::console::ReturnValueTraits<Type>::format(Type const & value,
std::ostream & os)
{
os << fn() << "\n";
}
template <class Fn>
prefix_ void senf::console::detail::ReturnValueTraits<void>::callAndWrite(Fn const & fn,
std::ostream & os)
{
fn();
os << value;
}
///////////////////////////////////////////////////////////////////////////
// senf::console::detail::ParameterTraits<Type>
// senf::console::ArgumentTraits<Type>
template <class Type>
prefix_ void senf::console::detail::ParameterTraits<Type>::
prefix_ void senf::console::ArgumentTraits<Type>::
parse(ParseCommandInfo::TokensRange const & tokens, Type & out)
{
if (tokens.size() != 1)
throw SyntaxErrorException("parameter syntax error");
try {
out = boost::lexical_cast<Type>(tokens.begin()[0].value());
}
......@@ -97,7 +60,7 @@ parse(ParseCommandInfo::TokensRange const & tokens, Type & out)
}
template <class Type>
prefix_ std::string senf::console::detail::ParameterTraits<Type>::typeDescription()
prefix_ std::string senf::console::ArgumentTraits<Type>::description()
{
std::string type (prettyName(typeid(Type)));
std::string::size_type i (type.rfind(':'));
......@@ -105,7 +68,7 @@ prefix_ std::string senf::console::detail::ParameterTraits<Type>::typeDescriptio
}
template <class Type>
prefix_ std::string senf::console::detail::ParameterTraits<Type>::dump(Type const & value)
prefix_ std::string senf::console::ArgumentTraits<Type>::str(Type const & value)
{
return boost::lexical_cast<std::string>(value);
}
......
......@@ -21,10 +21,10 @@
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief ParseParameter public header */
\brief Traits public header */
#ifndef HH_ParseParameter_
#define HH_ParseParameter_ 1
#ifndef HH_Traits_
#define HH_Traits_ 1
// Custom includes
#include <iostream>
......@@ -33,75 +33,73 @@
#include "Parse.hh"
#include "Node.hh"
//#include "ParseParameter.mpp"
//#include "Traits.mpp"
///////////////////////////////hh.p////////////////////////////////////////
namespace senf {
namespace console {
namespace detail {
struct ParameterInfoBase
: public intrusive_refcount
{
typedef boost::intrusive_ptr<ParameterInfoBase> ptr;
std::string type;
std::string name;
bool hasDefault;
std::string doc;
ParameterInfoBase(std::string const & type);
virtual std::string defaultValueStr() const = 0;
};
template <class ParameterType>
struct ParameterInfo
: public ParameterInfoBase
{
typedef boost::intrusive_ptr<ParameterInfo> ptr;
/** \brief Customize return value formating
static ptr create();
ParameterInfo();
ReturnValueTraits provides return value formatting. The default implementation provided here
will just write the value to the output stream.
ParameterType defaultValue;
To customize this behavior for some type, specialize this class for the type.
virtual std::string defaultValueStr() const;
};
The output should \e not end in a newline since one is added automatically.
*/
template <class Type>
struct ReturnValueTraits
{
typedef Type type;
template <class Fn>
static void callAndWrite(Fn const & fn, std::ostream & os);
static void format(Type const & value, std::ostream & os);
///< Write \a value to \a os
};
template <>
struct ReturnValueTraits<void>
{
typedef void type;
template <class Fn>
static void callAndWrite(Fn const & fn, std::ostream & os);
};
/** \brief Customize argument parsing
ArgumentTraits provides argument parsing, Additionally, this class provides a way to get a
string-description of a type and to convert a value back into it's string representation
used to display default values.
The default implementation provided here will use \c boost::lexical_cast and thereby \c
iostreams to convert an argument consisting of a single input token into the required
type. Types are named by returning the last component of the fully scoped name (e.g. \c
"string" for \c std::string). Values are formatted again using \c boost::lexical_cast.
To customize this behavior for some type, specialize this class for the type.
*/
template <class Type>
struct ParameterTraits
struct ArgumentTraits
{
typedef Type type;
static void parse(ParseCommandInfo::TokensRange const & tokens, Type & out);
static std::string typeDescription();
static std::string dump(Type const & value);
///< Parse token range into value
/**< This function needs to parse \a tokens and write the
parsed value into \a out. This function needs to parse
the \e complete list of tokens, additional tokens must
be considered as syntax error.
\throws SyntaxErrorException
\param[in] tokens tokens to parse
\param[out] out parsed value */
static std::string description(); ///< String description of type
/**< Returns the string description of \a Type. Used to
generate online help. */
static std::string str(Type const & value); ///< Stringify value
/**< To show default values in the online help, this
function converts a value back into a one-line string
representation. */
};
}}}
}}
///////////////////////////////hh.e////////////////////////////////////////
//#include "ParseParameter.cci"
//#include "ParseParameter.ct"
#include "ParseParameter.cti"
//#include "Traits.cci"
//#include "Traits.ct"
#include "Traits.cti"
#endif
......
......@@ -21,13 +21,13 @@
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/** \file
\brief ParseParameter.test unit tests */
\brief Traits.test unit tests */
//#include "ParseParameter.test.hh"
//#include "ParseParameter.test.ih"
//#include "Traits.test.hh"
//#include "Traits.test.ih"
// Custom includes
#include "ParseParameter.hh"
#include "Traits.hh"
#include "../Utils/auto_unit_test.hh"
#include <boost/test/test_tools.hpp>
......
......@@ -174,6 +174,8 @@ senf::ConcretePacket<PacketType>::create(size_type size, senf::NoInit_t)
return ConcretePacket(interpreter::create(size,senf::noinit));
}
#ifndef DOXYGEN
template <class PacketType>
template <class ForwardReadableRange>
prefix_ senf::ConcretePacket<PacketType> senf::ConcretePacket<PacketType>::
......@@ -192,6 +194,8 @@ senf::ConcretePacket<PacketType>::createAfter(Packet packet)
return ConcretePacket(interpreter::createAfter(packet.ptr()));
}
#endif
template <class PacketType>
prefix_ senf::ConcretePacket<PacketType>
senf::ConcretePacket<PacketType>::createAfter(Packet packet, senf::NoInit_t)
......
......@@ -1165,7 +1165,8 @@ PREDEFINED = DOXYGEN \
"SENF_LOG_CLASS_AREA()=" \
"SENF_LOG_DEFAULT_AREA(area)=" \
"SENF_LOG_DEFAULT_STREAM(stream)=" \
"BOOST_PP_ITERATE()="
"BOOST_PP_ITERATE()=" \
"BOOST_PARAMETER_KEYWORD(ns, name)=unspecified_keyword_type name;"
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
......
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings">
<xsl:output
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment