Coverage Report

Created: 2026-05-21 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/lib/yamlcpp/src/singledocparser.cpp
Line
Count
Source
1
#include <algorithm>
2
#include <cstdio>
3
#include <sstream>
4
5
#include "collectionstack.h"  // IWYU pragma: keep
6
#include "scanner.h"
7
#include "singledocparser.h"
8
#include "tag.h"
9
#include "token.h"
10
#include "yaml-cpp/depthguard.h"
11
#include "yaml-cpp/emitterstyle.h"
12
#include "yaml-cpp/eventhandler.h"
13
#include "yaml-cpp/exceptions.h"  // IWYU pragma: keep
14
#include "yaml-cpp/mark.h"
15
#include "yaml-cpp/null.h"
16
17
namespace YAML {
18
SingleDocParser::SingleDocParser(Scanner& scanner, const Directives& directives)
19
3.43k
    : m_scanner(scanner),
20
3.43k
      m_directives(directives),
21
3.43k
      m_pCollectionStack(new CollectionStack),
22
3.43k
      m_anchors{},
23
3.43k
      m_curAnchor(0) {}
24
25
3.43k
SingleDocParser::~SingleDocParser() = default;
26
27
// HandleDocument
28
// . Handles the next document
29
// . Throws a ParserException on error.
30
3.43k
void SingleDocParser::HandleDocument(EventHandler& eventHandler) {
31
3.43k
  assert(!m_scanner.empty());  // guaranteed that there are tokens
32
3.43k
  assert(!m_curAnchor);
33
34
3.43k
  eventHandler.OnDocumentStart(m_scanner.peek().mark);
35
36
  // eat doc start
37
3.43k
  if (m_scanner.peek().type == Token::DOC_START)
38
2
    m_scanner.pop();
39
40
  // recurse!
41
3.43k
  HandleNode(eventHandler);
42
43
3.43k
  eventHandler.OnDocumentEnd();
44
45
  // and finally eat any doc ends we see
46
3.75k
  while (!m_scanner.empty() && m_scanner.peek().type == Token::DOC_END)
47
318
    m_scanner.pop();
48
3.43k
}
49
50
95.3k
void SingleDocParser::HandleNode(EventHandler& eventHandler) {
51
95.3k
  DepthGuard<500> depthguard(depth, m_scanner.mark(), ErrorMsg::BAD_FILE);
52
53
  // an empty node *is* a possibility
54
95.3k
  if (m_scanner.empty()) {
55
20
    eventHandler.OnNull(m_scanner.mark(), NullAnchor);
56
20
    return;
57
20
  }
58
59
  // save location
60
95.3k
  Mark mark = m_scanner.peek().mark;
61
62
  // special case: a value node by itself must be a map, with no header
63
95.3k
  if (m_scanner.peek().type == Token::VALUE) {
64
440
    eventHandler.OnMapStart(mark, "?", NullAnchor, EmitterStyle::Default);
65
440
    HandleMap(eventHandler);
66
440
    eventHandler.OnMapEnd();
67
440
    return;
68
440
  }
69
70
  // special case: an alias node
71
94.9k
  if (m_scanner.peek().type == Token::ALIAS) {
72
1.05k
    eventHandler.OnAlias(mark, LookupAnchor(mark, m_scanner.peek().value));
73
1.05k
    m_scanner.pop();
74
1.05k
    return;
75
1.05k
  }
76
77
93.8k
  std::string tag;
78
93.8k
  std::string anchor_name;
79
93.8k
  anchor_t anchor;
80
93.8k
  ParseProperties(tag, anchor, anchor_name);
81
82
93.8k
  if (!anchor_name.empty())
83
3.78k
    eventHandler.OnAnchor(mark, anchor_name);
84
85
  // after parsing properties, an empty node is again a possibility
86
93.8k
  if (m_scanner.empty()) {
87
605
    eventHandler.OnNull(mark, anchor);
88
605
    return;
89
605
  }
90
91
93.2k
  const Token& token = m_scanner.peek();
92
93
  // add non-specific tags
94
93.2k
  if (tag.empty())
95
86.9k
    tag = (token.type == Token::NON_PLAIN_SCALAR ? "!" : "?");
96
  
97
93.2k
  if (token.type == Token::PLAIN_SCALAR 
98
9.59k
      && tag.compare("?") == 0 && IsNullString(token.value)) {
99
2.24k
    eventHandler.OnNull(mark, anchor);
100
2.24k
    m_scanner.pop();
101
2.24k
    return;
102
2.24k
  }
103
104
  // now split based on what kind of node we should be
105
91.0k
  switch (token.type) {
106
7.35k
    case Token::PLAIN_SCALAR:
107
8.17k
    case Token::NON_PLAIN_SCALAR:
108
8.17k
      eventHandler.OnScalar(mark, tag, anchor, token.value);
109
8.17k
      m_scanner.pop();
110
8.17k
      return;
111
21.2k
    case Token::FLOW_SEQ_START:
112
21.2k
      eventHandler.OnSequenceStart(mark, tag, anchor, EmitterStyle::Flow);
113
21.2k
      HandleSequence(eventHandler);
114
21.2k
      eventHandler.OnSequenceEnd();
115
21.2k
      return;
116
8.16k
    case Token::BLOCK_SEQ_START:
117
8.16k
      eventHandler.OnSequenceStart(mark, tag, anchor, EmitterStyle::Block);
118
8.16k
      HandleSequence(eventHandler);
119
8.16k
      eventHandler.OnSequenceEnd();
120
8.16k
      return;
121
12.7k
    case Token::FLOW_MAP_START:
122
12.7k
      eventHandler.OnMapStart(mark, tag, anchor, EmitterStyle::Flow);
123
12.7k
      HandleMap(eventHandler);
124
12.7k
      eventHandler.OnMapEnd();
125
12.7k
      return;
126
6.57k
    case Token::BLOCK_MAP_START:
127
6.57k
      eventHandler.OnMapStart(mark, tag, anchor, EmitterStyle::Block);
128
6.57k
      HandleMap(eventHandler);
129
6.57k
      eventHandler.OnMapEnd();
130
6.57k
      return;
131
21.0k
    case Token::KEY:
132
      // compact maps can only go in a flow sequence
133
21.0k
      if (m_pCollectionStack->GetCurCollectionType() ==
134
21.0k
          CollectionType::FlowSeq) {
135
20.5k
        eventHandler.OnMapStart(mark, tag, anchor, EmitterStyle::Flow);
136
20.5k
        HandleMap(eventHandler);
137
20.5k
        eventHandler.OnMapEnd();
138
20.5k
        return;
139
20.5k
      }
140
458
      break;
141
12.9k
    default:
142
12.9k
      break;
143
91.0k
  }
144
145
13.4k
  if (tag == "?")
146
11.9k
    eventHandler.OnNull(mark, anchor);
147
1.49k
  else
148
1.49k
    eventHandler.OnScalar(mark, tag, anchor, "");
149
13.4k
}
150
151
29.4k
void SingleDocParser::HandleSequence(EventHandler& eventHandler) {
152
  // split based on start token
153
29.4k
  switch (m_scanner.peek().type) {
154
8.16k
    case Token::BLOCK_SEQ_START:
155
8.16k
      HandleBlockSequence(eventHandler);
156
8.16k
      break;
157
21.2k
    case Token::FLOW_SEQ_START:
158
21.2k
      HandleFlowSequence(eventHandler);
159
21.2k
      break;
160
0
    default:
161
0
      break;
162
29.4k
  }
163
29.4k
}
164
165
8.16k
void SingleDocParser::HandleBlockSequence(EventHandler& eventHandler) {
166
  // eat start token
167
8.16k
  m_scanner.pop();
168
8.16k
  m_pCollectionStack->PushCollectionType(CollectionType::BlockSeq);
169
170
16.9k
  while (true) {
171
12.1k
    if (m_scanner.empty())
172
0
      throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ);
173
174
12.1k
    Token token = m_scanner.peek();
175
12.1k
    if (token.type != Token::BLOCK_ENTRY && token.type != Token::BLOCK_SEQ_END)
176
16
      throw ParserException(token.mark, ErrorMsg::END_OF_SEQ);
177
178
12.1k
    m_scanner.pop();
179
12.1k
    if (token.type == Token::BLOCK_SEQ_END)
180
3.27k
      break;
181
182
    // check for null
183
8.83k
    if (!m_scanner.empty()) {
184
8.81k
      const Token& nextToken = m_scanner.peek();
185
8.81k
      if (nextToken.type == Token::BLOCK_ENTRY ||
186
8.21k
          nextToken.type == Token::BLOCK_SEQ_END) {
187
978
        eventHandler.OnNull(nextToken.mark, NullAnchor);
188
978
        continue;
189
978
      }
190
8.81k
    }
191
192
7.85k
    HandleNode(eventHandler);
193
7.85k
  }
194
195
8.14k
  m_pCollectionStack->PopCollectionType(CollectionType::BlockSeq);
196
8.14k
}
197
198
21.2k
void SingleDocParser::HandleFlowSequence(EventHandler& eventHandler) {
199
  // eat start token
200
21.2k
  m_scanner.pop();
201
21.2k
  m_pCollectionStack->PushCollectionType(CollectionType::FlowSeq);
202
203
49.6k
  while (true) {
204
30.2k
    if (m_scanner.empty())
205
135
      throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ_FLOW);
206
207
    // first check for end
208
30.1k
    if (m_scanner.peek().type == Token::FLOW_SEQ_END) {
209
1.10k
      m_scanner.pop();
210
1.10k
      break;
211
1.10k
    }
212
213
    // then read the node
214
29.0k
    HandleNode(eventHandler);
215
216
29.0k
    if (m_scanner.empty())
217
463
      throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ_FLOW);
