1 | //===- lib/Support/YAMLTraits.cpp -----------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/Support/YAMLTraits.h" |
10 | #include "llvm/ADT/STLExtras.h" |
11 | #include "llvm/ADT/SmallString.h" |
12 | #include "llvm/ADT/StringExtras.h" |
13 | #include "llvm/ADT/StringRef.h" |
14 | #include "llvm/ADT/Twine.h" |
15 | #include "llvm/Support/Casting.h" |
16 | #include "llvm/Support/Errc.h" |
17 | #include "llvm/Support/ErrorHandling.h" |
18 | #include "llvm/Support/Format.h" |
19 | #include "llvm/Support/LineIterator.h" |
20 | #include "llvm/Support/MemoryBuffer.h" |
21 | #include "llvm/Support/VersionTuple.h" |
22 | #include "llvm/Support/YAMLParser.h" |
23 | #include "llvm/Support/raw_ostream.h" |
24 | #include <algorithm> |
25 | #include <cassert> |
26 | #include <cstdint> |
27 | #include <cstring> |
28 | #include <string> |
29 | #include <vector> |
30 | |
31 | using namespace llvm; |
32 | using namespace yaml; |
33 | |
34 | //===----------------------------------------------------------------------===// |
35 | // IO |
36 | //===----------------------------------------------------------------------===// |
37 | |
38 | IO::IO(void *Context) : Ctxt(Context) {} |
39 | |
40 | IO::~IO() = default; |
41 | |
42 | void *IO::getContext() const { |
43 | return Ctxt; |
44 | } |
45 | |
46 | void IO::setContext(void *Context) { |
47 | Ctxt = Context; |
48 | } |
49 | |
50 | void IO::setAllowUnknownKeys(bool Allow) { |
51 | llvm_unreachable("Only supported for Input" ); |
52 | } |
53 | |
54 | //===----------------------------------------------------------------------===// |
55 | // Input |
56 | //===----------------------------------------------------------------------===// |
57 | |
58 | Input::Input(StringRef InputContent, void *Ctxt, |
59 | SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt) |
60 | : IO(Ctxt), Strm(new Stream(InputContent, SrcMgr, false, &EC)) { |
61 | if (DiagHandler) |
62 | SrcMgr.setDiagHandler(DH: DiagHandler, Ctx: DiagHandlerCtxt); |
63 | DocIterator = Strm->begin(); |
64 | } |
65 | |
66 | Input::Input(MemoryBufferRef Input, void *Ctxt, |
67 | SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt) |
68 | : IO(Ctxt), Strm(new Stream(Input, SrcMgr, false, &EC)) { |
69 | if (DiagHandler) |
70 | SrcMgr.setDiagHandler(DH: DiagHandler, Ctx: DiagHandlerCtxt); |
71 | DocIterator = Strm->begin(); |
72 | } |
73 | |
74 | Input::~Input() = default; |
75 | |
76 | std::error_code Input::error() { return EC; } |
77 | |
78 | bool Input::outputting() const { |
79 | return false; |
80 | } |
81 | |
82 | bool Input::setCurrentDocument() { |
83 | if (DocIterator != Strm->end()) { |
84 | Node *N = DocIterator->getRoot(); |
85 | if (!N) { |
86 | EC = make_error_code(E: errc::invalid_argument); |
87 | return false; |
88 | } |
89 | |
90 | if (isa<NullNode>(Val: N)) { |
91 | // Empty files are allowed and ignored |
92 | ++DocIterator; |
93 | return setCurrentDocument(); |
94 | } |
95 | releaseHNodeBuffers(); |
96 | TopNode = createHNodes(node: N); |
97 | CurrentNode = TopNode; |
98 | return true; |
99 | } |
100 | return false; |
101 | } |
102 | |
103 | bool Input::nextDocument() { |
104 | return ++DocIterator != Strm->end(); |
105 | } |
106 | |
107 | const Node *Input::getCurrentNode() const { |
108 | return CurrentNode ? CurrentNode->_node : nullptr; |
109 | } |
110 | |
111 | bool Input::mapTag(StringRef Tag, bool Default) { |
112 | // CurrentNode can be null if setCurrentDocument() was unable to |
113 | // parse the document because it was invalid or empty. |
114 | if (!CurrentNode) |
115 | return false; |
116 | |
117 | std::string foundTag = CurrentNode->_node->getVerbatimTag(); |
118 | if (foundTag.empty()) { |
119 | // If no tag found and 'Tag' is the default, say it was found. |
120 | return Default; |
121 | } |
122 | // Return true iff found tag matches supplied tag. |
123 | return Tag.equals(RHS: foundTag); |
124 | } |
125 | |
126 | void Input::beginMapping() { |
127 | if (EC) |
128 | return; |
129 | // CurrentNode can be null if the document is empty. |
130 | MapHNode *MN = dyn_cast_or_null<MapHNode>(Val: CurrentNode); |
131 | if (MN) { |
132 | MN->ValidKeys.clear(); |
133 | } |
134 | } |
135 | |
136 | std::vector<StringRef> Input::keys() { |
137 | MapHNode *MN = dyn_cast<MapHNode>(Val: CurrentNode); |
138 | std::vector<StringRef> Ret; |
139 | if (!MN) { |
140 | setError(hnode: CurrentNode, message: "not a mapping" ); |
141 | return Ret; |
142 | } |
143 | for (auto &P : MN->Mapping) |
144 | Ret.push_back(x: P.first()); |
145 | return Ret; |
146 | } |
147 | |
148 | bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault, |
149 | void *&SaveInfo) { |
150 | UseDefault = false; |
151 | if (EC) |
152 | return false; |
153 | |
154 | // CurrentNode is null for empty documents, which is an error in case required |
155 | // nodes are present. |
156 | if (!CurrentNode) { |
157 | if (Required) |
158 | EC = make_error_code(E: errc::invalid_argument); |
159 | else |
160 | UseDefault = true; |
161 | return false; |
162 | } |
163 | |
164 | MapHNode *MN = dyn_cast<MapHNode>(Val: CurrentNode); |
165 | if (!MN) { |
166 | if (Required || !isa<EmptyHNode>(Val: CurrentNode)) |
167 | setError(hnode: CurrentNode, message: "not a mapping" ); |
168 | else |
169 | UseDefault = true; |
170 | return false; |
171 | } |
172 | MN->ValidKeys.push_back(Elt: Key); |
173 | HNode *Value = MN->Mapping[Key].first; |
174 | if (!Value) { |
175 | if (Required) |
176 | setError(hnode: CurrentNode, message: Twine("missing required key '" ) + Key + "'" ); |
177 | else |
178 | UseDefault = true; |
179 | return false; |
180 | } |
181 | SaveInfo = CurrentNode; |
182 | CurrentNode = Value; |
183 | return true; |
184 | } |
185 | |
186 | void Input::postflightKey(void *saveInfo) { |
187 | CurrentNode = reinterpret_cast<HNode *>(saveInfo); |
188 | } |
189 | |
190 | void Input::endMapping() { |
191 | if (EC) |
192 | return; |
193 | // CurrentNode can be null if the document is empty. |
194 | MapHNode *MN = dyn_cast_or_null<MapHNode>(Val: CurrentNode); |
195 | if (!MN) |
196 | return; |
197 | for (const auto &NN : MN->Mapping) { |
198 | if (!is_contained(Range&: MN->ValidKeys, Element: NN.first())) { |
199 | const SMRange &ReportLoc = NN.second.second; |
200 | if (!AllowUnknownKeys) { |
201 | setError(Range: ReportLoc, message: Twine("unknown key '" ) + NN.first() + "'" ); |
202 | break; |
203 | } else |
204 | reportWarning(Range: ReportLoc, message: Twine("unknown key '" ) + NN.first() + "'" ); |
205 | } |
206 | } |
207 | } |
208 | |
209 | void Input::beginFlowMapping() { beginMapping(); } |
210 | |
211 | void Input::endFlowMapping() { endMapping(); } |
212 | |
213 | unsigned Input::beginSequence() { |
214 | if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(Val: CurrentNode)) |
215 | return SQ->Entries.size(); |
216 | if (isa<EmptyHNode>(Val: CurrentNode)) |
217 | return 0; |
218 | // Treat case where there's a scalar "null" value as an empty sequence. |
219 | if (ScalarHNode *SN = dyn_cast<ScalarHNode>(Val: CurrentNode)) { |
220 | if (isNull(S: SN->value())) |
221 | return 0; |
222 | } |
223 | // Any other type of HNode is an error. |
224 | setError(hnode: CurrentNode, message: "not a sequence" ); |
225 | return 0; |
226 | } |
227 | |
228 | void Input::endSequence() { |
229 | } |
230 | |
231 | bool Input::preflightElement(unsigned Index, void *&SaveInfo) { |
232 | if (EC) |
233 | return false; |
234 | if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(Val: CurrentNode)) { |
235 | SaveInfo = CurrentNode; |
236 | CurrentNode = SQ->Entries[Index]; |
237 | return true; |
238 | } |
239 | return false; |
240 | } |
241 | |
242 | void Input::postflightElement(void *SaveInfo) { |
243 | CurrentNode = reinterpret_cast<HNode *>(SaveInfo); |
244 | } |
245 | |
246 | unsigned Input::beginFlowSequence() { return beginSequence(); } |
247 | |
248 | bool Input::preflightFlowElement(unsigned index, void *&SaveInfo) { |
249 | if (EC) |
250 | return false; |
251 | if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(Val: CurrentNode)) { |
252 | SaveInfo = CurrentNode; |
253 | CurrentNode = SQ->Entries[index]; |
254 | return true; |
255 | } |
256 | return false; |
257 | } |
258 | |
259 | void Input::postflightFlowElement(void *SaveInfo) { |
260 | CurrentNode = reinterpret_cast<HNode *>(SaveInfo); |
261 | } |
262 | |
263 | void Input::endFlowSequence() { |
264 | } |
265 | |
266 | void Input::beginEnumScalar() { |
267 | ScalarMatchFound = false; |
268 | } |
269 | |
270 | bool Input::matchEnumScalar(const char *Str, bool) { |
271 | if (ScalarMatchFound) |
272 | return false; |
273 | if (ScalarHNode *SN = dyn_cast<ScalarHNode>(Val: CurrentNode)) { |
274 | if (SN->value().equals(RHS: Str)) { |
275 | ScalarMatchFound = true; |
276 | return true; |
277 | } |
278 | } |
279 | return false; |
280 | } |
281 | |
282 | bool Input::matchEnumFallback() { |
283 | if (ScalarMatchFound) |
284 | return false; |
285 | ScalarMatchFound = true; |
286 | return true; |
287 | } |
288 | |
289 | void Input::endEnumScalar() { |
290 | if (!ScalarMatchFound) { |
291 | setError(hnode: CurrentNode, message: "unknown enumerated scalar" ); |
292 | } |
293 | } |
294 | |
295 | bool Input::beginBitSetScalar(bool &DoClear) { |
296 | BitValuesUsed.clear(); |
297 | if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(Val: CurrentNode)) { |
298 | BitValuesUsed.resize(N: SQ->Entries.size()); |
299 | } else { |
300 | setError(hnode: CurrentNode, message: "expected sequence of bit values" ); |
301 | } |
302 | DoClear = true; |
303 | return true; |
304 | } |
305 | |
306 | bool Input::bitSetMatch(const char *Str, bool) { |
307 | if (EC) |
308 | return false; |
309 | if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(Val: CurrentNode)) { |
310 | unsigned Index = 0; |
311 | for (auto &N : SQ->Entries) { |
312 | if (ScalarHNode *SN = dyn_cast<ScalarHNode>(Val: N)) { |
313 | if (SN->value().equals(RHS: Str)) { |
314 | BitValuesUsed[Index] = true; |
315 | return true; |
316 | } |
317 | } else { |
318 | setError(hnode: CurrentNode, message: "unexpected scalar in sequence of bit values" ); |
319 | } |
320 | ++Index; |
321 | } |
322 | } else { |
323 | setError(hnode: CurrentNode, message: "expected sequence of bit values" ); |
324 | } |
325 | return false; |
326 | } |
327 | |
328 | void Input::endBitSetScalar() { |
329 | if (EC) |
330 | return; |
331 | if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(Val: CurrentNode)) { |
332 | assert(BitValuesUsed.size() == SQ->Entries.size()); |
333 | for (unsigned i = 0; i < SQ->Entries.size(); ++i) { |
334 | if (!BitValuesUsed[i]) { |
335 | setError(hnode: SQ->Entries[i], message: "unknown bit value" ); |
336 | return; |
337 | } |
338 | } |
339 | } |
340 | } |
341 | |
342 | void Input::scalarString(StringRef &S, QuotingType) { |
343 | if (ScalarHNode *SN = dyn_cast<ScalarHNode>(Val: CurrentNode)) { |
344 | S = SN->value(); |
345 | } else { |
346 | setError(hnode: CurrentNode, message: "unexpected scalar" ); |
347 | } |
348 | } |
349 | |
350 | void Input::blockScalarString(StringRef &S) { scalarString(S, QuotingType::None); } |
351 | |
352 | void Input::scalarTag(std::string &Tag) { |
353 | Tag = CurrentNode->_node->getVerbatimTag(); |
354 | } |
355 | |
356 | void Input::setError(HNode *hnode, const Twine &message) { |
357 | assert(hnode && "HNode must not be NULL" ); |
358 | setError(node: hnode->_node, message); |
359 | } |
360 | |
361 | NodeKind Input::getNodeKind() { |
362 | if (isa<ScalarHNode>(Val: CurrentNode)) |
363 | return NodeKind::Scalar; |
364 | else if (isa<MapHNode>(Val: CurrentNode)) |
365 | return NodeKind::Map; |
366 | else if (isa<SequenceHNode>(Val: CurrentNode)) |
367 | return NodeKind::Sequence; |
368 | llvm_unreachable("Unsupported node kind" ); |
369 | } |
370 | |
371 | void Input::setError(Node *node, const Twine &message) { |
372 | Strm->printError(N: node, Msg: message); |
373 | EC = make_error_code(E: errc::invalid_argument); |
374 | } |
375 | |
376 | void Input::setError(const SMRange &range, const Twine &message) { |
377 | Strm->printError(Range: range, Msg: message); |
378 | EC = make_error_code(E: errc::invalid_argument); |
379 | } |
380 | |
381 | void Input::reportWarning(HNode *hnode, const Twine &message) { |
382 | assert(hnode && "HNode must not be NULL" ); |
383 | Strm->printError(N: hnode->_node, Msg: message, Kind: SourceMgr::DK_Warning); |
384 | } |
385 | |
386 | void Input::reportWarning(Node *node, const Twine &message) { |
387 | Strm->printError(N: node, Msg: message, Kind: SourceMgr::DK_Warning); |
388 | } |
389 | |
390 | void Input::reportWarning(const SMRange &range, const Twine &message) { |
391 | Strm->printError(Range: range, Msg: message, Kind: SourceMgr::DK_Warning); |
392 | } |
393 | |
394 | void Input::releaseHNodeBuffers() { |
395 | EmptyHNodeAllocator.DestroyAll(); |
396 | ScalarHNodeAllocator.DestroyAll(); |
397 | SequenceHNodeAllocator.DestroyAll(); |
398 | MapHNodeAllocator.DestroyAll(); |
399 | } |
400 | |
401 | Input::HNode *Input::createHNodes(Node *N) { |
402 | SmallString<128> StringStorage; |
403 | switch (N->getType()) { |
404 | case Node::NK_Scalar: { |
405 | ScalarNode *SN = dyn_cast<ScalarNode>(Val: N); |
406 | StringRef KeyStr = SN->getValue(Storage&: StringStorage); |
407 | if (!StringStorage.empty()) { |
408 | // Copy string to permanent storage |
409 | KeyStr = StringStorage.str().copy(A&: StringAllocator); |
410 | } |
411 | return new (ScalarHNodeAllocator.Allocate()) ScalarHNode(N, KeyStr); |
412 | } |
413 | case Node::NK_BlockScalar: { |
414 | BlockScalarNode *BSN = dyn_cast<BlockScalarNode>(Val: N); |
415 | StringRef ValueCopy = BSN->getValue().copy(A&: StringAllocator); |
416 | return new (ScalarHNodeAllocator.Allocate()) ScalarHNode(N, ValueCopy); |
417 | } |
418 | case Node::NK_Sequence: { |
419 | SequenceNode *SQ = dyn_cast<SequenceNode>(Val: N); |
420 | auto SQHNode = new (SequenceHNodeAllocator.Allocate()) SequenceHNode(N); |
421 | for (Node &SN : *SQ) { |
422 | auto Entry = createHNodes(N: &SN); |
423 | if (EC) |
424 | break; |
425 | SQHNode->Entries.push_back(x: Entry); |
426 | } |
427 | return SQHNode; |
428 | } |
429 | case Node::NK_Mapping: { |
430 | MappingNode *Map = dyn_cast<MappingNode>(Val: N); |
431 | auto mapHNode = new (MapHNodeAllocator.Allocate()) MapHNode(N); |
432 | for (KeyValueNode &KVN : *Map) { |
433 | Node *KeyNode = KVN.getKey(); |
434 | ScalarNode *Key = dyn_cast_or_null<ScalarNode>(Val: KeyNode); |
435 | Node *Value = KVN.getValue(); |
436 | if (!Key || !Value) { |
437 | if (!Key) |
438 | setError(node: KeyNode, message: "Map key must be a scalar" ); |
439 | if (!Value) |
440 | setError(node: KeyNode, message: "Map value must not be empty" ); |
441 | break; |
442 | } |
443 | StringStorage.clear(); |
444 | StringRef KeyStr = Key->getValue(Storage&: StringStorage); |
445 | if (!StringStorage.empty()) { |
446 | // Copy string to permanent storage |
447 | KeyStr = StringStorage.str().copy(A&: StringAllocator); |
448 | } |
449 | if (mapHNode->Mapping.count(Key: KeyStr)) |
450 | // From YAML spec: "The content of a mapping node is an unordered set of |
451 | // key/value node pairs, with the restriction that each of the keys is |
452 | // unique." |
453 | setError(node: KeyNode, message: Twine("duplicated mapping key '" ) + KeyStr + "'" ); |
454 | auto ValueHNode = createHNodes(N: Value); |
455 | if (EC) |
456 | break; |
457 | mapHNode->Mapping[KeyStr] = |
458 | std::make_pair(x: std::move(ValueHNode), y: KeyNode->getSourceRange()); |
459 | } |
460 | return std::move(mapHNode); |
461 | } |
462 | case Node::NK_Null: |
463 | return new (EmptyHNodeAllocator.Allocate()) EmptyHNode(N); |
464 | default: |
465 | setError(node: N, message: "unknown node kind" ); |
466 | return nullptr; |
467 | } |
468 | } |
469 | |
470 | void Input::setError(const Twine &Message) { |
471 | setError(hnode: CurrentNode, message: Message); |
472 | } |
473 | |
474 | void Input::setAllowUnknownKeys(bool Allow) { AllowUnknownKeys = Allow; } |
475 | |
476 | bool Input::canElideEmptySequence() { |
477 | return false; |
478 | } |
479 | |
480 | //===----------------------------------------------------------------------===// |
481 | // Output |
482 | //===----------------------------------------------------------------------===// |
483 | |
484 | Output::Output(raw_ostream &yout, void *context, int WrapColumn) |
485 | : IO(context), Out(yout), WrapColumn(WrapColumn) {} |
486 | |
487 | Output::~Output() = default; |
488 | |
489 | bool Output::outputting() const { |
490 | return true; |
491 | } |
492 | |
493 | void Output::beginMapping() { |
494 | StateStack.push_back(Elt: inMapFirstKey); |
495 | PaddingBeforeContainer = Padding; |
496 | Padding = "\n" ; |
497 | } |
498 | |
499 | bool Output::mapTag(StringRef Tag, bool Use) { |
500 | if (Use) { |
501 | // If this tag is being written inside a sequence we should write the start |
502 | // of the sequence before writing the tag, otherwise the tag won't be |
503 | // attached to the element in the sequence, but rather the sequence itself. |
504 | bool SequenceElement = false; |
505 | if (StateStack.size() > 1) { |
506 | auto &E = StateStack[StateStack.size() - 2]; |
507 | SequenceElement = inSeqAnyElement(State: E) || inFlowSeqAnyElement(State: E); |
508 | } |
509 | if (SequenceElement && StateStack.back() == inMapFirstKey) { |
510 | newLineCheck(); |
511 | } else { |
512 | output(s: " " ); |
513 | } |
514 | output(s: Tag); |
515 | if (SequenceElement) { |
516 | // If we're writing the tag during the first element of a map, the tag |
517 | // takes the place of the first element in the sequence. |
518 | if (StateStack.back() == inMapFirstKey) { |
519 | StateStack.pop_back(); |
520 | StateStack.push_back(Elt: inMapOtherKey); |
521 | } |
522 | // Tags inside maps in sequences should act as keys in the map from a |
523 | // formatting perspective, so we always want a newline in a sequence. |
524 | Padding = "\n" ; |
525 | } |
526 | } |
527 | return Use; |
528 | } |
529 | |
530 | void Output::endMapping() { |
531 | // If we did not map anything, we should explicitly emit an empty map |
532 | if (StateStack.back() == inMapFirstKey) { |
533 | Padding = PaddingBeforeContainer; |
534 | newLineCheck(); |
535 | output(s: "{}" ); |
536 | Padding = "\n" ; |
537 | } |
538 | StateStack.pop_back(); |
539 | } |
540 | |
541 | std::vector<StringRef> Output::keys() { |
542 | report_fatal_error(reason: "invalid call" ); |
543 | } |
544 | |
545 | bool Output::preflightKey(const char *Key, bool Required, bool SameAsDefault, |
546 | bool &UseDefault, void *&SaveInfo) { |
547 | UseDefault = false; |
548 | SaveInfo = nullptr; |
549 | if (Required || !SameAsDefault || WriteDefaultValues) { |
550 | auto State = StateStack.back(); |
551 | if (State == inFlowMapFirstKey || State == inFlowMapOtherKey) { |
552 | flowKey(Key); |
553 | } else { |
554 | newLineCheck(); |
555 | paddedKey(key: Key); |
556 | } |
557 | return true; |
558 | } |
559 | return false; |
560 | } |
561 | |
562 | void Output::postflightKey(void *) { |
563 | if (StateStack.back() == inMapFirstKey) { |
564 | StateStack.pop_back(); |
565 | StateStack.push_back(Elt: inMapOtherKey); |
566 | } else if (StateStack.back() == inFlowMapFirstKey) { |
567 | StateStack.pop_back(); |
568 | StateStack.push_back(Elt: inFlowMapOtherKey); |
569 | } |
570 | } |
571 | |
572 | void Output::beginFlowMapping() { |
573 | StateStack.push_back(Elt: inFlowMapFirstKey); |
574 | newLineCheck(); |
575 | ColumnAtMapFlowStart = Column; |
576 | output(s: "{ " ); |
577 | } |
578 | |
579 | void Output::endFlowMapping() { |
580 | StateStack.pop_back(); |
581 | outputUpToEndOfLine(s: " }" ); |
582 | } |
583 | |
584 | void Output::beginDocuments() { |
585 | outputUpToEndOfLine(s: "---" ); |
586 | } |
587 | |
588 | bool Output::preflightDocument(unsigned index) { |
589 | if (index > 0) |
590 | outputUpToEndOfLine(s: "\n---" ); |
591 | return true; |
592 | } |
593 | |
594 | void Output::postflightDocument() { |
595 | } |
596 | |
597 | void Output::endDocuments() { |
598 | output(s: "\n...\n" ); |
599 | } |
600 | |
601 | unsigned Output::beginSequence() { |
602 | StateStack.push_back(Elt: inSeqFirstElement); |
603 | PaddingBeforeContainer = Padding; |
604 | Padding = "\n" ; |
605 | return 0; |
606 | } |
607 | |
608 | void Output::endSequence() { |
609 | // If we did not emit anything, we should explicitly emit an empty sequence |
610 | if (StateStack.back() == inSeqFirstElement) { |
611 | Padding = PaddingBeforeContainer; |
612 | newLineCheck(/*EmptySequence=*/true); |
613 | output(s: "[]" ); |
614 | Padding = "\n" ; |
615 | } |
616 | StateStack.pop_back(); |
617 | } |
618 | |
619 | bool Output::preflightElement(unsigned, void *&SaveInfo) { |
620 | SaveInfo = nullptr; |
621 | return true; |
622 | } |
623 | |
624 | void Output::postflightElement(void *) { |
625 | if (StateStack.back() == inSeqFirstElement) { |
626 | StateStack.pop_back(); |
627 | StateStack.push_back(Elt: inSeqOtherElement); |
628 | } else if (StateStack.back() == inFlowSeqFirstElement) { |
629 | StateStack.pop_back(); |
630 | StateStack.push_back(Elt: inFlowSeqOtherElement); |
631 | } |
632 | } |
633 | |
634 | unsigned Output::beginFlowSequence() { |
635 | StateStack.push_back(Elt: inFlowSeqFirstElement); |
636 | newLineCheck(); |
637 | ColumnAtFlowStart = Column; |
638 | output(s: "[ " ); |
639 | NeedFlowSequenceComma = false; |
640 | return 0; |
641 | } |
642 | |
643 | void Output::endFlowSequence() { |
644 | StateStack.pop_back(); |
645 | outputUpToEndOfLine(s: " ]" ); |
646 | } |
647 | |
648 | bool Output::preflightFlowElement(unsigned, void *&SaveInfo) { |
649 | if (NeedFlowSequenceComma) |
650 | output(s: ", " ); |
651 | if (WrapColumn && Column > WrapColumn) { |
652 | output(s: "\n" ); |
653 | for (int i = 0; i < ColumnAtFlowStart; ++i) |
654 | output(s: " " ); |
655 | Column = ColumnAtFlowStart; |
656 | output(s: " " ); |
657 | } |
658 | SaveInfo = nullptr; |
659 | return true; |
660 | } |
661 | |
662 | void Output::postflightFlowElement(void *) { |
663 | NeedFlowSequenceComma = true; |
664 | } |
665 | |
666 | void Output::beginEnumScalar() { |
667 | EnumerationMatchFound = false; |
668 | } |
669 | |
670 | bool Output::matchEnumScalar(const char *Str, bool Match) { |
671 | if (Match && !EnumerationMatchFound) { |
672 | newLineCheck(); |
673 | outputUpToEndOfLine(s: Str); |
674 | EnumerationMatchFound = true; |
675 | } |
676 | return false; |
677 | } |
678 | |
679 | bool Output::matchEnumFallback() { |
680 | if (EnumerationMatchFound) |
681 | return false; |
682 | EnumerationMatchFound = true; |
683 | return true; |
684 | } |
685 | |
686 | void Output::endEnumScalar() { |
687 | if (!EnumerationMatchFound) |
688 | llvm_unreachable("bad runtime enum value" ); |
689 | } |
690 | |
691 | bool Output::beginBitSetScalar(bool &DoClear) { |
692 | newLineCheck(); |
693 | output(s: "[ " ); |
694 | NeedBitValueComma = false; |
695 | DoClear = false; |
696 | return true; |
697 | } |
698 | |
699 | bool Output::bitSetMatch(const char *Str, bool Matches) { |
700 | if (Matches) { |
701 | if (NeedBitValueComma) |
702 | output(s: ", " ); |
703 | output(s: Str); |
704 | NeedBitValueComma = true; |
705 | } |
706 | return false; |
707 | } |
708 | |
709 | void Output::endBitSetScalar() { |
710 | outputUpToEndOfLine(s: " ]" ); |
711 | } |
712 | |
713 | void Output::scalarString(StringRef &S, QuotingType MustQuote) { |
714 | newLineCheck(); |
715 | if (S.empty()) { |
716 | // Print '' for the empty string because leaving the field empty is not |
717 | // allowed. |
718 | outputUpToEndOfLine(s: "''" ); |
719 | return; |
720 | } |
721 | if (MustQuote == QuotingType::None) { |
722 | // Only quote if we must. |
723 | outputUpToEndOfLine(s: S); |
724 | return; |
725 | } |
726 | |
727 | const char *const Quote = MustQuote == QuotingType::Single ? "'" : "\"" ; |
728 | output(s: Quote); // Starting quote. |
729 | |
730 | // When using double-quoted strings (and only in that case), non-printable characters may be |
731 | // present, and will be escaped using a variety of unicode-scalar and special short-form |
732 | // escapes. This is handled in yaml::escape. |
733 | if (MustQuote == QuotingType::Double) { |
734 | output(s: yaml::escape(Input: S, /* EscapePrintable= */ false)); |
735 | outputUpToEndOfLine(s: Quote); |
736 | return; |
737 | } |
738 | |
739 | unsigned i = 0; |
740 | unsigned j = 0; |
741 | unsigned End = S.size(); |
742 | const char *Base = S.data(); |
743 | |
744 | // When using single-quoted strings, any single quote ' must be doubled to be escaped. |
745 | while (j < End) { |
746 | if (S[j] == '\'') { // Escape quotes. |
747 | output(s: StringRef(&Base[i], j - i)); // "flush". |
748 | output(s: StringLiteral("''" )); // Print it as '' |
749 | i = j + 1; |
750 | } |
751 | ++j; |
752 | } |
753 | output(s: StringRef(&Base[i], j - i)); |
754 | outputUpToEndOfLine(s: Quote); // Ending quote. |
755 | } |
756 | |
757 | void Output::blockScalarString(StringRef &S) { |
758 | if (!StateStack.empty()) |
759 | newLineCheck(); |
760 | output(s: " |" ); |
761 | outputNewLine(); |
762 | |
763 | unsigned Indent = StateStack.empty() ? 1 : StateStack.size(); |
764 | |
765 | auto Buffer = MemoryBuffer::getMemBuffer(InputData: S, BufferName: "" , RequiresNullTerminator: false); |
766 | for (line_iterator Lines(*Buffer, false); !Lines.is_at_end(); ++Lines) { |
767 | for (unsigned I = 0; I < Indent; ++I) { |
768 | output(s: " " ); |
769 | } |
770 | output(s: *Lines); |
771 | outputNewLine(); |
772 | } |
773 | } |
774 | |
775 | void Output::scalarTag(std::string &Tag) { |
776 | if (Tag.empty()) |
777 | return; |
778 | newLineCheck(); |
779 | output(s: Tag); |
780 | output(s: " " ); |
781 | } |
782 | |
783 | void Output::setError(const Twine &message) { |
784 | } |
785 | |
786 | bool Output::canElideEmptySequence() { |
787 | // Normally, with an optional key/value where the value is an empty sequence, |
788 | // the whole key/value can be not written. But, that produces wrong yaml |
789 | // if the key/value is the only thing in the map and the map is used in |
790 | // a sequence. This detects if the this sequence is the first key/value |
791 | // in map that itself is embedded in a sequence. |
792 | if (StateStack.size() < 2) |
793 | return true; |
794 | if (StateStack.back() != inMapFirstKey) |
795 | return true; |
796 | return !inSeqAnyElement(State: StateStack[StateStack.size() - 2]); |
797 | } |
798 | |
799 | void Output::output(StringRef s) { |
800 | Column += s.size(); |
801 | Out << s; |
802 | } |
803 | |
804 | void Output::outputUpToEndOfLine(StringRef s) { |
805 | output(s); |
806 | if (StateStack.empty() || (!inFlowSeqAnyElement(State: StateStack.back()) && |
807 | !inFlowMapAnyKey(State: StateStack.back()))) |
808 | Padding = "\n" ; |
809 | } |
810 | |
811 | void Output::outputNewLine() { |
812 | Out << "\n" ; |
813 | Column = 0; |
814 | } |
815 | |
816 | // if seq at top, indent as if map, then add "- " |
817 | // if seq in middle, use "- " if firstKey, else use " " |
818 | // |
819 | |
820 | void Output::newLineCheck(bool EmptySequence) { |
821 | if (Padding != "\n" ) { |
822 | output(s: Padding); |
823 | Padding = {}; |
824 | return; |
825 | } |
826 | outputNewLine(); |
827 | Padding = {}; |
828 | |
829 | if (StateStack.size() == 0 || EmptySequence) |
830 | return; |
831 | |
832 | unsigned Indent = StateStack.size() - 1; |
833 | bool OutputDash = false; |
834 | |
835 | if (StateStack.back() == inSeqFirstElement || |
836 | StateStack.back() == inSeqOtherElement) { |
837 | OutputDash = true; |
838 | } else if ((StateStack.size() > 1) && |
839 | ((StateStack.back() == inMapFirstKey) || |
840 | inFlowSeqAnyElement(State: StateStack.back()) || |
841 | (StateStack.back() == inFlowMapFirstKey)) && |
842 | inSeqAnyElement(State: StateStack[StateStack.size() - 2])) { |
843 | --Indent; |
844 | OutputDash = true; |
845 | } |
846 | |
847 | for (unsigned i = 0; i < Indent; ++i) { |
848 | output(s: " " ); |
849 | } |
850 | if (OutputDash) { |
851 | output(s: "- " ); |
852 | } |
853 | } |
854 | |
855 | void Output::paddedKey(StringRef key) { |
856 | output(s: key); |
857 | output(s: ":" ); |
858 | const char *spaces = " " ; |
859 | if (key.size() < strlen(s: spaces)) |
860 | Padding = &spaces[key.size()]; |
861 | else |
862 | Padding = " " ; |
863 | } |
864 | |
865 | void Output::flowKey(StringRef Key) { |
866 | if (StateStack.back() == inFlowMapOtherKey) |
867 | output(s: ", " ); |
868 | if (WrapColumn && Column > WrapColumn) { |
869 | output(s: "\n" ); |
870 | for (int I = 0; I < ColumnAtMapFlowStart; ++I) |
871 | output(s: " " ); |
872 | Column = ColumnAtMapFlowStart; |
873 | output(s: " " ); |
874 | } |
875 | output(s: Key); |
876 | output(s: ": " ); |
877 | } |
878 | |
879 | NodeKind Output::getNodeKind() { report_fatal_error(reason: "invalid call" ); } |
880 | |
881 | bool Output::inSeqAnyElement(InState State) { |
882 | return State == inSeqFirstElement || State == inSeqOtherElement; |
883 | } |
884 | |
885 | bool Output::inFlowSeqAnyElement(InState State) { |
886 | return State == inFlowSeqFirstElement || State == inFlowSeqOtherElement; |
887 | } |
888 | |
889 | bool Output::inMapAnyKey(InState State) { |
890 | return State == inMapFirstKey || State == inMapOtherKey; |
891 | } |
892 | |
893 | bool Output::inFlowMapAnyKey(InState State) { |
894 | return State == inFlowMapFirstKey || State == inFlowMapOtherKey; |
895 | } |
896 | |
897 | //===----------------------------------------------------------------------===// |
898 | // traits for built-in types |
899 | //===----------------------------------------------------------------------===// |
900 | |
901 | void ScalarTraits<bool>::output(const bool &Val, void *, raw_ostream &Out) { |
902 | Out << (Val ? "true" : "false" ); |
903 | } |
904 | |
905 | StringRef ScalarTraits<bool>::input(StringRef Scalar, void *, bool &Val) { |
906 | if (std::optional<bool> Parsed = parseBool(S: Scalar)) { |
907 | Val = *Parsed; |
908 | return StringRef(); |
909 | } |
910 | return "invalid boolean" ; |
911 | } |
912 | |
913 | void ScalarTraits<StringRef>::output(const StringRef &Val, void *, |
914 | raw_ostream &Out) { |
915 | Out << Val; |
916 | } |
917 | |
918 | StringRef ScalarTraits<StringRef>::input(StringRef Scalar, void *, |
919 | StringRef &Val) { |
920 | Val = Scalar; |
921 | return StringRef(); |
922 | } |
923 | |
924 | void ScalarTraits<std::string>::output(const std::string &Val, void *, |
925 | raw_ostream &Out) { |
926 | Out << Val; |
927 | } |
928 | |
929 | StringRef ScalarTraits<std::string>::input(StringRef Scalar, void *, |
930 | std::string &Val) { |
931 | Val = Scalar.str(); |
932 | return StringRef(); |
933 | } |
934 | |
935 | void ScalarTraits<uint8_t>::output(const uint8_t &Val, void *, |
936 | raw_ostream &Out) { |
937 | // use temp uin32_t because ostream thinks uint8_t is a character |
938 | uint32_t Num = Val; |
939 | Out << Num; |
940 | } |
941 | |
942 | StringRef ScalarTraits<uint8_t>::input(StringRef Scalar, void *, uint8_t &Val) { |
943 | unsigned long long n; |
944 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
945 | return "invalid number" ; |
946 | if (n > 0xFF) |
947 | return "out of range number" ; |
948 | Val = n; |
949 | return StringRef(); |
950 | } |
951 | |
952 | void ScalarTraits<uint16_t>::output(const uint16_t &Val, void *, |
953 | raw_ostream &Out) { |
954 | Out << Val; |
955 | } |
956 | |
957 | StringRef ScalarTraits<uint16_t>::input(StringRef Scalar, void *, |
958 | uint16_t &Val) { |
959 | unsigned long long n; |
960 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
961 | return "invalid number" ; |
962 | if (n > 0xFFFF) |
963 | return "out of range number" ; |
964 | Val = n; |
965 | return StringRef(); |
966 | } |
967 | |
968 | void ScalarTraits<uint32_t>::output(const uint32_t &Val, void *, |
969 | raw_ostream &Out) { |
970 | Out << Val; |
971 | } |
972 | |
973 | StringRef ScalarTraits<uint32_t>::input(StringRef Scalar, void *, |
974 | uint32_t &Val) { |
975 | unsigned long long n; |
976 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
977 | return "invalid number" ; |
978 | if (n > 0xFFFFFFFFUL) |
979 | return "out of range number" ; |
980 | Val = n; |
981 | return StringRef(); |
982 | } |
983 | |
984 | void ScalarTraits<uint64_t>::output(const uint64_t &Val, void *, |
985 | raw_ostream &Out) { |
986 | Out << Val; |
987 | } |
988 | |
989 | StringRef ScalarTraits<uint64_t>::input(StringRef Scalar, void *, |
990 | uint64_t &Val) { |
991 | unsigned long long N; |
992 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: N)) |
993 | return "invalid number" ; |
994 | Val = N; |
995 | return StringRef(); |
996 | } |
997 | |
998 | void ScalarTraits<int8_t>::output(const int8_t &Val, void *, raw_ostream &Out) { |
999 | // use temp in32_t because ostream thinks int8_t is a character |
1000 | int32_t Num = Val; |
1001 | Out << Num; |
1002 | } |
1003 | |
1004 | StringRef ScalarTraits<int8_t>::input(StringRef Scalar, void *, int8_t &Val) { |
1005 | long long N; |
1006 | if (getAsSignedInteger(Str: Scalar, Radix: 0, Result&: N)) |
1007 | return "invalid number" ; |
1008 | if ((N > 127) || (N < -128)) |
1009 | return "out of range number" ; |
1010 | Val = N; |
1011 | return StringRef(); |
1012 | } |
1013 | |
1014 | void ScalarTraits<int16_t>::output(const int16_t &Val, void *, |
1015 | raw_ostream &Out) { |
1016 | Out << Val; |
1017 | } |
1018 | |
1019 | StringRef ScalarTraits<int16_t>::input(StringRef Scalar, void *, int16_t &Val) { |
1020 | long long N; |
1021 | if (getAsSignedInteger(Str: Scalar, Radix: 0, Result&: N)) |
1022 | return "invalid number" ; |
1023 | if ((N > INT16_MAX) || (N < INT16_MIN)) |
1024 | return "out of range number" ; |
1025 | Val = N; |
1026 | return StringRef(); |
1027 | } |
1028 | |
1029 | void ScalarTraits<int32_t>::output(const int32_t &Val, void *, |
1030 | raw_ostream &Out) { |
1031 | Out << Val; |
1032 | } |
1033 | |
1034 | StringRef ScalarTraits<int32_t>::input(StringRef Scalar, void *, int32_t &Val) { |
1035 | long long N; |
1036 | if (getAsSignedInteger(Str: Scalar, Radix: 0, Result&: N)) |
1037 | return "invalid number" ; |
1038 | if ((N > INT32_MAX) || (N < INT32_MIN)) |
1039 | return "out of range number" ; |
1040 | Val = N; |
1041 | return StringRef(); |
1042 | } |
1043 | |
1044 | void ScalarTraits<int64_t>::output(const int64_t &Val, void *, |
1045 | raw_ostream &Out) { |
1046 | Out << Val; |
1047 | } |
1048 | |
1049 | StringRef ScalarTraits<int64_t>::input(StringRef Scalar, void *, int64_t &Val) { |
1050 | long long N; |
1051 | if (getAsSignedInteger(Str: Scalar, Radix: 0, Result&: N)) |
1052 | return "invalid number" ; |
1053 | Val = N; |
1054 | return StringRef(); |
1055 | } |
1056 | |
1057 | void ScalarTraits<double>::output(const double &Val, void *, raw_ostream &Out) { |
1058 | Out << format(Fmt: "%g" , Vals: Val); |
1059 | } |
1060 | |
1061 | StringRef ScalarTraits<double>::input(StringRef Scalar, void *, double &Val) { |
1062 | if (to_float(T: Scalar, Num&: Val)) |
1063 | return StringRef(); |
1064 | return "invalid floating point number" ; |
1065 | } |
1066 | |
1067 | void ScalarTraits<float>::output(const float &Val, void *, raw_ostream &Out) { |
1068 | Out << format(Fmt: "%g" , Vals: Val); |
1069 | } |
1070 | |
1071 | StringRef ScalarTraits<float>::input(StringRef Scalar, void *, float &Val) { |
1072 | if (to_float(T: Scalar, Num&: Val)) |
1073 | return StringRef(); |
1074 | return "invalid floating point number" ; |
1075 | } |
1076 | |
1077 | void ScalarTraits<Hex8>::output(const Hex8 &Val, void *, raw_ostream &Out) { |
1078 | Out << format(Fmt: "0x%" PRIX8, Vals: (uint8_t)Val); |
1079 | } |
1080 | |
1081 | StringRef ScalarTraits<Hex8>::input(StringRef Scalar, void *, Hex8 &Val) { |
1082 | unsigned long long n; |
1083 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
1084 | return "invalid hex8 number" ; |
1085 | if (n > 0xFF) |
1086 | return "out of range hex8 number" ; |
1087 | Val = n; |
1088 | return StringRef(); |
1089 | } |
1090 | |
1091 | void ScalarTraits<Hex16>::output(const Hex16 &Val, void *, raw_ostream &Out) { |
1092 | Out << format(Fmt: "0x%" PRIX16, Vals: (uint16_t)Val); |
1093 | } |
1094 | |
1095 | StringRef ScalarTraits<Hex16>::input(StringRef Scalar, void *, Hex16 &Val) { |
1096 | unsigned long long n; |
1097 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
1098 | return "invalid hex16 number" ; |
1099 | if (n > 0xFFFF) |
1100 | return "out of range hex16 number" ; |
1101 | Val = n; |
1102 | return StringRef(); |
1103 | } |
1104 | |
1105 | void ScalarTraits<Hex32>::output(const Hex32 &Val, void *, raw_ostream &Out) { |
1106 | Out << format(Fmt: "0x%" PRIX32, Vals: (uint32_t)Val); |
1107 | } |
1108 | |
1109 | StringRef ScalarTraits<Hex32>::input(StringRef Scalar, void *, Hex32 &Val) { |
1110 | unsigned long long n; |
1111 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
1112 | return "invalid hex32 number" ; |
1113 | if (n > 0xFFFFFFFFUL) |
1114 | return "out of range hex32 number" ; |
1115 | Val = n; |
1116 | return StringRef(); |
1117 | } |
1118 | |
1119 | void ScalarTraits<Hex64>::output(const Hex64 &Val, void *, raw_ostream &Out) { |
1120 | Out << format(Fmt: "0x%" PRIX64, Vals: (uint64_t)Val); |
1121 | } |
1122 | |
1123 | StringRef ScalarTraits<Hex64>::input(StringRef Scalar, void *, Hex64 &Val) { |
1124 | unsigned long long Num; |
1125 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: Num)) |
1126 | return "invalid hex64 number" ; |
1127 | Val = Num; |
1128 | return StringRef(); |
1129 | } |
1130 | |
1131 | void ScalarTraits<VersionTuple>::output(const VersionTuple &Val, void *, |
1132 | llvm::raw_ostream &Out) { |
1133 | Out << Val.getAsString(); |
1134 | } |
1135 | |
1136 | StringRef ScalarTraits<VersionTuple>::input(StringRef Scalar, void *, |
1137 | VersionTuple &Val) { |
1138 | if (Val.tryParse(string: Scalar)) |
1139 | return "invalid version format" ; |
1140 | return StringRef(); |
1141 | } |
1142 | |