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 40059 : for (auto & act : entry.second)
36 39693 : _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 286338 : for (auto & obj : entry.second)
41 285972 : _object_label_map[obj->name()] = std::make_pair(entry.first, obj->_file);
42 183 : }
43 :
44 : std::vector<std::string>
45 1402158 : JsonSyntaxTree::splitPath(const std::string & path)
46 : {
47 1402158 : std::string s;
48 1402158 : std::istringstream f(path);
49 1402158 : std::vector<std::string> paths;
50 5920803 : while (std::getline(f, s, '/'))
51 3116487 : if (s.size() > 0)
52 3116487 : paths.push_back(s);
53 2804316 : return paths;
54 1402158 : }
55 :
56 : nlohmann::json &
57 504204 : JsonSyntaxTree::getJson(const std::string & path)
58 : {
59 504204 : auto paths = splitPath(path);
60 : mooseAssert(paths.size() > 0, "path is empty");
61 504204 : auto * next = &(_root["blocks"][paths[0]]);
62 :
63 1048427 : for (auto pit = paths.begin() + 1; pit != paths.end(); ++pit)
64 : {
65 544223 : if (*pit == "*")
66 : // It has an action syntax as a parent
67 473020 : next = &(*next)["star"];
68 71203 : else if (*pit == "<type>")
69 0 : next = &(*next)["types"];
70 : else
71 71203 : next = &(*next)["subblocks"][*pit];
72 : }
73 504204 : return *next;
74 504204 : }
75 :
76 : nlohmann::json &
77 499718 : JsonSyntaxTree::getJson(const std::string & parent, const std::string & path, bool is_type)
78 : {
79 499718 : if (parent.empty())
80 : {
81 50576 : auto & j = getJson(path);
82 50576 : if (path.back() == '*' && !j.contains("subblock_types"))
83 11400 : j["subblock_types"] = nlohmann::json();
84 39176 : else if (path.back() != '*' && !j.contains("types"))
85 5824 : j["types"] = nlohmann::json();
86 50576 : return j["actions"];
87 : }
88 :
89 449142 : auto & parent_json = getJson(parent);
90 449142 : auto paths = splitPath(path);
91 449142 : std::string key = "subblock_types";
92 449142 : if (is_type)
93 48903 : key = "types";
94 449142 : auto & val = parent_json[key][paths.back()];
95 449142 : return val;
96 449142 : }
97 :
98 : size_t
99 519761 : JsonSyntaxTree::setParams(InputParameters * params, bool search_match, nlohmann::json & all_params)
100 : {
101 519761 : size_t count = 0;
102 18088118 : for (auto & iter : *params)
103 : {
104 : // Make sure we want to see this parameter
105 17568357 : bool param_match = !_search.empty() && MooseUtils::wildCardMatch(iter.first, _search);
106 17568357 : if (params->isPrivate(iter.first) || (!_search.empty() && !search_match && !param_match))
107 9229080 : continue;
108 :
109 8339277 : ++count;
110 8339277 : nlohmann::json param_json;
111 :
112 8339277 : param_json["required"] = params->isParamRequired(iter.first);
113 :
114 : // Only output default if it has one
115 8339277 : if (params->isParamValid(iter.first))
116 5652022 : param_json["default"] = buildOutputString(iter);
117 2687255 : else if (params->hasDefaultCoupledValue(iter.first))
118 6947 : param_json["default"] = params->defaultCoupledValue(iter.first);
119 :
120 8339277 : bool out_of_range_allowed = false;
121 8339277 : std::map<MooseEnumItem, std::string> docs;
122 8339277 : param_json["options"] = buildOptions(iter, out_of_range_allowed, docs);
123 8339277 : if (!nlohmann::to_string(param_json["options"]).empty())
124 : {
125 8339277 : param_json["out_of_range_allowed"] = out_of_range_allowed;
126 8339277 : if (!docs.empty())
127 : {
128 2341 : nlohmann::json jdocs;
129 8869 : for (const auto & doc : docs)
130 6528 : jdocs[doc.first.name()] = doc.second;
131 2341 : param_json["option_docs"] = jdocs;
132 2341 : }
133 : }
134 8339277 : auto reserved_values = params->reservedValues(iter.first);
135 8601099 : for (const auto & reserved : reserved_values)
136 261822 : param_json["reserved_values"].push_back(reserved);
137 :
138 8339277 : std::string t = MooseUtils::prettyCppType(params->type(iter.first));
139 8339277 : param_json["cpp_type"] = t;
140 8339277 : param_json["basic_type"] = basicCppType(t);
141 8339277 : param_json["group_name"] = params->getGroupName(iter.first);
142 8339277 : param_json["name"] = iter.first;
143 :
144 8339277 : std::string doc = params->getDocString(iter.first);
145 8339277 : MooseUtils::escape(doc);
146 8339277 : param_json["description"] = doc;
147 :
148 8339277 : param_json["doc_unit"] = params->getDocUnit(iter.first);
149 :
150 8339277 : param_json["controllable"] = params->isControllable(iter.first);
151 8339277 : param_json["deprecated"] = params->isParamDeprecated(iter.first);
152 8339277 : all_params[iter.first] = param_json;
153 8339277 : }
154 519761 : 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 520145 : 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 520145 : if (action == "EmptyAction")
189 549 : return false;
190 :
191 519596 : nlohmann::json all_params;
192 1089961 : bool search_match = !_search.empty() && (MooseUtils::wildCardMatch(path, _search) ||
193 570365 : MooseUtils::wildCardMatch(action, _search) ||
194 570365 : MooseUtils::wildCardMatch(parent, _search));
195 519596 : auto count = setParams(params, search_match, all_params);
196 519596 : if (!_search.empty() && count == 0)
197 : // no parameters that matched the search string
198 50755 : return false;
199 :
200 468841 : nlohmann::json & json = getJson(parent, path, is_type);
201 :
202 468841 : if (is_action)
203 : {
204 19699 : json[action]["parameters"] = all_params;
205 19699 : json[action]["description"] = params->getClassDescription();
206 19699 : json[action]["action_path"] = path;
207 19699 : auto label_pair = getActionLabel(action);
208 19699 : json[action]["label"] = label_pair.first;
209 19699 : json[action]["register_file"] = label_pair.second;
210 19699 : if (lineinfo.isValid())
211 15629 : json[action]["file_info"][lineinfo.file()] = lineinfo.line();
212 19699 : }
213 449142 : else if (params)
214 : {
215 449142 : if (params->hasBase())
216 449142 : json["moose_base"] = params->getBase();
217 :
218 449142 : json["parameters"] = all_params;
219 449142 : json["syntax_path"] = path;
220 449142 : json["parent_syntax"] = parent;
221 449142 : 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 449142 : 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 448812 : auto label_pair = getObjectLabel(path);
233 448812 : json["label"] = label_pair.first;
234 448812 : json["register_file"] = label_pair.second;
235 448812 : }
236 449142 : if (lineinfo.isValid())
237 : {
238 449142 : json["file_info"][lineinfo.file()] = lineinfo.line();
239 449142 : if (!classname.empty())
240 19886 : json["class"] = classname;
241 : }
242 : }
243 468841 : return true;
244 519596 : }
245 :
246 : std::string
247 8339277 : 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 8339277 : libMesh::Parameters::Value * val = MooseUtils::get(p.second);
252 :
253 8339277 : std::string options;
254 : {
255 8339277 : auto * enum_type = dynamic_cast<InputParameters::Parameter<MooseEnum> *>(val);
256 8339277 : if (enum_type)
257 : {
258 433197 : out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
259 433197 : options = enum_type->get().getRawNames();
260 433197 : docs = enum_type->get().getItemDocumentation();
261 : }
262 : }
263 : {
264 8339277 : auto * enum_type = dynamic_cast<InputParameters::Parameter<MultiMooseEnum> *>(val);
265 8339277 : if (enum_type)
266 : {
267 274190 : out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
268 274190 : options = enum_type->get().getRawNames();
269 274190 : docs = enum_type->get().getItemDocumentation();
270 : }
271 : }
272 : {
273 8339277 : auto * enum_type = dynamic_cast<InputParameters::Parameter<ExecFlagEnum> *>(val);
274 8339277 : if (enum_type)
275 : {
276 205002 : out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
277 205002 : options = enum_type->get().getRawNames();
278 205002 : docs = enum_type->get().getItemDocumentation();
279 : }
280 : }
281 : {
282 8339277 : auto * enum_type = dynamic_cast<InputParameters::Parameter<std::vector<MooseEnum>> *>(val);
283 8339277 : 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 8339277 : auto * enum_type = dynamic_cast<InputParameters::Parameter<std::vector<MultiMooseEnum>> *>(val);
292 8339277 : if (enum_type)
293 : {
294 263 : out_of_range_allowed = (enum_type->get())[0].isOutOfRangeAllowed();
295 263 : options = (enum_type->get())[0].getRawNames();
296 263 : docs = enum_type->get()[0].getItemDocumentation();
297 : }
298 : }
299 8339277 : return options;
300 0 : }
301 :
302 : std::string
303 5652086 : JsonSyntaxTree::buildOutputString(
304 : const std::iterator_traits<InputParameters::iterator>::value_type & p)
305 : {
306 5652086 : libMesh::Parameters::Value * val = MooseUtils::get(p.second);
307 :
308 : // Account for Point
309 5652086 : std::stringstream str;
310 5652086 : InputParameters::Parameter<Point> * ptr0 = dynamic_cast<InputParameters::Parameter<Point> *>(val);
311 :
312 : // Account for RealVectorValues
313 : InputParameters::Parameter<RealVectorValue> * ptr1 =
314 5652086 : dynamic_cast<InputParameters::Parameter<RealVectorValue> *>(val);
315 :
316 : // Output the Point components
317 5652086 : 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 5647522 : else if (ptr1)
323 2764 : str << ptr1->get().operator()(0) << " " << ptr1->get().operator()(1) << " "
324 2764 : << ptr1->get().operator()(2);
325 :
326 : // General case, call the print operator
327 : else
328 5644758 : val->print(str);
329 :
330 : // remove additional '\n' possibly generated in output (breaks JSON parsing)
331 5652086 : std::string tmp_str = str.str();
332 31520069 : for (auto & ch : tmp_str)
333 25867983 : if (ch == '\n')
334 0 : ch = ' ';
335 :
336 11304172 : return tmp_str.substr(0, tmp_str.find("<RESIDUAL>"));
337 5652086 : }
338 :
339 : void
340 4974 : JsonSyntaxTree::addSyntaxType(const std::string & path, const std::string type)
341 : {
342 4974 : if (MooseUtils::wildCardMatch(path, _search))
343 : {
344 4486 : auto & j = getJson(path);
345 4486 : j["associated_types"].push_back(type);
346 : }
347 : // If they are doing a search they probably don't want to see this
348 4974 : if (_search.empty())
349 : {
350 4486 : _root["global"]["associated_types"][type].push_back(path);
351 : }
352 4974 : }
353 :
354 : void
355 30877 : JsonSyntaxTree::addActionTask(const std::string & path,
356 : const std::string & action,
357 : const std::string & task_name,
358 : const FileLineInfo & lineinfo)
359 : {
360 30877 : nlohmann::json & json = getJson("", path, false);
361 30877 : if (lineinfo.isValid())
362 30877 : json[action]["tasks"][task_name]["file_info"][lineinfo.file()] = lineinfo.line();
363 30877 : }
364 :
365 : std::string
366 10687111 : JsonSyntaxTree::basicCppType(const std::string & cpp_type)
367 : {
368 10687111 : std::string s = "String";
369 19047882 : if (cpp_type.find("std::vector") != std::string::npos ||
370 16706293 : cpp_type.find("libMesh::VectorValue") != std::string::npos ||
371 27393404 : cpp_type.find("libMesh::TensorValue") != std::string::npos ||
372 8345101 : cpp_type.find("Eigen::Matrix") != std::string::npos)
373 : {
374 : // Get the template type and use its basic type for the array type
375 2347704 : pcrecpp::RE r("^[^<]+<\\s*(.*)\\s*>$");
376 2347704 : std::string t;
377 2347704 : r.FullMatch(cpp_type, &t);
378 :
379 : // Capture type just to the first comma for Eigen::Matrix<type,V,W,X,Y,Z>
380 2347704 : if (cpp_type.find("Eigen::Matrix") != std::string::npos)
381 5694 : t = t.substr(0, t.find(","));
382 :
383 2347704 : s = "Array:" + basicCppType(t);
384 2347704 : }
385 16404359 : else if (cpp_type.find("MultiMooseEnum") != std::string::npos ||
386 15924902 : cpp_type.find("ExecFlagEnum") != std::string::npos ||
387 24264309 : cpp_type.find("VectorPostprocessorName") != std::string::npos ||
388 7854510 : cpp_type.find("std::map") != std::string::npos)
389 490938 : s = "Array:String";
390 7848469 : else if (cpp_type.find("libMesh::Point") != std::string::npos)
391 27507 : s = "Array:Real";
392 15509526 : else if (cpp_type == "int" || cpp_type == "unsigned int" || cpp_type == "short" ||
393 7236834 : cpp_type == "unsigned short" || cpp_type == "char" || cpp_type == "unsigned char" ||
394 22713013 : cpp_type == "long" || cpp_type == "unsigned long" || cpp_type == "long long" ||
395 7203487 : cpp_type == "unsigned long long")
396 617475 : s = "Integer";
397 7203487 : else if (cpp_type == "double" || cpp_type == "float")
398 440679 : s = "Real";
399 6762808 : else if (cpp_type == "bool")
400 2594392 : s = "Boolean";
401 :
402 10687111 : return s;
403 0 : }
404 :
405 : std::pair<std::string, std::string>
406 448812 : JsonSyntaxTree::getObjectLabel(const std::string & obj) const
407 : {
408 448812 : auto paths = splitPath(obj);
409 448812 : auto it = _object_label_map.find(paths.back());
410 448812 : if (it != _object_label_map.end())
411 448812 : return it->second;
412 : else
413 0 : return std::make_pair("", "");
414 448812 : }
415 :
416 : std::pair<std::string, std::string>
417 20029 : JsonSyntaxTree::getActionLabel(const std::string & action) const
418 : {
419 20029 : auto it = _action_label_map.find(action);
420 20029 : if (it != _action_label_map.end())
421 20029 : return it->second;
422 : else
423 0 : return std::make_pair("", "");
424 : }
|