Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line | 
|---|---|---|---|
| 14 | pmbaty | 1 | //===- YAMLParser.h - Simple YAML parser ------------------------*- C++ -*-===// | 
| 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 | //  This is a YAML 1.2 parser. | ||
| 10 | // | ||
| 11 | //  See http://www.yaml.org/spec/1.2/spec.html for the full standard. | ||
| 12 | // | ||
| 13 | //  This currently does not implement the following: | ||
| 14 | //    * Tag resolution. | ||
| 15 | //    * UTF-16. | ||
| 16 | //    * BOMs anywhere other than the first Unicode scalar value in the file. | ||
| 17 | // | ||
| 18 | //  The most important class here is Stream. This represents a YAML stream with | ||
| 19 | //  0, 1, or many documents. | ||
| 20 | // | ||
| 21 | //  SourceMgr sm; | ||
| 22 | //  StringRef input = getInput(); | ||
| 23 | //  yaml::Stream stream(input, sm); | ||
| 24 | // | ||
| 25 | //  for (yaml::document_iterator di = stream.begin(), de = stream.end(); | ||
| 26 | //       di != de; ++di) { | ||
| 27 | //    yaml::Node *n = di->getRoot(); | ||
| 28 | //    if (n) { | ||
| 29 | //      // Do something with n... | ||
| 30 | //    } else | ||
| 31 | //      break; | ||
| 32 | //  } | ||
| 33 | // | ||
| 34 | //===----------------------------------------------------------------------===// | ||
| 35 | |||
| 36 | #ifndef LLVM_SUPPORT_YAMLPARSER_H | ||
| 37 | #define LLVM_SUPPORT_YAMLPARSER_H | ||
| 38 | |||
| 39 | #include "llvm/ADT/StringRef.h" | ||
| 40 | #include "llvm/Support/Allocator.h" | ||
| 41 | #include "llvm/Support/SMLoc.h" | ||
| 42 | #include "llvm/Support/SourceMgr.h" | ||
| 43 | #include <cassert> | ||
| 44 | #include <cstddef> | ||
| 45 | #include <iterator> | ||
| 46 | #include <map> | ||
| 47 | #include <memory> | ||
| 48 | #include <optional> | ||
| 49 | #include <string> | ||
| 50 | #include <system_error> | ||
| 51 | |||
| 52 | namespace llvm { | ||
| 53 | |||
| 54 | class MemoryBufferRef; | ||
| 55 | class raw_ostream; | ||
| 56 | class Twine; | ||
| 57 | |||
| 58 | namespace yaml { | ||
| 59 | |||
| 60 | class Document; | ||
| 61 | class document_iterator; | ||
| 62 | class Node; | ||
| 63 | class Scanner; | ||
| 64 | struct Token; | ||
| 65 | |||
| 66 | /// Dump all the tokens in this stream to OS. | ||
| 67 | /// \returns true if there was an error, false otherwise. | ||
| 68 | bool dumpTokens(StringRef Input, raw_ostream &); | ||
| 69 | |||
| 70 | /// Scans all tokens in input without outputting anything. This is used | ||
| 71 | ///        for benchmarking the tokenizer. | ||
| 72 | /// \returns true if there was an error, false otherwise. | ||
| 73 | bool scanTokens(StringRef Input); | ||
| 74 | |||
| 75 | /// Escape \a Input for a double quoted scalar; if \p EscapePrintable | ||
| 76 | /// is true, all UTF8 sequences will be escaped, if \p EscapePrintable is | ||
| 77 | /// false, those UTF8 sequences encoding printable unicode scalars will not be | ||
| 78 | /// escaped, but emitted verbatim. | ||
| 79 | std::string escape(StringRef Input, bool EscapePrintable = true); | ||
| 80 | |||
| 81 | /// Parse \p S as a bool according to https://yaml.org/type/bool.html. | ||
| 82 | std::optional<bool> parseBool(StringRef S); | ||
| 83 | |||
| 84 | /// This class represents a YAML stream potentially containing multiple | ||
| 85 | ///        documents. | ||
| 86 | class Stream { | ||
| 87 | public: | ||
| 88 |   /// This keeps a reference to the string referenced by \p Input. | ||
| 89 | Stream(StringRef Input, SourceMgr &, bool ShowColors = true, | ||
| 90 | std::error_code *EC = nullptr); | ||
| 91 | |||
| 92 | Stream(MemoryBufferRef InputBuffer, SourceMgr &, bool ShowColors = true, | ||
| 93 | std::error_code *EC = nullptr); | ||
| 94 | ~Stream(); | ||
| 95 | |||
| 96 | document_iterator begin(); | ||
| 97 | document_iterator end(); | ||
| 98 | void skip(); | ||
| 99 | bool failed(); | ||
| 100 | |||
| 101 | bool validate() { | ||
| 102 | skip(); | ||
| 103 | return !failed(); | ||
| 104 |   } | ||
| 105 | |||
| 106 | void printError(Node *N, const Twine &Msg, | ||
| 107 | SourceMgr::DiagKind Kind = SourceMgr::DK_Error); | ||
| 108 | void printError(const SMRange &Range, const Twine &Msg, | ||
| 109 | SourceMgr::DiagKind Kind = SourceMgr::DK_Error); | ||
| 110 | |||
| 111 | private: | ||
| 112 | friend class Document; | ||
| 113 | |||
| 114 | std::unique_ptr<Scanner> scanner; | ||
| 115 | std::unique_ptr<Document> CurrentDoc; | ||
| 116 | }; | ||
| 117 | |||
| 118 | /// Abstract base class for all Nodes. | ||
| 119 | class Node { | ||
| 120 | virtual void anchor(); | ||
| 121 | |||
| 122 | public: | ||
| 123 | enum NodeKind { | ||
| 124 | NK_Null, | ||
| 125 | NK_Scalar, | ||
| 126 | NK_BlockScalar, | ||
| 127 | NK_KeyValue, | ||
| 128 | NK_Mapping, | ||
| 129 | NK_Sequence, | ||
| 130 | NK_Alias | ||
| 131 | }; | ||
| 132 | |||
| 133 | Node(unsigned int Type, std::unique_ptr<Document> &, StringRef Anchor, | ||
| 134 | StringRef Tag); | ||
| 135 | |||
| 136 |   // It's not safe to copy YAML nodes; the document is streamed and the position | ||
| 137 |   // is part of the state. | ||
| 138 | Node(const Node &) = delete; | ||
| 139 | void operator=(const Node &) = delete; | ||
| 140 | |||
| 141 | void *operator new(size_t Size, BumpPtrAllocator &Alloc, | ||
| 142 | size_t Alignment = 16) noexcept { | ||
| 143 | return Alloc.Allocate(Size, Alignment); | ||
| 144 |   } | ||
| 145 | |||
| 146 | void operator delete(void *Ptr, BumpPtrAllocator &Alloc, | ||
| 147 | size_t Size) noexcept { | ||
| 148 | Alloc.Deallocate(Ptr, Size, 0); | ||
| 149 |   } | ||
| 150 | |||
| 151 | void operator delete(void *) noexcept = delete; | ||
| 152 | |||
| 153 |   /// Get the value of the anchor attached to this node. If it does not | ||
| 154 |   ///        have one, getAnchor().size() will be 0. | ||
| 155 | StringRef getAnchor() const { return Anchor; } | ||
| 156 | |||
| 157 |   /// Get the tag as it was written in the document. This does not | ||
| 158 |   ///   perform tag resolution. | ||
| 159 | StringRef getRawTag() const { return Tag; } | ||
| 160 | |||
| 161 |   /// Get the verbatium tag for a given Node. This performs tag resoluton | ||
| 162 |   ///   and substitution. | ||
| 163 | std::string getVerbatimTag() const; | ||
| 164 | |||
| 165 | SMRange getSourceRange() const { return SourceRange; } | ||
| 166 | void setSourceRange(SMRange SR) { SourceRange = SR; } | ||
| 167 | |||
| 168 |   // These functions forward to Document and Scanner. | ||
| 169 | Token &peekNext(); | ||
| 170 | Token getNext(); | ||
| 171 | Node *parseBlockNode(); | ||
| 172 | BumpPtrAllocator &getAllocator(); | ||
| 173 | void setError(const Twine &Message, Token &Location) const; | ||
| 174 | bool failed() const; | ||
| 175 | |||
| 176 | virtual void skip() {} | ||
| 177 | |||
| 178 | unsigned int getType() const { return TypeID; } | ||
| 179 | |||
| 180 | protected: | ||
| 181 | std::unique_ptr<Document> &Doc; | ||
| 182 |   SMRange SourceRange; | ||
| 183 | |||
| 184 | ~Node() = default; | ||
| 185 | |||
| 186 | private: | ||
| 187 | unsigned int TypeID; | ||
| 188 |   StringRef Anchor; | ||
| 189 |   /// The tag as typed in the document. | ||
| 190 |   StringRef Tag; | ||
| 191 | }; | ||
| 192 | |||
| 193 | /// A null value. | ||
| 194 | /// | ||
| 195 | /// Example: | ||
| 196 | ///   !!null null | ||
| 197 | class NullNode final : public Node { | ||
| 198 | void anchor() override; | ||
| 199 | |||
| 200 | public: | ||
| 201 | NullNode(std::unique_ptr<Document> &D) | ||
| 202 | : Node(NK_Null, D, StringRef(), StringRef()) {} | ||
| 203 | |||
| 204 | static bool classof(const Node *N) { return N->getType() == NK_Null; } | ||
| 205 | }; | ||
| 206 | |||
| 207 | /// A scalar node is an opaque datum that can be presented as a | ||
| 208 | ///        series of zero or more Unicode scalar values. | ||
| 209 | /// | ||
| 210 | /// Example: | ||
| 211 | ///   Adena | ||
| 212 | class ScalarNode final : public Node { | ||
| 213 | void anchor() override; | ||
| 214 | |||
| 215 | public: | ||
| 216 | ScalarNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag, | ||
| 217 |              StringRef Val) | ||
| 218 | : Node(NK_Scalar, D, Anchor, Tag), Value(Val) { | ||
| 219 | SMLoc Start = SMLoc::getFromPointer(Val.begin()); | ||
| 220 | SMLoc End = SMLoc::getFromPointer(Val.end()); | ||
| 221 | SourceRange = SMRange(Start, End); | ||
| 222 |   } | ||
| 223 | |||
| 224 |   // Return Value without any escaping or folding or other fun YAML stuff. This | ||
| 225 |   // is the exact bytes that are contained in the file (after conversion to | ||
| 226 |   // utf8). | ||
| 227 | StringRef getRawValue() const { return Value; } | ||
| 228 | |||
| 229 |   /// Gets the value of this node as a StringRef. | ||
| 230 |   /// | ||
| 231 |   /// \param Storage is used to store the content of the returned StringRef if | ||
| 232 |   ///        it requires any modification from how it appeared in the source. | ||
| 233 |   ///        This happens with escaped characters and multi-line literals. | ||
| 234 | StringRef getValue(SmallVectorImpl<char> &Storage) const; | ||
| 235 | |||
| 236 | static bool classof(const Node *N) { | ||
| 237 | return N->getType() == NK_Scalar; | ||
| 238 |   } | ||
| 239 | |||
| 240 | private: | ||
| 241 |   StringRef Value; | ||
| 242 | |||
| 243 |   StringRef unescapeDoubleQuoted(StringRef UnquotedValue, | ||
| 244 | StringRef::size_type Start, | ||
| 245 | SmallVectorImpl<char> &Storage) const; | ||
| 246 | }; | ||
| 247 | |||
| 248 | /// A block scalar node is an opaque datum that can be presented as a | ||
| 249 | ///        series of zero or more Unicode scalar values. | ||
| 250 | /// | ||
| 251 | /// Example: | ||
| 252 | ///   | | ||
| 253 | ///     Hello | ||
| 254 | ///     World | ||
| 255 | class BlockScalarNode final : public Node { | ||
| 256 | void anchor() override; | ||
| 257 | |||
| 258 | public: | ||
| 259 | BlockScalarNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag, | ||
| 260 |                   StringRef Value, StringRef RawVal) | ||
| 261 | : Node(NK_BlockScalar, D, Anchor, Tag), Value(Value) { | ||
| 262 | SMLoc Start = SMLoc::getFromPointer(RawVal.begin()); | ||
| 263 | SMLoc End = SMLoc::getFromPointer(RawVal.end()); | ||
| 264 | SourceRange = SMRange(Start, End); | ||
| 265 |   } | ||
| 266 | |||
| 267 |   /// Gets the value of this node as a StringRef. | ||
| 268 | StringRef getValue() const { return Value; } | ||
| 269 | |||
| 270 | static bool classof(const Node *N) { | ||
| 271 | return N->getType() == NK_BlockScalar; | ||
| 272 |   } | ||
| 273 | |||
| 274 | private: | ||
| 275 |   StringRef Value; | ||
| 276 | }; | ||
| 277 | |||
| 278 | /// A key and value pair. While not technically a Node under the YAML | ||
| 279 | ///        representation graph, it is easier to treat them this way. | ||
| 280 | /// | ||
| 281 | /// TODO: Consider making this not a child of Node. | ||
| 282 | /// | ||
| 283 | /// Example: | ||
| 284 | ///   Section: .text | ||
| 285 | class KeyValueNode final : public Node { | ||
| 286 | void anchor() override; | ||
| 287 | |||
| 288 | public: | ||
| 289 | KeyValueNode(std::unique_ptr<Document> &D) | ||
| 290 | : Node(NK_KeyValue, D, StringRef(), StringRef()) {} | ||
| 291 | |||
| 292 |   /// Parse and return the key. | ||
| 293 |   /// | ||
| 294 |   /// This may be called multiple times. | ||
| 295 |   /// | ||
| 296 |   /// \returns The key, or nullptr if failed() == true. | ||
| 297 | Node *getKey(); | ||
| 298 | |||
| 299 |   /// Parse and return the value. | ||
| 300 |   /// | ||
| 301 |   /// This may be called multiple times. | ||
| 302 |   /// | ||
| 303 |   /// \returns The value, or nullptr if failed() == true. | ||
| 304 | Node *getValue(); | ||
| 305 | |||
| 306 | void skip() override { | ||
| 307 | if (Node *Key = getKey()) { | ||
| 308 | Key->skip(); | ||
| 309 | if (Node *Val = getValue()) | ||
| 310 | Val->skip(); | ||
| 311 |     } | ||
| 312 |   } | ||
| 313 | |||
| 314 | static bool classof(const Node *N) { | ||
| 315 | return N->getType() == NK_KeyValue; | ||
| 316 |   } | ||
| 317 | |||
| 318 | private: | ||
| 319 | Node *Key = nullptr; | ||
| 320 | Node *Value = nullptr; | ||
| 321 | }; | ||
| 322 | |||
| 323 | /// This is an iterator abstraction over YAML collections shared by both | ||
| 324 | ///        sequences and maps. | ||
| 325 | /// | ||
| 326 | /// BaseT must have a ValueT* member named CurrentEntry and a member function | ||
| 327 | /// increment() which must set CurrentEntry to 0 to create an end iterator. | ||
| 328 | template <class BaseT, class ValueT> class basic_collection_iterator { | ||
| 329 | public: | ||
| 330 | using iterator_category = std::input_iterator_tag; | ||
| 331 | using value_type = ValueT; | ||
| 332 | using difference_type = std::ptrdiff_t; | ||
| 333 | using pointer = value_type *; | ||
| 334 | using reference = value_type &; | ||
| 335 | |||
| 336 | basic_collection_iterator() = default; | ||
| 337 | basic_collection_iterator(BaseT *B) : Base(B) {} | ||
| 338 | |||
| 339 | ValueT *operator->() const { | ||
| 340 | assert(Base && Base->CurrentEntry && "Attempted to access end iterator!"); | ||
| 341 | return Base->CurrentEntry; | ||
| 342 |   } | ||
| 343 | |||
| 344 | ValueT &operator*() const { | ||
| 345 | assert(Base && Base->CurrentEntry && | ||
| 346 | "Attempted to dereference end iterator!"); | ||
| 347 | return *Base->CurrentEntry; | ||
| 348 |   } | ||
| 349 | |||
| 350 | operator ValueT *() const { | ||
| 351 | assert(Base && Base->CurrentEntry && "Attempted to access end iterator!"); | ||
| 352 | return Base->CurrentEntry; | ||
| 353 |   } | ||
| 354 | |||
| 355 |   /// Note on EqualityComparable: | ||
| 356 |   /// | ||
| 357 |   /// The iterator is not re-entrant, | ||
| 358 |   /// it is meant to be used for parsing YAML on-demand | ||
| 359 |   /// Once iteration started - it can point only to one entry at a time | ||
| 360 |   /// hence Base.CurrentEntry and Other.Base.CurrentEntry are equal | ||
| 361 |   /// iff Base and Other.Base are equal. | ||
| 362 | bool operator==(const basic_collection_iterator &Other) const { | ||
| 363 | if (Base && (Base == Other.Base)) { | ||
| 364 | assert((Base->CurrentEntry == Other.Base->CurrentEntry) | ||
| 365 | && "Equal Bases expected to point to equal Entries"); | ||
| 366 |     } | ||
| 367 | |||
| 368 | return Base == Other.Base; | ||
| 369 |   } | ||
| 370 | |||
| 371 | bool operator!=(const basic_collection_iterator &Other) const { | ||
| 372 | return !(Base == Other.Base); | ||
| 373 |   } | ||
| 374 | |||
| 375 | basic_collection_iterator &operator++() { | ||
| 376 | assert(Base && "Attempted to advance iterator past end!"); | ||
| 377 | Base->increment(); | ||
| 378 |     // Create an end iterator. | ||
| 379 | if (!Base->CurrentEntry) | ||
| 380 | Base = nullptr; | ||
| 381 | return *this; | ||
| 382 |   } | ||
| 383 | |||
| 384 | private: | ||
| 385 | BaseT *Base = nullptr; | ||
| 386 | }; | ||
| 387 | |||
| 388 | // The following two templates are used for both MappingNode and Sequence Node. | ||
| 389 | template <class CollectionType> | ||
| 390 | typename CollectionType::iterator begin(CollectionType &C) { | ||
| 391 | assert(C.IsAtBeginning && "You may only iterate over a collection once!"); | ||
| 392 | C.IsAtBeginning = false; | ||
| 393 | typename CollectionType::iterator ret(&C); | ||
| 394 | ++ret; | ||
| 395 | return ret; | ||
| 396 | } | ||
| 397 | |||
| 398 | template <class CollectionType> void skip(CollectionType &C) { | ||
| 399 |   // TODO: support skipping from the middle of a parsed collection ;/ | ||
| 400 | assert((C.IsAtBeginning || C.IsAtEnd) && "Cannot skip mid parse!"); | ||
| 401 | if (C.IsAtBeginning) | ||
| 402 | for (typename CollectionType::iterator i = begin(C), e = C.end(); i != e; | ||
| 403 | ++i) | ||
| 404 | i->skip(); | ||
| 405 | } | ||
| 406 | |||
| 407 | /// Represents a YAML map created from either a block map for a flow map. | ||
| 408 | /// | ||
| 409 | /// This parses the YAML stream as increment() is called. | ||
| 410 | /// | ||
| 411 | /// Example: | ||
| 412 | ///   Name: _main | ||
| 413 | ///   Scope: Global | ||
| 414 | class MappingNode final : public Node { | ||
| 415 | void anchor() override; | ||
| 416 | |||
| 417 | public: | ||
| 418 | enum MappingType { | ||
| 419 | MT_Block, | ||
| 420 | MT_Flow, | ||
| 421 |     MT_Inline ///< An inline mapping node is used for "[key: value]". | ||
| 422 | }; | ||
| 423 | |||
| 424 | MappingNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag, | ||
| 425 |               MappingType MT) | ||
| 426 | : Node(NK_Mapping, D, Anchor, Tag), Type(MT) {} | ||
| 427 | |||
| 428 | friend class basic_collection_iterator<MappingNode, KeyValueNode>; | ||
| 429 | |||
| 430 | using iterator = basic_collection_iterator<MappingNode, KeyValueNode>; | ||
| 431 | |||
| 432 | template <class T> friend typename T::iterator yaml::begin(T &); | ||
| 433 | template <class T> friend void yaml::skip(T &); | ||
| 434 | |||
| 435 | iterator begin() { return yaml::begin(*this); } | ||
| 436 | |||
| 437 | iterator end() { return iterator(); } | ||
| 438 | |||
| 439 | void skip() override { yaml::skip(*this); } | ||
| 440 | |||
| 441 | static bool classof(const Node *N) { | ||
| 442 | return N->getType() == NK_Mapping; | ||
| 443 |   } | ||
| 444 | |||
| 445 | private: | ||
| 446 |   MappingType Type; | ||
| 447 | bool IsAtBeginning = true; | ||
| 448 | bool IsAtEnd = false; | ||
| 449 | KeyValueNode *CurrentEntry = nullptr; | ||
| 450 | |||
| 451 | void increment(); | ||
| 452 | }; | ||
| 453 | |||
| 454 | /// Represents a YAML sequence created from either a block sequence for a | ||
| 455 | ///        flow sequence. | ||
| 456 | /// | ||
| 457 | /// This parses the YAML stream as increment() is called. | ||
| 458 | /// | ||
| 459 | /// Example: | ||
| 460 | ///   - Hello | ||
| 461 | ///   - World | ||
| 462 | class SequenceNode final : public Node { | ||
| 463 | void anchor() override; | ||
| 464 | |||
| 465 | public: | ||
| 466 | enum SequenceType { | ||
| 467 | ST_Block, | ||
| 468 | ST_Flow, | ||
| 469 |     // Use for: | ||
| 470 |     // | ||
| 471 |     // key: | ||
| 472 |     // - val1 | ||
| 473 |     // - val2 | ||
| 474 |     // | ||
| 475 |     // As a BlockMappingEntry and BlockEnd are not created in this case. | ||
| 476 | ST_Indentless | ||
| 477 | }; | ||
| 478 | |||
| 479 | SequenceNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag, | ||
| 480 |                SequenceType ST) | ||
| 481 | : Node(NK_Sequence, D, Anchor, Tag), SeqType(ST) {} | ||
| 482 | |||
| 483 | friend class basic_collection_iterator<SequenceNode, Node>; | ||
| 484 | |||
| 485 | using iterator = basic_collection_iterator<SequenceNode, Node>; | ||
| 486 | |||
| 487 | template <class T> friend typename T::iterator yaml::begin(T &); | ||
| 488 | template <class T> friend void yaml::skip(T &); | ||
| 489 | |||
| 490 | void increment(); | ||
| 491 | |||
| 492 | iterator begin() { return yaml::begin(*this); } | ||
| 493 | |||
| 494 | iterator end() { return iterator(); } | ||
| 495 | |||
| 496 | void skip() override { yaml::skip(*this); } | ||
| 497 | |||
| 498 | static bool classof(const Node *N) { | ||
| 499 | return N->getType() == NK_Sequence; | ||
| 500 |   } | ||
| 501 | |||
| 502 | private: | ||
| 503 |   SequenceType SeqType; | ||
| 504 | bool IsAtBeginning = true; | ||
| 505 | bool IsAtEnd = false; | ||
| 506 | bool WasPreviousTokenFlowEntry = true; // Start with an imaginary ','. | ||
| 507 | Node *CurrentEntry = nullptr; | ||
| 508 | }; | ||
| 509 | |||
| 510 | /// Represents an alias to a Node with an anchor. | ||
| 511 | /// | ||
| 512 | /// Example: | ||
| 513 | ///   *AnchorName | ||
| 514 | class AliasNode final : public Node { | ||
| 515 | void anchor() override; | ||
| 516 | |||
| 517 | public: | ||
| 518 | AliasNode(std::unique_ptr<Document> &D, StringRef Val) | ||
| 519 | : Node(NK_Alias, D, StringRef(), StringRef()), Name(Val) {} | ||
| 520 | |||
| 521 | StringRef getName() const { return Name; } | ||
| 522 | |||
| 523 | static bool classof(const Node *N) { return N->getType() == NK_Alias; } | ||
| 524 | |||
| 525 | private: | ||
| 526 |   StringRef Name; | ||
| 527 | }; | ||
| 528 | |||
| 529 | /// A YAML Stream is a sequence of Documents. A document contains a root | ||
| 530 | ///        node. | ||
| 531 | class Document { | ||
| 532 | public: | ||
| 533 | Document(Stream &ParentStream); | ||
| 534 | |||
| 535 |   /// Root for parsing a node. Returns a single node. | ||
| 536 | Node *parseBlockNode(); | ||
| 537 | |||
| 538 |   /// Finish parsing the current document and return true if there are | ||
| 539 |   ///        more. Return false otherwise. | ||
| 540 | bool skip(); | ||
| 541 | |||
| 542 |   /// Parse and return the root level node. | ||
| 543 | Node *getRoot() { | ||
| 544 | if (Root) | ||
| 545 | return Root; | ||
| 546 | return Root = parseBlockNode(); | ||
| 547 |   } | ||
| 548 | |||
| 549 | const std::map<StringRef, StringRef> &getTagMap() const { return TagMap; } | ||
| 550 | |||
| 551 | private: | ||
| 552 | friend class Node; | ||
| 553 | friend class document_iterator; | ||
| 554 | |||
| 555 |   /// Stream to read tokens from. | ||
| 556 | Stream &stream; | ||
| 557 | |||
| 558 |   /// Used to allocate nodes to. All are destroyed without calling their | ||
| 559 |   ///        destructor when the document is destroyed. | ||
| 560 |   BumpPtrAllocator NodeAllocator; | ||
| 561 | |||
| 562 |   /// The root node. Used to support skipping a partially parsed | ||
| 563 |   ///        document. | ||
| 564 | Node *Root; | ||
| 565 | |||
| 566 |   /// Maps tag prefixes to their expansion. | ||
| 567 | std::map<StringRef, StringRef> TagMap; | ||
| 568 | |||
| 569 | Token &peekNext(); | ||
| 570 | Token getNext(); | ||
| 571 | void setError(const Twine &Message, Token &Location) const; | ||
| 572 | bool failed() const; | ||
| 573 | |||
| 574 |   /// Parse %BLAH directives and return true if any were encountered. | ||
| 575 | bool parseDirectives(); | ||
| 576 | |||
| 577 |   /// Parse %YAML | ||
| 578 | void parseYAMLDirective(); | ||
| 579 | |||
| 580 |   /// Parse %TAG | ||
| 581 | void parseTAGDirective(); | ||
| 582 | |||
| 583 |   /// Consume the next token and error if it is not \a TK. | ||
| 584 | bool expectToken(int TK); | ||
| 585 | }; | ||
| 586 | |||
| 587 | /// Iterator abstraction for Documents over a Stream. | ||
| 588 | class document_iterator { | ||
| 589 | public: | ||
| 590 | document_iterator() = default; | ||
| 591 | document_iterator(std::unique_ptr<Document> &D) : Doc(&D) {} | ||
| 592 | |||
| 593 | bool operator==(const document_iterator &Other) const { | ||
| 594 | if (isAtEnd() || Other.isAtEnd()) | ||
| 595 | return isAtEnd() && Other.isAtEnd(); | ||
| 596 | |||
| 597 | return Doc == Other.Doc; | ||
| 598 |   } | ||
| 599 | bool operator!=(const document_iterator &Other) const { | ||
| 600 | return !(*this == Other); | ||
| 601 |   } | ||
| 602 | |||
| 603 | document_iterator operator++() { | ||
| 604 | assert(Doc && "incrementing iterator past the end."); | ||
| 605 | if (!(*Doc)->skip()) { | ||
| 606 | Doc->reset(nullptr); | ||
| 607 | } else { | ||
| 608 | Stream &S = (*Doc)->stream; | ||
| 609 | Doc->reset(new Document(S)); | ||
| 610 |     } | ||
| 611 | return *this; | ||
| 612 |   } | ||
| 613 | |||
| 614 | Document &operator*() { return **Doc; } | ||
| 615 | |||
| 616 | std::unique_ptr<Document> &operator->() { return *Doc; } | ||
| 617 | |||
| 618 | private: | ||
| 619 | bool isAtEnd() const { return !Doc || !*Doc; } | ||
| 620 | |||
| 621 | std::unique_ptr<Document> *Doc = nullptr; | ||
| 622 | }; | ||
| 623 | |||
| 624 | } // end namespace yaml | ||
| 625 | |||
| 626 | } // end namespace llvm | ||
| 627 | |||
| 628 | #endif // LLVM_SUPPORT_YAMLPARSER_H |