5 #include "collectionstack.h" // IWYU pragma: keep
7 #include "singledocparser.h"
10 #include "yaml-cpp/emitterstyle.h"
11 #include "yaml-cpp/eventhandler.h"
12 #include "yaml-cpp/exceptions.h" // IWYU pragma: keep
13 #include "yaml-cpp/mark.h"
14 #include "yaml-cpp/null.h"
17 SingleDocParser::SingleDocParser(Scanner& scanner, const Directives& directives)
19 m_directives(directives),
20 m_pCollectionStack(new CollectionStack),
23 SingleDocParser::~SingleDocParser() {}
26 // . Handles the next document
27 // . Throws a ParserException on error.
28 void SingleDocParser::HandleDocument(EventHandler& eventHandler) {
29 assert(!m_scanner.empty()); // guaranteed that there are tokens
32 eventHandler.OnDocumentStart(m_scanner.peek().mark);
35 if (m_scanner.peek().type == Token::DOC_START)
39 HandleNode(eventHandler);
41 eventHandler.OnDocumentEnd();
43 // and finally eat any doc ends we see
44 while (!m_scanner.empty() && m_scanner.peek().type == Token::DOC_END)
48 void SingleDocParser::HandleNode(EventHandler& eventHandler) {
49 // an empty node *is* a possibility
50 if (m_scanner.empty()) {
51 eventHandler.OnNull(m_scanner.mark(), NullAnchor);
56 Mark mark = m_scanner.peek().mark;
58 // special case: a value node by itself must be a map, with no header
59 if (m_scanner.peek().type == Token::VALUE) {
60 eventHandler.OnMapStart(mark, "?", NullAnchor, EmitterStyle::Default);
61 HandleMap(eventHandler);
62 eventHandler.OnMapEnd();
66 // special case: an alias node
67 if (m_scanner.peek().type == Token::ALIAS) {
68 eventHandler.OnAlias(mark, LookupAnchor(mark, m_scanner.peek().value));
75 ParseProperties(tag, anchor);
77 const Token& token = m_scanner.peek();
79 if (token.type == Token::PLAIN_SCALAR && IsNullString(token.value)) {
80 eventHandler.OnNull(mark, anchor);
85 // add non-specific tags
87 tag = (token.type == Token::NON_PLAIN_SCALAR ? "!" : "?");
89 // now split based on what kind of node we should be
91 case Token::PLAIN_SCALAR:
92 case Token::NON_PLAIN_SCALAR:
93 eventHandler.OnScalar(mark, tag, anchor, token.value);
96 case Token::FLOW_SEQ_START:
97 eventHandler.OnSequenceStart(mark, tag, anchor, EmitterStyle::Flow);
98 HandleSequence(eventHandler);
99 eventHandler.OnSequenceEnd();
101 case Token::BLOCK_SEQ_START:
102 eventHandler.OnSequenceStart(mark, tag, anchor, EmitterStyle::Block);
103 HandleSequence(eventHandler);
104 eventHandler.OnSequenceEnd();
106 case Token::FLOW_MAP_START:
107 eventHandler.OnMapStart(mark, tag, anchor, EmitterStyle::Flow);
108 HandleMap(eventHandler);
109 eventHandler.OnMapEnd();
111 case Token::BLOCK_MAP_START:
112 eventHandler.OnMapStart(mark, tag, anchor, EmitterStyle::Block);
113 HandleMap(eventHandler);
114 eventHandler.OnMapEnd();
117 // compact maps can only go in a flow sequence
118 if (m_pCollectionStack->GetCurCollectionType() ==
119 CollectionType::FlowSeq) {
120 eventHandler.OnMapStart(mark, tag, anchor, EmitterStyle::Flow);
121 HandleMap(eventHandler);
122 eventHandler.OnMapEnd();
131 eventHandler.OnNull(mark, anchor);
133 eventHandler.OnScalar(mark, tag, anchor, "");
136 void SingleDocParser::HandleSequence(EventHandler& eventHandler) {
137 // split based on start token
138 switch (m_scanner.peek().type) {
139 case Token::BLOCK_SEQ_START:
140 HandleBlockSequence(eventHandler);
142 case Token::FLOW_SEQ_START:
143 HandleFlowSequence(eventHandler);
150 void SingleDocParser::HandleBlockSequence(EventHandler& eventHandler) {
153 m_pCollectionStack->PushCollectionType(CollectionType::BlockSeq);
156 if (m_scanner.empty())
157 throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ);
159 Token token = m_scanner.peek();
160 if (token.type != Token::BLOCK_ENTRY && token.type != Token::BLOCK_SEQ_END)
161 throw ParserException(token.mark, ErrorMsg::END_OF_SEQ);
164 if (token.type == Token::BLOCK_SEQ_END)
168 if (!m_scanner.empty()) {
169 const Token& token_ = m_scanner.peek();
170 if (token_.type == Token::BLOCK_ENTRY ||
171 token_.type == Token::BLOCK_SEQ_END) {
172 eventHandler.OnNull(token_.mark, NullAnchor);
177 HandleNode(eventHandler);
180 m_pCollectionStack->PopCollectionType(CollectionType::BlockSeq);
183 void SingleDocParser::HandleFlowSequence(EventHandler& eventHandler) {
186 m_pCollectionStack->PushCollectionType(CollectionType::FlowSeq);
189 if (m_scanner.empty())
190 throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ_FLOW);
192 // first check for end
193 if (m_scanner.peek().type == Token::FLOW_SEQ_END) {
198 // then read the node
199 HandleNode(eventHandler);
201 if (m_scanner.empty())
202 throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ_FLOW);
204 // now eat the separator (or could be a sequence end, which we ignore - but
205 // if it's neither, then it's a bad node)
206 Token& token = m_scanner.peek();
207 if (token.type == Token::FLOW_ENTRY)
209 else if (token.type != Token::FLOW_SEQ_END)
210 throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW);
213 m_pCollectionStack->PopCollectionType(CollectionType::FlowSeq);
216 void SingleDocParser::HandleMap(EventHandler& eventHandler) {
217 // split based on start token
218 switch (m_scanner.peek().type) {
219 case Token::BLOCK_MAP_START:
220 HandleBlockMap(eventHandler);
222 case Token::FLOW_MAP_START:
223 HandleFlowMap(eventHandler);
226 HandleCompactMap(eventHandler);
229 HandleCompactMapWithNoKey(eventHandler);
236 void SingleDocParser::HandleBlockMap(EventHandler& eventHandler) {
239 m_pCollectionStack->PushCollectionType(CollectionType::BlockMap);
242 if (m_scanner.empty())
243 throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP);
245 Token token = m_scanner.peek();
246 if (token.type != Token::KEY && token.type != Token::VALUE &&
247 token.type != Token::BLOCK_MAP_END)
248 throw ParserException(token.mark, ErrorMsg::END_OF_MAP);
250 if (token.type == Token::BLOCK_MAP_END) {
255 // grab key (if non-null)
256 if (token.type == Token::KEY) {
258 HandleNode(eventHandler);
260 eventHandler.OnNull(token.mark, NullAnchor);
263 // now grab value (optional)
264 if (!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
266 HandleNode(eventHandler);
268 eventHandler.OnNull(token.mark, NullAnchor);
272 m_pCollectionStack->PopCollectionType(CollectionType::BlockMap);
275 void SingleDocParser::HandleFlowMap(EventHandler& eventHandler) {
278 m_pCollectionStack->PushCollectionType(CollectionType::FlowMap);
281 if (m_scanner.empty())
282 throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP_FLOW);
284 Token& token = m_scanner.peek();
285 const Mark mark = token.mark;
286 // first check for end
287 if (token.type == Token::FLOW_MAP_END) {
292 // grab key (if non-null)
293 if (token.type == Token::KEY) {
295 HandleNode(eventHandler);
297 eventHandler.OnNull(mark, NullAnchor);
300 // now grab value (optional)
301 if (!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
303 HandleNode(eventHandler);
305 eventHandler.OnNull(mark, NullAnchor);
308 if (m_scanner.empty())
309 throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP_FLOW);
311 // now eat the separator (or could be a map end, which we ignore - but if
312 // it's neither, then it's a bad node)
313 Token& nextToken = m_scanner.peek();
314 if (nextToken.type == Token::FLOW_ENTRY)
316 else if (nextToken.type != Token::FLOW_MAP_END)
317 throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW);
320 m_pCollectionStack->PopCollectionType(CollectionType::FlowMap);
323 // . Single "key: value" pair in a flow sequence
324 void SingleDocParser::HandleCompactMap(EventHandler& eventHandler) {
325 m_pCollectionStack->PushCollectionType(CollectionType::CompactMap);
328 Mark mark = m_scanner.peek().mark;
330 HandleNode(eventHandler);
332 // now grab value (optional)
333 if (!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
335 HandleNode(eventHandler);
337 eventHandler.OnNull(mark, NullAnchor);
340 m_pCollectionStack->PopCollectionType(CollectionType::CompactMap);
343 // . Single ": value" pair in a flow sequence
344 void SingleDocParser::HandleCompactMapWithNoKey(EventHandler& eventHandler) {
345 m_pCollectionStack->PushCollectionType(CollectionType::CompactMap);
348 eventHandler.OnNull(m_scanner.peek().mark, NullAnchor);
352 HandleNode(eventHandler);
354 m_pCollectionStack->PopCollectionType(CollectionType::CompactMap);
358 // . Grabs any tag or anchor tokens and deals with them.
359 void SingleDocParser::ParseProperties(std::string& tag, anchor_t& anchor) {
364 if (m_scanner.empty())
367 switch (m_scanner.peek().type) {
380 void SingleDocParser::ParseTag(std::string& tag) {
381 Token& token = m_scanner.peek();
383 throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS);
386 tag = tagInfo.Translate(m_directives);
390 void SingleDocParser::ParseAnchor(anchor_t& anchor) {
391 Token& token = m_scanner.peek();
393 throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS);
395 anchor = RegisterAnchor(token.value);
399 anchor_t SingleDocParser::RegisterAnchor(const std::string& name) {
403 return m_anchors[name] = ++m_curAnchor;
406 anchor_t SingleDocParser::LookupAnchor(const Mark& mark,
407 const std::string& name) const {
408 Anchors::const_iterator it = m_anchors.find(name);
409 if (it == m_anchors.end())
410 throw ParserException(mark, ErrorMsg::UNKNOWN_ANCHOR);