218
219
    // now eat the separator (or could be a sequence end, which we ignore - but
220
    // if it's neither, then it's a bad node)
221
28.5k
    Token& token = m_scanner.peek();
222
28.5k
    if (token.type == Token::FLOW_ENTRY)
223
7.92k
      m_scanner.pop();
224
20.6k
    else if (token.type != Token::FLOW_SEQ_END)
225
83
      throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW);
226
28.5k
  }
227
228
20.5k
  m_pCollectionStack->PopCollectionType(CollectionType::FlowSeq);
229
20.5k
}
230
231
40.3k
void SingleDocParser::HandleMap(EventHandler& eventHandler) {
232
  // split based on start token
233
40.3k
  switch (m_scanner.peek().type) {
234
6.57k
    case Token::BLOCK_MAP_START:
235
6.57k
      HandleBlockMap(eventHandler);
236
6.57k
      break;
237
12.7k
    case Token::FLOW_MAP_START:
238
12.7k
      HandleFlowMap(eventHandler);
239
12.7k
      break;
240
20.5k
    case Token::KEY:
241
20.5k
      HandleCompactMap(eventHandler);
242
20.5k
      break;
243
440
    case Token::VALUE:
244
440
      HandleCompactMapWithNoKey(eventHandler);
245
440
      break;
246
0
    default:
247
0
      break;
248
40.3k
  }
249
40.3k
}
250
251
6.57k
void SingleDocParser::HandleBlockMap(EventHandler& eventHandler) {
252
  // eat start token
253
6.57k
  m_scanner.pop();
254
6.57k
  m_pCollectionStack->PushCollectionType(CollectionType::BlockMap);
255
256
14.1k
  while (true) {
257
11.3k
    if (m_scanner.empty())
258
0
      throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP);
259
260
11.3k
    Token token = m_scanner.peek();
261
11.3k
    if (token.type != Token::KEY && token.type != Token::VALUE &&
262
3.76k
        token.type != Token::BLOCK_MAP_END)
263
50
      throw ParserException(token.mark, ErrorMsg::END_OF_MAP);
264
265
11.2k
    if (token.type == Token::BLOCK_MAP_END) {
266
3.71k
      m_scanner.pop();
267
3.71k
      break;
268
3.71k
    }
269
270
    // grab key (if non-null)
271
7.55k
    if (token.type == Token::KEY) {
272
5.11k
      m_scanner.pop();
273
5.11k
      HandleNode(eventHandler);
274
5.11k
    } else {
275
2.44k
      eventHandler.OnNull(token.mark, NullAnchor);
276
2.44k
    }
277
278
    // now grab value (optional)
279
7.55k
    if (!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
280
4.63k
      m_scanner.pop();
281
4.63k
      HandleNode(eventHandler);
282
4.63k
    } else {
283
2.92k
      eventHandler.OnNull(token.mark, NullAnchor);
284
2.92k
    }
285
7.55k
  }
