mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-31 12:17:11 +01:00 
			
		
		
		
	New version of Clara
This commit is contained in:
		
							
								
								
									
										497
									
								
								include/external/clara.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										497
									
								
								include/external/clara.hpp
									
									
									
									
										vendored
									
									
								
							| @@ -4,11 +4,13 @@ | ||||
| #ifndef CATCH_CLARA_HPP_INCLUDED | ||||
| #define CATCH_CLARA_HPP_INCLUDED | ||||
|  | ||||
|  | ||||
| #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH | ||||
| #define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 | ||||
| #endif | ||||
|  | ||||
| #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH | ||||
| #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH | ||||
| #endif | ||||
|  | ||||
| // ----------- #included from clara_textflow.hpp ----------- | ||||
|  | ||||
| @@ -24,7 +26,6 @@ | ||||
| #ifndef CATCH_CLARA_TEXTFLOW_HPP_INCLUDED | ||||
| #define CATCH_CLARA_TEXTFLOW_HPP_INCLUDED | ||||
|  | ||||
|  | ||||
| #include <cassert> | ||||
| #include <ostream> | ||||
| #include <sstream> | ||||
| @@ -350,9 +351,8 @@ namespace Catch { namespace clara { namespace TextFlow { | ||||
| #include <set> | ||||
| #include <algorithm> | ||||
|  | ||||
| #if !defined(CLARA_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) | ||||
| #define CLARA_PLATFORM_WINDOWS | ||||
|  | ||||
| #if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) | ||||
| #define CATCH_PLATFORM_WINDOWS | ||||
| #endif | ||||
|  | ||||
| namespace Catch { namespace clara { | ||||
| @@ -360,15 +360,15 @@ namespace detail { | ||||
|  | ||||
|     // Traits for extracting arg and return type of lambdas (for single argument lambdas) | ||||
|     template<typename L> | ||||
|     struct UnaryLambdaTraits : UnaryLambdaTraits<decltype(&L::operator())> {}; | ||||
|     struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {}; | ||||
|  | ||||
|     template<typename ClassT, typename ReturnT, typename... Args> | ||||
|     struct UnaryLambdaTraits<ReturnT(ClassT::*)(Args...) const> { | ||||
|     struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> { | ||||
|         static const bool isValid = false; | ||||
|     }; | ||||
|  | ||||
|     template<typename ClassT, typename ReturnT, typename ArgT> | ||||
|     struct UnaryLambdaTraits<ReturnT(ClassT::*)(ArgT) const> { | ||||
|     struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> { | ||||
|         static const bool isValid = true; | ||||
|         using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;; | ||||
|         using ReturnType = ReturnT; | ||||
| @@ -383,13 +383,13 @@ namespace detail { | ||||
|         std::vector<std::string> m_args; | ||||
|  | ||||
|     public: | ||||
|         Args(int argc, char *argv[]) { | ||||
|         Args( int argc, char *argv[] ) { | ||||
|             m_exeName = argv[0]; | ||||
|             for (int i = 1; i < argc; ++i) | ||||
|                 m_args.push_back(argv[i]); | ||||
|             for( int i = 1; i < argc; ++i ) | ||||
|                 m_args.push_back( argv[i] ); | ||||
|         } | ||||
|  | ||||
|         Args(std::initializer_list<std::string> args) | ||||
|         Args( std::initializer_list<std::string> args ) | ||||
|         :   m_exeName( *args.begin() ), | ||||
|             m_args( args.begin()+1, args.end() ) | ||||
|         {} | ||||
| @@ -417,40 +417,40 @@ namespace detail { | ||||
|         std::vector<Token> m_tokenBuffer; | ||||
|  | ||||
|         void loadBuffer() { | ||||
|             m_tokenBuffer.resize(0); | ||||
|             m_tokenBuffer.resize( 0 ); | ||||
|  | ||||
|             // Skip any empty strings | ||||
|             while (it != itEnd && it->empty()) | ||||
|             while( it != itEnd && it->empty() ) | ||||
|                 ++it; | ||||
|  | ||||
|             if (it != itEnd) { | ||||
|             if( it != itEnd ) { | ||||
|                 auto const &next = *it; | ||||
|                 if (next[0] == '-' || next[0] == '/') { | ||||
|                     auto delimiterPos = next.find_first_of(" :="); | ||||
|                     if (delimiterPos != std::string::npos) { | ||||
|                         m_tokenBuffer.push_back({TokenType::Option, next.substr(0, delimiterPos)}); | ||||
|                         m_tokenBuffer.push_back({TokenType::Argument, next.substr(delimiterPos + 1)}); | ||||
|                 if( next[0] == '-' || next[0] == '/' ) { | ||||
|                     auto delimiterPos = next.find_first_of( " :=" ); | ||||
|                     if( delimiterPos != std::string::npos ) { | ||||
|                         m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); | ||||
|                         m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); | ||||
|                     } else { | ||||
|                         if (next[1] != '-' && next.size() > 2) { | ||||
|                         if( next[1] != '-' && next.size() > 2 ) { | ||||
|                             std::string opt = "- "; | ||||
|                             for (size_t i = 1; i < next.size(); ++i) { | ||||
|                             for( size_t i = 1; i < next.size(); ++i ) { | ||||
|                                 opt[1] = next[i]; | ||||
|                                 m_tokenBuffer.push_back({TokenType::Option, opt}); | ||||
|                                 m_tokenBuffer.push_back( { TokenType::Option, opt } ); | ||||
|                             } | ||||
|                         } else { | ||||
|                             m_tokenBuffer.push_back({TokenType::Option, next}); | ||||
|                             m_tokenBuffer.push_back( { TokenType::Option, next } ); | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     m_tokenBuffer.push_back({TokenType::Argument, next}); | ||||
|                     m_tokenBuffer.push_back( { TokenType::Argument, next } ); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     public: | ||||
|         explicit TokenStream(Args const &args) : TokenStream(args.m_args.begin(), args.m_args.end()) {} | ||||
|         explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} | ||||
|  | ||||
|         TokenStream(Iterator it, Iterator itEnd) : it(it), itEnd(itEnd) { | ||||
|         TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { | ||||
|             loadBuffer(); | ||||
|         } | ||||
|  | ||||
| @@ -461,20 +461,20 @@ namespace detail { | ||||
|         auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } | ||||
|  | ||||
|         auto operator*() const -> Token { | ||||
|             assert(!m_tokenBuffer.empty()); | ||||
|             assert( !m_tokenBuffer.empty() ); | ||||
|             return m_tokenBuffer.front(); | ||||
|         } | ||||
|  | ||||
|         auto operator->() const -> Token const * { | ||||
|             assert(!m_tokenBuffer.empty()); | ||||
|             assert( !m_tokenBuffer.empty() ); | ||||
|             return &m_tokenBuffer.front(); | ||||
|         } | ||||
|  | ||||
|         auto operator++() -> TokenStream & { | ||||
|             if (m_tokenBuffer.size() >= 2) { | ||||
|                 m_tokenBuffer.erase(m_tokenBuffer.begin()); | ||||
|             if( m_tokenBuffer.size() >= 2 ) { | ||||
|                 m_tokenBuffer.erase( m_tokenBuffer.begin() ); | ||||
|             } else { | ||||
|                 if (it != itEnd) | ||||
|                 if( it != itEnd ) | ||||
|                     ++it; | ||||
|                 loadBuffer(); | ||||
|             } | ||||
| @@ -490,7 +490,7 @@ namespace detail { | ||||
|         }; | ||||
|  | ||||
|     protected: | ||||
|         ResultBase(Type type) : m_type(type) {} | ||||
|         ResultBase( Type type ) : m_type( type ) {} | ||||
|         virtual ~ResultBase() = default; | ||||
|  | ||||
|         virtual void enforceOk() const = 0; | ||||
| @@ -507,28 +507,28 @@ namespace detail { | ||||
|         } | ||||
|  | ||||
|     protected: | ||||
|         ResultValueBase(Type type) : ResultBase(type) {} | ||||
|         ResultValueBase( Type type ) : ResultBase( type ) {} | ||||
|  | ||||
|         ResultValueBase(ResultValueBase const &other) : ResultBase(other) { | ||||
|             if (m_type == ResultBase::Ok) | ||||
|                 new(&m_value) T(other.m_value); | ||||
|         ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { | ||||
|             if( m_type == ResultBase::Ok ) | ||||
|                 new( &m_value ) T( other.m_value ); | ||||
|         } | ||||
|  | ||||
|         ResultValueBase(Type, T const &value) : ResultBase(Ok) { | ||||
|             new(&m_value) T(value); | ||||
|         ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { | ||||
|             new( &m_value ) T( value ); | ||||
|         } | ||||
|  | ||||
|         auto operator=(ResultValueBase const &other) -> ResultValueBase & { | ||||
|             if (m_type == ResultBase::Ok) | ||||
|         auto operator=( ResultValueBase const &other ) -> ResultValueBase & { | ||||
|             if( m_type == ResultBase::Ok ) | ||||
|                 m_value.~T(); | ||||
|             ResultBase::operator=(other); | ||||
|             if (m_type == ResultBase::Ok) | ||||
|                 new(&m_value) T(other.m_value); | ||||
|             if( m_type == ResultBase::Ok ) | ||||
|                 new( &m_value ) T( other.m_value ); | ||||
|             return *this; | ||||
|         } | ||||
|  | ||||
|         ~ResultValueBase() { | ||||
|             if (m_type == Ok) | ||||
|             if( m_type == Ok ) | ||||
|                 m_value.~T(); | ||||
|         } | ||||
|  | ||||
| @@ -547,37 +547,31 @@ namespace detail { | ||||
|     class BasicResult : public ResultValueBase<T> { | ||||
|     public: | ||||
|         template<typename U> | ||||
|         explicit BasicResult(BasicResult<U> const &other) | ||||
|                 :   ResultValueBase<T>(other.type()), | ||||
|                     m_errorMessage(other.errorMessage()) { | ||||
|             assert(type() != ResultBase::Ok); | ||||
|         explicit BasicResult( BasicResult<U> const &other ) | ||||
|         :   ResultValueBase<T>( other.type() ), | ||||
|             m_errorMessage( other.errorMessage() ) | ||||
|         { | ||||
|             assert( type() != ResultBase::Ok ); | ||||
|         } | ||||
|  | ||||
|         static auto ok() -> BasicResult { return {ResultBase::Ok}; } | ||||
|  | ||||
|         template<typename U> | ||||
|         static auto ok(U const &value) -> BasicResult { return {ResultBase::Ok, value}; } | ||||
|  | ||||
|         static auto logicError(std::string const &message) -> BasicResult { return {ResultBase::LogicError, message}; } | ||||
|  | ||||
|         static auto runtimeError(std::string const &message) -> BasicResult { | ||||
|             return {ResultBase::RuntimeError, message}; | ||||
|         } | ||||
|         static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } | ||||
|         static auto ok() -> BasicResult { return { ResultBase::Ok }; } | ||||
|         static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } | ||||
|         static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } | ||||
|  | ||||
|         explicit operator bool() const { return m_type == ResultBase::Ok; } | ||||
|  | ||||
|         auto type() const -> ResultBase::Type { return m_type; } | ||||
|  | ||||
|         auto errorMessage() const -> std::string { return m_errorMessage; } | ||||
|  | ||||
|     protected: | ||||
|         virtual void enforceOk() const { | ||||
|             // !TBD: If no exceptions, std::terminate here or something | ||||
|             switch (m_type) { | ||||
|             switch( m_type ) { | ||||
|                 case ResultBase::LogicError: | ||||
|                     throw std::logic_error(m_errorMessage); | ||||
|                     throw std::logic_error( m_errorMessage ); | ||||
|                 case ResultBase::RuntimeError: | ||||
|                     throw std::runtime_error(m_errorMessage); | ||||
|                     throw std::runtime_error( m_errorMessage ); | ||||
|                 case ResultBase::Ok: | ||||
|                     break; | ||||
|             } | ||||
| @@ -585,10 +579,11 @@ namespace detail { | ||||
|  | ||||
|         std::string m_errorMessage; // Only populated if resultType is an error | ||||
|  | ||||
|         BasicResult(ResultBase::Type type, std::string const &message) | ||||
|                 : ResultValueBase<T>(type), | ||||
|                   m_errorMessage(message) { | ||||
|             assert(m_type != ResultBase::Ok); | ||||
|         BasicResult( ResultBase::Type type, std::string const &message ) | ||||
|         :   ResultValueBase<T>(type), | ||||
|             m_errorMessage(message) | ||||
|         { | ||||
|             assert( m_type != ResultBase::Ok ); | ||||
|         } | ||||
|  | ||||
|         using ResultValueBase<T>::ResultValueBase; | ||||
| @@ -602,12 +597,12 @@ namespace detail { | ||||
|     class ParseState { | ||||
|     public: | ||||
|  | ||||
|         ParseState(ParseResultType type, TokenStream const &remainingTokens) | ||||
|                 : m_type(type), | ||||
|                   m_remainingTokens(remainingTokens) {} | ||||
|         ParseState( ParseResultType type, TokenStream const &remainingTokens ) | ||||
|         : m_type(type), | ||||
|           m_remainingTokens( remainingTokens ) | ||||
|         {} | ||||
|  | ||||
|         auto type() const -> ParseResultType { return m_type; } | ||||
|  | ||||
|         auto remainingTokens() const -> TokenStream { return m_remainingTokens; } | ||||
|  | ||||
|     private: | ||||
| @@ -625,69 +620,62 @@ namespace detail { | ||||
|     }; | ||||
|  | ||||
|     template<typename T> | ||||
|     inline auto convertInto(std::string const &source, T& target) -> ParserResult { | ||||
|     inline auto convertInto( std::string const &source, T& target ) -> ParserResult { | ||||
|         std::stringstream ss; | ||||
|         ss << source; | ||||
|         ss >> target; | ||||
|         if (ss.fail()) | ||||
|             return ParserResult::runtimeError("Unable to convert '" + source + "' to destination type"); | ||||
|         if( ss.fail() ) | ||||
|             return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); | ||||
|         else | ||||
|             return ParserResult::ok(ParseResultType::Matched); | ||||
|             return ParserResult::ok( ParseResultType::Matched ); | ||||
|     } | ||||
|     inline auto convertInto(std::string const &source, std::string& target) -> ParserResult { | ||||
|     inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { | ||||
|         target = source; | ||||
|         return ParserResult::ok(ParseResultType::Matched); | ||||
|         return ParserResult::ok( ParseResultType::Matched ); | ||||
|     } | ||||
|     inline auto convertInto(std::string const &source, bool &target) -> ParserResult { | ||||
|     inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { | ||||
|         std::string srcLC = source; | ||||
|         std::transform(srcLC.begin(), srcLC.end(), srcLC.begin(), [](char c) { return static_cast<char>( ::tolower(c) ); } ); | ||||
|         std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } ); | ||||
|         if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") | ||||
|             target = true; | ||||
|         else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") | ||||
|             target = false; | ||||
|         else | ||||
|             return ParserResult::runtimeError("Expected a boolean value but did not recognise: '" + source + "'"); | ||||
|         return ParserResult::ok(ParseResultType::Matched); | ||||
|             return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); | ||||
|         return ParserResult::ok( ParseResultType::Matched ); | ||||
|     } | ||||
|  | ||||
|     struct BoundRefBase { | ||||
|         BoundRefBase() = default; | ||||
|  | ||||
|         BoundRefBase(BoundRefBase const &) = delete; | ||||
|  | ||||
|         BoundRefBase(BoundRefBase &&) = delete; | ||||
|  | ||||
|         BoundRefBase &operator=(BoundRefBase const &) = delete; | ||||
|  | ||||
|         BoundRefBase &operator=(BoundRefBase &&) = delete; | ||||
|         BoundRefBase( BoundRefBase const & ) = delete; | ||||
|         BoundRefBase( BoundRefBase && ) = delete; | ||||
|         BoundRefBase &operator=( BoundRefBase const & ) = delete; | ||||
|         BoundRefBase &operator=( BoundRefBase && ) = delete; | ||||
|  | ||||
|         virtual ~BoundRefBase() = default; | ||||
|  | ||||
|         virtual auto isFlag() const -> bool = 0; | ||||
|  | ||||
|         virtual auto isContainer() const -> bool { return false; } | ||||
|  | ||||
|         virtual auto setValue(std::string const &arg) -> ParserResult = 0; | ||||
|  | ||||
|         virtual auto setFlag(bool flag) -> ParserResult = 0; | ||||
|         virtual auto setValue( std::string const &arg ) -> ParserResult = 0; | ||||
|         virtual auto setFlag( bool flag ) -> ParserResult = 0; | ||||
|     }; | ||||
|  | ||||
|     struct BoundValueRefBase : BoundRefBase { | ||||
|         auto isFlag() const -> bool override { return false; } | ||||
|  | ||||
|         auto setFlag(bool) -> ParserResult override { | ||||
|             return ParserResult::logicError("Flags can only be set on boolean fields"); | ||||
|         auto setFlag( bool ) -> ParserResult override { | ||||
|             return ParserResult::logicError( "Flags can only be set on boolean fields" ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     struct BoundFlagRefBase : BoundRefBase { | ||||
|         auto isFlag() const -> bool override { return true; } | ||||
|  | ||||
|         auto setValue(std::string const &arg) -> ParserResult override { | ||||
|         auto setValue( std::string const &arg ) -> ParserResult override { | ||||
|             bool flag; | ||||
|             auto result = convertInto(arg, flag); | ||||
|             if (result) | ||||
|                 setFlag(flag); | ||||
|             auto result = convertInto( arg, flag ); | ||||
|             if( result ) | ||||
|                 setFlag( flag ); | ||||
|             return result; | ||||
|         } | ||||
|     }; | ||||
| @@ -696,10 +684,10 @@ namespace detail { | ||||
|     struct BoundRef : BoundValueRefBase { | ||||
|         T &m_ref; | ||||
|  | ||||
|         explicit BoundRef(T &ref) : m_ref(ref) {} | ||||
|         explicit BoundRef( T &ref ) : m_ref( ref ) {} | ||||
|  | ||||
|         auto setValue(std::string const &arg) -> ParserResult override { | ||||
|             return convertInto(arg, m_ref); | ||||
|         auto setValue( std::string const &arg ) -> ParserResult override { | ||||
|             return convertInto( arg, m_ref ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| @@ -707,15 +695,15 @@ namespace detail { | ||||
|     struct BoundRef<std::vector<T>> : BoundValueRefBase { | ||||
|         std::vector<T> &m_ref; | ||||
|  | ||||
|         explicit BoundRef(std::vector<T> &ref) : m_ref(ref) {} | ||||
|         explicit BoundRef( std::vector<T> &ref ) : m_ref( ref ) {} | ||||
|  | ||||
|         auto isContainer() const -> bool override { return true; } | ||||
|  | ||||
|         auto setValue(std::string const &arg) -> ParserResult override { | ||||
|         auto setValue( std::string const &arg ) -> ParserResult override { | ||||
|             T temp; | ||||
|             auto result = convertInto(arg, temp); | ||||
|             if (result) | ||||
|                 m_ref.push_back(temp); | ||||
|             auto result = convertInto( arg, temp ); | ||||
|             if( result ) | ||||
|                 m_ref.push_back( temp ); | ||||
|             return result; | ||||
|         } | ||||
|     }; | ||||
| @@ -723,40 +711,40 @@ namespace detail { | ||||
|     struct BoundFlagRef : BoundFlagRefBase { | ||||
|         bool &m_ref; | ||||
|  | ||||
|         explicit BoundFlagRef(bool &ref) : m_ref(ref) {} | ||||
|         explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} | ||||
|  | ||||
|         auto setFlag(bool flag) -> ParserResult override { | ||||
|         auto setFlag( bool flag ) -> ParserResult override { | ||||
|             m_ref = flag; | ||||
|             return ParserResult::ok(ParseResultType::Matched); | ||||
|             return ParserResult::ok( ParseResultType::Matched ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template<typename ReturnType> | ||||
|     struct LambdaInvoker { | ||||
|         static_assert(std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult"); | ||||
|         static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" ); | ||||
|  | ||||
|         template<typename L, typename ArgType> | ||||
|         static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult { | ||||
|             return lambda(arg); | ||||
|         static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { | ||||
|             return lambda( arg ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template<> | ||||
|     struct LambdaInvoker<void> { | ||||
|         template<typename L, typename ArgType> | ||||
|         static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult { | ||||
|             lambda(arg); | ||||
|             return ParserResult::ok(ParseResultType::Matched); | ||||
|         static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { | ||||
|             lambda( arg ); | ||||
|             return ParserResult::ok( ParseResultType::Matched ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     template<typename ArgType, typename L> | ||||
|     inline auto invokeLambda(L const &lambda, std::string const &arg) -> ParserResult { | ||||
|     inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { | ||||
|         ArgType temp; | ||||
|         auto result = convertInto(arg, temp); | ||||
|         auto result = convertInto( arg, temp ); | ||||
|         return !result | ||||
|                ? result | ||||
|                : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke(lambda, temp); | ||||
|            ? result | ||||
|            : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp ); | ||||
|     }; | ||||
|  | ||||
|  | ||||
| @@ -765,10 +753,10 @@ namespace detail { | ||||
|         L m_lambda; | ||||
|  | ||||
|         static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); | ||||
|         explicit BoundLambda(L const &lambda) : m_lambda(lambda) {} | ||||
|         explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} | ||||
|  | ||||
|         auto setValue(std::string const &arg) -> ParserResult override { | ||||
|             return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(m_lambda, arg); | ||||
|         auto setValue( std::string const &arg ) -> ParserResult override { | ||||
|             return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| @@ -779,16 +767,14 @@ namespace detail { | ||||
|         static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); | ||||
|         static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" ); | ||||
|  | ||||
|         explicit BoundFlagLambda(L const &lambda) : m_lambda(lambda) {} | ||||
|         explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} | ||||
|  | ||||
|         auto setFlag(bool flag) -> ParserResult override { | ||||
|             return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke(m_lambda, flag); | ||||
|         auto setFlag( bool flag ) -> ParserResult override { | ||||
|             return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     enum class Optionality { | ||||
|         Optional, Required | ||||
|     }; | ||||
|     enum class Optionality { Optional, Required }; | ||||
|  | ||||
|     struct Parser; | ||||
|  | ||||
| @@ -799,8 +785,8 @@ namespace detail { | ||||
|         virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult  = 0; | ||||
|         virtual auto cardinality() const -> size_t { return 1; } | ||||
|  | ||||
|         auto parse(Args const &args) const -> InternalParseResult { | ||||
|             return parse( args.exeName(), TokenStream(args)); | ||||
|         auto parse( Args const &args ) const -> InternalParseResult { | ||||
|             return parse( args.exeName(), TokenStream( args ) ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| @@ -808,7 +794,7 @@ namespace detail { | ||||
|     class ComposableParserImpl : public ParserBase { | ||||
|     public: | ||||
|         template<typename T> | ||||
|         auto operator+(T const &other) const -> Parser; | ||||
|         auto operator|( T const &other ) const -> Parser; | ||||
|     }; | ||||
|  | ||||
|     // Common code and state for Args and Opts | ||||
| @@ -820,17 +806,22 @@ namespace detail { | ||||
|         std::string m_hint; | ||||
|         std::string m_description; | ||||
|  | ||||
|         explicit ParserRefImpl(std::shared_ptr<BoundRefBase> const &ref) : m_ref(ref) {} | ||||
|         explicit ParserRefImpl( std::shared_ptr<BoundRefBase> const &ref ) : m_ref( ref ) {} | ||||
|  | ||||
|     public: | ||||
|         template<typename T> | ||||
|         ParserRefImpl(T &ref, std::string const &hint) : m_ref(std::make_shared<BoundRef<T>>(ref)), m_hint(hint) {} | ||||
|         ParserRefImpl( T &ref, std::string const &hint ) | ||||
|         :   m_ref( std::make_shared<BoundRef<T>>( ref ) ), | ||||
|             m_hint( hint ) | ||||
|         {} | ||||
|  | ||||
|         template<typename LambdaT> | ||||
|         ParserRefImpl(LambdaT const &ref, std::string const &hint) : m_ref(std::make_shared<BoundLambda<LambdaT>>(ref)), | ||||
|                                                                      m_hint(hint) {} | ||||
|         ParserRefImpl( LambdaT const &ref, std::string const &hint ) | ||||
|         :   m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ), | ||||
|             m_hint(hint) | ||||
|         {} | ||||
|  | ||||
|         auto operator()(std::string const &description) -> DerivedT & { | ||||
|         auto operator()( std::string const &description ) -> DerivedT & { | ||||
|             m_description = description; | ||||
|             return static_cast<DerivedT &>( *this ); | ||||
|         } | ||||
| @@ -850,7 +841,7 @@ namespace detail { | ||||
|         } | ||||
|  | ||||
|         auto cardinality() const -> size_t override { | ||||
|             if (m_ref->isContainer()) | ||||
|             if( m_ref->isContainer() ) | ||||
|                 return 0; | ||||
|             else | ||||
|                 return 1; | ||||
| @@ -865,13 +856,13 @@ namespace detail { | ||||
|  | ||||
|         template<typename LambdaT> | ||||
|         static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundRefBase> { | ||||
|             return std::make_shared<BoundLambda<LambdaT>>(lambda); | ||||
|             return std::make_shared<BoundLambda<LambdaT>>( lambda) ; | ||||
|         } | ||||
|  | ||||
|     public: | ||||
|         ExeName() : m_name(std::make_shared<std::string>("<executable>")) {} | ||||
|         ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {} | ||||
|  | ||||
|         explicit ExeName(std::string &ref) : ExeName() { | ||||
|         explicit ExeName( std::string &ref ) : ExeName() { | ||||
|             m_ref = std::make_shared<BoundRef<std::string>>( ref ); | ||||
|         } | ||||
|  | ||||
| @@ -882,14 +873,14 @@ namespace detail { | ||||
|  | ||||
|         // The exe name is not parsed out of the normal tokens, but is handled specially | ||||
|         auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { | ||||
|             return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens)); | ||||
|             return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); | ||||
|         } | ||||
|  | ||||
|         auto name() const -> std::string { return *m_name; } | ||||
|         auto set( std::string const& newName ) -> ParserResult { | ||||
|  | ||||
|             auto lastSlash = newName.find_last_of( "\\/" ); | ||||
|             auto filename = (lastSlash == std::string::npos) | ||||
|             auto filename = ( lastSlash == std::string::npos ) | ||||
|                     ? newName | ||||
|                     : newName.substr( lastSlash+1 ); | ||||
|  | ||||
| @@ -905,27 +896,27 @@ namespace detail { | ||||
|     public: | ||||
|         using ParserRefImpl::ParserRefImpl; | ||||
|  | ||||
|         auto parse(std::string const &, TokenStream const &tokens) const -> InternalParseResult override { | ||||
|         auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { | ||||
|             auto validationResult = validate(); | ||||
|             if (!validationResult) | ||||
|                 return InternalParseResult(validationResult); | ||||
|             if( !validationResult ) | ||||
|                 return InternalParseResult( validationResult ); | ||||
|  | ||||
|             auto remainingTokens = tokens; | ||||
|             auto const &token = *remainingTokens; | ||||
|             if (token.type != TokenType::Argument) | ||||
|                 return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, remainingTokens)); | ||||
|             if( token.type != TokenType::Argument ) | ||||
|                 return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); | ||||
|  | ||||
|             auto result = m_ref->setValue(remainingTokens->token); | ||||
|             if (!result) | ||||
|                 return InternalParseResult(result); | ||||
|             auto result = m_ref->setValue( remainingTokens->token ); | ||||
|             if( !result ) | ||||
|                 return InternalParseResult( result ); | ||||
|             else | ||||
|                 return InternalParseResult::ok(ParseState(ParseResultType::Matched, ++remainingTokens)); | ||||
|                 return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     inline auto normaliseOpt(std::string const &optName) -> std::string { | ||||
|         if (optName[0] == '/') | ||||
|             return "-" + optName.substr(1); | ||||
|     inline auto normaliseOpt( std::string const &optName ) -> std::string { | ||||
|         if( optName[0] == '/' ) | ||||
|             return "-" + optName.substr( 1 ); | ||||
|         else | ||||
|             return optName; | ||||
|     } | ||||
| @@ -936,9 +927,9 @@ namespace detail { | ||||
|  | ||||
|     public: | ||||
|         template<typename LambdaT> | ||||
|         explicit Opt( LambdaT const &ref ) : ParserRefImpl(std::make_shared<BoundFlagLambda<LambdaT>>(ref)) {} | ||||
|         explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {} | ||||
|  | ||||
|         explicit Opt( bool &ref ) : ParserRefImpl(std::make_shared<BoundFlagRef>(ref)) {} | ||||
|         explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {} | ||||
|  | ||||
|         template<typename LambdaT> | ||||
|         Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} | ||||
| @@ -946,34 +937,34 @@ namespace detail { | ||||
|         template<typename T> | ||||
|         Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} | ||||
|  | ||||
|         auto operator[](std::string const &optName) -> Opt & { | ||||
|             m_optNames.push_back(optName); | ||||
|         auto operator[]( std::string const &optName ) -> Opt & { | ||||
|             m_optNames.push_back( optName ); | ||||
|             return *this; | ||||
|         } | ||||
|  | ||||
|         auto getHelpColumns() const -> std::vector<HelpColumns> { | ||||
|             std::ostringstream oss; | ||||
|             bool first = true; | ||||
|             for (auto const &opt : m_optNames) { | ||||
|             for( auto const &opt : m_optNames ) { | ||||
|                 if (first) | ||||
|                     first = false; | ||||
|                 else | ||||
|                     oss << ", "; | ||||
|                 oss << opt; | ||||
|             } | ||||
|             if (!m_hint.empty()) | ||||
|             if( !m_hint.empty() ) | ||||
|                 oss << " <" << m_hint << ">"; | ||||
|             return {{oss.str(), m_description}}; | ||||
|             return { { oss.str(), m_description } }; | ||||
|         } | ||||
|  | ||||
|         auto isMatch(std::string const &optToken) const -> bool { | ||||
| #ifdef CLARA_PLATFORM_WINDOWS | ||||
|         auto isMatch( std::string const &optToken ) const -> bool { | ||||
| #ifdef CATCH_PLATFORM_WINDOWS | ||||
|             auto normalisedToken = normaliseOpt( optToken ); | ||||
| #else | ||||
|             auto const &normalisedToken = optToken; | ||||
| #endif | ||||
|             for (auto const &name : m_optNames) { | ||||
|                 if (normaliseOpt(name) == normalisedToken) | ||||
|             for( auto const &name : m_optNames ) { | ||||
|                 if( normaliseOpt( name ) == normalisedToken ) | ||||
|                     return true; | ||||
|             } | ||||
|             return false; | ||||
| @@ -983,46 +974,46 @@ namespace detail { | ||||
|  | ||||
|         auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { | ||||
|             auto validationResult = validate(); | ||||
|             if (!validationResult) | ||||
|                 return InternalParseResult(validationResult); | ||||
|             if( !validationResult ) | ||||
|                 return InternalParseResult( validationResult ); | ||||
|  | ||||
|             auto remainingTokens = tokens; | ||||
|             if (remainingTokens && remainingTokens->type == TokenType::Option) { | ||||
|             if( remainingTokens && remainingTokens->type == TokenType::Option ) { | ||||
|                 auto const &token = *remainingTokens; | ||||
|                 if (isMatch(token.token)) { | ||||
|                     if (m_ref->isFlag()) { | ||||
|                         auto result = m_ref->setFlag(true); | ||||
|                         if (!result) | ||||
|                             return InternalParseResult(result); | ||||
|                         if (result.value() == ParseResultType::ShortCircuitAll) | ||||
|                             return InternalParseResult::ok(ParseState(result.value(), remainingTokens)); | ||||
|                 if( isMatch(token.token ) ) { | ||||
|                     if( m_ref->isFlag() ) { | ||||
|                         auto result = m_ref->setFlag( true ); | ||||
|                         if( !result ) | ||||
|                             return InternalParseResult( result ); | ||||
|                         if( result.value() == ParseResultType::ShortCircuitAll ) | ||||
|                             return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); | ||||
|                     } else { | ||||
|                         ++remainingTokens; | ||||
|                         if (!remainingTokens) | ||||
|                             return InternalParseResult::runtimeError("Expected argument following " + token.token); | ||||
|                         if( !remainingTokens ) | ||||
|                             return InternalParseResult::runtimeError( "Expected argument following " + token.token ); | ||||
|                         auto const &argToken = *remainingTokens; | ||||
|                         if (argToken.type != TokenType::Argument) | ||||
|                             return InternalParseResult::runtimeError("Expected argument following " + token.token); | ||||
|                         auto result = m_ref->setValue(argToken.token); | ||||
|                         if (!result) | ||||
|                             return InternalParseResult(result); | ||||
|                         if (result.value() == ParseResultType::ShortCircuitAll) | ||||
|                             return InternalParseResult::ok(ParseState(result.value(), remainingTokens)); | ||||
|                         if( argToken.type != TokenType::Argument ) | ||||
|                             return InternalParseResult::runtimeError( "Expected argument following " + token.token ); | ||||
|                         auto result = m_ref->setValue( argToken.token ); | ||||
|                         if( !result ) | ||||
|                             return InternalParseResult( result ); | ||||
|                         if( result.value() == ParseResultType::ShortCircuitAll ) | ||||
|                             return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); | ||||
|                     } | ||||
|                     return InternalParseResult::ok(ParseState(ParseResultType::Matched, ++remainingTokens)); | ||||
|                     return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); | ||||
|                 } | ||||
|             } | ||||
|             return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, remainingTokens)); | ||||
|             return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); | ||||
|         } | ||||
|  | ||||
|         auto validate() const -> Result override { | ||||
|             if (m_optNames.empty()) | ||||
|                 return Result::logicError("No options supplied to Opt"); | ||||
|             for (auto const &name : m_optNames) { | ||||
|                 if (name.empty()) | ||||
|                     return Result::logicError("Option name cannot be empty"); | ||||
|                 if (name[0] != '-' && name[0] != '/') | ||||
|                     return Result::logicError("Option name must begin with '-' or '/'"); | ||||
|             if( m_optNames.empty() ) | ||||
|                 return Result::logicError( "No options supplied to Opt" ); | ||||
|             for( auto const &name : m_optNames ) { | ||||
|                 if( name.empty() ) | ||||
|                     return Result::logicError( "Option name cannot be empty" ); | ||||
|                 if( name[0] != '-' && name[0] != '/' ) | ||||
|                     return Result::logicError( "Option name must begin with '-' or '/'" ); | ||||
|             } | ||||
|             return ParserRefImpl::validate(); | ||||
|         } | ||||
| @@ -1031,11 +1022,11 @@ namespace detail { | ||||
|     struct Help : Opt { | ||||
|         Help( bool &showHelpFlag ) | ||||
|         :   Opt([&]( bool flag ) { | ||||
|             showHelpFlag = flag; | ||||
|                 return ParserResult::ok(ParseResultType::ShortCircuitAll); | ||||
|                 showHelpFlag = flag; | ||||
|                 return ParserResult::ok( ParseResultType::ShortCircuitAll ); | ||||
|             }) | ||||
|         { | ||||
|             static_cast<Opt &>(*this) | ||||
|             static_cast<Opt &>( *this ) | ||||
|                     ("display usage information") | ||||
|                     ["-?"]["-h"]["--help"] | ||||
|                     .optional(); | ||||
| @@ -1049,61 +1040,61 @@ namespace detail { | ||||
|         std::vector<Opt> m_options; | ||||
|         std::vector<Arg> m_args; | ||||
|  | ||||
|         auto operator+=(ExeName const &exeName) -> Parser & { | ||||
|         auto operator|=( ExeName const &exeName ) -> Parser & { | ||||
|             m_exeName = exeName; | ||||
|             return *this; | ||||
|         } | ||||
|  | ||||
|         auto operator+=(Arg const &arg) -> Parser & { | ||||
|         auto operator|=( Arg const &arg ) -> Parser & { | ||||
|             m_args.push_back(arg); | ||||
|             return *this; | ||||
|         } | ||||
|  | ||||
|         auto operator+=(Opt const &opt) -> Parser & { | ||||
|         auto operator|=( Opt const &opt ) -> Parser & { | ||||
|             m_options.push_back(opt); | ||||
|             return *this; | ||||
|         } | ||||
|  | ||||
|         auto operator+=(Parser const &other) -> Parser & { | ||||
|         auto operator|=( Parser const &other ) -> Parser & { | ||||
|             m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); | ||||
|             m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); | ||||
|             return *this; | ||||
|         } | ||||
|  | ||||
|         template<typename T> | ||||
|         auto operator+(T const &other) const -> Parser { | ||||
|             return Parser(*this) += other; | ||||
|         auto operator|( T const &other ) const -> Parser { | ||||
|             return Parser( *this ) |= other; | ||||
|         } | ||||
|  | ||||
|         auto getHelpColumns() const -> std::vector<HelpColumns> { | ||||
|             std::vector<HelpColumns> cols; | ||||
|             for (auto const &o : m_options) { | ||||
|                 auto childCols = o.getHelpColumns(); | ||||
|                 cols.insert(cols.end(), childCols.begin(), childCols.end()); | ||||
|                 cols.insert( cols.end(), childCols.begin(), childCols.end() ); | ||||
|             } | ||||
|             return cols; | ||||
|         } | ||||
|  | ||||
|         void writeToStream(std::ostream &os) const { | ||||
|         void writeToStream( std::ostream &os ) const { | ||||
|             if (!m_exeName.name().empty()) { | ||||
|                 os << "usage:\n" << "  " << m_exeName.name() << " "; | ||||
|                 bool required = true, first = true; | ||||
|                 for (auto const &arg : m_args) { | ||||
|                 for( auto const &arg : m_args ) { | ||||
|                     if (first) | ||||
|                         first = false; | ||||
|                     else | ||||
|                         os << " "; | ||||
|                     if (arg.isOptional() && required) { | ||||
|                     if( arg.isOptional() && required ) { | ||||
|                         os << "["; | ||||
|                         required = false; | ||||
|                     } | ||||
|                     os << "<" << arg.hint() << ">"; | ||||
|                     if (arg.cardinality() == 0) | ||||
|                     if( arg.cardinality() == 0 ) | ||||
|                         os << " ... "; | ||||
|                 } | ||||
|                 if (!required) | ||||
|                 if( !required ) | ||||
|                     os << "]"; | ||||
|                 if (!m_options.empty()) | ||||
|                 if( !m_options.empty() ) | ||||
|                     os << " options"; | ||||
|                 os << "\n\nwhere options are:" << std::endl; | ||||
|             } | ||||
| @@ -1111,32 +1102,32 @@ namespace detail { | ||||
|             auto rows = getHelpColumns(); | ||||
|             size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; | ||||
|             size_t optWidth = 0; | ||||
|             for (auto const &cols : rows) | ||||
|             for( auto const &cols : rows ) | ||||
|                 optWidth = std::max(optWidth, cols.left.size() + 2); | ||||
|  | ||||
|             for (auto const &cols : rows) { | ||||
|             for( auto const &cols : rows ) { | ||||
|                 auto row = | ||||
|                         TextFlow::Column(cols.left).width(optWidth).indent(2) + | ||||
|                         TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + | ||||
|                         TextFlow::Spacer(4) + | ||||
|                         TextFlow::Column(cols.right).width(consoleWidth - 7 - optWidth); | ||||
|                         TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); | ||||
|                 os << row << std::endl; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         friend auto operator<<(std::ostream &os, Parser const &parser) -> std::ostream & { | ||||
|             parser.writeToStream(os); | ||||
|         friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { | ||||
|             parser.writeToStream( os ); | ||||
|             return os; | ||||
|         } | ||||
|  | ||||
|         auto validate() const -> Result override { | ||||
|             for (auto const &opt : m_options) { | ||||
|             for( auto const &opt : m_options ) { | ||||
|                 auto result = opt.validate(); | ||||
|                 if (!result) | ||||
|                 if( !result ) | ||||
|                     return result; | ||||
|             } | ||||
|             for (auto const &arg : m_args) { | ||||
|             for( auto const &arg : m_args ) { | ||||
|                 auto result = arg.validate(); | ||||
|                 if (!result) | ||||
|                 if( !result ) | ||||
|                     return result; | ||||
|             } | ||||
|             return Result::ok(); | ||||
| @@ -1144,47 +1135,41 @@ namespace detail { | ||||
|  | ||||
|         using ParserBase::parse; | ||||
|  | ||||
|         auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult override { | ||||
|             std::vector<ParserBase const *> allParsers; | ||||
|             allParsers.reserve(m_args.size() + m_options.size()); | ||||
|             std::set<ParserBase const *> requiredParsers; | ||||
|         auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { | ||||
|  | ||||
|             for (auto const &opt : m_options) { | ||||
|                 allParsers.push_back(&opt); | ||||
|                 if (!opt.isOptional()) | ||||
|                     requiredParsers.insert(&opt); | ||||
|             } | ||||
|  | ||||
|             size_t optionalArgs = 0; | ||||
|             for (auto const &arg : m_args) { | ||||
|                 allParsers.push_back(&arg); | ||||
|                 if (!arg.isOptional()) { | ||||
|                     if (optionalArgs > 0) | ||||
|                         return InternalParseResult::logicError( | ||||
|                                 "Required arguments must preceed any optional arguments"); | ||||
|                     else | ||||
|                         ++optionalArgs; | ||||
|                     requiredParsers.insert(&arg); | ||||
|                 } | ||||
|             } | ||||
|             struct ParserInfo { | ||||
|                 ParserBase const* parser = nullptr; | ||||
|                 size_t count = 0; | ||||
|             }; | ||||
|             const size_t totalParsers = m_options.size() + m_args.size(); | ||||
|             ParserInfo parseInfos[totalParsers]; | ||||
|             size_t i = 0; | ||||
|             for( auto const& opt : m_options ) parseInfos[i++].parser = &opt; | ||||
|             for( auto const& arg : m_args ) parseInfos[i++].parser = &arg; | ||||
|  | ||||
|             m_exeName.set( exeName ); | ||||
|  | ||||
|             auto result = InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens)); | ||||
|             while (result.value().remainingTokens()) { | ||||
|                 auto remainingTokenCount = result.value().remainingTokens().count(); | ||||
|                 for (auto parser : allParsers) { | ||||
|                     result = parser->parse( exeName, result.value().remainingTokens() ); | ||||
|                     if (!result || result.value().type() != ParseResultType::NoMatch) { | ||||
|                         if (parser->cardinality() == 1) | ||||
|                             allParsers.erase(std::remove(allParsers.begin(), allParsers.end(), parser), | ||||
|                                              allParsers.end()); | ||||
|                         requiredParsers.erase(parser); | ||||
|                         break; | ||||
|             auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); | ||||
|             while( result.value().remainingTokens() ) { | ||||
|                 bool tokenParsed = false; | ||||
|  | ||||
|                 for( auto& parseInfo : parseInfos ) { | ||||
|                     if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { | ||||
|                         result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); | ||||
|                         if (!result) | ||||
|                             return result; | ||||
|                         if (result.value().type() != ParseResultType::NoMatch) { | ||||
|                             tokenParsed = true; | ||||
|                             ++parseInfo.count; | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 if (!result || remainingTokenCount == result.value().remainingTokens().count()) | ||||
|  | ||||
|                 if( result.value().type() == ParseResultType::ShortCircuitAll ) | ||||
|                     return result; | ||||
|                 if( !tokenParsed ) | ||||
|                     return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); | ||||
|             } | ||||
|             // !TBD Check missing required options | ||||
|             return result; | ||||
| @@ -1193,8 +1178,8 @@ namespace detail { | ||||
|  | ||||
|     template<typename DerivedT> | ||||
|     template<typename T> | ||||
|     auto ComposableParserImpl<DerivedT>::operator+(T const &other) const -> Parser { | ||||
|         return Parser() + static_cast<DerivedT const &>( *this ) + other; | ||||
|     auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser { | ||||
|         return Parser() | static_cast<DerivedT const &>( *this ) | other; | ||||
|     } | ||||
| } // namespace detail | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Phil Nash
					Phil Nash