File indexing completed on 2025-09-18 09:08:50
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef CATCH_CLARA_HPP_INCLUDED
0009 #define CATCH_CLARA_HPP_INCLUDED
0010
0011 #if defined( __clang__ )
0012 # pragma clang diagnostic push
0013 # pragma clang diagnostic ignored "-Wweak-vtables"
0014 # pragma clang diagnostic ignored "-Wshadow"
0015 # pragma clang diagnostic ignored "-Wdeprecated"
0016 #endif
0017
0018 #if defined( __GNUC__ )
0019 # pragma GCC diagnostic push
0020 # pragma GCC diagnostic ignored "-Wsign-conversion"
0021 #endif
0022
0023 #ifndef CLARA_CONFIG_OPTIONAL_TYPE
0024 # ifdef __has_include
0025 # if __has_include( <optional>) && __cplusplus >= 201703L
0026 # include <optional>
0027 # define CLARA_CONFIG_OPTIONAL_TYPE std::optional
0028 # endif
0029 # endif
0030 #endif
0031
0032 #include <catch2/internal/catch_stringref.hpp>
0033 #include <catch2/internal/catch_move_and_forward.hpp>
0034 #include <catch2/internal/catch_noncopyable.hpp>
0035 #include <catch2/internal/catch_void_type.hpp>
0036
0037 #include <cassert>
0038 #include <memory>
0039 #include <ostream>
0040 #include <sstream>
0041 #include <string>
0042 #include <type_traits>
0043 #include <vector>
0044
0045 namespace Catch {
0046 namespace Clara {
0047
0048 class Args;
0049 class Parser;
0050
0051
0052 enum class ParseResultType {
0053 Matched,
0054 NoMatch,
0055 ShortCircuitAll,
0056 ShortCircuitSame
0057 };
0058
0059 struct accept_many_t {};
0060 constexpr accept_many_t accept_many {};
0061
0062 namespace Detail {
0063 struct fake_arg {
0064 template <typename T>
0065 operator T();
0066 };
0067
0068 template <typename F, typename = void>
0069 struct is_unary_function : std::false_type {};
0070
0071 template <typename F>
0072 struct is_unary_function<
0073 F,
0074 Catch::Detail::void_t<decltype(
0075 std::declval<F>()( fake_arg() ) )
0076 >
0077 > : std::true_type {};
0078
0079
0080
0081 template <typename L>
0082 struct UnaryLambdaTraits
0083 : UnaryLambdaTraits<decltype( &L::operator() )> {};
0084
0085 template <typename ClassT, typename ReturnT, typename... Args>
0086 struct UnaryLambdaTraits<ReturnT ( ClassT::* )( Args... ) const> {
0087 static const bool isValid = false;
0088 };
0089
0090 template <typename ClassT, typename ReturnT, typename ArgT>
0091 struct UnaryLambdaTraits<ReturnT ( ClassT::* )( ArgT ) const> {
0092 static const bool isValid = true;
0093 using ArgType = std::remove_const_t<std::remove_reference_t<ArgT>>;
0094 using ReturnType = ReturnT;
0095 };
0096
0097 class TokenStream;
0098
0099
0100
0101
0102 enum class TokenType { Option, Argument };
0103 struct Token {
0104 TokenType type;
0105 StringRef token;
0106 };
0107
0108
0109
0110 class TokenStream {
0111 using Iterator = std::vector<StringRef>::const_iterator;
0112 Iterator it;
0113 Iterator itEnd;
0114 std::vector<Token> m_tokenBuffer;
0115 void loadBuffer();
0116
0117 public:
0118 explicit TokenStream( Args const& args );
0119 TokenStream( Iterator it, Iterator itEnd );
0120
0121 explicit operator bool() const {
0122 return !m_tokenBuffer.empty() || it != itEnd;
0123 }
0124
0125 size_t count() const {
0126 return m_tokenBuffer.size() + ( itEnd - it );
0127 }
0128
0129 Token operator*() const {
0130 assert( !m_tokenBuffer.empty() );
0131 return m_tokenBuffer.front();
0132 }
0133
0134 Token const* operator->() const {
0135 assert( !m_tokenBuffer.empty() );
0136 return &m_tokenBuffer.front();
0137 }
0138
0139 TokenStream& operator++();
0140 };
0141
0142
0143 enum class ResultType {
0144 Ok,
0145 LogicError,
0146
0147 RuntimeError
0148 };
0149
0150 class ResultBase {
0151 protected:
0152 ResultBase( ResultType type ): m_type( type ) {}
0153 virtual ~ResultBase();
0154
0155
0156 ResultBase(ResultBase const&) = default;
0157 ResultBase& operator=(ResultBase const&) = default;
0158 ResultBase(ResultBase&&) = default;
0159 ResultBase& operator=(ResultBase&&) = default;
0160
0161 virtual void enforceOk() const = 0;
0162
0163 ResultType m_type;
0164 };
0165
0166 template <typename T>
0167 class ResultValueBase : public ResultBase {
0168 public:
0169 T const& value() const& {
0170 enforceOk();
0171 return m_value;
0172 }
0173 T&& value() && {
0174 enforceOk();
0175 return CATCH_MOVE( m_value );
0176 }
0177
0178 protected:
0179 ResultValueBase( ResultType type ): ResultBase( type ) {}
0180
0181 ResultValueBase( ResultValueBase const& other ):
0182 ResultBase( other ) {
0183 if ( m_type == ResultType::Ok )
0184 new ( &m_value ) T( other.m_value );
0185 }
0186 ResultValueBase( ResultValueBase&& other ):
0187 ResultBase( other ) {
0188 if ( m_type == ResultType::Ok )
0189 new ( &m_value ) T( CATCH_MOVE(other.m_value) );
0190 }
0191
0192
0193 ResultValueBase( ResultType, T const& value ):
0194 ResultBase( ResultType::Ok ) {
0195 new ( &m_value ) T( value );
0196 }
0197 ResultValueBase( ResultType, T&& value ):
0198 ResultBase( ResultType::Ok ) {
0199 new ( &m_value ) T( CATCH_MOVE(value) );
0200 }
0201
0202 ResultValueBase& operator=( ResultValueBase const& other ) {
0203 if ( m_type == ResultType::Ok )
0204 m_value.~T();
0205 ResultBase::operator=( other );
0206 if ( m_type == ResultType::Ok )
0207 new ( &m_value ) T( other.m_value );
0208 return *this;
0209 }
0210 ResultValueBase& operator=( ResultValueBase&& other ) {
0211 if ( m_type == ResultType::Ok ) m_value.~T();
0212 ResultBase::operator=( other );
0213 if ( m_type == ResultType::Ok )
0214 new ( &m_value ) T( CATCH_MOVE(other.m_value) );
0215 return *this;
0216 }
0217
0218
0219 ~ResultValueBase() override {
0220 if ( m_type == ResultType::Ok )
0221 m_value.~T();
0222 }
0223
0224 union {
0225 T m_value;
0226 };
0227 };
0228
0229 template <> class ResultValueBase<void> : public ResultBase {
0230 protected:
0231 using ResultBase::ResultBase;
0232 };
0233
0234 template <typename T = void>
0235 class BasicResult : public ResultValueBase<T> {
0236 public:
0237 template <typename U>
0238 explicit BasicResult( BasicResult<U> const& other ):
0239 ResultValueBase<T>( other.type() ),
0240 m_errorMessage( other.errorMessage() ) {
0241 assert( type() != ResultType::Ok );
0242 }
0243
0244 template <typename U>
0245 static auto ok( U&& value ) -> BasicResult {
0246 return { ResultType::Ok, CATCH_FORWARD(value) };
0247 }
0248 static auto ok() -> BasicResult { return { ResultType::Ok }; }
0249 static auto logicError( std::string&& message )
0250 -> BasicResult {
0251 return { ResultType::LogicError, CATCH_MOVE(message) };
0252 }
0253 static auto runtimeError( std::string&& message )
0254 -> BasicResult {
0255 return { ResultType::RuntimeError, CATCH_MOVE(message) };
0256 }
0257
0258 explicit operator bool() const {
0259 return m_type == ResultType::Ok;
0260 }
0261 auto type() const -> ResultType { return m_type; }
0262 auto errorMessage() const -> std::string const& {
0263 return m_errorMessage;
0264 }
0265
0266 protected:
0267 void enforceOk() const override {
0268
0269
0270
0271 assert( m_type != ResultType::LogicError );
0272 assert( m_type != ResultType::RuntimeError );
0273 if ( m_type != ResultType::Ok )
0274 std::abort();
0275 }
0276
0277 std::string
0278 m_errorMessage;
0279
0280 BasicResult( ResultType type,
0281 std::string&& message ):
0282 ResultValueBase<T>( type ), m_errorMessage( CATCH_MOVE(message) ) {
0283 assert( m_type != ResultType::Ok );
0284 }
0285
0286 using ResultValueBase<T>::ResultValueBase;
0287 using ResultBase::m_type;
0288 };
0289
0290 class ParseState {
0291 public:
0292 ParseState( ParseResultType type,
0293 TokenStream remainingTokens );
0294
0295 ParseResultType type() const { return m_type; }
0296 TokenStream const& remainingTokens() const& {
0297 return m_remainingTokens;
0298 }
0299 TokenStream&& remainingTokens() && {
0300 return CATCH_MOVE( m_remainingTokens );
0301 }
0302
0303 private:
0304 ParseResultType m_type;
0305 TokenStream m_remainingTokens;
0306 };
0307
0308 using Result = BasicResult<void>;
0309 using ParserResult = BasicResult<ParseResultType>;
0310 using InternalParseResult = BasicResult<ParseState>;
0311
0312 struct HelpColumns {
0313 std::string left;
0314 StringRef descriptions;
0315 };
0316
0317 template <typename T>
0318 ParserResult convertInto( std::string const& source, T& target ) {
0319 std::stringstream ss( source );
0320 ss >> target;
0321 if ( ss.fail() ) {
0322 return ParserResult::runtimeError(
0323 "Unable to convert '" + source +
0324 "' to destination type" );
0325 } else {
0326 return ParserResult::ok( ParseResultType::Matched );
0327 }
0328 }
0329 ParserResult convertInto( std::string const& source,
0330 std::string& target );
0331 ParserResult convertInto( std::string const& source, bool& target );
0332
0333 #ifdef CLARA_CONFIG_OPTIONAL_TYPE
0334 template <typename T>
0335 auto convertInto( std::string const& source,
0336 CLARA_CONFIG_OPTIONAL_TYPE<T>& target )
0337 -> ParserResult {
0338 T temp;
0339 auto result = convertInto( source, temp );
0340 if ( result )
0341 target = CATCH_MOVE( temp );
0342 return result;
0343 }
0344 #endif
0345
0346 struct BoundRef : Catch::Detail::NonCopyable {
0347 virtual ~BoundRef() = default;
0348 virtual bool isContainer() const;
0349 virtual bool isFlag() const;
0350 };
0351 struct BoundValueRefBase : BoundRef {
0352 virtual auto setValue( std::string const& arg )
0353 -> ParserResult = 0;
0354 };
0355 struct BoundFlagRefBase : BoundRef {
0356 virtual auto setFlag( bool flag ) -> ParserResult = 0;
0357 bool isFlag() const override;
0358 };
0359
0360 template <typename T> struct BoundValueRef : BoundValueRefBase {
0361 T& m_ref;
0362
0363 explicit BoundValueRef( T& ref ): m_ref( ref ) {}
0364
0365 ParserResult setValue( std::string const& arg ) override {
0366 return convertInto( arg, m_ref );
0367 }
0368 };
0369
0370 template <typename T>
0371 struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
0372 std::vector<T>& m_ref;
0373
0374 explicit BoundValueRef( std::vector<T>& ref ): m_ref( ref ) {}
0375
0376 auto isContainer() const -> bool override { return true; }
0377
0378 auto setValue( std::string const& arg )
0379 -> ParserResult override {
0380 T temp;
0381 auto result = convertInto( arg, temp );
0382 if ( result )
0383 m_ref.push_back( temp );
0384 return result;
0385 }
0386 };
0387
0388 struct BoundFlagRef : BoundFlagRefBase {
0389 bool& m_ref;
0390
0391 explicit BoundFlagRef( bool& ref ): m_ref( ref ) {}
0392
0393 ParserResult setFlag( bool flag ) override;
0394 };
0395
0396 template <typename ReturnType> struct LambdaInvoker {
0397 static_assert(
0398 std::is_same<ReturnType, ParserResult>::value,
0399 "Lambda must return void or clara::ParserResult" );
0400
0401 template <typename L, typename ArgType>
0402 static auto invoke( L const& lambda, ArgType const& arg )
0403 -> ParserResult {
0404 return lambda( arg );
0405 }
0406 };
0407
0408 template <> struct LambdaInvoker<void> {
0409 template <typename L, typename ArgType>
0410 static auto invoke( L const& lambda, ArgType const& arg )
0411 -> ParserResult {
0412 lambda( arg );
0413 return ParserResult::ok( ParseResultType::Matched );
0414 }
0415 };
0416
0417 template <typename ArgType, typename L>
0418 auto invokeLambda( L const& lambda, std::string const& arg )
0419 -> ParserResult {
0420 ArgType temp{};
0421 auto result = convertInto( arg, temp );
0422 return !result ? result
0423 : LambdaInvoker<typename UnaryLambdaTraits<
0424 L>::ReturnType>::invoke( lambda, temp );
0425 }
0426
0427 template <typename L> struct BoundLambda : BoundValueRefBase {
0428 L m_lambda;
0429
0430 static_assert(
0431 UnaryLambdaTraits<L>::isValid,
0432 "Supplied lambda must take exactly one argument" );
0433 explicit BoundLambda( L const& lambda ): m_lambda( lambda ) {}
0434
0435 auto setValue( std::string const& arg )
0436 -> ParserResult override {
0437 return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(
0438 m_lambda, arg );
0439 }
0440 };
0441
0442 template <typename L> struct BoundManyLambda : BoundLambda<L> {
0443 explicit BoundManyLambda( L const& lambda ): BoundLambda<L>( lambda ) {}
0444 bool isContainer() const override { return true; }
0445 };
0446
0447 template <typename L> struct BoundFlagLambda : BoundFlagRefBase {
0448 L m_lambda;
0449
0450 static_assert(
0451 UnaryLambdaTraits<L>::isValid,
0452 "Supplied lambda must take exactly one argument" );
0453 static_assert(
0454 std::is_same<typename UnaryLambdaTraits<L>::ArgType,
0455 bool>::value,
0456 "flags must be boolean" );
0457
0458 explicit BoundFlagLambda( L const& lambda ):
0459 m_lambda( lambda ) {}
0460
0461 auto setFlag( bool flag ) -> ParserResult override {
0462 return LambdaInvoker<typename UnaryLambdaTraits<
0463 L>::ReturnType>::invoke( m_lambda, flag );
0464 }
0465 };
0466
0467 enum class Optionality { Optional, Required };
0468
0469 class ParserBase {
0470 public:
0471 virtual ~ParserBase() = default;
0472 virtual auto validate() const -> Result { return Result::ok(); }
0473 virtual auto parse( std::string const& exeName,
0474 TokenStream tokens ) const
0475 -> InternalParseResult = 0;
0476 virtual size_t cardinality() const;
0477
0478 InternalParseResult parse( Args const& args ) const;
0479 };
0480
0481 template <typename DerivedT>
0482 class ComposableParserImpl : public ParserBase {
0483 public:
0484 template <typename T>
0485 auto operator|( T const& other ) const -> Parser;
0486 };
0487
0488
0489 template <typename DerivedT>
0490 class ParserRefImpl : public ComposableParserImpl<DerivedT> {
0491 protected:
0492 Optionality m_optionality = Optionality::Optional;
0493 std::shared_ptr<BoundRef> m_ref;
0494 StringRef m_hint;
0495 StringRef m_description;
0496
0497 explicit ParserRefImpl( std::shared_ptr<BoundRef> const& ref ):
0498 m_ref( ref ) {}
0499
0500 public:
0501 template <typename LambdaT>
0502 ParserRefImpl( accept_many_t,
0503 LambdaT const& ref,
0504 StringRef hint ):
0505 m_ref( std::make_shared<BoundManyLambda<LambdaT>>( ref ) ),
0506 m_hint( hint ) {}
0507
0508 template <typename T,
0509 typename = typename std::enable_if_t<
0510 !Detail::is_unary_function<T>::value>>
0511 ParserRefImpl( T& ref, StringRef hint ):
0512 m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
0513 m_hint( hint ) {}
0514
0515 template <typename LambdaT,
0516 typename = typename std::enable_if_t<
0517 Detail::is_unary_function<LambdaT>::value>>
0518 ParserRefImpl( LambdaT const& ref, StringRef hint ):
0519 m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
0520 m_hint( hint ) {}
0521
0522 DerivedT& operator()( StringRef description ) & {
0523 m_description = description;
0524 return static_cast<DerivedT&>( *this );
0525 }
0526 DerivedT&& operator()( StringRef description ) && {
0527 m_description = description;
0528 return static_cast<DerivedT&&>( *this );
0529 }
0530
0531 auto optional() -> DerivedT& {
0532 m_optionality = Optionality::Optional;
0533 return static_cast<DerivedT&>( *this );
0534 }
0535
0536 auto required() -> DerivedT& {
0537 m_optionality = Optionality::Required;
0538 return static_cast<DerivedT&>( *this );
0539 }
0540
0541 auto isOptional() const -> bool {
0542 return m_optionality == Optionality::Optional;
0543 }
0544
0545 auto cardinality() const -> size_t override {
0546 if ( m_ref->isContainer() )
0547 return 0;
0548 else
0549 return 1;
0550 }
0551
0552 StringRef hint() const { return m_hint; }
0553 };
0554
0555 }
0556
0557
0558
0559 class Arg : public Detail::ParserRefImpl<Arg> {
0560 public:
0561 using ParserRefImpl::ParserRefImpl;
0562 using ParserBase::parse;
0563
0564 Detail::InternalParseResult
0565 parse(std::string const&,
0566 Detail::TokenStream tokens) const override;
0567 };
0568
0569
0570 class Opt : public Detail::ParserRefImpl<Opt> {
0571 protected:
0572 std::vector<StringRef> m_optNames;
0573
0574 public:
0575 template <typename LambdaT>
0576 explicit Opt(LambdaT const& ref) :
0577 ParserRefImpl(
0578 std::make_shared<Detail::BoundFlagLambda<LambdaT>>(ref)) {}
0579
0580 explicit Opt(bool& ref);
0581
0582 template <typename LambdaT,
0583 typename = typename std::enable_if_t<
0584 Detail::is_unary_function<LambdaT>::value>>
0585 Opt( LambdaT const& ref, StringRef hint ):
0586 ParserRefImpl( ref, hint ) {}
0587
0588 template <typename LambdaT>
0589 Opt( accept_many_t, LambdaT const& ref, StringRef hint ):
0590 ParserRefImpl( accept_many, ref, hint ) {}
0591
0592 template <typename T,
0593 typename = typename std::enable_if_t<
0594 !Detail::is_unary_function<T>::value>>
0595 Opt( T& ref, StringRef hint ):
0596 ParserRefImpl( ref, hint ) {}
0597
0598 Opt& operator[]( StringRef optName ) & {
0599 m_optNames.push_back(optName);
0600 return *this;
0601 }
0602 Opt&& operator[]( StringRef optName ) && {
0603 m_optNames.push_back( optName );
0604 return CATCH_MOVE(*this);
0605 }
0606
0607 Detail::HelpColumns getHelpColumns() const;
0608
0609 bool isMatch(StringRef optToken) const;
0610
0611 using ParserBase::parse;
0612
0613 Detail::InternalParseResult
0614 parse(std::string const&,
0615 Detail::TokenStream tokens) const override;
0616
0617 Detail::Result validate() const override;
0618 };
0619
0620
0621 class ExeName : public Detail::ComposableParserImpl<ExeName> {
0622 std::shared_ptr<std::string> m_name;
0623 std::shared_ptr<Detail::BoundValueRefBase> m_ref;
0624
0625 public:
0626 ExeName();
0627 explicit ExeName(std::string& ref);
0628
0629 template <typename LambdaT>
0630 explicit ExeName(LambdaT const& lambda) : ExeName() {
0631 m_ref = std::make_shared<Detail::BoundLambda<LambdaT>>(lambda);
0632 }
0633
0634
0635
0636 Detail::InternalParseResult
0637 parse(std::string const&,
0638 Detail::TokenStream tokens) const override;
0639
0640 std::string const& name() const { return *m_name; }
0641 Detail::ParserResult set(std::string const& newName);
0642 };
0643
0644
0645
0646 class Parser : Detail::ParserBase {
0647 mutable ExeName m_exeName;
0648 std::vector<Opt> m_options;
0649 std::vector<Arg> m_args;
0650
0651 public:
0652
0653 auto operator|=(ExeName const& exeName) -> Parser& {
0654 m_exeName = exeName;
0655 return *this;
0656 }
0657
0658 auto operator|=(Arg const& arg) -> Parser& {
0659 m_args.push_back(arg);
0660 return *this;
0661 }
0662
0663 friend Parser& operator|=( Parser& p, Opt const& opt ) {
0664 p.m_options.push_back( opt );
0665 return p;
0666 }
0667 friend Parser& operator|=( Parser& p, Opt&& opt ) {
0668 p.m_options.push_back( CATCH_MOVE(opt) );
0669 return p;
0670 }
0671
0672 Parser& operator|=(Parser const& other);
0673
0674 template <typename T>
0675 friend Parser operator|( Parser const& p, T&& rhs ) {
0676 Parser temp( p );
0677 temp |= rhs;
0678 return temp;
0679 }
0680
0681 template <typename T>
0682 friend Parser operator|( Parser&& p, T&& rhs ) {
0683 p |= CATCH_FORWARD(rhs);
0684 return CATCH_MOVE(p);
0685 }
0686
0687 std::vector<Detail::HelpColumns> getHelpColumns() const;
0688
0689 void writeToStream(std::ostream& os) const;
0690
0691 friend auto operator<<(std::ostream& os, Parser const& parser)
0692 -> std::ostream& {
0693 parser.writeToStream(os);
0694 return os;
0695 }
0696
0697 Detail::Result validate() const override;
0698
0699 using ParserBase::parse;
0700 Detail::InternalParseResult
0701 parse(std::string const& exeName,
0702 Detail::TokenStream tokens) const override;
0703 };
0704
0705
0706
0707
0708 class Args {
0709 friend Detail::TokenStream;
0710 StringRef m_exeName;
0711 std::vector<StringRef> m_args;
0712
0713 public:
0714 Args(int argc, char const* const* argv);
0715
0716 Args(std::initializer_list<StringRef> args);
0717
0718 StringRef exeName() const { return m_exeName; }
0719 };
0720
0721
0722
0723 struct Help : Opt {
0724 Help(bool& showHelpFlag);
0725 };
0726
0727
0728 using Detail::ParserResult;
0729
0730 namespace Detail {
0731 template <typename DerivedT>
0732 template <typename T>
0733 Parser
0734 ComposableParserImpl<DerivedT>::operator|(T const& other) const {
0735 return Parser() | static_cast<DerivedT const&>(*this) | other;
0736 }
0737 }
0738
0739 }
0740 }
0741
0742 #if defined( __clang__ )
0743 # pragma clang diagnostic pop
0744 #endif
0745
0746 #if defined( __GNUC__ )
0747 # pragma GCC diagnostic pop
0748 #endif
0749
0750 #endif