286
287
6.52k
  m_pCollectionStack->PopCollectionType(CollectionType::BlockMap);
288
6.52k
}
289
290
12.7k
void SingleDocParser::HandleFlowMap(EventHandler& eventHandler) {
291
  // eat start token
292
12.7k
  m_scanner.pop();
293
12.7k
  m_pCollectionStack->PushCollectionType(CollectionType::FlowMap);
294
295
34.0k
  while (true) {
296
22.6k
    if (m_scanner.empty())
297
121
      throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP_FLOW);
298
299
22.5k
    Token& token = m_scanner.peek();
300
22.5k
    const Mark mark = token.mark;
301
    // first check for end
302
22.5k
    if (token.type == Token::FLOW_MAP_END) {
303
993
      m_scanner.pop();
304
993
      break;
305
993
    }
306
307
    // grab key (if non-null)
308
21.5k
    if (token.type == Token::KEY) {
309
17.7k
      m_scanner.pop();
310
17.7k
      HandleNode(eventHandler);
311
17.7k
    } else {
312
3.80k
      eventHandler.OnNull(mark, NullAnchor);
313
3.80k
    }
314
315
    // now grab value (optional)
316
21.5k
    if (!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
317
6.12k
      m_scanner.pop();
318
6.12k
      HandleNode(eventHandler);
319
15.4k
    } else {
320
15.4k
      eventHandler.OnNull(mark, NullAnchor);
321
15.4k
    }
322
323
21.5k
    if (m_scanner.empty())
324
273
      throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP_FLOW);
