clara.hpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  1. // Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. //
  6. // See https://github.com/philsquared/Clara for more details
  7. // Clara v1.1.5
  8. #ifndef CATCH_CLARA_HPP_INCLUDED
  9. #define CATCH_CLARA_HPP_INCLUDED
  10. #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH
  11. #define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80
  12. #endif
  13. #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
  14. #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
  15. #endif
  16. #ifndef CLARA_CONFIG_OPTIONAL_TYPE
  17. #ifdef __has_include
  18. #if __has_include(<optional>) && __cplusplus >= 201703L
  19. #include <optional>
  20. #define CLARA_CONFIG_OPTIONAL_TYPE std::optional
  21. #endif
  22. #endif
  23. #endif
  24. // ----------- #included from clara_textflow.hpp -----------
  25. // TextFlowCpp
  26. //
  27. // A single-header library for wrapping and laying out basic text, by Phil Nash
  28. //
  29. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  30. // file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  31. //
  32. // This project is hosted at https://github.com/philsquared/textflowcpp
  33. #ifndef CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
  34. #define CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
  35. #include <cassert>
  36. #include <ostream>
  37. #include <sstream>
  38. #include <vector>
  39. #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
  40. #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80
  41. #endif
  42. namespace Catch {
  43. namespace clara {
  44. namespace TextFlow {
  45. inline auto isWhitespace(char c) -> bool {
  46. static std::string chars = " \t\n\r";
  47. return chars.find(c) != std::string::npos;
  48. }
  49. inline auto isBreakableBefore(char c) -> bool {
  50. static std::string chars = "[({<|";
  51. return chars.find(c) != std::string::npos;
  52. }
  53. inline auto isBreakableAfter(char c) -> bool {
  54. static std::string chars = "])}>.,:;*+-=&/\\";
  55. return chars.find(c) != std::string::npos;
  56. }
  57. class Columns;
  58. class Column {
  59. std::vector<std::string> m_strings;
  60. size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
  61. size_t m_indent = 0;
  62. size_t m_initialIndent = std::string::npos;
  63. public:
  64. class iterator {
  65. friend Column;
  66. Column const& m_column;
  67. size_t m_stringIndex = 0;
  68. size_t m_pos = 0;
  69. size_t m_len = 0;
  70. size_t m_end = 0;
  71. bool m_suffix = false;
  72. iterator(Column const& column, size_t stringIndex)
  73. : m_column(column),
  74. m_stringIndex(stringIndex) {}
  75. auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
  76. auto isBoundary(size_t at) const -> bool {
  77. assert(at > 0);
  78. assert(at <= line().size());
  79. return at == line().size() ||
  80. (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||
  81. isBreakableBefore(line()[at]) ||
  82. isBreakableAfter(line()[at - 1]);
  83. }
  84. void calcLength() {
  85. assert(m_stringIndex < m_column.m_strings.size());
  86. m_suffix = false;
  87. auto width = m_column.m_width - indent();
  88. m_end = m_pos;
  89. if (line()[m_pos] == '\n') {
  90. ++m_end;
  91. }
  92. while (m_end < line().size() && line()[m_end] != '\n')
  93. ++m_end;
  94. if (m_end < m_pos + width) {
  95. m_len = m_end - m_pos;
  96. } else {
  97. size_t len = width;
  98. while (len > 0 && !isBoundary(m_pos + len))
  99. --len;
  100. while (len > 0 && isWhitespace(line()[m_pos + len - 1]))
  101. --len;
  102. if (len > 0) {
  103. m_len = len;
  104. } else {
  105. m_suffix = true;
  106. m_len = width - 1;
  107. }
  108. }
  109. }
  110. auto indent() const -> size_t {
  111. auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
  112. return initial == std::string::npos ? m_column.m_indent : initial;
  113. }
  114. auto addIndentAndSuffix(std::string const &plain) const -> std::string {
  115. return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain);
  116. }
  117. public:
  118. using difference_type = std::ptrdiff_t;
  119. using value_type = std::string;
  120. using pointer = value_type * ;
  121. using reference = value_type & ;
  122. using iterator_category = std::forward_iterator_tag;
  123. explicit iterator(Column const& column) : m_column(column) {
  124. assert(m_column.m_width > m_column.m_indent);
  125. assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent);
  126. calcLength();
  127. if (m_len == 0)
  128. m_stringIndex++; // Empty string
  129. }
  130. auto operator *() const -> std::string {
  131. assert(m_stringIndex < m_column.m_strings.size());
  132. assert(m_pos <= m_end);
  133. return addIndentAndSuffix(line().substr(m_pos, m_len));
  134. }
  135. auto operator ++() -> iterator& {
  136. m_pos += m_len;
  137. if (m_pos < line().size() && line()[m_pos] == '\n')
  138. m_pos += 1;
  139. else
  140. while (m_pos < line().size() && isWhitespace(line()[m_pos]))
  141. ++m_pos;
  142. if (m_pos == line().size()) {
  143. m_pos = 0;
  144. ++m_stringIndex;
  145. }
  146. if (m_stringIndex < m_column.m_strings.size())
  147. calcLength();
  148. return *this;
  149. }
  150. auto operator ++(int) -> iterator {
  151. iterator prev(*this);
  152. operator++();
  153. return prev;
  154. }
  155. auto operator ==(iterator const& other) const -> bool {
  156. return
  157. m_pos == other.m_pos &&
  158. m_stringIndex == other.m_stringIndex &&
  159. &m_column == &other.m_column;
  160. }
  161. auto operator !=(iterator const& other) const -> bool {
  162. return !operator==(other);
  163. }
  164. };
  165. using const_iterator = iterator;
  166. explicit Column(std::string const& text) { m_strings.push_back(text); }
  167. auto width(size_t newWidth) -> Column& {
  168. assert(newWidth > 0);
  169. m_width = newWidth;
  170. return *this;
  171. }
  172. auto indent(size_t newIndent) -> Column& {
  173. m_indent = newIndent;
  174. return *this;
  175. }
  176. auto initialIndent(size_t newIndent) -> Column& {
  177. m_initialIndent = newIndent;
  178. return *this;
  179. }
  180. auto width() const -> size_t { return m_width; }
  181. auto begin() const -> iterator { return iterator(*this); }
  182. auto end() const -> iterator { return { *this, m_strings.size() }; }
  183. inline friend std::ostream& operator << (std::ostream& os, Column const& col) {
  184. bool first = true;
  185. for (auto line : col) {
  186. if (first)
  187. first = false;
  188. else
  189. os << "\n";
  190. os << line;
  191. }
  192. return os;
  193. }
  194. auto operator + (Column const& other)->Columns;
  195. auto toString() const -> std::string {
  196. std::ostringstream oss;
  197. oss << *this;
  198. return oss.str();
  199. }
  200. };
  201. class Spacer : public Column {
  202. public:
  203. explicit Spacer(size_t spaceWidth) : Column("") {
  204. width(spaceWidth);
  205. }
  206. };
  207. class Columns {
  208. std::vector<Column> m_columns;
  209. public:
  210. class iterator {
  211. friend Columns;
  212. struct EndTag {};
  213. std::vector<Column> const& m_columns;
  214. std::vector<Column::iterator> m_iterators;
  215. size_t m_activeIterators;
  216. iterator(Columns const& columns, EndTag)
  217. : m_columns(columns.m_columns),
  218. m_activeIterators(0) {
  219. m_iterators.reserve(m_columns.size());
  220. for (auto const& col : m_columns)
  221. m_iterators.push_back(col.end());
  222. }
  223. public:
  224. using difference_type = std::ptrdiff_t;
  225. using value_type = std::string;
  226. using pointer = value_type * ;
  227. using reference = value_type & ;
  228. using iterator_category = std::forward_iterator_tag;
  229. explicit iterator(Columns const& columns)
  230. : m_columns(columns.m_columns),
  231. m_activeIterators(m_columns.size()) {
  232. m_iterators.reserve(m_columns.size());
  233. for (auto const& col : m_columns)
  234. m_iterators.push_back(col.begin());
  235. }
  236. auto operator ==(iterator const& other) const -> bool {
  237. return m_iterators == other.m_iterators;
  238. }
  239. auto operator !=(iterator const& other) const -> bool {
  240. return m_iterators != other.m_iterators;
  241. }
  242. auto operator *() const -> std::string {
  243. std::string row, padding;
  244. for (size_t i = 0; i < m_columns.size(); ++i) {
  245. auto width = m_columns[i].width();
  246. if (m_iterators[i] != m_columns[i].end()) {
  247. std::string col = *m_iterators[i];
  248. row += padding + col;
  249. if (col.size() < width)
  250. padding = std::string(width - col.size(), ' ');
  251. else
  252. padding = "";
  253. } else {
  254. padding += std::string(width, ' ');
  255. }
  256. }
  257. return row;
  258. }
  259. auto operator ++() -> iterator& {
  260. for (size_t i = 0; i < m_columns.size(); ++i) {
  261. if (m_iterators[i] != m_columns[i].end())
  262. ++m_iterators[i];
  263. }
  264. return *this;
  265. }
  266. auto operator ++(int) -> iterator {
  267. iterator prev(*this);
  268. operator++();
  269. return prev;
  270. }
  271. };
  272. using const_iterator = iterator;
  273. auto begin() const -> iterator { return iterator(*this); }
  274. auto end() const -> iterator { return { *this, iterator::EndTag() }; }
  275. auto operator += (Column const& col) -> Columns& {
  276. m_columns.push_back(col);
  277. return *this;
  278. }
  279. auto operator + (Column const& col) -> Columns {
  280. Columns combined = *this;
  281. combined += col;
  282. return combined;
  283. }
  284. inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) {
  285. bool first = true;
  286. for (auto line : cols) {
  287. if (first)
  288. first = false;
  289. else
  290. os << "\n";
  291. os << line;
  292. }
  293. return os;
  294. }
  295. auto toString() const -> std::string {
  296. std::ostringstream oss;
  297. oss << *this;
  298. return oss.str();
  299. }
  300. };
  301. inline auto Column::operator + (Column const& other) -> Columns {
  302. Columns cols;
  303. cols += *this;
  304. cols += other;
  305. return cols;
  306. }
  307. }
  308. }
  309. }
  310. #endif // CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
  311. // ----------- end of #include from clara_textflow.hpp -----------
  312. // ........... back in clara.hpp
  313. #include <cctype>
  314. #include <string>
  315. #include <memory>
  316. #include <set>
  317. #include <algorithm>
  318. #if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )
  319. #define CATCH_PLATFORM_WINDOWS
  320. #endif
  321. namespace Catch { namespace clara {
  322. namespace detail {
  323. // Traits for extracting arg and return type of lambdas (for single argument lambdas)
  324. template<typename L>
  325. struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};
  326. template<typename ClassT, typename ReturnT, typename... Args>
  327. struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {
  328. static const bool isValid = false;
  329. };
  330. template<typename ClassT, typename ReturnT, typename ArgT>
  331. struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
  332. static const bool isValid = true;
  333. using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
  334. using ReturnType = ReturnT;
  335. };
  336. class TokenStream;
  337. // Transport for raw args (copied from main args, or supplied via init list for testing)
  338. class Args {
  339. friend TokenStream;
  340. std::string m_exeName;
  341. std::vector<std::string> m_args;
  342. public:
  343. Args( int argc, char const* const* argv )
  344. : m_exeName(argv[0]),
  345. m_args(argv + 1, argv + argc) {}
  346. Args( std::initializer_list<std::string> args )
  347. : m_exeName( *args.begin() ),
  348. m_args( args.begin()+1, args.end() )
  349. {}
  350. auto exeName() const -> std::string {
  351. return m_exeName;
  352. }
  353. };
  354. // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string
  355. // may encode an option + its argument if the : or = form is used
  356. enum class TokenType {
  357. Option, Argument
  358. };
  359. struct Token {
  360. TokenType type;
  361. std::string token;
  362. };
  363. inline auto isOptPrefix( char c ) -> bool {
  364. return c == '-'
  365. #ifdef CATCH_PLATFORM_WINDOWS
  366. || c == '/'
  367. #endif
  368. ;
  369. }
  370. // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled
  371. class TokenStream {
  372. using Iterator = std::vector<std::string>::const_iterator;
  373. Iterator it;
  374. Iterator itEnd;
  375. std::vector<Token> m_tokenBuffer;
  376. void loadBuffer() {
  377. m_tokenBuffer.resize( 0 );
  378. // Skip any empty strings
  379. while( it != itEnd && it->empty() )
  380. ++it;
  381. if( it != itEnd ) {
  382. auto const &next = *it;
  383. if( isOptPrefix( next[0] ) ) {
  384. auto delimiterPos = next.find_first_of( " :=" );
  385. if( delimiterPos != std::string::npos ) {
  386. m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
  387. m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );
  388. } else {
  389. if( next[1] != '-' && next.size() > 2 ) {
  390. std::string opt = "- ";
  391. for( size_t i = 1; i < next.size(); ++i ) {
  392. opt[1] = next[i];
  393. m_tokenBuffer.push_back( { TokenType::Option, opt } );
  394. }
  395. } else {
  396. m_tokenBuffer.push_back( { TokenType::Option, next } );
  397. }
  398. }
  399. } else {
  400. m_tokenBuffer.push_back( { TokenType::Argument, next } );
  401. }
  402. }
  403. }
  404. public:
  405. explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}
  406. TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {
  407. loadBuffer();
  408. }
  409. explicit operator bool() const {
  410. return !m_tokenBuffer.empty() || it != itEnd;
  411. }
  412. auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
  413. auto operator*() const -> Token {
  414. assert( !m_tokenBuffer.empty() );
  415. return m_tokenBuffer.front();
  416. }
  417. auto operator->() const -> Token const * {
  418. assert( !m_tokenBuffer.empty() );
  419. return &m_tokenBuffer.front();
  420. }
  421. auto operator++() -> TokenStream & {
  422. if( m_tokenBuffer.size() >= 2 ) {
  423. m_tokenBuffer.erase( m_tokenBuffer.begin() );
  424. } else {
  425. if( it != itEnd )
  426. ++it;
  427. loadBuffer();
  428. }
  429. return *this;
  430. }
  431. };
  432. class ResultBase {
  433. public:
  434. enum Type {
  435. Ok, LogicError, RuntimeError
  436. };
  437. protected:
  438. ResultBase( Type type ) : m_type( type ) {}
  439. virtual ~ResultBase() = default;
  440. virtual void enforceOk() const = 0;
  441. Type m_type;
  442. };
  443. template<typename T>
  444. class ResultValueBase : public ResultBase {
  445. public:
  446. auto value() const -> T const & {
  447. enforceOk();
  448. return m_value;
  449. }
  450. protected:
  451. ResultValueBase( Type type ) : ResultBase( type ) {}
  452. ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {
  453. if( m_type == ResultBase::Ok )
  454. new( &m_value ) T( other.m_value );
  455. }
  456. ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {
  457. new( &m_value ) T( value );
  458. }
  459. auto operator=( ResultValueBase const &other ) -> ResultValueBase & {
  460. if( m_type == ResultBase::Ok )
  461. m_value.~T();
  462. ResultBase::operator=(other);
  463. if( m_type == ResultBase::Ok )
  464. new( &m_value ) T( other.m_value );
  465. return *this;
  466. }
  467. ~ResultValueBase() override {
  468. if( m_type == Ok )
  469. m_value.~T();
  470. }
  471. union {
  472. T m_value;
  473. };
  474. };
  475. template<>
  476. class ResultValueBase<void> : public ResultBase {
  477. protected:
  478. using ResultBase::ResultBase;
  479. };
  480. template<typename T = void>
  481. class BasicResult : public ResultValueBase<T> {
  482. public:
  483. template<typename U>
  484. explicit BasicResult( BasicResult<U> const &other )
  485. : ResultValueBase<T>( other.type() ),
  486. m_errorMessage( other.errorMessage() )
  487. {
  488. assert( type() != ResultBase::Ok );
  489. }
  490. template<typename U>
  491. static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }
  492. static auto ok() -> BasicResult { return { ResultBase::Ok }; }
  493. static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }
  494. static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }
  495. explicit operator bool() const { return m_type == ResultBase::Ok; }
  496. auto type() const -> ResultBase::Type { return m_type; }
  497. auto errorMessage() const -> std::string { return m_errorMessage; }
  498. protected:
  499. void enforceOk() const override {
  500. // Errors shouldn't reach this point, but if they do
  501. // the actual error message will be in m_errorMessage
  502. assert( m_type != ResultBase::LogicError );
  503. assert( m_type != ResultBase::RuntimeError );
  504. if( m_type != ResultBase::Ok )
  505. std::abort();
  506. }
  507. std::string m_errorMessage; // Only populated if resultType is an error
  508. BasicResult( ResultBase::Type type, std::string const &message )
  509. : ResultValueBase<T>(type),
  510. m_errorMessage(message)
  511. {
  512. assert( m_type != ResultBase::Ok );
  513. }
  514. using ResultValueBase<T>::ResultValueBase;
  515. using ResultBase::m_type;
  516. };
  517. enum class ParseResultType {
  518. Matched, NoMatch, ShortCircuitAll, ShortCircuitSame
  519. };
  520. class ParseState {
  521. public:
  522. ParseState( ParseResultType type, TokenStream const &remainingTokens )
  523. : m_type(type),
  524. m_remainingTokens( remainingTokens )
  525. {}
  526. auto type() const -> ParseResultType { return m_type; }
  527. auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
  528. private:
  529. ParseResultType m_type;
  530. TokenStream m_remainingTokens;
  531. };
  532. using Result = BasicResult<void>;
  533. using ParserResult = BasicResult<ParseResultType>;
  534. using InternalParseResult = BasicResult<ParseState>;
  535. struct HelpColumns {
  536. std::string left;
  537. std::string right;
  538. };
  539. template<typename T>
  540. inline auto convertInto( std::string const &source, T& target ) -> ParserResult {
  541. std::stringstream ss;
  542. ss << source;
  543. ss >> target;
  544. if( ss.fail() )
  545. return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );
  546. else
  547. return ParserResult::ok( ParseResultType::Matched );
  548. }
  549. inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {
  550. target = source;
  551. return ParserResult::ok( ParseResultType::Matched );
  552. }
  553. inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
  554. std::string srcLC = source;
  555. std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } );
  556. if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
  557. target = true;
  558. else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
  559. target = false;
  560. else
  561. return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
  562. return ParserResult::ok( ParseResultType::Matched );
  563. }
  564. #ifdef CLARA_CONFIG_OPTIONAL_TYPE
  565. template<typename T>
  566. inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
  567. T temp;
  568. auto result = convertInto( source, temp );
  569. if( result )
  570. target = std::move(temp);
  571. return result;
  572. }
  573. #endif // CLARA_CONFIG_OPTIONAL_TYPE
  574. struct NonCopyable {
  575. NonCopyable() = default;
  576. NonCopyable( NonCopyable const & ) = delete;
  577. NonCopyable( NonCopyable && ) = delete;
  578. NonCopyable &operator=( NonCopyable const & ) = delete;
  579. NonCopyable &operator=( NonCopyable && ) = delete;
  580. };
  581. struct BoundRef : NonCopyable {
  582. virtual ~BoundRef() = default;
  583. virtual auto isContainer() const -> bool { return false; }
  584. virtual auto isFlag() const -> bool { return false; }
  585. };
  586. struct BoundValueRefBase : BoundRef {
  587. virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
  588. };
  589. struct BoundFlagRefBase : BoundRef {
  590. virtual auto setFlag( bool flag ) -> ParserResult = 0;
  591. virtual auto isFlag() const -> bool { return true; }
  592. };
  593. template<typename T>
  594. struct BoundValueRef : BoundValueRefBase {
  595. T &m_ref;
  596. explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
  597. auto setValue( std::string const &arg ) -> ParserResult override {
  598. return convertInto( arg, m_ref );
  599. }
  600. };
  601. template<typename T>
  602. struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
  603. std::vector<T> &m_ref;
  604. explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
  605. auto isContainer() const -> bool override { return true; }
  606. auto setValue( std::string const &arg ) -> ParserResult override {
  607. T temp;
  608. auto result = convertInto( arg, temp );
  609. if( result )
  610. m_ref.push_back( temp );
  611. return result;
  612. }
  613. };
  614. struct BoundFlagRef : BoundFlagRefBase {
  615. bool &m_ref;
  616. explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}
  617. auto setFlag( bool flag ) -> ParserResult override {
  618. m_ref = flag;
  619. return ParserResult::ok( ParseResultType::Matched );
  620. }
  621. };
  622. template<typename ReturnType>
  623. struct LambdaInvoker {
  624. static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" );
  625. template<typename L, typename ArgType>
  626. static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
  627. return lambda( arg );
  628. }
  629. };
  630. template<>
  631. struct LambdaInvoker<void> {
  632. template<typename L, typename ArgType>
  633. static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
  634. lambda( arg );
  635. return ParserResult::ok( ParseResultType::Matched );
  636. }
  637. };
  638. template<typename ArgType, typename L>
  639. inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
  640. ArgType temp{};
  641. auto result = convertInto( arg, temp );
  642. return !result
  643. ? result
  644. : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
  645. }
  646. template<typename L>
  647. struct BoundLambda : BoundValueRefBase {
  648. L m_lambda;
  649. static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
  650. explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}
  651. auto setValue( std::string const &arg ) -> ParserResult override {
  652. return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );
  653. }
  654. };
  655. template<typename L>
  656. struct BoundFlagLambda : BoundFlagRefBase {
  657. L m_lambda;
  658. static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
  659. static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" );
  660. explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}
  661. auto setFlag( bool flag ) -> ParserResult override {
  662. return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );
  663. }
  664. };
  665. enum class Optionality { Optional, Required };
  666. struct Parser;
  667. class ParserBase {
  668. public:
  669. virtual ~ParserBase() = default;
  670. virtual auto validate() const -> Result { return Result::ok(); }
  671. virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0;
  672. virtual auto cardinality() const -> size_t { return 1; }
  673. auto parse( Args const &args ) const -> InternalParseResult {
  674. return parse( args.exeName(), TokenStream( args ) );
  675. }
  676. };
  677. template<typename DerivedT>
  678. class ComposableParserImpl : public ParserBase {
  679. public:
  680. template<typename T>
  681. auto operator|( T const &other ) const -> Parser;
  682. template<typename T>
  683. auto operator+( T const &other ) const -> Parser;
  684. };
  685. // Common code and state for Args and Opts
  686. template<typename DerivedT>
  687. class ParserRefImpl : public ComposableParserImpl<DerivedT> {
  688. protected:
  689. Optionality m_optionality = Optionality::Optional;
  690. std::shared_ptr<BoundRef> m_ref;
  691. std::string m_hint;
  692. std::string m_description;
  693. explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
  694. public:
  695. template<typename T>
  696. ParserRefImpl( T &ref, std::string const &hint )
  697. : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
  698. m_hint( hint )
  699. {}
  700. template<typename LambdaT>
  701. ParserRefImpl( LambdaT const &ref, std::string const &hint )
  702. : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
  703. m_hint(hint)
  704. {}
  705. auto operator()( std::string const &description ) -> DerivedT & {
  706. m_description = description;
  707. return static_cast<DerivedT &>( *this );
  708. }
  709. auto optional() -> DerivedT & {
  710. m_optionality = Optionality::Optional;
  711. return static_cast<DerivedT &>( *this );
  712. };
  713. auto required() -> DerivedT & {
  714. m_optionality = Optionality::Required;
  715. return static_cast<DerivedT &>( *this );
  716. };
  717. auto isOptional() const -> bool {
  718. return m_optionality == Optionality::Optional;
  719. }
  720. auto cardinality() const -> size_t override {
  721. if( m_ref->isContainer() )
  722. return 0;
  723. else
  724. return 1;
  725. }
  726. auto hint() const -> std::string { return m_hint; }
  727. };
  728. class ExeName : public ComposableParserImpl<ExeName> {
  729. std::shared_ptr<std::string> m_name;
  730. std::shared_ptr<BoundValueRefBase> m_ref;
  731. template<typename LambdaT>
  732. static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
  733. return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
  734. }
  735. public:
  736. ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
  737. explicit ExeName( std::string &ref ) : ExeName() {
  738. m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
  739. }
  740. template<typename LambdaT>
  741. explicit ExeName( LambdaT const& lambda ) : ExeName() {
  742. m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );
  743. }
  744. // The exe name is not parsed out of the normal tokens, but is handled specially
  745. auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
  746. return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
  747. }
  748. auto name() const -> std::string { return *m_name; }
  749. auto set( std::string const& newName ) -> ParserResult {
  750. auto lastSlash = newName.find_last_of( "\\/" );
  751. auto filename = ( lastSlash == std::string::npos )
  752. ? newName
  753. : newName.substr( lastSlash+1 );
  754. *m_name = filename;
  755. if( m_ref )
  756. return m_ref->setValue( filename );
  757. else
  758. return ParserResult::ok( ParseResultType::Matched );
  759. }
  760. };
  761. class Arg : public ParserRefImpl<Arg> {
  762. public:
  763. using ParserRefImpl::ParserRefImpl;
  764. auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {
  765. auto validationResult = validate();
  766. if( !validationResult )
  767. return InternalParseResult( validationResult );
  768. auto remainingTokens = tokens;
  769. auto const &token = *remainingTokens;
  770. if( token.type != TokenType::Argument )
  771. return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
  772. assert( !m_ref->isFlag() );
  773. auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
  774. auto result = valueRef->setValue( remainingTokens->token );
  775. if( !result )
  776. return InternalParseResult( result );
  777. else
  778. return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
  779. }
  780. };
  781. inline auto normaliseOpt( std::string const &optName ) -> std::string {
  782. #ifdef CATCH_PLATFORM_WINDOWS
  783. if( optName[0] == '/' )
  784. return "-" + optName.substr( 1 );
  785. else
  786. #endif
  787. return optName;
  788. }
  789. class Opt : public ParserRefImpl<Opt> {
  790. protected:
  791. std::vector<std::string> m_optNames;
  792. public:
  793. template<typename LambdaT>
  794. explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}
  795. explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}
  796. template<typename LambdaT>
  797. Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
  798. template<typename T>
  799. Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
  800. auto operator[]( std::string const &optName ) -> Opt & {
  801. m_optNames.push_back( optName );
  802. return *this;
  803. }
  804. auto getHelpColumns() const -> std::vector<HelpColumns> {
  805. std::ostringstream oss;
  806. bool first = true;
  807. for( auto const &opt : m_optNames ) {
  808. if (first)
  809. first = false;
  810. else
  811. oss << ", ";
  812. oss << opt;
  813. }
  814. if( !m_hint.empty() )
  815. oss << " <" << m_hint << ">";
  816. return { { oss.str(), m_description } };
  817. }
  818. auto isMatch( std::string const &optToken ) const -> bool {
  819. auto normalisedToken = normaliseOpt( optToken );
  820. for( auto const &name : m_optNames ) {
  821. if( normaliseOpt( name ) == normalisedToken )
  822. return true;
  823. }
  824. return false;
  825. }
  826. using ParserBase::parse;
  827. auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
  828. auto validationResult = validate();
  829. if( !validationResult )
  830. return InternalParseResult( validationResult );
  831. auto remainingTokens = tokens;
  832. if( remainingTokens && remainingTokens->type == TokenType::Option ) {
  833. auto const &token = *remainingTokens;
  834. if( isMatch(token.token ) ) {
  835. if( m_ref->isFlag() ) {
  836. auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
  837. auto result = flagRef->setFlag( true );
  838. if( !result )
  839. return InternalParseResult( result );
  840. if( result.value() == ParseResultType::ShortCircuitAll )
  841. return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
  842. } else {
  843. auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
  844. ++remainingTokens;
  845. if( !remainingTokens )
  846. return InternalParseResult::runtimeError( "Expected argument following " + token.token );
  847. auto const &argToken = *remainingTokens;
  848. if( argToken.type != TokenType::Argument )
  849. return InternalParseResult::runtimeError( "Expected argument following " + token.token );
  850. auto result = valueRef->setValue( argToken.token );
  851. if( !result )
  852. return InternalParseResult( result );
  853. if( result.value() == ParseResultType::ShortCircuitAll )
  854. return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
  855. }
  856. return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
  857. }
  858. }
  859. return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
  860. }
  861. auto validate() const -> Result override {
  862. if( m_optNames.empty() )
  863. return Result::logicError( "No options supplied to Opt" );
  864. for( auto const &name : m_optNames ) {
  865. if( name.empty() )
  866. return Result::logicError( "Option name cannot be empty" );
  867. #ifdef CATCH_PLATFORM_WINDOWS
  868. if( name[0] != '-' && name[0] != '/' )
  869. return Result::logicError( "Option name must begin with '-' or '/'" );
  870. #else
  871. if( name[0] != '-' )
  872. return Result::logicError( "Option name must begin with '-'" );
  873. #endif
  874. }
  875. return ParserRefImpl::validate();
  876. }
  877. };
  878. struct Help : Opt {
  879. Help( bool &showHelpFlag )
  880. : Opt([&]( bool flag ) {
  881. showHelpFlag = flag;
  882. return ParserResult::ok( ParseResultType::ShortCircuitAll );
  883. })
  884. {
  885. static_cast<Opt &>( *this )
  886. ("display usage information")
  887. ["-?"]["-h"]["--help"]
  888. .optional();
  889. }
  890. };
  891. struct Parser : ParserBase {
  892. mutable ExeName m_exeName;
  893. std::vector<Opt> m_options;
  894. std::vector<Arg> m_args;
  895. auto operator|=( ExeName const &exeName ) -> Parser & {
  896. m_exeName = exeName;
  897. return *this;
  898. }
  899. auto operator|=( Arg const &arg ) -> Parser & {
  900. m_args.push_back(arg);
  901. return *this;
  902. }
  903. auto operator|=( Opt const &opt ) -> Parser & {
  904. m_options.push_back(opt);
  905. return *this;
  906. }
  907. auto operator|=( Parser const &other ) -> Parser & {
  908. m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());
  909. m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());
  910. return *this;
  911. }
  912. template<typename T>
  913. auto operator|( T const &other ) const -> Parser {
  914. return Parser( *this ) |= other;
  915. }
  916. // Forward deprecated interface with '+' instead of '|'
  917. template<typename T>
  918. auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
  919. template<typename T>
  920. auto operator+( T const &other ) const -> Parser { return operator|( other ); }
  921. auto getHelpColumns() const -> std::vector<HelpColumns> {
  922. std::vector<HelpColumns> cols;
  923. for (auto const &o : m_options) {
  924. auto childCols = o.getHelpColumns();
  925. cols.insert( cols.end(), childCols.begin(), childCols.end() );
  926. }
  927. return cols;
  928. }
  929. void writeToStream( std::ostream &os ) const {
  930. if (!m_exeName.name().empty()) {
  931. os << "usage:\n" << " " << m_exeName.name() << " ";
  932. bool required = true, first = true;
  933. for( auto const &arg : m_args ) {
  934. if (first)
  935. first = false;
  936. else
  937. os << " ";
  938. if( arg.isOptional() && required ) {
  939. os << "[";
  940. required = false;
  941. }
  942. os << "<" << arg.hint() << ">";
  943. if( arg.cardinality() == 0 )
  944. os << " ... ";
  945. }
  946. if( !required )
  947. os << "]";
  948. if( !m_options.empty() )
  949. os << " options";
  950. os << "\n\nwhere options are:" << std::endl;
  951. }
  952. auto rows = getHelpColumns();
  953. size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;
  954. size_t optWidth = 0;
  955. for( auto const &cols : rows )
  956. optWidth = (std::max)(optWidth, cols.left.size() + 2);
  957. optWidth = (std::min)(optWidth, consoleWidth/2);
  958. for( auto const &cols : rows ) {
  959. auto row =
  960. TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
  961. TextFlow::Spacer(4) +
  962. TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );
  963. os << row << std::endl;
  964. }
  965. }
  966. friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {
  967. parser.writeToStream( os );
  968. return os;
  969. }
  970. auto validate() const -> Result override {
  971. for( auto const &opt : m_options ) {
  972. auto result = opt.validate();
  973. if( !result )
  974. return result;
  975. }
  976. for( auto const &arg : m_args ) {
  977. auto result = arg.validate();
  978. if( !result )
  979. return result;
  980. }
  981. return Result::ok();
  982. }
  983. using ParserBase::parse;
  984. auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {
  985. struct ParserInfo {
  986. ParserBase const* parser = nullptr;
  987. size_t count = 0;
  988. };
  989. const size_t totalParsers = m_options.size() + m_args.size();
  990. assert( totalParsers < 512 );
  991. // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do
  992. ParserInfo parseInfos[512];
  993. {
  994. size_t i = 0;
  995. for (auto const &opt : m_options) parseInfos[i++].parser = &opt;
  996. for (auto const &arg : m_args) parseInfos[i++].parser = &arg;
  997. }
  998. m_exeName.set( exeName );
  999. auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
  1000. while( result.value().remainingTokens() ) {
  1001. bool tokenParsed = false;
  1002. for( size_t i = 0; i < totalParsers; ++i ) {
  1003. auto& parseInfo = parseInfos[i];
  1004. if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {
  1005. result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
  1006. if (!result)
  1007. return result;
  1008. if (result.value().type() != ParseResultType::NoMatch) {
  1009. tokenParsed = true;
  1010. ++parseInfo.count;
  1011. break;
  1012. }
  1013. }
  1014. }
  1015. if( result.value().type() == ParseResultType::ShortCircuitAll )
  1016. return result;
  1017. if( !tokenParsed )
  1018. return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );
  1019. }
  1020. // !TBD Check missing required options
  1021. return result;
  1022. }
  1023. };
  1024. template<typename DerivedT>
  1025. template<typename T>
  1026. auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {
  1027. return Parser() | static_cast<DerivedT const &>( *this ) | other;
  1028. }
  1029. } // namespace detail
  1030. // A Combined parser
  1031. using detail::Parser;
  1032. // A parser for options
  1033. using detail::Opt;
  1034. // A parser for arguments
  1035. using detail::Arg;
  1036. // Wrapper for argc, argv from main()
  1037. using detail::Args;
  1038. // Specifies the name of the executable
  1039. using detail::ExeName;
  1040. // Convenience wrapper for option parser that specifies the help option
  1041. using detail::Help;
  1042. // enum of result types from a parse
  1043. using detail::ParseResultType;
  1044. // Result type for parser operation
  1045. using detail::ParserResult;
  1046. }} // namespace Catch::clara
  1047. #endif // CATCH_CLARA_HPP_INCLUDED