Updated version of Clara (should fix Windows compile issues)

- embedded using new embed script
This commit is contained in:
Phil Nash 2017-06-20 18:03:37 +01:00
parent ee0defb939
commit da5964af78
5 changed files with 1376 additions and 42 deletions

View File

@ -4,23 +4,40 @@
#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
#define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80
#endif
// ----------- #included from clara_textflow.hpp -----------
// TextFlowCpp
//
// A single-header library for wrapping and laying out basic text, by Phil Nash
//
// This work is licensed under the BSD 2-Clause license.
// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause
//
// This project is hosted at https://github.com/philsquared/textflowcpp
#ifndef CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
#define CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
#include <cassert> #include <cassert>
#include <ostream> #include <ostream>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include <memory>
#include <set>
#include <algorithm>
#ifndef CLARA_CONFIG_CONSOLE_WIDTH #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
#define CLARA_CONFIG_CONSOLE_WIDTH 80 #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
#endif #endif
namespace Catch {
namespace clara {
// Included from TextFlow.hpp namespace Catch { namespace clara { namespace TextFlow
namespace TextFlow { {
inline auto isWhitespace( char c ) -> bool { inline auto isWhitespace( char c ) -> bool {
static std::string chars = " \t\n\r"; static std::string chars = " \t\n\r";
@ -39,7 +56,7 @@ namespace TextFlow {
class Column { class Column {
std::vector<std::string> m_strings; std::vector<std::string> m_strings;
size_t m_width = CLARA_CONFIG_CONSOLE_WIDTH; size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
size_t m_indent = 0; size_t m_indent = 0;
size_t m_initialIndent = std::string::npos; size_t m_initialIndent = std::string::npos;
@ -51,7 +68,7 @@ namespace TextFlow {
size_t m_stringIndex = 0; size_t m_stringIndex = 0;
size_t m_pos = 0; size_t m_pos = 0;
size_t m_len; size_t m_len = 0;
bool m_suffix = false; bool m_suffix = false;
iterator( Column const& column, size_t stringIndex ) iterator( Column const& column, size_t stringIndex )
@ -171,7 +188,7 @@ namespace TextFlow {
auto width() const -> size_t { return m_width; } auto width() const -> size_t { return m_width; }
auto begin() const -> iterator { return iterator( *this ); } auto begin() const -> iterator { return iterator( *this ); }
auto end() const -> iterator { return iterator( *this, m_strings.size() ); } auto end() const -> iterator { return { *this, m_strings.size() }; }
inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) {
bool first = true; bool first = true;
@ -197,7 +214,7 @@ namespace TextFlow {
class Spacer : public Column { class Spacer : public Column {
public: public:
Spacer( size_t spaceWidth ) : Column( "" ) { explicit Spacer( size_t spaceWidth ) : Column( "" ) {
width( spaceWidth ); width( spaceWidth );
} }
}; };
@ -226,7 +243,7 @@ namespace TextFlow {
} }
public: public:
iterator( Columns const& columns ) explicit iterator( Columns const& columns )
: m_columns( columns.m_columns ), : m_columns( columns.m_columns ),
m_activeIterators( m_columns.size() ) m_activeIterators( m_columns.size() )
{ {
@ -277,7 +294,7 @@ namespace TextFlow {
using const_iterator = iterator; using const_iterator = iterator;
auto begin() const -> iterator { return iterator( *this ); } auto begin() const -> iterator { return iterator( *this ); }
auto end() const -> iterator { return iterator( *this, iterator::EndTag() ); } auto end() const -> iterator { return { *this, iterator::EndTag() }; }
auto operator += ( Column const& col ) -> Columns& { auto operator += ( Column const& col ) -> Columns& {
m_columns.push_back( col ); m_columns.push_back( col );
@ -315,9 +332,19 @@ namespace TextFlow {
cols += other; cols += other;
return cols; return cols;
} }
}}} // namespace Catch::clara::TextFlow
} // namespace TextFlow #endif // CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
// ----------- end of #include from clara_textflow.hpp -----------
// ........... back in clara.hpp
#include <memory>
#include <set>
#include <algorithm>
namespace Catch { namespace clara {
namespace detail { 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)
@ -475,8 +502,7 @@ namespace detail {
new(&m_value) T(other.m_value); new(&m_value) T(other.m_value);
} }
ResultValueBase(Type type, T const &value) ResultValueBase(Type, T const &value) : ResultBase(Ok) {
: ResultBase(Ok) {
new(&m_value) T(value); new(&m_value) T(value);
} }
@ -600,10 +626,9 @@ namespace detail {
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(), ::tolower); 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")
@ -941,10 +966,10 @@ 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&, TokenStream const &tokens ) const -> InternalParseResult override {
auto result = validate(); auto validationResult = validate();
if (!result) if (!validationResult)
return InternalParseResult(result); return InternalParseResult(validationResult);
auto remainingTokens = tokens; auto remainingTokens = tokens;
if (remainingTokens && remainingTokens->type == TokenType::Option) { if (remainingTokens && remainingTokens->type == TokenType::Option) {
@ -1069,6 +1094,7 @@ namespace detail {
} }
auto rows = getHelpColumns(); auto rows = getHelpColumns();
size_t consoleWidth = CATCH_CLARA_TEXTFLOW_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);
@ -1077,7 +1103,7 @@ namespace detail {
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(73 - optWidth); TextFlow::Column(cols.right).width(consoleWidth - 7 - optWidth);
os << row << std::endl; os << row << std::endl;
} }
} }
@ -1131,7 +1157,7 @@ namespace detail {
auto result = InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens)); auto result = InternalParseResult::ok(ParseState(ParseResultType::NoMatch, tokens));
while (result.value().remainingTokens()) { while (result.value().remainingTokens()) {
int remainingTokenCount = result.value().remainingTokens().count(); auto remainingTokenCount = result.value().remainingTokens().count();
for (auto parser : allParsers) { for (auto parser : allParsers) {
result = parser->parse( exeName, result.value().remainingTokens() ); result = parser->parse( exeName, result.value().remainingTokens() );
if (!result || result.value().type() != ParseResultType::NoMatch) { if (!result || result.value().type() != ParseResultType::NoMatch) {
@ -1183,7 +1209,7 @@ using detail::ParseResultType;
using detail::ParserResult; using detail::ParserResult;
} // namespace clara }} // namespace Catch::clara
} // namespace Catch
#endif // CATCH_CLARA_HPP_INCLUDED #endif // CATCH_CLARA_HPP_INCLUDED

View File

@ -11,10 +11,10 @@
// Use Catch's value for console width (store Clara's off to the side, if present) // Use Catch's value for console width (store Clara's off to the side, if present)
#ifdef CLARA_CONFIG_CONSOLE_WIDTH #ifdef CLARA_CONFIG_CONSOLE_WIDTH
#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
#undef CLARA_CONFIG_CONSOLE_WIDTH #undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
#endif #endif
#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
#include "../external/clara.hpp" #include "../external/clara.hpp"
@ -22,7 +22,7 @@
// Restore Clara's value for console width, if present // Restore Clara's value for console width, if present
#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
#endif #endif

73
scripts/embed.py Normal file
View File

@ -0,0 +1,73 @@
import re
preprocessorRe = re.compile( r'\s*#.*' )
fdefineRe = re.compile( r'\s*#\s*define\s*(\S*)\s*\(' ) # #defines that take arguments
defineRe = re.compile( r'\s*#\s*define\s*(\S*)(\s+)(.*)' ) # all #defines
undefRe = re.compile( r'\s*#\s*undef\s*(\S*)' ) # all #undefs
ifdefCommonRe = re.compile( r'\s*#\s*if' ) # all #ifdefs
ifdefRe = re.compile( r'\s*#\s*ifdef\s*(\S*)' )
ifndefRe = re.compile( r'\s*#\s*ifndef\s*(\S*)' )
endifRe = re.compile( r'\s*#\s*endif\s*//\s*(.*)' )
elseRe = re.compile( r'\s*#\s*else' )
ifRe = re.compile( r'\s*#\s*if\s+(.*)' )
nsRe = re.compile( r'(.*?\s*\s*namespace\s+)(\w+)(\s*{?)(.*)' )
nsCloseRe = re.compile( r'(.*\s*})(\s*\/\/\s*namespace\s+)(\w+)(\s*)(.*)' )
class LineMapper:
def __init__( self, idMap, outerNamespace ):
self.idMap = idMap
self.outerNamespace = outerNamespace
def replaceId( self, lineNo, id ):
if not self.idMap.has_key( id ):
raise ValueError( "Unrecognised macro identifier: '{0}' on line: {1}".format( id, lineNo ) )
subst = self.idMap[id]
if subst == "":
return id
else:
return subst
# TBD:
# #if, #ifdef, comments after #else
def mapLine( self, lineNo, line ):
m = ifndefRe.match( line )
if m:
return "#ifndef " + self.replaceId( lineNo, m.group(1)) + "\n"
m = defineRe.match( line )
if m:
return "#define {0}{1}{2}\n".format( self.replaceId( lineNo, m.group(1)), m.group(2), m.group(3) )
m = endifRe.match( line )
if m:
return "#endif // " + self.replaceId( lineNo, m.group(1)) + "\n"
m = nsCloseRe.match( line )
if m:
originalNs = m.group(3)
# print("[{0}] originalNs: '{1}' - closing".format(lineNo, originalNs))
# print( " " + line )
# print( " 1:[{0}]\n 2:[{1}]\n 3:[{2}]\n 4:[{3}]\n 5:[{4}]".format( m.group(1), m.group(2), m.group(3), m.group(4), m.group(5) ) )
if self.outerNamespace.has_key(originalNs):
outerNs, innerNs = self.outerNamespace[originalNs]
return "{0}}}{1}{2}::{3}{4}{5}\n".format( m.group(1), m.group(2), outerNs, innerNs, m.group(4), m.group(5))
m = nsRe.match( line )
if m:
originalNs = m.group(2)
# print("[{0}] originalNs: '{1}'".format(lineNo, originalNs))
# print( " " + line )
# print( " 1:[{0}]\n 2:[{1}]\n 3:[{2}]\n 4:[{3}]".format( m.group(1), m.group(2), m.group(3), m.group(4) ) )
if self.outerNamespace.has_key(originalNs):
outerNs, innerNs = self.outerNamespace[originalNs]
return "{0}{1} {{ namespace {2}{3}{4}\n".format( m.group(1), outerNs, innerNs, m.group(3), m.group(4) )
return line
def mapFile(self, filenameIn, filenameOut ):
print( "Embedding:\n {0}\nas:\n {1}".format( filenameIn, filenameOut ) )
with open( filenameIn, 'r' ) as f, open( filenameOut, 'w' ) as outf:
lineNo = 1
for line in f:
outf.write( self.mapLine( lineNo, line ) )
lineNo = lineNo + 1
print( "Written {0} lines".format( lineNo ) )

24
scripts/embedClara.py Normal file
View File

@ -0,0 +1,24 @@
# Execute this script any time you import a new copy of Clara into the third_party area
import os
import sys
import embed
rootPath = os.path.dirname(os.path.realpath( os.path.dirname(sys.argv[0])))
filename = os.path.join( rootPath, "third_party", "clara.hpp" )
outfilename = os.path.join( rootPath, "include", "external", "clara.hpp" )
# Mapping of pre-processor identifiers
idMap = {
"CLARA_HPP_INCLUDED": "CATCH_CLARA_HPP_INCLUDED",
"CLARA_CONFIG_CONSOLE_WIDTH": "CATCH_CLARA_CONFIG_CONSOLE_WIDTH",
"CLARA_TEXTFLOW_HPP_INCLUDED": "CATCH_CLARA_TEXTFLOW_HPP_INCLUDED",
"CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH": "CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH"
}
# outer namespace to add
outerNamespace = { "clara": ("Catch", "clara") }
mapper = embed.LineMapper( idMap, outerNamespace )
mapper.mapFile( filename, outfilename )

1211
third_party/clara.hpp vendored Normal file

File diff suppressed because it is too large Load Diff