Commit a71c03a1 authored by Jesse Beder's avatar Jesse Beder
Browse files

Merged r366:387 from the jbeder-event-api branch

parent 0a02403f
#pragma once
#ifndef ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "anchor.h"
#include <map>
namespace YAML
{
class Node;
class AliasManager
{
public:
AliasManager();
void RegisterReference(const Node& node);
const Node *LookupReference(const Node& node) const;
anchor_t LookupAnchor(const Node& node) const;
private:
const Node *_LookupReference(const Node& oldIdentity) const;
anchor_t _CreateNewAnchor();
private:
typedef std::map<const Node*, const Node*> NodeByNode;
NodeByNode m_newIdentityByOldIdentity;
typedef std::map<const Node*, anchor_t> AnchorByIdentity;
AnchorByIdentity m_anchorByIdentity;
anchor_t m_curAnchor;
};
}
#endif // ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#pragma once
#ifndef ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <cstddef>
namespace YAML
{
typedef std::size_t anchor_t;
const anchor_t NullAnchor = 0;
}
#endif // ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#pragma once
#ifndef EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "eventhandler.h"
#include <stack>
namespace YAML
{
class Emitter;
class EmitFromEvents: public EventHandler
{
public:
EmitFromEvents(Emitter& emitter);
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:
void BeginNode();
void EmitProps(const std::string& tag, anchor_t anchor);
private:
Emitter& m_emitter;
struct State { enum value { WaitingForSequenceEntry, WaitingForKey, WaitingForValue }; };
std::stack<State::value> m_stateStack;
};
}
#endif // EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#pragma once
#ifndef EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "anchor.h"
#include <string>
namespace YAML
{
struct Mark;
class EventHandler
{
public:
virtual ~EventHandler() {}
virtual void OnDocumentStart(const Mark& mark) = 0;
virtual void OnDocumentEnd() = 0;
virtual void OnNull(const std::string& tag, anchor_t anchor) = 0;
virtual void OnAlias(const Mark& mark, anchor_t anchor) = 0;
virtual void OnScalar(const Mark& mark, const std::string& tag, anchor_t anchor, const std::string& value) = 0;
virtual void OnSequenceStart(const Mark& mark, const std::string& tag, anchor_t anchor) = 0;
virtual void OnSequenceEnd() = 0;
virtual void OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor) = 0;
virtual void OnMapEnd() = 0;
};
}
#endif // EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
...@@ -17,10 +17,12 @@ ...@@ -17,10 +17,12 @@
namespace YAML namespace YAML
{ {
class AliasManager;
class Content; class Content;
class Scanner; class Scanner;
class Emitter; class Emitter;
struct ParserState; class EventHandler;
struct NodeProperties;
enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP };
...@@ -32,9 +34,18 @@ namespace YAML ...@@ -32,9 +34,18 @@ namespace YAML
void Clear(); void Clear();
std::auto_ptr<Node> Clone() const; std::auto_ptr<Node> Clone() const;
void Parse(Scanner *pScanner, ParserState& state); void EmitEvents(EventHandler& eventHandler) const;
void EmitEvents(AliasManager& am, EventHandler& eventHandler) const;
CONTENT_TYPE GetType() const; void Init(CONTENT_TYPE type, const Mark& mark, const std::string& tag);
void InitNull(const std::string& tag);
void InitAlias(const Mark& mark, const Node& identity);
void SetData(const std::string& data);
void Append(std::auto_ptr<Node> pNode);
void Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue);
CONTENT_TYPE GetType() const { return m_type; }
// file location of start of this node // file location of start of this node
const Mark GetMark() const { return m_mark; } const Mark GetMark() const { return m_mark; }
...@@ -97,19 +108,11 @@ namespace YAML ...@@ -97,19 +108,11 @@ namespace YAML
template <typename T> template <typename T>
const Node *FindValueForKey(const T& key) const; const Node *FindValueForKey(const T& key) const;
// helper for cloning
Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent);
// helpers for parsing
void ParseHeader(Scanner *pScanner, ParserState& state);
void ParseTag(Scanner *pScanner, ParserState& state);
void ParseAnchor(Scanner *pScanner, ParserState& state);
void ParseAlias(Scanner *pScanner, ParserState& state);
private: private:
Mark m_mark; Mark m_mark;
std::string m_anchor, m_tag; std::string m_tag;
CONTENT_TYPE m_type;
Content *m_pContent; Content *m_pContent;
bool m_alias; bool m_alias;
const Node *m_pIdentity; const Node *m_pIdentity;
......
#pragma once
#ifndef NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
namespace YAML
{
struct NodeProperties {
std::string tag;
std::string anchor;
};
}
#endif // NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
...@@ -4,19 +4,18 @@ ...@@ -4,19 +4,18 @@
#define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "node.h"
#include "noncopyable.h" #include "noncopyable.h"
#include <ios> #include <ios>
#include <string>
#include <vector>
#include <map>
#include <memory> #include <memory>
namespace YAML namespace YAML
{ {
class Scanner; struct Directives;
struct ParserState; struct Mark;
struct Token; struct Token;
class EventHandler;
class Node;
class Scanner;
class Parser: private noncopyable class Parser: private noncopyable
{ {
...@@ -28,6 +27,8 @@ namespace YAML ...@@ -28,6 +27,8 @@ namespace YAML
operator bool() const; operator bool() const;
void Load(std::istream& in); void Load(std::istream& in);
bool HandleNextDocument(EventHandler& eventHandler);
bool GetNextDocument(Node& document); bool GetNextDocument(Node& document);
void PrintTokens(std::ostream& out); void PrintTokens(std::ostream& out);
...@@ -36,10 +37,10 @@ namespace YAML ...@@ -36,10 +37,10 @@ namespace YAML
void HandleDirective(const Token& token); void HandleDirective(const Token& token);
void HandleYamlDirective(const Token& token); void HandleYamlDirective(const Token& token);
void HandleTagDirective(const Token& token); void HandleTagDirective(const Token& token);
private: private:
std::auto_ptr<Scanner> m_pScanner; std::auto_ptr<Scanner> m_pScanner;
std::auto_ptr<ParserState> m_pState; std::auto_ptr<Directives> m_pDirectives;
}; };
} }
......
...@@ -2,25 +2,10 @@ ...@@ -2,25 +2,10 @@
namespace YAML namespace YAML
{ {
AliasContent::AliasContent(Content* pNodeContent) AliasContent::AliasContent(Content* pNodeContent): m_pRef(pNodeContent)
: m_pRef(pNodeContent)
{ {
} }
Content *AliasContent::Clone() const
{
return 0; // TODO: how to clone an alias?
}
void AliasContent::Parse(Scanner * /*pScanner*/, ParserState& /*state*/)
{
}
void AliasContent::Write(Emitter&) const
{
// no content (just an alias)
}
bool AliasContent::GetBegin(std::vector <Node *>::const_iterator& i) const bool AliasContent::GetBegin(std::vector <Node *>::const_iterator& i) const
{ {
return m_pRef->GetBegin(i); return m_pRef->GetBegin(i);
...@@ -71,6 +56,11 @@ namespace YAML ...@@ -71,6 +56,11 @@ namespace YAML
return m_pRef->GetScalar(scalar); return m_pRef->GetScalar(scalar);
} }
void AliasContent::EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const
{
m_pRef->EmitEvents(am, eventHandler, mark, tag, anchor);
}
int AliasContent::Compare(Content *pContent) int AliasContent::Compare(Content *pContent)
{ {
return m_pRef->Compare(pContent); return m_pRef->Compare(pContent);
......
...@@ -12,11 +12,6 @@ namespace YAML ...@@ -12,11 +12,6 @@ namespace YAML
{ {
public: public:
AliasContent(Content *pNodeContent); AliasContent(Content *pNodeContent);
virtual Content *Clone() const;
virtual void Parse(Scanner* pScanner, ParserState& state);
virtual void Write(Emitter&) const;
virtual bool GetBegin(std::vector <Node *>::const_iterator&) const; virtual bool GetBegin(std::vector <Node *>::const_iterator&) const;
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator&) const; virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator&) const;
...@@ -29,6 +24,7 @@ namespace YAML ...@@ -29,6 +24,7 @@ namespace YAML
virtual bool IsSequence() const; virtual bool IsSequence() const;
virtual bool GetScalar(std::string& s) const; virtual bool GetScalar(std::string& s) const;
virtual void EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const;
virtual int Compare(Content *); virtual int Compare(Content *);
virtual int Compare(Scalar *); virtual int Compare(Scalar *);
......
#include "aliasmanager.h"
#include "node.h"
#include <cassert>
#include <sstream>
namespace YAML
{
AliasManager::AliasManager(): m_curAnchor(0)
{
}
void AliasManager::RegisterReference(const Node& node)
{
const Node *pIdentity = node.Identity();
m_newIdentityByOldIdentity.insert(std::make_pair(pIdentity, &node));
m_anchorByIdentity.insert(std::make_pair(&node, _CreateNewAnchor()));
}
const Node *AliasManager::LookupReference(const Node& node) const
{
const Node *pIdentity = node.Identity();
return _LookupReference(*pIdentity);
}
anchor_t AliasManager::LookupAnchor(const Node& node) const
{
AnchorByIdentity::const_iterator it = m_anchorByIdentity.find(&node);
if(it == m_anchorByIdentity.end())
assert(false); // TODO: throw
return it->second;
}
const Node *AliasManager::_LookupReference(const Node& oldIdentity) const
{
NodeByNode::const_iterator it = m_newIdentityByOldIdentity.find(&oldIdentity);
if(it == m_newIdentityByOldIdentity.end())
return 0;
return it->second;
}
anchor_t AliasManager::_CreateNewAnchor()
{
return ++m_curAnchor;
}
}
#pragma once
#ifndef COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <stack>
#include <cassert>
namespace YAML
{
struct CollectionType {
enum value { None, BlockMap, BlockSeq, FlowMap, FlowSeq, CompactMap };
};
class CollectionStack
{
public:
CollectionType::value GetCurCollectionType() const {
if(collectionStack.empty())
return CollectionType::None;
return collectionStack.top();
}
void PushCollectionType(CollectionType::value type) { collectionStack.push(type); }
void PopCollectionType(CollectionType::value type) { assert(type == GetCurCollectionType()); collectionStack.pop(); }
private:
std::stack<CollectionType::value> collectionStack;
};
}
#endif // COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "content.h"
#include "node.h"
#include <cassert>
namespace YAML
{
void Content::SetData(const std::string&)
{
assert(false); // TODO: throw
}
void Content::Append(std::auto_ptr<Node>)
{
assert(false); // TODO: throw
}
void Content::Insert(std::auto_ptr<Node>, std::auto_ptr<Node>)
{
assert(false); // TODO: throw
}
}
...@@ -4,32 +4,30 @@ ...@@ -4,32 +4,30 @@
#define CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <vector> #include "anchor.h"
#include <map>
#include "parserstate.h"
#include "exceptions.h" #include "exceptions.h"
#include "ltnode.h" #include "ltnode.h"
#include <map>
#include <memory>
#include <vector>
namespace YAML namespace YAML
{ {
class Scanner; struct Mark;
class Parser; struct NodeProperties;
class AliasManager;
class EventHandler;
class Map;
class Node; class Node;
class Scalar; class Scalar;
class Scanner;
class Sequence; class Sequence;
class Map;
class Emitter;
class Content class Content
{ {
public: public:
Content() {} Content() {}
virtual ~Content() {} virtual ~Content() {}
virtual Content *Clone() const = 0;
virtual void Parse(Scanner *pScanner, ParserState& state) = 0;
virtual void Write(Emitter& out) const = 0;
virtual bool GetBegin(std::vector <Node *>::const_iterator&) const { return false; } virtual bool GetBegin(std::vector <Node *>::const_iterator&) const { return false; }
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator&) const { return false; } virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator&) const { return false; }
...@@ -40,6 +38,11 @@ namespace YAML ...@@ -40,6 +38,11 @@ namespace YAML
virtual bool IsScalar() const { return false; } virtual bool IsScalar() const { return false; }
virtual bool IsMap() const { return false; } virtual bool IsMap() const { return false; }
virtual bool IsSequence() const { return false; } virtual bool IsSequence() const { return false; }
virtual void SetData(const std::string& data);
virtual void Append(std::auto_ptr<Node> pNode);
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 = 0;
// extraction // extraction
virtual bool GetScalar(std::string&) const { return false; } virtual bool GetScalar(std::string&) const { return false; }
......
#include "parserstate.h" #include "directives.h"
namespace YAML namespace YAML
{ {
ParserState::ParserState() Directives::Directives()
{ {
// version // version
version.isDefault = true; version.isDefault = true;
version.major = 1; version.major = 1;
version.minor = 2; version.minor = 2;
} }
const std::string ParserState::TranslateTagHandle(const std::string& handle) const const std::string Directives::TranslateTagHandle(const std::string& handle) const
{ {
std::map <std::string, std::string>::const_iterator it = tags.find(handle); std::map <std::string, std::string>::const_iterator it = tags.find(handle);
if(it == tags.end()) { if(it == tags.end()) {
...@@ -18,7 +18,7 @@ namespace YAML ...@@ -18,7 +18,7 @@ namespace YAML
return "tag:yaml.org,2002:"; return "tag:yaml.org,2002:";
return handle; return handle;
} }
return it->second; return it->second;
} }
} }
#pragma once
#ifndef DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
#include <map>
namespace YAML
{
struct Version {
bool isDefault;
int major, minor;
};
struct Directives {
Directives();
const std::string TranslateTagHandle(const std::string& handle) const;
Version version;
std::map<std::string, std::string> tags;
};
}
#endif // DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "emitfromevents.h"
#include "emitter.h"
#include "null.h"
#include <cassert>
#include <sstream>
namespace {
std::string ToString(YAML::anchor_t anchor) {
std::stringstream stream;
stream << anchor;
return stream.str();
}
}
namespace YAML
{
EmitFromEvents::EmitFromEvents(Emitter& emitter): m_emitter(emitter)
{
}
void EmitFromEvents::OnDocumentStart(const Mark&)
{
}
void EmitFromEvents::OnDocumentEnd()
{
}
void EmitFromEvents::OnNull(const std::string& tag, anchor_t anchor)
{
BeginNode();
EmitProps(tag, anchor);
if(tag.empty())
m_emitter << Null;
}
void EmitFromEvents::OnAlias(const Mark&, anchor_t anchor)
{
BeginNode();
m_emitter << Alias(ToString(anchor));
}
void EmitFromEvents::OnScalar(const Mark&, const std::string& tag, anchor_t anchor, const std::string& value)
{
BeginNode();
EmitProps(tag, anchor);
m_emitter << value;
}
void EmitFromEvents::OnSequenceStart(const Mark&, const std::string& tag, anchor_t anchor)
{
BeginNode();
EmitProps(tag, anchor);
m_emitter << BeginSeq;
m_stateStack.push(State::WaitingForSequenceEntry);
}
void EmitFromEvents::OnSequenceEnd()
{
m_emitter << EndSeq;
assert(m_stateStack.top() == State::WaitingForSequenceEntry);
m_stateStack.pop();
}
void EmitFromEvents::OnMapStart(const Mark&, const std::string& tag, anchor_t anchor)
{
BeginNode();
EmitProps(tag, anchor);
m_emitter << BeginMap;
m_stateStack.push(State::WaitingForKey);
}
void EmitFromEvents::OnMapEnd()
{
m_emitter << EndMap;
assert(m_stateStack.top() == State::WaitingForKey);
m_stateStack.pop();
}
void EmitFromEvents::BeginNode()
{
if(m_stateStack.empty())
return;
switch(m_stateStack.top()) {
case State::WaitingForKey:
m_emitter << Key;
m_stateStack.top() = State::WaitingForValue;
break;
case State::WaitingForValue:
m_emitter << Value;
m_stateStack.top() = State::WaitingForKey;
break;
default:
break;
}
}
void EmitFromEvents::EmitProps(const std::string& tag, anchor_t anchor)
{
if(!tag.empty())
m_emitter << VerbatimTag(tag);
if(anchor)
m_emitter << Anchor(ToString(anchor));
}
}
#include "map.h" #include "map.h"
#include "node.h" #include "node.h"
#include "scanner.h" #include "eventhandler.h"
#include "token.h"
#include "exceptions.h" #include "exceptions.h"
#include "emitter.h"
namespace YAML namespace YAML
{ {
Map::Map() Map::Map()
{ {
} }
Map::Map(const node_map& data)
{
for(node_map::const_iterator it=data.begin();it!=data.end();++it) {
std::auto_ptr<Node> pKey = it->first->Clone();
std::auto_ptr<Node> pValue = it->second->Clone();
AddEntry(pKey, pValue);
}
}
Map::~Map() Map::~Map()
{ {
...@@ -34,11 +23,6 @@ namespace YAML ...@@ -34,11 +23,6 @@ namespace YAML
m_data.clear(); m_data.clear();
} }
Content *Map::Clone() const
{
return new Map(m_data);
}
bool Map::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const bool Map::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const
{ {
it = m_data.begin(); it = m_data.begin();
...@@ -56,140 +40,7 @@ namespace YAML ...@@ -56,140 +40,7 @@ namespace YAML
return m_data.size(); return m_data.size();
} }
void Map::Parse(Scanner *pScanner, ParserState& state) void Map::Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue)
{
Clear();
// split based on start token
switch(pScanner->peek().type) {
case Token::BLOCK_MAP_START: ParseBlock(pScanner, state); break;
case Token::FLOW_MAP_START: ParseFlow(pScanner, state); break;
case Token::KEY: ParseCompact(pScanner, state); break;
case Token::VALUE: ParseCompactWithNoKey(pScanner, state); break;
default: break;
}
}
void Map::ParseBlock(Scanner *pScanner, ParserState& state)
{
// eat start token
pScanner->pop();
state.PushCollectionType(ParserState::BLOCK_MAP);
while(1) {
if(pScanner->empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP);
Token token = pScanner->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) {
pScanner->pop();
break;
}
std::auto_ptr <Node> pKey(new Node), pValue(new Node);
// grab key (if non-null)
if(token.type == Token::KEY) {
pScanner->pop();
pKey->Parse(pScanner, state);
}
// now grab value (optional)
if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
pScanner->pop();
pValue->Parse(pScanner, state);
}
AddEntry(pKey, pValue);
}
state.PopCollectionType(ParserState::BLOCK_MAP);
}
void Map::ParseFlow(Scanner *pScanner, ParserState& state)
{
// eat start token
pScanner->pop();
state.PushCollectionType(ParserState::FLOW_MAP);
while(1) {
if(pScanner->empty())
throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP_FLOW);
Token& token = pScanner->peek();
// first check for end
if(token.type == Token::FLOW_MAP_END) {
pScanner->pop();
break;
}
std::auto_ptr <Node> pKey(new Node), pValue(new Node);
// grab key (if non-null)
if(token.type == Token::KEY) {
pScanner->pop();
pKey->Parse(pScanner, state);
}
// now grab value (optional)
if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
pScanner->pop();
pValue->Parse(pScanner, state);
}
// 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 = pScanner->peek();
if(nextToken.type == Token::FLOW_ENTRY)
pScanner->pop();
else if(nextToken.type != Token::FLOW_MAP_END)
throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW);
AddEntry(pKey, pValue);
}
state.PopCollectionType(ParserState::FLOW_MAP);
}
// ParseCompact
// . Single "key: value" pair in a flow sequence
void Map::ParseCompact(Scanner *pScanner, ParserState& state)
{
state.PushCollectionType(ParserState::COMPACT_MAP);
std::auto_ptr <Node> pKey(new Node), pValue(new Node);
// grab key
pScanner->pop();
pKey->Parse(pScanner, state);
// now grab value (optional)
if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
pScanner->pop();
pValue->Parse(pScanner, state);
}
AddEntry(pKey, pValue);
state.PopCollectionType(ParserState::COMPACT_MAP);
}
// ParseCompactWithNoKey
// . Single ": value" pair in a flow sequence
void Map::ParseCompactWithNoKey(Scanner *pScanner, ParserState& state)
{
state.PushCollectionType(ParserState::COMPACT_MAP);
std::auto_ptr <Node> pKey(new Node), pValue(new Node);
// grab value
pScanner->pop();
pValue->Parse(pScanner, state);
AddEntry(pKey, pValue);
state.PopCollectionType(ParserState::COMPACT_MAP);
}
void Map::AddEntry(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue)
{ {
node_map::const_iterator it = m_data.find(pKey.get()); node_map::const_iterator it = m_data.find(pKey.get());
if(it != m_data.end()) if(it != m_data.end())
...@@ -198,12 +49,14 @@ namespace YAML ...@@ -198,12 +49,14 @@ namespace YAML
m_data[pKey.release()] = pValue.release(); m_data[pKey.release()] = pValue.release();
} }
void Map::Write(Emitter& out) const void Map::EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const
{ {
out << BeginMap; eventHandler.OnMapStart(mark, tag, anchor);
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
out << Key << *it->first << Value << *it->second; it->first->EmitEvents(am, eventHandler);
out << EndMap; it->second->EmitEvents(am, eventHandler);
}
eventHandler.OnMapEnd();
} }
int Map::Compare(Content *pContent) int Map::Compare(Content *pContent)
......
...@@ -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,15 +25,8 @@ namespace YAML ...@@ -20,15 +25,8 @@ 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_type(CT_NONE), 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()
...@@ -39,156 +37,112 @@ namespace YAML ...@@ -39,156 +37,112 @@ namespace YAML
void Node::Clear() void Node::Clear()
{ {
delete m_pContent; delete m_pContent;
m_type = CT_NONE;
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
if(pScanner->peek().type == Token::VALUE) {
m_pContent = new Map;
m_pContent->Parse(pScanner, state);
return;
}
ParseHeader(pScanner, state);
// 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 void Node::EmitEvents(AliasManager& am, EventHandler& eventHandler) const
// being deleted twice {
Content *pAliasedContent = pReferencedNode->m_pContent; anchor_t anchor = NullAnchor;
if(pAliasedContent) if(m_referenced || m_alias) {
m_pContent = new AliasContent(pAliasedContent); if(const Node *pOther = am.LookupReference(*this)) {
eventHandler.OnAlias(m_mark, am.LookupAnchor(*pOther));
return;
}
return; am.RegisterReference(*this);
anchor = am.LookupAnchor(*this);
} }
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_type = type;
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; m_pContent = new Map;
break; break;
case Token::KEY:
// compact maps can only go in a flow sequence
if(state.GetCurCollectionType() == ParserState::FLOW_SEQ)
m_pContent = new Map;
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(); m_type = identity.GetType();
}
identity.m_referenced = true;
} }
void Node::ParseAnchor(Scanner *pScanner, ParserState& /*state*/)
{
Token& token = pScanner->peek();
if(m_anchor != "")
throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS);
m_anchor = token.value; void Node::SetData(const std::string& data)
m_alias = false; {
pScanner->pop(); assert(m_pContent); // TODO: throw
m_pContent->SetData(data);
} }
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;
m_alias = true;
pScanner->pop();
} }
CONTENT_TYPE Node::GetType() const void Node::Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue)
{ {
if(!m_pContent) assert(m_pContent); // TODO: throw
return CT_NONE; m_pContent->Insert(pKey, pValue);
if(m_pContent->IsScalar())
return CT_SCALAR;
else if(m_pContent->IsSequence())
return CT_SEQUENCE;
else if(m_pContent->IsMap())
return CT_MAP;
return CT_NONE;
} }
// begin // begin
...@@ -261,23 +215,8 @@ namespace YAML ...@@ -261,23 +215,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);
}
}
}
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