"vscode:/vscode.git/clone" did not exist on "21fbf2ce56124c8dbc758c86b28b4e8bf8339a6c"
Commit 55c8486e authored by rtweeks21's avatar rtweeks21
Browse files

Reintegrated the event-api branch (second iteration) into the rtweeks21-staging branch.

parent 7220c6b7
...@@ -19,17 +19,16 @@ namespace YAML ...@@ -19,17 +19,16 @@ namespace YAML
public: public:
Map(); Map();
Map(const node_map& data);
virtual ~Map(); virtual ~Map();
void Clear(); void Clear();
virtual Content *Clone() const;
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const; virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const; virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual std::size_t GetSize() const; virtual std::size_t GetSize() const;
virtual void Parse(Scanner *pScanner, ParserState& state);
virtual void Write(Emitter& out) const; virtual void Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue);
virtual void EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const;
virtual bool IsMap() const { return true; } virtual bool IsMap() const { return true; }
...@@ -39,14 +38,6 @@ namespace YAML ...@@ -39,14 +38,6 @@ namespace YAML
virtual int Compare(Sequence *) { return 1; } virtual int Compare(Sequence *) { return 1; }
virtual int Compare(Map *pMap); virtual int Compare(Map *pMap);
private:
void ParseBlock(Scanner *pScanner, ParserState& state);
void ParseFlow(Scanner *pScanner, ParserState& state);
void ParseCompact(Scanner *pScanner, ParserState& state);
void ParseCompactWithNoKey(Scanner *pScanner, ParserState& state);
void AddEntry(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue);
private: private:
node_map m_data; node_map m_data;
}; };
......
#include "node.h" #include "node.h"
#include "token.h" #include "aliascontent.h"
#include "scanner.h" #include "aliasmanager.h"
#include "content.h" #include "content.h"
#include "parser.h" #include "emitfromevents.h"
#include "emitter.h"
#include "eventhandler.h"
#include "iterpriv.h"
#include "map.h"
#include "nodebuilder.h"
#include "nodeproperties.h"
#include "scalar.h" #include "scalar.h"
#include "scanner.h"
#include "sequence.h" #include "sequence.h"
#include "map.h"
#include "aliascontent.h"
#include "iterpriv.h"
#include "emitter.h"
#include "tag.h" #include "tag.h"
#include "token.h"
#include <cassert>
#include <stdexcept> #include <stdexcept>
namespace YAML namespace YAML
...@@ -20,17 +25,10 @@ namespace YAML ...@@ -20,17 +25,10 @@ namespace YAML
return *pNode1 < *pNode2; return *pNode1 < *pNode2;
} }
Node::Node(): m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(true) Node::Node(): m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(false)
{ {
} }
Node::Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent)
: m_mark(mark), m_anchor(anchor), m_tag(tag), m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(false)
{
if(pContent)
m_pContent = pContent->Clone();
}
Node::~Node() Node::~Node()
{ {
Clear(); Clear();
...@@ -42,138 +40,105 @@ namespace YAML ...@@ -42,138 +40,105 @@ namespace YAML
m_pContent = 0; m_pContent = 0;
m_alias = false; m_alias = false;
m_referenced = false; m_referenced = false;
m_anchor.clear();
m_tag.clear(); m_tag.clear();
} }
std::auto_ptr<Node> Node::Clone() const std::auto_ptr<Node> Node::Clone() const
{ {
if(m_alias) std::auto_ptr<Node> pNode(new Node);
throw std::runtime_error("yaml-cpp: Can't clone alias"); // TODO: what to do about aliases? NodeBuilder nodeBuilder(*pNode);
EmitEvents(nodeBuilder);
return std::auto_ptr<Node> (new Node(m_mark, m_anchor, m_tag, m_pContent)); return pNode;
} }
void Node::Parse(Scanner *pScanner, ParserState& state) void Node::EmitEvents(EventHandler& eventHandler) const
{ {
Clear(); eventHandler.OnDocumentStart(m_mark);
AliasManager am;
// an empty node *is* a possibility EmitEvents(am, eventHandler);
if(pScanner->empty()) eventHandler.OnDocumentEnd();
return; }
// save location
m_mark = pScanner->peek().mark;
// special case: a value node by itself must be a map, with no header void Node::EmitEvents(AliasManager& am, EventHandler& eventHandler) const
if(pScanner->peek().type == Token::VALUE) { {
m_pContent = new Map; anchor_t anchor = NullAnchor;
m_pContent->Parse(pScanner, state); if(m_referenced || m_alias) {
if(const Node *pOther = am.LookupReference(*this)) {
eventHandler.OnAlias(m_mark, am.LookupAnchor(*pOther));
return; return;
} }
ParseHeader(pScanner, state); am.RegisterReference(*this);
anchor = am.LookupAnchor(*this);
// is this an alias? if so, its contents are an alias to }
// a previously defined anchor
if(m_alias) {
// the scanner throws an exception if it doesn't know this anchor name
const Node *pReferencedNode = pScanner->Retrieve(m_anchor);
m_pIdentity = pReferencedNode;
// mark the referenced node for the sake of the client code
pReferencedNode->m_referenced = true;
// use of an Alias object keeps the referenced content from
// being deleted twice
Content *pAliasedContent = pReferencedNode->m_pContent;
if(pAliasedContent)
m_pContent = new AliasContent(pAliasedContent);
return; if(m_pContent)
m_pContent->EmitEvents(am, eventHandler, m_mark, GetTag(), anchor);
else
eventHandler.OnNull(GetTag(), anchor);
} }
// now split based on what kind of node we should be void Node::Init(CONTENT_TYPE type, const Mark& mark, const std::string& tag)
switch(pScanner->peek().type) { {
case Token::SCALAR: Clear();
m_mark = mark;
m_tag = tag;
m_alias = false;
m_pIdentity = this;
m_referenced = false;
switch(type) {
case CT_SCALAR:
m_pContent = new Scalar; m_pContent = new Scalar;
break; break;
case Token::FLOW_SEQ_START: case CT_SEQUENCE:
case Token::BLOCK_SEQ_START:
m_pContent = new Sequence; m_pContent = new Sequence;
break; break;
case Token::FLOW_MAP_START: case CT_MAP:
case Token::BLOCK_MAP_START:
m_pContent = new Map;
break;
case Token::KEY:
// compact maps can only go in a flow sequence
if(state.GetCurCollectionType() == ParserState::FLOW_SEQ)
m_pContent = new Map; m_pContent = new Map;
break; break;
default: default:
m_pContent = 0;
break; break;
} }
// Have to save anchor before parsing to allow for aliases as
// contained node (recursive structure)
if(!m_anchor.empty())
pScanner->Save(m_anchor, this);
if(m_pContent)
m_pContent->Parse(pScanner, state);
} }
// ParseHeader void Node::InitNull(const std::string& tag)
// . Grabs any tag, alias, or anchor tokens and deals with them.
void Node::ParseHeader(Scanner *pScanner, ParserState& state)
{ {
while(1) { Clear();
if(pScanner->empty()) m_tag = tag;
return; m_alias = false;
m_pIdentity = this;
switch(pScanner->peek().type) { m_referenced = false;
case Token::TAG: ParseTag(pScanner, state); break;
case Token::ANCHOR: ParseAnchor(pScanner, state); break;
case Token::ALIAS: ParseAlias(pScanner, state); break;
default: return;
}
}
} }
void Node::ParseTag(Scanner *pScanner, ParserState& state) void Node::InitAlias(const Mark& mark, const Node& identity)
{ {
Token& token = pScanner->peek(); Clear();
if(m_tag != "") m_mark = mark;
throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS); m_alias = true;
m_pIdentity = &identity;
Tag tag(token); if(identity.m_pContent)
m_tag = tag.Translate(state); m_pContent = new AliasContent(identity.m_pContent);
pScanner->pop(); identity.m_referenced = true;
} }
void Node::ParseAnchor(Scanner *pScanner, ParserState& /*state*/) void Node::SetData(const std::string& data)
{ {
Token& token = pScanner->peek(); assert(m_pContent); // TODO: throw
if(m_anchor != "") m_pContent->SetData(data);
throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS);
m_anchor = token.value;
m_alias = false;
pScanner->pop();
} }
void Node::ParseAlias(Scanner *pScanner, ParserState& /*state*/) void Node::Append(std::auto_ptr<Node> pNode)
{ {
Token& token = pScanner->peek(); assert(m_pContent); // TODO: throw
if(m_anchor != "") m_pContent->Append(pNode);
throw ParserException(token.mark, ErrorMsg::MULTIPLE_ALIASES); }
if(m_tag != "")
throw ParserException(token.mark, ErrorMsg::ALIAS_CONTENT);
m_anchor = token.value; void Node::Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue)
m_alias = true; {
pScanner->pop(); assert(m_pContent); // TODO: throw
m_pContent->Insert(pKey, pValue);
} }
CONTENT_TYPE Node::GetType() const CONTENT_TYPE Node::GetType() const
...@@ -261,23 +226,8 @@ namespace YAML ...@@ -261,23 +226,8 @@ namespace YAML
Emitter& operator << (Emitter& out, const Node& node) Emitter& operator << (Emitter& out, const Node& node)
{ {
// write anchor/alias EmitFromEvents emitFromEvents(out);
if(node.m_anchor != "") { node.EmitEvents(emitFromEvents);
if(node.m_alias)
out << Alias(node.m_anchor);
else
out << Anchor(node.m_anchor);
}
if(node.m_tag != "")
out << VerbatimTag(node.m_tag);
// write content
if(node.m_pContent)
node.m_pContent->Write(out);
else if(!node.m_alias)
out << Null;
return out; return out;
} }
......
#include "nodebuilder.h"
#include "mark.h"
#include "node.h"
#include "nodeproperties.h"
#include <cassert>
namespace YAML
{
NodeBuilder::NodeBuilder(Node& root): m_root(root), m_initializedRoot(false), m_finished(false)
{
m_root.Clear();
m_anchors.push_back(0); // since the anchors start at 1
}
NodeBuilder::~NodeBuilder()
{
}
void NodeBuilder::OnDocumentStart(const Mark&)
{
}
void NodeBuilder::OnDocumentEnd()
{
assert(m_finished);
}
void NodeBuilder::OnNull(const std::string& tag, anchor_t anchor)
{
Node& node = Push(anchor);
node.InitNull(tag);
Pop();
}
void NodeBuilder::OnAlias(const Mark& mark, anchor_t anchor)
{
Node& node = Push();
node.InitAlias(mark, *m_anchors[anchor]);
Pop();
}
void NodeBuilder::OnScalar(const Mark& mark, const std::string& tag, anchor_t anchor, const std::string& value)
{
Node& node = Push(anchor);
node.Init(CT_SCALAR, mark, tag);
node.SetData(value);
Pop();
}
void NodeBuilder::OnSequenceStart(const Mark& mark, const std::string& tag, anchor_t anchor)
{
Node& node = Push(anchor);
node.Init(CT_SEQUENCE, mark, tag);
}
void NodeBuilder::OnSequenceEnd()
{
Pop();
}
void NodeBuilder::OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor)
{
Node& node = Push(anchor);
node.Init(CT_MAP, mark, tag);
m_didPushKey.push(false);
}
void NodeBuilder::OnMapEnd()
{
m_didPushKey.pop();
Pop();
}
Node& NodeBuilder::Push(anchor_t anchor)
{
Node& node = Push();
RegisterAnchor(anchor, node);
return node;
}
Node& NodeBuilder::Push()
{
if(!m_initializedRoot) {
m_initializedRoot = true;
return m_root;
}
std::auto_ptr<Node> pNode(new Node);
m_stack.push(pNode);
return m_stack.top();
}
Node& NodeBuilder::Top()
{
return m_stack.empty() ? m_root : m_stack.top();
}
void NodeBuilder::Pop()
{
assert(!m_finished);
if(m_stack.empty()) {
m_finished = true;
return;
}
std::auto_ptr<Node> pNode = m_stack.pop();
Insert(pNode);
}
void NodeBuilder::Insert(std::auto_ptr<Node> pNode)
{
Node& node = Top();
switch(node.GetType()) {
case CT_SEQUENCE:
node.Append(pNode);
break;
case CT_MAP:
assert(!m_didPushKey.empty());
if(m_didPushKey.top()) {
assert(!m_pendingKeys.empty());
std::auto_ptr<Node> pKey = m_pendingKeys.pop();
node.Insert(pKey, pNode);
m_didPushKey.top() = false;
} else {
m_pendingKeys.push(pNode);
m_didPushKey.top() = true;
}
break;
default:
assert(false);
}
}
void NodeBuilder::RegisterAnchor(anchor_t anchor, const Node& node)
{
if(anchor) {
assert(anchor == m_anchors.size());
m_anchors.push_back(&node);
}
}
}
#pragma once
#ifndef NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "eventhandler.h"
#include "ptr_stack.h"
#include <map>
#include <memory>
#include <stack>
namespace YAML
{
class Node;
class NodeBuilder: public EventHandler
{
public:
explicit NodeBuilder(Node& root);
virtual ~NodeBuilder();
virtual void OnDocumentStart(const Mark& mark);
virtual void OnDocumentEnd();
virtual void OnNull(const std::string& tag, anchor_t anchor);
virtual void OnAlias(const Mark& mark, anchor_t anchor);
virtual void OnScalar(const Mark& mark, const std::string& tag, anchor_t anchor, const std::string& value);
virtual void OnSequenceStart(const Mark& mark, const std::string& tag, anchor_t anchor);
virtual void OnSequenceEnd();
virtual void OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor);
virtual void OnMapEnd();
private:
Node& Push(anchor_t anchor);
Node& Push();
Node& Top();
void Pop();
void Insert(std::auto_ptr<Node> pNode);
void RegisterAnchor(anchor_t anchor, const Node& node);
private:
Node& m_root;
bool m_initializedRoot;
bool m_finished;
ptr_stack<Node> m_stack;
ptr_stack<Node> m_pendingKeys;
std::stack<bool> m_didPushKey;
typedef std::vector<const Node *> Anchors;
Anchors m_anchors;
};
}
#endif // NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "parser.h" #include "parser.h"
#include "directives.h"
#include "eventhandler.h"
#include "exceptions.h"
#include "graphbuilderadapter.h"
#include "node.h"
#include "nodebuilder.h"
#include "scanner.h" #include "scanner.h"
#include "singledocparser.h"
#include "tag.h"
#include "token.h" #include "token.h"
#include "exceptions.h"
#include "parserstate.h"
#include <sstream> #include <sstream>
#include <cstdio> #include <cstdio>
...@@ -29,42 +35,47 @@ namespace YAML ...@@ -29,42 +35,47 @@ namespace YAML
void Parser::Load(std::istream& in) void Parser::Load(std::istream& in)
{ {
m_pScanner.reset(new Scanner(in)); m_pScanner.reset(new Scanner(in));
m_pState.reset(new ParserState); m_pDirectives.reset(new Directives);
} }
// GetNextDocument // HandleNextDocument
// . Reads the next document in the queue (of tokens). // . Handles the next document
// . Throws a ParserException on error. // . Throws a ParserException on error.
bool Parser::GetNextDocument(Node& document) // . Returns false if there are no more documents
bool Parser::HandleNextDocument(EventHandler& eventHandler)
{ {
if(!m_pScanner.get()) if(!m_pScanner.get())
return false; return false;
// clear node
document.Clear();
// first read directives
ParseDirectives(); ParseDirectives();
// we better have some tokens in the queue
if(m_pScanner->empty()) if(m_pScanner->empty())
return false; return false;
// first eat doc start (optional) SingleDocParser sdp(*m_pScanner, *m_pDirectives);
if(m_pScanner->peek().type == Token::DOC_START) sdp.HandleDocument(eventHandler);
m_pScanner->pop(); return true;
}
// now parse our root node
document.Parse(m_pScanner.get(), *m_pState);
// and finally eat any doc ends we see
while(!m_pScanner->empty() && m_pScanner->peek().type == Token::DOC_END)
m_pScanner->pop();
// clear anchors from the scanner, which are no longer relevant // BuildNextDocumentGraph
m_pScanner->ClearAnchors(); // . Builds a graph of the next document
// . Returns NULL if there are no more documents
void *Parser::BuildNextDocumentGraph(GraphBuilderInterface& graphBuilder)
{
GraphBuilderAdapter eventHandler(graphBuilder);
if (HandleNextDocument(eventHandler)) {
return eventHandler.RootNode();
} else {
return NULL;
}
}
return true; // GetNextDocument
// . Reads the next document in the queue (of tokens).
// . Throws a ParserException on error.
bool Parser::GetNextDocument(Node& document)
{
NodeBuilder builder(document);
return HandleNextDocument(builder);
} }
// ParseDirectives // ParseDirectives
...@@ -84,7 +95,7 @@ namespace YAML ...@@ -84,7 +95,7 @@ namespace YAML
// we keep the directives from the last document if none are specified; // we keep the directives from the last document if none are specified;
// but if any directives are specific, then we reset them // but if any directives are specific, then we reset them
if(!readDirective) if(!readDirective)
m_pState.reset(new ParserState); m_pDirectives.reset(new Directives);
readDirective = true; readDirective = true;
HandleDirective(token); HandleDirective(token);
...@@ -107,20 +118,20 @@ namespace YAML ...@@ -107,20 +118,20 @@ namespace YAML
if(token.params.size() != 1) if(token.params.size() != 1)
throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS); throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS);
if(!m_pState->version.isDefault) if(!m_pDirectives->version.isDefault)
throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE); throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE);
std::stringstream str(token.params[0]); std::stringstream str(token.params[0]);
str >> m_pState->version.major; str >> m_pDirectives->version.major;
str.get(); str.get();
str >> m_pState->version.minor; str >> m_pDirectives->version.minor;
if(!str || str.peek() != EOF) if(!str || str.peek() != EOF)
throw ParserException(token.mark, ErrorMsg::YAML_VERSION + token.params[0]); throw ParserException(token.mark, ErrorMsg::YAML_VERSION + token.params[0]);
if(m_pState->version.major > 1) if(m_pDirectives->version.major > 1)
throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION); throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION);
m_pState->version.isDefault = false; m_pDirectives->version.isDefault = false;
// TODO: warning on major == 1, minor > 2? // TODO: warning on major == 1, minor > 2?
} }
...@@ -133,10 +144,10 @@ namespace YAML ...@@ -133,10 +144,10 @@ namespace YAML
const std::string& handle = token.params[0]; const std::string& handle = token.params[0];
const std::string& prefix = token.params[1]; const std::string& prefix = token.params[1];
if(m_pState->tags.find(handle) != m_pState->tags.end()) if(m_pDirectives->tags.find(handle) != m_pDirectives->tags.end())
throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE); throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE);
m_pState->tags[handle] = prefix; m_pDirectives->tags[handle] = prefix;
} }
void Parser::PrintTokens(std::ostream& out) void Parser::PrintTokens(std::ostream& out)
......
#pragma once
#ifndef PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
#include <map>
#include <stack>
#include <cassert>
namespace YAML
{
struct Version {
bool isDefault;
int major, minor;
};
struct ParserState
{
enum COLLECTION_TYPE { NONE, BLOCK_MAP, BLOCK_SEQ, FLOW_MAP, FLOW_SEQ, COMPACT_MAP };
ParserState();
const std::string TranslateTagHandle(const std::string& handle) const;
COLLECTION_TYPE GetCurCollectionType() const { if(collectionStack.empty()) return NONE; return collectionStack.top(); }
void PushCollectionType(COLLECTION_TYPE type) { collectionStack.push(type); }
void PopCollectionType(COLLECTION_TYPE type) { assert(type == GetCurCollectionType()); collectionStack.pop(); }
Version version;
std::map <std::string, std::string> tags;
std::stack <COLLECTION_TYPE> collectionStack;
};
}
#endif // PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#pragma once
#ifndef PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <memory>
#include <vector>
template <typename T>
class ptr_stack
{
public:
ptr_stack() {}
~ptr_stack() { clear(); }
void clear() {
for(unsigned i=0;i<m_data.size();i++)
delete m_data[i];
m_data.clear();
}
std::size_t size() const { return m_data.size(); }
bool empty() const { return m_data.empty(); }
void push(std::auto_ptr<T> t) { m_data.push_back(t.release()); }
std::auto_ptr<T> pop() {
std::auto_ptr<T> t(m_data.back());
m_data.pop_back();
return t;
}
T& top() { return *m_data.back(); }
private:
std::vector<T*> m_data;
};
#endif // PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "scalar.h" #include "scalar.h"
#include "scanner.h" #include "eventhandler.h"
#include "token.h"
#include "exceptions.h"
#include "node.h"
#include "emitter.h"
namespace YAML namespace YAML
{ {
...@@ -11,29 +7,13 @@ namespace YAML ...@@ -11,29 +7,13 @@ namespace YAML
{ {
} }
Scalar::Scalar(const std::string& data): m_data(data)
{
}
Scalar::~Scalar() Scalar::~Scalar()
{ {
} }
Content *Scalar::Clone() const void Scalar::EmitEvents(AliasManager&, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const
{
return new Scalar(m_data);
}
void Scalar::Parse(Scanner *pScanner, ParserState& /*state*/)
{
Token& token = pScanner->peek();
m_data = token.value;
pScanner->pop();
}
void Scalar::Write(Emitter& out) const
{ {
out << m_data; eventHandler.OnScalar(mark, tag, anchor, m_data);
} }
int Scalar::Compare(Content *pContent) int Scalar::Compare(Content *pContent)
......
...@@ -13,15 +13,12 @@ namespace YAML ...@@ -13,15 +13,12 @@ namespace YAML
{ {
public: public:
Scalar(); Scalar();
Scalar(const std::string& data);
virtual ~Scalar(); virtual ~Scalar();
virtual Content *Clone() const; virtual void SetData(const std::string& data) { m_data = data; }
virtual void Parse(Scanner *pScanner, ParserState& state);
virtual void Write(Emitter& out) const;
virtual bool IsScalar() const { return true; } virtual bool IsScalar() const { return true; }
virtual void EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const;
// extraction // extraction
virtual bool GetScalar(std::string& scalar) const { virtual bool GetScalar(std::string& scalar) const {
......
...@@ -32,14 +32,9 @@ namespace YAML ...@@ -32,14 +32,9 @@ namespace YAML
void Scanner::pop() void Scanner::pop()
{ {
EnsureTokensInQueue(); EnsureTokensInQueue();
if(!m_tokens.empty()) { if(!m_tokens.empty())
// Saved anchors shouldn't survive popping the document end marker
if (m_tokens.front().type == Token::DOC_END) {
ClearAnchors();
}
m_tokens.pop(); m_tokens.pop();
} }
}
// peek // peek
// . Returns (but does not remove) the next token on the queue. // . Returns (but does not remove) the next token on the queue.
...@@ -245,7 +240,6 @@ namespace YAML ...@@ -245,7 +240,6 @@ namespace YAML
IndentMarker *pIndent = new IndentMarker(-1, IndentMarker::NONE); IndentMarker *pIndent = new IndentMarker(-1, IndentMarker::NONE);
m_indentRefs.push_back(pIndent); m_indentRefs.push_back(pIndent);
m_indents.push(pIndent); m_indents.push(pIndent);
m_anchors.clear();
} }
// EndStream // EndStream
...@@ -378,29 +372,6 @@ namespace YAML ...@@ -378,29 +372,6 @@ namespace YAML
return m_indents.top()->column; return m_indents.top()->column;
} }
// Save
// . Saves a pointer to the Node object referenced by a particular anchor
// name.
void Scanner::Save(const std::string& anchor, Node* value)
{
m_anchors[anchor] = value;
}
// Retrieve
// . Retrieves a pointer previously saved for an anchor name.
// . Throws an exception if the anchor has not been defined.
const Node *Scanner::Retrieve(const std::string& anchor) const
{
typedef std::map<std::string, const Node *> map;
map::const_iterator itNode = m_anchors.find(anchor);
if(m_anchors.end() == itNode)
ThrowParserException(ErrorMsg::UNKNOWN_ANCHOR);
return itNode->second;
}
// ThrowParserException // ThrowParserException
// . Throws a ParserException with the current token location // . Throws a ParserException with the current token location
// (if available). // (if available).
...@@ -414,10 +385,5 @@ namespace YAML ...@@ -414,10 +385,5 @@ namespace YAML
} }
throw ParserException(mark, msg); throw ParserException(mark, msg);
} }
void Scanner::ClearAnchors()
{
m_anchors.clear();
}
} }
...@@ -29,11 +29,6 @@ namespace YAML ...@@ -29,11 +29,6 @@ namespace YAML
void pop(); void pop();
Token& peek(); Token& peek();
// anchor management
void Save(const std::string& anchor, Node* value);
const Node *Retrieve(const std::string& anchor) const;
void ClearAnchors();
private: private:
struct IndentMarker { struct IndentMarker {
enum INDENT_TYPE { MAP, SEQ, NONE }; enum INDENT_TYPE { MAP, SEQ, NONE };
...@@ -127,7 +122,6 @@ namespace YAML ...@@ -127,7 +122,6 @@ namespace YAML
std::stack <IndentMarker *> m_indents; std::stack <IndentMarker *> m_indents;
std::vector <IndentMarker *> m_indentRefs; // for "garbage collection" std::vector <IndentMarker *> m_indentRefs; // for "garbage collection"
std::stack <FLOW_MARKER> m_flows; std::stack <FLOW_MARKER> m_flows;
std::map <std::string, const Node *> m_anchors;
}; };
} }
......
#include "sequence.h" #include "sequence.h"
#include "eventhandler.h"
#include "node.h" #include "node.h"
#include "scanner.h"
#include "token.h"
#include "emitter.h"
#include <stdexcept> #include <stdexcept>
namespace YAML namespace YAML
...@@ -12,12 +10,6 @@ namespace YAML ...@@ -12,12 +10,6 @@ namespace YAML
} }
Sequence::Sequence(const std::vector<Node *>& data)
{
for(std::size_t i=0;i<data.size();i++)
m_data.push_back(data[i]->Clone().release());
}
Sequence::~Sequence() Sequence::~Sequence()
{ {
Clear(); Clear();
...@@ -30,11 +22,6 @@ namespace YAML ...@@ -30,11 +22,6 @@ namespace YAML
m_data.clear(); m_data.clear();
} }
Content *Sequence::Clone() const
{
return new Sequence(m_data);
}
bool Sequence::GetBegin(std::vector <Node *>::const_iterator& it) const bool Sequence::GetBegin(std::vector <Node *>::const_iterator& it) const
{ {
it = m_data.begin(); it = m_data.begin();
...@@ -59,90 +46,17 @@ namespace YAML ...@@ -59,90 +46,17 @@ namespace YAML
return m_data.size(); return m_data.size();
} }
void Sequence::Parse(Scanner *pScanner, ParserState& state) void Sequence::Append(std::auto_ptr<Node> pNode)
{
Clear();
// split based on start token
switch(pScanner->peek().type) {
case Token::BLOCK_SEQ_START: ParseBlock(pScanner, state); break;
case Token::FLOW_SEQ_START: ParseFlow(pScanner, state); break;
default: break;
}
}
void Sequence::ParseBlock(Scanner *pScanner, ParserState& state)
{ {
// eat start token m_data.push_back(pNode.release());
pScanner->pop();
state.PushCollectionType(ParserState::BLOCK_SEQ);
while(1) {
if(pScanner->empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ);
Token token = pScanner->peek();
if(token.type != Token::BLOCK_ENTRY && token.type != Token::BLOCK_SEQ_END)
throw ParserException(token.mark, ErrorMsg::END_OF_SEQ);
pScanner->pop();
if(token.type == Token::BLOCK_SEQ_END)
break;
Node *pNode = new Node;
m_data.push_back(pNode);
// check for null
if(!pScanner->empty()) {
const Token& token = pScanner->peek();
if(token.type == Token::BLOCK_ENTRY || token.type == Token::BLOCK_SEQ_END)
continue;
}
pNode->Parse(pScanner, state);
}
state.PopCollectionType(ParserState::BLOCK_SEQ);
}
void Sequence::ParseFlow(Scanner *pScanner, ParserState& state)
{
// eat start token
pScanner->pop();
state.PushCollectionType(ParserState::FLOW_SEQ);
while(1) {
if(pScanner->empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ_FLOW);
// first check for end
if(pScanner->peek().type == Token::FLOW_SEQ_END) {
pScanner->pop();
break;
}
// then read the node
Node *pNode = new Node;
m_data.push_back(pNode);
pNode->Parse(pScanner, state);
// 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 = pScanner->peek();
if(token.type == Token::FLOW_ENTRY)
pScanner->pop();
else if(token.type != Token::FLOW_SEQ_END)
throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW);
}
state.PopCollectionType(ParserState::FLOW_SEQ);
} }
void Sequence::Write(Emitter& out) const void Sequence::EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const
{ {
out << BeginSeq; eventHandler.OnSequenceStart(mark, tag, anchor);
for(std::size_t i=0;i<m_data.size();i++) for(std::size_t i=0;i<m_data.size();i++)
out << *m_data[i]; m_data[i]->EmitEvents(am, eventHandler);
out << EndSeq; eventHandler.OnSequenceEnd();
} }
int Sequence::Compare(Content *pContent) int Sequence::Compare(Content *pContent)
......
...@@ -15,19 +15,17 @@ namespace YAML ...@@ -15,19 +15,17 @@ namespace YAML
{ {
public: public:
Sequence(); Sequence();
Sequence(const std::vector<Node *>& data);
virtual ~Sequence(); virtual ~Sequence();
void Clear(); void Clear();
virtual Content *Clone() const;
virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const; virtual bool GetBegin(std::vector <Node *>::const_iterator& it) const;
virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const; virtual bool GetEnd(std::vector <Node *>::const_iterator& it) const;
virtual Node *GetNode(std::size_t i) const; virtual Node *GetNode(std::size_t i) const;
virtual std::size_t GetSize() const; virtual std::size_t GetSize() const;
virtual void Parse(Scanner *pScanner, ParserState& state); virtual void Append(std::auto_ptr<Node> pNode);
virtual void Write(Emitter& out) const; virtual void EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const;
virtual bool IsSequence() const { return true; } virtual bool IsSequence() const { return true; }
...@@ -37,10 +35,6 @@ namespace YAML ...@@ -37,10 +35,6 @@ namespace YAML
virtual int Compare(Sequence *pSeq); virtual int Compare(Sequence *pSeq);
virtual int Compare(Map *) { return -1; } virtual int Compare(Map *) { return -1; }
private:
void ParseBlock(Scanner *pScanner, ParserState& state);
void ParseFlow(Scanner *pScanner, ParserState& state);
protected: protected:
std::vector <Node *> m_data; std::vector <Node *> m_data;
}; };
......
#include "singledocparser.h"
#include "collectionstack.h"
#include "directives.h"
#include "eventhandler.h"
#include "exceptions.h"
#include "scanner.h"
#include "tag.h"
#include "token.h"
#include <sstream>
#include <cstdio>
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("", 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);
// now split based on what kind of node we should be
switch(m_scanner.peek().type) {
case Token::SCALAR:
eventHandler.OnScalar(mark, tag, anchor, m_scanner.peek().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;
}
eventHandler.OnNull(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("", 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("", NullAnchor);
}
// now grab value (optional)
if(!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
m_scanner.pop();
HandleNode(eventHandler);
} else {
eventHandler.OnNull("", 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("", NullAnchor);
}
// now grab value (optional)
if(!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) {
m_scanner.pop();
HandleNode(eventHandler);
} else {
eventHandler.OnNull("", 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
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("", 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("", 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;
}
}
#pragma once
#ifndef SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "anchor.h"
#include "noncopyable.h"
#include <string>
#include <map>
#include <memory>
namespace YAML
{
struct Directives;
struct Mark;
struct Token;
class CollectionStack;
class EventHandler;
class Node;
class Scanner;
class SingleDocParser: private noncopyable
{
public:
SingleDocParser(Scanner& scanner, const Directives& directives);
~SingleDocParser();
void HandleDocument(EventHandler& eventHandler);
private:
void HandleNode(EventHandler& eventHandler);
void HandleSequence(EventHandler& eventHandler);
void HandleBlockSequence(EventHandler& eventHandler);
void HandleFlowSequence(EventHandler& eventHandler);
void HandleMap(EventHandler& eventHandler);
void HandleBlockMap(EventHandler& eventHandler);
void HandleFlowMap(EventHandler& eventHandler);
void HandleCompactMap(EventHandler& eventHandler);
void HandleCompactMapWithNoKey(EventHandler& eventHandler);
void ParseProperties(std::string& tag, anchor_t& anchor);
void ParseTag(std::string& tag);
void ParseAnchor(anchor_t& anchor);
anchor_t RegisterAnchor(const std::string& name);
anchor_t LookupAnchor(const Mark& mark, const std::string& name) const;
private:
Scanner& m_scanner;
const Directives& m_directives;
std::auto_ptr<CollectionStack> m_pCollectionStack;
typedef std::map<std::string, anchor_t> Anchors;
Anchors m_anchors;
anchor_t m_curAnchor;
};
}
#endif // SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "tag.h" #include "tag.h"
#include "directives.h"
#include "token.h" #include "token.h"
#include "parserstate.h"
#include <cassert> #include <cassert>
namespace YAML namespace YAML
...@@ -28,17 +28,17 @@ namespace YAML ...@@ -28,17 +28,17 @@ namespace YAML
} }
} }
const std::string Tag::Translate(const ParserState& state) const std::string Tag::Translate(const Directives& directives)
{ {
switch(type) { switch(type) {
case VERBATIM: case VERBATIM:
return value; return value;
case PRIMARY_HANDLE: case PRIMARY_HANDLE:
return state.TranslateTagHandle("!") + value; return directives.TranslateTagHandle("!") + value;
case SECONDARY_HANDLE: case SECONDARY_HANDLE:
return state.TranslateTagHandle("!!") + value; return directives.TranslateTagHandle("!!") + value;
case NAMED_HANDLE: case NAMED_HANDLE:
return state.TranslateTagHandle("!" + handle + "!") + value; return directives.TranslateTagHandle("!" + handle + "!") + value;
case NON_SPECIFIC: case NON_SPECIFIC:
// TODO: // TODO:
return "!"; return "!";
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
namespace YAML namespace YAML
{ {
struct Token; struct Token;
struct ParserState; struct Directives;
struct Tag { struct Tag {
enum TYPE { enum TYPE {
...@@ -16,7 +16,7 @@ namespace YAML ...@@ -16,7 +16,7 @@ namespace YAML
}; };
Tag(const Token& token); Tag(const Token& token);
const std::string Translate(const ParserState& state); const std::string Translate(const Directives& directives);
TYPE type; TYPE type;
std::string handle, value; std::string handle, value;
......
#include "yaml.h" #include "yaml.h"
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <vector>
struct Params {
bool hasFile;
std::string fileName;
};
Params ParseArgs(int argc, char **argv) {
Params p;
std::vector<char*> args(argv + 1, argv + argc);
return p;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
Params p = ParseArgs(argc, argv);
std::ifstream fin; std::ifstream fin;
if(argc > 1) if(argc > 1)
fin.open(argv[1]); fin.open(argv[1]);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment