rapidyaml  0.12.0
parse and emit YAML, and do it fast
preprocess.cpp
Go to the documentation of this file.
1 #include "c4/yml/preprocess.hpp"
2 #include "c4/yml/error.hpp"
3 #include "c4/yml/detail/dbgprint.hpp"
4 
5 /** @file preprocess.hpp Functions for preprocessing YAML prior to parsing. */
6 
7 namespace c4 {
8 namespace yml {
9 
10 C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
11 // NOLINTBEGIN(modernize-avoid-c-style-cast)
12 
13 
14 //-----------------------------------------------------------------------------
15 //-----------------------------------------------------------------------------
16 //-----------------------------------------------------------------------------
17 
18 namespace {
19 C4_ALWAYS_INLINE bool _is_idchar(char c)
20 {
21  return (c >= 'a' && c <= 'z')
22  || (c >= 'A' && c <= 'Z')
23  || (c >= '0' && c <= '9')
24  || (c == '_' || c == '-' || c == '~' || c == '$');
25 }
26 
27 enum _ppstate : int { kReadPending = 0, kKeyPending = 1, kValPending = 2 }; // NOLINT
28 C4_ALWAYS_INLINE _ppstate _next(_ppstate s)
29 {
30  int n = (int)s + 1;
31  return (_ppstate)(n <= (int)kValPending ? n : 0);
32 }
33 } // empty namespace
34 
35 
36 //-----------------------------------------------------------------------------
37 
38 size_t preprocess_rxmap(csubstr s, substr buf)
39 {
40  detail::_SubstrWriter writer(buf);
41  _ppstate state = kReadPending;
42  size_t last = 0;
43 
44  if(s.begins_with('{'))
45  {
46  _RYML_CHECK_BASIC(s.ends_with('}'));
47  s = s.offs(1, 1);
48  }
49 
50  writer.append('{');
51 
52  for(size_t i = 0; i < s.len; ++i)
53  {
54  const char curr = s[i];
55  const char next = i+1 < s.len ? s[i+1] : '\0';
56 
57  if(curr == '\'' || curr == '"')
58  {
59  csubstr ss = s.sub(i).pair_range_esc(curr, '\\');
60  i += static_cast<size_t>(ss.end() - (s.str + i));
61  state = _next(state);
62  }
63  else if(state == kReadPending && _is_idchar(curr))
64  {
65  state = _next(state);
66  }
67 
68  switch(state)
69  {
70  case kKeyPending:
71  {
72  if(curr == ':' && next == ' ')
73  {
74  state = _next(state);
75  }
76  else if(curr == ',' && next == ' ')
77  {
78  writer.append(s.range(last, i));
79  writer.append(": 1, ");
80  last = i + 2;
81  }
82  break;
83  }
84  case kValPending:
85  {
86  if(curr == '[' || curr == '{' || curr == '(')
87  {
88  csubstr ss = s.sub(i).pair_range_nested(curr, '\\');
89  i += static_cast<size_t>(ss.end() - (s.str + i));
90  state = _next(state);
91  }
92  else if(curr == ',' && next == ' ')
93  {
94  state = _next(state);
95  }
96  break;
97  }
98  default:
99  // nothing to do
100  break;
101  }
102  }
103 
104  writer.append(s.sub(last));
105  if(state == kKeyPending)
106  writer.append(": 1");
107  writer.append('}');
108 
109  return writer.pos;
110 }
111 
112 // NOLINTEND(modernize-avoid-c-style-cast)
113 C4_SUPPRESS_WARNING_GCC_CLANG_POP
114 
115 } // namespace yml
116 } // namespace c4
Error utilities used by ryml.
size_t preprocess_rxmap(csubstr s, substr buf)
Write into a given output buffer.
Definition: preprocess.cpp:38
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition: common.cpp:14
Functions for preprocessing YAML prior to parsing.