Options.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Defines classes and functions for making classes creatable from
6 /// input files.
7 
8 #pragma once
9 
10 #include <exception>
11 #include <memory>
12 #include <ostream>
13 #include <sstream>
14 #include <string>
15 #include <utility>
16 
17 #include "ErrorHandling/Error.hpp"
18 #include "Utilities/NoSuchType.hpp"
19 
20 /// \cond
21 namespace YAML {
22 class Node;
23 } // namespace YAML
24 /// \endcond
25 
26 /// The string used in option structs
27 using OptionString = const char* const;
28 
29 /// \ingroup OptionParsingGroup
30 /// Information about the nested operations being performed by the
31 /// parser, for use in printing errors. A default-constructed
32 /// OptionContext is printed as an empty string. This struct is
33 /// primarily used as an argument to PARSE_ERROR for reporting input
34 /// file parsing errors. Users outside of the core option parsing
35 /// code should not need to manipulate the contents.
36 struct OptionContext {
37  bool top_level{true};
38  /// (Part of) the parsing "backtrace" printed with an error
40  /// File line number (0 based)
41  int line{-1};
42  /// File column number (0 based)
43  int column{-1};
44 
45  /// Append a line to the context. Automatically appends a colon.
46  void append(const std::string& c) noexcept { context += c + ":\n"; }
47 };
48 
49 inline std::ostream& operator<<(std::ostream& s,
50  const OptionContext& c) noexcept {
51  s << c.context;
52  if (c.line >= 0 and c.column >= 0) {
53  s << "At line " << c.line + 1 << " column " << c.column + 1 << ":\n";
54  }
55  return s;
56 }
57 
58 /// \ingroup OptionParsingGroup
59 /// Like ERROR("\n" << (context) << m), but instead throws an
60 /// exception that will be caught in a higher level Options if not
61 /// passed a top-level context. This is used to print a parsing
62 /// "backtrace" since we can't pass any extra data through the
63 /// yaml-cpp code.
64 ///
65 /// \param context OptionContext used to print a parsing traceback
66 /// \param m error message, as for ERROR
67 #define PARSE_ERROR(context, m) \
68  do { \
69  if ((context).top_level) { \
70  /* clang-tidy: macro arg in parentheses */ \
71  ERROR("\n" << (context) << m); /* NOLINT */ \
72  } else { \
73  std::ostringstream avoid_name_collisions_PARSE_ERROR; \
74  /* clang-tidy: macro arg in parentheses */ \
75  avoid_name_collisions_PARSE_ERROR << (context) << m; /* NOLINT */ \
76  throw Options_detail::propagate_context( \
77  avoid_name_collisions_PARSE_ERROR.str()); \
78  } \
79  } while (false)
80 
81 namespace Options_detail {
82 class propagate_context : public std::exception {
83  public:
84  // cppcheck-suppress passedByValue
85  explicit propagate_context(std::string message) noexcept
86  : message_(std::move(message)) {}
87 
88  const char* what() const noexcept override { return message_.c_str(); }
89  const std::string& message() const noexcept { return message_; }
90 
91  private:
92  std::string message_;
93 };
94 } // namespace Options_detail
95 
96 /// \ingroup OptionParsingGroup
97 /// The type that options are passed around as. Contains YAML node
98 /// data and an OptionContext.
99 ///
100 /// \note To use any methods on this class in a concrete function you
101 /// must include ParseOptions.hpp, but you do *not* need to include
102 /// that header to use this in an uninstantiated
103 /// `create_from_yaml::create` function.
104 class Option {
105  public:
106  const OptionContext& context() const noexcept;
107 
108  /// Append a line to the contained context.
109  void append_context(const std::string& context) noexcept;
110 
111  /// Convert to an object of type `T`.
112  template <typename T, typename Metavariables = NoSuchType>
113  T parse_as() const;
114 
115  /// \note This constructor overwrites the mark data in the supplied
116  /// context with the one from the node.
117  ///
118  /// \warning This method is for internal use of the option parser.
119  explicit Option(YAML::Node node, OptionContext context = {}) noexcept;
120 
121  /// \warning This method is for internal use of the option parser.
122  explicit Option(OptionContext context) noexcept;
123 
124  /// \warning This method is for internal use of the option parser.
125  const YAML::Node& node() const noexcept;
126 
127  /// Sets the node and updates the context's mark to correspond to it.
128  ///
129  /// \warning This method is for internal use of the option parser.
130  void set_node(YAML::Node node) noexcept;
131 
132  private:
134  OptionContext context_;
135 };
136 
137 /// \ingroup OptionParsingGroup
138 /// Used by the parser to create an object. The default action is to
139 /// parse options using `T::options`. This struct may be specialized
140 /// to change that behavior for specific types.
141 ///
142 /// Do not call create directly. Use Option::parse_as instead.
143 template <typename T>
145  template <typename Metavariables>
146  static T create(const Option& options);
147 };
The type that options are passed around as. Contains YAML node data and an OptionContext.
Definition: Options.hpp:104
Used by the parser to create an object. The default action is to parse options using T::options...
Definition: Options.hpp:144
constexpr auto create(Args &&... args)
Create a new DataBox.
Definition: DataBox.hpp:1259
const char *const OptionString
The string used in option structs.
Definition: Options.hpp:27
int column
File column number (0 based)
Definition: Options.hpp:43
int line
File line number (0 based)
Definition: Options.hpp:41
void append(const std::string &c) noexcept
Append a line to the context. Automatically appends a colon.
Definition: Options.hpp:46
Information about the nested operations being performed by the parser, for use in printing errors...
Definition: Options.hpp:36
Holds details of the implementation of Options.
Definition: Options.hpp:81
Definition: ParseOptions.hpp:580
std::string context
(Part of) the parsing "backtrace" printed with an error
Definition: Options.hpp:39
Defines macro ERROR.