rapidyaml  0.11.1
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 
12 //-----------------------------------------------------------------------------
13 //-----------------------------------------------------------------------------
14 //-----------------------------------------------------------------------------
15 
16 namespace {
17 C4_ALWAYS_INLINE bool _is_idchar(char c)
18 {
19  return (c >= 'a' && c <= 'z')
20  || (c >= 'A' && c <= 'Z')
21  || (c >= '0' && c <= '9')
22  || (c == '_' || c == '-' || c == '~' || c == '$');
23 }
24 
25 enum _ppstate : int { kReadPending = 0, kKeyPending = 1, kValPending = 2 };
26 C4_ALWAYS_INLINE _ppstate _next(_ppstate s)
27 {
28  int n = (int)s + 1;
29  return (_ppstate)(n <= (int)kValPending ? n : 0);
30 }
31 } // empty namespace
32 
33 
34 //-----------------------------------------------------------------------------
35 
36 size_t preprocess_rxmap(csubstr s, substr buf)
37 {
38  detail::_SubstrWriter writer(buf);
39  _ppstate state = kReadPending;
40  size_t last = 0;
41 
42  if(s.begins_with('{'))
43  {
44  _RYML_CHECK_BASIC(s.ends_with('}'));
45  s = s.offs(1, 1);
46  }
47 
48  writer.append('{');
49 
50  for(size_t i = 0; i < s.len; ++i)
51  {
52  const char curr = s[i];
53  const char next = i+1 < s.len ? s[i+1] : '\0';
54 
55  if(curr == '\'' || curr == '"')
56  {
57  csubstr ss = s.sub(i).pair_range_esc(curr, '\\');
58  i += static_cast<size_t>(ss.end() - (s.str + i));
59  state = _next(state);
60  }
61  else if(state == kReadPending && _is_idchar(curr))
62  {
63  state = _next(state);
64  }
65 
66  switch(state)
67  {
68  case kKeyPending:
69  {
70  if(curr == ':' && next == ' ')
71  {
72  state = _next(state);
73  }
74  else if(curr == ',' && next == ' ')
75  {
76  writer.append(s.range(last, i));
77  writer.append(": 1, ");
78  last = i + 2;
79  }
80  break;
81  }
82  case kValPending:
83  {
84  if(curr == '[' || curr == '{' || curr == '(')
85  {
86  csubstr ss = s.sub(i).pair_range_nested(curr, '\\');
87  i += static_cast<size_t>(ss.end() - (s.str + i));
88  state = _next(state);
89  }
90  else if(curr == ',' && next == ' ')
91  {
92  state = _next(state);
93  }
94  break;
95  }
96  default:
97  // nothing to do
98  break;
99  }
100  }
101 
102  writer.append(s.sub(last));
103  if(state == kKeyPending)
104  writer.append(": 1");
105  writer.append('}');
106 
107  return writer.pos;
108 }
109 
110 C4_SUPPRESS_WARNING_GCC_CLANG_POP
111 
112 } // namespace yml
113 } // namespace c4
Error utilities used by ryml.
size_t preprocess_rxmap(csubstr s, substr buf)
Write into a given output buffer.
Definition: preprocess.cpp:36
(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.