LCOV - code coverage report
Current view: top level - src/utils - JsonSyntaxTree.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 240 246 97.6 %
Date: 2025-07-17 01:28:37 Functions: 14 14 100.0 %
Legend: Lines: hit not hit

          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       38529 :     for (auto & act : entry.second)
      36       38163 :       _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      273138 :     for (auto & obj : entry.second)
      41      272772 :       _object_label_map[obj->name()] = std::make_pair(entry.first, obj->_file);
      42         183 : }
      43             : 
      44             : std::vector<std::string>
      45     1148117 : JsonSyntaxTree::splitPath(const std::string & path)
      46             : {
      47     1148117 :   std::string s;
      48     1148117 :   std::istringstream f(path);
      49     1148117 :   std::vector<std::string> paths;
      50     4892039 :   while (std::getline(f, s, '/'))
      51     2595805 :     if (s.size() > 0)
      52     2595805 :       paths.push_back(s);
      53     2296234 :   return paths;
      54     1148117 : }
      55             : 
      56             : nlohmann::json &
      57      418609 : JsonSyntaxTree::getJson(const std::string & path)
      58             : {
      59      418609 :   auto paths = splitPath(path);
      60             :   mooseAssert(paths.size() > 0, "path is empty");
      61      418609 :   auto * next = &(_root["blocks"][paths[0]]);
      62             : 
      63      875437 :   for (auto pit = paths.begin() + 1; pit != paths.end(); ++pit)
      64             :   {
      65      456828 :     if (*pit == "*")
      66             :       // It has an action syntax as a parent
      67      387590 :       next = &(*next)["star"];
      68       69238 :     else if (*pit == "<type>")
      69           0 :       next = &(*next)["types"];
      70             :     else
      71       69238 :       next = &(*next)["subblocks"][*pit];
      72             :   }
      73      418609 :   return *next;
      74      418609 : }
      75             : 
      76             : nlohmann::json &
      77      414319 : JsonSyntaxTree::getJson(const std::string & parent, const std::string & path, bool is_type)
      78             : {
      79      414319 :   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      364919 :   auto & parent_json = getJson(parent);
      90      364919 :   auto paths = splitPath(path);
      91      364919 :   std::string key = "subblock_types";
      92      364919 :   if (is_type)
      93       47103 :     key = "types";
      94      364919 :   auto & val = parent_json[key][paths.back()];
      95      364919 :   return val;
      96      364919 : }
      97             : 
      98             : size_t
      99      426230 : JsonSyntaxTree::setParams(InputParameters * params, bool search_match, nlohmann::json & all_params)
     100             : {
     101      426230 :   size_t count = 0;
     102    14521675 :   for (auto & iter : *params)
     103             :   {
     104             :     // Make sure we want to see this parameter
     105    14095445 :     bool param_match = !_search.empty() && MooseUtils::wildCardMatch(iter.first, _search);
     106    14095445 :     if (params->isPrivate(iter.first) || (!_search.empty() && !search_match && !param_match))
     107     7455761 :       continue;
     108             : 
     109     6639684 :     ++count;
     110     6639684 :     nlohmann::json param_json;
     111             : 
     112     6639684 :     param_json["required"] = params->isParamRequired(iter.first);
     113             : 
     114             :     // Only output default if it has one
     115     6639684 :     if (params->isParamValid(iter.first))
     116     4474666 :       param_json["default"] = buildOutputString(iter);
     117     2165018 :     else if (params->hasDefaultCoupledValue(iter.first))
     118        5575 :       param_json["default"] = params->defaultCoupledValue(iter.first);
     119             : 
     120     6639684 :     bool out_of_range_allowed = false;
     121     6639684 :     std::map<MooseEnumItem, std::string> docs;
     122     6639684 :     param_json["options"] = buildOptions(iter, out_of_range_allowed, docs);
     123     6639684 :     if (!nlohmann::to_string(param_json["options"]).empty())
     124             :     {
     125     6639684 :       param_json["out_of_range_allowed"] = out_of_range_allowed;
     126     6639684 :       if (!docs.empty())
     127             :       {
     128         495 :         nlohmann::json jdocs;
     129        2145 :         for (const auto & doc : docs)
     130        1650 :           jdocs[doc.first.name()] = doc.second;
     131         495 :         param_json["option_docs"] = jdocs;
     132         495 :       }
     133             :     }
     134     6639684 :     auto reserved_values = params->reservedValues(iter.first);
     135     6866042 :     for (const auto & reserved : reserved_values)
     136      226358 :       param_json["reserved_values"].push_back(reserved);
     137             : 
     138     6639684 :     std::string t = MooseUtils::prettyCppType(params->type(iter.first));
     139     6639684 :     param_json["cpp_type"] = t;
     140     6639684 :     param_json["basic_type"] = basicCppType(t);
     141     6639684 :     param_json["group_name"] = params->getGroupName(iter.first);
     142     6639684 :     param_json["name"] = iter.first;
     143             : 
     144     6639684 :     std::string doc = params->getDocString(iter.first);
     145     6639684 :     MooseUtils::escape(doc);
     146     6639684 :     param_json["description"] = doc;
     147             : 
     148     6639684 :     param_json["doc_unit"] = params->getDocUnit(iter.first);
     149             : 
     150     6639684 :     param_json["controllable"] = params->isControllable(iter.first);
     151     6639684 :     param_json["deprecated"] = params->isParamDeprecated(iter.first);
     152     6639684 :     all_params[iter.first] = param_json;
     153     6639684 :   }
     154      426230 :   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(&params, 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      426614 : 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      426614 :   if (action == "EmptyAction")
     189         549 :     return false;
     190             : 
     191      426065 :   nlohmann::json all_params;
     192      894179 :   bool search_match = !_search.empty() && (MooseUtils::wildCardMatch(path, _search) ||
     193      468114 :                                            MooseUtils::wildCardMatch(action, _search) ||
     194      468114 :                                            MooseUtils::wildCardMatch(parent, _search));
     195      426065 :   auto count = setParams(params, search_match, all_params);
     196      426065 :   if (!_search.empty() && count == 0)
     197             :     // no parameters that matched the search string
     198       42035 :     return false;
     199             : 
     200      384030 :   nlohmann::json & json = getJson(parent, path, is_type);
     201             : 
     202      384030 :   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      364919 :   else if (params)
     214             :   {
     215      364919 :     if (params->isParamValid("_moose_base"))
     216      364919 :       json["moose_base"] = params->get<std::string>("_moose_base");
     217             : 
     218      364919 :     json["parameters"] = all_params;
     219      364919 :     json["syntax_path"] = path;
     220      364919 :     json["parent_syntax"] = parent;
     221      364919 :     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      364919 :     if (params->isParamValid("_moose_base") && 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      364589 :       auto label_pair = getObjectLabel(path);
     233      364589 :       json["label"] = label_pair.first;
     234      364589 :       json["register_file"] = label_pair.second;
     235      364589 :     }
     236      364919 :     if (lineinfo.isValid())
     237             :     {
     238      364919 :       json["file_info"][lineinfo.file()] = lineinfo.line();
     239      364919 :       if (!classname.empty())
     240       16458 :         json["class"] = classname;
     241             :     }
     242             :   }
     243      384030 :   return true;
     244      426065 : }
     245             : 
     246             : std::string
     247     6639684 : 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     6639684 :   libMesh::Parameters::Value * val = MooseUtils::get(p.second);
     252             : 
     253     6639684 :   std::string options;
     254             :   {
     255     6639684 :     auto * enum_type = dynamic_cast<InputParameters::Parameter<MooseEnum> *>(val);
     256     6639684 :     if (enum_type)
     257             :     {
     258      194521 :       out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
     259      194521 :       options = enum_type->get().getRawNames();
     260      194521 :       docs = enum_type->get().getItemDocumentation();
     261             :     }
     262             :   }
     263             :   {
     264     6639684 :     auto * enum_type = dynamic_cast<InputParameters::Parameter<MultiMooseEnum> *>(val);
     265     6639684 :     if (enum_type)
     266             :     {
     267      204841 :       out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
     268      204841 :       options = enum_type->get().getRawNames();
     269      204841 :       docs = enum_type->get().getItemDocumentation();
     270             :     }
     271             :   }
     272             :   {
     273     6639684 :     auto * enum_type = dynamic_cast<InputParameters::Parameter<ExecFlagEnum> *>(val);
     274     6639684 :     if (enum_type)
     275             :     {
     276      178925 :       out_of_range_allowed = enum_type->get().isOutOfRangeAllowed();
     277      178925 :       options = enum_type->get().getRawNames();
     278      178925 :       docs = enum_type->get().getItemDocumentation();
     279             :     }
     280             :   }
     281             :   {
     282     6639684 :     auto * enum_type = dynamic_cast<InputParameters::Parameter<std::vector<MooseEnum>> *>(val);
     283     6639684 :     if (enum_type)
     284             :     {
     285         330 :       out_of_range_allowed = (enum_type->get())[0].isOutOfRangeAllowed();
     286         330 :       options = (enum_type->get())[0].getRawNames();
     287         330 :       docs = enum_type->get()[0].getItemDocumentation();
     288             :     }
     289             :   }
     290             :   {
     291     6639684 :     auto * enum_type = dynamic_cast<InputParameters::Parameter<std::vector<MultiMooseEnum>> *>(val);
     292     6639684 :     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     6639684 :   return options;
     300           0 : }
     301             : 
     302             : std::string
     303     4474698 : JsonSyntaxTree::buildOutputString(
     304             :     const std::iterator_traits<InputParameters::iterator>::value_type & p)
     305             : {
     306     4474698 :   libMesh::Parameters::Value * val = MooseUtils::get(p.second);
     307             : 
     308             :   // Account for Point
     309     4474698 :   std::stringstream str;
     310     4474698 :   InputParameters::Parameter<Point> * ptr0 = dynamic_cast<InputParameters::Parameter<Point> *>(val);
     311             : 
     312             :   // Account for RealVectorValues
     313             :   InputParameters::Parameter<RealVectorValue> * ptr1 =
     314     4474698 :       dynamic_cast<InputParameters::Parameter<RealVectorValue> *>(val);
     315             : 
     316             :   // Output the Point components
     317     4474698 :   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     4470134 :   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     4468154 :     val->print(str);
     329             : 
     330             :   // remove additional '\n' possibly generated in output (breaks JSON parsing)
     331     4474698 :   std::string tmp_str = str.str();
     332    20695818 :   for (auto & ch : tmp_str)
     333    16221120 :     if (ch == '\n')
     334           0 :       ch = ' ';
     335             : 
     336     8949396 :   return tmp_str.substr(0, tmp_str.find("<RESIDUAL>"));
     337     4474698 : }
     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     8501539 : JsonSyntaxTree::basicCppType(const std::string & cpp_type)
     367             : {
     368     8501539 :   std::string s = "String";
     369    15158565 :   if (cpp_type.find("std::vector") != std::string::npos ||
     370    13300858 :       cpp_type.find("libMesh::VectorValue") != std::string::npos ||
     371    21802397 :       cpp_type.find("libMesh::TensorValue") != std::string::npos ||
     372     6643509 :       cpp_type.find("Eigen::Matrix") != std::string::npos)
     373             :   {
     374             :     // Get the template type and use its basic type for the array type
     375     1861790 :     pcrecpp::RE r("^[^<]+<\\s*(.*)\\s*>$");
     376     1861790 :     std::string t;
     377     1861790 :     r.FullMatch(cpp_type, &t);
     378             : 
     379             :     // Capture type just to the first comma for Eigen::Matrix<type,V,W,X,Y,Z>
     380     1861790 :     if (cpp_type.find("Eigen::Matrix") != std::string::npos)
     381        3760 :       t = t.substr(0, t.find(","));
     382             : 
     383     1861790 :     s = "Array:" + basicCppType(t);
     384     1861790 :   }
     385    13074491 :   else if (cpp_type.find("MultiMooseEnum") != std::string::npos ||
     386    12690559 :            cpp_type.find("ExecFlagEnum") != std::string::npos ||
     387    19330308 :            cpp_type.find("VectorPostprocessorName") != std::string::npos ||
     388     6250867 :            cpp_type.find("std::map") != std::string::npos)
     389      393453 :     s = "Array:String";
     390     6246296 :   else if (cpp_type.find("libMesh::Point") != std::string::npos)
     391       26949 :     s = "Array:Real";
     392    18048937 :   else if (cpp_type == "int" || cpp_type == "unsigned int" || cpp_type == "short" ||
     393    17149500 :            cpp_type == "unsigned short" || cpp_type == "char" || cpp_type == "unsigned char" ||
     394    23724978 :            cpp_type == "long" || cpp_type == "unsigned long" || cpp_type == "long long" ||
     395     5700632 :            cpp_type == "unsigned long long")
     396      518715 :     s = "Integer";
     397     5700632 :   else if (cpp_type == "double" || cpp_type == "float")
     398      381570 :     s = "Real";
     399     5319062 :   else if (cpp_type == "bool")
     400     2172275 :     s = "Boolean";
     401             : 
     402     8501539 :   return s;
     403           0 : }
     404             : 
     405             : std::pair<std::string, std::string>
     406      364589 : JsonSyntaxTree::getObjectLabel(const std::string & obj) const
     407             : {
     408      364589 :   auto paths = splitPath(obj);
     409      364589 :   auto it = _object_label_map.find(paths.back());
     410      364589 :   if (it != _object_label_map.end())
     411      364589 :     return it->second;
     412             :   else
     413           0 :     return std::make_pair("", "");
     414      364589 : }
     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             : }

Generated by: LCOV version 1.14