www.mooseframework.org
SONDefinitionFormatter.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 
15 
16 // ******************************** toString ************************************ //
17 // traverse the associated types array of cpp_types and absolute lookup paths and //
18 // transform the paths to work with our parsed hierarchy and store pairs in a map //
19 // of types to paths for use by the ExistsIn rule and store the global/parameters //
20 // object then add root blocks recursively and return constructed stream's string //
21 // ****************************************************************************** //
22 std::string
24 {
25 
26  const std::map<std::string, std::string> json_path_regex_replacement_map = {
27  {"/star/subblock_types/([A-Za-z0-9_]*)/", "/\\1_type/"},
28  {"[A-Za-z0-9_]*/types/([A-Za-z0-9_]*)/", "\\1_type/"},
29  {"/actions/[A-Za-z0-9_]*/parameters/", "/"},
30  {"/parameters/", "/"},
31  {"/subblocks/", "/"}};
32 
33  for (const auto & type : root["global"]["associated_types"].getMemberNames())
34  for (const auto & path_iter : root["global"]["associated_types"][type])
35  {
36  std::string path = path_iter.asString();
37  for (const auto & map_iter : json_path_regex_replacement_map)
38  pcrecpp::RE(map_iter.first).GlobalReplace(map_iter.second, &path);
39  _assoc_types_map[type].push_back(path);
40  }
41 
42  _global_params = root["global"]["parameters"];
43  _stream.clear();
44  _stream.str("");
45  for (const auto & name : root["blocks"].getMemberNames())
46  addBlock(name, root["blocks"][name]);
47  return _stream.str();
48 }
49 
50 // ******************************** addLine ************************************* //
51 // add a single new-line-terminated and indented line to the stream //
52 // ****************************************************************************** //
53 void
54 SONDefinitionFormatter::addLine(const std::string & line)
55 {
56  _stream << std::string(!line.empty() * _level * _spaces, ' ') << line << "\n";
57  return;
58 }
59 
60 // ******************************* addBlock ************************************* //
61 // add parameters and recursively add NormalBlock children and TypeBlock children //
62 // ****************************************************************************** //
63 void
64 SONDefinitionFormatter::addBlock(const std::string & block_name,
65  const JsonVal & block,
66  bool is_typeblock,
67  const std::string & parent_name,
68  const JsonVal & parameters_in,
69  const JsonVal & subblocks_in)
70 {
71 
72  // open block with "_type" appended to the name if this is a TypeBlock because the
73  // parser appends "_type" to the name of blocks with a "type=" parameter specified
74  addLine("'" + block_name + (is_typeblock ? "_type" : "") + "'{");
75  _level++;
76 
77  // decide the actual block [./declarator] name that will be specified later unless
78  // this is a StarBlock and then decide if this is a StarBlock or not for later use
79  // - if TypeBlock : this will be the parent block name
80  // - if NormalBlock : this will be this block name
81  std::string block_decl = (is_typeblock ? parent_name : block_name);
82  bool is_starblock = (block_decl == "*" ? true : false);
83 
84  // - add InputTmpl : the autocomplete template that is used for all block types
85  // - add InputName : if is_typeblock then this will be dropped in after "type="
86  // - add InputType : block type - normal_top / normal_sub / type_top / type_sub
87  // - add InputDefault : block [./declarator] name from above that will be used for
88  // autocompletion of this block unless it is a StarBlock then
89  // [./insert_name_here] will be used because any name is okay
90  addLine("InputTmpl=MooseBlock");
91  addLine("InputName=\"" + block_name + "\"");
92  if (!is_typeblock)
93  addLine(_level == 1 ? "InputType=normal_top" : "InputType=normal_sub");
94  else
95  addLine(_level == 1 ? "InputType=type_top" : "InputType=type_sub");
96  if (!is_starblock)
97  addLine("InputDefault=\"" + block_decl + "\"");
98  else
99  addLine("InputDefault=\"insert_name_here\"");
100 
101  // add Description of block if it exists
102  std::string description = block["description"].asString();
103  pcrecpp::RE("\"").GlobalReplace("'", &description);
104  pcrecpp::RE("[\r\n]").GlobalReplace(" ", &description);
105  if (!description.empty())
106  addLine("Description=\"" + description + "\"");
107 
108  // add MinOccurs : optional because nothing available to specify block requirement
109  addLine("MinOccurs=0");
110 
111  // add MaxOccurs : if a StarBlock then no limit / otherwise maximum one occurrence
112  addLine(is_starblock ? "MaxOccurs=NoLimit" : "MaxOccurs=1");
113 
114  // ensure block has one string declarator node and if this is not a StarBlock then
115  // also ensure that the block [./declarator] is the expected block_decl from above
116  addLine("decl{");
117  _level++;
118  addLine("MinOccurs=1");
119  addLine("MaxOccurs=1");
120  addLine("ValType=String");
121  if (!is_starblock)
122  addLine("ValEnums=[ \"" + block_decl + "\" ]");
123  _level--;
124  addLine("}");
125 
126  // if this block is the GlobalParams block then add a add "*/value" level
127  if (block_name == "GlobalParams")
128  {
129  addLine("'*'{");
130  _level++;
131  addLine("'value'{");
132  addLine("}");
133  _level--;
134  addLine("} % end *");
135  }
136 
137  // store parameters ---
138  // first : start with global parameters as a base
139  // second : add or overwrite with any parameter inheritance
140  // third : add or overwrite with any local RegularParameters
141  // fourth : add or overwrite with any local ActionParameters
142  JsonVal parameters = _global_params;
143  for (const auto & name : parameters_in.getMemberNames())
144  parameters[name] = parameters_in[name];
145  for (const auto & name : block["parameters"].getMemberNames())
146  parameters[name] = block["parameters"][name];
147  for (const auto & act : block["actions"].getMemberNames())
148  for (const auto & param : block["actions"][act]["parameters"].getMemberNames())
149  parameters[param] = block["actions"][act]["parameters"][param];
150 
151  // store NormalBlock children ---
152  // first : start with any NormalBlock inheritance passed in as a base
153  // second : add or overwrite these with any local NormalBlock children
154  // third : add star named child block if it exists
155  JsonVal subblocks = subblocks_in;
156  for (const auto & name : block["subblocks"].getMemberNames())
157  subblocks[name] = block["subblocks"][name];
158  if (block.isMember("star"))
159  subblocks["*"] = block["star"];
160 
161  // store TypeBlock children ---
162  // first : start with ["types"] child block as a base
163  // second : add ["subblock_types"] child block
164  JsonVal typeblocks = block["types"];
165  for (const auto & name : block["subblock_types"].getMemberNames())
166  typeblocks[name] = block["subblock_types"][name];
167 
168  // add parameters ---
169  // if this block has a "type=" parameter with a specified default "type=" name and
170  // if that default is also the name of a ["types"] child block then the parameters
171  // belonging to that default ["types"] child block are added to this block as well
172  // first : start with default ["types"] child block's RegularParameters as a base
173  // second : add or overwrite with default ["types"] child block's ActionParameters
174  // third : add or overwrite with parameters that were stored above for this block
175  // fourth : either add newly stored parameters or add previously stored parameters
176  if (parameters.isMember("type") && parameters["type"].isMember("default") &&
177  block["types"].isMember(parameters["type"]["default"].asString()))
178  {
179  std::string type_default = parameters["type"]["default"].asString();
180  const JsonVal & default_block = block["types"][type_default];
181  JsonVal default_child_params = default_block["parameters"];
182  const JsonVal & default_actions = default_block["actions"];
183  for (const auto & act : default_actions.getMemberNames())
184  for (const auto & param : default_actions[act]["parameters"].getMemberNames())
185  default_child_params[param] = default_actions[act]["parameters"][param];
186  for (const auto & name : parameters.getMemberNames())
187  default_child_params[name] = parameters[name];
188  addParameters(default_child_params);
189  }
190  else
191  addParameters(parameters);
192 
193  // add previously stored NormalBlocks children recursively
194  for (const auto & name : subblocks.getMemberNames())
195  addBlock(name, subblocks[name]);
196 
197  // close block now because the parser stores TypeBlock children at this same level
198  _level--;
199  addLine("} % end block " + block_name + (is_typeblock ? "_type" : ""));
200 
201  // add all previously stored TypeBlock children recursively and pass the parameter
202  // and NormalBlock children added at this level in as inheritance to all TypeBlock
203  // children so that they may each also add them and pass in the name of this block
204  // as well so that all TypeBlock children can add a rule ensuring that their block
205  // [./declarator] is the name of this parent block unless this block is named star
206  for (const auto & name : typeblocks.getMemberNames())
207  addBlock(name, typeblocks[name], true, block_name, parameters, subblocks);
208 }
209 
210 // ***************************** addParameters ********************************** //
211 // add all of the information for each parameter of a block
212 // - parameter :: add ChildAtLeastOne
213 // - parameter :: add InputTmpl
214 // - parameter :: add InputType
215 // - parameter :: add InputName
216 // - parameter :: add Description
217 // - parameter :: add MinOccurs
218 // - parameter :: add MaxOccurs
219 // - parameter's value :: add MinOccurs
220 // - parameter's value :: add MaxOccurs
221 // - parameter's value :: add ValType
222 // - parameter's value :: add ValEnums
223 // - parameter's value :: add InputChoices
224 // - parameter's value :: add ExistsIn
225 // - parameter's value :: add MinValInc
226 // - parameter's value :: add InputDefault
227 // ****************************************************************************** //
228 void
230 {
231 
232  for (const auto & name : params.getMemberNames())
233  {
234 
235  JsonVal param = params[name];
236 
237  // lambda to calculate relative path from the current level to the document root
238  auto backtrack = [](int level) {
239  std::string backtrack_path;
240  for (int i = 0; i < level; ++i)
241  backtrack_path += "../";
242  return backtrack_path;
243  };
244 
245  // capture the cpp_type and basic_type and strip off any unnecessary information
246  std::string cpp_type = param["cpp_type"].asString();
247  std::string basic_type = param["basic_type"].asString();
248  bool is_array = false;
249  if (cpp_type == "FunctionExpression" || basic_type.compare(0, 6, "Array:") == 0)
250  is_array = true;
251  pcrecpp::RE(".+<([A-Za-z0-9_' ':]*)>.*").GlobalReplace("\\1", &cpp_type);
252  pcrecpp::RE("(Array:)*(.*)").GlobalReplace("\\2", &basic_type);
253 
254  // *** ChildAtLeastOne of parameter
255  // if parameter is required and no default exists then outside its level specify
256  // ChildAtLeastOne = [ "backtrack/GlobalParams/name/value" "name/value" ]
257  bool required = param["required"].asBool();
258  std::string def = MooseUtils::trim(param["default"].asString());
259  if (required && def.empty())
260  addLine("ChildAtLeastOne=[ \"" + backtrack(_level) + "GlobalParams/" + name +
261  "/value\" \"" + name + "/value\"" + " ]");
262 
263  // *** open parameter
264  addLine("'" + name + "'" + "{");
265  _level++;
266 
267  // *** InputTmpl of parameter
268  addLine("InputTmpl=MooseParam");
269 
270  // *** InputType of parameter
271  if (is_array)
272  addLine("InputType=key_array");
273  else
274  addLine("InputType=key_value");
275 
276  // *** InputName of parameter
277  addLine("InputName=\"" + name + "\"");
278 
279  // *** Description of parameter
280  std::string description = param["description"].asString();
281  pcrecpp::RE("\"").GlobalReplace("'", &description);
282  pcrecpp::RE("[\r\n]").GlobalReplace(" ", &description);
283  if (!description.empty())
284  addLine("Description=\"" + description + "\"");
285 
286  // *** MinOccurs / MaxOccurs of parameter
287  addLine("MinOccurs=0");
288  addLine("MaxOccurs=1");
289 
290  // *** open parameter's value
291  addLine("'value'{");
292  _level++;
293 
294  // *** MinOccurs / MaxOccurs of parameter's value
295  addLine("MinOccurs=1");
296  addLine(is_array ? "MaxOccurs=NoLimit" : "MaxOccurs=1");
297 
298  // *** ValType of parameter's value
299  if (basic_type == "Integer")
300  addLine("ValType=Int");
301  else if (basic_type == "Real")
302  addLine("ValType=Real");
303  else
304  addLine("ValType=String");
305 
306  // *** ValEnums / InputChoices of parameter's value
307  if (basic_type.find("Boolean") != std::string::npos)
308  addLine("ValEnums=[ true false 1 0 ]");
309  else
310  {
311  std::string options = param["options"].asString();
312  if (!options.empty())
313  {
314  pcrecpp::RE(" ").GlobalReplace("\" \"", &options);
315  if (!param["out_of_range_allowed"].asBool())
316  addLine("ValEnums=[ \"" + options + "\" ]");
317  else
318  addLine("InputChoices=[ \"" + options + "\" ]");
319  }
320  }
321 
322  // *** ExistsIn of parameter's value
323  // add any reserved_values and if this parameter's above transformed cpp_type is
324  // "FunctionName" then add an ExpressionsAreOkay flag and check if there are any
325  // paths associated with the cpp_type in the map that was built before traversal
326  // then add those paths relative to this node here as well
327  std::string paths;
328  for (const auto & reserved : param["reserved_values"])
329  paths += "EXTRA:\"" + reserved.asString() + "\" ";
330  if (cpp_type == "FunctionName")
331  paths += "EXTRA:\"ExpressionsAreOkay\" ";
332  for (const auto & path : _assoc_types_map[cpp_type])
333  paths += "\"" + backtrack(_level) + path + "/decl\" ";
334  if (!paths.empty())
335  addLine("ExistsIn=[ " + paths + "]");
336 
337  // *** MinValInc of parameter's value
338  if (cpp_type.compare(0, 8, "unsigned") == 0 && basic_type == "Integer")
339  addLine("MinValInc=0");
340 
341  // *** InputDefault of parameter's value
342  if (!def.empty())
343  addLine("InputDefault=\"" + def + "\"");
344 
345  // *** close parameter's value
346  _level--;
347  addLine("}");
348 
349  // *** close parameter
350  _level--;
351  addLine("} % end parameter " + name);
352  }
353 }
void addParameters(const JsonVal &params)
adds all parameters from a given block
moosecontrib::Json::Value JsonVal
std::string toString(const JsonVal &root)
returns a string representation of the tree in input file format
std::map< std::string, std::vector< std::string > > _assoc_types_map
std::string trim(const std::string &str, const std::string &white_space=" \\\)
Standard scripting language trim function.
Definition: MooseUtils.C:113
void addLine(const std::string &line)
adds a line to the output with the proper indentation automatically
void addBlock(const std::string &block_name, const JsonVal &block, bool is_typeblock=false, const std::string &parent_name="", const JsonVal &parameters_in=JsonVal::null, const JsonVal &subblocks_in=JsonVal::null)
adds a new block to the output
MatType type