Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #include "JsonSyntaxTree.h"
11 :
12 : // MOOSE includes
13 : #include "MooseEnum.h"
14 : #include "MultiMooseEnum.h"
15 : #include "ExecFlagEnum.h"
16 : #include "Builder.h"
17 : #include "pcrecpp.h"
18 : #include "Action.h"
19 : #include "AppFactory.h"
20 : #include "Registry.h"
21 : #include "MooseUtils.h"
22 :
23 : #include "libmesh/vector_value.h"
24 :
25 : // C++ includes
26 : #include <algorithm>
27 : #include <cctype>
28 :
29 183 : JsonSyntaxTree::JsonSyntaxTree(const std::string & search_string) : _search(search_string)
30 : {
31 : // Registry holds a map with labels (ie MooseApp) as keys and a vector of RegistryEntry
32 : // as values. We need the reverse map: given an action or object name then get the label.
33 183 : auto & actmap = Registry::allActions();
34 549 : for (auto & entry : actmap)
35 38787 : for (auto & act : entry.second)
36 38421 : _action_label_map[act->_classname] = std::make_pair(entry.first, act->_file);
37 :
38 183 : auto & objmap = Registry::allObjects();
39 549 : for (auto & entry : objmap)
40 276813 : for (auto & obj : entry.second)
41 276447 : _object_label_map[obj->name()] = std::make_pair(entry.first, obj->_file);
42 183 : }
43 :
44 : std::vector<std::string>
45 1164668 : JsonSyntaxTree::splitPath(const std::string & path)
46 : {
47 1164668 : std::string s;
48 1164668 : std::istringstream f(path);
49 1164668 : std::vector<std::string> paths;
50 4963514 : while (std::getline(f, s, '/'))
51 2634178 : if (s.size() > 0)
52 2634178 : paths.push_back(s);
53 2329336 : return paths;
54 1164668 : }
55 :
56 : nlohmann::json &
57 424126 : JsonSyntaxTree::getJson(const std::string & path)
58 : {
59 424126 : auto paths = splitPath(path);
60 : mooseAssert(paths.size() > 0, "path is empty");
61 424126 : auto * next = &(_root["blocks"][paths[0]]);
62 :
63 887224 : for (auto pit = paths.begin() + 1; pit != paths.end(); ++pit)
64 : {
65 463098 : if (*pit == "*")
66 : // It has an action syntax as a parent
67 392942 : next = &(*next)["star"];
68 70156 : else if (*pit == "<type>")
69 0 : next = &(*next)["types"];
70 : else
71 70156 : next = &(*next)["subblocks"][*pit];
72 : }
73 424126 : return *next;
74 424126 : }
75 :
76 : nlohmann::json &
77 419836 : JsonSyntaxTree::getJson(const std::string & parent, const std::string & path, bool is_type)
78 : {
79 419836 : if (parent.empty())
80 : {
81 49400 : auto & j = getJson(path);
82 49400 : if (path.back() == '*' && !j.contains("subblock_types"))
83 10812 : j["subblock_types"] = nlohmann::json();
84 38588 : else if (path.back() != '*' && !j.contains("types"))
85 5824 : j["types"] = nlohmann::json();
86 49400 : return j["actions"];
87 : }
88 :
89 370436 : auto & parent_json = getJson(parent);
90 370436 : auto paths = splitPath(path);
91 370436 : std::string key = "subblock_types";
92 370436 : if (is_type)
93 47856 : key = "types";
94 370436 : auto & val = parent_json[key][paths.back()];
95 370436 : return val;
96 370436 : }
97 :
98 : size_t
99 432337 : JsonSyntaxTree::setParams(InputParameters * params, bool search_match, nlohmann::json & all_params)
100 : {
101 432337 : size_t count = 0;
102 14787047 : for (auto & iter : *params)
103 : {
104 : // Make sure we want to see this parameter
105 14354710 : bool param_match = !_search.empty() && MooseUtils::wildCardMatch(iter.first, _search);
106 14354710 : if (params->isPrivate(iter.first) || (!_search.empty() && !search_match && !param_match))
107 7616550 : continue;
108 :
109 6738160 : ++count;
110 6738160 : nlohmann::json param_json;
111 :
112 6738160 : param_json["required"] = params->isParamRequired(iter.first);
113 :
114 : // Only output default if it has one
115 6738160 : if (params->isParamValid(iter.first))
116 4545198 : param_json["default"] = buildOutputString(iter);
117 2192962 : else if (params->hasDefaultCoupledValue(iter.first))
118 5575 : param_json["default"] = params->defaultCoupledValue(iter.first);
119 :
120 6738160 : bool out_of_range_allowed = false;
121 6738160 : std::map<MooseEnumItem, std::string> docs;
122 6738160 : param_json["options"] = buildOptions(iter, out_of_range_allowed, docs);
123 6738160 : if (!nlohmann::to_string(param_json["options"]).empty())
124 : {
125 6738160 : param_json["out_of_range_allowed"] = out_of_range_allowed;
126 6738160 : if (!docs.empty())
127 : {
128 2145 : nlohmann::json jdocs;
129 8085 : for (const auto & doc : docs)
130 5940 : jdocs[doc.first.name()] = doc.second;
131 2145 : param_json["option_docs"] = jdocs;
132 2145 : }
133 : }
134 6738160 : auto reserved_values = params->reservedValues(iter.first);
135 6967220 : for (const auto & reserved : reserved_values)
136 229060 : param_json["reserved_values"].push_back(reserved);
137 :
138 6738160 : std::string t = MooseUtils::prettyCppType(params->type(iter.first));
139 6738160 : param_json["cpp_type"] = t;
140 6738160 : param_json["basic_type"] = basicCppType(t);
141 6738160 : param_json["group_name"] = params->getGroupName(iter.first);
142 6738160 : param_json["name"] = iter.first;
143 :
144 6738160 : std::string doc = params->getDocString(iter.first);
145 6738160 : MooseUtils::escape(doc);
146 6738160 : param_json["description"] = doc;
147 :
148 6738160 : param_json["doc_unit"] = params->getDocUnit(iter.first);
149 :
150 6738160 : param_json["controllable"] = params->isControllable(iter.first);
151 6738160 : param_json["deprecated"] = params->isParamDeprecated(iter.first);
152 6738160 : all_params[iter.first] = param_json;
153 6738160 : }
154 432337 : return count;
155 : }
156 :
157 : void
158 183 : JsonSyntaxTree::addGlobal()
159 : {
160 : // If they are doing a search they probably don't want to see this
161 183 : if (_search.empty())
162 : {
163 165 : auto params = Moose::Builder::validParams();
164 165 : nlohmann::json jparams;
165 165 : setParams(¶ms, true, jparams);
166 165 : _root["global"]["parameters"] = jparams;
167 :
168 : // Just create a list of registered app names
169 165 : nlohmann::json apps;
170 165 : auto & factory = AppFactory::instance();
171 330 : for (const auto & name_bi_pair : factory.registeredObjects())
172 165 : apps.push_back(name_bi_pair.first);
173 :
174 165 : _root["global"]["registered_apps"] = apps;
175 165 : }
176 183 : }
177 :
178 : bool
179 432721 : JsonSyntaxTree::addParameters(const std::string & parent,
180 : const std::string & path,
181 : bool is_type,
182 : const std::string & action,
183 : bool is_action,
184 : InputParameters * params,
185 : const FileLineInfo & lineinfo,
186 : const std::string & classname)
187 : {
188 432721 : if (action == "EmptyAction")
189 549 : return false;
190 :
191 432172 : nlohmann::json all_params;
192 906983 : bool search_match = !_search.empty() && (MooseUtils::wildCardMatch(path, _search) ||
193 474811 : MooseUtils::wildCardMatch(action, _search) ||
194 474811 : MooseUtils::wildCardMatch(parent, _search));
195 432172 : auto count = setParams(params, search_match, all_params);
196 432172 : if (!_search.empty() && count == 0)
197 : // no parameters that matched the search string
198 42625 : return false;
199 :
200 389547 : nlohmann::json & json = getJson(parent, path, is_type);
201 :
202 389547 : if (is_action)
203 : {
204 19111 : json[action]["parameters"] = all_params;
205 19111 : json[action]["description"] = params->getClassDescription();
206 19111 : json[action]["action_path"] = path;
207 19111 : auto label_pair = getActionLabel(action);
208 19111 : json[action]["label"] = label_pair.first;
209 19111 : json[action]["register_file"] = label_pair.second;
210 19111 : if (lineinfo.isValid())
211 15433 : json[action]["file_info"][lineinfo.file()] = lineinfo.line();
212 19111 : }
213 370436 : else if (params)
214 : {
215 370436 : if (params->hasBase())
216 370436 : json["moose_base"] = params->getBase();
217 :
218 370436 : json["parameters"] = all_params;
219 370436 : json["syntax_path"] = path;
220 370436 : json["parent_syntax"] = parent;
221 370436 : json["description"] = params->getClassDescription();
222 : // We do this for ActionComponents which are registered as Actions but
223 : // dumped to the syntax tree as Objects
224 370436 : if (params->hasBase() && json["moose_base"] == "Action")
225 : {
226 330 : auto label_pair = getActionLabel(classname);
227 330 : json["label"] = label_pair.first;
228 330 : json["register_file"] = label_pair.second;
229 330 : }
230 : else
231 : {
232 370106 : auto label_pair = getObjectLabel(path);
233 370106 : json["label"] = label_pair.first;
234 370106 : json["register_file"] = label_pair.second;
235 370106 : }
236 370436 : if (lineinfo.isValid())
237 : {
238 370436 : json["file_info"][lineinfo.file()] = lineinfo.line();
239 370436 : if (!classname.empty())
240 16946 : json["class"] = classname;
241 : }
242 : }
243 389547 : return true;
244 432172 : }
245 :
246 : std::string
247 6738160 : JsonSyntaxTree::buildOptions(const std::iterator_traits<InputParameters::iterator>::value_type & p,
248 : bool & out_of_range_allowed,
249 : std::map<MooseEnumItem, std::string> & docs)
250 : {
251 6738160 : libMesh::Parameters::Value * val = MooseUtils::get(p.second);
252 :
253 6738160 : std::string options;
254 : {
255 6738160 : auto * enum_type = dynamic_cast<InputParameters::Parameter<MooseEnum> *>(val);
256 6738160 : if (enum_type)
257 : {
258 195820 : out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
259 195820 : options = enum_type->get().getRawNames();
260 195820 : docs = enum_type->get().getItemDocumentation();
261 : }
262 : }
263 : {
264 6738160 : auto * enum_type = dynamic_cast<InputParameters::Parameter<MultiMooseEnum> *>(val);
265 6738160 : if (enum_type)
266 : {
267 203588 : out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
268 203588 : options = enum_type->get().getRawNames();
269 203588 : docs = enum_type->get().getItemDocumentation();
270 : }
271 : }
272 : {
273 6738160 : auto * enum_type = dynamic_cast<InputParameters::Parameter<ExecFlagEnum> *>(val);
274 6738160 : if (enum_type)
275 : {
276 182189 : out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
277 182189 : options = enum_type->get().getRawNames();
278 182189 : docs = enum_type->get().getItemDocumentation();
279 : }
280 : }
281 : {
282 6738160 : auto * enum_type = dynamic_cast<InputParameters::Parameter<std::vector<MooseEnum>> *>(val);
283 6738160 : if (enum_type)
284 : {
285 1320 : out_of_range_allowed = (enum_type->get())[0].isOutOfRangeAllowed();
286 1320 : options = (enum_type->get())[0].getRawNames();
287 1320 : docs = enum_type->get()[0].getItemDocumentation();
288 : }
289 : }
290 : {
291 6738160 : auto * enum_type = dynamic_cast<InputParameters::Parameter<std::vector<MultiMooseEnum>> *>(val);
292 6738160 : if (enum_type)
293 : {
294 165 : out_of_range_allowed = (enum_type->get())[0].isOutOfRangeAllowed();
295 165 : options = (enum_type->get())[0].getRawNames();
296 165 : docs = enum_type->get()[0].getItemDocumentation();
297 : }
298 : }
299 6738160 : return options;
300 0 : }
301 :
302 : std::string
303 4545230 : JsonSyntaxTree::buildOutputString(
304 : const std::iterator_traits<InputParameters::iterator>::value_type & p)
305 : {
306 4545230 : libMesh::Parameters::Value * val = MooseUtils::get(p.second);
307 :
308 : // Account for Point
309 4545230 : std::stringstream str;
310 4545230 : InputParameters::Parameter<Point> * ptr0 = dynamic_cast<InputParameters::Parameter<Point> *>(val);
311 :
312 : // Account for RealVectorValues
313 : InputParameters::Parameter<RealVectorValue> * ptr1 =
314 4545230 : dynamic_cast<InputParameters::Parameter<RealVectorValue> *>(val);
315 :
316 : // Output the Point components
317 4545230 : if (ptr0)
318 4564 : str << ptr0->get().operator()(0) << " " << ptr0->get().operator()(1) << " "
319 4564 : << ptr0->get().operator()(2);
320 :
321 : // Output the RealVectorValue components
322 4540666 : else if (ptr1)
323 1980 : str << ptr1->get().operator()(0) << " " << ptr1->get().operator()(1) << " "
324 1980 : << ptr1->get().operator()(2);
325 :
326 : // General case, call the print operator
327 : else
328 4538686 : val->print(str);
329 :
330 : // remove additional '\n' possibly generated in output (breaks JSON parsing)
331 4545230 : std::string tmp_str = str.str();
332 21067224 : for (auto & ch : tmp_str)
333 16521994 : if (ch == '\n')
334 0 : ch = ' ';
335 :
336 9090460 : return tmp_str.substr(0, tmp_str.find("<RESIDUAL>"));
337 4545230 : }
338 :
339 : void
340 4758 : JsonSyntaxTree::addSyntaxType(const std::string & path, const std::string type)
341 : {
342 4758 : if (MooseUtils::wildCardMatch(path, _search))
343 : {
344 4290 : auto & j = getJson(path);
345 4290 : j["associated_types"].push_back(type);
346 : }
347 : // If they are doing a search they probably don't want to see this
348 4758 : if (_search.empty())
349 : {
350 4290 : _root["global"]["associated_types"][type].push_back(path);
351 : }
352 4758 : }
353 :
354 : void
355 30289 : JsonSyntaxTree::addActionTask(const std::string & path,
356 : const std::string & action,
357 : const std::string & task_name,
358 : const FileLineInfo & lineinfo)
359 : {
360 30289 : nlohmann::json & json = getJson("", path, false);
361 30289 : if (lineinfo.isValid())
362 30289 : json[action]["tasks"][task_name]["file_info"][lineinfo.file()] = lineinfo.line();
363 30289 : }
364 :
365 : std::string
366 8615856 : JsonSyntaxTree::basicCppType(const std::string & cpp_type)
367 : {
368 8615856 : std::string s = "String";
369 15371853 : if (cpp_type.find("std::vector") != std::string::npos ||
370 13498800 : cpp_type.find("libMesh::VectorValue") != std::string::npos ||
371 22114656 : cpp_type.find("libMesh::TensorValue") != std::string::npos ||
372 6742480 : cpp_type.find("Eigen::Matrix") != std::string::npos)
373 : {
374 : // Get the template type and use its basic type for the array type
375 1877631 : pcrecpp::RE r("^[^<]+<\\s*(.*)\\s*>$");
376 1877631 : std::string t;
377 1877631 : r.FullMatch(cpp_type, &t);
378 :
379 : // Capture type just to the first comma for Eigen::Matrix<type,V,W,X,Y,Z>
380 1877631 : if (cpp_type.find("Eigen::Matrix") != std::string::npos)
381 4255 : t = t.substr(0, t.find(","));
382 :
383 1877631 : s = "Array:" + basicCppType(t);
384 1877631 : }
385 13272696 : else if (cpp_type.find("MultiMooseEnum") != std::string::npos ||
386 12886753 : cpp_type.find("ExecFlagEnum") != std::string::npos ||
387 19624978 : cpp_type.find("VectorPostprocessorName") != std::string::npos ||
388 6347332 : cpp_type.find("std::map") != std::string::npos)
389 395464 : s = "Array:String";
390 6342761 : else if (cpp_type.find("libMesh::Point") != std::string::npos)
391 26949 : s = "Array:Real";
392 12504657 : else if (cpp_type == "int" || cpp_type == "unsigned int" || cpp_type == "short" ||
393 5819612 : cpp_type == "unsigned short" || cpp_type == "char" || cpp_type == "unsigned char" ||
394 18291677 : cpp_type == "long" || cpp_type == "unsigned long" || cpp_type == "long long" ||
395 5787020 : cpp_type == "unsigned long long")
396 528792 : s = "Integer";
397 5787020 : else if (cpp_type == "double" || cpp_type == "float")
398 387896 : s = "Real";
399 5399124 : else if (cpp_type == "bool")
400 2212969 : s = "Boolean";
401 :
402 8615856 : return s;
403 0 : }
404 :
405 : std::pair<std::string, std::string>
406 370106 : JsonSyntaxTree::getObjectLabel(const std::string & obj) const
407 : {
408 370106 : auto paths = splitPath(obj);
409 370106 : auto it = _object_label_map.find(paths.back());
410 370106 : if (it != _object_label_map.end())
411 370106 : return it->second;
412 : else
413 0 : return std::make_pair("", "");
414 370106 : }
415 :
416 : std::pair<std::string, std::string>
417 19441 : JsonSyntaxTree::getActionLabel(const std::string & action) const
418 : {
419 19441 : auto it = _action_label_map.find(action);
420 19441 : if (it != _action_label_map.end())
421 19441 : return it->second;
422 : else
423 0 : return std::make_pair("", "");
424 : }
|