LCOV - code coverage report
Current view: top level - src/utils - JsonSyntaxTree.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #31730 (e8b711) with base e0c998 Lines: 240 246 97.6 %
Date: 2025-10-29 16:49:47 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       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(&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      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             : }

Generated by: LCOV version 1.14