mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-22 21:36:11 +01:00
New version of Clara
This commit is contained in:
parent
9541e89e6a
commit
2a1f8ae684
487
include/external/clara.hpp
vendored
487
include/external/clara.hpp
vendored
@ -4,11 +4,13 @@
|
|||||||
#ifndef CATCH_CLARA_HPP_INCLUDED
|
#ifndef CATCH_CLARA_HPP_INCLUDED
|
||||||
#define CATCH_CLARA_HPP_INCLUDED
|
#define CATCH_CLARA_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH
|
#ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH
|
||||||
#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80
|
#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80
|
||||||
#endif
|
#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 -----------
|
// ----------- #included from clara_textflow.hpp -----------
|
||||||
|
|
||||||
@ -24,7 +26,6 @@
|
|||||||
#ifndef CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
|
#ifndef CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
|
||||||
#define CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
|
#define CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@ -350,9 +351,8 @@ namespace Catch { namespace clara { namespace TextFlow {
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#if !defined(CLARA_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )
|
#if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )
|
||||||
#define CLARA_PLATFORM_WINDOWS
|
#define CATCH_PLATFORM_WINDOWS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Catch { namespace clara {
|
namespace Catch { namespace clara {
|
||||||
@ -360,15 +360,15 @@ namespace detail {
|
|||||||
|
|
||||||
// Traits for extracting arg and return type of lambdas (for single argument lambdas)
|
// Traits for extracting arg and return type of lambdas (for single argument lambdas)
|
||||||
template<typename L>
|
template<typename L>
|
||||||
struct UnaryLambdaTraits : UnaryLambdaTraits<decltype(&L::operator())> {};
|
struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};
|
||||||
|
|
||||||
template<typename ClassT, typename ReturnT, typename... Args>
|
template<typename ClassT, typename ReturnT, typename... Args>
|
||||||
struct UnaryLambdaTraits<ReturnT(ClassT::*)(Args...) const> {
|
struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {
|
||||||
static const bool isValid = false;
|
static const bool isValid = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ClassT, typename ReturnT, typename ArgT>
|
template<typename ClassT, typename ReturnT, typename ArgT>
|
||||||
struct UnaryLambdaTraits<ReturnT(ClassT::*)(ArgT) const> {
|
struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
|
||||||
static const bool isValid = true;
|
static const bool isValid = true;
|
||||||
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;;
|
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;;
|
||||||
using ReturnType = ReturnT;
|
using ReturnType = ReturnT;
|
||||||
@ -383,13 +383,13 @@ namespace detail {
|
|||||||
std::vector<std::string> m_args;
|
std::vector<std::string> m_args;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Args(int argc, char *argv[]) {
|
Args( int argc, char *argv[] ) {
|
||||||
m_exeName = argv[0];
|
m_exeName = argv[0];
|
||||||
for (int i = 1; i < argc; ++i)
|
for( int i = 1; i < argc; ++i )
|
||||||
m_args.push_back(argv[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_exeName( *args.begin() ),
|
||||||
m_args( args.begin()+1, args.end() )
|
m_args( args.begin()+1, args.end() )
|
||||||
{}
|
{}
|
||||||
@ -417,40 +417,40 @@ namespace detail {
|
|||||||
std::vector<Token> m_tokenBuffer;
|
std::vector<Token> m_tokenBuffer;
|
||||||
|
|
||||||
void loadBuffer() {
|
void loadBuffer() {
|
||||||
m_tokenBuffer.resize(0);
|
m_tokenBuffer.resize( 0 );
|
||||||
|
|
||||||
// Skip any empty strings
|
// Skip any empty strings
|
||||||
while (it != itEnd && it->empty())
|
while( it != itEnd && it->empty() )
|
||||||
++it;
|
++it;
|
||||||
|
|
||||||
if (it != itEnd) {
|
if( it != itEnd ) {
|
||||||
auto const &next = *it;
|
auto const &next = *it;
|
||||||
if (next[0] == '-' || next[0] == '/') {
|
if( next[0] == '-' || next[0] == '/' ) {
|
||||||
auto delimiterPos = next.find_first_of(" :=");
|
auto delimiterPos = next.find_first_of( " :=" );
|
||||||
if (delimiterPos != std::string::npos) {
|
if( delimiterPos != std::string::npos ) {
|
||||||
m_tokenBuffer.push_back({TokenType::Option, next.substr(0, delimiterPos)});
|
m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
|
||||||
m_tokenBuffer.push_back({TokenType::Argument, next.substr(delimiterPos + 1)});
|
m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );
|
||||||
} else {
|
} else {
|
||||||
if (next[1] != '-' && next.size() > 2) {
|
if( next[1] != '-' && next.size() > 2 ) {
|
||||||
std::string opt = "- ";
|
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];
|
opt[1] = next[i];
|
||||||
m_tokenBuffer.push_back({TokenType::Option, opt});
|
m_tokenBuffer.push_back( { TokenType::Option, opt } );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_tokenBuffer.push_back({TokenType::Option, next});
|
m_tokenBuffer.push_back( { TokenType::Option, next } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_tokenBuffer.push_back({TokenType::Argument, next});
|
m_tokenBuffer.push_back( { TokenType::Argument, next } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
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();
|
loadBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,20 +461,20 @@ namespace detail {
|
|||||||
auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
|
auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
|
||||||
|
|
||||||
auto operator*() const -> Token {
|
auto operator*() const -> Token {
|
||||||
assert(!m_tokenBuffer.empty());
|
assert( !m_tokenBuffer.empty() );
|
||||||
return m_tokenBuffer.front();
|
return m_tokenBuffer.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator->() const -> Token const * {
|
auto operator->() const -> Token const * {
|
||||||
assert(!m_tokenBuffer.empty());
|
assert( !m_tokenBuffer.empty() );
|
||||||
return &m_tokenBuffer.front();
|
return &m_tokenBuffer.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator++() -> TokenStream & {
|
auto operator++() -> TokenStream & {
|
||||||
if (m_tokenBuffer.size() >= 2) {
|
if( m_tokenBuffer.size() >= 2 ) {
|
||||||
m_tokenBuffer.erase(m_tokenBuffer.begin());
|
m_tokenBuffer.erase( m_tokenBuffer.begin() );
|
||||||
} else {
|
} else {
|
||||||
if (it != itEnd)
|
if( it != itEnd )
|
||||||
++it;
|
++it;
|
||||||
loadBuffer();
|
loadBuffer();
|
||||||
}
|
}
|
||||||
@ -490,7 +490,7 @@ namespace detail {
|
|||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ResultBase(Type type) : m_type(type) {}
|
ResultBase( Type type ) : m_type( type ) {}
|
||||||
virtual ~ResultBase() = default;
|
virtual ~ResultBase() = default;
|
||||||
|
|
||||||
virtual void enforceOk() const = 0;
|
virtual void enforceOk() const = 0;
|
||||||
@ -507,28 +507,28 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ResultValueBase(Type type) : ResultBase(type) {}
|
ResultValueBase( Type type ) : ResultBase( type ) {}
|
||||||
|
|
||||||
ResultValueBase(ResultValueBase const &other) : ResultBase(other) {
|
ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {
|
||||||
if (m_type == ResultBase::Ok)
|
if( m_type == ResultBase::Ok )
|
||||||
new(&m_value) T(other.m_value);
|
new( &m_value ) T( other.m_value );
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultValueBase(Type, T const &value) : ResultBase(Ok) {
|
ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {
|
||||||
new(&m_value) T(value);
|
new( &m_value ) T( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator=(ResultValueBase const &other) -> ResultValueBase & {
|
auto operator=( ResultValueBase const &other ) -> ResultValueBase & {
|
||||||
if (m_type == ResultBase::Ok)
|
if( m_type == ResultBase::Ok )
|
||||||
m_value.~T();
|
m_value.~T();
|
||||||
ResultBase::operator=(other);
|
ResultBase::operator=(other);
|
||||||
if (m_type == ResultBase::Ok)
|
if( m_type == ResultBase::Ok )
|
||||||
new(&m_value) T(other.m_value);
|
new( &m_value ) T( other.m_value );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~ResultValueBase() {
|
~ResultValueBase() {
|
||||||
if (m_type == Ok)
|
if( m_type == Ok )
|
||||||
m_value.~T();
|
m_value.~T();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,37 +547,31 @@ namespace detail {
|
|||||||
class BasicResult : public ResultValueBase<T> {
|
class BasicResult : public ResultValueBase<T> {
|
||||||
public:
|
public:
|
||||||
template<typename U>
|
template<typename U>
|
||||||
explicit BasicResult(BasicResult<U> const &other)
|
explicit BasicResult( BasicResult<U> const &other )
|
||||||
: ResultValueBase<T>(other.type()),
|
: ResultValueBase<T>( other.type() ),
|
||||||
m_errorMessage(other.errorMessage()) {
|
m_errorMessage( other.errorMessage() )
|
||||||
assert(type() != ResultBase::Ok);
|
{
|
||||||
|
assert( type() != ResultBase::Ok );
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto ok() -> BasicResult { return {ResultBase::Ok}; }
|
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
static auto ok(U const &value) -> BasicResult { return {ResultBase::Ok, value}; }
|
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 logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }
|
||||||
|
static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }
|
||||||
static auto runtimeError(std::string const &message) -> BasicResult {
|
|
||||||
return {ResultBase::RuntimeError, message};
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit operator bool() const { return m_type == ResultBase::Ok; }
|
explicit operator bool() const { return m_type == ResultBase::Ok; }
|
||||||
|
|
||||||
auto type() const -> ResultBase::Type { return m_type; }
|
auto type() const -> ResultBase::Type { return m_type; }
|
||||||
|
|
||||||
auto errorMessage() const -> std::string { return m_errorMessage; }
|
auto errorMessage() const -> std::string { return m_errorMessage; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void enforceOk() const {
|
virtual void enforceOk() const {
|
||||||
// !TBD: If no exceptions, std::terminate here or something
|
// !TBD: If no exceptions, std::terminate here or something
|
||||||
switch (m_type) {
|
switch( m_type ) {
|
||||||
case ResultBase::LogicError:
|
case ResultBase::LogicError:
|
||||||
throw std::logic_error(m_errorMessage);
|
throw std::logic_error( m_errorMessage );
|
||||||
case ResultBase::RuntimeError:
|
case ResultBase::RuntimeError:
|
||||||
throw std::runtime_error(m_errorMessage);
|
throw std::runtime_error( m_errorMessage );
|
||||||
case ResultBase::Ok:
|
case ResultBase::Ok:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -585,10 +579,11 @@ namespace detail {
|
|||||||
|
|
||||||
std::string m_errorMessage; // Only populated if resultType is an error
|
std::string m_errorMessage; // Only populated if resultType is an error
|
||||||
|
|
||||||
BasicResult(ResultBase::Type type, std::string const &message)
|
BasicResult( ResultBase::Type type, std::string const &message )
|
||||||
: ResultValueBase<T>(type),
|
: ResultValueBase<T>(type),
|
||||||
m_errorMessage(message) {
|
m_errorMessage(message)
|
||||||
assert(m_type != ResultBase::Ok);
|
{
|
||||||
|
assert( m_type != ResultBase::Ok );
|
||||||
}
|
}
|
||||||
|
|
||||||
using ResultValueBase<T>::ResultValueBase;
|
using ResultValueBase<T>::ResultValueBase;
|
||||||
@ -602,12 +597,12 @@ namespace detail {
|
|||||||
class ParseState {
|
class ParseState {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ParseState(ParseResultType type, TokenStream const &remainingTokens)
|
ParseState( ParseResultType type, TokenStream const &remainingTokens )
|
||||||
: m_type(type),
|
: m_type(type),
|
||||||
m_remainingTokens(remainingTokens) {}
|
m_remainingTokens( remainingTokens )
|
||||||
|
{}
|
||||||
|
|
||||||
auto type() const -> ParseResultType { return m_type; }
|
auto type() const -> ParseResultType { return m_type; }
|
||||||
|
|
||||||
auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
|
auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -625,69 +620,62 @@ namespace detail {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
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;
|
std::stringstream ss;
|
||||||
ss << source;
|
ss << source;
|
||||||
ss >> target;
|
ss >> target;
|
||||||
if (ss.fail())
|
if( ss.fail() )
|
||||||
return ParserResult::runtimeError("Unable to convert '" + source + "' to destination type");
|
return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );
|
||||||
else
|
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;
|
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::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")
|
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
|
||||||
target = true;
|
target = true;
|
||||||
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
|
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
|
||||||
target = false;
|
target = false;
|
||||||
else
|
else
|
||||||
return ParserResult::runtimeError("Expected a boolean value but did not recognise: '" + source + "'");
|
return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
|
||||||
return ParserResult::ok(ParseResultType::Matched);
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BoundRefBase {
|
struct BoundRefBase {
|
||||||
BoundRefBase() = default;
|
BoundRefBase() = default;
|
||||||
|
BoundRefBase( BoundRefBase const & ) = delete;
|
||||||
BoundRefBase(BoundRefBase const &) = delete;
|
BoundRefBase( BoundRefBase && ) = delete;
|
||||||
|
BoundRefBase &operator=( BoundRefBase const & ) = delete;
|
||||||
BoundRefBase(BoundRefBase &&) = delete;
|
BoundRefBase &operator=( BoundRefBase && ) = delete;
|
||||||
|
|
||||||
BoundRefBase &operator=(BoundRefBase const &) = delete;
|
|
||||||
|
|
||||||
BoundRefBase &operator=(BoundRefBase &&) = delete;
|
|
||||||
|
|
||||||
virtual ~BoundRefBase() = default;
|
virtual ~BoundRefBase() = default;
|
||||||
|
|
||||||
virtual auto isFlag() const -> bool = 0;
|
virtual auto isFlag() const -> bool = 0;
|
||||||
|
|
||||||
virtual auto isContainer() const -> bool { return false; }
|
virtual auto isContainer() const -> bool { return false; }
|
||||||
|
virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
|
||||||
virtual auto setValue(std::string const &arg) -> ParserResult = 0;
|
virtual auto setFlag( bool flag ) -> ParserResult = 0;
|
||||||
|
|
||||||
virtual auto setFlag(bool flag) -> ParserResult = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BoundValueRefBase : BoundRefBase {
|
struct BoundValueRefBase : BoundRefBase {
|
||||||
auto isFlag() const -> bool override { return false; }
|
auto isFlag() const -> bool override { return false; }
|
||||||
|
|
||||||
auto setFlag(bool) -> ParserResult override {
|
auto setFlag( bool ) -> ParserResult override {
|
||||||
return ParserResult::logicError("Flags can only be set on boolean fields");
|
return ParserResult::logicError( "Flags can only be set on boolean fields" );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BoundFlagRefBase : BoundRefBase {
|
struct BoundFlagRefBase : BoundRefBase {
|
||||||
auto isFlag() const -> bool override { return true; }
|
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;
|
bool flag;
|
||||||
auto result = convertInto(arg, flag);
|
auto result = convertInto( arg, flag );
|
||||||
if (result)
|
if( result )
|
||||||
setFlag(flag);
|
setFlag( flag );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -696,10 +684,10 @@ namespace detail {
|
|||||||
struct BoundRef : BoundValueRefBase {
|
struct BoundRef : BoundValueRefBase {
|
||||||
T &m_ref;
|
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 {
|
auto setValue( std::string const &arg ) -> ParserResult override {
|
||||||
return convertInto(arg, m_ref);
|
return convertInto( arg, m_ref );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -707,15 +695,15 @@ namespace detail {
|
|||||||
struct BoundRef<std::vector<T>> : BoundValueRefBase {
|
struct BoundRef<std::vector<T>> : BoundValueRefBase {
|
||||||
std::vector<T> &m_ref;
|
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 isContainer() const -> bool override { return true; }
|
||||||
|
|
||||||
auto setValue(std::string const &arg) -> ParserResult override {
|
auto setValue( std::string const &arg ) -> ParserResult override {
|
||||||
T temp;
|
T temp;
|
||||||
auto result = convertInto(arg, temp);
|
auto result = convertInto( arg, temp );
|
||||||
if (result)
|
if( result )
|
||||||
m_ref.push_back(temp);
|
m_ref.push_back( temp );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -723,40 +711,40 @@ namespace detail {
|
|||||||
struct BoundFlagRef : BoundFlagRefBase {
|
struct BoundFlagRef : BoundFlagRefBase {
|
||||||
bool &m_ref;
|
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;
|
m_ref = flag;
|
||||||
return ParserResult::ok(ParseResultType::Matched);
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ReturnType>
|
template<typename ReturnType>
|
||||||
struct LambdaInvoker {
|
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>
|
template<typename L, typename ArgType>
|
||||||
static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult {
|
static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
|
||||||
return lambda(arg);
|
return lambda( arg );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct LambdaInvoker<void> {
|
struct LambdaInvoker<void> {
|
||||||
template<typename L, typename ArgType>
|
template<typename L, typename ArgType>
|
||||||
static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult {
|
static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
|
||||||
lambda(arg);
|
lambda( arg );
|
||||||
return ParserResult::ok(ParseResultType::Matched);
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ArgType, typename L>
|
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;
|
ArgType temp;
|
||||||
auto result = convertInto(arg, temp);
|
auto result = convertInto( arg, temp );
|
||||||
return !result
|
return !result
|
||||||
? result
|
? result
|
||||||
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke(lambda, temp);
|
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -765,10 +753,10 @@ namespace detail {
|
|||||||
L m_lambda;
|
L m_lambda;
|
||||||
|
|
||||||
static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
|
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 {
|
auto setValue( std::string const &arg ) -> ParserResult override {
|
||||||
return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(m_lambda, arg);
|
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( 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" );
|
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 {
|
auto setFlag( bool flag ) -> ParserResult override {
|
||||||
return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke(m_lambda, flag);
|
return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Optionality {
|
enum class Optionality { Optional, Required };
|
||||||
Optional, Required
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Parser;
|
struct Parser;
|
||||||
|
|
||||||
@ -799,8 +785,8 @@ namespace detail {
|
|||||||
virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0;
|
virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0;
|
||||||
virtual auto cardinality() const -> size_t { return 1; }
|
virtual auto cardinality() const -> size_t { return 1; }
|
||||||
|
|
||||||
auto parse(Args const &args) const -> InternalParseResult {
|
auto parse( Args const &args ) const -> InternalParseResult {
|
||||||
return parse( args.exeName(), TokenStream(args));
|
return parse( args.exeName(), TokenStream( args ) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -808,7 +794,7 @@ namespace detail {
|
|||||||
class ComposableParserImpl : public ParserBase {
|
class ComposableParserImpl : public ParserBase {
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
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
|
// Common code and state for Args and Opts
|
||||||
@ -820,17 +806,22 @@ namespace detail {
|
|||||||
std::string m_hint;
|
std::string m_hint;
|
||||||
std::string m_description;
|
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:
|
public:
|
||||||
template<typename T>
|
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>
|
template<typename LambdaT>
|
||||||
ParserRefImpl(LambdaT const &ref, std::string const &hint) : m_ref(std::make_shared<BoundLambda<LambdaT>>(ref)),
|
ParserRefImpl( LambdaT const &ref, std::string const &hint )
|
||||||
m_hint(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;
|
m_description = description;
|
||||||
return static_cast<DerivedT &>( *this );
|
return static_cast<DerivedT &>( *this );
|
||||||
}
|
}
|
||||||
@ -850,7 +841,7 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto cardinality() const -> size_t override {
|
auto cardinality() const -> size_t override {
|
||||||
if (m_ref->isContainer())
|
if( m_ref->isContainer() )
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
@ -865,13 +856,13 @@ namespace detail {
|
|||||||
|
|
||||||
template<typename LambdaT>
|
template<typename LambdaT>
|
||||||
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundRefBase> {
|
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:
|
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 );
|
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
|
// 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 {
|
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 name() const -> std::string { return *m_name; }
|
||||||
auto set( std::string const& newName ) -> ParserResult {
|
auto set( std::string const& newName ) -> ParserResult {
|
||||||
|
|
||||||
auto lastSlash = newName.find_last_of( "\\/" );
|
auto lastSlash = newName.find_last_of( "\\/" );
|
||||||
auto filename = (lastSlash == std::string::npos)
|
auto filename = ( lastSlash == std::string::npos )
|
||||||
? newName
|
? newName
|
||||||
: newName.substr( lastSlash+1 );
|
: newName.substr( lastSlash+1 );
|
||||||
|
|
||||||
@ -905,27 +896,27 @@ namespace detail {
|
|||||||
public:
|
public:
|
||||||
using ParserRefImpl::ParserRefImpl;
|
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();
|
auto validationResult = validate();
|
||||||
if (!validationResult)
|
if( !validationResult )
|
||||||
return InternalParseResult(validationResult);
|
return InternalParseResult( validationResult );
|
||||||
|
|
||||||
auto remainingTokens = tokens;
|
auto remainingTokens = tokens;
|
||||||
auto const &token = *remainingTokens;
|
auto const &token = *remainingTokens;
|
||||||
if (token.type != TokenType::Argument)
|
if( token.type != TokenType::Argument )
|
||||||
return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, remainingTokens));
|
return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
|
||||||
|
|
||||||
auto result = m_ref->setValue(remainingTokens->token);
|
auto result = m_ref->setValue( remainingTokens->token );
|
||||||
if (!result)
|
if( !result )
|
||||||
return InternalParseResult(result);
|
return InternalParseResult( result );
|
||||||
else
|
else
|
||||||
return InternalParseResult::ok(ParseState(ParseResultType::Matched, ++remainingTokens));
|
return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto normaliseOpt(std::string const &optName) -> std::string {
|
inline auto normaliseOpt( std::string const &optName ) -> std::string {
|
||||||
if (optName[0] == '/')
|
if( optName[0] == '/' )
|
||||||
return "-" + optName.substr(1);
|
return "-" + optName.substr( 1 );
|
||||||
else
|
else
|
||||||
return optName;
|
return optName;
|
||||||
}
|
}
|
||||||
@ -936,9 +927,9 @@ namespace detail {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
template<typename LambdaT>
|
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>
|
template<typename LambdaT>
|
||||||
Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
|
Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
|
||||||
@ -946,34 +937,34 @@ namespace detail {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
|
Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
|
||||||
|
|
||||||
auto operator[](std::string const &optName) -> Opt & {
|
auto operator[]( std::string const &optName ) -> Opt & {
|
||||||
m_optNames.push_back(optName);
|
m_optNames.push_back( optName );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto const &opt : m_optNames) {
|
for( auto const &opt : m_optNames ) {
|
||||||
if (first)
|
if (first)
|
||||||
first = false;
|
first = false;
|
||||||
else
|
else
|
||||||
oss << ", ";
|
oss << ", ";
|
||||||
oss << opt;
|
oss << opt;
|
||||||
}
|
}
|
||||||
if (!m_hint.empty())
|
if( !m_hint.empty() )
|
||||||
oss << " <" << m_hint << ">";
|
oss << " <" << m_hint << ">";
|
||||||
return {{oss.str(), m_description}};
|
return { { oss.str(), m_description } };
|
||||||
}
|
}
|
||||||
|
|
||||||
auto isMatch(std::string const &optToken) const -> bool {
|
auto isMatch( std::string const &optToken ) const -> bool {
|
||||||
#ifdef CLARA_PLATFORM_WINDOWS
|
#ifdef CATCH_PLATFORM_WINDOWS
|
||||||
auto normalisedToken = normaliseOpt( optToken );
|
auto normalisedToken = normaliseOpt( optToken );
|
||||||
#else
|
#else
|
||||||
auto const &normalisedToken = optToken;
|
auto const &normalisedToken = optToken;
|
||||||
#endif
|
#endif
|
||||||
for (auto const &name : m_optNames) {
|
for( auto const &name : m_optNames ) {
|
||||||
if (normaliseOpt(name) == normalisedToken)
|
if( normaliseOpt( name ) == normalisedToken )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -983,46 +974,46 @@ namespace detail {
|
|||||||
|
|
||||||
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();
|
auto validationResult = validate();
|
||||||
if (!validationResult)
|
if( !validationResult )
|
||||||
return InternalParseResult(validationResult);
|
return InternalParseResult( validationResult );
|
||||||
|
|
||||||
auto remainingTokens = tokens;
|
auto remainingTokens = tokens;
|
||||||
if (remainingTokens && remainingTokens->type == TokenType::Option) {
|
if( remainingTokens && remainingTokens->type == TokenType::Option ) {
|
||||||
auto const &token = *remainingTokens;
|
auto const &token = *remainingTokens;
|
||||||
if (isMatch(token.token)) {
|
if( isMatch(token.token ) ) {
|
||||||
if (m_ref->isFlag()) {
|
if( m_ref->isFlag() ) {
|
||||||
auto result = m_ref->setFlag(true);
|
auto result = m_ref->setFlag( true );
|
||||||
if (!result)
|
if( !result )
|
||||||
return InternalParseResult(result);
|
return InternalParseResult( result );
|
||||||
if (result.value() == ParseResultType::ShortCircuitAll)
|
if( result.value() == ParseResultType::ShortCircuitAll )
|
||||||
return InternalParseResult::ok(ParseState(result.value(), remainingTokens));
|
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
|
||||||
} else {
|
} else {
|
||||||
++remainingTokens;
|
++remainingTokens;
|
||||||
if (!remainingTokens)
|
if( !remainingTokens )
|
||||||
return InternalParseResult::runtimeError("Expected argument following " + token.token);
|
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
|
||||||
auto const &argToken = *remainingTokens;
|
auto const &argToken = *remainingTokens;
|
||||||
if (argToken.type != TokenType::Argument)
|
if( argToken.type != TokenType::Argument )
|
||||||
return InternalParseResult::runtimeError("Expected argument following " + token.token);
|
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
|
||||||
auto result = m_ref->setValue(argToken.token);
|
auto result = m_ref->setValue( argToken.token );
|
||||||
if (!result)
|
if( !result )
|
||||||
return InternalParseResult(result);
|
return InternalParseResult( result );
|
||||||
if (result.value() == ParseResultType::ShortCircuitAll)
|
if( result.value() == ParseResultType::ShortCircuitAll )
|
||||||
return InternalParseResult::ok(ParseState(result.value(), remainingTokens));
|
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 {
|
auto validate() const -> Result override {
|
||||||
if (m_optNames.empty())
|
if( m_optNames.empty() )
|
||||||
return Result::logicError("No options supplied to Opt");
|
return Result::logicError( "No options supplied to Opt" );
|
||||||
for (auto const &name : m_optNames) {
|
for( auto const &name : m_optNames ) {
|
||||||
if (name.empty())
|
if( name.empty() )
|
||||||
return Result::logicError("Option name cannot be empty");
|
return Result::logicError( "Option name cannot be empty" );
|
||||||
if (name[0] != '-' && name[0] != '/')
|
if( name[0] != '-' && name[0] != '/' )
|
||||||
return Result::logicError("Option name must begin with '-' or '/'");
|
return Result::logicError( "Option name must begin with '-' or '/'" );
|
||||||
}
|
}
|
||||||
return ParserRefImpl::validate();
|
return ParserRefImpl::validate();
|
||||||
}
|
}
|
||||||
@ -1032,10 +1023,10 @@ namespace detail {
|
|||||||
Help( bool &showHelpFlag )
|
Help( bool &showHelpFlag )
|
||||||
: Opt([&]( bool flag ) {
|
: Opt([&]( bool flag ) {
|
||||||
showHelpFlag = flag;
|
showHelpFlag = flag;
|
||||||
return ParserResult::ok(ParseResultType::ShortCircuitAll);
|
return ParserResult::ok( ParseResultType::ShortCircuitAll );
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
static_cast<Opt &>(*this)
|
static_cast<Opt &>( *this )
|
||||||
("display usage information")
|
("display usage information")
|
||||||
["-?"]["-h"]["--help"]
|
["-?"]["-h"]["--help"]
|
||||||
.optional();
|
.optional();
|
||||||
@ -1049,61 +1040,61 @@ namespace detail {
|
|||||||
std::vector<Opt> m_options;
|
std::vector<Opt> m_options;
|
||||||
std::vector<Arg> m_args;
|
std::vector<Arg> m_args;
|
||||||
|
|
||||||
auto operator+=(ExeName const &exeName) -> Parser & {
|
auto operator|=( ExeName const &exeName ) -> Parser & {
|
||||||
m_exeName = exeName;
|
m_exeName = exeName;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator+=(Arg const &arg) -> Parser & {
|
auto operator|=( Arg const &arg ) -> Parser & {
|
||||||
m_args.push_back(arg);
|
m_args.push_back(arg);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator+=(Opt const &opt) -> Parser & {
|
auto operator|=( Opt const &opt ) -> Parser & {
|
||||||
m_options.push_back(opt);
|
m_options.push_back(opt);
|
||||||
return *this;
|
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_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());
|
m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto operator+(T const &other) const -> Parser {
|
auto operator|( T const &other ) const -> Parser {
|
||||||
return Parser(*this) += other;
|
return Parser( *this ) |= other;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
||||||
std::vector<HelpColumns> cols;
|
std::vector<HelpColumns> cols;
|
||||||
for (auto const &o : m_options) {
|
for (auto const &o : m_options) {
|
||||||
auto childCols = o.getHelpColumns();
|
auto childCols = o.getHelpColumns();
|
||||||
cols.insert(cols.end(), childCols.begin(), childCols.end());
|
cols.insert( cols.end(), childCols.begin(), childCols.end() );
|
||||||
}
|
}
|
||||||
return cols;
|
return cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeToStream(std::ostream &os) const {
|
void writeToStream( std::ostream &os ) const {
|
||||||
if (!m_exeName.name().empty()) {
|
if (!m_exeName.name().empty()) {
|
||||||
os << "usage:\n" << " " << m_exeName.name() << " ";
|
os << "usage:\n" << " " << m_exeName.name() << " ";
|
||||||
bool required = true, first = true;
|
bool required = true, first = true;
|
||||||
for (auto const &arg : m_args) {
|
for( auto const &arg : m_args ) {
|
||||||
if (first)
|
if (first)
|
||||||
first = false;
|
first = false;
|
||||||
else
|
else
|
||||||
os << " ";
|
os << " ";
|
||||||
if (arg.isOptional() && required) {
|
if( arg.isOptional() && required ) {
|
||||||
os << "[";
|
os << "[";
|
||||||
required = false;
|
required = false;
|
||||||
}
|
}
|
||||||
os << "<" << arg.hint() << ">";
|
os << "<" << arg.hint() << ">";
|
||||||
if (arg.cardinality() == 0)
|
if( arg.cardinality() == 0 )
|
||||||
os << " ... ";
|
os << " ... ";
|
||||||
}
|
}
|
||||||
if (!required)
|
if( !required )
|
||||||
os << "]";
|
os << "]";
|
||||||
if (!m_options.empty())
|
if( !m_options.empty() )
|
||||||
os << " options";
|
os << " options";
|
||||||
os << "\n\nwhere options are:" << std::endl;
|
os << "\n\nwhere options are:" << std::endl;
|
||||||
}
|
}
|
||||||
@ -1111,32 +1102,32 @@ namespace detail {
|
|||||||
auto rows = getHelpColumns();
|
auto rows = getHelpColumns();
|
||||||
size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;
|
size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;
|
||||||
size_t optWidth = 0;
|
size_t optWidth = 0;
|
||||||
for (auto const &cols : rows)
|
for( auto const &cols : rows )
|
||||||
optWidth = std::max(optWidth, cols.left.size() + 2);
|
optWidth = std::max(optWidth, cols.left.size() + 2);
|
||||||
|
|
||||||
for (auto const &cols : rows) {
|
for( auto const &cols : rows ) {
|
||||||
auto row =
|
auto row =
|
||||||
TextFlow::Column(cols.left).width(optWidth).indent(2) +
|
TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
|
||||||
TextFlow::Spacer(4) +
|
TextFlow::Spacer(4) +
|
||||||
TextFlow::Column(cols.right).width(consoleWidth - 7 - optWidth);
|
TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );
|
||||||
os << row << std::endl;
|
os << row << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
friend auto operator<<(std::ostream &os, Parser const &parser) -> std::ostream & {
|
friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {
|
||||||
parser.writeToStream(os);
|
parser.writeToStream( os );
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto validate() const -> Result override {
|
auto validate() const -> Result override {
|
||||||
for (auto const &opt : m_options) {
|
for( auto const &opt : m_options ) {
|
||||||
auto result = opt.validate();
|
auto result = opt.validate();
|
||||||
if (!result)
|
if( !result )
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
for (auto const &arg : m_args) {
|
for( auto const &arg : m_args ) {
|
||||||
auto result = arg.validate();
|
auto result = arg.validate();
|
||||||
if (!result)
|
if( !result )
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return Result::ok();
|
return Result::ok();
|
||||||
@ -1144,47 +1135,41 @@ namespace detail {
|
|||||||
|
|
||||||
using ParserBase::parse;
|
using ParserBase::parse;
|
||||||
|
|
||||||
auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult override {
|
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;
|
|
||||||
|
|
||||||
for (auto const &opt : m_options) {
|
struct ParserInfo {
|
||||||
allParsers.push_back(&opt);
|
ParserBase const* parser = nullptr;
|
||||||
if (!opt.isOptional())
|
size_t count = 0;
|
||||||
requiredParsers.insert(&opt);
|
};
|
||||||
}
|
const size_t totalParsers = m_options.size() + m_args.size();
|
||||||
|
ParserInfo parseInfos[totalParsers];
|
||||||
size_t optionalArgs = 0;
|
size_t i = 0;
|
||||||
for (auto const &arg : m_args) {
|
for( auto const& opt : m_options ) parseInfos[i++].parser = &opt;
|
||||||
allParsers.push_back(&arg);
|
for( auto const& arg : m_args ) parseInfos[i++].parser = &arg;
|
||||||
if (!arg.isOptional()) {
|
|
||||||
if (optionalArgs > 0)
|
|
||||||
return InternalParseResult::logicError(
|
|
||||||
"Required arguments must preceed any optional arguments");
|
|
||||||
else
|
|
||||||
++optionalArgs;
|
|
||||||
requiredParsers.insert(&arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_exeName.set( exeName );
|
m_exeName.set( exeName );
|
||||||
|
|
||||||
auto result = InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens));
|
auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
|
||||||
while (result.value().remainingTokens()) {
|
while( result.value().remainingTokens() ) {
|
||||||
auto remainingTokenCount = result.value().remainingTokens().count();
|
bool tokenParsed = false;
|
||||||
for (auto parser : allParsers) {
|
|
||||||
result = parser->parse( exeName, result.value().remainingTokens() );
|
for( auto& parseInfo : parseInfos ) {
|
||||||
if (!result || result.value().type() != ParseResultType::NoMatch) {
|
if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {
|
||||||
if (parser->cardinality() == 1)
|
result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
|
||||||
allParsers.erase(std::remove(allParsers.begin(), allParsers.end(), parser),
|
if (!result)
|
||||||
allParsers.end());
|
return result;
|
||||||
requiredParsers.erase(parser);
|
if (result.value().type() != ParseResultType::NoMatch) {
|
||||||
|
tokenParsed = true;
|
||||||
|
++parseInfo.count;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!result || remainingTokenCount == result.value().remainingTokens().count())
|
}
|
||||||
|
|
||||||
|
if( result.value().type() == ParseResultType::ShortCircuitAll )
|
||||||
return result;
|
return result;
|
||||||
|
if( !tokenParsed )
|
||||||
|
return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );
|
||||||
}
|
}
|
||||||
// !TBD Check missing required options
|
// !TBD Check missing required options
|
||||||
return result;
|
return result;
|
||||||
@ -1193,8 +1178,8 @@ namespace detail {
|
|||||||
|
|
||||||
template<typename DerivedT>
|
template<typename DerivedT>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto ComposableParserImpl<DerivedT>::operator+(T const &other) const -> Parser {
|
auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {
|
||||||
return Parser() + static_cast<DerivedT const &>( *this ) + other;
|
return Parser() | static_cast<DerivedT const &>( *this ) | other;
|
||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
@ -98,84 +98,84 @@ namespace Catch {
|
|||||||
|
|
||||||
auto cli
|
auto cli
|
||||||
= ExeName( config.processName )
|
= ExeName( config.processName )
|
||||||
+ Help( config.showHelp )
|
| Help( config.showHelp )
|
||||||
+ Opt( config.listTests )
|
| Opt( config.listTests )
|
||||||
["-l"]["--list-tests"]
|
["-l"]["--list-tests"]
|
||||||
( "list all/matching test cases" )
|
( "list all/matching test cases" )
|
||||||
+ Opt( config.listTags )
|
| Opt( config.listTags )
|
||||||
["-t"]["--list-tags"]
|
["-t"]["--list-tags"]
|
||||||
( "list all/matching tags" )
|
( "list all/matching tags" )
|
||||||
+ Opt( config.showSuccessfulTests )
|
| Opt( config.showSuccessfulTests )
|
||||||
["-s"]["--success"]
|
["-s"]["--success"]
|
||||||
( "include successful tests in output" )
|
( "include successful tests in output" )
|
||||||
+ Opt( config.shouldDebugBreak )
|
| Opt( config.shouldDebugBreak )
|
||||||
["-b"]["--break"]
|
["-b"]["--break"]
|
||||||
( "break into debugger on failure" )
|
( "break into debugger on failure" )
|
||||||
+ Opt( config.noThrow )
|
| Opt( config.noThrow )
|
||||||
["-e"]["--nothrow"]
|
["-e"]["--nothrow"]
|
||||||
( "skip exception tests" )
|
( "skip exception tests" )
|
||||||
+ Opt( config.showInvisibles )
|
| Opt( config.showInvisibles )
|
||||||
["-i"]["--invisibles"]
|
["-i"]["--invisibles"]
|
||||||
( "show invisibles (tabs, newlines)" )
|
( "show invisibles (tabs, newlines)" )
|
||||||
+ Opt( config.outputFilename, "filename" )
|
| Opt( config.outputFilename, "filename" )
|
||||||
["-o"]["--out"]
|
["-o"]["--out"]
|
||||||
( "output filename" )
|
( "output filename" )
|
||||||
+ Opt( config.reporterNames, "name" )
|
| Opt( config.reporterNames, "name" )
|
||||||
["-r"]["--reporter"]
|
["-r"]["--reporter"]
|
||||||
( "reporter to use (defaults to console)" )
|
( "reporter to use (defaults to console)" )
|
||||||
+ Opt( config.name, "name" )
|
| Opt( config.name, "name" )
|
||||||
["-n"]["--name"]
|
["-n"]["--name"]
|
||||||
( "suite name" )
|
( "suite name" )
|
||||||
+ Opt( [&]( bool ){ config.abortAfter = 1; } )
|
| Opt( [&]( bool ){ config.abortAfter = 1; } )
|
||||||
["-a"]["--abort"]
|
["-a"]["--abort"]
|
||||||
( "abort at first failure" )
|
( "abort at first failure" )
|
||||||
+ Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
|
| Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
|
||||||
["-x"]["--abortx"]
|
["-x"]["--abortx"]
|
||||||
( "abort after x failures" )
|
( "abort after x failures" )
|
||||||
+ Opt( setWarning, "warning name" )
|
| Opt( setWarning, "warning name" )
|
||||||
["-w"]["--warn"]
|
["-w"]["--warn"]
|
||||||
( "enable warnings" )
|
( "enable warnings" )
|
||||||
+ Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
|
| Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
|
||||||
["-d"]["--durations"]
|
["-d"]["--durations"]
|
||||||
( "show test durations" )
|
( "show test durations" )
|
||||||
+ Opt( loadTestNamesFromFile, "filename" )
|
| Opt( loadTestNamesFromFile, "filename" )
|
||||||
["-f"]["--input-file"]
|
["-f"]["--input-file"]
|
||||||
( "load test names to run from a file" )
|
( "load test names to run from a file" )
|
||||||
+ Opt( config.filenamesAsTags )
|
| Opt( config.filenamesAsTags )
|
||||||
["-#"]["--filenames-as-tags"]
|
["-#"]["--filenames-as-tags"]
|
||||||
( "adds a tag for the filename" )
|
( "adds a tag for the filename" )
|
||||||
+ Opt( config.sectionsToRun, "section name" )
|
| Opt( config.sectionsToRun, "section name" )
|
||||||
["-c"]["--section"]
|
["-c"]["--section"]
|
||||||
( "specify section to run" )
|
( "specify section to run" )
|
||||||
+ Opt( setVerbosity, "quiet|normal|high" )
|
| Opt( setVerbosity, "quiet|normal|high" )
|
||||||
["-v"]["--verbosity"]
|
["-v"]["--verbosity"]
|
||||||
( "set output verbosity" )
|
( "set output verbosity" )
|
||||||
+ Opt( config.listTestNamesOnly )
|
| Opt( config.listTestNamesOnly )
|
||||||
["--list-test-names-only"]
|
["--list-test-names-only"]
|
||||||
( "list all/matching test cases names only" )
|
( "list all/matching test cases names only" )
|
||||||
+ Opt( config.listReporters )
|
| Opt( config.listReporters )
|
||||||
["--list-reporters"]
|
["--list-reporters"]
|
||||||
( "list all reporters" )
|
( "list all reporters" )
|
||||||
+ Opt( setTestOrder, "decl|lex|rand" )
|
| Opt( setTestOrder, "decl|lex|rand" )
|
||||||
["--order"]
|
["--order"]
|
||||||
( "test case order (defaults to decl)" )
|
( "test case order (defaults to decl)" )
|
||||||
+ Opt( setRngSeed, "'time'|number" )
|
| Opt( setRngSeed, "'time'|number" )
|
||||||
["--rng-seed"]
|
["--rng-seed"]
|
||||||
( "set a specific seed for random numbers" )
|
( "set a specific seed for random numbers" )
|
||||||
+ Opt( setColourUsage, "yes|no" )
|
| Opt( setColourUsage, "yes|no" )
|
||||||
["--use-colour"]
|
["--use-colour"]
|
||||||
( "should output be colourised" )
|
( "should output be colourised" )
|
||||||
+ Opt( config.libIdentify )
|
| Opt( config.libIdentify )
|
||||||
["--libidentify"]
|
["--libidentify"]
|
||||||
( "report name and version according to libidentify standard" )
|
( "report name and version according to libidentify standard" )
|
||||||
+ Opt( setWaitForKeypress, "start|exit|both" )
|
| Opt( setWaitForKeypress, "start|exit|both" )
|
||||||
["--wait-for-keypress"]
|
["--wait-for-keypress"]
|
||||||
( "waits for a keypress before exiting" )
|
( "waits for a keypress before exiting" )
|
||||||
+ Opt( config.benchmarkResolutionMultiple, "multiplier" )
|
| Opt( config.benchmarkResolutionMultiple, "multiplier" )
|
||||||
["--benchmark-resolution-multiple"]
|
["--benchmark-resolution-multiple"]
|
||||||
( "multiple of clock resolution to run benchmarks" )
|
( "multiple of clock resolution to run benchmarks" )
|
||||||
|
|
||||||
+ Arg( config.testsOrTags, "test name|pattern|tags" )
|
| Arg( config.testsOrTags, "test name|pattern|tags" )
|
||||||
( "which test or tests to use" );
|
( "which test or tests to use" );
|
||||||
|
|
||||||
return cli;
|
return cli;
|
||||||
|
480
third_party/clara.hpp
vendored
480
third_party/clara.hpp
vendored
@ -8,6 +8,9 @@
|
|||||||
#define CLARA_CONFIG_CONSOLE_WIDTH 80
|
#define CLARA_CONFIG_CONSOLE_WIDTH 80
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
|
||||||
|
#define CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
|
||||||
|
#endif
|
||||||
|
|
||||||
// ----------- #included from clara_textflow.hpp -----------
|
// ----------- #included from clara_textflow.hpp -----------
|
||||||
|
|
||||||
@ -133,7 +136,7 @@ namespace clara { namespace TextFlow {
|
|||||||
|
|
||||||
auto operator *() const -> std::string {
|
auto operator *() const -> std::string {
|
||||||
assert( m_stringIndex < m_column.m_strings.size() );
|
assert( m_stringIndex < m_column.m_strings.size() );
|
||||||
assert( m_pos < m_end );
|
assert( m_pos <= m_end );
|
||||||
if( m_pos + m_column.m_width < m_end )
|
if( m_pos + m_column.m_width < m_end )
|
||||||
return addIndentAndSuffix(line().substr(m_pos, m_len));
|
return addIndentAndSuffix(line().substr(m_pos, m_len));
|
||||||
else
|
else
|
||||||
@ -357,15 +360,15 @@ namespace detail {
|
|||||||
|
|
||||||
// Traits for extracting arg and return type of lambdas (for single argument lambdas)
|
// Traits for extracting arg and return type of lambdas (for single argument lambdas)
|
||||||
template<typename L>
|
template<typename L>
|
||||||
struct UnaryLambdaTraits : UnaryLambdaTraits<decltype(&L::operator())> {};
|
struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};
|
||||||
|
|
||||||
template<typename ClassT, typename ReturnT, typename... Args>
|
template<typename ClassT, typename ReturnT, typename... Args>
|
||||||
struct UnaryLambdaTraits<ReturnT(ClassT::*)(Args...) const> {
|
struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {
|
||||||
static const bool isValid = false;
|
static const bool isValid = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ClassT, typename ReturnT, typename ArgT>
|
template<typename ClassT, typename ReturnT, typename ArgT>
|
||||||
struct UnaryLambdaTraits<ReturnT(ClassT::*)(ArgT) const> {
|
struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
|
||||||
static const bool isValid = true;
|
static const bool isValid = true;
|
||||||
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;;
|
using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;;
|
||||||
using ReturnType = ReturnT;
|
using ReturnType = ReturnT;
|
||||||
@ -380,13 +383,13 @@ namespace detail {
|
|||||||
std::vector<std::string> m_args;
|
std::vector<std::string> m_args;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Args(int argc, char *argv[]) {
|
Args( int argc, char *argv[] ) {
|
||||||
m_exeName = argv[0];
|
m_exeName = argv[0];
|
||||||
for (int i = 1; i < argc; ++i)
|
for( int i = 1; i < argc; ++i )
|
||||||
m_args.push_back(argv[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_exeName( *args.begin() ),
|
||||||
m_args( args.begin()+1, args.end() )
|
m_args( args.begin()+1, args.end() )
|
||||||
{}
|
{}
|
||||||
@ -414,40 +417,40 @@ namespace detail {
|
|||||||
std::vector<Token> m_tokenBuffer;
|
std::vector<Token> m_tokenBuffer;
|
||||||
|
|
||||||
void loadBuffer() {
|
void loadBuffer() {
|
||||||
m_tokenBuffer.resize(0);
|
m_tokenBuffer.resize( 0 );
|
||||||
|
|
||||||
// Skip any empty strings
|
// Skip any empty strings
|
||||||
while (it != itEnd && it->empty())
|
while( it != itEnd && it->empty() )
|
||||||
++it;
|
++it;
|
||||||
|
|
||||||
if (it != itEnd) {
|
if( it != itEnd ) {
|
||||||
auto const &next = *it;
|
auto const &next = *it;
|
||||||
if (next[0] == '-' || next[0] == '/') {
|
if( next[0] == '-' || next[0] == '/' ) {
|
||||||
auto delimiterPos = next.find_first_of(" :=");
|
auto delimiterPos = next.find_first_of( " :=" );
|
||||||
if (delimiterPos != std::string::npos) {
|
if( delimiterPos != std::string::npos ) {
|
||||||
m_tokenBuffer.push_back({TokenType::Option, next.substr(0, delimiterPos)});
|
m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
|
||||||
m_tokenBuffer.push_back({TokenType::Argument, next.substr(delimiterPos + 1)});
|
m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );
|
||||||
} else {
|
} else {
|
||||||
if (next[1] != '-' && next.size() > 2) {
|
if( next[1] != '-' && next.size() > 2 ) {
|
||||||
std::string opt = "- ";
|
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];
|
opt[1] = next[i];
|
||||||
m_tokenBuffer.push_back({TokenType::Option, opt});
|
m_tokenBuffer.push_back( { TokenType::Option, opt } );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_tokenBuffer.push_back({TokenType::Option, next});
|
m_tokenBuffer.push_back( { TokenType::Option, next } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_tokenBuffer.push_back({TokenType::Argument, next});
|
m_tokenBuffer.push_back( { TokenType::Argument, next } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
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();
|
loadBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,20 +461,20 @@ namespace detail {
|
|||||||
auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
|
auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
|
||||||
|
|
||||||
auto operator*() const -> Token {
|
auto operator*() const -> Token {
|
||||||
assert(!m_tokenBuffer.empty());
|
assert( !m_tokenBuffer.empty() );
|
||||||
return m_tokenBuffer.front();
|
return m_tokenBuffer.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator->() const -> Token const * {
|
auto operator->() const -> Token const * {
|
||||||
assert(!m_tokenBuffer.empty());
|
assert( !m_tokenBuffer.empty() );
|
||||||
return &m_tokenBuffer.front();
|
return &m_tokenBuffer.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator++() -> TokenStream & {
|
auto operator++() -> TokenStream & {
|
||||||
if (m_tokenBuffer.size() >= 2) {
|
if( m_tokenBuffer.size() >= 2 ) {
|
||||||
m_tokenBuffer.erase(m_tokenBuffer.begin());
|
m_tokenBuffer.erase( m_tokenBuffer.begin() );
|
||||||
} else {
|
} else {
|
||||||
if (it != itEnd)
|
if( it != itEnd )
|
||||||
++it;
|
++it;
|
||||||
loadBuffer();
|
loadBuffer();
|
||||||
}
|
}
|
||||||
@ -487,7 +490,7 @@ namespace detail {
|
|||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ResultBase(Type type) : m_type(type) {}
|
ResultBase( Type type ) : m_type( type ) {}
|
||||||
virtual ~ResultBase() = default;
|
virtual ~ResultBase() = default;
|
||||||
|
|
||||||
virtual void enforceOk() const = 0;
|
virtual void enforceOk() const = 0;
|
||||||
@ -504,28 +507,28 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ResultValueBase(Type type) : ResultBase(type) {}
|
ResultValueBase( Type type ) : ResultBase( type ) {}
|
||||||
|
|
||||||
ResultValueBase(ResultValueBase const &other) : ResultBase(other) {
|
ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {
|
||||||
if (m_type == ResultBase::Ok)
|
if( m_type == ResultBase::Ok )
|
||||||
new(&m_value) T(other.m_value);
|
new( &m_value ) T( other.m_value );
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultValueBase(Type, T const &value) : ResultBase(Ok) {
|
ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {
|
||||||
new(&m_value) T(value);
|
new( &m_value ) T( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator=(ResultValueBase const &other) -> ResultValueBase & {
|
auto operator=( ResultValueBase const &other ) -> ResultValueBase & {
|
||||||
if (m_type == ResultBase::Ok)
|
if( m_type == ResultBase::Ok )
|
||||||
m_value.~T();
|
m_value.~T();
|
||||||
ResultBase::operator=(other);
|
ResultBase::operator=(other);
|
||||||
if (m_type == ResultBase::Ok)
|
if( m_type == ResultBase::Ok )
|
||||||
new(&m_value) T(other.m_value);
|
new( &m_value ) T( other.m_value );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~ResultValueBase() {
|
~ResultValueBase() {
|
||||||
if (m_type == Ok)
|
if( m_type == Ok )
|
||||||
m_value.~T();
|
m_value.~T();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,37 +547,31 @@ namespace detail {
|
|||||||
class BasicResult : public ResultValueBase<T> {
|
class BasicResult : public ResultValueBase<T> {
|
||||||
public:
|
public:
|
||||||
template<typename U>
|
template<typename U>
|
||||||
explicit BasicResult(BasicResult<U> const &other)
|
explicit BasicResult( BasicResult<U> const &other )
|
||||||
: ResultValueBase<T>(other.type()),
|
: ResultValueBase<T>( other.type() ),
|
||||||
m_errorMessage(other.errorMessage()) {
|
m_errorMessage( other.errorMessage() )
|
||||||
assert(type() != ResultBase::Ok);
|
{
|
||||||
|
assert( type() != ResultBase::Ok );
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto ok() -> BasicResult { return {ResultBase::Ok}; }
|
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
static auto ok(U const &value) -> BasicResult { return {ResultBase::Ok, value}; }
|
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 logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }
|
||||||
|
static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }
|
||||||
static auto runtimeError(std::string const &message) -> BasicResult {
|
|
||||||
return {ResultBase::RuntimeError, message};
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit operator bool() const { return m_type == ResultBase::Ok; }
|
explicit operator bool() const { return m_type == ResultBase::Ok; }
|
||||||
|
|
||||||
auto type() const -> ResultBase::Type { return m_type; }
|
auto type() const -> ResultBase::Type { return m_type; }
|
||||||
|
|
||||||
auto errorMessage() const -> std::string { return m_errorMessage; }
|
auto errorMessage() const -> std::string { return m_errorMessage; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void enforceOk() const {
|
virtual void enforceOk() const {
|
||||||
// !TBD: If no exceptions, std::terminate here or something
|
// !TBD: If no exceptions, std::terminate here or something
|
||||||
switch (m_type) {
|
switch( m_type ) {
|
||||||
case ResultBase::LogicError:
|
case ResultBase::LogicError:
|
||||||
throw std::logic_error(m_errorMessage);
|
throw std::logic_error( m_errorMessage );
|
||||||
case ResultBase::RuntimeError:
|
case ResultBase::RuntimeError:
|
||||||
throw std::runtime_error(m_errorMessage);
|
throw std::runtime_error( m_errorMessage );
|
||||||
case ResultBase::Ok:
|
case ResultBase::Ok:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -582,10 +579,11 @@ namespace detail {
|
|||||||
|
|
||||||
std::string m_errorMessage; // Only populated if resultType is an error
|
std::string m_errorMessage; // Only populated if resultType is an error
|
||||||
|
|
||||||
BasicResult(ResultBase::Type type, std::string const &message)
|
BasicResult( ResultBase::Type type, std::string const &message )
|
||||||
: ResultValueBase<T>(type),
|
: ResultValueBase<T>(type),
|
||||||
m_errorMessage(message) {
|
m_errorMessage(message)
|
||||||
assert(m_type != ResultBase::Ok);
|
{
|
||||||
|
assert( m_type != ResultBase::Ok );
|
||||||
}
|
}
|
||||||
|
|
||||||
using ResultValueBase<T>::ResultValueBase;
|
using ResultValueBase<T>::ResultValueBase;
|
||||||
@ -599,12 +597,12 @@ namespace detail {
|
|||||||
class ParseState {
|
class ParseState {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ParseState(ParseResultType type, TokenStream const &remainingTokens)
|
ParseState( ParseResultType type, TokenStream const &remainingTokens )
|
||||||
: m_type(type),
|
: m_type(type),
|
||||||
m_remainingTokens(remainingTokens) {}
|
m_remainingTokens( remainingTokens )
|
||||||
|
{}
|
||||||
|
|
||||||
auto type() const -> ParseResultType { return m_type; }
|
auto type() const -> ParseResultType { return m_type; }
|
||||||
|
|
||||||
auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
|
auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -622,69 +620,62 @@ namespace detail {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
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;
|
std::stringstream ss;
|
||||||
ss << source;
|
ss << source;
|
||||||
ss >> target;
|
ss >> target;
|
||||||
if (ss.fail())
|
if( ss.fail() )
|
||||||
return ParserResult::runtimeError("Unable to convert '" + source + "' to destination type");
|
return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );
|
||||||
else
|
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;
|
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::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")
|
if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
|
||||||
target = true;
|
target = true;
|
||||||
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
|
else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
|
||||||
target = false;
|
target = false;
|
||||||
else
|
else
|
||||||
return ParserResult::runtimeError("Expected a boolean value but did not recognise: '" + source + "'");
|
return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
|
||||||
return ParserResult::ok(ParseResultType::Matched);
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BoundRefBase {
|
struct BoundRefBase {
|
||||||
BoundRefBase() = default;
|
BoundRefBase() = default;
|
||||||
|
BoundRefBase( BoundRefBase const & ) = delete;
|
||||||
BoundRefBase(BoundRefBase const &) = delete;
|
BoundRefBase( BoundRefBase && ) = delete;
|
||||||
|
BoundRefBase &operator=( BoundRefBase const & ) = delete;
|
||||||
BoundRefBase(BoundRefBase &&) = delete;
|
BoundRefBase &operator=( BoundRefBase && ) = delete;
|
||||||
|
|
||||||
BoundRefBase &operator=(BoundRefBase const &) = delete;
|
|
||||||
|
|
||||||
BoundRefBase &operator=(BoundRefBase &&) = delete;
|
|
||||||
|
|
||||||
virtual ~BoundRefBase() = default;
|
virtual ~BoundRefBase() = default;
|
||||||
|
|
||||||
virtual auto isFlag() const -> bool = 0;
|
virtual auto isFlag() const -> bool = 0;
|
||||||
|
|
||||||
virtual auto isContainer() const -> bool { return false; }
|
virtual auto isContainer() const -> bool { return false; }
|
||||||
|
virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
|
||||||
virtual auto setValue(std::string const &arg) -> ParserResult = 0;
|
virtual auto setFlag( bool flag ) -> ParserResult = 0;
|
||||||
|
|
||||||
virtual auto setFlag(bool flag) -> ParserResult = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BoundValueRefBase : BoundRefBase {
|
struct BoundValueRefBase : BoundRefBase {
|
||||||
auto isFlag() const -> bool override { return false; }
|
auto isFlag() const -> bool override { return false; }
|
||||||
|
|
||||||
auto setFlag(bool) -> ParserResult override {
|
auto setFlag( bool ) -> ParserResult override {
|
||||||
return ParserResult::logicError("Flags can only be set on boolean fields");
|
return ParserResult::logicError( "Flags can only be set on boolean fields" );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BoundFlagRefBase : BoundRefBase {
|
struct BoundFlagRefBase : BoundRefBase {
|
||||||
auto isFlag() const -> bool override { return true; }
|
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;
|
bool flag;
|
||||||
auto result = convertInto(arg, flag);
|
auto result = convertInto( arg, flag );
|
||||||
if (result)
|
if( result )
|
||||||
setFlag(flag);
|
setFlag( flag );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -693,10 +684,10 @@ namespace detail {
|
|||||||
struct BoundRef : BoundValueRefBase {
|
struct BoundRef : BoundValueRefBase {
|
||||||
T &m_ref;
|
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 {
|
auto setValue( std::string const &arg ) -> ParserResult override {
|
||||||
return convertInto(arg, m_ref);
|
return convertInto( arg, m_ref );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -704,15 +695,15 @@ namespace detail {
|
|||||||
struct BoundRef<std::vector<T>> : BoundValueRefBase {
|
struct BoundRef<std::vector<T>> : BoundValueRefBase {
|
||||||
std::vector<T> &m_ref;
|
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 isContainer() const -> bool override { return true; }
|
||||||
|
|
||||||
auto setValue(std::string const &arg) -> ParserResult override {
|
auto setValue( std::string const &arg ) -> ParserResult override {
|
||||||
T temp;
|
T temp;
|
||||||
auto result = convertInto(arg, temp);
|
auto result = convertInto( arg, temp );
|
||||||
if (result)
|
if( result )
|
||||||
m_ref.push_back(temp);
|
m_ref.push_back( temp );
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -720,40 +711,40 @@ namespace detail {
|
|||||||
struct BoundFlagRef : BoundFlagRefBase {
|
struct BoundFlagRef : BoundFlagRefBase {
|
||||||
bool &m_ref;
|
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;
|
m_ref = flag;
|
||||||
return ParserResult::ok(ParseResultType::Matched);
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ReturnType>
|
template<typename ReturnType>
|
||||||
struct LambdaInvoker {
|
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>
|
template<typename L, typename ArgType>
|
||||||
static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult {
|
static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
|
||||||
return lambda(arg);
|
return lambda( arg );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct LambdaInvoker<void> {
|
struct LambdaInvoker<void> {
|
||||||
template<typename L, typename ArgType>
|
template<typename L, typename ArgType>
|
||||||
static auto invoke(L const &lambda, ArgType const &arg) -> ParserResult {
|
static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
|
||||||
lambda(arg);
|
lambda( arg );
|
||||||
return ParserResult::ok(ParseResultType::Matched);
|
return ParserResult::ok( ParseResultType::Matched );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename ArgType, typename L>
|
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;
|
ArgType temp;
|
||||||
auto result = convertInto(arg, temp);
|
auto result = convertInto( arg, temp );
|
||||||
return !result
|
return !result
|
||||||
? result
|
? result
|
||||||
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke(lambda, temp);
|
: LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -762,10 +753,10 @@ namespace detail {
|
|||||||
L m_lambda;
|
L m_lambda;
|
||||||
|
|
||||||
static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
|
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 {
|
auto setValue( std::string const &arg ) -> ParserResult override {
|
||||||
return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(m_lambda, arg);
|
return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -776,16 +767,14 @@ namespace detail {
|
|||||||
static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
|
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" );
|
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 {
|
auto setFlag( bool flag ) -> ParserResult override {
|
||||||
return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke(m_lambda, flag);
|
return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Optionality {
|
enum class Optionality { Optional, Required };
|
||||||
Optional, Required
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Parser;
|
struct Parser;
|
||||||
|
|
||||||
@ -796,8 +785,8 @@ namespace detail {
|
|||||||
virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0;
|
virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0;
|
||||||
virtual auto cardinality() const -> size_t { return 1; }
|
virtual auto cardinality() const -> size_t { return 1; }
|
||||||
|
|
||||||
auto parse(Args const &args) const -> InternalParseResult {
|
auto parse( Args const &args ) const -> InternalParseResult {
|
||||||
return parse( args.exeName(), TokenStream(args));
|
return parse( args.exeName(), TokenStream( args ) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -805,7 +794,7 @@ namespace detail {
|
|||||||
class ComposableParserImpl : public ParserBase {
|
class ComposableParserImpl : public ParserBase {
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
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
|
// Common code and state for Args and Opts
|
||||||
@ -817,17 +806,22 @@ namespace detail {
|
|||||||
std::string m_hint;
|
std::string m_hint;
|
||||||
std::string m_description;
|
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:
|
public:
|
||||||
template<typename T>
|
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>
|
template<typename LambdaT>
|
||||||
ParserRefImpl(LambdaT const &ref, std::string const &hint) : m_ref(std::make_shared<BoundLambda<LambdaT>>(ref)),
|
ParserRefImpl( LambdaT const &ref, std::string const &hint )
|
||||||
m_hint(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;
|
m_description = description;
|
||||||
return static_cast<DerivedT &>( *this );
|
return static_cast<DerivedT &>( *this );
|
||||||
}
|
}
|
||||||
@ -847,7 +841,7 @@ namespace detail {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto cardinality() const -> size_t override {
|
auto cardinality() const -> size_t override {
|
||||||
if (m_ref->isContainer())
|
if( m_ref->isContainer() )
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
@ -862,13 +856,13 @@ namespace detail {
|
|||||||
|
|
||||||
template<typename LambdaT>
|
template<typename LambdaT>
|
||||||
static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundRefBase> {
|
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:
|
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 );
|
m_ref = std::make_shared<BoundRef<std::string>>( ref );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -879,14 +873,14 @@ namespace detail {
|
|||||||
|
|
||||||
// The exe name is not parsed out of the normal tokens, but is handled specially
|
// 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 {
|
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 name() const -> std::string { return *m_name; }
|
||||||
auto set( std::string const& newName ) -> ParserResult {
|
auto set( std::string const& newName ) -> ParserResult {
|
||||||
|
|
||||||
auto lastSlash = newName.find_last_of( "\\/" );
|
auto lastSlash = newName.find_last_of( "\\/" );
|
||||||
auto filename = (lastSlash == std::string::npos)
|
auto filename = ( lastSlash == std::string::npos )
|
||||||
? newName
|
? newName
|
||||||
: newName.substr( lastSlash+1 );
|
: newName.substr( lastSlash+1 );
|
||||||
|
|
||||||
@ -902,27 +896,27 @@ namespace detail {
|
|||||||
public:
|
public:
|
||||||
using ParserRefImpl::ParserRefImpl;
|
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();
|
auto validationResult = validate();
|
||||||
if (!validationResult)
|
if( !validationResult )
|
||||||
return InternalParseResult(validationResult);
|
return InternalParseResult( validationResult );
|
||||||
|
|
||||||
auto remainingTokens = tokens;
|
auto remainingTokens = tokens;
|
||||||
auto const &token = *remainingTokens;
|
auto const &token = *remainingTokens;
|
||||||
if (token.type != TokenType::Argument)
|
if( token.type != TokenType::Argument )
|
||||||
return InternalParseResult::ok(ParseState(ParseResultType::NoMatch, remainingTokens));
|
return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
|
||||||
|
|
||||||
auto result = m_ref->setValue(remainingTokens->token);
|
auto result = m_ref->setValue( remainingTokens->token );
|
||||||
if (!result)
|
if( !result )
|
||||||
return InternalParseResult(result);
|
return InternalParseResult( result );
|
||||||
else
|
else
|
||||||
return InternalParseResult::ok(ParseState(ParseResultType::Matched, ++remainingTokens));
|
return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto normaliseOpt(std::string const &optName) -> std::string {
|
inline auto normaliseOpt( std::string const &optName ) -> std::string {
|
||||||
if (optName[0] == '/')
|
if( optName[0] == '/' )
|
||||||
return "-" + optName.substr(1);
|
return "-" + optName.substr( 1 );
|
||||||
else
|
else
|
||||||
return optName;
|
return optName;
|
||||||
}
|
}
|
||||||
@ -933,9 +927,9 @@ namespace detail {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
template<typename LambdaT>
|
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>
|
template<typename LambdaT>
|
||||||
Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
|
Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
|
||||||
@ -943,34 +937,34 @@ namespace detail {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
|
Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
|
||||||
|
|
||||||
auto operator[](std::string const &optName) -> Opt & {
|
auto operator[]( std::string const &optName ) -> Opt & {
|
||||||
m_optNames.push_back(optName);
|
m_optNames.push_back( optName );
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto const &opt : m_optNames) {
|
for( auto const &opt : m_optNames ) {
|
||||||
if (first)
|
if (first)
|
||||||
first = false;
|
first = false;
|
||||||
else
|
else
|
||||||
oss << ", ";
|
oss << ", ";
|
||||||
oss << opt;
|
oss << opt;
|
||||||
}
|
}
|
||||||
if (!m_hint.empty())
|
if( !m_hint.empty() )
|
||||||
oss << " <" << m_hint << ">";
|
oss << " <" << m_hint << ">";
|
||||||
return {{oss.str(), m_description}};
|
return { { oss.str(), m_description } };
|
||||||
}
|
}
|
||||||
|
|
||||||
auto isMatch(std::string const &optToken) const -> bool {
|
auto isMatch( std::string const &optToken ) const -> bool {
|
||||||
#ifdef CLARA_PLATFORM_WINDOWS
|
#ifdef CLARA_PLATFORM_WINDOWS
|
||||||
auto normalisedToken = normaliseOpt( optToken );
|
auto normalisedToken = normaliseOpt( optToken );
|
||||||
#else
|
#else
|
||||||
auto const &normalisedToken = optToken;
|
auto const &normalisedToken = optToken;
|
||||||
#endif
|
#endif
|
||||||
for (auto const &name : m_optNames) {
|
for( auto const &name : m_optNames ) {
|
||||||
if (normaliseOpt(name) == normalisedToken)
|
if( normaliseOpt( name ) == normalisedToken )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -980,46 +974,46 @@ namespace detail {
|
|||||||
|
|
||||||
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();
|
auto validationResult = validate();
|
||||||
if (!validationResult)
|
if( !validationResult )
|
||||||
return InternalParseResult(validationResult);
|
return InternalParseResult( validationResult );
|
||||||
|
|
||||||
auto remainingTokens = tokens;
|
auto remainingTokens = tokens;
|
||||||
if (remainingTokens && remainingTokens->type == TokenType::Option) {
|
if( remainingTokens && remainingTokens->type == TokenType::Option ) {
|
||||||
auto const &token = *remainingTokens;
|
auto const &token = *remainingTokens;
|
||||||
if (isMatch(token.token)) {
|
if( isMatch(token.token ) ) {
|
||||||
if (m_ref->isFlag()) {
|
if( m_ref->isFlag() ) {
|
||||||
auto result = m_ref->setFlag(true);
|
auto result = m_ref->setFlag( true );
|
||||||
if (!result)
|
if( !result )
|
||||||
return InternalParseResult(result);
|
return InternalParseResult( result );
|
||||||
if (result.value() == ParseResultType::ShortCircuitAll)
|
if( result.value() == ParseResultType::ShortCircuitAll )
|
||||||
return InternalParseResult::ok(ParseState(result.value(), remainingTokens));
|
return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
|
||||||
} else {
|
} else {
|
||||||
++remainingTokens;
|
++remainingTokens;
|
||||||
if (!remainingTokens)
|
if( !remainingTokens )
|
||||||
return InternalParseResult::runtimeError("Expected argument following " + token.token);
|
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
|
||||||
auto const &argToken = *remainingTokens;
|
auto const &argToken = *remainingTokens;
|
||||||
if (argToken.type != TokenType::Argument)
|
if( argToken.type != TokenType::Argument )
|
||||||
return InternalParseResult::runtimeError("Expected argument following " + token.token);
|
return InternalParseResult::runtimeError( "Expected argument following " + token.token );
|
||||||
auto result = m_ref->setValue(argToken.token);
|
auto result = m_ref->setValue( argToken.token );
|
||||||
if (!result)
|
if( !result )
|
||||||
return InternalParseResult(result);
|
return InternalParseResult( result );
|
||||||
if (result.value() == ParseResultType::ShortCircuitAll)
|
if( result.value() == ParseResultType::ShortCircuitAll )
|
||||||
return InternalParseResult::ok(ParseState(result.value(), remainingTokens));
|
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 {
|
auto validate() const -> Result override {
|
||||||
if (m_optNames.empty())
|
if( m_optNames.empty() )
|
||||||
return Result::logicError("No options supplied to Opt");
|
return Result::logicError( "No options supplied to Opt" );
|
||||||
for (auto const &name : m_optNames) {
|
for( auto const &name : m_optNames ) {
|
||||||
if (name.empty())
|
if( name.empty() )
|
||||||
return Result::logicError("Option name cannot be empty");
|
return Result::logicError( "Option name cannot be empty" );
|
||||||
if (name[0] != '-' && name[0] != '/')
|
if( name[0] != '-' && name[0] != '/' )
|
||||||
return Result::logicError("Option name must begin with '-' or '/'");
|
return Result::logicError( "Option name must begin with '-' or '/'" );
|
||||||
}
|
}
|
||||||
return ParserRefImpl::validate();
|
return ParserRefImpl::validate();
|
||||||
}
|
}
|
||||||
@ -1029,10 +1023,10 @@ namespace detail {
|
|||||||
Help( bool &showHelpFlag )
|
Help( bool &showHelpFlag )
|
||||||
: Opt([&]( bool flag ) {
|
: Opt([&]( bool flag ) {
|
||||||
showHelpFlag = flag;
|
showHelpFlag = flag;
|
||||||
return ParserResult::ok(ParseResultType::ShortCircuitAll);
|
return ParserResult::ok( ParseResultType::ShortCircuitAll );
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
static_cast<Opt &>(*this)
|
static_cast<Opt &>( *this )
|
||||||
("display usage information")
|
("display usage information")
|
||||||
["-?"]["-h"]["--help"]
|
["-?"]["-h"]["--help"]
|
||||||
.optional();
|
.optional();
|
||||||
@ -1046,61 +1040,61 @@ namespace detail {
|
|||||||
std::vector<Opt> m_options;
|
std::vector<Opt> m_options;
|
||||||
std::vector<Arg> m_args;
|
std::vector<Arg> m_args;
|
||||||
|
|
||||||
auto operator+=(ExeName const &exeName) -> Parser & {
|
auto operator|=( ExeName const &exeName ) -> Parser & {
|
||||||
m_exeName = exeName;
|
m_exeName = exeName;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator+=(Arg const &arg) -> Parser & {
|
auto operator|=( Arg const &arg ) -> Parser & {
|
||||||
m_args.push_back(arg);
|
m_args.push_back(arg);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator+=(Opt const &opt) -> Parser & {
|
auto operator|=( Opt const &opt ) -> Parser & {
|
||||||
m_options.push_back(opt);
|
m_options.push_back(opt);
|
||||||
return *this;
|
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_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());
|
m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto operator+(T const &other) const -> Parser {
|
auto operator|( T const &other ) const -> Parser {
|
||||||
return Parser(*this) += other;
|
return Parser( *this ) |= other;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
auto getHelpColumns() const -> std::vector<HelpColumns> {
|
||||||
std::vector<HelpColumns> cols;
|
std::vector<HelpColumns> cols;
|
||||||
for (auto const &o : m_options) {
|
for (auto const &o : m_options) {
|
||||||
auto childCols = o.getHelpColumns();
|
auto childCols = o.getHelpColumns();
|
||||||
cols.insert(cols.end(), childCols.begin(), childCols.end());
|
cols.insert( cols.end(), childCols.begin(), childCols.end() );
|
||||||
}
|
}
|
||||||
return cols;
|
return cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeToStream(std::ostream &os) const {
|
void writeToStream( std::ostream &os ) const {
|
||||||
if (!m_exeName.name().empty()) {
|
if (!m_exeName.name().empty()) {
|
||||||
os << "usage:\n" << " " << m_exeName.name() << " ";
|
os << "usage:\n" << " " << m_exeName.name() << " ";
|
||||||
bool required = true, first = true;
|
bool required = true, first = true;
|
||||||
for (auto const &arg : m_args) {
|
for( auto const &arg : m_args ) {
|
||||||
if (first)
|
if (first)
|
||||||
first = false;
|
first = false;
|
||||||
else
|
else
|
||||||
os << " ";
|
os << " ";
|
||||||
if (arg.isOptional() && required) {
|
if( arg.isOptional() && required ) {
|
||||||
os << "[";
|
os << "[";
|
||||||
required = false;
|
required = false;
|
||||||
}
|
}
|
||||||
os << "<" << arg.hint() << ">";
|
os << "<" << arg.hint() << ">";
|
||||||
if (arg.cardinality() == 0)
|
if( arg.cardinality() == 0 )
|
||||||
os << " ... ";
|
os << " ... ";
|
||||||
}
|
}
|
||||||
if (!required)
|
if( !required )
|
||||||
os << "]";
|
os << "]";
|
||||||
if (!m_options.empty())
|
if( !m_options.empty() )
|
||||||
os << " options";
|
os << " options";
|
||||||
os << "\n\nwhere options are:" << std::endl;
|
os << "\n\nwhere options are:" << std::endl;
|
||||||
}
|
}
|
||||||
@ -1108,32 +1102,32 @@ namespace detail {
|
|||||||
auto rows = getHelpColumns();
|
auto rows = getHelpColumns();
|
||||||
size_t consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
|
size_t consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
|
||||||
size_t optWidth = 0;
|
size_t optWidth = 0;
|
||||||
for (auto const &cols : rows)
|
for( auto const &cols : rows )
|
||||||
optWidth = std::max(optWidth, cols.left.size() + 2);
|
optWidth = std::max(optWidth, cols.left.size() + 2);
|
||||||
|
|
||||||
for (auto const &cols : rows) {
|
for( auto const &cols : rows ) {
|
||||||
auto row =
|
auto row =
|
||||||
TextFlow::Column(cols.left).width(optWidth).indent(2) +
|
TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
|
||||||
TextFlow::Spacer(4) +
|
TextFlow::Spacer(4) +
|
||||||
TextFlow::Column(cols.right).width(consoleWidth - 7 - optWidth);
|
TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );
|
||||||
os << row << std::endl;
|
os << row << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
friend auto operator<<(std::ostream &os, Parser const &parser) -> std::ostream & {
|
friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {
|
||||||
parser.writeToStream(os);
|
parser.writeToStream( os );
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto validate() const -> Result override {
|
auto validate() const -> Result override {
|
||||||
for (auto const &opt : m_options) {
|
for( auto const &opt : m_options ) {
|
||||||
auto result = opt.validate();
|
auto result = opt.validate();
|
||||||
if (!result)
|
if( !result )
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
for (auto const &arg : m_args) {
|
for( auto const &arg : m_args ) {
|
||||||
auto result = arg.validate();
|
auto result = arg.validate();
|
||||||
if (!result)
|
if( !result )
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return Result::ok();
|
return Result::ok();
|
||||||
@ -1141,47 +1135,41 @@ namespace detail {
|
|||||||
|
|
||||||
using ParserBase::parse;
|
using ParserBase::parse;
|
||||||
|
|
||||||
auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult override {
|
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;
|
|
||||||
|
|
||||||
for (auto const &opt : m_options) {
|
struct ParserInfo {
|
||||||
allParsers.push_back(&opt);
|
ParserBase const* parser = nullptr;
|
||||||
if (!opt.isOptional())
|
size_t count = 0;
|
||||||
requiredParsers.insert(&opt);
|
};
|
||||||
}
|
const size_t totalParsers = m_options.size() + m_args.size();
|
||||||
|
ParserInfo parseInfos[totalParsers];
|
||||||
size_t optionalArgs = 0;
|
size_t i = 0;
|
||||||
for (auto const &arg : m_args) {
|
for( auto const& opt : m_options ) parseInfos[i++].parser = &opt;
|
||||||
allParsers.push_back(&arg);
|
for( auto const& arg : m_args ) parseInfos[i++].parser = &arg;
|
||||||
if (!arg.isOptional()) {
|
|
||||||
if (optionalArgs > 0)
|
|
||||||
return InternalParseResult::logicError(
|
|
||||||
"Required arguments must preceed any optional arguments");
|
|
||||||
else
|
|
||||||
++optionalArgs;
|
|
||||||
requiredParsers.insert(&arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_exeName.set( exeName );
|
m_exeName.set( exeName );
|
||||||
|
|
||||||
auto result = InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens));
|
auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
|
||||||
while (result.value().remainingTokens()) {
|
while( result.value().remainingTokens() ) {
|
||||||
auto remainingTokenCount = result.value().remainingTokens().count();
|
bool tokenParsed = false;
|
||||||
for (auto parser : allParsers) {
|
|
||||||
result = parser->parse( exeName, result.value().remainingTokens() );
|
for( auto& parseInfo : parseInfos ) {
|
||||||
if (!result || result.value().type() != ParseResultType::NoMatch) {
|
if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {
|
||||||
if (parser->cardinality() == 1)
|
result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
|
||||||
allParsers.erase(std::remove(allParsers.begin(), allParsers.end(), parser),
|
if (!result)
|
||||||
allParsers.end());
|
return result;
|
||||||
requiredParsers.erase(parser);
|
if (result.value().type() != ParseResultType::NoMatch) {
|
||||||
|
tokenParsed = true;
|
||||||
|
++parseInfo.count;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!result || remainingTokenCount == result.value().remainingTokens().count())
|
}
|
||||||
|
|
||||||
|
if( result.value().type() == ParseResultType::ShortCircuitAll )
|
||||||
return result;
|
return result;
|
||||||
|
if( !tokenParsed )
|
||||||
|
return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );
|
||||||
}
|
}
|
||||||
// !TBD Check missing required options
|
// !TBD Check missing required options
|
||||||
return result;
|
return result;
|
||||||
@ -1190,8 +1178,8 @@ namespace detail {
|
|||||||
|
|
||||||
template<typename DerivedT>
|
template<typename DerivedT>
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto ComposableParserImpl<DerivedT>::operator+(T const &other) const -> Parser {
|
auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {
|
||||||
return Parser() + static_cast<DerivedT const &>( *this ) + other;
|
return Parser() | static_cast<DerivedT const &>( *this ) | other;
|
||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user