Console: More flexible default_value handling
[senf.git] / Console / ParsedCommand.mpp
index 57948c1..3d998c4 100644 (file)
 // Custom includes
 #include <boost/preprocessor/iteration/iterate.hpp>
 #include <boost/preprocessor/repetition/enum_trailing.hpp>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/repetition/enum_binary_params.hpp>
 #include <boost/preprocessor/cat.hpp>
 #include <boost/preprocessor/arithmetic/inc.hpp>
+#include <boost/preprocessor/arithmetic/sub.hpp>
 #include <boost/preprocessor/repetition/repeat.hpp>
 #include <boost/type_traits/remove_reference.hpp>
 #include <boost/type_traits/remove_const.hpp>
@@ -70,9 +73,8 @@ public:
                                                          mpp_TrailingArgTypes())> Function;
 
 #   define mpp_l(z,n,d)                                                                           \
-        typedef typename boost::remove_const<                                                     \
-            typename boost::remove_reference< typename traits::mpp_ArgTypeN(n) >::type >::type    \
-                mpp_ArgTypeN(n);
+        typedef typename senf::remove_cvref< typename traits::mpp_ArgTypeN(n) >::type             \
+            mpp_ArgTypeN(n);
     BOOST_PP_REPEAT( BOOST_PP_ITERATION(), mpp_l, _ )
 #   undef mpp_l
 
@@ -123,40 +125,27 @@ prefix_ void senf::console::ParsedCommandOverload<FunctionTraits, BOOST_PP_ITERA
 v_execute(std::ostream & os, ParseCommandInfo const & command)
     const
 {
-    if ( command.arguments().size() > BOOST_PP_ITERATION()
-         || (command.arguments().size() < BOOST_PP_ITERATION()
-             && ! arg( BOOST_PP_ITERATION()-1 ).hasDefault) )
+    if ( command.arguments().size() > BOOST_PP_ITERATION() )
         throw SyntaxErrorException("invalid number of arguments");
+    int nDefaults ( BOOST_PP_ITERATION() - command.arguments().size() );
 
-    // First define local variables argN for the parameters. The variables are initialized to their
-    // default values
-#   define mpp_l(z,n,d) mpp_ArgTypeN(n) mpp_ArgN(n) (arg< mpp_ArgTypeN(n) >( n ).defaultValue);
-    BOOST_PP_REPEAT( BOOST_PP_ITERATION(), mpp_l, _ ) 
-#   undef mpp_l
-    
-    ParseCommandInfo::argument_iterator i (command.arguments().begin());
-    ParseCommandInfo::argument_iterator const i_end (command.arguments().end());
-
-    // Now parse the arguments which are provided leaving the trailing arguments at their default
-    // value. We have already checked above, whether those default values are valid. Be aware, that
-    // the following cases do NOT have 'break' statements !
-
-    switch (BOOST_PP_ITERATION() - command.arguments().size()) {
+    typedef typename boost::range_const_reverse_iterator<ParseCommandInfo::ArgumentsRange>::type
+        riterator;
+    riterator i (boost::rbegin(command.arguments()));
+    riterator const i_end (boost::rend(command.arguments()));
 
 #   define mpp_l(z,n,d)                                                                           \
-        case n :                                                                                  \
-            detail::ParameterTraits< mpp_ArgTypeN(n) >::parse( *(i++), mpp_ArgN(n) );
-    BOOST_PP_REPEAT( BOOST_PP_ITERATION(), mpp_l, _ ) 
+        if (i == i_end)                                                                           \
+            throw SyntaxErrorException("invalid number of arguments");                            \
+        mpp_ArgTypeN(n) mpp_ArgN(n) (arg< mpp_ArgTypeN(n) >( n ).defaultValue);                   \
+        if (! arg(n).hasDefault || nDefaults-- <= 0)                                              \
+            ArgumentTraits< mpp_ArgTypeN(n) >::parse( *(i++), mpp_ArgN(n) );
+#   define mpp_l_(z,n,d) mpp_l(z, BOOST_PP_SUB(BOOST_PP_DEC(BOOST_PP_ITERATION()), n), d)
+    BOOST_PP_REPEAT( BOOST_PP_ITERATION(), mpp_l_, _ ) 
 #   undef mpp_l
+#   undef mpp_l_
 
-    default : // This happens, if ALL arguments are defaulted
-        ;
-    }
-
-    // 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 );
@@ -183,6 +172,19 @@ struct CreateParsedCommandOverload<Traits, true, BOOST_PP_ITERATION()>
 };
 
 // ////////////////////////////////////////////////////////////////////////
+#elif BOOST_PP_ITERATION_FLAGS()==5 // ////////////////////////////////////
+// ////////////////////////////////////////////////////////////////////////
+
+// Create keyword arg forwarding functions
+
+template <BOOST_PP_ENUM_PARAMS( BOOST_PP_ITERATION(), class A ) > 
+next_type arg ( BOOST_PP_ENUM_BINARY_PARAMS( BOOST_PP_ITERATION(), A, const & a ),
+                typename arg_params::match< BOOST_PP_ENUM_PARAMS( BOOST_PP_ITERATION(), A ) >::type
+                    kw = arg_params()) const {
+    return argInfo( kw(BOOST_PP_ENUM_PARAMS( BOOST_PP_ITERATION(), a )) );
+}
+
+// ////////////////////////////////////////////////////////////////////////
 #endif // /////////////////////////////////////////////////////////////////
 // ////////////////////////////////////////////////////////////////////////
 // Undefine local Macros