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 "SONDefinitionFormatter.h" 11 : #include "MooseUtils.h" 12 : #include "pcrecpp.h" 13 : #include <algorithm> 14 : 15 130 : SONDefinitionFormatter::SONDefinitionFormatter() : _spaces(2), _level(0) {} 16 : 17 : // ******************************** toString ************************************ // 18 : // traverse the associated types array of cpp_types and absolute lookup paths and // 19 : // transform the paths to work with our parsed hierarchy and store pairs in a map // 20 : // of types to paths for use by InputChoices rule and store the global/parameters // 21 : // object then add root blocks recursively and return constructed stream's string // 22 : // ****************************************************************************** // 23 : std::string 24 130 : SONDefinitionFormatter::toString(const nlohmann::json & root) 25 : { 26 : 27 : const std::map<std::string, std::string> json_path_regex_replacement_map = { 28 : {"/star/subblock_types/([A-Za-z0-9_]*)/", "/\\1_type/"}, 29 : {"[A-Za-z0-9_]*/types/([A-Za-z0-9_]*)/", "\\1_type/"}, 30 : {"/actions/[A-Za-z0-9_]*/parameters/", "/"}, 31 : {"/parameters/", "/"}, 32 780 : {"/subblocks/", "/"}}; 33 : 34 5590 : for (const auto & el : root["global"]["associated_types"].items()) 35 : { 36 2730 : const auto & type = el.key(); 37 9490 : for (const auto & el_path : el.value().items()) 38 : { 39 3380 : std::string path = el_path.value(); 40 20280 : for (const auto & map_iter : json_path_regex_replacement_map) 41 16900 : pcrecpp::RE(map_iter.first).GlobalReplace(map_iter.second, &path); 42 3380 : _assoc_types_map[type].push_back(path); 43 6110 : } 44 130 : } 45 : 46 130 : _global_params = root["global"]["parameters"]; 47 130 : _stream.clear(); 48 130 : _stream.str(""); 49 9672 : for (const auto & el : root["blocks"].items()) 50 9672 : addBlock(el.key(), el.value()); 51 260 : return _stream.str(); 52 260 : } 53 : 54 : // ******************************** addLine ************************************* // 55 : // add a single new-line-terminated and indented line to the stream // 56 : // ****************************************************************************** // 57 : void 58 163169734 : SONDefinitionFormatter::addLine(const std::string & line) 59 : { 60 163169734 : _stream << line << "\n"; 61 163169734 : return; 62 : } 63 : 64 : // ******************************* addBlock ************************************* // 65 : // add parameters and recursively add NormalBlock children and TypeBlock children // 66 : // ****************************************************************************** // 67 : void 68 842595 : SONDefinitionFormatter::addBlock(const std::string & block_name, 69 : const nlohmann::json & block, 70 : bool is_typeblock, 71 : const std::string & parent_name, 72 : const nlohmann::json & parameters_in, 73 : const nlohmann::json & subblocks_in) 74 : { 75 : // open block with "_type" appended to the name if this is a TypeBlock because the 76 : // parser appends "_type" to the name of blocks with a "type=" parameter specified 77 842595 : addLine("'" + block_name + (is_typeblock ? "_type" : "") + "'{"); 78 842595 : _level++; 79 : 80 : // decide the actual block [./declarator] name that will be specified later unless 81 : // this is a StarBlock and then decide if this is a StarBlock or not for later use 82 : // - if TypeBlock : this will be the parent block name 83 : // - if NormalBlock : this will be this block name 84 842595 : std::string block_decl = (is_typeblock ? parent_name : block_name); 85 842595 : bool is_starblock = (block_decl == "*" ? true : false); 86 : 87 : // - add InputTmpl : the autocomplete template that is used for all block types 88 : // - add InputName : if is_typeblock then this will be dropped in after "type=" 89 : // - add InputType : block type - normal_top / normal_sub / type_top / type_sub 90 : // - add InputDefault : block [./declarator] name from above that will be used for 91 : // autocompletion of this block unless it is a StarBlock then 92 : // [./insert_name_here] will be used because any name is okay 93 842595 : addLine("InputTmpl=MooseBlock"); 94 842595 : addLine("InputName=\"" + block_name + "\""); 95 842595 : if (!is_typeblock) 96 49582 : addLine(_level == 1 ? "InputType=normal_top" : "InputType=normal_sub"); 97 : else 98 793013 : addLine(_level == 1 ? "InputType=type_top" : "InputType=type_sub"); 99 842595 : if (!is_starblock) 100 363324 : addLine("InputDefault=\"" + block_decl + "\""); 101 : else 102 479271 : addLine("InputDefault=\"insert_name_here\""); 103 : 104 : // add Description of block if it exists 105 842595 : std::string description = block.contains("description") ? block["description"] : ""; 106 842595 : pcrecpp::RE("\"").GlobalReplace("'", &description); 107 842595 : pcrecpp::RE("[\r\n]").GlobalReplace(" ", &description); 108 842595 : if (!description.empty()) 109 668278 : addLine("Description=\"" + description + "\""); 110 : 111 : // ensure every block has no more than one string declarator node and if this is a 112 : // TypeBlock but not a StarBlock then also ensure that the block [./declarator] is 113 : // the expected block_decl from above which should be the name of the parent block 114 842595 : addLine("decl{"); 115 842595 : _level++; 116 842595 : addLine("MaxOccurs=1"); 117 842595 : if (is_typeblock && !is_starblock) 118 329784 : addLine("ValEnums=[ \"" + block_decl + "\" ]"); 119 842595 : _level--; 120 842595 : addLine("}"); 121 : 122 : // if this block is the GlobalParams block then add a add "*/value" level 123 842595 : if (block_name == "GlobalParams") 124 : { 125 130 : addLine("'*'{"); 126 130 : _level++; 127 130 : addLine("'value'{"); 128 130 : addLine("}"); 129 130 : _level--; 130 130 : addLine("}"); 131 : } 132 : 133 : // store parameters --- 134 : // first : start with global parameters as a base 135 : // second : add or overwrite with any parameter inheritance 136 : // third : add or overwrite with any local RegularParameters 137 : // fourth : add or overwrite with any local ActionParameters 138 842595 : nlohmann::json parameters = _global_params; 139 4351295 : for (const auto & el : parameters_in.items()) 140 4351295 : parameters[el.key()] = el.value(); 141 842595 : if (block.contains("parameters")) 142 : { 143 12175709 : for (const auto & el : block["parameters"].items()) 144 12175709 : parameters[el.key()] = el.value(); 145 : } 146 : 147 842595 : if (block.contains("actions")) 148 : { 149 117962 : for (const auto & el : block["actions"].items()) 150 39884 : if (el.value().contains("parameters")) 151 314600 : for (const auto & param_el : el.value()["parameters"].items()) 152 352794 : parameters[param_el.key()] = param_el.value(); 153 : } 154 : 155 : // store NormalBlock children --- 156 : // first : start with any NormalBlock inheritance passed in as a base 157 : // second : add or overwrite these with any local NormalBlock children 158 : // third : add star named child block if it exists 159 842595 : nlohmann::json subblocks = subblocks_in; 160 842595 : if (block.contains("subblocks")) 161 : { 162 4550 : for (const auto & el : block["subblocks"].items()) 163 4550 : subblocks[el.key()] = el.value(); 164 : } 165 842595 : if (block.contains("star")) 166 13624 : subblocks["*"] = block["star"]; 167 : 168 : // store TypeBlock children --- 169 : // first : start with ["types"] child block as a base 170 : // second : add ["subblock_types"] child block 171 842595 : nlohmann::json typeblocks = block.contains("types") ? block["types"] : nlohmann::json(); 172 842595 : if (block.contains("subblock_types")) 173 479271 : for (const auto & el : block["subblock_types"].items()) 174 479271 : typeblocks[el.key()] = el.value(); 175 : 176 : // add parameters --- 177 : // if this block has a "type=" parameter with a specified default "type=" name and 178 : // if that default is also the name of a saved TypeBlock child then the parameters 179 : // belonging to that default saved TypeBlock child are added to this block as well 180 : // first : start with default saved TypeBlock child's RegularParameters as a base 181 : // second : add or overwrite with default saved TypeBlock child's ActionParameters 182 : // third : add or overwrite with parameters that were stored above for this block 183 : // fourth : either add newly stored parameters or add previously stored parameters 184 1622192 : if (parameters.contains("type") && parameters["type"].contains("default") && 185 2464787 : parameters["type"]["default"].is_string() && 186 1640912 : typeblocks.contains(parameters["type"]["default"].get<std::string>())) 187 : { 188 1560 : std::string type_default = parameters["type"]["default"].get<std::string>(); 189 1560 : const nlohmann::json & default_block = typeblocks[type_default]; 190 1560 : if (default_block.contains("parameters")) 191 : { 192 1560 : nlohmann::json default_child_params = default_block["parameters"]; 193 1560 : if (default_block.contains("actions")) 194 : { 195 0 : const nlohmann::json & default_actions = default_block["actions"]; 196 0 : for (const auto & el : default_actions.items()) 197 : { 198 0 : if (el.value().contains("parameters")) 199 0 : for (const auto & param_el : el.value()["parameters"].items()) 200 0 : default_child_params[param_el.key()] = param_el.value(); 201 0 : } 202 : } 203 : 204 : // unrequire the 'file' parameter added to the Mesh via the FileMesh TypeBlock 205 : // since MeshGenerators internally change the default block type from FileMesh 206 1690 : if (block_name == "Mesh" && default_child_params.contains("file") && 207 1820 : default_child_params["file"].contains("required") && 208 130 : default_child_params["file"]["required"].is_boolean()) 209 130 : default_child_params["file"]["required"] = false; 210 : 211 17420 : for (const auto & el : parameters.items()) 212 17420 : default_child_params[el.key()] = el.value(); 213 1560 : addParameters(default_child_params); 214 1560 : } 215 1560 : } 216 : else 217 841035 : addParameters(parameters); 218 : 219 : // add previously stored NormalBlocks children recursively 220 882635 : for (const auto & el : subblocks.items()) 221 882635 : addBlock(el.key(), el.value()); 222 : 223 : // close block now because the parser stores TypeBlock children at this same level 224 842595 : _level--; 225 842595 : addLine("} % end block " + block_name + (is_typeblock ? "_type" : "")); 226 : 227 : // add all previously stored TypeBlock children recursively and pass the parameter 228 : // and NormalBlock children added at this level in as inheritance to all TypeBlock 229 : // children so that they may each also add them and pass in the name of this block 230 : // as well so that all TypeBlock children can add a rule ensuring that their block 231 : // [./declarator] is the name of this parent block unless this block is named star 232 2428621 : for (const auto & el : typeblocks.items()) 233 1635608 : addBlock(el.key(), el.value(), true, block_name, parameters, subblocks); 234 842595 : } 235 : 236 : // ***************************** addParameters ********************************** // 237 : // add all of the information for each parameter of a block 238 : // - parameter :: add ChildAtLeastOne 239 : // - parameter :: add InputTmpl 240 : // - parameter :: add InputType 241 : // - parameter :: add InputName 242 : // - parameter :: add Description 243 : // - parameter :: add MinOccurs 244 : // - parameter :: add MaxOccurs 245 : // - parameter's value :: add MinOccurs 246 : // - parameter's value :: add MaxOccurs 247 : // - parameter's value :: add ValType 248 : // - parameter's value :: add ValEnums 249 : // - parameter's value :: add InputChoices (options) 250 : // - parameter's value :: add InputChoices (lookups) 251 : // - parameter's value :: add MinValInc 252 : // - parameter's value :: add InputDefault 253 : // ****************************************************************************** // 254 : void 255 842595 : SONDefinitionFormatter::addParameters(const nlohmann::json & params) 256 : { 257 : 258 : // build list of any '_object_params_set_by_action' that are not required in input 259 842595 : std::vector<std::string> action_set_params; 260 1097655 : if (params.contains("_object_params_set_by_action") && 261 255060 : params["_object_params_set_by_action"].contains("default")) 262 : { 263 255060 : std::string opsba = nlohmann::to_string(params["_object_params_set_by_action"]["default"]); 264 255060 : if (opsba.front() == '"' && opsba.back() == '"') 265 : { 266 255060 : opsba.erase(opsba.begin()); 267 255060 : opsba.pop_back(); 268 : } 269 255060 : action_set_params = MooseUtils::split(MooseUtils::trim(opsba), " "); 270 255060 : } 271 : 272 28382003 : for (const auto & el : params.items()) 273 : { 274 13769704 : auto & name = el.key(); 275 13769704 : auto & param = el.value(); 276 : 277 : // skip '_object_params_set_by_action' parameters because they will not be input 278 13769704 : if (name == "_object_params_set_by_action") 279 255060 : continue; 280 : 281 : // lambda to calculate relative path from the current level to the document root 282 2914964 : auto backtrack = [](int level) 283 : { 284 2914964 : std::string backtrack_path; 285 13283790 : for (int i = 0; i < level; ++i) 286 10368826 : backtrack_path += "../"; 287 2914964 : return backtrack_path; 288 0 : }; 289 : 290 : // capture the cpp_type and basic_type and strip off any unnecessary information 291 13514644 : std::string cpp_type = param["cpp_type"]; 292 13514644 : std::string basic_type = param["basic_type"]; 293 13514644 : bool is_array = false; 294 27019148 : if (cpp_type == "FunctionExpression" || cpp_type == "FunctionName" || 295 27019148 : basic_type.compare(0, 6, "Array:") == 0 || cpp_type.compare(0, 13, "Eigen::Matrix") == 0) 296 5264220 : is_array = true; 297 13514644 : pcrecpp::RE(".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace("\\1", &cpp_type); 298 13514644 : pcrecpp::RE("(Array:)*(.*)").GlobalReplace("\\2", &basic_type); 299 : 300 : // *** ChildAtLeastOne of parameter 301 : // if parameter is required, not action set, and no default exists, then specify 302 : // ChildAtLeastOne = [ "backtrack/GlobalParams/name/value" "name/value" ] 303 13514644 : auto def_ptr = param.find("default"); 304 13514644 : std::string def; 305 13514644 : if (def_ptr != param.end()) 306 9479587 : def = def_ptr->is_string() ? def_ptr->get<std::string>() : nlohmann::to_string(*def_ptr); 307 13514644 : def = MooseUtils::trim(def); 308 27029288 : if (param.contains("required") && 309 13514644 : std::find(action_set_params.begin(), action_set_params.end(), name) == 310 27029288 : action_set_params.end()) 311 : { 312 13267124 : bool required = param["required"]; 313 13267124 : if (required && def.empty()) 314 3588273 : addLine("ChildAtLeastOne=[ \"" + backtrack(_level) + "GlobalParams/" + name + 315 3588273 : "/value\" \"" + name + "\" ]"); 316 : } 317 : 318 : // *** open parameter 319 13514644 : addLine("'" + name + "'" + "{"); 320 13514644 : _level++; 321 : 322 : // *** InputTmpl of parameter 323 13514644 : addLine("InputTmpl=MooseParam"); 324 : 325 : // *** InputType of parameter 326 13514644 : if (is_array) 327 5264220 : addLine("InputType=key_array"); 328 : else 329 8250424 : addLine("InputType=key_value"); 330 : 331 : // *** InputName of parameter 332 13514644 : addLine("InputName=\"" + name + "\""); 333 : 334 : // *** Description of parameter 335 13514644 : if (param.contains("description")) 336 : { 337 13514644 : std::string description = param["description"]; 338 13514644 : pcrecpp::RE("\"").GlobalReplace("'", &description); 339 13514644 : pcrecpp::RE("[\r\n]").GlobalReplace(" ", &description); 340 13514644 : if (!description.empty()) 341 12702079 : addLine("Description=\"" + description + "\""); 342 13514644 : } 343 : 344 : // *** MaxOccurs=1 for each parameter 345 13514644 : addLine("MaxOccurs=1"); 346 : 347 : // *** open parameter's value 348 13514644 : addLine("'value'{"); 349 13514644 : _level++; 350 : 351 : // *** MinOccurs / MaxOccurs of parameter's value 352 : // is_array indicates the parameter value child may occur zero or multiple times 353 13514644 : if (!is_array) 354 : { 355 8250424 : addLine("MinOccurs=1"); 356 8250424 : addLine("MaxOccurs=1"); 357 : } 358 : 359 : // *** ValType of parameter's value 360 13514644 : if (basic_type == "Integer") 361 988845 : addLine("ValType=Int"); 362 12525799 : else if (basic_type == "Real") 363 985309 : addLine("ValType=Real"); 364 : 365 : // *** ValEnums / InputChoices of parameter's value 366 13514644 : if (basic_type.find("Boolean") != std::string::npos) 367 3710395 : addLine("ValEnums=[ true false 1 0 on off ]"); 368 : else 369 : { 370 9804249 : std::string options = param["options"]; 371 9804249 : if (!options.empty()) 372 : { 373 863837 : pcrecpp::RE(" ").GlobalReplace("\" \"", &options); 374 863837 : if (!param["out_of_range_allowed"]) 375 700531 : addLine("ValEnums=[ \"" + options + "\" ]"); 376 : else 377 163306 : addLine("InputChoices=[ \"" + options + "\" ]"); 378 : } 379 9804249 : } 380 : 381 : // *** InputChoices (lookups) of parameter's value 382 : // add any reserved_values then check if there are any paths associated with the 383 : // cpp_type in the assoc_types_map that was built before traversal and add those 384 : // paths relative to this node here as well 385 13514644 : std::string choices; 386 13514644 : if (param.contains("reserved_values")) 387 : { 388 268827 : for (const auto & reserved : param["reserved_values"]) 389 179218 : choices += nlohmann::to_string(reserved) + " "; 390 : } 391 : 392 15233517 : for (const auto & path : _assoc_types_map[cpp_type]) 393 1718873 : choices += "PATH:\"" + backtrack(_level) + path + "/decl\" "; 394 13514644 : if (!choices.empty()) 395 1220050 : addLine("InputChoices=[ " + choices + "]"); 396 : 397 : // *** MinValInc of parameter's value 398 13514644 : if (cpp_type.compare(0, 8, "unsigned") == 0 && basic_type == "Integer") 399 781482 : addLine("MinValInc=0"); 400 : 401 : // *** InputDefault of parameter's value 402 13514644 : if (!def.empty()) 403 7521709 : addLine("InputDefault=\"" + def + "\""); 404 : 405 : // *** close parameter's value 406 13514644 : _level--; 407 13514644 : addLine("}"); 408 : 409 : // *** close parameter 410 13514644 : _level--; 411 13514644 : addLine("}"); 412 14357239 : } 413 842595 : }