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 == 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() == 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() == 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 | output(S, MustQuote); |
722 | outputUpToEndOfLine(s: "" ); |
723 | } |
724 | |
725 | void Output::blockScalarString(StringRef &S) { |
726 | if (!StateStack.empty()) |
727 | newLineCheck(); |
728 | output(s: " |" ); |
729 | outputNewLine(); |
730 | |
731 | unsigned Indent = StateStack.empty() ? 1 : StateStack.size(); |
732 | |
733 | auto Buffer = MemoryBuffer::getMemBuffer(InputData: S, BufferName: "" , RequiresNullTerminator: false); |
734 | for (line_iterator Lines(*Buffer, false); !Lines.is_at_end(); ++Lines) { |
735 | for (unsigned I = 0; I < Indent; ++I) { |
736 | output(s: " " ); |
737 | } |
738 | output(s: *Lines); |
739 | outputNewLine(); |
740 | } |
741 | } |
742 | |
743 | void Output::scalarTag(std::string &Tag) { |
744 | if (Tag.empty()) |
745 | return; |
746 | newLineCheck(); |
747 | output(s: Tag); |
748 | output(s: " " ); |
749 | } |
750 | |
751 | void Output::setError(const Twine &message) { |
752 | } |
753 | |
754 | bool Output::canElideEmptySequence() { |
755 | // Normally, with an optional key/value where the value is an empty sequence, |
756 | // the whole key/value can be not written. But, that produces wrong yaml |
757 | // if the key/value is the only thing in the map and the map is used in |
758 | // a sequence. This detects if the this sequence is the first key/value |
759 | // in map that itself is embedded in a sequence. |
760 | if (StateStack.size() < 2) |
761 | return true; |
762 | if (StateStack.back() != inMapFirstKey) |
763 | return true; |
764 | return !inSeqAnyElement(State: StateStack[StateStack.size() - 2]); |
765 | } |
766 | |
767 | void Output::output(StringRef s) { |
768 | Column += s.size(); |
769 | Out << s; |
770 | } |
771 | |
772 | void Output::output(StringRef S, QuotingType MustQuote) { |
773 | if (MustQuote == QuotingType::None) { |
774 | // Only quote if we must. |
775 | output(s: S); |
776 | return; |
777 | } |
778 | |
779 | StringLiteral Quote = MustQuote == QuotingType::Single ? StringLiteral("'" ) |
780 | : StringLiteral("\"" ); |
781 | output(s: Quote); // Starting quote. |
782 | |
783 | // When using double-quoted strings (and only in that case), non-printable |
784 | // characters may be present, and will be escaped using a variety of |
785 | // unicode-scalar and special short-form escapes. This is handled in |
786 | // yaml::escape. |
787 | if (MustQuote == QuotingType::Double) { |
788 | output(s: yaml::escape(Input: S, /* EscapePrintable= */ false)); |
789 | output(s: Quote); |
790 | return; |
791 | } |
792 | |
793 | unsigned i = 0; |
794 | unsigned j = 0; |
795 | unsigned End = S.size(); |
796 | const char *Base = S.data(); |
797 | |
798 | // When using single-quoted strings, any single quote ' must be doubled to be |
799 | // escaped. |
800 | while (j < End) { |
801 | if (S[j] == '\'') { // Escape quotes. |
802 | output(s: StringRef(&Base[i], j - i)); // "flush". |
803 | output(s: StringLiteral("''" )); // Print it as '' |
804 | i = j + 1; |
805 | } |
806 | ++j; |
807 | } |
808 | output(s: StringRef(&Base[i], j - i)); |
809 | output(s: Quote); // Ending quote. |
810 | } |
811 | |
812 | void Output::outputUpToEndOfLine(StringRef s) { |
813 | output(s); |
814 | if (StateStack.empty() || (!inFlowSeqAnyElement(State: StateStack.back()) && |
815 | !inFlowMapAnyKey(State: StateStack.back()))) |
816 | Padding = "\n" ; |
817 | } |
818 | |
819 | void Output::outputNewLine() { |
820 | Out << "\n" ; |
821 | Column = 0; |
822 | } |
823 | |
824 | // if seq at top, indent as if map, then add "- " |
825 | // if seq in middle, use "- " if firstKey, else use " " |
826 | // |
827 | |
828 | void Output::newLineCheck(bool EmptySequence) { |
829 | if (Padding != "\n" ) { |
830 | output(s: Padding); |
831 | Padding = {}; |
832 | return; |
833 | } |
834 | outputNewLine(); |
835 | Padding = {}; |
836 | |
837 | if (StateStack.size() == 0 || EmptySequence) |
838 | return; |
839 | |
840 | unsigned Indent = StateStack.size() - 1; |
841 | bool OutputDash = false; |
842 | |
843 | if (StateStack.back() == inSeqFirstElement || |
844 | StateStack.back() == inSeqOtherElement) { |
845 | OutputDash = true; |
846 | } else if ((StateStack.size() > 1) && |
847 | ((StateStack.back() == inMapFirstKey) || |
848 | inFlowSeqAnyElement(State: StateStack.back()) || |
849 | (StateStack.back() == inFlowMapFirstKey)) && |
850 | inSeqAnyElement(State: StateStack[StateStack.size() - 2])) { |
851 | --Indent; |
852 | OutputDash = true; |
853 | } |
854 | |
855 | for (unsigned i = 0; i < Indent; ++i) { |
856 | output(s: " " ); |
857 | } |
858 | if (OutputDash) { |
859 | output(s: "- " ); |
860 | } |
861 | } |
862 | |
863 | void Output::paddedKey(StringRef key) { |
864 | output(S: key, MustQuote: needsQuotes(S: key, ForcePreserveAsString: false)); |
865 | output(s: ":" ); |
866 | const char *spaces = " " ; |
867 | if (key.size() < strlen(s: spaces)) |
868 | Padding = &spaces[key.size()]; |
869 | else |
870 | Padding = " " ; |
871 | } |
872 | |
873 | void Output::flowKey(StringRef Key) { |
874 | if (StateStack.back() == inFlowMapOtherKey) |
875 | output(s: ", " ); |
876 | if (WrapColumn && Column > WrapColumn) { |
877 | output(s: "\n" ); |
878 | for (int I = 0; I < ColumnAtMapFlowStart; ++I) |
879 | output(s: " " ); |
880 | Column = ColumnAtMapFlowStart; |
881 | output(s: " " ); |
882 | } |
883 | output(S: Key, MustQuote: needsQuotes(S: Key, ForcePreserveAsString: false)); |
884 | output(s: ": " ); |
885 | } |
886 | |
887 | NodeKind Output::getNodeKind() { report_fatal_error(reason: "invalid call" ); } |
888 | |
889 | bool Output::inSeqAnyElement(InState State) { |
890 | return State == inSeqFirstElement || State == inSeqOtherElement; |
891 | } |
892 | |
893 | bool Output::inFlowSeqAnyElement(InState State) { |
894 | return State == inFlowSeqFirstElement || State == inFlowSeqOtherElement; |
895 | } |
896 | |
897 | bool Output::inMapAnyKey(InState State) { |
898 | return State == inMapFirstKey || State == inMapOtherKey; |
899 | } |
900 | |
901 | bool Output::inFlowMapAnyKey(InState State) { |
902 | return State == inFlowMapFirstKey || State == inFlowMapOtherKey; |
903 | } |
904 | |
905 | //===----------------------------------------------------------------------===// |
906 | // traits for built-in types |
907 | //===----------------------------------------------------------------------===// |
908 | |
909 | void ScalarTraits<bool>::output(const bool &Val, void *, raw_ostream &Out) { |
910 | Out << (Val ? "true" : "false" ); |
911 | } |
912 | |
913 | StringRef ScalarTraits<bool>::input(StringRef Scalar, void *, bool &Val) { |
914 | if (std::optional<bool> Parsed = parseBool(S: Scalar)) { |
915 | Val = *Parsed; |
916 | return StringRef(); |
917 | } |
918 | return "invalid boolean" ; |
919 | } |
920 | |
921 | void ScalarTraits<StringRef>::output(const StringRef &Val, void *, |
922 | raw_ostream &Out) { |
923 | Out << Val; |
924 | } |
925 | |
926 | StringRef ScalarTraits<StringRef>::input(StringRef Scalar, void *, |
927 | StringRef &Val) { |
928 | Val = Scalar; |
929 | return StringRef(); |
930 | } |
931 | |
932 | void ScalarTraits<std::string>::output(const std::string &Val, void *, |
933 | raw_ostream &Out) { |
934 | Out << Val; |
935 | } |
936 | |
937 | StringRef ScalarTraits<std::string>::input(StringRef Scalar, void *, |
938 | std::string &Val) { |
939 | Val = Scalar.str(); |
940 | return StringRef(); |
941 | } |
942 | |
943 | void ScalarTraits<uint8_t>::output(const uint8_t &Val, void *, |
944 | raw_ostream &Out) { |
945 | // use temp uin32_t because ostream thinks uint8_t is a character |
946 | uint32_t Num = Val; |
947 | Out << Num; |
948 | } |
949 | |
950 | StringRef ScalarTraits<uint8_t>::input(StringRef Scalar, void *, uint8_t &Val) { |
951 | unsigned long long n; |
952 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
953 | return "invalid number" ; |
954 | if (n > 0xFF) |
955 | return "out of range number" ; |
956 | Val = n; |
957 | return StringRef(); |
958 | } |
959 | |
960 | void ScalarTraits<uint16_t>::output(const uint16_t &Val, void *, |
961 | raw_ostream &Out) { |
962 | Out << Val; |
963 | } |
964 | |
965 | StringRef ScalarTraits<uint16_t>::input(StringRef Scalar, void *, |
966 | uint16_t &Val) { |
967 | unsigned long long n; |
968 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
969 | return "invalid number" ; |
970 | if (n > 0xFFFF) |
971 | return "out of range number" ; |
972 | Val = n; |
973 | return StringRef(); |
974 | } |
975 | |
976 | void ScalarTraits<uint32_t>::output(const uint32_t &Val, void *, |
977 | raw_ostream &Out) { |
978 | Out << Val; |
979 | } |
980 | |
981 | StringRef ScalarTraits<uint32_t>::input(StringRef Scalar, void *, |
982 | uint32_t &Val) { |
983 | unsigned long long n; |
984 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
985 | return "invalid number" ; |
986 | if (n > 0xFFFFFFFFUL) |
987 | return "out of range number" ; |
988 | Val = n; |
989 | return StringRef(); |
990 | } |
991 | |
992 | void ScalarTraits<uint64_t>::output(const uint64_t &Val, void *, |
993 | raw_ostream &Out) { |
994 | Out << Val; |
995 | } |
996 | |
997 | StringRef ScalarTraits<uint64_t>::input(StringRef Scalar, void *, |
998 | uint64_t &Val) { |
999 | unsigned long long N; |
1000 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: N)) |
1001 | return "invalid number" ; |
1002 | Val = N; |
1003 | return StringRef(); |
1004 | } |
1005 | |
1006 | void ScalarTraits<int8_t>::output(const int8_t &Val, void *, raw_ostream &Out) { |
1007 | // use temp in32_t because ostream thinks int8_t is a character |
1008 | int32_t Num = Val; |
1009 | Out << Num; |
1010 | } |
1011 | |
1012 | StringRef ScalarTraits<int8_t>::input(StringRef Scalar, void *, int8_t &Val) { |
1013 | long long N; |
1014 | if (getAsSignedInteger(Str: Scalar, Radix: 0, Result&: N)) |
1015 | return "invalid number" ; |
1016 | if ((N > 127) || (N < -128)) |
1017 | return "out of range number" ; |
1018 | Val = N; |
1019 | return StringRef(); |
1020 | } |
1021 | |
1022 | void ScalarTraits<int16_t>::output(const int16_t &Val, void *, |
1023 | raw_ostream &Out) { |
1024 | Out << Val; |
1025 | } |
1026 | |
1027 | StringRef ScalarTraits<int16_t>::input(StringRef Scalar, void *, int16_t &Val) { |
1028 | long long N; |
1029 | if (getAsSignedInteger(Str: Scalar, Radix: 0, Result&: N)) |
1030 | return "invalid number" ; |
1031 | if ((N > INT16_MAX) || (N < INT16_MIN)) |
1032 | return "out of range number" ; |
1033 | Val = N; |
1034 | return StringRef(); |
1035 | } |
1036 | |
1037 | void ScalarTraits<int32_t>::output(const int32_t &Val, void *, |
1038 | raw_ostream &Out) { |
1039 | Out << Val; |
1040 | } |
1041 | |
1042 | StringRef ScalarTraits<int32_t>::input(StringRef Scalar, void *, int32_t &Val) { |
1043 | long long N; |
1044 | if (getAsSignedInteger(Str: Scalar, Radix: 0, Result&: N)) |
1045 | return "invalid number" ; |
1046 | if ((N > INT32_MAX) || (N < INT32_MIN)) |
1047 | return "out of range number" ; |
1048 | Val = N; |
1049 | return StringRef(); |
1050 | } |
1051 | |
1052 | void ScalarTraits<int64_t>::output(const int64_t &Val, void *, |
1053 | raw_ostream &Out) { |
1054 | Out << Val; |
1055 | } |
1056 | |
1057 | StringRef ScalarTraits<int64_t>::input(StringRef Scalar, void *, int64_t &Val) { |
1058 | long long N; |
1059 | if (getAsSignedInteger(Str: Scalar, Radix: 0, Result&: N)) |
1060 | return "invalid number" ; |
1061 | Val = N; |
1062 | return StringRef(); |
1063 | } |
1064 | |
1065 | void ScalarTraits<double>::output(const double &Val, void *, raw_ostream &Out) { |
1066 | Out << format(Fmt: "%g" , Vals: Val); |
1067 | } |
1068 | |
1069 | StringRef ScalarTraits<double>::input(StringRef Scalar, void *, double &Val) { |
1070 | if (to_float(T: Scalar, Num&: Val)) |
1071 | return StringRef(); |
1072 | return "invalid floating point number" ; |
1073 | } |
1074 | |
1075 | void ScalarTraits<float>::output(const float &Val, void *, raw_ostream &Out) { |
1076 | Out << format(Fmt: "%g" , Vals: Val); |
1077 | } |
1078 | |
1079 | StringRef ScalarTraits<float>::input(StringRef Scalar, void *, float &Val) { |
1080 | if (to_float(T: Scalar, Num&: Val)) |
1081 | return StringRef(); |
1082 | return "invalid floating point number" ; |
1083 | } |
1084 | |
1085 | void ScalarTraits<Hex8>::output(const Hex8 &Val, void *, raw_ostream &Out) { |
1086 | Out << format(Fmt: "0x%" PRIX8, Vals: (uint8_t)Val); |
1087 | } |
1088 | |
1089 | StringRef ScalarTraits<Hex8>::input(StringRef Scalar, void *, Hex8 &Val) { |
1090 | unsigned long long n; |
1091 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
1092 | return "invalid hex8 number" ; |
1093 | if (n > 0xFF) |
1094 | return "out of range hex8 number" ; |
1095 | Val = n; |
1096 | return StringRef(); |
1097 | } |
1098 | |
1099 | void ScalarTraits<Hex16>::output(const Hex16 &Val, void *, raw_ostream &Out) { |
1100 | Out << format(Fmt: "0x%" PRIX16, Vals: (uint16_t)Val); |
1101 | } |
1102 | |
1103 | StringRef ScalarTraits<Hex16>::input(StringRef Scalar, void *, Hex16 &Val) { |
1104 | unsigned long long n; |
1105 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
1106 | return "invalid hex16 number" ; |
1107 | if (n > 0xFFFF) |
1108 | return "out of range hex16 number" ; |
1109 | Val = n; |
1110 | return StringRef(); |
1111 | } |
1112 | |
1113 | void ScalarTraits<Hex32>::output(const Hex32 &Val, void *, raw_ostream &Out) { |
1114 | Out << format(Fmt: "0x%" PRIX32, Vals: (uint32_t)Val); |
1115 | } |
1116 | |
1117 | StringRef ScalarTraits<Hex32>::input(StringRef Scalar, void *, Hex32 &Val) { |
1118 | unsigned long long n; |
1119 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: n)) |
1120 | return "invalid hex32 number" ; |
1121 | if (n > 0xFFFFFFFFUL) |
1122 | return "out of range hex32 number" ; |
1123 | Val = n; |
1124 | return StringRef(); |
1125 | } |
1126 | |
1127 | void ScalarTraits<Hex64>::output(const Hex64 &Val, void *, raw_ostream &Out) { |
1128 | Out << format(Fmt: "0x%" PRIX64, Vals: (uint64_t)Val); |
1129 | } |
1130 | |
1131 | StringRef ScalarTraits<Hex64>::input(StringRef Scalar, void *, Hex64 &Val) { |
1132 | unsigned long long Num; |
1133 | if (getAsUnsignedInteger(Str: Scalar, Radix: 0, Result&: Num)) |
1134 | return "invalid hex64 number" ; |
1135 | Val = Num; |
1136 | return StringRef(); |
1137 | } |
1138 | |
1139 | void ScalarTraits<VersionTuple>::output(const VersionTuple &Val, void *, |
1140 | llvm::raw_ostream &Out) { |
1141 | Out << Val.getAsString(); |
1142 | } |
1143 | |
1144 | StringRef ScalarTraits<VersionTuple>::input(StringRef Scalar, void *, |
1145 | VersionTuple &Val) { |
1146 | if (Val.tryParse(string: Scalar)) |
1147 | return "invalid version format" ; |
1148 | return StringRef(); |
1149 | } |
1150 | |