19#include "libmesh/parallel.h"
20#include "libmesh/fparser.hh"
31 std::string func_text;
34 auto n_errs = exp.errors.size();
38 fp.AddConstant(
"e", std::exp(Real(1)));
39 std::vector<std::string> var_names;
40 auto ret = fp.ParseAndDeduceVariables(func_text, var_names);
43 exp.errors.emplace_back(
44 "fparse error: " + std::string(fp.ErrorMsg()) +
" in '" + n->fullpath() +
"'", n);
48 std::vector<double> var_vals;
49 for (
auto & var : var_names)
53 while ((curr = curr->parent()))
55 auto src = curr->find(var);
56 if (src && src != n && src->type() == hit::NodeType::Field)
58 exp.used.push_back(hit::pathJoin({curr->fullpath(), var}));
59 var_vals.push_back(curr->param<
double>(var));
65 exp.errors.emplace_back(
"no variable '" + var +
66 "' found for use in function parser expression in '" +
71 if (exp.errors.size() != n_errs)
75 ss << std::setprecision(17) << fp.Eval(var_vals.data());
78 n->setVal(n->val(), hit::Field::Kind::Float);
84 const std::list<std::string> & args,
85 hit::BraceExpander & exp)
87 std::vector<std::string> argv;
88 argv.insert(argv.begin(), args.begin(), args.end());
93 n->setVal(n->val(), hit::Field::Kind::Float);
98 if (argv.size() != 4 || (argv.size() >= 3 && argv[2] !=
"->"))
100 exp.errors.emplace_back(
"units error: Expected 4 arguments ${units number from_unit -> "
101 "to_unit} or 2 arguments ${units number unit} in '" +
110 if (!from_unit.conformsTo(to_unit))
112 std::ostringstream err;
113 err <<
"units error: " << argv[1] <<
" (" << from_unit <<
") does not convert to " << argv[3]
114 <<
" (" << to_unit <<
") in '" << n->fullpath() <<
"'";
115 exp.errors.emplace_back(err.str(), n);
120 Real num = MooseUtils::convert<Real>(argv[0]);
123 std::stringstream ss;
124 ss << std::setprecision(17) << to_unit.convert(num, from_unit);
139 n->setVal(n->val(), hit::Field::Kind::Float);
146 std::vector<std::string> argv;
147 argv.insert(argv.begin(), args.begin(), args.end());
149 if (argv.size() != 3)
151 exp.errors.emplace_back(
152 "enumerate error: Expected 3 arguments ${enumerate prefix first_index last_index} in '" +
158 const auto & prefix = argv[0];
159 std::array<int, 2> index;
160 for (
const auto i : make_range(2))
162 const auto & arg = argv[i + 1];
163 if (arg.empty() || arg.find_first_not_of(
"0123456789") != std::string::npos)
165 exp.errors.emplace_back(
"enumerate error: index '" + arg +
166 "' is not a non-negative integer in '" + n->fullpath() +
"'",
170 index[i] = MooseUtils::convert<int>(arg);
173 if (index[1] < index[0])
175 exp.errors.emplace_back(
"enumerate error: last index " + argv[2] +
176 " is smaller than first index " + argv[1] +
" in '" +
182 std::vector<std::string> names;
183 for (
const auto i : make_range(index[0], index[1] + 1))
184 names.push_back(prefix + std::to_string(i));
192 std::vector<std::string> argv;
193 argv.insert(argv.begin(), args.begin(), args.end());
195 if (argv.size() < 2 || argv.size() > 3)
197 exp.errors.emplace_back(
"range error: Expected either 2 arguments '${range start stop}' "
198 "or 3 arguments '${range start stop step}' in '" +
204 std::array<int, 3> int_args;
205 for (
const auto i : make_range(argv.size()))
207 bool success =
false;
208 if (!argv[i].empty())
213 exp.errors.emplace_back(
"range error: parameter '" + argv[i] +
"' is not an integer in '" +
219 if (argv.size() == 2)
222 if (int_args[2] == 0)
224 exp.errors.emplace_back(
"range error: step is zero in '" + n->fullpath() +
"'", n);
228 std::vector<std::string> names;
231 if (int_args[1] < int_args[0])
233 exp.errors.emplace_back(
"range error: end point '" + argv[1] +
234 "' is smaller than the start point '" + argv[0] +
235 "' when the step is positive in '" + n->fullpath() +
"'",
240 for (
int i = int_args[0]; i < int_args[1]; i += int_args[2])
241 names.push_back(std::to_string(i));
245 if (int_args[0] < int_args[1])
247 exp.errors.emplace_back(
"range error: start point '" + argv[0] +
248 "' is smaller than the end point '" + argv[1] +
249 "' when the step is negative in '" + n->fullpath() +
"'",
254 for (
int i = int_args[0]; i > int_args[1]; i += int_args[2])
255 names.push_back(std::to_string(i));
264 std::vector<std::string> argv;
265 argv.insert(argv.begin(), args.begin(), args.end());
267 if (argv.size() != 2)
269 exp.errors.emplace_back(
270 "repeat error: Expected 2 arguments ${repeat name count} in '" + n->fullpath() +
"'", n);
274 const auto & count_arg = argv[1];
275 if (count_arg.empty() || count_arg.find_first_not_of(
"0123456789") != std::string::npos)
277 exp.errors.emplace_back(
"repeat error: count '" + count_arg +
278 "' is not a non-negative integer in '" + n->fullpath() +
"'",
283 const std::vector<std::string>
values(MooseUtils::convert<int>(count_arg), argv[0]);
288 const std::optional<std::vector<std::string>> & input_text )
290 _input_filenames(input_filenames),
291 _input_text(input_text ? *input_text :
std::vector<
std::string>()),
293 _throw_on_error(false)
296 mooseError(
"Parser: Input text not the same length as input filenames");
300 const std::optional<std::string> & input_text )
302 input_text ? std::optional<std::vector<std::string>>({*input_text})
303 :
std::optional<
std::vector<
std::string>>())
310 const auto it =
_have.try_emplace(fullpath, n);
313 const std::string type = n->type() == hit::NodeType::Field ?
"parameter" :
"section";
314 const std::string error = type +
" '" + fullpath +
"' supplied multiple times";
317 const auto existing = it.first->second;
318 if (std::find_if(
errors.begin(),
320 [&existing](
const auto & err)
321 { return err.node == existing; }) ==
errors.end())
322 errors.emplace_back(error, existing);
324 errors.emplace_back(error, n);
330 const std::string & ,
333 if (n->type() == hit::NodeType::Field)
339 const std::string & ,
342 const auto it =
_map.find(fullpath);
343 if (it !=
_map.end())
347 "' overrides the same parameter in ",
348 it->second->filename(),
350 it->second->line()));
354BadActiveWalker ::walk(
const std::string & fullpath,
355 const std::string & ,
358 auto actives = section->find(
"active");
359 auto inactives = section->find(
"inactive");
361 if (actives && inactives && actives->type() == hit::NodeType::Field &&
362 inactives->type() == hit::NodeType::Field && actives->parent() == inactives->parent())
365 "'active' and 'inactive' parameters both provided in section '" + fullpath +
"'", section);
370 if (actives && actives->type() == hit::NodeType::Field && actives->parent() == section)
372 auto vars = section->param<std::vector<std::string>>(
"active");
373 std::string msg =
"";
374 for (
auto & var :
vars)
376 if (!section->find(var))
381 msg = msg.substr(0, msg.size() - 2);
382 errors.emplace_back(
"variables listed as active (" + msg +
") in section '" +
383 section->fullpath() +
"' not found in input",
388 if (inactives && inactives->type() == hit::NodeType::Field && inactives->parent() == section)
390 auto vars = section->param<std::vector<std::string>>(
"inactive");
391 std::string msg =
"";
392 for (
auto & var :
vars)
394 if (!section->find(var))
399 msg = msg.substr(0, msg.size() - 2);
400 errors.emplace_back(
"variables listed as inactive (" + msg +
") in section '" +
401 section->fullpath() +
"' not found in input",
411 walk(
const std::string & ,
const std::string & , hit::Node * n)
override
413 if (n && n->type() == hit::NodeType::Field && n->fullpath() ==
"Application/type")
433 mooseError(
"Parser::getLastInputFileName(): No inputs are set");
451 const std::string use_rel_paths_str =
452 std::getenv(
"MOOSE_RELATIVE_FILEPATHS") ? std::getenv(
"MOOSE_RELATIVE_FILEPATHS") :
"false";
453 const auto use_real_paths = use_rel_paths_str ==
"0" || use_rel_paths_str ==
"false";
454 std::vector<std::string> filenames;
460 for (
const auto & filename : filenames)
463 std::ifstream f(filename);
465 std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>()));
474 std::vector<hit::ErrorMessage> dw_errors;
478 const auto & filename = filenames[i];
485 std::vector<hit::ErrorMessage> syntax_errors;
486 std::unique_ptr<hit::Node> root(hit::parse(filename, input, &syntax_errors));
489 root->
walk(&dw, hit::NodeType::Field);
493 _root = std::move(root);
496 root->walk(&opw, hit::NodeType::Field);
497 hit::merge(root.get(), &
getRoot());
500 if (!syntax_errors.empty())
503 getRoot().walk(&cpw, hit::NodeType::Field);
505 catch (hit::Error & err)
518 _root.reset(hit::parse(
"EMPTY",
""));
535 if (dw_errors.size())
539 const auto joined_params =
543 _cli_root.reset(hit::parse(
"CLI_ARGS", joined_params));
546 catch (hit::Error & err)
551 std::vector<hit::ErrorMessage> errors;
559 hit::ReplaceEvaler repl;
565 hit::BraceExpander exw;
566 exw.registerEvaler(
"raw", raw);
567 exw.registerEvaler(
"env", env);
568 exw.registerEvaler(
"fparse", fparse_ev);
569 exw.registerEvaler(
"replace", repl);
570 exw.registerEvaler(
"units", units_ev);
571 exw.registerEvaler(
"enumerate", enumerate_ev);
572 exw.registerEvaler(
"range", range_ev);
573 exw.registerEvaler(
"repeat", repeat_ev);
575 for (
auto & var : exw.used)
602 mooseError(
"Parser::getRoot(): root is not set");
610 mooseError(
"Parser::getCommandLineRoot(): command line root is not set");
617 return const_cast<hit::Node &
>(std::as_const(*this).getCommandLineRoot());
622 const std::vector<hit::ErrorMessage> & from)
624 to.insert(to.end(), from.begin(), from.end());
636 std::vector<std::string>
values;
637 for (
const auto & em : error_messages)
638 values.push_back(em.prefixed_message);
660 for (
auto & em : messages)
663 em = hit::ErrorMessage(em.message,
"CLI_ARGS");
void mooseInfoRepeated(Args &&... args)
Emit an informational message with the given stringified, concatenated args.
void mooseInfo(Args &&... args)
Emit an informational message with the given stringified, concatenated args.
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
std::array< Real, 2 > values
std::vector< hit::ErrorMessage > errors
virtual void walk(const std::string &, const std::string &, hit::Node *section) override
std::map< std::string, hit::Node * > ParamMap
virtual void walk(const std::string &fullpath, const std::string &, hit::Node *n) override
std::map< std::string, hit::Node * > _have
virtual void walk(const std::string &fullpath, const std::string &, hit::Node *n) override
std::vector< hit::ErrorMessage > errors
virtual std::string eval(hit::Field *n, const std::list< std::string > &args, hit::BraceExpander &exp)
std::optional< std::string > _app_type
const std::optional< std::string > & getApp()
void walk(const std::string &, const std::string &, hit::Node *n) override
virtual std::string eval(hit::Field *n, const std::list< std::string > &args, hit::BraceExpander &exp)
Physical unit management class with runtime unit string parsing, unit checking, unit conversion,...
const CompileParamWalker::ParamMap & _map
std::vector< std::string > warnings
void walk(const std::string &fullpath, const std::string &, hit::Node *n) override
Class for parsing input files.
std::set< std::string > _extracted_vars
Variables that have been extracted during brace expansion.
static void appendErrorMessages(std::vector< hit::ErrorMessage > &to, const std::vector< hit::ErrorMessage > &from)
Helper for accumulating errors from a walker into an accumulation of errors.
const std::string & getLastInputFileName() const
void setAppType(const std::string &app_type)
const hit::Node & getCommandLineRoot() const
const hit::Node * queryRoot() const
void setCommandLineParams(const std::vector< std::string > ¶ms)
Sets the HIT parameters from the command line.
const std::vector< std::string > & getInputText() const
std::vector< std::string > _input_text
The input text (may be filled during parse())
const std::vector< std::string > & getInputFileNames() const
const std::vector< std::string > _input_filenames
The input file names.
std::optional< std::vector< std::string > > _command_line_params
The command line HIT parameters (if any)
std::unique_ptr< hit::Node > _cli_root
The root node for command line hit arguments.
std::unique_ptr< hit::Node > _root
The root node, which owns the whole tree.
void parseError(std::vector< hit::ErrorMessage > messages) const
Helper for throwing an error with the given messages.
bool _throw_on_error
Whether or not to throw on error.
const hit::Node * queryCommandLineRoot() const
void parse()
Parses the inputs.
Parser(const std::vector< std::string > &input_filenames, const std::optional< std::vector< std::string > > &input_text={})
Constructor given a list of input files, given in input_filenames.
static std::string joinErrorMessages(const std::vector< hit::ErrorMessage > &error_messages)
Helper for combining error messages into a single, newline separated message.
virtual std::string eval(hit::Field *n, const std::list< std::string > &args, hit::BraceExpander &exp)
virtual std::string eval(hit::Field *n, const std::list< std::string > &args, hit::BraceExpander &exp)
virtual std::string eval(hit::Field *n, const std::list< std::string > &args, hit::BraceExpander &exp)
bool convert(const std::string &str, T &value, const bool throw_on_failure)
Takes the string representation of a value and converts it to the value.
std::string realpath(const std::string &path)
std::string stringJoin(const std::vector< std::string > &values, const std::string &separator=" ")
Concatenates value into a single string separated by separator.
bool checkFileReadable(const std::string &filename, bool check_line_endings, bool throw_on_unreadable, bool check_for_git_lfs_pointer)
std::string stringify(const T &t)
conversion to string