Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_YamlParser.cpp
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Teuchos: Common Tools Package
6 // Copyright (2004) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Dan Ibanez (daibane@sandia.gov)
40 //
41 // ***********************************************************************
42 //
43 // @HEADER
44 
45 #include <iostream>
46 #include <iomanip>
47 #include <ios>
48 #include <sstream>
49 #include <cctype>
50 #include <fstream>
51 
55 #include "Teuchos_TwoDArray.hpp"
56 
57 #include "Teuchos_Reader.hpp"
58 #include "Teuchos_YAML.hpp"
59 
60 namespace Teuchos {
61 
62 std::string remove_trailing_whitespace(std::string const& in) {
63  std::size_t new_end = 0;
64  for (std::size_t ri = 0; ri < in.size(); ++ri) {
65  std::size_t i = in.size() - 1 - ri;
66  if (in[i] != ' ' && in[i] != '\t') {
67  new_end = i + 1;
68  break;
69  }
70  }
71  return in.substr(0, new_end);
72 }
73 
74 std::string remove_trailing_whitespace_and_newlines(std::string const& in) {
75  std::size_t new_end = 0;
76  for (std::size_t ri = 0; ri < in.size(); ++ri) {
77  std::size_t i = in.size() - 1 - ri;
78  if (in[i] != ' ' && in[i] != '\t' && in[i] != '\n' && in[i] != '\r') {
79  new_end = i + 1;
80  break;
81  }
82  }
83  return in.substr(0, new_end);
84 }
85 
86 template <typename T>
87 bool is_parseable_as(std::string const& text) {
88  std::istringstream ss(text);
89  T val;
90  ss >> std::noskipws >> val;
91  return ss.eof() && !ss.fail();
92 }
93 
94 template <>
95 bool is_parseable_as<int>(std::string const& text) {
96  std::istringstream ss(text);
97  using LL = long long;
98  LL val;
99  ss >> std::noskipws >> val;
100  return ss.eof() && !ss.fail() &&
101  (val >= LL(std::numeric_limits<int>::min())) &&
102  (val <= LL(std::numeric_limits<int>::max()));
103 }
104 
105 template <typename T>
106 T parse_as(std::string const& text) {
107  std::istringstream ss(text);
108  T value;
109  ss >> value;
110  return value;
111 }
112 
113 // http://en.cppreference.com/w/cpp/string/byte/tolower
114 static char my_tolower(char ch)
115 {
116  return std::tolower(static_cast<unsigned char>(ch));
117 }
118 
119 // http://en.cppreference.com/w/cpp/string/byte/isdigit
120 static bool my_isdigit(char ch)
121 {
122  return std::isdigit(static_cast<unsigned char>(ch));
123 }
124 
125 template <>
126 bool is_parseable_as<bool>(std::string const& text) {
127  std::string lower;
128  for (std::size_t i = 0; i < text.size(); ++i) {
129  lower.push_back(my_tolower(text[i]));
130  }
131  return lower == "true" || lower == "yes" ||
132  lower == "false" || lower == "no";
133 }
134 
135 template <>
136 bool parse_as<bool>(std::string const& text) {
137  std::string lower;
138  for (std::size_t i = 0; i < text.size(); ++i) {
139  lower.push_back(my_tolower(text[i]));
140  }
141  return !(lower == "false" || lower == "no");
142 }
143 
144 struct PLPair {
145  std::string key;
146  ParameterEntry value;
147 };
148 
149 struct Scalar {
150  enum Source {
151  RAW,
152  DQUOTED,
153  SQUOTED,
154  BLOCK
155  };
156  /* order matters, a higher type should be convertible to a lower type */
157  enum Type {
158  STRING = 0,
159  DOUBLE = 1,
160  LONG_LONG = 2,
161  INT = 3,
162  BOOL = 4
163  };
164  int source;
165  int tag_type;
166  std::string text;
167  int infer_type() const {
168  if (tag_type != -1) {
169  return tag_type;
170  }
171  if (source != RAW) {
172  return STRING;
173  }
174  if (is_parseable_as<bool>(text)) {
175  return BOOL;
176  }
177  if (is_parseable_as<int>(text)) {
178  return INT;
179  }
180  if (is_parseable_as<long long>(text)) {
181  return LONG_LONG;
182  }
183  if (is_parseable_as<double>(text)) {
184  return DOUBLE;
185  }
186  return STRING;
187  }
188 };
189 
190 bool operator==(Scalar const&, Scalar const&) { return false; }
191 std::ostream& operator<<(std::ostream& os, Scalar const&) { return os; }
192 
193 void safe_set_entry(ParameterList& list, std::string const& name_in, ParameterEntry const& entry_in) {
194  TEUCHOS_TEST_FOR_EXCEPTION(list.isParameter(name_in), ParserFail,
195  "Parameter \"" << name_in << "\" already exists in list \"" << list.name() << "\"\n");
196  list.setEntry(name_in, entry_in);
197 }
198 
199 namespace YAMLParameterList {
200 
201 class Reader : public Teuchos::Reader {
202  public:
203  Reader():Teuchos::Reader(Teuchos::YAML::ask_reader_tables()) {}
204  virtual ~Reader() {}
205  protected:
206  enum {
207  TRIM_NORMAL,
208  TRIM_DASH
209  };
210  virtual void at_shift(any& result_any, int token, std::string& text) {
211  using std::swap;
212  switch (token) {
213  case Teuchos::YAML::TOK_NEWLINE: {
214  std::string& result = make_any_ref<std::string>(result_any);
215  swap(result, text);
216  break;
217  }
218  case Teuchos::YAML::TOK_SPACE:
219  case Teuchos::YAML::TOK_OTHER: {
220  result_any = text.at(0);
221  break;
222  }
223  }
224  }
225  virtual void at_reduce(any& result_any, int prod, std::vector<any>& rhs) {
226  using std::swap;
227  switch (prod) {
228  case Teuchos::YAML::PROD_DOC:
229  case Teuchos::YAML::PROD_DOC2: {
230  std::size_t offset = prod == Teuchos::YAML::PROD_DOC2 ? 1 : 0;
231  TEUCHOS_ASSERT(!rhs.at(offset).empty());
232  swap(result_any, rhs.at(offset));
233  TEUCHOS_ASSERT(result_any.type() == typeid(ParameterList));
234  break;
235  }
236  case Teuchos::YAML::PROD_TOP_BMAP: {
237  TEUCHOS_ASSERT(!rhs.at(0).empty());
238  TEUCHOS_ASSERT(rhs.at(0).type() == typeid(PLPair));
239  PLPair& pair = any_ref_cast<PLPair>(rhs.at(0));
240  any& pair_rhs_any = pair.value.getAny(/* set isUsed = */ false);
241  result_any = pair_rhs_any;
242  break;
243  }
244  case Teuchos::YAML::PROD_TOP_FIRST: {
245  if (rhs.at(0).type() == typeid(ParameterList)) {
246  swap(result_any, rhs.at(0));
247  }
248  break;
249  }
250  case Teuchos::YAML::PROD_TOP_NEXT: {
251  if (rhs.at(1).type() == typeid(ParameterList)) {
252  TEUCHOS_TEST_FOR_EXCEPTION(!rhs.at(0).empty(), ParserFail,
253  "Can't specify multiple top-level ParameterLists in one YAML file!\n");
254  swap(result_any, rhs.at(1));
255  } else {
256  swap(result_any, rhs.at(0));
257  }
258  break;
259  }
260  case Teuchos::YAML::PROD_BMAP_FIRST:
261  case Teuchos::YAML::PROD_FMAP_FIRST: {
262  TEUCHOS_ASSERT(rhs.at(0).type() == typeid(PLPair));
263  map_first_item(result_any, rhs.at(0));
264  TEUCHOS_ASSERT(result_any.type() == typeid(ParameterList));
265  break;
266  }
267  case Teuchos::YAML::PROD_BMAP_NEXT: {
268  map_next_item(result_any, rhs.at(0), rhs.at(1));
269  break;
270  }
271  case Teuchos::YAML::PROD_FMAP_NEXT: {
272  map_next_item(result_any, rhs.at(0), rhs.at(3));
273  break;
274  }
275  case Teuchos::YAML::PROD_BMAP_SCALAR:
276  case Teuchos::YAML::PROD_FMAP_SCALAR:
277  case Teuchos::YAML::PROD_FMAP_FMAP:
278  case Teuchos::YAML::PROD_FMAP_FSEQ: {
279  int scalar_type = interpret_tag(rhs.at(3));
280  map_item(result_any, rhs.at(0), rhs.at(4), scalar_type);
281  break;
282  }
283  case Teuchos::YAML::PROD_BMAP_BSCALAR: {
284  map_item(result_any, rhs.at(0), rhs.at(3), Scalar::STRING);
285  break;
286  }
287  case Teuchos::YAML::PROD_BMAP_BVALUE: {
288  map_item(result_any, rhs.at(0), rhs.at(4));
289  break;
290  }
291  case Teuchos::YAML::PROD_BVALUE_EMPTY: {
292  result_any = ParameterList();
293  break;
294  }
295  case Teuchos::YAML::PROD_BVALUE_BMAP:
296  case Teuchos::YAML::PROD_BVALUE_BSEQ: {
297  swap(result_any, rhs.at(1));
298  break;
299  }
300  case Teuchos::YAML::PROD_BMAP_FMAP: {
301  map_item(result_any, rhs.at(0), rhs.at(4));
302  break;
303  }
304  case Teuchos::YAML::PROD_BMAP_FSEQ: {
305  TEUCHOS_ASSERT(rhs.at(4).type() == typeid(Array<Scalar>) ||
306  rhs.at(4).type() == typeid(Array<Array<Scalar>>));
307  int scalar_type = interpret_tag(rhs.at(3));
308  map_item(result_any, rhs.at(0), rhs.at(4), scalar_type);
309  break;
310  }
311  case Teuchos::YAML::PROD_BSEQ_FIRST: {
312  seq_first_item(result_any, rhs.at(0));
313  break;
314  }
315  case Teuchos::YAML::PROD_BSEQ_NEXT: {
316  seq_next_item(result_any, rhs.at(0), rhs.at(1));
317  break;
318  }
319  case Teuchos::YAML::PROD_BSEQ_SCALAR: {
320  swap(result_any, rhs.at(3));
321  Scalar& scalar = any_ref_cast<Scalar>(result_any);
322  scalar.tag_type = interpret_tag(rhs.at(2));
323  break;
324  }
325  case Teuchos::YAML::PROD_BSEQ_BSCALAR: {
326  swap(result_any, rhs.at(2));
327  break;
328  }
329  case Teuchos::YAML::PROD_BSEQ_BMAP:
330  case Teuchos::YAML::PROD_BSEQ_BMAP_TRAIL:
331  case Teuchos::YAML::PROD_BSEQ_FMAP: {
332  throw ParserFail("Can't interpret a map inside a sequence as a Teuchos Parameter");
333  }
334  case Teuchos::YAML::PROD_BSEQ_BSEQ: {
335  swap(result_any, rhs.at(3));
336  break;
337  }
338  case Teuchos::YAML::PROD_BSEQ_BSEQ_TRAIL: {
339  swap(result_any, rhs.at(4));
340  break;
341  }
342  case Teuchos::YAML::PROD_BSEQ_FSEQ: {
343  swap(result_any, rhs.at(3));
344  break;
345  }
346  case Teuchos::YAML::PROD_FMAP: {
347  swap(result_any, rhs.at(2));
348  break;
349  }
350  case Teuchos::YAML::PROD_FMAP_EMPTY: {
351  result_any = ParameterList();
352  break;
353  }
354  case Teuchos::YAML::PROD_FSEQ: {
355  swap(result_any, rhs.at(2));
356  TEUCHOS_ASSERT(result_any.type() == typeid(Array<Scalar>) ||
357  result_any.type() == typeid(Array<Array<Scalar>>));
358  break;
359  }
360  case Teuchos::YAML::PROD_FSEQ_EMPTY: {
361  result_any = Array<Scalar>();
362  break;
363  }
364  case Teuchos::YAML::PROD_FSEQ_FIRST: {
365  seq_first_item(result_any, rhs.at(0));
366  break;
367  }
368  case Teuchos::YAML::PROD_FSEQ_NEXT: {
369  seq_next_item(result_any, rhs.at(0), rhs.at(3));
370  break;
371  }
372  case Teuchos::YAML::PROD_FSEQ_SCALAR: {
373  swap(result_any, rhs.at(1));
374  Scalar& scalar = any_ref_cast<Scalar>(result_any);
375  scalar.tag_type = interpret_tag(rhs.at(0));
376  break;
377  }
378  case Teuchos::YAML::PROD_FSEQ_FSEQ:
379  case Teuchos::YAML::PROD_FSEQ_FMAP: {
380  swap(result_any, rhs.at(1));
381  break;
382  }
383  case Teuchos::YAML::PROD_SCALAR_QUOTED:
384  case Teuchos::YAML::PROD_MAP_SCALAR_QUOTED: {
385  swap(result_any, rhs.at(0));
386  break;
387  }
388  case Teuchos::YAML::PROD_SCALAR_RAW:
389  case Teuchos::YAML::PROD_MAP_SCALAR_RAW: {
390  Scalar& scalar = make_any_ref<Scalar>(result_any);
391  TEUCHOS_ASSERT(!rhs.at(0).empty());
392  scalar.text = any_ref_cast<std::string>(rhs.at(0));
393  scalar.text += any_ref_cast<std::string>(rhs.at(1));
394  if (prod == Teuchos::YAML::PROD_MAP_SCALAR_RAW) {
395  scalar.text += any_ref_cast<std::string>(rhs.at(2));
396  }
397  scalar.text = remove_trailing_whitespace(scalar.text);
398  scalar.source = Scalar::RAW;
399  scalar.tag_type = -1;
400  break;
401  }
402  case Teuchos::YAML::PROD_SCALAR_HEAD_OTHER:
403  case Teuchos::YAML::PROD_SCALAR_HEAD_DOT:
404  case Teuchos::YAML::PROD_SCALAR_HEAD_DASH:
405  case Teuchos::YAML::PROD_SCALAR_HEAD_DOT_DOT: {
406  std::size_t offset;
407  if (prod == Teuchos::YAML::PROD_SCALAR_HEAD_OTHER) offset = 0;
408  else if (prod == Teuchos::YAML::PROD_SCALAR_HEAD_DOT_DOT) offset = 2;
409  else offset = 1;
410  char second = any_cast<char>(rhs.at(offset));
411  std::string& result = make_any_ref<std::string>(result_any);
412  if (prod == Teuchos::YAML::PROD_SCALAR_HEAD_DOT) result += '.';
413  else if (prod == Teuchos::YAML::PROD_SCALAR_HEAD_DASH) result += '-';
414  else if (prod == Teuchos::YAML::PROD_SCALAR_HEAD_DOT_DOT) result += "..";
415  result += second;
416  break;
417  }
418  case Teuchos::YAML::PROD_SCALAR_DQUOTED:
419  case Teuchos::YAML::PROD_SCALAR_SQUOTED: {
420  std::string& first = any_ref_cast<std::string>(rhs.at(1));
421  std::string& rest = any_ref_cast<std::string>(rhs.at(2));
422  Scalar& scalar = make_any_ref<Scalar>(result_any);
423  scalar.text += first;
424  scalar.text += rest;
425  if (prod == Teuchos::YAML::PROD_SCALAR_DQUOTED) {
426  scalar.source = Scalar::DQUOTED;
427  } else if (prod == Teuchos::YAML::PROD_SCALAR_SQUOTED) {
428  scalar.source = Scalar::SQUOTED;
429  }
430  scalar.tag_type = -1;
431  break;
432  }
433  case Teuchos::YAML::PROD_MAP_SCALAR_ESCAPED_EMPTY: {
434  result_any = std::string();
435  break;
436  }
437  case Teuchos::YAML::PROD_MAP_SCALAR_ESCAPED_NEXT: {
438  swap(result_any, rhs.at(0));
439  std::string& str = any_ref_cast<std::string>(result_any);
440  str += ',';
441  str += any_ref_cast<std::string>(rhs.at(2));
442  break;
443  }
444  case Teuchos::YAML::PROD_TAG: {
445  swap(result_any, rhs.at(2));
446  break;
447  }
448  case Teuchos::YAML::PROD_BSCALAR: {
449  std::size_t parent_indent_level =
450  this->symbol_indentation_stack.at(
451  this->symbol_indentation_stack.size() - 5);
452  std::string& header = any_ref_cast<std::string>(rhs.at(0));
453  std::string& leading_empties_or_comments =
454  any_ref_cast<std::string>(rhs.at(2));
455  std::string& rest = any_ref_cast<std::string>(rhs.at(4));
456  std::string& content = make_any_ref<std::string>(result_any);
457  std::string comment;
458  handle_block_scalar(
459  parent_indent_level,
460  header, leading_empties_or_comments, rest,
461  content, comment);
462  break;
463  }
464  case Teuchos::YAML::PROD_BSCALAR_FIRST: {
465  swap(result_any, rhs.at(0));
466  break;
467  }
468  // all these cases reduce to concatenating two strings
469  case Teuchos::YAML::PROD_BSCALAR_NEXT:
470  case Teuchos::YAML::PROD_BSCALAR_LINE:
471  case Teuchos::YAML::PROD_DESCAPE_NEXT:
472  case Teuchos::YAML::PROD_SESCAPE_NEXT: {
473  swap(result_any, rhs.at(0));
474  std::string& str = any_ref_cast<std::string>(result_any);
475  str += any_ref_cast<std::string>(rhs.at(1));
476  break;
477  }
478  case Teuchos::YAML::PROD_BSCALAR_INDENT: {
479  swap(result_any, rhs.at(1));
480  break;
481  }
482  case Teuchos::YAML::PROD_BSCALAR_HEADER_LITERAL:
483  case Teuchos::YAML::PROD_BSCALAR_HEADER_FOLDED: {
484  std::string& result = make_any_ref<std::string>(result_any);
485  if (prod == Teuchos::YAML::PROD_BSCALAR_HEADER_LITERAL) {
486  result += "|";
487  } else {
488  result += ">";
489  }
490  std::string& rest = any_ref_cast<std::string>(rhs.at(1));
491  result += rest;
492  break;
493  }
494  case Teuchos::YAML::PROD_DESCAPE: {
495  std::string& str = make_any_ref<std::string>(result_any);
496  std::string& rest = any_ref_cast<std::string>(rhs.at(2));
497  str += any_cast<char>(rhs.at(1));
498  str += rest;
499  break;
500  }
501  case Teuchos::YAML::PROD_SESCAPE: {
502  std::string& str = make_any_ref<std::string>(result_any);
503  std::string& rest = any_ref_cast<std::string>(rhs.at(2));
504  str += '\'';
505  str += rest;
506  break;
507  }
508  case Teuchos::YAML::PROD_OTHER_FIRST:
509  case Teuchos::YAML::PROD_SPACE_PLUS_FIRST: {
510  std::string& str = make_any_ref<std::string>(result_any);
511  str.push_back(any_cast<char>(rhs.at(0)));
512  break;
513  }
514  case Teuchos::YAML::PROD_SCALAR_TAIL_SPACE:
515  case Teuchos::YAML::PROD_SCALAR_TAIL_OTHER:
516  case Teuchos::YAML::PROD_DESCAPED_DQUOTED:
517  case Teuchos::YAML::PROD_DQUOTED_COMMON:
518  case Teuchos::YAML::PROD_SQUOTED_COMMON:
519  case Teuchos::YAML::PROD_ANY_COMMON:
520  case Teuchos::YAML::PROD_COMMON_SPACE:
521  case Teuchos::YAML::PROD_COMMON_OTHER:
522  case Teuchos::YAML::PROD_BSCALAR_HEAD_OTHER: {
523  swap(result_any, rhs.at(0));
524  break;
525  }
526  // all these cases reduce to appending a character
527  case Teuchos::YAML::PROD_DQUOTED_NEXT:
528  case Teuchos::YAML::PROD_SQUOTED_NEXT:
529  case Teuchos::YAML::PROD_ANY_NEXT:
530  case Teuchos::YAML::PROD_SCALAR_TAIL_NEXT:
531  case Teuchos::YAML::PROD_SPACE_STAR_NEXT:
532  case Teuchos::YAML::PROD_SPACE_PLUS_NEXT:
533  case Teuchos::YAML::PROD_BSCALAR_HEAD_NEXT: {
534  TEUCHOS_TEST_FOR_EXCEPTION(rhs.at(0).empty(), ParserFail,
535  "leading characters in " << prod << ": any was empty\n");
536  swap(result_any, rhs.at(0));
537  std::string& str = any_ref_cast<std::string>(result_any);
538  str += any_cast<char>(rhs.at(1));
539  break;
540  }
541  case Teuchos::YAML::PROD_DQUOTED_EMPTY:
542  case Teuchos::YAML::PROD_SQUOTED_EMPTY:
543  case Teuchos::YAML::PROD_ANY_EMPTY:
544  case Teuchos::YAML::PROD_DESCAPE_EMPTY:
545  case Teuchos::YAML::PROD_SESCAPE_EMPTY:
546  case Teuchos::YAML::PROD_SCALAR_TAIL_EMPTY:
547  case Teuchos::YAML::PROD_SPACE_STAR_EMPTY:
548  case Teuchos::YAML::PROD_BSCALAR_HEAD_EMPTY: {
549  result_any = std::string();
550  break;
551  }
552  case Teuchos::YAML::PROD_DESCAPED_DQUOT:
553  case Teuchos::YAML::PROD_SQUOTED_DQUOT:
554  case Teuchos::YAML::PROD_ANY_DQUOT: {
555  result_any = '"';
556  break;
557  }
558  case Teuchos::YAML::PROD_DESCAPED_SLASH:
559  case Teuchos::YAML::PROD_SQUOTED_SLASH:
560  case Teuchos::YAML::PROD_ANY_SLASH: {
561  result_any = '\\';
562  break;
563  }
564  case Teuchos::YAML::PROD_SCALAR_TAIL_SQUOT:
565  case Teuchos::YAML::PROD_DQUOTED_SQUOT:
566  case Teuchos::YAML::PROD_ANY_SQUOT: {
567  result_any = '\'';
568  break;
569  }
570  case Teuchos::YAML::PROD_COMMON_COLON: {
571  result_any = ':';
572  break;
573  }
574  case Teuchos::YAML::PROD_SCALAR_TAIL_DOT:
575  case Teuchos::YAML::PROD_COMMON_DOT: {
576  result_any = '.';
577  break;
578  }
579  case Teuchos::YAML::PROD_SCALAR_TAIL_DASH:
580  case Teuchos::YAML::PROD_COMMON_DASH:
581  case Teuchos::YAML::PROD_BSCALAR_HEAD_DASH: {
582  result_any = '-';
583  break;
584  }
585  case Teuchos::YAML::PROD_COMMON_PIPE: {
586  result_any = '|';
587  break;
588  }
589  case Teuchos::YAML::PROD_COMMON_LSQUARE: {
590  result_any = '[';
591  break;
592  }
593  case Teuchos::YAML::PROD_COMMON_RSQUARE: {
594  result_any = ']';
595  break;
596  }
597  case Teuchos::YAML::PROD_COMMON_LCURLY: {
598  result_any = '{';
599  break;
600  }
601  case Teuchos::YAML::PROD_COMMON_RCURLY: {
602  result_any = '}';
603  break;
604  }
605  case Teuchos::YAML::PROD_COMMON_RANGLE: {
606  result_any = '>';
607  break;
608  }
609  case Teuchos::YAML::PROD_COMMON_COMMA: {
610  result_any = ',';
611  break;
612  }
613  case Teuchos::YAML::PROD_COMMON_PERCENT: {
614  result_any = '%';
615  break;
616  }
617  case Teuchos::YAML::PROD_COMMON_EXCL: {
618  result_any = '!';
619  break;
620  }
621  }
622  }
623  void map_first_item(any& result_any, any& first_item) {
624  ParameterList& list = make_any_ref<ParameterList>(result_any);
625  TEUCHOS_ASSERT(!first_item.empty());
626  PLPair& pair = any_ref_cast<PLPair>(first_item);
627  safe_set_entry(list, pair.key, pair.value);
628  }
629  void map_next_item(any& result_any, any& items, any& next_item) {
630  using std::swap;
631  swap(result_any, items);
632  ParameterList& list = any_ref_cast<ParameterList>(result_any);
633  PLPair& pair = any_ref_cast<PLPair>(next_item);
634  safe_set_entry(list, pair.key, pair.value);
635  }
636  void map_item(any& result_any, any& key_any, any& value_any, int scalar_type = -1) {
637  using std::swap;
638  PLPair& result = make_any_ref<PLPair>(result_any);
639  {
640  std::string& key = any_ref_cast<Scalar>(key_any).text;
641  swap(result.key, key);
642  }
643  resolve_map_value(value_any, scalar_type);
644  if (value_any.type() == typeid(bool)) {
645  bool value = any_cast<bool>(value_any);
646  result.value = ParameterEntry(value);
647  } else if (value_any.type() == typeid(int)) {
648  int value = any_cast<int>(value_any);
649  result.value = ParameterEntry(value);
650  } else if (value_any.type() == typeid(long long)) {
651  long long value = any_cast<long long>(value_any);
652  result.value = ParameterEntry(value);
653  } else if (value_any.type() == typeid(double)) {
654  double value = any_cast<double>(value_any);
655  result.value = ParameterEntry(value);
656  } else if (value_any.type() == typeid(std::string)) {
657  std::string& value = any_ref_cast<std::string >(value_any);
658  result.value = ParameterEntry(value);
659  } else if (value_any.type() == typeid(Array<int>)) {
660  Array<int>& value = any_ref_cast<Array<int> >(value_any);
661  result.value = ParameterEntry(value);
662  } else if (value_any.type() == typeid(Array<long long>)) {
663  Array<long long>& value = any_ref_cast<Array<long long> >(value_any);
664  result.value = ParameterEntry(value);
665  } else if (value_any.type() == typeid(Array<double>)) {
666  Array<double>& value = any_ref_cast<Array<double> >(value_any);
667  result.value = ParameterEntry(value);
668  } else if (value_any.type() == typeid(Array<std::string>)) {
669  Array<std::string>& value = any_ref_cast<Array<std::string> >(value_any);
670  result.value = ParameterEntry(value);
671  } else if (value_any.type() == typeid(TwoDArray<int>)) {
672  TwoDArray<int>& value = any_ref_cast<TwoDArray<int> >(value_any);
673  result.value = ParameterEntry(value);
674  } else if (value_any.type() == typeid(TwoDArray<long long>)) {
675  TwoDArray<long long>& value = any_ref_cast<TwoDArray<long long> >(value_any);
676  result.value = ParameterEntry(value);
677  } else if (value_any.type() == typeid(TwoDArray<double>)) {
678  TwoDArray<double>& value = any_ref_cast<TwoDArray<double> >(value_any);
679  result.value = ParameterEntry(value);
680  } else if (value_any.type() == typeid(TwoDArray<std::string>)) {
681  TwoDArray<std::string>& value = any_ref_cast<TwoDArray<std::string> >(value_any);
682  result.value = ParameterEntry(value);
683  } else if (value_any.type() == typeid(ParameterList)) {
684  ParameterList& value = any_ref_cast<ParameterList>(value_any);
685  ParameterList& result_pl = result.value.setList();
686  swap(result_pl, value);
687  result_pl.setName(result.key);
688  } else {
689  std::string msg = "unexpected YAML map value type ";
690  msg += value_any.type().name();
691  msg += " for key \"";
692  msg += result.key;
693  msg += "\"\n";
694  throw ParserFail(msg);
695  }
696  }
697  void resolve_map_value(any& value_any, int scalar_type = -1) const {
698  if (value_any.type() == typeid(Scalar)) {
699  Scalar& scalar_value = any_ref_cast<Scalar>(value_any);
700  if (scalar_type == -1) {
701  scalar_type = scalar_value.infer_type();
702  }
703  if (scalar_type == Scalar::BOOL) {
704  value_any = parse_as<bool>(scalar_value.text);
705  } else if (scalar_type == Scalar::INT) {
706  value_any = parse_as<int>(scalar_value.text);
707  } else if (scalar_type == Scalar::LONG_LONG) {
708  value_any = parse_as<long long>(scalar_value.text);
709  } else if (scalar_type == Scalar::DOUBLE) {
710  value_any = parse_as<double>(scalar_value.text);
711  } else {
712  value_any = scalar_value.text;
713  }
714  } else if (value_any.type() == typeid(Array<Scalar>)) {
715  Array<Scalar>& scalars = any_ref_cast<Array<Scalar> >(value_any);
716  if (scalar_type == -1) {
717  if (scalars.size() == 0) {
718  throw ParserFail("implicitly typed arrays can't be empty\n"
719  "(need to determine their element type)\n");
720  }
721  /* Teuchos::Array uses std::vector but doesn't account for std::vector<bool>,
722  so it can't store bools */
723  scalar_type = Scalar::INT;
724  for (Teuchos_Ordinal i = 0; i < scalars.size(); ++i) {
725  scalar_type = std::min(scalar_type, scalars[i].infer_type());
726  }
727  }
728  if (scalar_type == Scalar::INT) {
729  Array<int> result(scalars.size());
730  for (Teuchos_Ordinal i = 0; i < scalars.size(); ++i) {
731  result[i] = parse_as<int>(scalars[i].text);
732  }
733  value_any = result;
734  } else if (scalar_type == Scalar::LONG_LONG) {
735  Array<long long> result(scalars.size());
736  for (Teuchos_Ordinal i = 0; i < scalars.size(); ++i) {
737  result[i] = parse_as<long long>(scalars[i].text);
738  }
739  value_any = result;
740  } else if (scalar_type == Scalar::DOUBLE) {
741  Array<double> result(scalars.size());
742  for (Teuchos_Ordinal i = 0; i < scalars.size(); ++i) {
743  result[i] = parse_as<double>(scalars[i].text);
744  }
745  value_any = result;
746  } else if (scalar_type == Scalar::STRING) {
747  Array<std::string> result(scalars.size());
748  for (Teuchos_Ordinal i = 0; i < scalars.size(); ++i) {
749  result[i] = scalars[i].text;
750  }
751  value_any = result;
752  }
753  } else if (value_any.type() == typeid(Array<Array<Scalar>>)) {
754  Array<Array<Scalar>>& scalars = any_ref_cast<Array<Array<Scalar>> >(value_any);
755  if (scalar_type == -1) {
756  if (scalars.size() == 0) {
757  throw ParserFail("implicitly typed 2D arrays can't be empty\n"
758  "(need to determine their element type)\n");
759  }
760  /* Teuchos::Array uses std::vector but doesn't account for std::vector<bool>,
761  so it can't store bools */
762  scalar_type = Scalar::INT;
763  for (Teuchos_Ordinal i = 0; i < scalars.size(); ++i) {
764  if (scalars[0].size() == 0) {
765  throw ParserFail("implicitly typed 2D arrays can't have empty rows\n"
766  "(need to determine their element type)\n");
767  }
768  if (scalars[i].size() != scalars[0].size()) {
769  throw ParserFail("2D array: sub-arrays are different sizes");
770  }
771  for (Teuchos_Ordinal j = 0; j < scalars[i].size(); ++j) {
772  int item_type = scalars[i][j].infer_type();
773  scalar_type = std::min(scalar_type, item_type);
774  }
775  }
776  }
777  if (scalar_type == Scalar::INT) {
778  TwoDArray<int> result(scalars.size(), scalars[0].size());
779  for (Teuchos_Ordinal i = 0; i < scalars.size(); ++i) {
780  for (Teuchos_Ordinal j = 0; j < scalars[0].size(); ++j) {
781  result(i, j) = parse_as<int>(scalars[i][j].text);
782  }
783  }
784  value_any = result;
785  } else if (scalar_type == Scalar::LONG_LONG) {
786  TwoDArray<long long> result(scalars.size(), scalars[0].size());
787  for (Teuchos_Ordinal i = 0; i < scalars.size(); ++i) {
788  for (Teuchos_Ordinal j = 0; j < scalars[0].size(); ++j) {
789  result(i, j) = parse_as<long long>(scalars[i][j].text);
790  }
791  }
792  value_any = result;
793  } else if (scalar_type == Scalar::DOUBLE) {
794  TwoDArray<double> result(scalars.size(), scalars[0].size());
795  for (Teuchos_Ordinal i = 0; i < scalars.size(); ++i) {
796  for (Teuchos_Ordinal j = 0; j < scalars[0].size(); ++j) {
797  result(i, j) = parse_as<double>(scalars[i][j].text);
798  }
799  }
800  value_any = result;
801  } else if (scalar_type == Scalar::STRING) {
802  TwoDArray<std::string> result(scalars.size(), scalars[0].size());
803  for (Teuchos_Ordinal i = 0; i < scalars.size(); ++i) {
804  for (Teuchos_Ordinal j = 0; j < scalars[0].size(); ++j) {
805  result(i, j) = scalars[i][j].text;
806  }
807  }
808  value_any = result;
809  }
810  }
811  }
812  int interpret_tag(any& tag_any) {
813  if (tag_any.type() != typeid(std::string)) return -1;
814  std::string& text = any_ref_cast<std::string>(tag_any);
815  if (text.find("bool") != std::string::npos) return Scalar::BOOL;
816  else if (text.find("int") != std::string::npos) return Scalar::INT;
817  else if (text.find("double") != std::string::npos) return Scalar::DOUBLE;
818  else if (text.find("string") != std::string::npos) return Scalar::STRING;
819  else {
820  std::string msg = "Unable to parse type tag \"";
821  msg += text;
822  msg += "\"\n";
823  throw ParserFail(msg);
824  }
825  }
826  void seq_first_item(any& result_any, any& first_any) {
827  using std::swap;
828  if (first_any.type() == typeid(Scalar)) {
829  Array<Scalar>& a = make_any_ref<Array<Scalar> >(result_any);
830  Scalar& v = any_ref_cast<Scalar>(first_any);
831  a.push_back(Scalar());
832  swap(a.back(), v);
833  } else if (first_any.type() == typeid(Array<Scalar>)) {
834  Array<Array<Scalar>>& a = make_any_ref<Array<Array<Scalar>> >(result_any);
835  Array<Scalar>& v = any_ref_cast<Array<Scalar> >(first_any);
836  a.push_back(Array<Scalar>());
837  swap(a.back(), v);
838  } else {
839  throw Teuchos::ParserFail(
840  "bug in YAMLParameterList::Reader: unexpected type for first sequence item");
841  }
842  }
843  void seq_next_item(any& result_any, any& items, any& next_item) {
844  using std::swap;
845  swap(result_any, items);
846  if (result_any.type() == typeid(Array<Scalar>)) {
847  Array<Scalar>& a = any_ref_cast<Array<Scalar> >(result_any);
848  Scalar& val = any_ref_cast<Scalar>(next_item);
849  a.push_back(Scalar());
850  swap(a.back(), val);
851  } else if (result_any.type() == typeid(Array<Array<Scalar>>)) {
852  Array<Array<Scalar>>& a = any_ref_cast<Array<Array<Scalar>> >(result_any);
853  Array<Scalar>& v = any_ref_cast<Array<Scalar> >(next_item);
854  a.push_back(Array<Scalar>());
855  swap(a.back(), v);
856  } else {
857  throw Teuchos::ParserFail(
858  "bug in YAMLParameterList::Reader: unexpected type for next sequence item");
859  }
860  }
861  /* block scalars are a super complicated mess, this function handles that mess */
862  void handle_block_scalar(
863  std::size_t parent_indent_level,
864  std::string const& header,
865  std::string const& leading_empties_or_comments,
866  std::string const& rest,
867  std::string& content,
868  std::string& comment) {
869  /* read the header, resulting in: block style, chomping indicator, and indentation indicator */
870  char style;
871  char chomping_indicator;
872  std::size_t indentation_indicator = 0;
873  style = header[0];
874  std::stringstream ss(header.substr(1,std::string::npos));
875  if (header.size() > 1 && my_isdigit(header[1])) {
876  ss >> indentation_indicator;
877  // indentation indicator is given as a relative number, but we need it in absolute terms
878  indentation_indicator += parent_indent_level;
879  }
880  if (!(ss >> chomping_indicator)) chomping_indicator = '\0';
881  /* get information about newlines, indentation level, and comment from
882  the leading_empties_or_comments string */
883  std::size_t first_newline = leading_empties_or_comments.find_first_of("\r\n");
884  std::string newline;
885  if (first_newline > 0 && leading_empties_or_comments[first_newline - 1] == '\r') {
886  newline = "\r\n";
887  } else {
888  newline = "\n";
889  }
890  std::size_t keep_beg = first_newline + 1 - newline.size();
891  if (leading_empties_or_comments[0] == '#') {
892  comment = leading_empties_or_comments.substr(1, keep_beg);
893  }
894  // according to the YAML spec, a tab is content, not indentation
895  std::size_t content_beg = leading_empties_or_comments.find_first_not_of("\r\n ");
896  if (content_beg == std::string::npos) content_beg = leading_empties_or_comments.size();
897  std::size_t newline_before_content = leading_empties_or_comments.rfind("\n", content_beg);
898  std::size_t num_indent_spaces = (content_beg - newline_before_content) - 1;
899  /* indentation indicator overrides the derived level of indentation, in case the
900  user wants to keep some of that indentation as content */
901  if (indentation_indicator > 0) {
902  TEUCHOS_TEST_FOR_EXCEPTION(num_indent_spaces < indentation_indicator,
904  "Indentation indicator " << indentation_indicator << " > leading spaces " << num_indent_spaces);
905  num_indent_spaces = indentation_indicator;
906  }
907  /* prepend the content from the leading_empties_or_comments to the rest */
908  content = leading_empties_or_comments.substr(keep_beg, std::string::npos);
909  content += rest;
910  /* per Trilinos issue #2090, there can be trailing comments after the block
911  scalar which are less indented than it, but they will be included in the
912  final NEWLINE token.
913  this code removes all contiguous trailing lines which are less indented
914  than the content.
915  */
916  while (true) {
917  auto last_newline = content.find_last_of("\n", content.size() - 2);
918  if (last_newline == std::string::npos) break;
919  std::size_t num_spaces = 0;
920  for (auto ispace = last_newline + 1;
921  ispace < content.size() && content[ispace] == ' ';
922  ++ispace) {
923  ++num_spaces;
924  }
925  if (num_spaces >= num_indent_spaces) break;
926  content.erase(content.begin() + last_newline + 1, content.end());
927  }
928  /* remove both indentation and newlines as dictated by header information */
929  std::size_t unindent_pos = 0;
930  while (true) {
931  std::size_t next_newline = content.find_first_of("\n", unindent_pos);
932  if (next_newline == std::string::npos) break;
933  std::size_t start_cut = next_newline + 1;
934  /* folding block scalars remove newlines */
935  if (style == '>') start_cut -= newline.size();
936  std::size_t end_cut = next_newline + 1;
937  /* the actual amount of indentation in the content varies, start by
938  marking it all for removal */
939  while (end_cut < content.size() && content[end_cut] == ' ') {
940  ++end_cut;
941  }
942  /* but don't remove more than the actual indent number */
943  end_cut = std::min(next_newline + 1 + num_indent_spaces, end_cut);
944  /* cut this (newline?)+indentation out of the content */
945  content = content.substr(0, start_cut) +
946  content.substr(end_cut, std::string::npos);
947  unindent_pos = start_cut;
948  }
949  if (chomping_indicator != '+') {
950  content = remove_trailing_whitespace_and_newlines(content);
951  if (chomping_indicator != '-') content += newline;
952  }
953  if (style == '|') {
954  // if not already, remove the leading newline
955  content = content.substr(newline.size(), std::string::npos);
956  }
957  }
958 };
959 
960 } // end namespace YAMLParameterList
961 
962 /* Helper functions */
963 
964 void updateParametersFromYamlFile(const std::string& yamlFileName,
965  const Teuchos::Ptr<Teuchos::ParameterList>& paramList)
966 {
967  //load the YAML file in as a new param list
968  Teuchos::RCP<Teuchos::ParameterList> updated = YAMLParameterList::parseYamlFile(yamlFileName);
969  if (paramList->name() == "ANONYMOUS") {
970  paramList->setName(updated->name());
971  }
972  //now update the original list (overwriting values with same key)
973  paramList->setParameters(*updated);
974 }
975 
976 void updateParametersFromYamlCString(const char* const data,
977  const Teuchos::Ptr<Teuchos::ParameterList>& paramList,
978  bool overwrite)
979 {
980  Teuchos::RCP<Teuchos::ParameterList> updated = YAMLParameterList::parseYamlText(data, "CString");
981  if(overwrite)
982  {
983  if (paramList->name() == "ANONYMOUS") {
984  paramList->setName(updated->name());
985  }
986  paramList->setParameters(*updated);
987  }
988  else
989  {
990  paramList->setParametersNotAlreadySet(*updated);
991  }
992 }
993 
994 void updateParametersFromYamlString(const std::string& yamlData,
995  const Teuchos::Ptr<Teuchos::ParameterList>& paramList,
996  bool overwrite,
997  const std::string& name)
998 {
999  Teuchos::RCP<Teuchos::ParameterList> updated = YAMLParameterList::parseYamlText(yamlData, name);
1000  if(overwrite)
1001  {
1002  if (paramList->name() == "ANONYMOUS") {
1003  paramList->setName(updated->name());
1004  }
1005  paramList->setParameters(*updated);
1006  }
1007  else
1008  {
1009  paramList->setParametersNotAlreadySet(*updated);
1010  }
1011 }
1012 
1013 Teuchos::RCP<Teuchos::ParameterList> getParametersFromYamlFile(const std::string& yamlFileName)
1014 {
1015  return YAMLParameterList::parseYamlFile(yamlFileName);
1016 }
1017 
1018 Teuchos::RCP<Teuchos::ParameterList> getParametersFromYamlString(const std::string& yamlStr)
1019 {
1020  std::stringstream ss(yamlStr);
1021  return YAMLParameterList::parseYamlStream(ss);
1022 }
1023 
1024 void writeParameterListToYamlOStream(
1025  const ParameterList &paramList,
1026  std::ostream &yamlOut
1027  )
1028 {
1029  YAMLParameterList::writeYamlStream(yamlOut, paramList);
1030 }
1031 
1032 void writeParameterListToYamlFile(
1033  const ParameterList &paramList,
1034  const std::string &yamlFileName
1035  )
1036 {
1037  YAMLParameterList::writeYamlFile(yamlFileName, paramList);
1038 }
1039 
1040 std::string convertXmlToYaml(const std::string& xmlFileName)
1041 {
1042  //load the parameter list from xml
1043  Teuchos::RCP<Teuchos::ParameterList> toConvert = Teuchos::getParametersFromXmlFile(xmlFileName);
1044  //replace the file extension ".xml" with ".yaml", or append it if there was no extension
1045  std::string yamlFileName;
1046  if(xmlFileName.find(".xml") == std::string::npos)
1047  {
1048  yamlFileName = xmlFileName + ".yaml";
1049  }
1050  else
1051  {
1052  yamlFileName = xmlFileName.substr(0, xmlFileName.length() - 4) + ".yaml";
1053  }
1054  YAMLParameterList::writeYamlFile(yamlFileName, *toConvert);
1055  return yamlFileName;
1056 }
1057 
1058 void convertXmlToYaml(const std::string& xmlFileName, const std::string& yamlFileName)
1059 {
1060  Teuchos::RCP<Teuchos::ParameterList> toConvert = Teuchos::getParametersFromXmlFile(xmlFileName);
1061  YAMLParameterList::writeYamlFile(yamlFileName, *toConvert);
1062 }
1063 
1064 void convertXmlToYaml(std::istream& xmlStream, std::ostream& yamlStream)
1065 {
1066  //read xmlStream into a string until EOF
1067  std::istreambuf_iterator<char> begin(xmlStream);
1068  std::istreambuf_iterator<char> end;
1069  std::string xmlString(begin, end);
1070  Teuchos::RCP<Teuchos::ParameterList> toConvert = Teuchos::getParametersFromXmlString(xmlString);
1071  YAMLParameterList::writeYamlStream(yamlStream, *toConvert);
1072 }
1073 
1074 namespace YAMLParameterList
1075 {
1076 
1077 Teuchos::RCP<Teuchos::ParameterList> parseYamlText(const std::string& text, const std::string& name)
1078 {
1079  Teuchos::YAMLParameterList::Reader reader;
1080  any result;
1081  reader.read_string(result, text, name);
1082  ParameterList& pl = any_ref_cast<ParameterList>(result);
1083  return Teuchos::rcp(new ParameterList(pl));
1084 }
1085 
1086 Teuchos::RCP<Teuchos::ParameterList> parseYamlFile(const std::string& yamlFile)
1087 {
1088  Teuchos::YAMLParameterList::Reader reader;
1089  any result;
1090  reader.read_file(result, yamlFile);
1091  ParameterList& pl = any_ref_cast<ParameterList>(result);
1092  return Teuchos::rcp(new ParameterList(pl));
1093 }
1094 
1095 Teuchos::RCP<Teuchos::ParameterList> parseYamlStream(std::istream& yaml)
1096 {
1097  Teuchos::YAMLParameterList::Reader reader;
1098  any result;
1099  reader.read_stream(result, yaml, "parseYamlStream");
1100  ParameterList& pl = any_ref_cast<ParameterList>(result);
1101  return Teuchos::rcp(new ParameterList(pl));
1102 }
1103 
1104 void writeYamlStream(std::ostream& yaml, const Teuchos::ParameterList& pl)
1105 {
1106  //warn the user if floats/doubles with integer values will be printed incorrectly
1107  std::ios_base::fmtflags flags = yaml.flags();
1108  //make temporary stringstream to test flags
1109  std::ostringstream testStream;
1110  testStream.flags(flags);
1111  double testVal = 1;
1112  testStream << testVal;
1113  bool popFlags = false;
1114  if(testStream.str() == "1")
1115  {
1116  //must add showpoint to flags while writing yaml
1117  //this will always disambiguate (double) n and n, even if stream precision is 0
1118  //prints as "n.0000" where the number of trailing zeros is the stream precision
1119  //note: in YAML, "5." is a double but not an int
1120  std::cout << "Warning: yaml stream format flags would confuse double with integer value with int.\n";
1121  std::cout << "Setting std::ios::showpoint on the stream to fix this (will restore flags when done)\n";
1122  std::ios_base::fmtflags flagsCopy = flags;
1123  flagsCopy |= std::ios::showpoint;
1124  popFlags = true;
1125  }
1126  yaml << "%YAML 1.1\n---\n";
1127  yaml << pl.name() << ':';
1128  if(pl.numParams() == 0)
1129  {
1130  yaml << " { }\n";
1131  }
1132  else
1133  {
1134  writeParameterList(pl, yaml, 2);
1135  }
1136  yaml << "...\n";
1137  //restore flags
1138  if(popFlags)
1139  {
1140  yaml.flags(flags);
1141  }
1142 }
1143 
1144 void writeYamlFile(const std::string& yamlFile, const Teuchos::ParameterList& pl)
1145 {
1146  std::ofstream yaml(yamlFile.c_str());
1147  /* set default floating-point style:
1148  1. 17 decimal places to ensure the value remains the same
1149  2. scientific: this prevents floating-point values that happen
1150  to be integers from being printed as integers, because YAML
1151  will then read that value back typed as an integer.
1152  */
1153  yaml << std::scientific << std::setprecision(17);
1154  writeYamlStream(yaml, pl);
1155 }
1156 
1157 void writeParameterList(const Teuchos::ParameterList& pl, std::ostream& yaml, int indentLevel)
1158 {
1159  if(pl.begin() == pl.end())
1160  {
1161  yaml << "{ }\n";
1162  }
1163  else
1164  {
1165  yaml << '\n';
1166  for(PLIter it = pl.begin(); it != pl.end(); it++)
1167  {
1168  writeParameter(pl.name(it), pl.entry(it), yaml, indentLevel);
1169  }
1170  }
1171 }
1172 
1173 template <typename T>
1174 struct YamlWrite {
1175  static void write(T const& x, std::ostream& stream) {
1176  stream << x;
1177  }
1178 };
1179 
1180 template <>
1181 struct YamlWrite<double> {
1182  static void write(double const& x, std::ostream& stream) {
1183  generalWriteDouble(x, stream);
1184  }
1185 };
1186 
1187 template <>
1188 struct YamlWrite<std::string> {
1189  static void write(std::string const& x, std::ostream& stream) {
1190  generalWriteString(x, stream);
1191  }
1192 };
1193 
1194 template <typename T>
1195 void writeYamlTwoDArray(Teuchos::TwoDArray<T> const& arr, std::ostream& stream)
1196 {
1197  typename Teuchos::TwoDArray<T>::size_type i, j;
1198  stream << '[';
1199  for (i = 0; i < arr.getNumRows(); ++i)
1200  {
1201  if (i) stream << ", ";
1202  stream << '[';
1203  for (j = 0; j < arr.getNumCols(); ++j)
1204  {
1205  if (j) stream << ", ";
1206  YamlWrite<T>::write(arr(i, j), stream);
1207  }
1208  stream << ']';
1209  }
1210  stream << ']';
1211 }
1212 
1213 void writeParameter(const std::string& paramName, const Teuchos::ParameterEntry& entry, std::ostream& yaml, int indentLevel)
1214 {
1215  for(int i = 0; i < indentLevel; i++)
1216  {
1217  yaml << ' ';
1218  }
1219  generalWriteString(paramName, yaml);
1220  yaml << ": ";
1221  if(entry.isList())
1222  {
1223  writeParameterList(Teuchos::getValue<Teuchos::ParameterList>(entry), yaml, indentLevel + 2);
1224  return;
1225  }
1226  else if(entry.isArray())
1227  {
1228  yaml << '[';
1229  if(entry.isType<Teuchos::Array<int> >())
1230  {
1231  Teuchos::Array<int>& arr = Teuchos::getValue<Teuchos::Array<int> >(entry);
1232  for(int i = 0; i < arr.size(); i++)
1233  {
1234  yaml << arr[i];
1235  if(i != arr.size() - 1)
1236  yaml << ", ";
1237  }
1238  }
1239  if(entry.isType<Teuchos::Array<long long> >())
1240  {
1241  Teuchos::Array<long long>& arr = Teuchos::getValue<Teuchos::Array<long long> >(entry);
1242  for(int i = 0; i < arr.size(); i++)
1243  {
1244  yaml << arr[i];
1245  if(i != arr.size() - 1)
1246  yaml << ", ";
1247  }
1248  }
1249  else if(entry.isType<Teuchos::Array<double> >())
1250  {
1251  Teuchos::Array<double>& arr = Teuchos::getValue<Teuchos::Array<double> >(entry);
1252  for(int i = 0; i < arr.size(); i++)
1253  {
1254  generalWriteDouble(arr[i], yaml);
1255  if(i != arr.size() - 1)
1256  yaml << ", ";
1257  }
1258  }
1259  else if(entry.isType<Teuchos::Array<std::string> >())
1260  {
1261  Teuchos::Array<std::string>& arr = Teuchos::getValue<Teuchos::Array<std::string> >(entry);
1262  for(int i = 0; i < arr.size(); i++)
1263  {
1264  generalWriteString(arr[i], yaml);
1265  if(i != arr.size() - 1)
1266  yaml << ", ";
1267  }
1268  }
1269  yaml << ']';
1270  }
1271  else if(entry.isTwoDArray())
1272  {
1273  if(entry.isType<Teuchos::TwoDArray<int> >())
1274  {
1275  writeYamlTwoDArray<int>(
1276  Teuchos::getValue<Teuchos::TwoDArray<int> >(entry), yaml);
1277  }
1279  {
1280  writeYamlTwoDArray<long long>(
1281  Teuchos::getValue<Teuchos::TwoDArray<long long> >(entry), yaml);
1282  }
1283  else if(entry.isType<Teuchos::TwoDArray<double> >())
1284  {
1285  writeYamlTwoDArray<double>(
1286  Teuchos::getValue<Teuchos::TwoDArray<double> >(entry), yaml);
1287  }
1288  else if(entry.isType<Teuchos::TwoDArray<std::string> >())
1289  {
1290  writeYamlTwoDArray<std::string>(
1291  Teuchos::getValue<Teuchos::TwoDArray<std::string> >(entry), yaml);
1292  }
1293  }
1294  else if(entry.isType<int>())
1295  {
1296  yaml << Teuchos::getValue<int>(entry);
1297  }
1298  else if(entry.isType<long long>())
1299  {
1300  yaml << Teuchos::getValue<long long>(entry);
1301  }
1302  else if(entry.isType<double>())
1303  {
1304  generalWriteDouble(Teuchos::getValue<double>(entry), yaml);
1305  }
1306  else if(entry.isType<std::string>())
1307  {
1308  std::string& str = Teuchos::getValue<std::string>(entry);
1309  if(strchr(str.c_str(), '\n'))
1310  {
1311  yaml << "|";
1312  // if the content has leading spaces, automatic indentation
1313  // detection would fail, in which case we must emit
1314  // an indentation indicator
1315  std::size_t first_non_newline_pos = str.find_first_not_of("\r\n");
1316  if (first_non_newline_pos != std::string::npos &&
1317  str[first_non_newline_pos] == ' ') {
1318  yaml << "2";
1319  }
1320  if (str[str.size() - 1] != '\n') yaml << "-";
1321  yaml << "\n";
1322  //for each line, apply indent then print the line verbatim
1323  size_t index = 0;
1324  while(true)
1325  {
1326  size_t next = str.find('\n', index);
1327  for(int i = 0; i < indentLevel + 2; i++)
1328  {
1329  yaml << ' ';
1330  }
1331  if(next == std::string::npos)
1332  {
1333  yaml << str.substr(index, std::string::npos);
1334  break;
1335  }
1336  else
1337  {
1338  yaml << str.substr(index, next - index) << '\n';
1339  }
1340  index = next + 1;
1341  }
1342  }
1343  else
1344  {
1345  generalWriteString(str, yaml);
1346  }
1347  }
1348  else if(entry.isType<bool>())
1349  {
1350  yaml << (Teuchos::getValue<bool>(entry) ? "true" : "false");
1351  }
1352  yaml << '\n';
1353 }
1354 
1355 void generalWriteString(const std::string& str, std::ostream& yaml)
1356 {
1357  // default to single quoting
1358  if(stringNeedsQuotes(str))
1359  {
1360  yaml << '\'';
1361  for (std::size_t i = 0; i < str.size(); ++i) {
1362  if (str[i] == '\'') yaml << "''";
1363  else yaml << str[i];
1364  }
1365  yaml << '\'';
1366  }
1367  else
1368  {
1369  yaml << str;
1370  }
1371 }
1372 
1373 void generalWriteDouble(double d, std::ostream& yaml)
1374 {
1375  yaml << d;
1376 }
1377 
1378 static bool containsSpecialCharacters(std::string const& s) {
1379  char const* const control_chars = ":'{}[],&*#?|<>=!%@\\";
1380  return s.find_first_of(control_chars) != std::string::npos;
1381 }
1382 
1383 bool stringNeedsQuotes(const std::string& s)
1384 {
1385  return s.empty() ||
1386  containsSpecialCharacters(s) ||
1387  is_parseable_as<bool>(s) ||
1388  is_parseable_as<int>(s) ||
1389  is_parseable_as<long long>(s) ||
1390  is_parseable_as<double>(s);
1391 }
1392 
1393 } //namespace YAMLParameterList
1394 
1395 } //namespace Teuchos
A thin wrapper around the Teuchos Array class that allows for 2 dimensional arrays.
const std::string & name() const
The name of this ParameterList.
Reader(ReaderTablesPtr tables_in)
Constructor: accepts an RCP to ReaderTables.
ConstIterator end() const
An iterator pointing beyond the last entry.
Functions to convert between ParameterList and YAML.
This object is held as the &quot;value&quot; in the Teuchos::ParameterList std::map.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
bool isArray() const
Test if the type of data being contained is a Teuchos::Array.
Tries to create LALR(1) parser tables for a given grammar.
bool isType() const
Test the type of the data being contained.
Ordinal numParams() const
Get the number of stored parameters.
A TeuchosParser Language for a subset of YAML.
Simple helper functions that make it easy to read and write XML to and from a parameterlist.
A thin wrapper around the Array class which causes it to be interpreted as a 2D Array.
The main class for users to read text using TeuchosParser.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Deprecated.
size_type getNumCols() const
returns the number of columns in the TwoDArray.
ConstIterator begin() const
An iterator pointing to the first entry.
bool isList() const
Return whether or not the value itself is a list.
A list of parameters of arbitrary type.
ParameterList & setParameters(const ParameterList &source)
const ParameterEntry & entry(ConstIterator i) const
Access to ParameterEntry (i.e., returns i-&gt;second)
size_type getNumRows() const
returns the number of rows in the TwoDArray.
ParameterList & setParametersNotAlreadySet(const ParameterList &source)
bool isTwoDArray() const
Test if the type of data being contained is a Teuchos::TwoDArray.
size_type size() const
ParameterList & setName(const std::string &name)
Set the name of *this list.
#define TEUCHOS_ASSERT(assertion_test)
This macro is throws when an assert fails.
Simple helper functions that make it easy to read and write Yaml to and from a parameterlist.
Simple wrapper class for raw pointers to single objects where no persisting relationship exists...
Declares Teuchos::Reader.