yaml-cpp

FORK: A YAML parser and emitter in C++
git clone https://git.neptards.moe/neptards/yaml-cpp.git
Log | Files | Refs | README | LICENSE

singledocparser.cpp (12063B)


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