325
326
    // now eat the separator (or could be a map end, which we ignore - but if
327
    // it's neither, then it's a bad node)
328
21.3k
    Token& nextToken = m_scanner.peek();
329
21.3k
    if (nextToken.type == Token::FLOW_ENTRY)
330
8.94k
      m_scanner.pop();
331
12.3k
    else if (nextToken.type != Token::FLOW_MAP_END)
332
74
      throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW);
333
21.3k
  }
334
335
12.3k
  m_pCollectionStack->PopCollectionType(CollectionType::FlowMap);
336
12.3k
}
337
338
// . Single "key: value" pair in a flow sequence
339
20.5k
void SingleDocParser::HandleCompactMap(EventHandler& eventHandler) {
340
20.5k
  m_pCollectionStack->PushCollectionType(CollectionType::CompactMap);
341
342
  // grab key
343
20.5k
  Mark mark = m_scanner.peek().mark;
344
20.5k
  m_scanner.pop();
345
20.5k
  HandleNode(eventHandler);
346
347
  // now grab value (optional)
348
20.5k
  if (!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
349
453
    m_scanner.pop();
350
453
    HandleNode(eventHandler);
351
20.1k
  } else {
352
20.1k
    eventHandler.OnNull(mark, NullAnchor);
353
20.1k
  }
354
355
20.5k
  m_pCollectionStack->PopCollectionType(CollectionType::CompactMap);
356
20.5k
}
357
358
// . Single ": value" pair in a flow sequence
359
440
void SingleDocParser::HandleCompactMapWithNoKey(EventHandler& eventHandler) {
360
440
  m_pCollectionStack->PushCollectionType(CollectionType::CompactMap);
361
362
  // null key
363
440
  eventHandler.OnNull(m_scanner.peek().mark, NullAnchor);
364
365
  // grab value
366
440
  m_scanner.pop();
367
440
  HandleNode(eventHandler);
368
369
440
  m_pCollectionStack->PopCollectionType(CollectionType::CompactMap);
370
440
}
371
372
// ParseProperties
373
// . Grabs any tag or anchor tokens and deals with them.
374
void SingleDocParser::ParseProperties(std::string& tag, anchor_t& anchor,
375
93.7k
                                      std::string& anchor_name) {
376
93.7k
  tag.clear();
377
93.7k
  anchor_name.clear();
378
93.7k
  anchor = NullAnchor;
379
380
104k
  while (true) {
381
104k
    if (m_scanner.empty())
382
605
      return;
383
384
103k
    switch (m_scanner.peek().type) {
385
6.76k
      case Token::TAG:
386
6.76k
        ParseTag(tag);
387
6.76k
        break;
388
3.80k
      case Token::ANCHOR:
389
3.80k
        ParseAnchor(anchor, anchor_name);
390
3.80k
        break;
391
93.1k
      default:
392
93.1k
        return;
393
103k
    }
394
103k
  }
395
93.7k
}
396
397
6.76k
void SingleDocParser::ParseTag(std::string& tag) {
398
6.76k
  Token& token = m_scanner.peek();
399
6.76k
  if (!tag.empty())
400
33
    throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS);
401
402
6.73k
  Tag tagInfo(token);
403
6.73k
  tag = tagInfo.Translate(m_directives);
404
6.73k
  m_scanner.pop();
405
6.73k
}
406
407
3.80k
void SingleDocParser::ParseAnchor(anchor_t& anchor, std::string& anchor_name) {
408
3.80k
  Token& token = m_scanner.peek();
409
3.80k
  if (anchor)
410
7
    throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS);
411
412
3.79k
  anchor_name = token.value;
413
3.79k
  anchor = RegisterAnchor(token.value);
414
3.79k
  m_scanner.pop();
415
3.79k
}
416
417
3.79k
anchor_t SingleDocParser::RegisterAnchor(const std::string& name) {
418
3.79k
  if (name.empty())
419
0
    return NullAnchor;
420
421
3.79k
  return m_anchors[name] = ++m_curAnchor;
422
3.79k
}
423
424
anchor_t SingleDocParser::LookupAnchor(const Mark& mark,
425
1.05k
                                       const std::string& name) const {
426
1.05k
  auto it = m_anchors.find(name);
427
1.05k
  if (it == m_anchors.end()) {
428
245
    std::stringstream ss;
429
245
    ss << ErrorMsg::UNKNOWN_ANCHOR << name;
430
245
    throw ParserException(mark, ss.str());
431
245
  }
432
433
812
  return it->second;
434
1.05k
}
435
}  // namespace YAML