summaryrefslogtreecommitdiffstats
path: root/external_libs/yaml-cpp/src/singledocparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'external_libs/yaml-cpp/src/singledocparser.cpp')
-rw-r--r--external_libs/yaml-cpp/src/singledocparser.cpp381
1 files changed, 381 insertions, 0 deletions
diff --git a/external_libs/yaml-cpp/src/singledocparser.cpp b/external_libs/yaml-cpp/src/singledocparser.cpp
new file mode 100644
index 00000000..47759c32
--- /dev/null
+++ b/external_libs/yaml-cpp/src/singledocparser.cpp
@@ -0,0 +1,381 @@
+#include "singledocparser.h"
+#include "collectionstack.h"
+#include "directives.h"
+#include "yaml-cpp/eventhandler.h"
+#include "yaml-cpp/exceptions.h"
+#include "scanner.h"
+#include "tag.h"
+#include "token.h"
+#include <sstream>
+#include <cstdio>
+#include <algorithm>
+
+namespace YAML
+{
+ SingleDocParser::SingleDocParser(Scanner& scanner, const Directives& directives): m_scanner(scanner), m_directives(directives), m_pCollectionStack(new CollectionStack), m_curAnchor(0)
+ {
+ }
+
+ SingleDocParser::~SingleDocParser()
+ {
+ }
+
+ // HandleDocument
+ // . Handles the next document
+ // . Throws a ParserException on error.
+ void SingleDocParser::HandleDocument(EventHandler& eventHandler)
+ {
+ assert(!m_scanner.empty()); // guaranteed that there are tokens
+ assert(!m_curAnchor);
+
+ eventHandler.OnDocumentStart(m_scanner.peek().mark);
+
+ // eat doc start
+ if(m_scanner.peek().type == Token::DOC_START)
+ m_scanner.pop();
+
+ // recurse!
+ HandleNode(eventHandler);
+
+ eventHandler.OnDocumentEnd();
+
+ // and finally eat any doc ends we see
+ while(!m_scanner.empty() && m_scanner.peek().type == Token::DOC_END)
+ m_scanner.pop();
+ }
+
+ void SingleDocParser::HandleNode(EventHandler& eventHandler)
+ {
+ // an empty node *is* a possibility
+ if(m_scanner.empty()) {
+ eventHandler.OnNull(Mark::null(), NullAnchor);
+ return;
+ }
+
+ // save location
+ Mark mark = m_scanner.peek().mark;
+
+ // special case: a value node by itself must be a map, with no header
+ if(m_scanner.peek().type == Token::VALUE) {
+ eventHandler.OnMapStart(mark, "", NullAnchor);
+ HandleMap(eventHandler);
+ eventHandler.OnMapEnd();
+ return;
+ }
+
+ // special case: an alias node
+ if(m_scanner.peek().type == Token::ALIAS) {
+ eventHandler.OnAlias(mark, LookupAnchor(mark, m_scanner.peek().value));
+ m_scanner.pop();
+ return;
+ }
+
+ std::string tag;
+ anchor_t anchor;
+ ParseProperties(tag, anchor);
+
+ const Token& token = m_scanner.peek();
+
+ // add non-specific tags
+ if(tag.empty())
+ tag = (token.type == Token::NON_PLAIN_SCALAR ? "!" : "?");
+
+ // now split based on what kind of node we should be
+ switch(token.type) {
+ case Token::PLAIN_SCALAR:
+ case Token::NON_PLAIN_SCALAR:
+ eventHandler.OnScalar(mark, tag, anchor, token.value);
+ m_scanner.pop();
+ return;
+ case Token::FLOW_SEQ_START:
+ case Token::BLOCK_SEQ_START:
+ eventHandler.OnSequenceStart(mark, tag, anchor);
+ HandleSequence(eventHandler);
+ eventHandler.OnSequenceEnd();
+ return;
+ case Token::FLOW_MAP_START:
+ case Token::BLOCK_MAP_START:
+ eventHandler.OnMapStart(mark, tag, anchor);
+ HandleMap(eventHandler);
+ eventHandler.OnMapEnd();
+ return;
+ case Token::KEY:
+ // compact maps can only go in a flow sequence
+ if(m_pCollectionStack->GetCurCollectionType() == CollectionType::FlowSeq) {
+ eventHandler.OnMapStart(mark, tag, anchor);
+ HandleMap(eventHandler);
+ eventHandler.OnMapEnd();
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if(tag == "?")
+ eventHandler.OnNull(mark, anchor);
+ else
+ eventHandler.OnScalar(mark, tag, anchor, "");
+ }
+
+ void SingleDocParser::HandleSequence(EventHandler& eventHandler)
+ {
+ // split based on start token
+ switch(m_scanner.peek().type) {
+ case Token::BLOCK_SEQ_START: HandleBlockSequence(eventHandler); break;
+ case Token::FLOW_SEQ_START: HandleFlowSequence(eventHandler); break;
+ default: break;
+ }
+ }
+
+ void SingleDocParser::HandleBlockSequence(EventHandler& eventHandler)
+ {
+ // eat start token
+ m_scanner.pop();
+ m_pCollectionStack->PushCollectionType(CollectionType::BlockSeq);
+
+ while(1) {
+ if(m_scanner.empty())
+ throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ);
+
+ Token token = m_scanner.peek();
+ if(token.type != Token::BLOCK_ENTRY && token.type != Token::BLOCK_SEQ_END)
+ throw ParserException(token.mark, ErrorMsg::END_OF_SEQ);
+
+ m_scanner.pop();
+ if(token.type == Token::BLOCK_SEQ_END)
+ break;
+
+ // check for null
+ if(!m_scanner.empty()) {
+ const Token& token = m_scanner.peek();
+ if(token.type == Token::BLOCK_ENTRY || token.type == Token::BLOCK_SEQ_END) {
+ eventHandler.OnNull(token.mark, NullAnchor);
+ continue;
+ }
+ }
+
+ HandleNode(eventHandler);
+ }
+
+ m_pCollectionStack->PopCollectionType(CollectionType::BlockSeq);
+ }
+
+ void SingleDocParser::HandleFlowSequence(EventHandler& eventHandler)
+ {
+ // eat start token
+ m_scanner.pop();
+ m_pCollectionStack->PushCollectionType(CollectionType::FlowSeq);
+
+ while(1) {
+ if(m_scanner.empty())
+ throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ_FLOW);
+
+ // first check for end
+ if(m_scanner.peek().type == Token::FLOW_SEQ_END) {
+ m_scanner.pop();
+ break;
+ }
+
+ // then read the node
+ HandleNode(eventHandler);
+
+ // now eat the separator (or could be a sequence end, which we ignore - but if it's neither, then it's a bad node)
+ Token& token = m_scanner.peek();
+ if(token.type == Token::FLOW_ENTRY)
+ m_scanner.pop();
+ else if(token.type != Token::FLOW_SEQ_END)
+ throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW);
+ }
+
+ m_pCollectionStack->PopCollectionType(CollectionType::FlowSeq);
+ }
+
+ void SingleDocParser::HandleMap(EventHandler& eventHandler)
+ {
+ // split based on start token
+ switch(m_scanner.peek().type) {
+ case Token::BLOCK_MAP_START: HandleBlockMap(eventHandler); break;
+ case Token::FLOW_MAP_START: HandleFlowMap(eventHandler); break;
+ case Token::KEY: HandleCompactMap(eventHandler); break;
+ case Token::VALUE: HandleCompactMapWithNoKey(eventHandler); break;
+ default: break;
+ }
+ }
+
+ void SingleDocParser::HandleBlockMap(EventHandler& eventHandler)
+ {
+ // eat start token
+ m_scanner.pop();
+ m_pCollectionStack->PushCollectionType(CollectionType::BlockMap);
+
+ while(1) {
+ if(m_scanner.empty())
+ throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP);
+
+ Token token = m_scanner.peek();
+ if(token.type != Token::KEY && token.type != Token::VALUE && token.type != Token::BLOCK_MAP_END)
+ throw ParserException(token.mark, ErrorMsg::END_OF_MAP);
+
+ if(token.type == Token::BLOCK_MAP_END) {
+ m_scanner.pop();
+ break;
+ }
+
+ // grab key (if non-null)
+ if(token.type == Token::KEY) {
+ m_scanner.pop();
+ HandleNode(eventHandler);
+ } else {
+ eventHandler.OnNull(token.mark, NullAnchor);
+ }
+
+ // now grab value (optional)
+ if(!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
+ m_scanner.pop();
+ HandleNode(eventHandler);
+ } else {
+ eventHandler.OnNull(token.mark, NullAnchor);
+ }
+ }
+
+ m_pCollectionStack->PopCollectionType(CollectionType::BlockMap);
+ }
+
+ void SingleDocParser::HandleFlowMap(EventHandler& eventHandler)
+ {
+ // eat start token
+ m_scanner.pop();
+ m_pCollectionStack->PushCollectionType(CollectionType::FlowMap);
+
+ while(1) {
+ if(m_scanner.empty())
+ throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP_FLOW);
+
+ Token& token = m_scanner.peek();
+ // first check for end
+ if(token.type == Token::FLOW_MAP_END) {
+ m_scanner.pop();
+ break;
+ }
+
+ // grab key (if non-null)
+ if(token.type == Token::KEY) {
+ m_scanner.pop();
+ HandleNode(eventHandler);
+ } else {
+ eventHandler.OnNull(token.mark, NullAnchor);
+ }
+
+ // now grab value (optional)
+ if(!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
+ m_scanner.pop();
+ HandleNode(eventHandler);
+ } else {
+ eventHandler.OnNull(token.mark, NullAnchor);
+ }
+
+ // now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node)
+ Token& nextToken = m_scanner.peek();
+ if(nextToken.type == Token::FLOW_ENTRY)
+ m_scanner.pop();
+ else if(nextToken.type != Token::FLOW_MAP_END)
+ throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW);
+ }
+
+ m_pCollectionStack->PopCollectionType(CollectionType::FlowMap);
+ }
+
+ // . Single "key: value" pair in a flow sequence
+ void SingleDocParser::HandleCompactMap(EventHandler& eventHandler)
+ {
+ m_pCollectionStack->PushCollectionType(CollectionType::CompactMap);
+
+ // grab key
+ Mark mark = m_scanner.peek().mark;
+ m_scanner.pop();
+ HandleNode(eventHandler);
+
+ // now grab value (optional)
+ if(!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
+ m_scanner.pop();
+ HandleNode(eventHandler);
+ } else {
+ eventHandler.OnNull(mark, NullAnchor);
+ }
+
+ m_pCollectionStack->PopCollectionType(CollectionType::CompactMap);
+ }
+
+ // . Single ": value" pair in a flow sequence
+ void SingleDocParser::HandleCompactMapWithNoKey(EventHandler& eventHandler)
+ {
+ m_pCollectionStack->PushCollectionType(CollectionType::CompactMap);
+
+ // null key
+ eventHandler.OnNull(m_scanner.peek().mark, NullAnchor);
+
+ // grab value
+ m_scanner.pop();
+ HandleNode(eventHandler);
+
+ m_pCollectionStack->PopCollectionType(CollectionType::CompactMap);
+ }
+
+ // ParseProperties
+ // . Grabs any tag or anchor tokens and deals with them.
+ void SingleDocParser::ParseProperties(std::string& tag, anchor_t& anchor)
+ {
+ tag.clear();
+ anchor = NullAnchor;
+
+ while(1) {
+ if(m_scanner.empty())
+ return;
+
+ switch(m_scanner.peek().type) {
+ case Token::TAG: ParseTag(tag); break;
+ case Token::ANCHOR: ParseAnchor(anchor); break;
+ default: return;
+ }
+ }
+ }
+
+ void SingleDocParser::ParseTag(std::string& tag)
+ {
+ Token& token = m_scanner.peek();
+ if(!tag.empty())
+ throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS);
+
+ Tag tagInfo(token);
+ tag = tagInfo.Translate(m_directives);
+ m_scanner.pop();
+ }
+
+ void SingleDocParser::ParseAnchor(anchor_t& anchor)
+ {
+ Token& token = m_scanner.peek();
+ if(anchor)
+ throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS);
+
+ anchor = RegisterAnchor(token.value);
+ m_scanner.pop();
+ }
+
+ anchor_t SingleDocParser::RegisterAnchor(const std::string& name)
+ {
+ if(name.empty())
+ return NullAnchor;
+
+ return m_anchors[name] = ++m_curAnchor;
+ }
+
+ anchor_t SingleDocParser::LookupAnchor(const Mark& mark, const std::string& name) const
+ {
+ Anchors::const_iterator it = m_anchors.find(name);
+ if(it == m_anchors.end())
+ throw ParserException(mark, ErrorMsg::UNKNOWN_ANCHOR);
+
+ return it->second;
+ }
+}