-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Option parsing #142
Option parsing #142
Conversation
Builds are failing because yaml-cpp is too old. The latest release can't handle non-copyable types. We need something more recent than November 2016. |
Okay, I can update the container we run on Travis |
I've prepared a commit documenting the yaml-cpp version requirement, but I'll hold off pushing until it can trigger a Travis run with the update. |
src/Options/Options.hpp
Outdated
/// parser, for use in printing errors. A default-constructed | ||
/// OptionContext is printed as an empty string. This struct is | ||
/// primarily used as an argument to PARSE_ERROR for reporting input | ||
/// file parsing errors. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a brief explanation of what YAML::Mark
is used for or link to the yaml-cpp documentation? The yaml-cpp documentation is not exactly super complete or easy to navigate. If I understand correctly, YAML::Mark
used to store the line and column in the file where a parsing error occurred?
@@ -168,13 +168,13 @@ inline constexpr auto make_array_from_list() { | |||
|
|||
/// \ingroup ConstantExpressions | |||
/// \brief Compute the length of a const char* at compile time | |||
SPECTRE_ALWAYS_INLINE constexpr size_t cstring_length(const char* str) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the place that caused the error use a std::string
instead which actually supports these features?
src/Options/Options.hpp
Outdated
// See LICENSE.txt for details. | ||
|
||
/// \file | ||
/// Defined classes and functions that handle parsing of input parameters. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Defines"
src/Options/Options.hpp
Outdated
|
||
void append(const std::string& c) { context += c + ":\n"; } | ||
}; | ||
inline std::ostream& operator<<(std::ostream& s, const OptionContext& c) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blank line
src/Options/Options.hpp
Outdated
/// data and an OptionContext. | ||
class Option_t { | ||
public: | ||
Option_t() = delete; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add comment saying we don't want a default constructor
src/Options/Options.hpp
Outdated
|
||
/// NOTE: This constructor overwrites the mark data in the supplied | ||
/// context with the one from the node. | ||
Option_t(YAML::Node node, OptionContext context = OptionContext()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
explicit
src/Options/OptionsDetails.hpp
Outdated
|
||
/// Holds details of the implementation of Options | ||
namespace Options_details { | ||
template <typename S, typename U = void> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
U = void
-> = cpp17::void_t<>
src/Options/OptionsDetails.hpp
Outdated
template <typename T> | ||
void operator()(tmpl::type_<T> /*meta*/) { | ||
std::ostringstream ss; | ||
ss << " " << std::setw(max_label_size_) << std::left << T::label |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
look at setw
things
src/Options/OptionsDetails.hpp
Outdated
<< std::setw(0) << T::help << "\n\n"; | ||
value += ss.str(); | ||
} | ||
value_type value{}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blank line above
src/Options/OptionsDetails.hpp
Outdated
} | ||
} | ||
|
||
template <typename T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move to TypeTraits.hpp
tests/Unit/Options/Test_Options.cpp
Outdated
} // namespace | ||
|
||
TEST_CASE("Unit.Options.Defaulted.specified", "[Unit][Options]") { | ||
const std::string yaml = "Defaulted: 20"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inline short strings
src/Options/Factory.hpp
Outdated
/// | ||
/// To use a factory, the base class (here `BaseClass`) should inherit | ||
/// from Factory<BaseClass> and define a static method \code | ||
/// static std::string class_id() { return "BaseClass"; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could experiment with using pretty_type
to replace class_id()
src/Options/Factory.hpp
Outdated
/// from Factory<BaseClass> and define a static method \code | ||
/// static std::string class_id() { return "BaseClass"; } | ||
/// \endcode | ||
/// and a type \code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
\code
to next line
src/Options/Factory.hpp
Outdated
/// input file. | ||
/// | ||
/// To use a factory, the base class (here `BaseClass`) should inherit | ||
/// from Factory<BaseClass> and define a static method \code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
\code
on next line
src/Options/Factory.hpp
Outdated
/// class method shown above. | ||
/// 2) define static OptionString_t help containing class-specfic help | ||
/// text | ||
/// 3) define a type options as a typelist of option structs required |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
define a type alias options
src/Options/Factory.hpp
Outdated
static std::string help_derived(); | ||
|
||
template < | ||
typename CreateLs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CreateLs
to CreateList
src/Options/Factory.hpp
Outdated
}; | ||
|
||
template <typename BaseClass> | ||
template <typename CreateLs, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CreateLs
src/Options/Factory.hpp
Outdated
derived_opts.Context().append("While creating type " + id); | ||
auto derived = | ||
create_derived<typename BaseClass::creatable_classes>(id, derived_opts); | ||
if (derived) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
derived != nullptr
for clarity
src/Options/Factory.hpp
Outdated
<< std::setw(name_col) << "" | ||
<< std::setw(help_col - name_col - 1) << T::class_id(); | ||
if (ss.str().size() >= help_col) { | ||
ss << std::setw(0) << "\n" << std::setw(help_col - 1) << ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need to setw(0)
src/Options/Factory.hpp
Outdated
return true; | ||
} | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// namespace YAML
tests/Unit/Options/Test_Factory.cpp
Outdated
std::string arg_; | ||
}; | ||
|
||
struct OptionsVecArg { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clean up
src/Options/Options.hpp
Outdated
static_assert(cpp17::is_same_v<decltype(T::lower_bound()), typename T::type>, | ||
"Lower bound is not of the same type as the option."); | ||
static_assert(not cpp17::is_same_v<typename T::type, bool>, | ||
"Cannot set an lower bound for a bool."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an -> a
The new commits fall into a few groups:
There was discussion of adding support for giving the option parser a small set of values allowed for an option. There is currently support for adding parsability to an enum (see example on MCFY) and for providing parsing errors from factory class constructors. The only additional feature that I think the parser could add would be displaying options in the help text, but we're trying to keep that short so I'm kind of leery of printing arbitrary lists of values there. |
And looks like yaml-cpp is broken on the clang Travis setups. |
Trying to clean up the doxygen warnings, I've hit two issues:
|
src/Options/Options.hpp
Outdated
context_.mark = node_.Mark(); | ||
} | ||
|
||
/// Convert to an object ot type `T`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ot -> of
src/Options/Options.hpp
Outdated
for (auto it = options.begin(); it != options.end(); ++it) { | ||
const auto key = it->first.as<std::string>(); | ||
const auto value = it->second; | ||
for (const auto& kv : node) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while I've used kv for the range-based key-value pair, others ( @gsb76 , @osheamonn ) have voiced other opinions
src/Utilities/PrettyType.hpp
Outdated
* \brief Extract the "base name" from a name, that is, the name | ||
* without template parameters or scopes. | ||
*/ | ||
std::string extract_base_name(std::string name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot think of an alternative at the moment, but when I first saw base_name I thought about the name of a base class...
src/Options/Factory.hpp
Outdated
/// returns a unique id for the derived class, similar to the base | ||
/// class method shown above. | ||
/// 2) define static OptionString_t help containing class-specfic help | ||
/// 1) define static OptionString_t help containing class-specfic help |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doxygen does have a syntax for enumerated list (having to relabel the comments made me think of this...)
/// the `options` and an OptionContext. | ||
/// A class to be created must be default constructible and move | ||
/// assignable. If create_from_yaml is not specialized for the class | ||
/// it must additionally declare a tnpl::list of Options-style option |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tnpl -> tmpl
Speculation on the Travis yaml-cpp problem: using a libstdc++-linked yaml-cpp for a libc++ build. |
Yes, that is what it is. |
src/Options/Options.hpp
Outdated
/// Parse an Option_t to obtain options and their values. | ||
void parse(const Option_t& options); | ||
|
||
/// Parse an file containing options |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parse a
src/Options/Options.hpp
Outdated
//@} | ||
|
||
//@{ | ||
/// Check for an iterable type that the size is above the upper bound |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
above -> below
src/Options/Options.hpp
Outdated
/// If the options has a lower bound, check it is satisfied. | ||
/// | ||
/// Note: Lower bounds are >=, not just >. | ||
/// \tparam T the option "type" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"type" -> something clearer
src/Options/Options.hpp
Outdated
/// If the options has a upper bound, check it is satisfied. | ||
/// | ||
/// Note: Upper bounds are <=, not just <. | ||
/// \tparam T the option "type" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
src/Options/Options.hpp
Outdated
|
||
// \cond | ||
// Doxygen is confused by decltype(auto) | ||
template <typename OptionsList> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OptionsList -> OptionList
}; | ||
/// [options_example_scalar_struct] | ||
} // namespace | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test that a out-of-bounds default fails
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
squash
src/Options/Options.hpp
Outdated
@@ -232,7 +232,10 @@ class Options { | |||
void parse(const YAML::Node& node); | |||
|
|||
//@{ | |||
/// Check for an iterable type that the size is above the lower bound | |||
/// Check for an that the size is not smaller than the lower bound |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check that the....
src/Options/Options.hpp
Outdated
@@ -247,7 +250,10 @@ class Options { | |||
//@} | |||
|
|||
//@{ | |||
/// Check for an iterable type that the size is below the upper bound | |||
/// Check for an that the size is not larger than the upper bound |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again
src/Options/Options.hpp
Outdated
@@ -263,6 +269,8 @@ class Options { | |||
|
|||
//@{ | |||
/// Returns the default value or errors if there is no default. | |||
/// | |||
/// \tparam T the option struct | |||
template <typename T, | |||
std::enable_if_t<Options_details::has_default<T>::value>* = nullptr> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change all to Requires<...> = nullptr
Will, can you rebase on the latest commit that attempted to fix Travis stuff |
I'll look at what the heck Travis is doing |
Could you rebase to get the new Travis things that uses libstdc++ with Clang? |
@wthrowe could you try applying the changes in this commit nilsdeppe@0dfcc15 ? |
Codecov Report
@@ Coverage Diff @@
## develop #142 +/- ##
===========================================
- Coverage 98.93% 98.59% -0.35%
===========================================
Files 110 115 +5
Lines 3766 4047 +281
===========================================
+ Hits 3726 3990 +264
- Misses 40 57 +17
Continue to review full report at Codecov.
|
I have made many changes from the original code. Some of the highlights:
MAKE_CREATABLE_FROM_YAML
macro for non-factory stuff as discussed elsewhere.MAKE_CREATABLE_FROM_YAML
to allow parsing simple types without using full option parsing (e.g., parsing an old-style Point class asCenter: [1, 2, 3]
or an enum asNorm: L2
).OptionContext
parameter that can be passed to thePARSE_ERROR
macro to include information about the input file location in an error message (generally for doing more complex checks on input values).OptionsList
in factory/MCFY classes has been renamed tooptions
because it should be camel case and it isn't a list in MCFY forwarding.I've put some examples of parsing error output at http://astro.cornell.edu/~wthrowe/parsing_errors (executable at http://astro.cornell.edu/~wthrowe/parsing_errors.cpp).