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 39768 : for (auto & act : entry.second)
36 39402 : _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 284925 : for (auto & obj : entry.second)
41 284559 : _object_label_map[obj->name()] = std::make_pair(entry.first, obj->_file);
42 183 : }
43 :
44 : std::vector<std::string>
45 1383939 : JsonSyntaxTree::splitPath(const std::string & path)
46 : {
47 1383939 : std::string s;
48 1383939 : std::istringstream f(path);
49 1383939 : std::vector<std::string> paths;
50 5845869 : while (std::getline(f, s, '/'))
51 3077991 : if (s.size() > 0)
52 3077991 : paths.push_back(s);
53 2767878 : return paths;
54 1383939 : }
55 :
56 : nlohmann::json &
57 497935 : JsonSyntaxTree::getJson(const std::string & path)
58 : {
59 497935 : auto paths = splitPath(path);
60 : mooseAssert(paths.size() > 0, "path is empty");
61 497935 : auto * next = &(_root["blocks"][paths[0]]);
62 :
63 1035595 : for (auto pit = paths.begin() + 1; pit != paths.end(); ++pit)
64 : {
65 537660 : if (*pit == "*")
66 : // It has an action syntax as a parent
67 466751 : next = &(*next)["star"];
68 70909 : else if (*pit == "<type>")
69 0 : next = &(*next)["types"];
70 : else
71 70909 : next = &(*next)["subblocks"][*pit];
72 : }
73 497935 : return *next;
74 497935 : }
75 :
76 : nlohmann::json &
77 493547 : JsonSyntaxTree::getJson(const std::string & parent, const std::string & path, bool is_type)
78 : {
79 493547 : if (parent.empty())
80 : {
81 50380 : auto & j = getJson(path);
82 50380 : if (path.back() == '*' && !j.contains("subblock_types"))
83 11302 : j["subblock_types"] = nlohmann::json();
84 39078 : else if (path.back() != '*' && !j.contains("types"))
85 5824 : j["types"] = nlohmann::json();
86 50380 : return j["actions"];
87 : }
88 :
89 443167 : auto & parent_json = getJson(parent);
90 443167 : auto paths = splitPath(path);
91 443167 : std::string key = "subblock_types";
92 443167 : if (is_type)
93 48609 : key = "types";
94 443167 : auto & val = parent_json[key][paths.back()];
95 443167 : return val;
96 443167 : }
97 :
98 : size_t
99 513064 : JsonSyntaxTree::setParams(InputParameters * params, bool search_match, nlohmann::json & all_params)
100 : {
101 513064 : size_t count = 0;
102 17904866 : for (auto & iter : *params)
103 : {
104 : // Make sure we want to see this parameter
105 17391802 : bool param_match = !_search.empty() && MooseUtils::wildCardMatch(iter.first, _search);
106 17391802 : if (params->isPrivate(iter.first) || (!_search.empty() && !search_match && !param_match))
107 9124300 : continue;
108 :
109 8267502 : ++count;
110 8267502 : nlohmann::json param_json;
111 :
112 8267502 : param_json["required"] = params->isParamRequired(iter.first);
113 :
114 : // Only output default if it has one
115 8267502 : if (params->isParamValid(iter.first))
116 5611457 : param_json["default"] = buildOutputString(iter);
117 2656045 : else if (params->hasDefaultCoupledValue(iter.first))
118 6947 : param_json["default"] = params->defaultCoupledValue(iter.first);
119 :
120 8267502 : bool out_of_range_allowed = false;
121 8267502 : std::map<MooseEnumItem, std::string> docs;
122 8267502 : param_json["options"] = buildOptions(iter, out_of_range_allowed, docs);
123 8267502 : if (!nlohmann::to_string(param_json["options"]).empty())
124 : {
125 8267502 : param_json["out_of_range_allowed"] = out_of_range_allowed;
126 8267502 : 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 8267502 : auto reserved_values = params->reservedValues(iter.first);
135 8529324 : for (const auto & reserved : reserved_values)
136 261822 : param_json["reserved_values"].push_back(reserved);
137 :
138 8267502 : std::string t = MooseUtils::prettyCppType(params->type(iter.first));
139 8267502 : param_json["cpp_type"] = t;
140 8267502 : param_json["basic_type"] = basicCppType(t);
141 8267502 : param_json["group_name"] = params->getGroupName(iter.first);
142 8267502 : param_json["name"] = iter.first;
143 :
144 8267502 : std::string doc = params->getDocString(iter.first);
145 8267502 : MooseUtils::escape(doc);
146 8267502 : param_json["description"] = doc;
147 :
148 8267502 : param_json["doc_unit"] = params->getDocUnit(iter.first);
149 :
150 8267502 : param_json["controllable"] = params->isControllable(iter.first);
151 8267502 : param_json["deprecated"] = params->isParamDeprecated(iter.first);
152 8267502 : all_params[iter.first] = param_json;
153 8267502 : }
154 513064 : 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 513448 : 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 513448 : if (action == "EmptyAction")
189 549 : return false;
190 :
191 512899 : nlohmann::json all_params;
192 1075943 : bool search_match = !_search.empty() && (MooseUtils::wildCardMatch(path, _search) ||
193 563044 : MooseUtils::wildCardMatch(action, _search) ||
194 563044 : MooseUtils::wildCardMatch(parent, _search));
195 512899 : auto count = setParams(params, search_match, all_params);
196 512899 : if (!_search.empty() && count == 0)
197 : // no parameters that matched the search string
198 50131 : return false;
199 :
200 462768 : nlohmann::json & json = getJson(parent, path, is_type);
201 :
202 462768 : if (is_action)
203 : {
204 19601 : json[action]["parameters"] = all_params;
205 19601 : json[action]["description"] = params->getClassDescription();
206 19601 : json[action]["action_path"] = path;
207 19601 : auto label_pair = getActionLabel(action);
208 19601 : json[action]["label"] = label_pair.first;
209 19601 : json[action]["register_file"] = label_pair.second;
210 19601 : if (lineinfo.isValid())
211 15531 : json[action]["file_info"][lineinfo.file()] = lineinfo.line();
212 19601 : }
213 443167 : else if (params)
214 : {
215 443167 : if (params->hasBase())
216 443167 : json["moose_base"] = params->getBase();
217 :
218 443167 : json["parameters"] = all_params;
219 443167 : json["syntax_path"] = path;
220 443167 : json["parent_syntax"] = parent;
221 443167 : 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 443167 : 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 442837 : auto label_pair = getObjectLabel(path);
233 442837 : json["label"] = label_pair.first;
234 442837 : json["register_file"] = label_pair.second;
235 442837 : }
236 443167 : if (lineinfo.isValid())
237 : {
238 443167 : json["file_info"][lineinfo.file()] = lineinfo.line();
239 443167 : if (!classname.empty())
240 19200 : json["class"] = classname;
241 : }
242 : }
243 462768 : return true;
244 512899 : }
245 :
246 : std::string
247 8267502 : 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 8267502 : libMesh::Parameters::Value * val = MooseUtils::get(p.second);
252 :
253 8267502 : std::string options;
254 : {
255 8267502 : auto * enum_type = dynamic_cast<InputParameters::Parameter<MooseEnum> *>(val);
256 8267502 : if (enum_type)
257 : {
258 429499 : out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
259 429499 : options = enum_type->get().getRawNames();
260 429499 : docs = enum_type->get().getItemDocumentation();
261 : }
262 : }
263 : {
264 8267502 : auto * enum_type = dynamic_cast<InputParameters::Parameter<MultiMooseEnum> *>(val);
265 8267502 : if (enum_type)
266 : {
267 271452 : out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
268 271452 : options = enum_type->get().getRawNames();
269 271452 : docs = enum_type->get().getItemDocumentation();
270 : }
271 : }
272 : {
273 8267502 : auto * enum_type = dynamic_cast<InputParameters::Parameter<ExecFlagEnum> *>(val);
274 8267502 : if (enum_type)
275 : {
276 204120 : out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
277 204120 : options = enum_type->get().getRawNames();
278 204120 : docs = enum_type->get().getItemDocumentation();
279 : }
280 : }
281 : {
282 8267502 : auto * enum_type = dynamic_cast<InputParameters::Parameter<std::vector<MooseEnum>> *>(val);
283 8267502 : 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 8267502 : auto * enum_type = dynamic_cast<InputParameters::Parameter<std::vector<MultiMooseEnum>> *>(val);
292 8267502 : 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 8267502 : return options;
300 0 : }
301 :
302 : std::string
303 5611521 : JsonSyntaxTree::buildOutputString(
304 : const std::iterator_traits<InputParameters::iterator>::value_type & p)
305 : {
306 5611521 : libMesh::Parameters::Value * val = MooseUtils::get(p.second);
307 :
308 : // Account for Point
309 5611521 : std::stringstream str;
310 5611521 : InputParameters::Parameter<Point> * ptr0 = dynamic_cast<InputParameters::Parameter<Point> *>(val);
311 :
312 : // Account for RealVectorValues
313 : InputParameters::Parameter<RealVectorValue> * ptr1 =
314 5611521 : dynamic_cast<InputParameters::Parameter<RealVectorValue> *>(val);
315 :
316 : // Output the Point components
317 5611521 : 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 5606957 : else if (ptr1)
323 2372 : str << ptr1->get().operator()(0) << " " << ptr1->get().operator()(1) << " "
324 2372 : << ptr1->get().operator()(2);
325 :
326 : // General case, call the print operator
327 : else
328 5604585 : val->print(str);
329 :
330 : // remove additional '\n' possibly generated in output (breaks JSON parsing)
331 5611521 : std::string tmp_str = str.str();
332 31251356 : for (auto & ch : tmp_str)
333 25639835 : if (ch == '\n')
334 0 : ch = ' ';
335 :
336 11223042 : return tmp_str.substr(0, tmp_str.find("<RESIDUAL>"));
337 5611521 : }
338 :
339 : void
340 4866 : JsonSyntaxTree::addSyntaxType(const std::string & path, const std::string type)
341 : {
342 4866 : if (MooseUtils::wildCardMatch(path, _search))
343 : {
344 4388 : auto & j = getJson(path);
345 4388 : j["associated_types"].push_back(type);
346 : }
347 : // If they are doing a search they probably don't want to see this
348 4866 : if (_search.empty())
349 : {
350 4388 : _root["global"]["associated_types"][type].push_back(path);
351 : }
352 4866 : }
353 :
354 : void
355 30779 : JsonSyntaxTree::addActionTask(const std::string & path,
356 : const std::string & action,
357 : const std::string & task_name,
358 : const FileLineInfo & lineinfo)
359 : {
360 30779 : nlohmann::json & json = getJson("", path, false);
361 30779 : if (lineinfo.isValid())
362 30779 : json[action]["tasks"][task_name]["file_info"][lineinfo.file()] = lineinfo.line();
363 30779 : }
364 :
365 : std::string
366 10596613 : JsonSyntaxTree::basicCppType(const std::string & cpp_type)
367 : {
368 10596613 : std::string s = "String";
369 18884954 : if (cpp_type.find("std::vector") != std::string::npos ||
370 16561825 : cpp_type.find("libMesh::VectorValue") != std::string::npos ||
371 27158438 : cpp_type.find("libMesh::TensorValue") != std::string::npos ||
372 8273063 : cpp_type.find("Eigen::Matrix") != std::string::npos)
373 : {
374 : // Get the template type and use its basic type for the array type
375 2328981 : pcrecpp::RE r("^[^<]+<\\s*(.*)\\s*>$");
376 2328981 : std::string t;
377 2328981 : r.FullMatch(cpp_type, &t);
378 :
379 : // Capture type just to the first comma for Eigen::Matrix<type,V,W,X,Y,Z>
380 2328981 : if (cpp_type.find("Eigen::Matrix") != std::string::npos)
381 5431 : t = t.substr(0, t.find(","));
382 :
383 2328981 : s = "Array:" + basicCppType(t);
384 2328981 : }
385 16263547 : else if (cpp_type.find("MultiMooseEnum") != std::string::npos ||
386 15787710 : cpp_type.find("ExecFlagEnum") != std::string::npos ||
387 24055342 : cpp_type.find("VectorPostprocessorName") != std::string::npos ||
388 7786551 : cpp_type.find("std::map") != std::string::npos)
389 487122 : s = "Array:String";
390 7780510 : else if (cpp_type.find("libMesh::Point") != std::string::npos)
391 27146 : s = "Array:Real";
392 15375212 : else if (cpp_type == "int" || cpp_type == "unsigned int" || cpp_type == "short" ||
393 7173447 : cpp_type == "unsigned short" || cpp_type == "char" || cpp_type == "unsigned char" ||
394 22515410 : cpp_type == "long" || cpp_type == "unsigned long" || cpp_type == "long long" ||
395 7140198 : cpp_type == "unsigned long long")
396 613166 : s = "Integer";
397 7140198 : else if (cpp_type == "double" || cpp_type == "float")
398 432344 : s = "Real";
399 6707854 : else if (cpp_type == "bool")
400 2576669 : s = "Boolean";
401 :
402 10596613 : return s;
403 0 : }
404 :
405 : std::pair<std::string, std::string>
406 442837 : JsonSyntaxTree::getObjectLabel(const std::string & obj) const
407 : {
408 442837 : auto paths = splitPath(obj);
409 442837 : auto it = _object_label_map.find(paths.back());
410 442837 : if (it != _object_label_map.end())
411 442837 : return it->second;
412 : else
413 0 : return std::make_pair("", "");
414 442837 : }
415 :
416 : std::pair<std::string, std::string>
417 19931 : JsonSyntaxTree::getActionLabel(const std::string & action) const
418 : {
419 19931 : auto it = _action_label_map.find(action);
420 19931 : if (it != _action_label_map.end())
421 19931 : return it->second;
422 : else
423 0 : return std::make_pair("", "");
424 : }
|