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